From b80c2401123e16b9038ff3fb6f6d660717ee68e1 Mon Sep 17 00:00:00 2001
From: Joshua Harlow <harlowja@yahoo-inc.com>
Date: Thu, 8 Nov 2012 17:37:16 -0800
Subject: Fix the case where on a redhat based system the fully qualified
 domain name should end up in /etc/sysconfig/network by passing the fqdn to
 the update and set hostname methods and using it accordingly.

LP: #1076759
---
 cloudinit/config/cc_set_hostname.py    | 10 ++++++----
 cloudinit/config/cc_update_hostname.py |  8 +++++---
 cloudinit/distros/__init__.py          |  4 ++--
 cloudinit/distros/debian.py            |  4 ++--
 cloudinit/distros/rhel.py              | 25 +++++++++++++++++--------
 5 files changed, 32 insertions(+), 19 deletions(-)

diff --git a/cloudinit/config/cc_set_hostname.py b/cloudinit/config/cc_set_hostname.py
index b0f27ebf..2b32fc94 100644
--- a/cloudinit/config/cc_set_hostname.py
+++ b/cloudinit/config/cc_set_hostname.py
@@ -27,9 +27,11 @@ def handle(name, cfg, cloud, log, _args):
                     " not setting the hostname in module %s"), name)
         return
 
-    (hostname, _fqdn) = util.get_hostname_fqdn(cfg, cloud)
+    (hostname, fqdn) = util.get_hostname_fqdn(cfg, cloud)
     try:
-        log.debug("Setting hostname to %s", hostname)
-        cloud.distro.set_hostname(hostname)
+        log.debug("Setting the hostname to %s (%s)", fqdn, hostname)
+        cloud.distro.set_hostname(hostname, fqdn)
     except Exception:
-        util.logexc(log, "Failed to set hostname to %s", hostname)
+        util.logexc(log, "Failed to set the hostname to %s (%s)",
+                    fqdn, hostname)
+        raise
diff --git a/cloudinit/config/cc_update_hostname.py b/cloudinit/config/cc_update_hostname.py
index 1d6679ea..52225cd8 100644
--- a/cloudinit/config/cc_update_hostname.py
+++ b/cloudinit/config/cc_update_hostname.py
@@ -32,10 +32,12 @@ def handle(name, cfg, cloud, log, _args):
                     " not updating the hostname in module %s"), name)
         return
 
-    (hostname, _fqdn) = util.get_hostname_fqdn(cfg, cloud)
+    (hostname, fqdn) = util.get_hostname_fqdn(cfg, cloud)
     try:
         prev_fn = os.path.join(cloud.get_cpath('data'), "previous-hostname")
-        cloud.distro.update_hostname(hostname, prev_fn)
+        log.debug("Updating hostname to %s (%s)", fqdn, hostname)
+        cloud.distro.update_hostname(hostname, fqdn, prev_fn)
     except Exception:
-        util.logexc(log, "Failed to set the hostname to %s", hostname)
+        util.logexc(log, "Failed to update the hostname to %s (%s)",
+                    fqdn, hostname)
         raise
diff --git a/cloudinit/distros/__init__.py b/cloudinit/distros/__init__.py
index 869540d2..bd04ba79 100644
--- a/cloudinit/distros/__init__.py
+++ b/cloudinit/distros/__init__.py
@@ -58,11 +58,11 @@ class Distro(object):
         return self._cfg.get(opt_name, default)
 
     @abc.abstractmethod
-    def set_hostname(self, hostname):
+    def set_hostname(self, hostname, fqdn=None):
         raise NotImplementedError()
 
     @abc.abstractmethod
-    def update_hostname(self, hostname, prev_hostname_fn):
+    def update_hostname(self, hostname, fqdn, prev_hostname_fn):
         raise NotImplementedError()
 
     @abc.abstractmethod
diff --git a/cloudinit/distros/debian.py b/cloudinit/distros/debian.py
index cc7e53a0..ed4070b4 100644
--- a/cloudinit/distros/debian.py
+++ b/cloudinit/distros/debian.py
@@ -67,7 +67,7 @@ class Distro(distros.Distro):
         else:
             return distros.Distro._bring_up_interfaces(self, device_names)
 
-    def set_hostname(self, hostname):
+    def set_hostname(self, hostname, fqdn=None):
         self._write_hostname(hostname, "/etc/hostname")
         LOG.debug("Setting hostname to %s", hostname)
         util.subp(['hostname', hostname])
@@ -76,7 +76,7 @@ class Distro(distros.Distro):
         # "" gives trailing newline.
         util.write_file(out_fn, "%s\n" % str(hostname), 0644)
 
-    def update_hostname(self, hostname, prev_fn):
+    def update_hostname(self, hostname, fqdn, prev_fn):
         hostname_prev = self._read_hostname(prev_fn)
         hostname_in_etc = self._read_hostname("/etc/hostname")
         update_files = []
diff --git a/cloudinit/distros/rhel.py b/cloudinit/distros/rhel.py
index bf3c18d2..e4c27216 100644
--- a/cloudinit/distros/rhel.py
+++ b/cloudinit/distros/rhel.py
@@ -146,8 +146,13 @@ class Distro(distros.Distro):
                 lines.insert(0, _make_header())
             util.write_file(fn, "\n".join(lines), 0644)
 
-    def set_hostname(self, hostname):
-        self._write_hostname(hostname, '/etc/sysconfig/network')
+    def set_hostname(self, hostname, fqdn=None):
+        # See: http://bit.ly/TwitgL
+        # Should be fqdn if we can use it
+        sysconfig_hostname = fqdn
+        if not sysconfig_hostname:
+            sysconfig_hostname = hostname
+        self._write_hostname(sysconfig_hostname, '/etc/sysconfig/network')
         LOG.debug("Setting hostname to %s", hostname)
         util.subp(['hostname', hostname])
 
@@ -165,28 +170,32 @@ class Distro(distros.Distro):
         }
         self._update_sysconfig_file(out_fn, host_cfg)
 
-    def update_hostname(self, hostname, prev_file):
+    def update_hostname(self, hostname, fqdn, prev_file):
+        # See: http://bit.ly/TwitgL
+        # Should be fqdn if we can use it
+        sysconfig_hostname = fqdn
+        if not sysconfig_hostname:
+            sysconfig_hostname = hostname
         hostname_prev = self._read_hostname(prev_file)
         hostname_in_sys = self._read_hostname("/etc/sysconfig/network")
         update_files = []
-        if not hostname_prev or hostname_prev != hostname:
+        if not hostname_prev or hostname_prev != sysconfig_hostname:
             update_files.append(prev_file)
         if (not hostname_in_sys or
             (hostname_in_sys == hostname_prev
-             and hostname_in_sys != hostname)):
+             and hostname_in_sys != sysconfig_hostname)):
             update_files.append("/etc/sysconfig/network")
         for fn in update_files:
             try:
-                self._write_hostname(hostname, fn)
+                self._write_hostname(sysconfig_hostname, fn)
             except:
                 util.logexc(LOG, "Failed to write hostname %s to %s",
-                            hostname, fn)
+                            sysconfig_hostname, fn)
         if (hostname_in_sys and hostname_prev and
             hostname_in_sys != hostname_prev):
             LOG.debug(("%s differs from /etc/sysconfig/network."
                         " Assuming user maintained hostname."), prev_file)
         if "/etc/sysconfig/network" in update_files:
-            # Only do this if we are running in non-adjusted root mode
             LOG.debug("Setting hostname to %s", hostname)
             util.subp(['hostname', hostname])
 
-- 
cgit v1.2.3


From bd01f3466e10ca515a8e8aec42d00201f40cbd53 Mon Sep 17 00:00:00 2001
From: Joshua Harlow <harlowja@yahoo-inc.com>
Date: Thu, 8 Nov 2012 17:41:36 -0800
Subject: Forgot the test!

---
 .../test_handler/test_handler_set_hostname.py      | 58 ++++++++++++++++++++++
 1 file changed, 58 insertions(+)
 create mode 100644 tests/unittests/test_handler/test_handler_set_hostname.py

diff --git a/tests/unittests/test_handler/test_handler_set_hostname.py b/tests/unittests/test_handler/test_handler_set_hostname.py
new file mode 100644
index 00000000..a1aba62f
--- /dev/null
+++ b/tests/unittests/test_handler/test_handler_set_hostname.py
@@ -0,0 +1,58 @@
+from cloudinit.config import cc_set_hostname
+
+from cloudinit import cloud
+from cloudinit import distros
+from cloudinit import helpers
+from cloudinit import util
+
+from tests.unittests import helpers as t_help
+
+import logging
+
+from StringIO import StringIO
+
+from configobj import ConfigObj
+
+LOG = logging.getLogger(__name__)
+
+
+class TestHostname(t_help.FilesystemMockingTestCase):
+    def setUp(self):
+        super(TestHostname, self).setUp()
+        self.tmp = self.makeDir(prefix="unittest_")
+
+    def _fetch_distro(self, kind):
+        cls = distros.fetch(kind)
+        paths = helpers.Paths({})
+        return cls(kind, {}, paths)
+
+    def test_write_hostname_rhel(self):
+        cfg = {
+            'hostname': 'blah.blah.blah.yahoo.com',
+        }
+        distro = self._fetch_distro('rhel')
+        paths = helpers.Paths({})
+        ds = None
+        cc = cloud.Cloud(ds, paths, {}, distro, None)
+        self.patchUtils(self.tmp)
+        self.patchOS(self.tmp)
+        cc_set_hostname.handle('cc_set_hostname',
+                               cfg, cc, LOG, [])
+        contents = util.load_file("/etc/sysconfig/network")
+        n_cfg = ConfigObj(StringIO(contents))
+        self.assertEquals({'HOSTNAME': 'blah.blah.blah.yahoo.com'},
+                          dict(n_cfg))
+
+    def test_write_hostname_debian(self):
+        cfg = {
+            'hostname': 'blah.blah.blah.yahoo.com',
+        }
+        distro = self._fetch_distro('debian')
+        paths = helpers.Paths({})
+        ds = None
+        cc = cloud.Cloud(ds, paths, {}, distro, None)
+        self.patchUtils(self.tmp)
+        cc_set_hostname.handle('cc_set_hostname',
+                               cfg, cc, LOG, [])
+        contents = util.load_file("/etc/hostname")
+        self.assertEquals('blah', contents.strip())
-- 
cgit v1.2.3