← Back to team overview

cloud-init-dev team mailing list archive

[Merge] lp:~bbaude/cloud-init/azure_dhcp into lp:cloud-init

 

Brent Baude has proposed merging lp:~bbaude/cloud-init/azure_dhcp into lp:cloud-init.

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

For more details, see:
https://code.launchpad.net/~bbaude/cloud-init/azure_dhcp/+merge/298677
-- 
Your team cloud init development team is requested to review the proposed merge of lp:~bbaude/cloud-init/azure_dhcp into lp:cloud-init.
=== modified file 'cloudinit/sources/helpers/azure.py'
--- cloudinit/sources/helpers/azure.py	2016-05-12 20:52:56 +0000
+++ cloudinit/sources/helpers/azure.py	2016-06-29 16:34:09 +0000
@@ -189,6 +189,7 @@
 
     def __init__(self):
         LOG.debug('WALinuxAgentShim instantiated...')
+        self.dhcpoptions = os.path.join("/run/cloud-init", "dhcpoptions")
         self.endpoint = self.find_endpoint()
         self.openssl_manager = None
         self.values = {}
@@ -212,14 +213,30 @@
             packed_bytes = unescaped_value.encode('utf-8')
         return socket.inet_ntoa(packed_bytes)
 
-    @staticmethod
-    def find_endpoint():
+    def find_endpoint(self):
         LOG.debug('Finding Azure endpoint...')
-        content = util.load_file('/var/lib/dhcp/dhclient.eth0.leases')
-        value = None
-        for line in content.splitlines():
-            if 'unknown-245' in line:
-                value = line.strip(' ').split(' ', 2)[-1].strip(';\n"')
+        try:
+            # Option-245 stored in /run/cloud-init/dhcpoptions by dhclient
+            content = util.load_file(self.dhcpoptions)
+            dhcp_options = dict(line.split('=', 1) for line in
+                                content.strip().split("\n"))
+
+            # Depending on the environment, the option can be
+            # preceded by DHCP4 or new
+            value = dhcp_options.get("DHCP4_UNKNOWN_245") if \
+                dhcp_options.get("new_unknown_245") is None else \
+                dhcp_options.get("new_unknown_245")
+            LOG.debug("Option-245 has value of {}".format(value))
+        except Exception:
+            # Fallback and check the leases file if unsuccessful
+            LOG.debug("Unable to find {}.  Falling back to check lease "
+                      "files".format(self.dhcpoptions))
+            content = util.load_file('/var/lib/dhcp/dhclient.eth0.leases')
+            value = None
+            for line in content.splitlines():
+                if 'unknown-245' in line:
+                    value = line.strip(' ').split(' ', 2)[-1].strip(';\n"')
+        LOG.debug(value)
         if value is None:
             raise ValueError('No endpoint found in DHCP config.')
         endpoint_ip_address = WALinuxAgentShim.get_ip_from_lease_value(value)

=== modified file 'doc/sources/azure/README.rst'
--- doc/sources/azure/README.rst	2013-07-25 18:37:10 +0000
+++ doc/sources/azure/README.rst	2016-06-29 16:34:09 +0000
@@ -9,8 +9,17 @@
 The azure cloud-platform provides initial data to an instance via an attached
 CD formated in UDF.  That CD contains a 'ovf-env.xml' file that provides some
 information.  Additional information is obtained via interaction with the
-"endpoint".  The ip address of the endpoint is advertised to the instance
-inside of dhcp option 245.  On ubuntu, that can be seen in
+"endpoint".
+
+To find the endpoint, we now leverage the dhcp client's ability to log its
+known values on exit.  The endpoint servcer is special DHCP option 245.
+Depending on your networking stack, this can be done
+by calling a script in /etc/dhcp/dhclient-exit-hooks or a file in
+/etc/NetworkManager/dispatcher.d.  Both of these call /usr/bin/cloud-init-log-dhcp
+which will write the client information to /run/cloud-init/dhcpoptions.
+
+If those files are not available, the fallback is to check the leases file
+for the endpoint server (again option 245).  On ubuntu, that can be seen in
 /var/lib/dhcp/dhclient.eth0.leases as a colon delimited hex value (example:
 ``option unknown-245 64:41:60:82;`` is 100.65.96.130)
 

=== modified file 'setup.py'
--- setup.py	2016-06-14 21:56:51 +0000
+++ setup.py	2016-06-29 16:34:09 +0000
@@ -176,6 +176,8 @@
         (ETC + '/cloud', glob('config/*.cfg')),
         (ETC + '/cloud/cloud.cfg.d', glob('config/cloud.cfg.d/*')),
         (ETC + '/cloud/templates', glob('templates/*')),
+        (ETC + '/NetworkManager/dispatcher.d/', ['tools/NM-cloudinit']),
+        (ETC + '/dhcp/dhclient-exit-hooks.d/', ['tools/cloud-init-log-dhcp']),
         (USR_LIB_EXEC + '/cloud-init', ['tools/uncloud-init',
                                         'tools/write-ssh-key-fingerprints']),
         (USR + '/share/doc/cloud-init', [f for f in glob('doc/*') if is_f(f)]),
@@ -204,7 +206,8 @@
     author_email='scott.moser@xxxxxxxxxxxxx',
     url='http://launchpad.net/cloud-init/',
     packages=setuptools.find_packages(exclude=['tests']),
-    scripts=['tools/cloud-init-per'],
+    scripts=['tools/cloud-init-per',
+            'tools/cloud-init-dhcp-options'],
     license='GPLv3',
     data_files=data_files,
     install_requires=requirements,

=== modified file 'tests/unittests/test_datasource/test_azure_helper.py'
--- tests/unittests/test_datasource/test_azure_helper.py	2016-06-10 21:22:17 +0000
+++ tests/unittests/test_datasource/test_azure_helper.py	2016-06-29 16:34:09 +0000
@@ -57,12 +57,12 @@
     def test_missing_file(self):
         self.load_file.side_effect = IOError
         self.assertRaises(IOError,
-                          azure_helper.WALinuxAgentShim.find_endpoint)
+                          azure_helper.WALinuxAgentShim)
 
     def test_missing_special_azure_line(self):
         self.load_file.return_value = ''
         self.assertRaises(ValueError,
-                          azure_helper.WALinuxAgentShim.find_endpoint)
+                          azure_helper.WALinuxAgentShim)
 
     @staticmethod
     def _build_lease_content(encoded_address):
@@ -72,13 +72,21 @@
             ' option unknown-245 {0};'.format(encoded_address),
             '}'])
 
+    def test_from_dhcp_client(self):
+        file_content = '\n'.join(['DHCP4_UNKNOWN_245=5:4:3:2'])
+        print(file_content)
+        self.load_file.return_value = file_content
+        shim = azure_helper.WALinuxAgentShim()
+        self.assertEqual('5.4.3.2', shim.find_endpoint())
+
     def test_latest_lease_used(self):
         encoded_addresses = ['5:4:3:2', '4:3:2:1']
         file_content = '\n'.join([self._build_lease_content(encoded_address)
                                   for encoded_address in encoded_addresses])
         self.load_file.return_value = file_content
+        shim = azure_helper.WALinuxAgentShim()
         self.assertEqual(encoded_addresses[-1].replace(':', '.'),
-                         azure_helper.WALinuxAgentShim.find_endpoint())
+                         shim.find_endpoint())
 
 
 class TestExtractIpAddressFromLeaseValue(TestCase):

=== added file 'tools/NM-cloudinit'
--- tools/NM-cloudinit	1970-01-01 00:00:00 +0000
+++ tools/NM-cloudinit	2016-06-29 16:34:09 +0000
@@ -0,0 +1,9 @@
+#!/bin/bash
+# 
+# Writes DHCP lease information into the cloud-init data
+# directory.
+
+MDFILE=/run/cloud-init/dhcpoptions
+
+cloud-init-dhcp-options
+

=== added file 'tools/cloud-init-dhcp-options'
--- tools/cloud-init-dhcp-options	1970-01-01 00:00:00 +0000
+++ tools/cloud-init-dhcp-options	2016-06-29 16:34:09 +0000
@@ -0,0 +1,15 @@
+#!/bin/bash
+# 
+# Writes DHCP lease information into the cloud-init data
+# directory.
+
+MDFILE=/run/cloud-init/dhcpoptions
+
+if [ ! -d $(dirname $MDFILE) ]; then
+        mkdir -p $(dirname $MDFILE)
+fi
+if [ -f $MDFILE ]; then
+        rm -f $MDFILE
+fi
+
+env | grep '^new_\|^DHCP4_' > $MDFILE

=== added file 'tools/cloud-init-log-dhcp'
--- tools/cloud-init-log-dhcp	1970-01-01 00:00:00 +0000
+++ tools/cloud-init-log-dhcp	2016-06-29 16:34:09 +0000
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+cloud-init-dhcp-options


Follow ups