[Ovirt-devel] [PATCH server] suggest ip address for nics/bondings on edit host/vm network forms

Mohammed Morsi mmorsi at redhat.com
Tue Nov 3 22:47:03 UTC 2009


Provides a mechanism to generate ip addresses for static networks
and prefill the 'ip address' fields of the host and vm networking
forms w/ the first suggested ip.
---
 src/app/controllers/vm_controller.rb  |    2 +-
 src/app/models/ip_address.rb          |   52 +++++++++++++++++++++++++++++++++
 src/app/models/network.rb             |   11 +++++++
 src/app/models/physical_network.rb    |    6 ++++
 src/app/models/vlan.rb                |    6 ++++
 src/app/services/host_service.rb      |    2 +
 src/app/views/host/edit_network.rhtml |    4 ++-
 src/test/unit/ip_address_test.rb      |   17 +++++++++++
 src/test/unit/network_test.rb         |   19 ++++++++++++
 9 files changed, 117 insertions(+), 2 deletions(-)

diff --git a/src/app/controllers/vm_controller.rb b/src/app/controllers/vm_controller.rb
index 9860843..c4ad7ce 100644
--- a/src/app/controllers/vm_controller.rb
+++ b/src/app/controllers/vm_controller.rb
@@ -193,7 +193,7 @@ class VmController < ApplicationController
     networks.each{ |net|
         nnic = Nic.new(:mac => Nic::gen_mac, :network => net)
         if(net.boot_type.proto == 'static')
-           nnic.ip_addresses << IpAddress.new(:address => '127.0.0.1') # FIXME
+           nnic.ip_addresses << IpAddress.new(:address => net.gen_address)
         end
         @nics.push nnic
     }
diff --git a/src/app/models/ip_address.rb b/src/app/models/ip_address.rb
index 13f5d19..2909e4e 100644
--- a/src/app/models/ip_address.rb
+++ b/src/app/models/ip_address.rb
@@ -17,6 +17,8 @@
 # MA  02110-1301, USA.  A copy of the GNU General Public License is
 # also available at http://www.gnu.org/copyleft/gpl.html.
 
+require 'ipaddr'
+
 # +IpAddress+ is the base class for all address related classes.
 #
 class IpAddress < ActiveRecord::Base
@@ -35,4 +37,54 @@ class IpAddress < ActiveRecord::Base
       raise ArgumentError("Invalid type #{params[:type]}")
     end
   end
+
+  # get the range of valid addresses for this network address
+  def range
+     # exclude the gateway and broadcast addresses
+     # associated w/ this ip address
+     sgatewayi = IPAddr.new(gateway).to_i
+     sbcasti = IPAddr.new(broadcast).to_i
+
+     addresses = []
+     _numeric_range.each { |i| # this can be a big performance hit
+                               # depending on your network / mask
+        unless i == sgatewayi || i == sbcasti
+           addresses.push IPAddr.new(i, Socket::AF_INET).to_s
+        end
+     }
+
+     addresses
+  end
+
+  # get first available address for this network address given list
+  # of addresses already used
+  def first_available_address(used_addresses)
+     # exclude the gateway and broadcast addresses
+     # associated w/ this ip address
+     sgatewayi = IPAddr.new(gateway).to_i
+     sbcasti = IPAddr.new(broadcast).to_i
+
+     _numeric_range.each { |i|
+        ip = IPAddr.new(i, Socket::AF_INET).to_s
+        unless i == sgatewayi || i == sbcasti || used_addresses.include?(ip)
+          return ip
+        end
+     }
+
+     nil
+  end
+
+ private
+  # internal helper method, get the range of numeric addresses for this
+  # network address
+  def _numeric_range
+     return [] unless network_id != nil
+     netaddress_ip = IPAddr.new(address)
+     netmask_ip = IPAddr.new(netmask)
+     firstaddress = netaddress_ip.to_i + 1
+     lastaddress = netaddress_ip.to_i + (~netmask_ip).to_i - 1
+     (firstaddress...lastaddress+1)
+  end
+
+
 end
diff --git a/src/app/models/network.rb b/src/app/models/network.rb
index 22e5692..c9d5d84 100644
--- a/src/app/models/network.rb
+++ b/src/app/models/network.rb
@@ -42,5 +42,16 @@ class Network < ActiveRecord::Base
     end
   end
 
+  # return true / false if network has statically assigned ips
+  def is_static?
+     !boot_type.nil? && boot_type.proto == "static"
+  end
+
+  # generate an ip address for this network based on the
+  # associated IpAddress and specified array of addreses already used
+  def gen_address(used_addresses = [])
+     return nil if ip_addresses.nil? || ip_addresses.size == 0
+     ip_addresses[0].first_available_address(used_addresses)
+  end
 
 end
diff --git a/src/app/models/physical_network.rb b/src/app/models/physical_network.rb
index f50eeff..17a325e 100644
--- a/src/app/models/physical_network.rb
+++ b/src/app/models/physical_network.rb
@@ -20,4 +20,10 @@ class PhysicalNetwork < Network
   def is_destroyable?
     nics.empty?
   end
+
+  # generate an ip address for this network based on associated ip and
+  # addresses already associated w/ nics
+  def gen_address
+    super(nics.collect { |n| n.ip_address})
+  end
 end
diff --git a/src/app/models/vlan.rb b/src/app/models/vlan.rb
index e34dddc..ca80dfc 100644
--- a/src/app/models/vlan.rb
+++ b/src/app/models/vlan.rb
@@ -26,6 +26,12 @@ class Vlan < Network
     bondings.empty? && nics.empty?
   end
 
+  # generate an ip address for this network based on associated ip and
+  # addresses already associated w/ bondings/nics
+  def gen_address
+    super(bondings.collect { |b| b.ip_address } + nics.collect { |n| n.ip_address})
+  end
+
   protected
    def validate
      # ensure that any assigned nics only belong to vms, not hosts
diff --git a/src/app/services/host_service.rb b/src/app/services/host_service.rb
index 3b59f0e..e6b2810 100644
--- a/src/app/services/host_service.rb
+++ b/src/app/services/host_service.rb
@@ -73,6 +73,8 @@ module HostService
   def svc_modify(id)
     lookup(id, Privilege::MODIFY)
     @networks = Network.find(:all)
+    @suggested_ips = {}
+    @networks.each { |n| @suggested_ips[n.id] = n.gen_address }
     @bonding_types = BondingType.find(:all)
   end
 
diff --git a/src/app/views/host/edit_network.rhtml b/src/app/views/host/edit_network.rhtml
index 1154595..2b22a7c 100644
--- a/src/app/views/host/edit_network.rhtml
+++ b/src/app/views/host/edit_network.rhtml
@@ -241,6 +241,7 @@
     jnet.static_ip  = <%= rnet.boot_type.proto == 'static' %>;
     jnet.boot_type  = "<%= rnet.boot_type.proto %>";
     jnet.selected = false;
+    jnet.suggested_ip = "<%= @suggested_ips[rnet.id] %>";
     networks.push(jnet);
   <% } %>
 
@@ -380,7 +381,8 @@
       div.children("input").removeAttr("disabled");
 
       // grab value of address field from device
-      address = device ? device.ip_address : "";
+      address = (device && (device.ip_address != "")) ?
+                 device.ip_address : network.suggested_ip;
       div.children("input").val(address);
 
     // for non-static networks disable/hide ip address textbox
diff --git a/src/test/unit/ip_address_test.rb b/src/test/unit/ip_address_test.rb
index 89972ad..f0aa96b 100644
--- a/src/test/unit/ip_address_test.rb
+++ b/src/test/unit/ip_address_test.rb
@@ -17,4 +17,21 @@ class IpAddressTest < ActiveSupport::TestCase
 #    this networking is in flux.  Revisit this test once that stabilizes.
      flunk "Ip Address must be associated with network, nic, or bonding" unless @ip_address.valid?
   end
+
+  def test_ip_address_range
+     ipv4addr = IpV4Address.new :address => '1.2.3.0',
+                                :netmask => '255.255.255.0',
+                                :gateway => '1.2.3.1',
+                                :broadcast => '1.2.3.255',
+                                :network_id => 5
+
+    range = ipv4addr.range
+
+    assert_equal 253, range.size
+    assert !range.include?("1.2.3.1")
+    assert !range.include?("1.2.3.255")
+    (2...255).each { |i|
+      assert range.include?("1.2.3." + i.to_s)
+    }
+  end
 end
diff --git a/src/test/unit/network_test.rb b/src/test/unit/network_test.rb
index 73ea7eb..e9aa0d6 100644
--- a/src/test/unit/network_test.rb
+++ b/src/test/unit/network_test.rb
@@ -66,4 +66,23 @@ class NetworkTest < ActiveSupport::TestCase
    vl.bondings.push Bonding.new
    flunk "Vlan with bondings should not be destroyable" if vl.is_destroyable?
   end
+
+  def test_gen_physical_net_address
+    net = networks :static_physical_network_one
+    addr = net.gen_address
+
+    assert net.ip_addresses[0].address != addr
+    assert net.ip_addresses[0].netmask != addr
+    assert net.ip_addresses[0].broadcast != addr
+    assert net.ip_addresses[0].gateway != addr
+    net.nics.each { |nic|
+      assert nic.ip_address != addr
+    }
+
+   addri  = IPAddr.new(addr).to_i
+   naddri = IPAddr.new(net.ip_addresses[0].address).to_i
+   baddri = naddri + (~IPAddr.new(net.ip_addresses[0].netmask)).to_i
+   assert addri > naddri
+   assert addri < baddri
+  end
 end
-- 
1.6.2.5




More information about the ovirt-devel mailing list