cloud-init-dev team mailing list archive
-
cloud-init-dev team
-
Mailing list archive
-
Message #00240
[Merge] lp:~smoser/cloud-init/lp1020695 into lp:cloud-init
Scott Moser has proposed merging lp:~smoser/cloud-init/lp1020695 into lp:cloud-init.
Requested reviews:
cloud init development team (cloud-init-dev)
Related bugs:
Bug #1020695 in cloud-init: "Add variable for local IP address to /etc/hosts manager"
https://bugs.launchpad.net/cloud-init/+bug/1020695
For more details, see:
https://code.launchpad.net/~smoser/cloud-init/lp1020695/+merge/163216
Improve the data available in /etc/hosts namagement
Previously, cloud-config like:
manage_etc_hosts: template
would render /etc/hosts file from /etc/cloud/templates/. However, there were not many variables available for substitution.
This change does the following things:
* moves the 'manage_etc_hosts' key to:
| etc_hosts:
| manage_mode: template
but supports it in the old place
* allows users to reference things from metadata:
$public_ipv4
$private_ipv4
$public_hostname
$private_hostname
* allow reference in template to:
$devaddr_<devname> ($devaddr_eth0) ip address of the device
$devaddr6_<devname> ($devaddr6_eth0) ipv6 addr on the device
* adds configuration of 'etc_hosts' like this:
| etc_hosts:
| template_from_metadata:
| public-ipv4: '0.0.0.0'
| public-hostname: 'undefined-public-hostname'
| private-ipv4: '0.0.0.0'
| private-hostname: 'undefined-private-hostname'
| default_addr: '0.0.0.0',
| default_addr6: '::1',
| manage_mode: False
'template_from_metadata' is 'field-name': 'default' pairs.
default_addr and default_addr6 are used if the interface referenced
does not have an address or is not present.
Anything in 'template_from_metadata' will be loaded from the
metadata for the cloud. ie: metadata['public-ipv4']. and placed
into the template (with - replaced with _)
--
https://code.launchpad.net/~smoser/cloud-init/lp1020695/+merge/163216
Your team cloud init development team is requested to review the proposed merge of lp:~smoser/cloud-init/lp1020695 into lp:cloud-init.
=== modified file 'cloudinit/config/cc_update_etc_hosts.py'
--- cloudinit/config/cc_update_etc_hosts.py 2013-01-15 21:34:51 +0000
+++ cloudinit/config/cc_update_etc_hosts.py 2013-05-09 20:12:38 +0000
@@ -18,6 +18,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+from cloudinit import netinfo
from cloudinit import templater
from cloudinit import util
@@ -26,14 +27,44 @@
frequency = PER_ALWAYS
+def get_template_parms(hostname, fqdn, cfg, metadata):
+ # metadata is a cloud metadata
+ # cfg is a 'etc_hosts' entry in cloud-config
+ # etc_hosts
+ # template_from_metadata:
+ # public-ipv4: '0.0.0.0'
+ # public-hostname: 'undefined-public-hostname'
+ # private-ipv4: '0.0.0.0'
+ # private-hostname: 'undefined-private-hostname'
+ # default_addr: '0.0.0.0'
+ # manage_mode: 'template'
+ parms = {'hostname': hostname, 'fqdn': fqdn}
+
+ if metadata:
+ for field, default in cfg.get('template_from_metadata', {}).iteritems():
+ parms[field.replace("-","_")] = metadata.get(field, default)
+
+ dev_default = cfg.get('default_addr', "0.0.0.0")
+ dev_default6 = cfg.get('default_addr6', "0.0.0.0")
+ devs = netinfo.netdev_info()
+ for dev, info in devs.items():
+ parms['devaddr_' + dev] = info.get('addr') or dev_default
+ parms['devaddr6_' + dev] = info.get('addr6') or dev_default6
+
+ return parms
+
+
def handle(name, cfg, cloud, log, _args):
- manage_hosts = util.get_cfg_option_str(cfg, "manage_etc_hosts", False)
+
+ # copy the old 'manage_etc_hosts' value to new location
+ hostscfg = cfg.get('etc_hosts', {})
+ if manage_hosts:
+ if 'manage_etc_hosts' in cfg:
+ hostscfg['manage_mode'] = cfg['manage_etc_hosts']
+
+ manage_hosts = hostscfg['manage_mode']
+
if util.translate_bool(manage_hosts, addons=['template']):
- (hostname, fqdn) = util.get_hostname_fqdn(cfg, cloud)
- if not hostname:
- log.warn(("Option 'manage_etc_hosts' was set,"
- " but no hostname was found"))
- return
# Render from a template file
tpl_fn_name = cloud.get_template_filename("hosts.%s" %
@@ -43,8 +74,16 @@
" found for distro %s") %
(cloud.distro.osfamily))
- templater.render_to_file(tpl_fn_name, '/etc/hosts',
- {'hostname': hostname, 'fqdn': fqdn})
+ (hostname, fqdn) = util.get_hostname_fqdn(cfg, cloud)
+ if not hostname:
+ log.warn(("Option 'manage_etc_hosts' was set,"
+ " but no hostname was found"))
+ return
+
+ parms = get_template_parms(hostname, fqdn, hostscfg,
+ cloud.datasource.metadata)
+
+ templater.render_to_file(tpl_fn_name, '/etc/hosts', parms)
elif manage_hosts == "localhost":
(hostname, fqdn) = util.get_hostname_fqdn(cfg, cloud)
=== modified file 'cloudinit/settings.py'
--- cloudinit/settings.py 2012-08-20 05:28:14 +0000
+++ cloudinit/settings.py 2013-05-09 20:12:38 +0000
@@ -49,6 +49,17 @@
},
'distro': 'ubuntu',
},
+ 'etc_hosts': {
+ 'template_from_metadata': {
+ 'public-ipv4': '0.0.0.0',
+ 'public-hostname': 'undefined-public-hostname',
+ 'private-ipv4': '0.0.0.0',
+ 'private-hostname': 'undefined-private-hostname',
+ },
+ 'default_addr': '0.0.0.0',
+ 'default_addr6': '::1',
+ 'manage_mode': False
+ }
}
# Valid frequencies of handlers/modules
=== modified file 'doc/examples/cloud-config.txt'
--- doc/examples/cloud-config.txt 2013-04-03 22:29:32 +0000
+++ doc/examples/cloud-config.txt 2013-05-09 20:12:38 +0000
@@ -440,10 +440,25 @@
# true or 'template':
# on every boot, /etc/hosts will be re-written from
# /etc/cloud/templates/hosts.tmpl.
-# The strings '$hostname' and '$fqdn' are replaced in the template
-# with the appropriate values.
# To make modifications persistant across a reboot, you must make
-# modificatoins to /etc/cloud/templates/hosts.tmpl
+# modifications to /etc/cloud/templates/hosts.tmpl
+#
+# You can use the following values in the template:
+# $hostname: hostname
+# $fqdn: fully qualified hostname
+# You can reference a specific device's ipv4 or ipv6 address with:
+# $devaddr_<name> (example: devaddr_eth0)
+# $devaddr6_<name> (example: devaddr6_eth0)
+# Be careful referencing addresses, as the network device might not be
+# configured at the point when the update is done.
+#
+# Other values can be referenced directly from the metadata service:
+# By default that list, and default value (if not present in metadata) are:
+# template_name metadata_name default
+# $public_ipv4 public-ipv4 0.0.0.0
+# $public_hostname public-hostname undefined-private-hostname
+# $private_ipv4 public-ipv4 0.0.0.0
+# $private_hostname public-hostname undefined-private-hostname
#
# localhost:
# This option ensures that an entry is present for fqdn as described in
=== added file 'tests/unittests/test_handler/test_handler_etc_hosts.py'
--- tests/unittests/test_handler/test_handler_etc_hosts.py 1970-01-01 00:00:00 +0000
+++ tests/unittests/test_handler/test_handler_etc_hosts.py 2013-05-09 20:12:38 +0000
@@ -0,0 +1,53 @@
+from mocker import MockerTestCase
+
+from cloudinit import netinfo
+from cloudinit.config.cc_update_etc_hosts import get_template_parms
+
+NETDEV_INFO = {
+ 'eth0': {'addr': '', 'bcast': '', 'hwaddr': 'e8:9a:8f:66:13:ca',
+ 'mask': '', 'up': True},
+ 'lo': {'addr': '127.0.0.1', 'addr6': '::1/128', 'bcast': '',
+ 'hwaddr': '', 'mask': '255.0.0.0', 'up': True},
+ 'lxcbr0': {'addr': '10.0.3.1', 'addr6': 'fe80::8061:d9ff:fed6:deca/64',
+ 'bcast': '10.0.3.255', 'hwaddr': '00:00:00:00:00:00',
+ 'mask': '255.255.255.0', 'up': True},
+ 'wlan0': {'addr': '10.155.36.209', 'addr6': 'fe80::d2df:9aff:fe1a:8fda/64',
+ 'bcast': '10.155.63.255', 'hwaddr': 'd0:df:9a:1a:8f:da',
+ 'mask': '255.255.224.0', 'up': True}
+}
+
+
+class TestTemplateParms(MockerTestCase):
+ def test_basic(self):
+ ndinfo = self.mocker.replace(netinfo.netdev_info,
+ passthrough=False)
+ ndinfo()
+ self.mocker.result(NETDEV_INFO)
+ self.mocker.replay()
+
+ parms = get_template_parms("myhost", "myfqdn", {}, {})
+
+ self.assertEqual(parms['devaddr_wlan0'], '10.155.36.209')
+
+ def test_md_values(self):
+ ndinfo = self.mocker.replace(netinfo.netdev_info,
+ passthrough=False)
+ ndinfo()
+ self.mocker.result(NETDEV_INFO)
+ self.mocker.replay()
+
+ nohost = 'NOHOSTHERE'
+ mycfg = {
+ 'template_from_metadata': {
+ 'public-ipv4': '0.0.0.0',
+ 'public-hostname': nohost,
+ }
+ }
+ md = {'public-ipv4': '10.0.1.2'}
+ parms = get_template_parms("myhost", "myfqdn", mycfg, md)
+
+ self.assertEqual(parms['devaddr_wlan0'], '10.155.36.209')
+ self.assertEqual(parms['public_ipv4'], '10.0.1.2')
+ self.assertEqual(parms['public_hostname'], nohost)
+
+# vi: ts=4 expandtab