← Back to team overview

cloud-init-dev team mailing list archive

[Merge] ~sw37th/cloud-init:fix_for_opennebula into cloud-init:master

 

Akihiko Ota has proposed merging ~sw37th/cloud-init:fix_for_opennebula into cloud-init:master.

Requested reviews:
  cloud-init commiters (cloud-init-dev)
Related bugs:
  Bug #1716397 in cloud-init: "OpenNebula network configuration is ignored for distros with predictable interface names."
  https://bugs.launchpad.net/cloud-init/+bug/1716397
  Bug #1719157 in cloud-init: "DataSourceOpenNebula.py doesn't configure network"
  https://bugs.launchpad.net/cloud-init/+bug/1719157
  Bug #1736750 in cloud-init: "DataSourceOpenNebula's get_mask() and get_network() return empty string"
  https://bugs.launchpad.net/cloud-init/+bug/1736750

For more details, see:
https://code.launchpad.net/~sw37th/cloud-init/+git/cloud-init/+merge/335217
-- 
Your team cloud-init commiters is requested to review the proposed merge of ~sw37th/cloud-init:fix_for_opennebula into cloud-init:master.
diff --git a/cloudinit/sources/DataSourceOpenNebula.py b/cloudinit/sources/DataSourceOpenNebula.py
index 5da1184..846fc9a 100644
--- a/cloudinit/sources/DataSourceOpenNebula.py
+++ b/cloudinit/sources/DataSourceOpenNebula.py
@@ -19,6 +19,7 @@ import string
 
 from cloudinit import log as logging
 from cloudinit import net
+from cloudinit.net import eni
 from cloudinit import sources
 from cloudinit import util
 
@@ -89,11 +90,18 @@ class DataSourceOpenNebula(sources.DataSource):
             return False
 
         self.seed = seed
-        self.network_eni = results.get("network_config")
+        self.network_eni = results.get('network-interfaces')
         self.metadata = md
         self.userdata_raw = results.get('userdata')
         return True
 
+    @property
+    def network_config(self):
+        if self.network_eni is not None:
+            return eni.convert_eni_data(self.network_eni)
+        else:
+            return None
+
     def get_hostname(self, fqdn=False, resolve_ip=None):
         if resolve_ip is None:
             if self.dsmode == sources.DSMODE_NETWORK:
@@ -118,6 +126,13 @@ class OpenNebulaNetwork(object):
             system_nics_by_mac = get_physical_nics_by_mac()
         self.ifaces = system_nics_by_mac
 
+        # device name used by context.sh
+        self.context_devname = {}
+        for k, v in context.items():
+            m = re.match(r'^(.+)_MAC$', k)
+            if m:
+                self.context_devname[v.lower()] = m.group(1)
+
     def mac2ip(self, mac):
         components = mac.split(':')[2:]
         return [str(int(c, 16)) for c in components]
@@ -125,21 +140,30 @@ class OpenNebulaNetwork(object):
     def get_ip(self, dev, components):
         var_name = dev.upper() + '_IP'
         if var_name in self.context:
-            return self.context[var_name]
+            if self.context[var_name]:
+                return self.context[var_name]
+            else:
+                return '.'.join(components)
         else:
             return '.'.join(components)
 
     def get_mask(self, dev):
         var_name = dev.upper() + '_MASK'
         if var_name in self.context:
-            return self.context[var_name]
+            if self.context[var_name]:
+                return self.context[var_name]
+            else:
+                return '255.255.255.0'
         else:
             return '255.255.255.0'
 
     def get_network(self, dev, components):
         var_name = dev.upper() + '_NETWORK'
         if var_name in self.context:
-            return self.context[var_name]
+            if self.context[var_name]:
+                return self.context[var_name]
+            else:
+                return '.'.join(components[:-1]) + '.0'
         else:
             return '.'.join(components[:-1]) + '.0'
 
@@ -177,22 +201,31 @@ class OpenNebulaNetwork(object):
         for mac, dev in self.ifaces.items():
             ip_components = self.mac2ip(mac)
 
+            # set 'ETHx'
+            if mac.lower() in self.context_devname:
+                # for Predictable Network Interface Names
+                # 'ETHx' prefix has mapped to its MAC address
+                c_dev = self.context_devname[mac.lower()]
+            else:
+                # There is no variable ETHx_MAC in context.sh
+                c_dev = dev
+
             conf.append('auto ' + dev)
             conf.append('iface ' + dev + ' inet static')
-            conf.append('  address ' + self.get_ip(dev, ip_components))
-            conf.append('  network ' + self.get_network(dev, ip_components))
-            conf.append('  netmask ' + self.get_mask(dev))
+            conf.append('  address ' + self.get_ip(c_dev, ip_components))
+            conf.append('  network ' + self.get_network(c_dev, ip_components))
+            conf.append('  netmask ' + self.get_mask(c_dev))
 
-            gateway = self.get_gateway(dev)
+            gateway = self.get_gateway(c_dev)
             if gateway:
                 conf.append('  gateway ' + gateway)
 
-            domain = self.get_domain(dev)
+            domain = self.get_domain(c_dev)
             if domain:
                 conf.append('  dns-search ' + domain)
 
             # add global DNS servers to all interfaces
-            dns = self.get_dns(dev)
+            dns = self.get_dns(c_dev)
             if global_dns or dns:
                 all_dns = global_dns
                 if dns:

Follow ups