20a859
From 9c2b33562da7e5ca3359a2e70b893d19c44eb66c Mon Sep 17 00:00:00 2001
20a859
From: Brent Baude <bbaude@redhat.com>
20a859
Date: Mon, 20 Mar 2017 12:31:15 -0500
20a859
Subject: [PATCH] Bounce network interface for Azure when using the built-in
20a859
 path.
20a859
20a859
When deploying on Azure and using only cloud-init, you must "bounce" the
20a859
network interface to trigger a DDNS update. This allows dhclient to
20a859
register the hostname with Azure so that DNS works correctly on their
20a859
private networks (i.e. between vm and vm).
20a859
20a859
The agent path was already doing the bounce so this creates parity
20a859
between the built-in path and the agent.
20a859
20a859
LP: #1674685
20a859
Resolves: rhbz#1434109
20a859
(cherry picked from commit 86715c88aab8561e1ddadac95671f6095d16f9e7)
20a859
---
20a859
 cloudinit/sources/DataSourceAzure.py | 78 +++++++++++++++++++++---------------
20a859
 cloudinit/sources/__init__.py        |  2 +-
20a859
 2 files changed, 47 insertions(+), 33 deletions(-)
20a859
20a859
diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py
20a859
index c5af8b8..48a3e1d 100644
20a859
--- a/cloudinit/sources/DataSourceAzure.py
20a859
+++ b/cloudinit/sources/DataSourceAzure.py
20a859
@@ -111,50 +111,62 @@ class DataSourceAzureNet(sources.DataSource):
20a859
         root = sources.DataSource.__str__(self)
20a859
         return "%s [seed=%s]" % (root, self.seed)
20a859
 
20a859
-    def get_metadata_from_agent(self):
20a859
-        temp_hostname = self.metadata.get('local-hostname')
20a859
+    def bounce_network_with_azure_hostname(self):
20a859
+        # When using cloud-init to provision, we have to set the hostname from
20a859
+        # the metadata and "bounce" the network to force DDNS to update via
20a859
+        # dhclient
20a859
+        azure_hostname = self.metadata.get('local-hostname')
20a859
+        LOG.debug("Hostname in metadata is {}".format(azure_hostname))
20a859
         hostname_command = self.ds_cfg['hostname_bounce']['hostname_command']
20a859
-        agent_cmd = self.ds_cfg['agent_command']
20a859
-        LOG.debug("Getting metadata via agent.  hostname=%s cmd=%s",
20a859
-                  temp_hostname, agent_cmd)
20a859
-        with temporary_hostname(temp_hostname, self.ds_cfg,
20a859
+
20a859
+        with temporary_hostname(azure_hostname, self.ds_cfg,
20a859
                                 hostname_command=hostname_command) \
20a859
                 as previous_hostname:
20a859
             if (previous_hostname is not None and
20a859
-               util.is_true(self.ds_cfg.get('set_hostname'))):
20a859
+                    util.is_true(self.ds_cfg.get('set_hostname'))):
20a859
                 cfg = self.ds_cfg['hostname_bounce']
20a859
+
20a859
+                # "Bouncing" the network
20a859
                 try:
20a859
-                    perform_hostname_bounce(hostname=temp_hostname,
20a859
+                    perform_hostname_bounce(hostname=azure_hostname,
20a859
                                             cfg=cfg,
20a859
                                             prev_hostname=previous_hostname)
20a859
                 except Exception as e:
20a859
                     LOG.warn("Failed publishing hostname: %s", e)
20a859
                     util.logexc(LOG, "handling set_hostname failed")
20a859
 
20a859
-            try:
20a859
-                invoke_agent(agent_cmd)
20a859
-            except util.ProcessExecutionError:
20a859
-                # claim the datasource even if the command failed
20a859
-                util.logexc(LOG, "agent command '%s' failed.",
20a859
-                            self.ds_cfg['agent_command'])
20a859
-
20a859
-            ddir = self.ds_cfg['data_dir']
20a859
-
20a859
-            fp_files = []
20a859
-            key_value = None
20a859
-            for pk in self.cfg.get('_pubkeys', []):
20a859
-                if pk.get('value', None):
20a859
-                    key_value = pk['value']
20a859
-                    LOG.debug("ssh authentication: using value from fabric")
20a859
-                else:
20a859
-                    bname = str(pk['fingerprint'] + ".crt")
20a859
-                    fp_files += [os.path.join(ddir, bname)]
20a859
-                    LOG.debug("ssh authentication: "
20a859
-                              "using fingerprint from fabirc")
20a859
-
20a859
-            missing = util.log_time(logfunc=LOG.debug, msg="waiting for files",
20a859
-                                    func=wait_for_files,
20a859
-                                    args=(fp_files,))
20a859
+    def get_metadata_from_agent(self):
20a859
+        temp_hostname = self.metadata.get('local-hostname')
20a859
+        agent_cmd = self.ds_cfg['agent_command']
20a859
+        LOG.debug("Getting metadata via agent.  hostname=%s cmd=%s",
20a859
+                  temp_hostname, agent_cmd)
20a859
+
20a859
+        self.bounce_network_with_azure_hostname()
20a859
+
20a859
+        try:
20a859
+            invoke_agent(agent_cmd)
20a859
+        except util.ProcessExecutionError:
20a859
+            # claim the datasource even if the command failed
20a859
+            util.logexc(LOG, "agent command '%s' failed.",
20a859
+                        self.ds_cfg['agent_command'])
20a859
+
20a859
+        ddir = self.ds_cfg['data_dir']
20a859
+
20a859
+        fp_files = []
20a859
+        key_value = None
20a859
+        for pk in self.cfg.get('_pubkeys', []):
20a859
+            if pk.get('value', None):
20a859
+                key_value = pk['value']
20a859
+                LOG.debug("ssh authentication: using value from fabric")
20a859
+            else:
20a859
+                bname = str(pk['fingerprint'] + ".crt")
20a859
+                fp_files += [os.path.join(ddir, bname)]
20a859
+                LOG.debug("ssh authentication: "
20a859
+                          "using fingerprint from fabirc")
20a859
+
20a859
+        missing = util.log_time(logfunc=LOG.debug, msg="waiting for files",
20a859
+                                func=wait_for_files,
20a859
+                                args=(fp_files,))
20a859
         if len(missing):
20a859
             LOG.warn("Did not find files, but going on: %s", missing)
20a859
 
20a859
@@ -220,6 +232,8 @@ class DataSourceAzureNet(sources.DataSource):
20a859
         write_files(ddir, files, dirmode=0o700)
20a859
 
20a859
         if self.ds_cfg['agent_command'] == AGENT_START_BUILTIN:
20a859
+            self.bounce_network_with_azure_hostname()
20a859
+
20a859
             metadata_func = partial(get_metadata_from_fabric,
20a859
                                     fallback_lease_file=self.
20a859
                                     dhclient_lease_file)
20a859
diff --git a/cloudinit/sources/__init__.py b/cloudinit/sources/__init__.py
20a859
index 3d01072..1829450 100644
20a859
--- a/cloudinit/sources/__init__.py
20a859
+++ b/cloudinit/sources/__init__.py
20a859
@@ -210,7 +210,7 @@ class DataSource(object):
20a859
         else:
20a859
             hostname = toks[0]
20a859
 
20a859
-        if fqdn:
20a859
+        if fqdn and domain != defdomain:
20a859
             return "%s.%s" % (hostname, domain)
20a859
         else:
20a859
             return hostname