summaryrefslogtreecommitdiff
path: root/tests/unittests/test_distros
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unittests/test_distros')
-rw-r--r--tests/unittests/test_distros/test_create_users.py30
-rw-r--r--tests/unittests/test_distros/test_freebsd.py45
-rw-r--r--tests/unittests/test_distros/test_generic.py24
-rw-r--r--tests/unittests/test_distros/test_netconfig.py403
-rw-r--r--tests/unittests/test_distros/test_user_data_normalize.py3
5 files changed, 338 insertions, 167 deletions
diff --git a/tests/unittests/test_distros/test_create_users.py b/tests/unittests/test_distros/test_create_users.py
index c3f258d5..ef11784d 100644
--- a/tests/unittests/test_distros/test_create_users.py
+++ b/tests/unittests/test_distros/test_create_users.py
@@ -206,7 +206,7 @@ class TestCreateUser(CiTestCase):
user = 'foouser'
self.dist.create_user(user, ssh_redirect_user='someuser')
self.assertIn(
- 'WARNING: Unable to disable ssh logins for foouser given '
+ 'WARNING: Unable to disable SSH logins for foouser given '
'ssh_redirect_user: someuser. No cloud public-keys present.\n',
self.logs.getvalue())
m_setup_user_keys.assert_not_called()
@@ -240,4 +240,32 @@ class TestCreateUser(CiTestCase):
[mock.call(set(['auth1']), user), # not disabled
mock.call(set(['key1']), 'foouser', options=disable_prefix)])
+ @mock.patch("cloudinit.distros.util.which")
+ def test_lock_with_usermod_if_no_passwd(self, m_which, m_subp,
+ m_is_snappy):
+ """Lock uses usermod --lock if no 'passwd' cmd available."""
+ m_which.side_effect = lambda m: m in ('usermod',)
+ self.dist.lock_passwd("bob")
+ self.assertEqual(
+ [mock.call(['usermod', '--lock', 'bob'])],
+ m_subp.call_args_list)
+
+ @mock.patch("cloudinit.distros.util.which")
+ def test_lock_with_passwd_if_available(self, m_which, m_subp,
+ m_is_snappy):
+ """Lock with only passwd will use passwd."""
+ m_which.side_effect = lambda m: m in ('passwd',)
+ self.dist.lock_passwd("bob")
+ self.assertEqual(
+ [mock.call(['passwd', '-l', 'bob'])],
+ m_subp.call_args_list)
+
+ @mock.patch("cloudinit.distros.util.which")
+ def test_lock_raises_runtime_if_no_commands(self, m_which, m_subp,
+ m_is_snappy):
+ """Lock with no commands available raises RuntimeError."""
+ m_which.return_value = None
+ with self.assertRaises(RuntimeError):
+ self.dist.lock_passwd("bob")
+
# vi: ts=4 expandtab
diff --git a/tests/unittests/test_distros/test_freebsd.py b/tests/unittests/test_distros/test_freebsd.py
new file mode 100644
index 00000000..8af253a2
--- /dev/null
+++ b/tests/unittests/test_distros/test_freebsd.py
@@ -0,0 +1,45 @@
+# This file is part of cloud-init. See LICENSE file for license information.
+
+from cloudinit.util import (find_freebsd_part, get_path_dev_freebsd)
+from cloudinit.tests.helpers import (CiTestCase, mock)
+
+import os
+
+
+class TestDeviceLookUp(CiTestCase):
+
+ @mock.patch('cloudinit.util.subp')
+ def test_find_freebsd_part_label(self, mock_subp):
+ glabel_out = '''
+gptid/fa52d426-c337-11e6-8911-00155d4c5e47 N/A da0p1
+ label/rootfs N/A da0p2
+ label/swap N/A da0p3
+'''
+ mock_subp.return_value = (glabel_out, "")
+ res = find_freebsd_part("/dev/label/rootfs")
+ self.assertEqual("da0p2", res)
+
+ @mock.patch('cloudinit.util.subp')
+ def test_find_freebsd_part_gpt(self, mock_subp):
+ glabel_out = '''
+ gpt/bootfs N/A vtbd0p1
+gptid/3f4cbe26-75da-11e8-a8f2-002590ec6166 N/A vtbd0p1
+ gpt/swapfs N/A vtbd0p2
+ gpt/rootfs N/A vtbd0p3
+ iso9660/cidata N/A vtbd2
+'''
+ mock_subp.return_value = (glabel_out, "")
+ res = find_freebsd_part("/dev/gpt/rootfs")
+ self.assertEqual("vtbd0p3", res)
+
+ def test_get_path_dev_freebsd_label(self):
+ mnt_list = '''
+/dev/label/rootfs / ufs rw 1 1
+devfs /dev devfs rw,multilabel 0 0
+fdescfs /dev/fd fdescfs rw 0 0
+/dev/da1s1 /mnt/resource ufs rw 2 2
+'''
+ with mock.patch.object(os.path, 'exists',
+ return_value=True):
+ res = get_path_dev_freebsd('/etc', mnt_list)
+ self.assertIsNotNone(res)
diff --git a/tests/unittests/test_distros/test_generic.py b/tests/unittests/test_distros/test_generic.py
index 791fe612..02b334e3 100644
--- a/tests/unittests/test_distros/test_generic.py
+++ b/tests/unittests/test_distros/test_generic.py
@@ -8,11 +8,7 @@ from cloudinit.tests import helpers
import os
import shutil
import tempfile
-
-try:
- from unittest import mock
-except ImportError:
- import mock
+from unittest import mock
unknown_arch_info = {
'arches': ['default'],
@@ -244,5 +240,23 @@ class TestGenericDistro(helpers.FilesystemMockingTestCase):
with self.assertRaises(NotImplementedError):
d.get_locale()
+ def test_expire_passwd_uses_chpasswd(self):
+ """Test ubuntu.expire_passwd uses the passwd command."""
+ for d_name in ("ubuntu", "rhel"):
+ cls = distros.fetch(d_name)
+ d = cls(d_name, {}, None)
+ with mock.patch("cloudinit.util.subp") as m_subp:
+ d.expire_passwd("myuser")
+ m_subp.assert_called_once_with(["passwd", "--expire", "myuser"])
+
+ def test_expire_passwd_freebsd_uses_pw_command(self):
+ """Test FreeBSD.expire_passwd uses the pw command."""
+ cls = distros.fetch("freebsd")
+ d = cls("freebsd", {}, None)
+ with mock.patch("cloudinit.util.subp") as m_subp:
+ d.expire_passwd("myuser")
+ m_subp.assert_called_once_with(
+ ["pw", "usermod", "myuser", "-p", "01-Jan-1970"])
+
# vi: ts=4 expandtab
diff --git a/tests/unittests/test_distros/test_netconfig.py b/tests/unittests/test_distros/test_netconfig.py
index 6e339355..ccf66161 100644
--- a/tests/unittests/test_distros/test_netconfig.py
+++ b/tests/unittests/test_distros/test_netconfig.py
@@ -1,20 +1,17 @@
# This file is part of cloud-init. See LICENSE file for license information.
+import copy
import os
-from six import StringIO
+from io import StringIO
from textwrap import dedent
-
-try:
- from unittest import mock
-except ImportError:
- import mock
+from unittest import mock
from cloudinit import distros
from cloudinit.distros.parsers.sys_conf import SysConf
from cloudinit import helpers
from cloudinit import settings
from cloudinit.tests.helpers import (
- FilesystemMockingTestCase, dir2dict, populate_dir)
+ FilesystemMockingTestCase, dir2dict)
from cloudinit import util
@@ -91,9 +88,9 @@ V1_NET_CFG = {'config': [{'name': 'eth0',
'version': 1}
V1_NET_CFG_OUTPUT = """\
-# This file is generated from information provided by
-# the datasource. Changes to it will not persist across an instance.
-# To disable cloud-init's network configuration capabilities, write a file
+# This file is generated from information provided by the datasource. Changes
+# to it will not persist across an instance reboot. To disable cloud-init's
+# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
auto lo
@@ -109,13 +106,31 @@ auto eth1
iface eth1 inet dhcp
"""
+V1_NET_CFG_IPV6_OUTPUT = """\
+# This file is generated from information provided by the datasource. Changes
+# to it will not persist across an instance reboot. To disable cloud-init's
+# network configuration capabilities, write a file
+# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
+# network: {config: disabled}
+auto lo
+iface lo inet loopback
+
+auto eth0
+iface eth0 inet6 static
+ address 2607:f0d0:1002:0011::2/64
+ gateway 2607:f0d0:1002:0011::1
+
+auto eth1
+iface eth1 inet dhcp
+"""
+
V1_NET_CFG_IPV6 = {'config': [{'name': 'eth0',
'subnets': [{'address':
'2607:f0d0:1002:0011::2',
'gateway':
'2607:f0d0:1002:0011::1',
'netmask': '64',
- 'type': 'static'}],
+ 'type': 'static6'}],
'type': 'physical'},
{'name': 'eth1',
'subnets': [{'control': 'auto',
@@ -125,9 +140,9 @@ V1_NET_CFG_IPV6 = {'config': [{'name': 'eth0',
V1_TO_V2_NET_CFG_OUTPUT = """\
-# This file is generated from information provided by
-# the datasource. Changes to it will not persist across an instance.
-# To disable cloud-init's network configuration capabilities, write a file
+# This file is generated from information provided by the datasource. Changes
+# to it will not persist across an instance reboot. To disable cloud-init's
+# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
@@ -141,6 +156,23 @@ network:
dhcp4: true
"""
+V1_TO_V2_NET_CFG_IPV6_OUTPUT = """\
+# This file is generated from information provided by the datasource. Changes
+# to it will not persist across an instance reboot. To disable cloud-init's
+# network configuration capabilities, write a file
+# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
+# network: {config: disabled}
+network:
+ version: 2
+ ethernets:
+ eth0:
+ addresses:
+ - 2607:f0d0:1002:0011::2/64
+ gateway6: 2607:f0d0:1002:0011::1
+ eth1:
+ dhcp4: true
+"""
+
V2_NET_CFG = {
'ethernets': {
'eth7': {
@@ -154,9 +186,9 @@ V2_NET_CFG = {
V2_TO_V2_NET_CFG_OUTPUT = """\
-# This file is generated from information provided by
-# the datasource. Changes to it will not persist across an instance.
-# To disable cloud-init's network configuration capabilities, write a file
+# This file is generated from information provided by the datasource. Changes
+# to it will not persist across an instance reboot. To disable cloud-init's
+# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
@@ -213,128 +245,95 @@ class TestNetCfgDistroBase(FilesystemMockingTestCase):
self.assertEqual(v, b2[k])
-class TestNetCfgDistroFreebsd(TestNetCfgDistroBase):
+class TestNetCfgDistroFreeBSD(TestNetCfgDistroBase):
+
+ def setUp(self):
+ super(TestNetCfgDistroFreeBSD, self).setUp()
+ self.distro = self._get_distro('freebsd', renderers=['freebsd'])
- frbsd_ifout = """\
-hn0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
- options=51b<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,TSO4,LRO>
- ether 00:15:5d:4c:73:00
- inet6 fe80::215:5dff:fe4c:7300%hn0 prefixlen 64 scopeid 0x2
- inet 10.156.76.127 netmask 0xfffffc00 broadcast 10.156.79.255
- nd6 options=23<PERFORMNUD,ACCEPT_RTADV,AUTO_LINKLOCAL>
- media: Ethernet autoselect (10Gbase-T <full-duplex>)
- status: active
+ def _apply_and_verify_freebsd(self, apply_fn, config, expected_cfgs=None,
+ bringup=False):
+ if not expected_cfgs:
+ raise ValueError('expected_cfg must not be None')
+
+ tmpd = None
+ with mock.patch('cloudinit.net.freebsd.available') as m_avail:
+ m_avail.return_value = True
+ with self.reRooted(tmpd) as tmpd:
+ util.ensure_dir('/etc')
+ util.ensure_file('/etc/rc.conf')
+ util.ensure_file('/etc/resolv.conf')
+ apply_fn(config, bringup)
+
+ results = dir2dict(tmpd)
+ for cfgpath, expected in expected_cfgs.items():
+ print("----------")
+ print(expected)
+ print("^^^^ expected | rendered VVVVVVV")
+ print(results[cfgpath])
+ print("----------")
+ self.assertEqual(
+ set(expected.split('\n')),
+ set(results[cfgpath].split('\n')))
+ self.assertEqual(0o644, get_mode(cfgpath, tmpd))
+
+ @mock.patch('cloudinit.net.get_interfaces_by_mac')
+ def test_apply_network_config_freebsd_standard(self, ifaces_mac):
+ ifaces_mac.return_value = {
+ '00:15:5d:4c:73:00': 'eth0',
+ }
+ rc_conf_expected = """\
+defaultrouter=192.168.1.254
+ifconfig_eth0='192.168.1.5 netmask 255.255.255.0'
+ifconfig_eth1=DHCP
"""
- @mock.patch('cloudinit.distros.freebsd.Distro.get_ifconfig_list')
- @mock.patch('cloudinit.distros.freebsd.Distro.get_ifconfig_ifname_out')
- def test_get_ip_nic_freebsd(self, ifname_out, iflist):
- frbsd_distro = self._get_distro('freebsd')
- iflist.return_value = "lo0 hn0"
- ifname_out.return_value = self.frbsd_ifout
- res = frbsd_distro.get_ipv4()
- self.assertEqual(res, ['lo0', 'hn0'])
- res = frbsd_distro.get_ipv6()
- self.assertEqual(res, [])
-
- @mock.patch('cloudinit.distros.freebsd.Distro.get_ifconfig_ether')
- @mock.patch('cloudinit.distros.freebsd.Distro.get_ifconfig_ifname_out')
- @mock.patch('cloudinit.distros.freebsd.Distro.get_interface_mac')
- def test_generate_fallback_config_freebsd(self, mac, ifname_out, if_ether):
- frbsd_distro = self._get_distro('freebsd')
-
- if_ether.return_value = 'hn0'
- ifname_out.return_value = self.frbsd_ifout
- mac.return_value = '00:15:5d:4c:73:00'
- res = frbsd_distro.generate_fallback_config()
- self.assertIsNotNone(res)
-
- def test_simple_write_freebsd(self):
- fbsd_distro = self._get_distro('freebsd')
-
- rc_conf = '/etc/rc.conf'
- read_bufs = {
- rc_conf: 'initial-rc-conf-not-validated',
- '/etc/resolv.conf': 'initial-resolv-conf-not-validated',
+ expected_cfgs = {
+ '/etc/rc.conf': rc_conf_expected,
+ '/etc/resolv.conf': ''
}
+ self._apply_and_verify_freebsd(self.distro.apply_network_config,
+ V1_NET_CFG,
+ expected_cfgs=expected_cfgs.copy())
- tmpd = self.tmp_dir()
- populate_dir(tmpd, read_bufs)
- with self.reRooted(tmpd):
- with mock.patch("cloudinit.distros.freebsd.util.subp",
- return_value=('vtnet0', '')):
- fbsd_distro.apply_network(BASE_NET_CFG, False)
- results = dir2dict(tmpd)
-
- self.assertIn(rc_conf, results)
- self.assertCfgEquals(
- dedent('''\
- ifconfig_vtnet0="192.168.1.5 netmask 255.255.255.0"
- ifconfig_vtnet1="DHCP"
- defaultrouter="192.168.1.254"
- '''), results[rc_conf])
- self.assertEqual(0o644, get_mode(rc_conf, tmpd))
-
- def test_simple_write_freebsd_from_v2eni(self):
- fbsd_distro = self._get_distro('freebsd')
-
- rc_conf = '/etc/rc.conf'
- read_bufs = {
- rc_conf: 'initial-rc-conf-not-validated',
- '/etc/resolv.conf': 'initial-resolv-conf-not-validated',
+ @mock.patch('cloudinit.net.get_interfaces_by_mac')
+ def test_apply_network_config_freebsd_ifrename(self, ifaces_mac):
+ ifaces_mac.return_value = {
+ '00:15:5d:4c:73:00': 'vtnet0',
}
+ rc_conf_expected = """\
+ifconfig_vtnet0_name=eth0
+defaultrouter=192.168.1.254
+ifconfig_eth0='192.168.1.5 netmask 255.255.255.0'
+ifconfig_eth1=DHCP
+"""
- tmpd = self.tmp_dir()
- populate_dir(tmpd, read_bufs)
- with self.reRooted(tmpd):
- with mock.patch("cloudinit.distros.freebsd.util.subp",
- return_value=('vtnet0', '')):
- fbsd_distro.apply_network(BASE_NET_CFG_FROM_V2, False)
- results = dir2dict(tmpd)
-
- self.assertIn(rc_conf, results)
- self.assertCfgEquals(
- dedent('''\
- ifconfig_vtnet0="192.168.1.5 netmask 255.255.255.0"
- ifconfig_vtnet1="DHCP"
- defaultrouter="192.168.1.254"
- '''), results[rc_conf])
- self.assertEqual(0o644, get_mode(rc_conf, tmpd))
-
- def test_apply_network_config_fallback_freebsd(self):
- fbsd_distro = self._get_distro('freebsd')
-
- # a weak attempt to verify that we don't have an implementation
- # of _write_network_config or apply_network_config in fbsd now,
- # which would make this test not actually test the fallback.
- self.assertRaises(
- NotImplementedError, fbsd_distro._write_network_config,
- BASE_NET_CFG)
-
- # now run
- mynetcfg = {
- 'config': [{"type": "physical", "name": "eth0",
- "mac_address": "c0:d6:9f:2c:e8:80",
- "subnets": [{"type": "dhcp"}]}],
- 'version': 1}
-
- rc_conf = '/etc/rc.conf'
- read_bufs = {
- rc_conf: 'initial-rc-conf-not-validated',
- '/etc/resolv.conf': 'initial-resolv-conf-not-validated',
+ V1_NET_CFG_RENAME = copy.deepcopy(V1_NET_CFG)
+ V1_NET_CFG_RENAME['config'][0]['mac_address'] = '00:15:5d:4c:73:00'
+
+ expected_cfgs = {
+ '/etc/rc.conf': rc_conf_expected,
+ '/etc/resolv.conf': ''
}
+ self._apply_and_verify_freebsd(self.distro.apply_network_config,
+ V1_NET_CFG_RENAME,
+ expected_cfgs=expected_cfgs.copy())
- tmpd = self.tmp_dir()
- populate_dir(tmpd, read_bufs)
- with self.reRooted(tmpd):
- with mock.patch("cloudinit.distros.freebsd.util.subp",
- return_value=('vtnet0', '')):
- fbsd_distro.apply_network_config(mynetcfg, bring_up=False)
- results = dir2dict(tmpd)
+ @mock.patch('cloudinit.net.get_interfaces_by_mac')
+ def test_apply_network_config_freebsd_nameserver(self, ifaces_mac):
+ ifaces_mac.return_value = {
+ '00:15:5d:4c:73:00': 'eth0',
+ }
- self.assertIn(rc_conf, results)
- self.assertCfgEquals('ifconfig_vtnet0="DHCP"', results[rc_conf])
- self.assertEqual(0o644, get_mode(rc_conf, tmpd))
+ V1_NET_CFG_DNS = copy.deepcopy(V1_NET_CFG)
+ ns = ['1.2.3.4']
+ V1_NET_CFG_DNS['config'][0]['subnets'][0]['dns_nameservers'] = ns
+ expected_cfgs = {
+ '/etc/resolv.conf': 'nameserver 1.2.3.4\n'
+ }
+ self._apply_and_verify_freebsd(self.distro.apply_network_config,
+ V1_NET_CFG_DNS,
+ expected_cfgs=expected_cfgs.copy())
class TestNetCfgDistroUbuntuEni(TestNetCfgDistroBase):
@@ -376,6 +375,14 @@ class TestNetCfgDistroUbuntuEni(TestNetCfgDistroBase):
V1_NET_CFG,
expected_cfgs=expected_cfgs.copy())
+ def test_apply_network_config_ipv6_ub(self):
+ expected_cfgs = {
+ self.eni_path(): V1_NET_CFG_IPV6_OUTPUT
+ }
+ self._apply_and_verify_eni(self.distro.apply_network_config,
+ V1_NET_CFG_IPV6,
+ expected_cfgs=expected_cfgs.copy())
+
class TestNetCfgDistroUbuntuNetplan(TestNetCfgDistroBase):
def setUp(self):
@@ -407,7 +414,7 @@ class TestNetCfgDistroUbuntuNetplan(TestNetCfgDistroBase):
self.assertEqual(0o644, get_mode(cfgpath, tmpd))
def netplan_path(self):
- return '/etc/netplan/50-cloud-init.yaml'
+ return '/etc/netplan/50-cloud-init.yaml'
def test_apply_network_config_v1_to_netplan_ub(self):
expected_cfgs = {
@@ -419,6 +426,16 @@ class TestNetCfgDistroUbuntuNetplan(TestNetCfgDistroBase):
V1_NET_CFG,
expected_cfgs=expected_cfgs.copy())
+ def test_apply_network_config_v1_ipv6_to_netplan_ub(self):
+ expected_cfgs = {
+ self.netplan_path(): V1_TO_V2_NET_CFG_IPV6_OUTPUT,
+ }
+
+ # ub_distro.apply_network_config(V1_NET_CFG_IPV6, False)
+ self._apply_and_verify_netplan(self.distro.apply_network_config,
+ V1_NET_CFG_IPV6,
+ expected_cfgs=expected_cfgs.copy())
+
def test_apply_network_config_v2_passthrough_ub(self):
expected_cfgs = {
self.netplan_path(): V2_TO_V2_NET_CFG_OUTPUT,
@@ -551,24 +568,14 @@ class TestNetCfgDistroOpensuse(TestNetCfgDistroBase):
"""Opensuse uses apply_network_config and renders sysconfig"""
expected_cfgs = {
self.ifcfg_path('eth0'): dedent("""\
- BOOTPROTO=none
- DEFROUTE=yes
- DEVICE=eth0
- GATEWAY=192.168.1.254
+ BOOTPROTO=static
IPADDR=192.168.1.5
NETMASK=255.255.255.0
- NM_CONTROLLED=no
- ONBOOT=yes
- TYPE=Ethernet
- USERCTL=no
+ STARTMODE=auto
"""),
self.ifcfg_path('eth1'): dedent("""\
- BOOTPROTO=dhcp
- DEVICE=eth1
- NM_CONTROLLED=no
- ONBOOT=yes
- TYPE=Ethernet
- USERCTL=no
+ BOOTPROTO=dhcp4
+ STARTMODE=auto
"""),
}
self._apply_and_verify(self.distro.apply_network_config,
@@ -579,24 +586,13 @@ class TestNetCfgDistroOpensuse(TestNetCfgDistroBase):
"""Opensuse uses apply_network_config and renders sysconfig w/ipv6"""
expected_cfgs = {
self.ifcfg_path('eth0'): dedent("""\
- BOOTPROTO=none
- DEFROUTE=yes
- DEVICE=eth0
- IPV6ADDR=2607:f0d0:1002:0011::2/64
- IPV6INIT=yes
- IPV6_DEFAULTGW=2607:f0d0:1002:0011::1
- NM_CONTROLLED=no
- ONBOOT=yes
- TYPE=Ethernet
- USERCTL=no
+ BOOTPROTO=static
+ IPADDR6=2607:f0d0:1002:0011::2/64
+ STARTMODE=auto
"""),
self.ifcfg_path('eth1'): dedent("""\
- BOOTPROTO=dhcp
- DEVICE=eth1
- NM_CONTROLLED=no
- ONBOOT=yes
- TYPE=Ethernet
- USERCTL=no
+ BOOTPROTO=dhcp4
+ STARTMODE=auto
"""),
}
self._apply_and_verify(self.distro.apply_network_config,
@@ -604,6 +600,93 @@ class TestNetCfgDistroOpensuse(TestNetCfgDistroBase):
expected_cfgs=expected_cfgs.copy())
+class TestNetCfgDistroArch(TestNetCfgDistroBase):
+ def setUp(self):
+ super(TestNetCfgDistroArch, self).setUp()
+ self.distro = self._get_distro('arch', renderers=['netplan'])
+
+ def _apply_and_verify(self, apply_fn, config, expected_cfgs=None,
+ bringup=False, with_netplan=False):
+ if not expected_cfgs:
+ raise ValueError('expected_cfg must not be None')
+
+ tmpd = None
+ with mock.patch('cloudinit.net.netplan.available',
+ return_value=with_netplan):
+ with self.reRooted(tmpd) as tmpd:
+ apply_fn(config, bringup)
+
+ results = dir2dict(tmpd)
+ for cfgpath, expected in expected_cfgs.items():
+ print("----------")
+ print(expected)
+ print("^^^^ expected | rendered VVVVVVV")
+ print(results[cfgpath])
+ print("----------")
+ self.assertEqual(expected, results[cfgpath])
+ self.assertEqual(0o644, get_mode(cfgpath, tmpd))
+
+ def netctl_path(self, iface):
+ return '/etc/netctl/%s' % iface
+
+ def netplan_path(self):
+ return '/etc/netplan/50-cloud-init.yaml'
+
+ def test_apply_network_config_v1_without_netplan(self):
+ # Note that this is in fact an invalid netctl config:
+ # "Address=None/None"
+ # But this is what the renderer has been writing out for a long time,
+ # and the test's purpose is to assert that the netctl renderer is
+ # still being used in absence of netplan, not the correctness of the
+ # rendered netctl config.
+ expected_cfgs = {
+ self.netctl_path('eth0'): dedent("""\
+ Address=192.168.1.5/255.255.255.0
+ Connection=ethernet
+ DNS=()
+ Gateway=192.168.1.254
+ IP=static
+ Interface=eth0
+ """),
+ self.netctl_path('eth1'): dedent("""\
+ Address=None/None
+ Connection=ethernet
+ DNS=()
+ Gateway=
+ IP=dhcp
+ Interface=eth1
+ """),
+ }
+
+ # ub_distro.apply_network_config(V1_NET_CFG, False)
+ self._apply_and_verify(self.distro.apply_network_config,
+ V1_NET_CFG,
+ expected_cfgs=expected_cfgs.copy(),
+ with_netplan=False)
+
+ def test_apply_network_config_v1_with_netplan(self):
+ expected_cfgs = {
+ self.netplan_path(): dedent("""\
+ # generated by cloud-init
+ network:
+ version: 2
+ ethernets:
+ eth0:
+ addresses:
+ - 192.168.1.5/24
+ gateway4: 192.168.1.254
+ eth1:
+ dhcp4: true
+ """),
+ }
+
+ with mock.patch('cloudinit.util.is_FreeBSD', return_value=False):
+ self._apply_and_verify(self.distro.apply_network_config,
+ V1_NET_CFG,
+ expected_cfgs=expected_cfgs.copy(),
+ with_netplan=True)
+
+
def get_mode(path, target=None):
return os.stat(util.target_path(target, path)).st_mode & 0o777
diff --git a/tests/unittests/test_distros/test_user_data_normalize.py b/tests/unittests/test_distros/test_user_data_normalize.py
index fa4b6cfe..a6faf0ef 100644
--- a/tests/unittests/test_distros/test_user_data_normalize.py
+++ b/tests/unittests/test_distros/test_user_data_normalize.py
@@ -1,12 +1,13 @@
# This file is part of cloud-init. See LICENSE file for license information.
+from unittest import mock
+
from cloudinit import distros
from cloudinit.distros import ug_util
from cloudinit import helpers
from cloudinit import settings
from cloudinit.tests.helpers import TestCase
-import mock
bcfg = {