[Ovirt-devel] [PATCH server] permit many-to-many vms / networks relationship redux (frontend changes)

Mohammed Morsi mmorsi at redhat.com
Fri Jul 24 21:01:36 UTC 2009


implements changes to the views, helpers, and css
to permit vms to be associated with multiple networks.
---
 src/app/views/host/show.rhtml         |    2 +-
 src/app/views/network/_select.rhtml   |    2 +-
 src/app/views/network/edit_nic.rhtml  |    4 +-
 src/app/views/nic/show.rhtml          |    2 +
 src/app/views/task/_user_list.rhtml   |    2 +-
 src/app/views/vm/_form.rhtml          |  216 +++++++++++++++++++++++++++++++--
 src/app/views/vm/_grid.rhtml          |    1 -
 src/app/views/vm/_list.rhtml          |    2 -
 src/app/views/vm/show.rhtml           |    6 +-
 src/public/stylesheets/components.css |   42 ++++++-
 10 files changed, 261 insertions(+), 18 deletions(-)

diff --git a/src/app/views/host/show.rhtml b/src/app/views/host/show.rhtml
index f706761..ddc6481 100644
--- a/src/app/views/host/show.rhtml
+++ b/src/app/views/host/show.rhtml
@@ -64,7 +64,7 @@
 	<%=h @host.status_str %><br/>
 	<%=  @host.nics.collect{ |n|
                 n.interface_name.to_s + " " + n.mac +
-                (n.physical_network.nil? ? "" : " " + n.physical_network.name)
+                (n.network.nil? ? "" : " " + n.network.name)
               }.join("<br/>")
         %><br/>
 	<%=  @host.bondings.collect { |n| n.name }.join("<br/>") %><br/>
diff --git a/src/app/views/network/_select.rhtml b/src/app/views/network/_select.rhtml
index 4d056df..47ab319 100644
--- a/src/app/views/network/_select.rhtml
+++ b/src/app/views/network/_select.rhtml
@@ -1,5 +1,5 @@
 <% target = 'nic' unless target
-   network_id = 'physical_network_id' if target == 'nic'
+   network_id = 'network_id' if target == 'nic'
    network_id = 'vlan_id' if target == 'bonding'
 
  %>
diff --git a/src/app/views/network/edit_nic.rhtml b/src/app/views/network/edit_nic.rhtml
index 1b58c20..e458ff2 100644
--- a/src/app/views/network/edit_nic.rhtml
+++ b/src/app/views/network/edit_nic.rhtml
@@ -6,10 +6,12 @@
 
  <%= error_messages_for 'nic' %>
 
+ <%# TODO doesn't currently break anything due to where this form is displayed
+     but @nic.host assumption should be removed so this template can be included elsewhere %>
  <div id="selected_popup_content_expanded" class="dialog_form">
   <%= hidden_field_tag 'id', @nic.id %>
   <%= hidden_field_tag 'nic_host_id', @nic.host.id %>
-  <%= hidden_field_tag 'nic_network_id', @nic.physical_network.id if @nic.physical_network %>
+  <%= hidden_field_tag 'nic_network_id', @nic.network.id if @nic.network %>
 
   <div class="selected_popup_content_left">MAC:</div>
   <div class="selected_popup_content_right"><%= @nic.mac %></div>
diff --git a/src/app/views/nic/show.rhtml b/src/app/views/nic/show.rhtml
index 0bd3910..aaee67a 100644
--- a/src/app/views/nic/show.rhtml
+++ b/src/app/views/nic/show.rhtml
@@ -7,6 +7,8 @@
 </p>
 <% end %>
 
+<%# TODO doesn't currently break anything due to where this form is displayed
+    but @nic.host assumption should be removed so thiw template can be included elsewhere %>
 <p><b>Host:</b> <%= link_to @nic.host.hostname, { :controller => "host", :action => "show", :id => @nic.host }, { :class => "show" } %></p>
 </div>
 
diff --git a/src/app/views/task/_user_list.rhtml b/src/app/views/task/_user_list.rhtml
index e289932..1506359 100644
--- a/src/app/views/task/_user_list.rhtml
+++ b/src/app/views/task/_user_list.rhtml
@@ -7,7 +7,7 @@
     <% for task in tasks %>
       <li class="task">
         <span class="secondary">action: </span><%= link_to task.action, { :controller => "task", :action => 'show', :id => task }, { :class => "action" } -%><br/>
-        <span class="secondary">vm: </span><%= link_to task.vm.description, { :controller => "vm",  :action => 'show', :id => task }, { :class => "description", :title => "cpus: %s mem: %s vNIC: %s" % [ task.vm.num_vcpus_used, task.vm.memory_used, task.vm.vnic_mac_addr ] } -%><br/>
+        <span class="secondary">vm: </span><%= link_to task.vm.description, { :controller => "vm",  :action => 'show', :id => task }, { :class => "description", :title => "cpus: %s mem: %s" % [ task.vm.num_vcpus_used, task.vm.memory_used ] } -%><br/>
         <span class="secondary">state: </span><span class="state"><%= task.state -%></span></li>
     <% end %>
     </ul>
diff --git a/src/app/views/vm/_form.rhtml b/src/app/views/vm/_form.rhtml
index 8373bf4..97b7188 100644
--- a/src/app/views/vm/_form.rhtml
+++ b/src/app/views/vm/_form.rhtml
@@ -50,19 +50,35 @@
   <div class="form_heading clickable closed">Network</div>
   <div class="vm_form_section" style="display:none;">
     <div class="clear_row"></div>
-    <div class="clear_row"></div>
-    <div style="float:left;">
-      <%= text_field_with_label "VNIC:", "vm", "vnic_mac_addr",  {:style=>"width:250;"} %>
-    </div>
-    <div style="float:left;">
-      <%= select_with_label "Network:", 'vm', 'network_id', @networks.insert(0, ""), :style=>"width:250px;" %>
-    </div>
+    <% if @nics.size > 0 %>
+      <div id="vm_network_config_header">
+        <div id="vm_network_config_header_network">
+          Network:
+        </div>
+        <div id="vm_network_config_header_mac">
+          MAC Address:
+        </div>
+        <div id="vm_network_config_header_ip">
+          <%# this column is only populated if a static ip network is selected: %>
+          IP Address:
+        </div>
+        <div class="clear_row"></div><div style="clear:both;"></div>
+      </div>
+        <%# populated with jquery below: %>
+        <div id="vm_network_config_networks"></div>
+        <div id="vm_network_config_add">
+          Add Another Network
+        </div>
+    <% else %>
+         <b>No networks available</b>
+    <% end %>
+    <div style="clear:both;"></div>
     <div class="clear_row"></div>
 
-    <%= check_box_tag_with_label "Forward vm's vnc port locally", "forward_vnc", 1, @vm.forward_vnc %>
   </div>
   <div class="clear_row"></div>
 
+   <div class="form_heading"/>
    <%= check_box_tag_with_label "Start VM Now? (pending current resource availability)", "start_now", nil if create or @vm.state == Vm::STATE_STOPPED %>
    <%= check_box_tag_with_label "Restart VM Now? (pending current resource availability)", "restart_now", nil if @vm.state == Vm::STATE_RUNNING %>
 
@@ -119,4 +135,188 @@ ${htmlList(pools, id)}
           }
       });
     });
+
+    /////////////////////////////////////////////////// vm networks config
+
+    // number of rows which we are currently displaying in net config
+    var vm_network_config_rows = 0;
+
+    // last row currently being displayed
+    var vm_network_config_last_row = 0;
+
+    // value of current selectbox
+    var current_selectbox_value = 0;
+
+    // create list of nics
+    var nics = new Array();
+    <% @nics.each { |rnic| %>
+     jnic = new Object;
+     jnic.network_id = "<%= rnic.network_id.to_s %>";
+     jnic.name = "<%= rnic.network.name %>";
+     jnic.mac  = "<%= rnic.mac %>";
+     jnic.ip   = "<%= rnic.ip_address %>";
+     jnic.static_ip   = <%= rnic.network.boot_type.proto == 'static' %>;
+     jnic.selected = false;
+     nics.push(jnic);
+    <% } %>
+
+    // adds unselected network back to selectboxes indicated by selector
+    function add_unselected_network(selector, network_id){
+        for(j = 0; j < nics.length; ++j){
+          if(nics[j].network_id == network_id){
+               nics[j].selected = false;
+               $(selector).append('<option value="' + nics[j].network_id + '">' + nics[j].name + '</option>');
+               break;
+          }
+        }
+    }
+
+    // show / hide ip address column
+    function toggle_ip_address_column(){
+       for(i = 0; i < nics.length; ++i){
+         if(nics[i].selected && nics[i].static_ip){
+            $('#vm_network_config_header_ip').show();
+            return;
+         }
+       }
+       $('#vm_network_config_header_ip').hide();
+    }
+
+    // show a new network config row
+    function add_network_config_row(no_remove_link){
+
+       // if the number of rows is equal to the number of
+       // networks, don't show any more rows
+       if(vm_network_config_rows == nics.length)
+          return;
+
+       vm_network_config_rows += 1;
+       vm_network_config_last_row = vm_network_config_rows;
+
+       // create the content for another row to be added to the vm_network_config_networks div above.
+       // currently a row has a network select box, a mac text field, and an ip address field if a static network is selected
+       var content = '<div id="vm_network_config_row_'+vm_network_config_rows+'" class="vm_network_config_row">';
+       content    += ' <div class="vm_network_config_net">';
+       content    += '   <select id="vm_network_config_network_select_'+vm_network_config_rows+'" class="vm_network_config_network_select">';
+       content    += '     <option value="">None</option>';
+       for(i = 0; i < nics.length; ++i){
+        if(!nics[i].selected)
+         content  += '     <option value="' + nics[i].network_id + '">' + nics[i].name + '</option>';
+       }
+       content    += '   </select>';
+       content    += ' </div>';
+       content    += ' <div id="vm_network_config_mac_'+vm_network_config_rows+'" class="vm_network_config_mac">';
+       content    +=  '  <input style="width: 130px;"></input>';
+       content    += ' </div>';
+       content    += ' <div id="vm_network_config_ip_'+vm_network_config_rows+'" class="vm_network_config_ip">';
+       content    += '     ';
+       content    += ' </div>';
+
+       if(!no_remove_link){
+         content  += ' <div id="vm_network_config_remove_'+vm_network_config_rows+'" class="vm_network_config_remove">';
+         content  += '  Remove';
+         content  += ' </div>';
+       }
+       content    += ' <div class="clear_row"></div><div class="clear_row"></div><div style="clear:both;"></div>';
+       content    += '</div>';
+
+       $('#vm_network_config_networks').append(content);
+
+       $('#vm_network_config_networks').ready(function(){
+         // when vm_network_config_remove link is click remove target row
+         $('#vm_network_config_remove_'+vm_network_config_rows).bind('click', function(e){
+             remove_network_config_row(e.target.id.substr(25)); // remove vm_network_config_remove_ bit to get row num
+         });
+
+         // when select box clicked, store current value for use on change
+         $('#vm_network_config_network_select_'+vm_network_config_rows).bind('click', function(e){
+            current_selectbox_value = e.target.value;
+         });
+
+         // when value of network select box is switched
+         $('#vm_network_config_network_select_'+vm_network_config_rows).bind('change', function(e){
+         row = e.target.id.substr(33)
+
+              // find nic w/ selected network id
+         for(i = 0; i < nics.length; ++i){
+           if(nics[i].network_id == e.target.value){
+              nics[i].selected = true;
+
+              // fill in mac / ip address textfields as necessary
+              $('#vm_network_config_mac_'+row).html('<input id="vm_network_config_mac_field_'+nics[i].network_id+'" style="width: 130px" value="'+nics[i].mac+'"/
+              if(nics[i].static_ip != ""){
+                $('#vm_network_config_ip_'+row).html('<input id="vm_network_config_ip_field_'+nics[i].ip+'" style="width: 130px" value="'+nics[i].ip+'"/>');
+              }else{
+                $('#vm_network_config_ip_'+row).html(' ');
+             }
+
+             // for the other select boxes, removed selected network
+             $('.vm_network_config_network_select:not(#vm_network_config_network_select_'+row+') option[@value='+nics[i].network_id+']').remove();
+
+             break;
+           }
+         }
+
+         // if we are clearing the row, do so
+         if(e.target.value == ""){
+           $('#vm_network_config_mac_'+row).html('<input id="vm_network_config_mac_field_'+row+'" style="width: 130px" value=""/>');
+           $('#vm_network_config_ip_'+row).html(' ');
+         }
+
+         // add unselected network back to other selectboxes.
+         add_unselected_network('.vm_network_config_network_select:not(#vm_network_config_network_select_'+row+')', current_selectbox_value);
+
+         // show / hide ip address column
+         toggle_ip_address_column();
+
+         // only add a new blank row if last row's select box was changed
+         if(e.target.value != "" && row == vm_network_config_last_row){
+           // add row
+           add_network_config_row();
+         }
+        });
+      });
+
+      // show / hide ip address column
+      toggle_ip_address_column();
+   }
+
+
+
+   // remove a network config row
+   function remove_network_config_row(row_num){
+      // if trying to remove the first row or a nonexistant one, fail to do so
+      if(row_num < 2 || row_num > vm_network_config_last_row)
+          return;
+
+      // get selected network, add it to other selectboxes
+      network_id = $('#vm_network_config_network_select_' + row_num).val();
+      add_unselected_network('.vm_network_config_network_select:not(#vm_network_config_network_select_'+row_num+')', network_id);
+
+      // remove the row
+      $('#vm_network_config_row_' + row_num).remove();
+
+      // when removed, set global params
+      $('#vm_network_config_networks').ready(function(){
+        vm_network_config_rows -= 1;
+        rows = $('#vm_network_config_networks').children();
+        vm_network_config_last_row = rows[rows.length - 1].id.substr(22);
+
+        // show / hide ip address column
+        toggle_ip_address_column();
+      });
+   }
+
+   // intially show only one vm network config row
+   $(document).ready(function(){
+      add_network_config_row(true);
+   });
+
+   // when vm_network_config_add link is clicked show new row
+   $('#vm_network_config_add').bind('click', function(){
+       // TODO check if there exists an empty row
+       // TODO check to see if we've already added as many rows as there are nets
+       add_network_config_row();
+   });
+
 </script>
diff --git a/src/app/views/vm/_grid.rhtml b/src/app/views/vm/_grid.rhtml
index a110011..e3fa0e0 100644
--- a/src/app/views/vm/_grid.rhtml
+++ b/src/app/views/vm/_grid.rhtml
@@ -34,7 +34,6 @@
         <% end %>
         {display: 'CPUs', name : 'num_vcpus_allocated', width : 40, sortable : true, align: 'left'},
         {display: 'Memory (MB)', name : 'memory_allocated', width : 60, sortable : true, align: 'right'},
-        {display: 'vNIC Mac Addr', name : 'vnic_mac_addr', width : 60, sortable : true, align: 'right'},
         {display: 'State', name : 'state', width : 50, sortable : true, align: 'right'},
         {display: 'Total Run Time', name : 'calc_uptime', width : 50, align: 'right'},
         {display: 'Load', name : 'load', width: 180, sortable : false, align: 'left', process: <%= table_id %>_load_widget }
diff --git a/src/app/views/vm/_list.rhtml b/src/app/views/vm/_list.rhtml
index 42300d6..54ae741 100644
--- a/src/app/views/vm/_list.rhtml
+++ b/src/app/views/vm/_list.rhtml
@@ -4,7 +4,6 @@
     <th class="empty">Description <span class="amp">&</span> UUID</th>
     <th>CPUs</th>
     <th>Memory (mb)</th>
-    <th>vNIC MAC Addr</th>
     <th>State</th>
   </thead>
   
@@ -15,7 +14,6 @@
     <td style="text-align:left"><%= link_to vm.description, { :controller => "vm", :action => 'show', :id => vm }, { :class => "show" } %><div class="secondary"><%= vm.uuid %></div></td>
     <td><%= vm.num_vcpus_allocated %></td>
     <td><%= vm.memory_allocated_in_mb %></td>
-    <td><%= vm.vnic_mac_addr %></td>
     <td style="text-align:left">
       <%= vm.state %>
       <%unless vm.needs_restart.nil? or vm.needs_restart == 0  -%>
diff --git a/src/app/views/vm/show.rhtml b/src/app/views/vm/show.rhtml
index ffe5055..1a3f81c 100644
--- a/src/app/views/vm/show.rhtml
+++ b/src/app/views/vm/show.rhtml
@@ -106,7 +106,7 @@
 	Num vcpus used:<br/>
 	Memory allocated:<br/>
 	Memory used:<br/>
-	vNIC MAC address:<br/>
+	vNIC MAC addresses:<br/>
 	Boot device:<br/>
         Provisioning source:<br/>
 	State:<br/>
@@ -122,7 +122,9 @@
        <%=h @vm.num_vcpus_used %><br/>
        <%=h @vm.memory_allocated_in_mb %> MB<br/>
        <%=h @vm.memory_used_in_mb %> MB<br/>
-       <%=h @vm.vnic_mac_addr %><br/>
+       <% nic_macs = ""
+          @vm.nics.each { |nic| nic_macs += nic.mac + " " } %>
+       <%=h nic_macs %><br/>
        <%=h @vm.boot_device %><br/>
        <%=h @vm.provisioning_and_boot_settings %><br/>
        <%=h @vm.state %>
diff --git a/src/public/stylesheets/components.css b/src/public/stylesheets/components.css
index 074cc09..3844611 100644
--- a/src/public/stylesheets/components.css
+++ b/src/public/stylesheets/components.css
@@ -339,4 +339,44 @@
   height: 11px;
 }
 
-.vm_form_section {padding-left: 2em;}
\ No newline at end of file
+.vm_form_section {padding-left: 2em;}
+
+#vm_network_config .i {
+  float: left;
+}
+
+#vm_network_config_header_network {
+  float: left;
+  width: 20%;
+}
+#vm_network_config_header_mac, #vm_network_config_header_ip{
+  float: left;
+  width: 33%;
+}
+
+.vm_network_config_net {
+  float: left;
+  width: 20%;
+}
+.vm_network_config_mac, .vm_network_config_ip{
+  float: left;
+  width: 33%;
+  min-width: 100px;
+}
+
+.vm_network_config_remove {
+  float: left;
+  padding-top: 5px;
+  color: #0033CC;
+}
+.vm_network_config_remove:hover {
+  cursor: pointer;
+}
+
+#vm_network_config_add {
+  color: #0033CC;
+}
+#vm_network_config_add:hover {
+  cursor: pointer;
+}
+
-- 
1.6.0.6




More information about the ovirt-devel mailing list