diff options
-rw-r--r-- | cloudinit/distros/arch.py | 90 | ||||
-rw-r--r-- | tests/unittests/test_distros/__init__.py | 21 | ||||
-rw-r--r-- | tests/unittests/test_distros/test_arch.py | 45 |
3 files changed, 125 insertions, 31 deletions
diff --git a/cloudinit/distros/arch.py b/cloudinit/distros/arch.py index b4c0ba72..f87a3432 100644 --- a/cloudinit/distros/arch.py +++ b/cloudinit/distros/arch.py @@ -14,6 +14,8 @@ from cloudinit.distros.parsers.hostname import HostnameConf from cloudinit.settings import PER_INSTANCE +import os + LOG = logging.getLogger(__name__) @@ -52,31 +54,10 @@ class Distro(distros.Distro): entries = net_util.translate_network(settings) LOG.debug("Translated ubuntu style network settings %s into %s", settings, entries) - dev_names = entries.keys() - # Format for netctl - for (dev, info) in entries.items(): - nameservers = [] - net_fn = self.network_conf_dir + dev - net_cfg = { - 'Connection': 'ethernet', - 'Interface': dev, - 'IP': info.get('bootproto'), - 'Address': "('%s/%s')" % (info.get('address'), - info.get('netmask')), - 'Gateway': info.get('gateway'), - 'DNS': str(tuple(info.get('dns-nameservers'))).replace(',', '') - } - util.write_file(net_fn, convert_netctl(net_cfg)) - if info.get('auto'): - self._enable_interface(dev) - if 'dns-nameservers' in info: - nameservers.extend(info['dns-nameservers']) - - if nameservers: - util.write_file(self.resolve_conf_fn, - convert_resolv_conf(nameservers)) - - return dev_names + return _render_network( + entries, resolv_conf=self.resolve_conf_fn, + conf_dir=self.network_conf_dir, + enable_func=self._enable_interface) def _enable_interface(self, device_name): cmd = ['netctl', 'reenable', device_name] @@ -173,13 +154,60 @@ class Distro(distros.Distro): ["-y"], freq=PER_INSTANCE) +def _render_network(entries, target="/", conf_dir="etc/netctl", + resolv_conf="etc/resolv.conf", enable_func=None): + """Render the translate_network format into netctl files in target. + Paths will be rendered under target. + """ + + devs = [] + nameservers = [] + resolv_conf = util.target_path(target, resolv_conf) + conf_dir = util.target_path(target, conf_dir) + + for (dev, info) in entries.items(): + if dev == 'lo': + # no configuration should be rendered for 'lo' + continue + devs.append(dev) + net_fn = os.path.join(conf_dir, dev) + net_cfg = { + 'Connection': 'ethernet', + 'Interface': dev, + 'IP': info.get('bootproto'), + 'Address': "%s/%s" % (info.get('address'), + info.get('netmask')), + 'Gateway': info.get('gateway'), + 'DNS': info.get('dns-nameservers', []), + } + util.write_file(net_fn, convert_netctl(net_cfg)) + if enable_func and info.get('auto'): + enable_func(dev) + if 'dns-nameservers' in info: + nameservers.extend(info['dns-nameservers']) + + if nameservers: + util.write_file(resolv_conf, + convert_resolv_conf(nameservers)) + return devs + + def convert_netctl(settings): - """Returns a settings string formatted for netctl.""" - result = '' - if isinstance(settings, dict): - for k, v in settings.items(): - result = result + '%s=%s\n' % (k, v) - return result + """Given a dictionary, returns a string in netctl profile format. + + netctl profile is described at: + https://git.archlinux.org/netctl.git/tree/docs/netctl.profile.5.txt + + Note that the 'Special Quoting Rules' are not handled here.""" + result = [] + for key in sorted(settings): + val = settings[key] + if val is None: + val = "" + elif isinstance(val, (tuple, list)): + val = "(" + ' '.join("'%s'" % v for v in val) + ")" + result.append("%s=%s\n" % (key, val)) + return ''.join(result) def convert_resolv_conf(settings): diff --git a/tests/unittests/test_distros/__init__.py b/tests/unittests/test_distros/__init__.py index e69de29b..5394aa56 100644 --- a/tests/unittests/test_distros/__init__.py +++ b/tests/unittests/test_distros/__init__.py @@ -0,0 +1,21 @@ +# This file is part of cloud-init. See LICENSE file for license information. +import copy + +from cloudinit import distros +from cloudinit import helpers +from cloudinit import settings + + +def _get_distro(dtype, system_info=None): + """Return a Distro class of distro 'dtype'. + + cfg is format of CFG_BUILTIN['system_info']. + + example: _get_distro("debian") + """ + if system_info is None: + system_info = copy.deepcopy(settings.CFG_BUILTIN['system_info']) + system_info['distro'] = dtype + paths = helpers.Paths(system_info['paths']) + distro_cls = distros.fetch(dtype) + return distro_cls(dtype, system_info, paths) diff --git a/tests/unittests/test_distros/test_arch.py b/tests/unittests/test_distros/test_arch.py new file mode 100644 index 00000000..3d4c9a70 --- /dev/null +++ b/tests/unittests/test_distros/test_arch.py @@ -0,0 +1,45 @@ +# This file is part of cloud-init. See LICENSE file for license information. + +from cloudinit.distros.arch import _render_network +from cloudinit import util + +from ..helpers import (CiTestCase, dir2dict) + +from . import _get_distro + + +class TestArch(CiTestCase): + + def test_get_distro(self): + distro = _get_distro("arch") + hostname = "myhostname" + hostfile = self.tmp_path("hostfile") + distro._write_hostname(hostname, hostfile) + self.assertEqual(hostname + "\n", util.load_file(hostfile)) + + +class TestRenderNetwork(CiTestCase): + def test_basic_static(self): + """Just the most basic static config. + + note 'lo' should not be rendered as an interface.""" + entries = {'eth0': {'auto': True, + 'dns-nameservers': ['8.8.8.8'], + 'bootproto': 'static', + 'address': '10.0.0.2', + 'gateway': '10.0.0.1', + 'netmask': '255.255.255.0'}, + 'lo': {'auto': True}} + target = self.tmp_dir() + devs = _render_network(entries, target=target) + files = dir2dict(target, prefix=target) + self.assertEqual(['eth0'], devs) + self.assertEqual( + {'/etc/netctl/eth0': '\n'.join([ + "Address=10.0.0.2/255.255.255.0", + "Connection=ethernet", + "DNS=('8.8.8.8')", + "Gateway=10.0.0.1", + "IP=static", + "Interface=eth0", ""]), + '/etc/resolv.conf': 'nameserver 8.8.8.8\n'}, files) |