<html><head><meta http-equiv="Content-Type" content="text/html charset=windows-1252"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">Need some guidance here…<div><br></div><div>Under Launch Instance, Networking tab, we have a custom Horizon version that also has a "Policy Profile" Checkbox field, in addition to the Network" MultipleChoiceList field.</div><div><br></div><div>Now, we'd like to be able to select a policy for each network selected. The initial thought was to convert the Policy Profile Checkbox field into a MultipleChoiceList (If there is a better way to define these, please let us know!). With the Network field, as the user drags and drops networks, they are associated with nic1, nic2, nic3… I was figuring the same thing could be done with the "Policy Profile". So…</div><div><br></div><div>I changed the field type and added a widget, the same as with the Network field. Then, I modified the populate function (and the contribute function, but I'm not quite sure yet how that plays into this). The code snippet looks like this:</div><div><br></div><div><div style="margin: 0px; "><font face="Courier New"><span style="color: rgb(4, 51, 255); ">class</span> <b>SetNetworkAction</b>(workflows.Action):</font></div><div style="margin: 0px; "><font face="Courier New"> network = forms.MultipleChoiceField(label=_(<span style="color: #00b400"><i>"Networks"</i></span>),</font></div><div style="margin: 0px; "><font face="Courier New"> required=<span style="color: #0433ff">True</span>,</font></div><div style="margin: 0px; "><font face="Courier New"> widget=forms.CheckboxSelectMultiple(),</font></div><div style="margin: 0px; "><font face="Courier New"> error_messages={</font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #00b400"><i>'required'</i></span>: _(</font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #00b400"><i>"At least one network must"</i></span></font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #00b400"><i>" be specified."</i></span>)},</font></div><div style="margin: 0px; "><font face="Courier New"> help_text=_(<span style="color: #00b400"><i>"Launch instance with"</i></span></font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #00b400"><i>"these networks"</i></span>))</font></div><div style="margin: 0px; "><font face="Courier New"> profile = forms.MultipleChoiceField(label=_(<span style="color: #00b400"><i>"Policy Profiles"</i></span>),</font></div><div style="margin: 0px; "><font face="Courier New"> required=<span style="color: #0433ff">False</span>,</font></div><div style="margin: 0px; "><font face="Courier New"> widget=forms.CheckboxSelectMultiple(),</font></div><div style="margin: 0px; "><font face="Courier New"> help_text=_(<span style="color: #00b400"><i>"Launch instance with "</i></span></font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #00b400"><i>"these policy profile(s)"</i></span>))</font></div><div style="margin: 0px; min-height: 12px; "><font face="Courier New"><br></font></div><div style="margin: 0px; min-height: 12px; "><font face="Courier New"><br></font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #0433ff">class</span> <b>Meta</b>:</font></div><div style="margin: 0px; "><font face="Courier New"> name = _(<span style="color: #00b400"><i>"Networking"</i></span>)</font></div><div style="margin: 0px; color: rgb(0, 180, 0); "><font face="Courier New"><span style="color: #000000"> permissions = (</span><i>'openstack.services.network'</i><span style="color: #000000">,)</span></font></div><div style="margin: 0px; color: rgb(0, 180, 0); "><font face="Courier New"><span style="color: #000000"> help_text = _(</span><i>"Select networks for your instance."</i><span style="color: #000000">)</span></font></div><div style="margin: 0px; min-height: 12px; "><font face="Courier New"><br></font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #0433ff">def</span> <b>populate_network_choices</b>(<i>self</i>, request, context):</font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #0433ff">try</span>:</font></div><div style="margin: 0px; "><font face="Courier New"> tenant_id = <i>self</i>.request.user.tenant_id</font></div><div style="margin: 0px; "><font face="Courier New"> networks = api.quantum.network_list_for_tenant(request, tenant_id)</font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #0433ff">for</span> n <span style="color: #0433ff">in</span> networks:</font></div><div style="margin: 0px; "><font face="Courier New"> n.set_id_as_name_if_empty()</font></div><div style="margin: 0px; "><font face="Courier New"> network_list = [(network.id, network.name) <span style="color: #0433ff">for</span> network <span style="color: #0433ff">in</span> networks]</font></div><div style="margin: 0px; "><font face="Courier New"> LOG.error(<span style="color: #00b400"><i>"PCM Populating NETWORKS: %s"</i></span> % network_list)</font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #0433ff">except</span>:</font></div><div style="margin: 0px; "><font face="Courier New"> network_list = []</font></div><div style="margin: 0px; "><font face="Courier New"> exceptions.handle(request,</font></div><div style="margin: 0px; "><font face="Courier New"> _(<span style="color: #00b400"><i>'Unable to retrieve networks.'</i></span>))</font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #0433ff">return</span> network_list</font></div><div style="margin: 0px; min-height: 12px; "><font face="Courier New"><br></font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #0433ff">def</span> <b>populate_profile_choices</b>(<i>self</i>, request, context):</font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #0433ff">try</span>:</font></div><div style="margin: 0px; "><font face="Courier New"> profiles = api.quantum.profile_list(request, <span style="color: #00b400"><i>'policy'</i></span>)</font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #0433ff">for</span> p <span style="color: #0433ff">in</span> profiles:</font></div><div style="margin: 0px; "><font face="Courier New"> p.set_id_as_name_if_empty()</font></div><div style="margin: 0px; "><font face="Courier New"> profile_list = [(p.id, p.name) <span style="color: #0433ff">for</span> p <span style="color: #0433ff">in</span> profiles]</font></div><div style="margin: 0px; "><font face="Courier New"> LOG.error(<span style="color: #00b400"><i>"PCM Populating PROFILES: %s"</i></span> % profile_list)</font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #0433ff">except</span>:</font></div><div style="margin: 0px; "><font face="Courier New"> profile_list = []</font></div><div style="margin: 0px; "><font face="Courier New"> exceptions.handle(request, _(<span style="color: #00b400"><i>"Unable to retrieve profiles."</i></span>))</font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #0433ff">return</span> profile_list</font></div><div style="margin: 0px; min-height: 12px; "><font face="Courier New"><br></font></div><div style="margin: 0px; min-height: 12px; "><font face="Courier New"><br></font></div><div style="margin: 0px; "><font face="Courier New"><span style="color: #0433ff">class</span> <b>SetNetwork</b>(workflows.Step):</font></div><div style="margin: 0px; "><font face="Courier New"> action_class = SetNetworkAction</font></div><div style="margin: 0px; color: rgb(0, 180, 0); "><font face="Courier New"><span style="color: #000000"> template_name = </span><i>"project/instances/_update_networks.html"</i></font></div><div style="margin: 0px; color: rgb(0, 180, 0); "><font face="Courier New"><span style="color: #000000"> contributes = (</span><i>"network_id"</i><span style="color: #000000">, </span><i>"profile_id"</i><span style="color: #000000">)</span></font></div><div style="margin: 0px; min-height: 12px; "><font face="Courier New"><br></font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #0433ff">def</span> <b>contribute</b>(<i>self</i>, data, context):</font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #0433ff">if</span> data:</font></div><div style="margin: 0px; "><font face="Courier New"> networks = <i>self</i>.workflow.request.POST.getlist(<span style="color: #00b400"><i>"network"</i></span>)</font></div><div style="margin: 0px; color: rgb(203, 203, 203); "><font face="Courier New"><span style="color: #000000"> </span># If no networks are explicitly specified, network list</font></div><div style="margin: 0px; color: rgb(203, 203, 203); "><font face="Courier New"><span style="color: #000000"> </span># contains an empty string, so remove it.</font></div><div style="margin: 0px; "><font face="Courier New"> networks = [n <span style="color: #0433ff">for</span> n <span style="color: #0433ff">in</span> networks <span style="color: #0433ff">if</span> n != <span style="color: #00b400"><i>''</i></span>]</font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #0433ff">if</span> networks:</font></div><div style="margin: 0px; "><font face="Courier New"> context[<span style="color: #00b400"><i>'network_id'</i></span>] = networks</font></div><div style="margin: 0px; min-height: 12px; "><font face="Courier New"><br></font></div><div style="margin: 0px; "><font face="Courier New"> profiles = <i>self</i>.workflow.request.POST.getlist(<span style="color: #00b400"><i>"profile"</i></span>)</font></div><div style="margin: 0px; color: rgb(203, 203, 203); "><font face="Courier New"><span style="color: #000000"> </span># If no profiles are explicitly specified, profile list</font></div><div style="margin: 0px; color: rgb(203, 203, 203); "><font face="Courier New"><span style="color: #000000"> </span># contains an empty string, so remove it.</font></div><div style="margin: 0px; "><font face="Courier New"> profiles = [p <span style="color: #0433ff">for</span> p <span style="color: #0433ff">in</span> profiles <span style="color: #0433ff">if</span> p != <span style="color: #00b400"><i>''</i></span>]</font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #0433ff">if</span> profiles:</font></div><div style="margin: 0px; "><font face="Courier New"> context[<span style="color: #00b400"><i>'profile_id'</i></span>] = profiles</font></div><div style="margin: 0px; "><font face="Courier New"> LOG.debug(<span style="color: #00b400"><i>"PCM at contribute %d - %d"</i></span> %(len(networks), len(profiles)))</font></div><div style="margin: 0px; "><font face="Courier New"> <span style="color: #0433ff">return</span> context</font></div><div style="margin: 0px; "><font face="Courier New"> ...</font></div><div style="margin: 0px; min-height: 12px; "><font face="Courier New"><br></font></div><div style="margin: 0px; min-height: 12px; ">I do see the populate functions called and there is data there. In the HTML template, I modified the row for the Policy Profile from using a "{{form.profile }}" to having the same code as the Network list field has. I created identical CSS definitions for the profile styles. Code looks like this:</div><div style="margin: 0px; min-height: 12px; "><br></div><div style="margin: 0px; min-height: 12px; "><div style="margin: 0px; "><font face="Courier New"><table class="table-fixed" id="networkListSortContainer"></font></div><div style="margin: 0px; "><font face="Courier New"> <tbody></font></div><div style="margin: 0px; "><font face="Courier New"> <tr></font></div><div style="margin: 0px; "><font face="Courier New"> <td class="actions"></font></div><div style="margin: 0px; "><font face="Courier New"> <h4 id="selected_network_h4">{% <span style="text-decoration: underline ; color: #4d4d4d">trans</span> "Selected Networks" %}</h4></font></div><div style="margin: 0px; "><font face="Courier New"> <ul id="selected_network" class="<span style="text-decoration: underline ; color: #4d4d4d">networklist</span>"></font></div><div style="margin: 0px; "><font face="Courier New"> </ul></font></div><div style="margin: 0px; "><font face="Courier New"> <h4>{% <span style="text-decoration: underline ; color: #4d4d4d">trans</span> "Available networks" %}</h4></font></div><div style="margin: 0px; "><font face="Courier New"> <ul id="available_network" class="<span style="text-decoration: underline ; color: #4d4d4d">networklist</span>"></font></div><div style="margin: 0px; "><font face="Courier New"> </ul></font></div><div style="margin: 0px; "><font face="Courier New"> </td></font></div><div style="margin: 0px; "><font face="Courier New"> <td class="help_text"></font></div><div style="margin: 0px; "><font face="Courier New"> {% include "project/instances/_launch_network_help.html" %}</font></div><div style="margin: 0px; "><font face="Courier New"> </td></font></div><div style="margin: 0px; "><font face="Courier New"> </tr></font></div><p style="margin: 0px; min-height: 12px; "><font face="Courier New"> <br class="webkit-block-placeholder"></font></p><div style="margin: 0px; "><font face="Courier New"> <tr></font></div><div style="margin: 0px; "><font face="Courier New"> <td class="actions"></font></div><div style="margin: 0px; "><font face="Courier New"> <h4 id="selected_profile_h4">{% <span style="text-decoration: underline ; color: #4d4d4d">trans</span> "Selected Profiles" %}</h4></font></div><div style="margin: 0px; "><font face="Courier New"> <ul id="selected_profile" class="<span style="text-decoration: underline ; color: #4d4d4d">profilelist</span>"></font></div><div style="margin: 0px; "><font face="Courier New"> </ul></font></div><div style="margin: 0px; "><font face="Courier New"> <h4>{% <span style="text-decoration: underline ; color: #4d4d4d">trans</span> "Available profiles" %}</h4></font></div><div style="margin: 0px; "><font face="Courier New"> <ul id="available_profile" class="<span style="text-decoration: underline ; color: #4d4d4d">profilelist</span>"></font></div><div style="margin: 0px; "><font face="Courier New"> </ul></font></div><div style="margin: 0px; "><font face="Courier New"> </td></font></div><div style="margin: 0px; "><font face="Courier New"> <td class="help_text"></font></div><div style="margin: 0px; "><font face="Courier New"> {% include "project/instances/_launch_profile_help.html" %}</font></div><div style="margin: 0px; "><font face="Courier New"> </td></font></div><div style="margin: 0px; "><font face="Courier New"> </tr></font></div><div style="margin: 0px; "><font face="Courier New"> </tbody></font></div><div style="margin: 0px; "><font face="Courier New"></table></font></div><div><br></div></div><div style="margin: 0px; min-height: 12px; "><br></div><div style="margin: 0px; min-height: 12px; ">When I try this, I see the choices for the "Available Networks" and I can drag and drop them to the "Selected Networks", but the "Available Profiles" list is empty. No box or anything shown, just the h4 headings. I did try having a second table, with id profileListSortedContainer, but the same results occurred.</div><div style="margin: 0px; min-height: 12px; "><br></div><div style="margin: 0px; min-height: 12px; ">BTW, if I rename the populate_network_choices to populate_policy_choices, and vice versa, I see the list of policies in the "Available Networks" and nothing still in the "Available Policies" field.</div><div style="margin: 0px; min-height: 12px; "><br></div><div style="margin: 0px; min-height: 12px; ">What am I missing/doing wrong, such that the policy choices information is not being filled out in the template?</div><div style="margin: 0px; min-height: 12px; "><br></div><div style="margin: 0px; min-height: 12px; ">How does the populate_policy_choices info get used in the template. I'm missing that part of things?</div><div style="margin: 0px; min-height: 12px; "><br></div><div style="margin: 0px; min-height: 12px; ">At a higher level, is there a better way to relate these two fields? I still need to verify that for each network there needs to be one policy, and whether or not the policy choice needs to be unique (as in not having the same policy for multiple networks - which MAY be allowed - I need to check).</div><div style="margin: 0px; min-height: 12px; "><br></div><div style="margin: 0px; min-height: 12px; ">Thanks in advance!</div><div style="margin: 0px; min-height: 12px; "><br></div><div style="margin: 0px; font-size: 10px; min-height: 12px; "><br></div><div style="margin: 0px; font-size: 10px; min-height: 12px; "><br></div><div apple-content-edited="true">
<span class="Apple-style-span" style="border-collapse: separate; color: rgb(0, 0, 0); font-family: Helvetica; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; font-size: medium; "><div>PCM (Paul Michali)</div><div><br></div><div>MAIL <a href="mailto:pcm@cisco.com">pcm@cisco.com</a></div><div>IRC pcm_ (<a href="http://irc.freenode.net">irc.freenode.net</a>)</div><div>TW @pmichali</div></span>
</div>
<br></div></body></html>