cloud-init-dev team mailing list archive
-
cloud-init-dev team
-
Mailing list archive
-
Message #00610
[Merge] lp:~utlemming/cloud-init/lp1375252 into lp:cloud-init
Ben Howard has proposed merging lp:~utlemming/cloud-init/lp1375252 into lp:cloud-init.
Requested reviews:
cloud init development team (cloud-init-dev)
Related bugs:
Bug #1375252 in walinuxagent (Ubuntu): "Hostname change is not preserved across reboot on Azure Ubuntu VMs"
https://bugs.launchpad.net/ubuntu/+source/walinuxagent/+bug/1375252
For more details, see:
https://code.launchpad.net/~utlemming/cloud-init/lp1375252/+merge/247438
Allow the system hostname and the fabric name to be separate per bug #137525. This change also brings the Azure datasource closer in behavior to other Datasources.
--
Your team cloud init development team is requested to review the proposed merge of lp:~utlemming/cloud-init/lp1375252 into lp:cloud-init.
=== modified file 'cloudinit/sources/DataSourceAzure.py'
--- cloudinit/sources/DataSourceAzure.py 2014-08-26 18:50:11 +0000
+++ cloudinit/sources/DataSourceAzure.py 2015-01-23 16:09:58 +0000
@@ -21,6 +21,7 @@
import fnmatch
import os
import os.path
+import re
import time
from xml.dom import minidom
@@ -46,7 +47,6 @@
'interface': 'eth0',
'policy': True,
'command': BOUNCE_COMMAND,
- 'hostname_command': 'hostname',
},
'disk_aliases': {'ephemeral0': '/dev/sdb'},
}
@@ -64,6 +64,7 @@
DS_CFG_PATH = ['datasource', DS_NAME]
DEF_EPHEMERAL_LABEL = 'Temporary Storage'
+DHCPCLIENT_CONFIGS = ["/etc/dhcp/dhclient.conf", "/etc/dhcp3/dhclient.conf"]
class DataSourceAzureNet(sources.DataSource):
@@ -155,7 +156,7 @@
# handle the hostname 'publishing'
try:
- handle_set_hostname(mycfg.get('set_hostname'),
+ handle_set_dhcp_hostname(mycfg.get('set_hostname'),
self.metadata.get('local-hostname'),
mycfg['hostname_bounce'])
except Exception as e:
@@ -298,7 +299,45 @@
return mod_list
-def handle_set_hostname(enabled, hostname, cfg):
+def set_dhcp_hostname(hostname):
+ try:
+ for dhcp_fns in DHCPCLIENT_CONFIGS:
+ if not os.path.exists(dhcp_fns):
+ continue
+
+ LOG.debug("reading current DHCP configuration from {}".format(
+ dhcp_fns))
+ content = util.load_file(dhcp_fns)
+
+ host_re = re.compile(r'^send\s*host-name.*')
+ new_content = []
+ for line in content.splitlines():
+ if host_re.match(line):
+ current_hostname = None
+
+ if current_hostname == hostname:
+ LOG.debug("dhcpclient is already configured for"
+ " current hostname '{}'".format(hostname))
+ return False
+
+ line = 'send host-name = "{}";'.format(hostname)
+ new_content.append(line)
+
+ LOG.debug("setting 'send host-name = {};' in {}".format(
+ hostname, dhcp_fns))
+ util.write_file(dhcp_fns, "\n".join(new_content))
+ return True
+
+ except IOError, e:
+ LOG.warn("unable to set DHCP hostname.\n{}".format(e.message))
+ return False
+
+
+def handle_set_dhcp_hostname(enabled, hostname, cfg):
+ if not set_dhcp_hostname(hostname):
+ LOG.info("dchpclient hostname matches the fabric name")
+ return
+
if not util.is_true(enabled):
return
@@ -308,38 +347,25 @@
apply_hostname_bounce(hostname=hostname, policy=cfg['policy'],
interface=cfg['interface'],
- command=cfg['command'],
- hostname_command=cfg['hostname_command'])
-
-
-def apply_hostname_bounce(hostname, policy, interface, command,
- hostname_command="hostname"):
- # set the hostname to 'hostname' if it is not already set to that.
- # then, if policy is not off, bounce the interface using command
- prev_hostname = util.subp(hostname_command, capture=True)[0].strip()
-
- util.subp([hostname_command, hostname])
-
- msg = ("phostname=%s hostname=%s policy=%s interface=%s" %
- (prev_hostname, hostname, policy, interface))
+ command=cfg['command'])
+
+
+def apply_hostname_bounce(hostname, policy, interface, command):
+ msg = ("fabric_name={} policy={} interface={}".format(hostname, policy,
+ interface))
if util.is_false(policy):
- LOG.debug("pubhname: policy false, skipping [%s]", msg)
- return
-
- if prev_hostname == hostname and policy != "force":
- LOG.debug("pubhname: no change, policy != force. skipping. [%s]", msg)
+ LOG.debug("pubhname: policy false, skipping [{}]".format(msg))
return
env = os.environ.copy()
env['interface'] = interface
env['hostname'] = hostname
- env['old_hostname'] = prev_hostname
if command == "builtin":
command = BOUNCE_COMMAND
- LOG.debug("pubhname: publishing hostname [%s]", msg)
+ LOG.debug("pubhname: publishing hostname [{}]".format(msg))
shell = not isinstance(command, (list, tuple))
# capture=False, see comments in bug 1202758 and bug 1206164.
util.log_time(logfunc=LOG.debug, msg="publishing hostname",
=== modified file 'tests/unittests/test_datasource/test_azure.py'
--- tests/unittests/test_datasource/test_azure.py 2014-08-26 18:50:11 +0000
+++ tests/unittests/test_datasource/test_azure.py 2015-01-23 16:09:58 +0000
@@ -1,5 +1,5 @@
from cloudinit import helpers
-from cloudinit.util import load_file
+from cloudinit.util import (load_file, write_file)
from cloudinit.sources import DataSourceAzure
from ..helpers import populate_dir
@@ -76,6 +76,10 @@
self.paths = helpers.Paths({'cloud_dir': self.tmp})
self.waagent_d = os.path.join(self.tmp, 'var', 'lib', 'waagent')
+ # spoof a dhcp configuration
+ self.dhcp_cfg = os.path.join(self.tmp, 'etc', 'dhcp', 'dhclient.conf')
+ write_file(self.dhcp_cfg, "send host-name = gethostname();")
+
self.unapply = []
super(TestAzureDataSource, self).setUp()
@@ -116,6 +120,7 @@
mod = DataSourceAzure
mod.BUILTIN_DS_CONFIG['data_dir'] = self.waagent_d
+ mod.DHCPCLIENT_CONFIGS = [self.dhcp_cfg]
self.apply_patches([(mod, 'list_possible_azure_ds_devs', dsdevs)])
@@ -268,11 +273,13 @@
self.assertEqual(data['apply_hostname_bounce']['hostname'],
odata['HostName'])
+ new_dhcp_cfg = load_file(self.dhcp_cfg)
+ self.assertIn('my-random-hostname', new_dhcp_cfg)
+
def test_apply_bounce_call_configurable(self):
# hostname_bounce should be configurable in datasource cfg
cfg = {'hostname_bounce': {'interface': 'eth1', 'policy': 'off',
- 'command': 'my-bounce-command',
- 'hostname_command': 'my-hostname-command'}}
+ 'command': 'my-bounce-command'}}
odata = {'HostName': "xhost",
'dscfg': {'text': base64.b64encode(yaml.dump(cfg)),
'encoding': 'base64'}}
@@ -285,6 +292,9 @@
for k, v in cfg['hostname_bounce'].items():
self.assertEqual(data['apply_hostname_bounce'][k], v)
+ new_dhcp_cfg = load_file(self.dhcp_cfg)
+ self.assertIn('xhost', new_dhcp_cfg)
+
def test_set_hostname_disabled(self):
# config specifying set_hostname off should not bounce
cfg = {'set_hostname': False}
@@ -296,6 +306,9 @@
self.assertEqual(data.get('apply_hostname_bounce', "N/A"), "N/A")
+ new_dhcp_cfg = load_file(self.dhcp_cfg)
+ self.assertIn('xhost', new_dhcp_cfg)
+
def test_default_ephemeral(self):
# make sure the ephemeral device works
odata = {}