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

Mohammed Morsi mmorsi at redhat.com
Thu Jul 9 21:56:27 UTC 2009


  implements changes to the views, helpers, and css
  to permit vms to be associated with multiple networks.
---
 src/app/helpers/application_helper.rb |    4 +-
 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          |  217 +++++++++++++++++++++++++++++++--
 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 |   39 ++++++
 11 files changed, 261 insertions(+), 20 deletions(-)

diff --git a/src/app/helpers/application_helper.rb b/src/app/helpers/application_helper.rb
index d3eecd7..79d835c 100644
--- a/src/app/helpers/application_helper.rb
+++ b/src/app/helpers/application_helper.rb
@@ -78,9 +78,9 @@ module ApplicationHelper
   end
 
   # same as check_box_tag_with_label but w/ the checkbox appearing first
-  def rcheck_box_tag_with_label(label, name, value = "1", checked = false)
+  def rcheck_box_tag_with_label(label, name, value = "1", checked = false, opts={})
     %{
-      <div class="i">#{check_box_tag name, value, checked}
+      <div class="i">#{check_box_tag name, value, checked, opts}
       <label for="#{name}">#{_(label)}</label></div>
      }
   end
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..7f0bc02 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..46fb2c6 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 373452d..ead26e1 100644
--- a/src/app/views/vm/_form.rhtml
+++ b/src/app/views/vm/_form.rhtml
@@ -58,19 +58,36 @@
   </div>
   <div id="vm_network_config">
     <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>
-    <div class="clear_row"></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>
 
-    <%= rcheck_box_tag_with_label "Forward vm's vnc port locally", "forward_vnc", 1, @vm.forward_vnc %>
+        <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>
   </div>
   <div class="clear_row"></div>
 
+   <div class="form_heading"/>
    <%= rcheck_box_tag_with_label "Start VM Now? (pending current resource availability)", "start_now", nil if create or @vm.state == Vm::STATE_STOPPED %>
    <%= rcheck_box_tag_with_label "Restart VM Now? (pending current resource availability)", "restart_now", nil if @vm.state == Vm::STATE_RUNNING %>
 
@@ -135,4 +152,186 @@ ${htmlList(pools, id)}
      hide_section_with_header('#vm_network_config',   '#vm_network_section_link',   'Network');
    });
 
+   /////////////////////////////////////////////////// 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 b137de6..7ac3fdf 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: '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 0f70da8..a7a7388 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/>
@@ -121,7 +121,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 1409692..09f7b06 100644
--- a/src/public/stylesheets/components.css
+++ b/src/public/stylesheets/components.css
@@ -343,6 +343,45 @@
   padding-left: 30px;
 }
 
+#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;
+}
+
 #vm_general_section_link img, #vm_resources_section_link img, #vm_storage_section_link img, #vm_network_section_link img{
   float: left;
   padding-top: 2px;
-- 
1.6.0.6




More information about the ovirt-devel mailing list