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
_______________________________________________ Mailing list: https://launchpad.net/~cloud-init-dev Post to : [email protected] Unsubscribe : https://launchpad.net/~cloud-init-dev More help : https://help.launchpad.net/ListHelp

