diff options
-rw-r--r-- | cloudinit/net/__init__.py | 63 | ||||
-rw-r--r-- | cloudinit/net/tests/test_init.py | 91 |
2 files changed, 137 insertions, 17 deletions
diff --git a/cloudinit/net/__init__.py b/cloudinit/net/__init__.py index c015e793..f69c0ef2 100644 --- a/cloudinit/net/__init__.py +++ b/cloudinit/net/__init__.py @@ -274,23 +274,52 @@ def apply_network_config_names(netcfg, strict_present=True, strict_busy=True): renames are only attempted for interfaces of type 'physical'. It is expected that the network system will create other devices with the correct name in place.""" - renames = [] - for ent in netcfg.get('config', {}): - if ent.get('type') != 'physical': - continue - mac = ent.get('mac_address') - if not mac: - continue - name = ent.get('name') - driver = ent.get('params', {}).get('driver') - device_id = ent.get('params', {}).get('device_id') - if not driver: - driver = device_driver(name) - if not device_id: - device_id = device_devid(name) - renames.append([mac, name, driver, device_id]) - - return _rename_interfaces(renames) + + def _version_1(netcfg): + renames = [] + for ent in netcfg.get('config', {}): + if ent.get('type') != 'physical': + continue + mac = ent.get('mac_address') + if not mac: + continue + name = ent.get('name') + driver = ent.get('params', {}).get('driver') + device_id = ent.get('params', {}).get('device_id') + if not driver: + driver = device_driver(name) + if not device_id: + device_id = device_devid(name) + renames.append([mac, name, driver, device_id]) + return renames + + def _version_2(netcfg): + renames = [] + for key, ent in netcfg.get('ethernets', {}).items(): + # only rename if configured to do so + name = ent.get('set-name') + if not name: + continue + # cloud-init requires macaddress for renaming + mac = ent.get('match', {}).get('macaddress') + if not mac: + continue + driver = ent.get('match', {}).get('driver') + device_id = ent.get('match', {}).get('device_id') + if not driver: + driver = device_driver(name) + if not device_id: + device_id = device_devid(name) + renames.append([mac, name, driver, device_id]) + return renames + + if netcfg.get('version') == 1: + return _rename_interfaces(_version_1(netcfg)) + elif netcfg.get('version') == 2: + return _rename_interfaces(_version_2(netcfg)) + + raise RuntimeError('Failed to apply network config names. Found bad' + ' network config version: %s' % netcfg.get('version')) def interface_has_own_mac(ifname, strict=False): diff --git a/cloudinit/net/tests/test_init.py b/cloudinit/net/tests/test_init.py index 8cb4114e..276556ee 100644 --- a/cloudinit/net/tests/test_init.py +++ b/cloudinit/net/tests/test_init.py @@ -4,6 +4,8 @@ import copy import errno import mock import os +import textwrap +import yaml import cloudinit.net as net from cloudinit.util import ensure_file, write_file, ProcessExecutionError @@ -520,3 +522,92 @@ class TestEphemeralIPV4Network(CiTestCase): with net.EphemeralIPv4Network(**params): self.assertEqual(expected_setup_calls, m_subp.call_args_list) m_subp.assert_has_calls(expected_teardown_calls) + + +class TestApplyNetworkCfgNames(CiTestCase): + V1_CONFIG = textwrap.dedent("""\ + version: 1 + config: + - type: physical + name: interface0 + mac_address: "52:54:00:12:34:00" + subnets: + - type: static + address: 10.0.2.15 + netmask: 255.255.255.0 + gateway: 10.0.2.2 + """) + V2_CONFIG = textwrap.dedent("""\ + version: 2 + ethernets: + interface0: + match: + macaddress: "52:54:00:12:34:00" + addresses: + - 10.0.2.15/24 + gateway4: 10.0.2.2 + set-name: interface0 + """) + + V2_CONFIG_NO_SETNAME = textwrap.dedent("""\ + version: 2 + ethernets: + interface0: + match: + macaddress: "52:54:00:12:34:00" + addresses: + - 10.0.2.15/24 + gateway4: 10.0.2.2 + """) + + V2_CONFIG_NO_MAC = textwrap.dedent("""\ + version: 2 + ethernets: + interface0: + match: + driver: virtio-net + addresses: + - 10.0.2.15/24 + gateway4: 10.0.2.2 + set-name: interface0 + """) + + @mock.patch('cloudinit.net.device_devid') + @mock.patch('cloudinit.net.device_driver') + @mock.patch('cloudinit.net._rename_interfaces') + def test_apply_v1_renames(self, m_rename_interfaces, m_device_driver, + m_device_devid): + m_device_driver.return_value = 'virtio_net' + m_device_devid.return_value = '0x15d8' + + net.apply_network_config_names(yaml.load(self.V1_CONFIG)) + + call = ['52:54:00:12:34:00', 'interface0', 'virtio_net', '0x15d8'] + m_rename_interfaces.assert_called_with([call]) + + @mock.patch('cloudinit.net.device_devid') + @mock.patch('cloudinit.net.device_driver') + @mock.patch('cloudinit.net._rename_interfaces') + def test_apply_v2_renames(self, m_rename_interfaces, m_device_driver, + m_device_devid): + m_device_driver.return_value = 'virtio_net' + m_device_devid.return_value = '0x15d8' + + net.apply_network_config_names(yaml.load(self.V2_CONFIG)) + + call = ['52:54:00:12:34:00', 'interface0', 'virtio_net', '0x15d8'] + m_rename_interfaces.assert_called_with([call]) + + @mock.patch('cloudinit.net._rename_interfaces') + def test_apply_v2_renames_skips_without_setname(self, m_rename_interfaces): + net.apply_network_config_names(yaml.load(self.V2_CONFIG_NO_SETNAME)) + m_rename_interfaces.assert_called_with([]) + + @mock.patch('cloudinit.net._rename_interfaces') + def test_apply_v2_renames_skips_without_mac(self, m_rename_interfaces): + net.apply_network_config_names(yaml.load(self.V2_CONFIG_NO_MAC)) + m_rename_interfaces.assert_called_with([]) + + def test_apply_v2_renames_raises_runtime_error_on_unknown_version(self): + with self.assertRaises(RuntimeError): + net.apply_network_config_names(yaml.load("version: 3")) |