← Back to team overview

cloud-init-dev team mailing list archive

[Merge] ~bbaude/cloud-init:azure_bounce into cloud-init:master

 

Brent Baude has proposed merging ~bbaude/cloud-init:azure_bounce into cloud-init:master.

Requested reviews:
  Server Team CI bot (server-team-bot): continuous-integration
  cloud init development team (cloud-init-dev)

For more details, see:
https://code.launchpad.net/~bbaude/cloud-init/+git/cloud-init/+merge/320411

This PR adds the ability to set the hostname and bounce the network interfaces when provisioning in Azure with just cloud-init.  The hostname must be set and network bounced in order for DNS to work correctly in Azure when communicating between azure vms.
-- 
Your team cloud init development team is requested to review the proposed merge of ~bbaude/cloud-init:azure_bounce into cloud-init:master.
diff --git a/cloudinit/sources/DataSourceAzure.py b/cloudinit/sources/DataSourceAzure.py
index c5af8b8..9afff95 100644
--- a/cloudinit/sources/DataSourceAzure.py
+++ b/cloudinit/sources/DataSourceAzure.py
@@ -74,28 +74,6 @@ def set_hostname(hostname, hostname_command='hostname'):
     util.subp([hostname_command, hostname])
 
 
-@contextlib.contextmanager
-def temporary_hostname(temp_hostname, cfg, hostname_command='hostname'):
-    """
-    Set a temporary hostname, restoring the previous hostname on exit.
-
-    Will have the value of the previous hostname when used as a context
-    manager, or None if the hostname was not changed.
-    """
-    policy = cfg['hostname_bounce']['policy']
-    previous_hostname = get_hostname(hostname_command)
-    if (not util.is_true(cfg.get('set_hostname')) or
-       util.is_false(policy) or
-       (previous_hostname == temp_hostname and policy != 'force')):
-        yield None
-        return
-    set_hostname(temp_hostname, hostname_command)
-    try:
-        yield previous_hostname
-    finally:
-        set_hostname(previous_hostname, hostname_command)
-
-
 class DataSourceAzureNet(sources.DataSource):
     def __init__(self, sys_cfg, distro, paths):
         sources.DataSource.__init__(self, sys_cfg, distro, paths)
@@ -111,50 +89,56 @@ class DataSourceAzureNet(sources.DataSource):
         root = sources.DataSource.__str__(self)
         return "%s [seed=%s]" % (root, self.seed)
 
+    def set_hostname_and_bounce(self):
+        # When using cloud-init to provision, we have to set the hostname from
+        # the metadata and "bounce" the network to force DDNS to update via
+        # dhclient
+        hostname_command = self.ds_cfg['hostname_bounce']['hostname_command']
+        prev_hostname, _ = util.subp([hostname_command], capture=True)
+        hostname = self.metadata.get('local-hostname')
+        LOG.debug("Hostname in metadata is {}".format(hostname))
+        self.distro.set_hostname(hostname, hostname)
+        cfg = self.ds_cfg['hostname_bounce']
+
+        # "Bouncing" the network, same as what is done with the agent path
+        try:
+            perform_hostname_bounce(hostname=hostname, cfg=cfg, prev_hostname=prev_hostname)
+        except Exception as e:
+            LOG.warn("Failed publishing hostname: %s", e)
+            util.logexc(LOG, "handling set_hostname failed")
+
     def get_metadata_from_agent(self):
         temp_hostname = self.metadata.get('local-hostname')
-        hostname_command = self.ds_cfg['hostname_bounce']['hostname_command']
         agent_cmd = self.ds_cfg['agent_command']
         LOG.debug("Getting metadata via agent.  hostname=%s cmd=%s",
                   temp_hostname, agent_cmd)
-        with temporary_hostname(temp_hostname, self.ds_cfg,
-                                hostname_command=hostname_command) \
-                as previous_hostname:
-            if (previous_hostname is not None and
-               util.is_true(self.ds_cfg.get('set_hostname'))):
-                cfg = self.ds_cfg['hostname_bounce']
-                try:
-                    perform_hostname_bounce(hostname=temp_hostname,
-                                            cfg=cfg,
-                                            prev_hostname=previous_hostname)
-                except Exception as e:
-                    LOG.warn("Failed publishing hostname: %s", e)
-                    util.logexc(LOG, "handling set_hostname failed")
 
-            try:
-                invoke_agent(agent_cmd)
-            except util.ProcessExecutionError:
-                # claim the datasource even if the command failed
-                util.logexc(LOG, "agent command '%s' failed.",
-                            self.ds_cfg['agent_command'])
-
-            ddir = self.ds_cfg['data_dir']
-
-            fp_files = []
-            key_value = None
-            for pk in self.cfg.get('_pubkeys', []):
-                if pk.get('value', None):
-                    key_value = pk['value']
-                    LOG.debug("ssh authentication: using value from fabric")
-                else:
-                    bname = str(pk['fingerprint'] + ".crt")
-                    fp_files += [os.path.join(ddir, bname)]
-                    LOG.debug("ssh authentication: "
-                              "using fingerprint from fabirc")
-
-            missing = util.log_time(logfunc=LOG.debug, msg="waiting for files",
-                                    func=wait_for_files,
-                                    args=(fp_files,))
+        self.set_hostname_and_bounce()
+
+        try:
+            invoke_agent(agent_cmd)
+        except util.ProcessExecutionError:
+            # claim the datasource even if the command failed
+            util.logexc(LOG, "agent command '%s' failed.",
+                        self.ds_cfg['agent_command'])
+
+        ddir = self.ds_cfg['data_dir']
+
+        fp_files = []
+        key_value = None
+        for pk in self.cfg.get('_pubkeys', []):
+            if pk.get('value', None):
+                key_value = pk['value']
+                LOG.debug("ssh authentication: using value from fabric")
+            else:
+                bname = str(pk['fingerprint'] + ".crt")
+                fp_files += [os.path.join(ddir, bname)]
+                LOG.debug("ssh authentication: "
+                          "using fingerprint from fabirc")
+
+        missing = util.log_time(logfunc=LOG.debug, msg="waiting for files",
+                                func=wait_for_files,
+                                args=(fp_files,))
         if len(missing):
             LOG.warn("Did not find files, but going on: %s", missing)
 
@@ -220,6 +204,8 @@ class DataSourceAzureNet(sources.DataSource):
         write_files(ddir, files, dirmode=0o700)
 
         if self.ds_cfg['agent_command'] == AGENT_START_BUILTIN:
+            self.set_hostname_and_bounce()
+
             metadata_func = partial(get_metadata_from_fabric,
                                     fallback_lease_file=self.
                                     dhclient_lease_file)
diff --git a/cloudinit/sources/__init__.py b/cloudinit/sources/__init__.py
index 3d01072..1829450 100644
--- a/cloudinit/sources/__init__.py
+++ b/cloudinit/sources/__init__.py
@@ -210,7 +210,7 @@ class DataSource(object):
         else:
             hostname = toks[0]
 
-        if fqdn:
+        if fqdn and domain != defdomain:
             return "%s.%s" % (hostname, domain)
         else:
             return hostname