Properly compute network mask:
authorFrantišek Dvořák <valtri@civ.zcu.cz>
Tue, 6 Sep 2016 20:23:48 +0000 (22:23 +0200)
committerFrantišek Dvořák <valtri@civ.zcu.cz>
Tue, 6 Sep 2016 20:23:48 +0000 (22:23 +0200)
* ignore SIZE parameter - used only by OpenNebula
* consider NETWORK_MASK parameter
* default prefix is 24 (IPv4) or 64 (IPv6)

lib/nebula.rb
spec/nebula/get_spec.rb
spec/nebula/network-mask1.xml [new file with mode: 0644]
spec/nebula/network-mask2.xml [new file with mode: 0644]

index 3e76c54..a6a5952 100644 (file)
@@ -114,44 +114,64 @@ module Now
       raise NowError.new(code), return_code.message
     end
 
-    def parse_range(vn_id, ar)
-      id = ar['AR_ID']
+    def parse_range(vn_id, vn, ar)
+      id = ar['AR_ID'] || '(undef)'
       type = ar['TYPE']
-      size = ar['SIZE']
+      ip = ar['NETWORK_ADDRESS'] || vn['NETWORK_ADDRESS']
+      mask = ar['NETWORK_MASK'] || vn['NETWORK_MASK']
+
       case type
       when 'IP4'
         ip = ar['IP']
-        addr_size = 32
         if ip.nil? || ip.empty?
           raise NowError.new(422), "Missing 'IP' in the address range #{id} of network #{vn_id}"
         end
+        address = IPAddress ip
+        if !ip.include? '/'
+          address.prefix = 24
+        end
       when 'IP6', 'IP4_6'
         ip = ar['GLOBAL_PREFIX'] || ar['ULA_PREFIX']
-        addr_size = 128
         if ip.nil? || ip.empty?
           raise NowError.new(422), "Missing 'GLOBAL_PREFIX' in the address range #{id} of network #{vn_id}"
         end
+        address = IPAddress ip
+        if !ip.include? '/'
+          address.prefix = 64
+        end
+      when nil
+        if ip.nil? || ip.empty?
+          raise NowError.new(422), "No address range and no NETWORK_ADDRESS in the network #{vn_id}"
+        end
+        address = IPAddress ip
       else
         raise NowError.new(501), "Unknown type '#{type}' in the address range #{id} of network #{vn_id}"
       end
-      if size.nil? || size.empty?
-        raise NowError.new(422), "Missing 'SIZE' in the address range #{id} of network #{vn_id}"
+
+      # get the mask from NETWORK_MASK network parameter, if IP not in CIDR notation already
+      if !ip.include? '/'
+        if mask && !mask.empty?
+          if /\d+\.\d+\.\d+\.\d+/.match(mask)
+            address.netmask = mask
+          else
+            address.prefix = mask.to_i
+          end
+        end
       end
-      size = size.to_i
-      mask = addr_size - Math.log(size, 2).ceil
-      logger.debug "[parse_range] id=#{id}, address=#{ip}/#{mask} (size #{size})"
 
-      return Now::Range.new(address: IPAddress.parse("#{ip}/#{mask}"), allocation: 'dynamic')
+      logger.debug "[parse_range] network id=#{vn_id}, address=#{address.to_string}"
+      return Now::Range.new(address: address, allocation: 'dynamic')
     end
 
     def parse_ranges(vn_id, vn)
-      range = nil
-      vn.each('AR_POOL/AR') do |ar|
-        if !range.nil?
+      ar = nil
+      vn.each('AR_POOL/AR') do |a|
+        if !ar.nil?
           raise NowError.new(501), "Multiple address ranges found in network #{vn_id}"
         end
-        range = parse_range(vn_id, ar)
+        ar = a
       end
+      range = parse_range(vn_id, vn, ar)
       return range
     end
 
index c5e6825..94eb280 100644 (file)
@@ -5,6 +5,8 @@ describe 'network get' do
   net1 = l('network-example')
   net6a = l('network-ipv6-global')
   net6b = l('network-ipv6-local')
+  net_mask1 = l('network-mask1')
+  net_mask2 = l('network-mask2')
   nebula_base = Now::Nebula.new('opennebula' => { 'endpoint' => 'myendpoint' })
 
   context 'example' do
@@ -54,8 +56,6 @@ describe 'network get' do
 
       expect(network.id).to eq(id)
       expect(network.title).to eq('vx1')
-      #FIXME
-      pending('do not use size for netmask')
       expect(network.range).to eq(range)
     end
   end
@@ -76,7 +76,46 @@ describe 'network get' do
 
       expect(network.id).to eq(id)
       expect(network.title).to eq('vx2')
-      pending('do not use size for netmask')
+      expect(network.range).to eq(range)
+    end
+  end
+
+  context 'mask1' do
+    let(:client) do
+      instance_double('client', call: net_mask1)
+    end
+    let(:nebula) do
+      nebula_base.ctx = client
+      nebula_base
+    end
+    let(:id) { 0 }
+    let(:range) { Now::Range.new(address: IPAddress.parse('192.168.0.4/24'), allocation: 'dynamic') }
+
+    it 'get' do
+      network = nebula.get(id)
+
+      expect(network.id).to eq(id)
+      expect(network.title).to eq('example')
+      expect(network.range).to eq(range)
+    end
+  end
+
+  context 'mask2' do
+    let(:client) do
+      instance_double('client', call: net_mask2)
+    end
+    let(:nebula) do
+      nebula_base.ctx = client
+      nebula_base
+    end
+    let(:id) { 0 }
+    let(:range) { Now::Range.new(address: IPAddress.parse('192.168.0.4/24'), allocation: 'dynamic') }
+
+    it 'get' do
+      network = nebula.get(id)
+
+      expect(network.id).to eq(id)
+      expect(network.title).to eq('example')
       expect(network.range).to eq(range)
     end
   end
diff --git a/spec/nebula/network-mask1.xml b/spec/nebula/network-mask1.xml
new file mode 100644 (file)
index 0000000..5f83e0d
--- /dev/null
@@ -0,0 +1,54 @@
+<VNET>
+  <ID>0</ID>
+  <UID>0</UID>
+  <GID>1</GID>
+  <UNAME>oneadmin</UNAME>
+  <GNAME>users</GNAME>
+  <NAME>example</NAME>
+  <PERMISSIONS>
+    <OWNER_U>1</OWNER_U>
+    <OWNER_M>1</OWNER_M>
+    <OWNER_A>1</OWNER_A>
+    <GROUP_U>1</GROUP_U>
+    <GROUP_M>0</GROUP_M>
+    <GROUP_A>0</GROUP_A>
+    <OTHER_U>0</OTHER_U>
+    <OTHER_M>0</OTHER_M>
+    <OTHER_A>0</OTHER_A>
+  </PERMISSIONS>
+  <CLUSTERS>
+    <ID>0</ID>
+  </CLUSTERS>
+  <BRIDGE><![CDATA[br0]]></BRIDGE>
+  <PARENT_NETWORK_ID/>
+  <VN_MAD><![CDATA[ebtables]]></VN_MAD>
+  <PHYDEV/>
+  <VLAN_ID/>
+  <VLAN_ID_AUTOMATIC/>
+  <USED_LEASES>3</USED_LEASES>
+  <VROUTERS/>
+  <TEMPLATE>
+    <BRIDGE><![CDATA[br0]]></BRIDGE>
+    <DNS><![CDATA[192.168.0.1]]></DNS>
+    <GATEWAY><![CDATA[192.168.0.1]]></GATEWAY>
+    <NETWORK_ADDRESS><![CDATA[192.168.0.0]]></NETWORK_ADDRESS>
+    <NETWORK_MASK><![CDATA[255.255.255.0]]></NETWORK_MASK>
+    <PHYDEV><![CDATA[]]></PHYDEV>
+    <SECURITY_GROUPS><![CDATA[0]]></SECURITY_GROUPS>
+    <TYPE><![CDATA[RANGED]]></TYPE>
+    <VN_MAD><![CDATA[ebtables]]></VN_MAD>
+  </TEMPLATE>
+  <AR_POOL>
+    <AR>
+      <AR_ID><![CDATA[0]]></AR_ID>
+      <IP><![CDATA[192.168.0.4]]></IP>
+      <MAC><![CDATA[02:00:c0:a8:00:04]]></MAC>
+      <SIZE><![CDATA[251]]></SIZE>
+      <TYPE><![CDATA[IP4]]></TYPE>
+      <MAC_END><![CDATA[02:00:c0:a8:00:fe]]></MAC_END>
+      <IP_END><![CDATA[192.168.0.254]]></IP_END>
+      <USED_LEASES>3</USED_LEASES>
+      <LEASES/>
+    </AR>
+  </AR_POOL>
+</VNET>
diff --git a/spec/nebula/network-mask2.xml b/spec/nebula/network-mask2.xml
new file mode 100644 (file)
index 0000000..8c95580
--- /dev/null
@@ -0,0 +1,53 @@
+<VNET>
+  <ID>0</ID>
+  <UID>0</UID>
+  <GID>1</GID>
+  <UNAME>oneadmin</UNAME>
+  <GNAME>users</GNAME>
+  <NAME>example</NAME>
+  <PERMISSIONS>
+    <OWNER_U>1</OWNER_U>
+    <OWNER_M>1</OWNER_M>
+    <OWNER_A>1</OWNER_A>
+    <GROUP_U>1</GROUP_U>
+    <GROUP_M>0</GROUP_M>
+    <GROUP_A>0</GROUP_A>
+    <OTHER_U>0</OTHER_U>
+    <OTHER_M>0</OTHER_M>
+    <OTHER_A>0</OTHER_A>
+  </PERMISSIONS>
+  <CLUSTERS>
+    <ID>0</ID>
+  </CLUSTERS>
+  <BRIDGE><![CDATA[br0]]></BRIDGE>
+  <PARENT_NETWORK_ID/>
+  <VN_MAD><![CDATA[ebtables]]></VN_MAD>
+  <PHYDEV/>
+  <VLAN_ID/>
+  <VLAN_ID_AUTOMATIC/>
+  <USED_LEASES>3</USED_LEASES>
+  <VROUTERS/>
+  <TEMPLATE>
+    <BRIDGE><![CDATA[br0]]></BRIDGE>
+    <DNS><![CDATA[192.168.0.1]]></DNS>
+    <GATEWAY><![CDATA[192.168.0.1]]></GATEWAY>
+    <NETWORK_ADDRESS><![CDATA[192.168.0.0/24]]></NETWORK_ADDRESS>
+    <PHYDEV><![CDATA[]]></PHYDEV>
+    <SECURITY_GROUPS><![CDATA[0]]></SECURITY_GROUPS>
+    <TYPE><![CDATA[RANGED]]></TYPE>
+    <VN_MAD><![CDATA[ebtables]]></VN_MAD>
+  </TEMPLATE>
+  <AR_POOL>
+    <AR>
+      <AR_ID><![CDATA[0]]></AR_ID>
+      <IP><![CDATA[192.168.0.4]]></IP>
+      <MAC><![CDATA[02:00:c0:a8:00:04]]></MAC>
+      <SIZE><![CDATA[251]]></SIZE>
+      <TYPE><![CDATA[IP4]]></TYPE>
+      <MAC_END><![CDATA[02:00:c0:a8:00:fe]]></MAC_END>
+      <IP_END><![CDATA[192.168.0.254]]></IP_END>
+      <USED_LEASES>3</USED_LEASES>
+      <LEASES/>
+    </AR>
+  </AR_POOL>
+</VNET>