← Back to team overview

cloud-init-dev team mailing list archive

[Merge] lp:~i-franz/cloud-init/network-config-for-ovf into lp:cloud-init

 

Franz Schwartau has proposed merging lp:~i-franz/cloud-init/network-config-for-ovf into lp:cloud-init.

Requested reviews:
  cloud init development team (cloud-init-dev)

For more details, see:
https://code.launchpad.net/~i-franz/cloud-init/network-config-for-ovf/+merge/244467

Allow network configuration via OVF properties in DataSourceOVF.
Add handling for dhcphostname

-- 
Your team cloud init development team is requested to review the proposed merge of lp:~i-franz/cloud-init/network-config-for-ovf into lp:cloud-init.
=== modified file 'cloudinit/distros/net_util.py'
--- cloudinit/distros/net_util.py	2014-11-25 00:30:00 +0000
+++ cloudinit/distros/net_util.py	2014-12-11 16:27:59 +0000
@@ -133,6 +133,8 @@
             # really care about
             if proto_type in ['dhcp', 'static']:
                 iface_info['bootproto'] = proto_type
+            if proto_type == 'dhcp' and 'hostname' in info:
+                iface_info['dhcphostname'] = info['hostname']
         # These can just be copied over
         if use_ipv6:
             for k in ['address', 'gateway']:

=== modified file 'cloudinit/distros/rhel.py'
--- cloudinit/distros/rhel.py	2014-11-25 19:46:10 +0000
+++ cloudinit/distros/rhel.py	2014-12-11 16:27:59 +0000
@@ -84,6 +84,7 @@
                 'BROADCAST': info.get('broadcast'),
                 'MACADDR': info.get('hwaddress'),
                 'ONBOOT': _make_sysconfig_bool(info.get('auto')),
+                'DHCP_HOSTNAME': info.get('dhcphostname'),
             }
             if info.get('inet6'):
                 use_ipv6 = True

=== modified file 'cloudinit/sources/DataSourceOVF.py'
--- cloudinit/sources/DataSourceOVF.py	2014-09-22 18:35:03 +0000
+++ cloudinit/sources/DataSourceOVF.py	2014-12-11 16:27:59 +0000
@@ -25,6 +25,7 @@
 import base64
 import os
 import re
+import netifaces
 
 from cloudinit import log as logging
 from cloudinit import sources
@@ -64,7 +65,7 @@
             found.append(seed)
         else:
             np = {'iso': transport_iso9660,
-                  'vmware-guestd': transport_vmware_guestd, }
+                  'vmware-tools': transport_vmware_tools, }
             name = None
             for (name, transfunc) in np.iteritems():
                 (contents, _dev, _fname) = transfunc()
@@ -97,6 +98,17 @@
             md = util.mergemanydict([md, md_seed])
             found.append(seedfrom)
 
+        try:
+            network_config = gen_network_config(md)
+
+            if network_config != '':
+                LOG.debug("Updating network interfaces from %s", self)
+                self.distro.apply_network(network_config)
+            else:
+                LOG.debug("network_config empty. Is ipv4.bootproto empty?")
+        except Exception as e:
+            util.logexc(LOG, 'NetworkConfigError: %s' % str(e))
+
         # Now that we have exhausted any other places merge in the defaults
         md = util.mergemanydict([md, defaults])
 
@@ -137,7 +149,7 @@
     cfg = {}
     ud = ""
     cfg_props = ['password']
-    md_props = ['seedfrom', 'local-hostname', 'public-keys', 'instance-id']
+    md_props = ['seedfrom', 'local-hostname', 'public-keys', 'instance-id', 'ipv4.bootproto', 'ipv4.dhcphostname', 'ipv4.address', 'ipv4.gateway', 'ipv4.netmask', 'ipv4.broadcast', 'dns.server1', 'dns.server2', 'macaddr']
     for (prop, val) in props.iteritems():
         if prop == 'hostname':
             prop = "local-hostname"
@@ -226,17 +238,16 @@
     return (False, None, None)
 
 
-def transport_vmware_guestd():
+def transport_vmware_tools():
     # http://blogs.vmware.com/vapp/2009/07/ \
     #    selfconfiguration-and-the-ovf-environment.html
-    # try:
-    #     cmd = ['vmware-guestd', '--cmd', 'info-get guestinfo.ovfEnv']
-    #     (out, err) = subp(cmd)
-    #     return(out, 'guestinfo.ovfEnv', 'vmware-guestd')
-    # except:
-    #     # would need to error check here and see why this failed
-    #     # to know if log/error should be raised
-    #     return(False, None, None)
+    for tool in ['vmtoolsd', 'vmware-guestd']:
+        try:
+            cmd = [tool, '--cmd', 'info-get guestinfo.ovfEnv']
+            (out, err) = util.subp(cmd)
+            return(out, 'guestinfo.ovfEnv', 'vmware-tools')
+        except util.ProcessExecutionError:
+            pass
     return (False, None, None)
 
 
@@ -260,6 +271,7 @@
         raise XmlError("No Child Nodes")
 
     envNsURI = "http://schemas.dmtf.org/ovf/environment/1";
+    ovfEnvNsURI = "http://www.vmware.com/schema/ovfenv";
 
     # could also check here that elem.namespaceURI ==
     #   "http://schemas.dmtf.org/ovf/environment/1";
@@ -278,12 +290,76 @@
         val = elem.attributes.getNamedItemNS(envNsURI, "value").value
         props[key] = val
 
+    ethernetAdapterSections = find_child(dom.documentElement,
+        lambda n: n.localName == "EthernetAdapterSection")
+
+    if len(ethernetAdapterSections) == 0:
+        raise XmlError("No 'EthernetAdapterSection's")
+
+    adapterElems = find_child(ethernetAdapterSections[0],
+                            (lambda n: n.localName == "Adapter"))
+
+    if len(adapterElems) == 0:
+        raise XmlError("No 'Adapter's")
+
+    val = adapterElems[0].attributes.getNamedItemNS(ovfEnvNsURI, "mac").value
+    props['macaddr'] = val
+
     return props
 
+def gen_network_config(md):
+    conf = []
+
+    if 'ipv4.bootproto' not in md:
+        return ''
+
+    if 'macaddr' not in md:
+        raise NetworkConfigError('No macaddr in metadata')
+
+    dev = ''
+
+    for i in netifaces.interfaces():
+        addr = netifaces.ifaddresses(i)[netifaces.AF_LINK]
+        if addr[0]['addr'] == md['macaddr']:
+            dev = i
+            break
+
+    if dev == '':
+        raise NetworkConfigError('Could not find interface for macaddr ' + md['macaddr'])
+
+    if md['ipv4.bootproto'] == 'static':
+        if set(('ipv4.address', 'ipv4.netmask', 'ipv4.broadcast', 'ipv4.gateway')) > set(md):
+            raise NetworkConfigError('All of ipv4.address, ipv4.netmask, ipv4.broadcast, and ipv4.gateway have to be set.')
+
+        conf.append('auto ' + dev)
+        conf.append('iface ' + dev + ' inet ' + md['ipv4.bootproto'])
+        conf.append('  address   ' + md['ipv4.address'])
+        conf.append('  netmask   ' + md['ipv4.netmask'])
+        conf.append('  broadcast ' + md['ipv4.broadcast'])
+        conf.append('  gateway   ' + md['ipv4.gateway'])
+        conf.append('  hwaddress ' + md['macaddr'])
+
+        if 'dns.server1' in md or 'dns.server2' in md:
+            conf.append('  dns-nameservers ' + ' '.join((md.get('dns.server1'), md.get('dns.server2'))))
+    elif md['ipv4.bootproto'] == 'dhcp':
+        conf.append('auto ' + dev)
+        conf.append('iface ' + dev + ' inet ' + md['ipv4.bootproto'])
+
+        if 'ipv4.dhcphostname' in md:
+            conf.append('  hostname ' + md['ipv4.dhcphostname'])
+    else:
+        raise NetworkConfigError('ipv4.bootproto has to be dhcp or static')
+
+    conf.append('')
+
+    return "\n".join(conf)
 
 class XmlError(Exception):
     pass
 
+class NetworkConfigError(Exception):
+    pass
+
 
 # Used to match classes to dependencies
 datasources = (

=== modified file 'requirements.txt'
--- requirements.txt	2014-03-05 23:05:59 +0000
+++ requirements.txt	2014-12-11 16:27:59 +0000
@@ -32,3 +32,6 @@
 
 # For patching pieces of cloud-config together
 jsonpatch
+
+# used in DataSourceOVF for mac addr -> interface lookup
+netifaces


Follow ups