cloud-init-dev team mailing list archive
-
cloud-init-dev team
-
Mailing list archive
-
Message #05844
Re: [Merge] ~i.galic/cloud-init:refactor/net-fbsd into cloud-init:master
Diff comments:
> diff --git a/cloudinit/net/tests/test_init.py b/cloudinit/net/tests/test_init.py
> index f55c31e..5da76ef 100644
> --- a/cloudinit/net/tests/test_init.py
> +++ b/cloudinit/net/tests/test_init.py
> @@ -14,542 +14,6 @@ from cloudinit.util import ensure_file, write_file, ProcessExecutionError
> from cloudinit.tests.helpers import CiTestCase, HttprettyTestCase
>
>
> -class TestSysDevPath(CiTestCase):
> -
When I checkout a fresh copy of your branch it is still missing. Looks like your commit e152c470ae64aa21bc41399d07c0d88f8e4da1c9 removed that class. I don't see any subsequent commits to that file reverting this changeset.
you could just apply another commit with the reverse patch related to test_init.py:
git show e152c470ae64aa21bc41399d07c0d88f8e4da1c9 cloudinit/net/tests/test_init.py > mypatch; patch -p1 -R < mypatch; git commit -m 'revert unittest deletion' cloudinit/net/tests/test_init.py
> - def test_sys_dev_path(self):
> - """sys_dev_path returns a path under SYS_CLASS_NET for a device."""
> - dev = 'something'
> - path = 'attribute'
> - expected = net.SYS_CLASS_NET + dev + '/' + path
> - self.assertEqual(expected, net.sys_dev_path(dev, path))
> -
> - def test_sys_dev_path_without_path(self):
> - """When path param isn't provided it defaults to empty string."""
> - dev = 'something'
> - expected = net.SYS_CLASS_NET + dev + '/'
> - self.assertEqual(expected, net.sys_dev_path(dev))
> -
> -
> -class TestReadSysNet(CiTestCase):
> - with_logs = True
> -
> - def setUp(self):
> - super(TestReadSysNet, self).setUp()
> - sys_mock = mock.patch('cloudinit.net.get_sys_class_path')
> - self.m_sys_path = sys_mock.start()
> - self.sysdir = self.tmp_dir() + '/'
> - self.m_sys_path.return_value = self.sysdir
> - self.addCleanup(sys_mock.stop)
> -
> - def test_read_sys_net_strips_contents_of_sys_path(self):
> - """read_sys_net strips whitespace from the contents of a sys file."""
> - content = 'some stuff with trailing whitespace\t\r\n'
> - write_file(os.path.join(self.sysdir, 'dev', 'attr'), content)
> - self.assertEqual(content.strip(), net.read_sys_net('dev', 'attr'))
> -
> - def test_read_sys_net_reraises_oserror(self):
> - """read_sys_net raises OSError/IOError when file doesn't exist."""
> - # Non-specific Exception because versions of python OSError vs IOError.
> - with self.assertRaises(Exception) as context_manager: # noqa: H202
> - net.read_sys_net('dev', 'attr')
> - error = context_manager.exception
> - self.assertIn('No such file or directory', str(error))
> -
> - def test_read_sys_net_handles_error_with_on_enoent(self):
> - """read_sys_net handles OSError/IOError with on_enoent if provided."""
> - handled_errors = []
> -
> - def on_enoent(e):
> - handled_errors.append(e)
> -
> - net.read_sys_net('dev', 'attr', on_enoent=on_enoent)
> - error = handled_errors[0]
> - self.assertIsInstance(error, Exception)
> - self.assertIn('No such file or directory', str(error))
> -
> - def test_read_sys_net_translates_content(self):
> - """read_sys_net translates content when translate dict is provided."""
> - content = "you're welcome\n"
> - write_file(os.path.join(self.sysdir, 'dev', 'attr'), content)
> - translate = {"you're welcome": 'de nada'}
> - self.assertEqual(
> - 'de nada',
> - net.read_sys_net('dev', 'attr', translate=translate))
> -
> - def test_read_sys_net_errors_on_translation_failures(self):
> - """read_sys_net raises a KeyError and logs details on failure."""
> - content = "you're welcome\n"
> - write_file(os.path.join(self.sysdir, 'dev', 'attr'), content)
> - with self.assertRaises(KeyError) as context_manager:
> - net.read_sys_net('dev', 'attr', translate={})
> - error = context_manager.exception
> - self.assertEqual('"you\'re welcome"', str(error))
> - self.assertIn(
> - "Found unexpected (not translatable) value 'you're welcome' in "
> - "'{0}dev/attr".format(self.sysdir),
> - self.logs.getvalue())
> -
> - def test_read_sys_net_handles_handles_with_onkeyerror(self):
> - """read_sys_net handles translation errors calling on_keyerror."""
> - content = "you're welcome\n"
> - write_file(os.path.join(self.sysdir, 'dev', 'attr'), content)
> - handled_errors = []
> -
> - def on_keyerror(e):
> - handled_errors.append(e)
> -
> - net.read_sys_net('dev', 'attr', translate={}, on_keyerror=on_keyerror)
> - error = handled_errors[0]
> - self.assertIsInstance(error, KeyError)
> - self.assertEqual('"you\'re welcome"', str(error))
> -
> - def test_read_sys_net_safe_false_on_translate_failure(self):
> - """read_sys_net_safe returns False on translation failures."""
> - content = "you're welcome\n"
> - write_file(os.path.join(self.sysdir, 'dev', 'attr'), content)
> - self.assertFalse(net.read_sys_net_safe('dev', 'attr', translate={}))
> -
> - def test_read_sys_net_safe_returns_false_on_noent_failure(self):
> - """read_sys_net_safe returns False on file not found failures."""
> - self.assertFalse(net.read_sys_net_safe('dev', 'attr'))
> -
> - def test_read_sys_net_int_returns_none_on_error(self):
> - """read_sys_net_safe returns None on failures."""
> - self.assertFalse(net.read_sys_net_int('dev', 'attr'))
> -
> - def test_read_sys_net_int_returns_none_on_valueerror(self):
> - """read_sys_net_safe returns None when content is not an int."""
> - write_file(os.path.join(self.sysdir, 'dev', 'attr'), 'NOTINT\n')
> - self.assertFalse(net.read_sys_net_int('dev', 'attr'))
> -
> - def test_read_sys_net_int_returns_integer_from_content(self):
> - """read_sys_net_safe returns None on failures."""
> - write_file(os.path.join(self.sysdir, 'dev', 'attr'), '1\n')
> - self.assertEqual(1, net.read_sys_net_int('dev', 'attr'))
> -
> - def test_is_up_true(self):
> - """is_up is True if sys/net/devname/operstate is 'up' or 'unknown'."""
> - for state in ['up', 'unknown']:
> - write_file(os.path.join(self.sysdir, 'eth0', 'operstate'), state)
> - self.assertTrue(net.is_up('eth0'))
> -
> - def test_is_up_false(self):
> - """is_up is False if sys/net/devname/operstate is 'down' or invalid."""
> - for state in ['down', 'incomprehensible']:
> - write_file(os.path.join(self.sysdir, 'eth0', 'operstate'), state)
> - self.assertFalse(net.is_up('eth0'))
> -
> - def test_is_wireless(self):
> - """is_wireless is True when /sys/net/devname/wireless exists."""
> - self.assertFalse(net.is_wireless('eth0'))
> - ensure_file(os.path.join(self.sysdir, 'eth0', 'wireless'))
> - self.assertTrue(net.is_wireless('eth0'))
> -
> - def test_is_bridge(self):
> - """is_bridge is True when /sys/net/devname/bridge exists."""
> - self.assertFalse(net.is_bridge('eth0'))
> - ensure_file(os.path.join(self.sysdir, 'eth0', 'bridge'))
> - self.assertTrue(net.is_bridge('eth0'))
> -
> - def test_is_bond(self):
> - """is_bond is True when /sys/net/devname/bonding exists."""
> - self.assertFalse(net.is_bond('eth0'))
> - ensure_file(os.path.join(self.sysdir, 'eth0', 'bonding'))
> - self.assertTrue(net.is_bond('eth0'))
> -
> - def test_is_vlan(self):
> - """is_vlan is True when /sys/net/devname/uevent has DEVTYPE=vlan."""
> - ensure_file(os.path.join(self.sysdir, 'eth0', 'uevent'))
> - self.assertFalse(net.is_vlan('eth0'))
> - content = 'junk\nDEVTYPE=vlan\njunk\n'
> - write_file(os.path.join(self.sysdir, 'eth0', 'uevent'), content)
> - self.assertTrue(net.is_vlan('eth0'))
> -
> - def test_is_connected_when_physically_connected(self):
> - """is_connected is True when /sys/net/devname/iflink reports 2."""
> - self.assertFalse(net.is_connected('eth0'))
> - write_file(os.path.join(self.sysdir, 'eth0', 'iflink'), "2")
> - self.assertTrue(net.is_connected('eth0'))
> -
> - def test_is_connected_when_wireless_and_carrier_active(self):
> - """is_connected is True if wireless /sys/net/devname/carrier is 1."""
> - self.assertFalse(net.is_connected('eth0'))
> - ensure_file(os.path.join(self.sysdir, 'eth0', 'wireless'))
> - self.assertFalse(net.is_connected('eth0'))
> - write_file(os.path.join(self.sysdir, 'eth0', 'carrier'), "1")
> - self.assertTrue(net.is_connected('eth0'))
> -
> - def test_is_physical(self):
> - """is_physical is True when /sys/net/devname/device exists."""
> - self.assertFalse(net.is_physical('eth0'))
> - ensure_file(os.path.join(self.sysdir, 'eth0', 'device'))
> - self.assertTrue(net.is_physical('eth0'))
> -
> - def test_is_present(self):
> - """is_present is True when /sys/net/devname exists."""
> - self.assertFalse(net.is_present('eth0'))
> - ensure_file(os.path.join(self.sysdir, 'eth0', 'device'))
> - self.assertTrue(net.is_present('eth0'))
> -
> -
> -class TestGenerateFallbackConfig(CiTestCase):
> -
> - def setUp(self):
> - super(TestGenerateFallbackConfig, self).setUp()
> - sys_mock = mock.patch('cloudinit.net.get_sys_class_path')
> - self.m_sys_path = sys_mock.start()
> - self.sysdir = self.tmp_dir() + '/'
> - self.m_sys_path.return_value = self.sysdir
> - self.addCleanup(sys_mock.stop)
> - self.add_patch('cloudinit.net.util.is_container', 'm_is_container',
> - return_value=False)
> - self.add_patch('cloudinit.net.util.udevadm_settle', 'm_settle')
> -
> - def test_generate_fallback_finds_connected_eth_with_mac(self):
> - """generate_fallback_config finds any connected device with a mac."""
> - write_file(os.path.join(self.sysdir, 'eth0', 'carrier'), '1')
> - write_file(os.path.join(self.sysdir, 'eth1', 'carrier'), '1')
> - mac = 'aa:bb:cc:aa:bb:cc'
> - write_file(os.path.join(self.sysdir, 'eth1', 'address'), mac)
> - expected = {
> - 'config': [{'type': 'physical', 'mac_address': mac,
> - 'name': 'eth1', 'subnets': [{'type': 'dhcp'}]}],
> - 'version': 1}
> - self.assertEqual(expected, net.generate_fallback_config())
> -
> - def test_generate_fallback_finds_dormant_eth_with_mac(self):
> - """generate_fallback_config finds any dormant device with a mac."""
> - write_file(os.path.join(self.sysdir, 'eth0', 'dormant'), '1')
> - mac = 'aa:bb:cc:aa:bb:cc'
> - write_file(os.path.join(self.sysdir, 'eth0', 'address'), mac)
> - expected = {
> - 'config': [{'type': 'physical', 'mac_address': mac,
> - 'name': 'eth0', 'subnets': [{'type': 'dhcp'}]}],
> - 'version': 1}
> - self.assertEqual(expected, net.generate_fallback_config())
> -
> - def test_generate_fallback_finds_eth_by_operstate(self):
> - """generate_fallback_config finds any dormant device with a mac."""
> - mac = 'aa:bb:cc:aa:bb:cc'
> - write_file(os.path.join(self.sysdir, 'eth0', 'address'), mac)
> - expected = {
> - 'config': [{'type': 'physical', 'mac_address': mac,
> - 'name': 'eth0', 'subnets': [{'type': 'dhcp'}]}],
> - 'version': 1}
> - valid_operstates = ['dormant', 'down', 'lowerlayerdown', 'unknown']
> - for state in valid_operstates:
> - write_file(os.path.join(self.sysdir, 'eth0', 'operstate'), state)
> - self.assertEqual(expected, net.generate_fallback_config())
> - write_file(os.path.join(self.sysdir, 'eth0', 'operstate'), 'noworky')
> - self.assertIsNone(net.generate_fallback_config())
> -
> - def test_generate_fallback_config_skips_veth(self):
> - """generate_fallback_config will skip any veth interfaces."""
> - # A connected veth which gets ignored
> - write_file(os.path.join(self.sysdir, 'veth0', 'carrier'), '1')
> - self.assertIsNone(net.generate_fallback_config())
> -
> - def test_generate_fallback_config_skips_bridges(self):
> - """generate_fallback_config will skip any bridges interfaces."""
> - # A connected veth which gets ignored
> - write_file(os.path.join(self.sysdir, 'eth0', 'carrier'), '1')
> - mac = 'aa:bb:cc:aa:bb:cc'
> - write_file(os.path.join(self.sysdir, 'eth0', 'address'), mac)
> - ensure_file(os.path.join(self.sysdir, 'eth0', 'bridge'))
> - self.assertIsNone(net.generate_fallback_config())
> -
> - def test_generate_fallback_config_skips_bonds(self):
> - """generate_fallback_config will skip any bonded interfaces."""
> - # A connected veth which gets ignored
> - write_file(os.path.join(self.sysdir, 'eth0', 'carrier'), '1')
> - mac = 'aa:bb:cc:aa:bb:cc'
> - write_file(os.path.join(self.sysdir, 'eth0', 'address'), mac)
> - ensure_file(os.path.join(self.sysdir, 'eth0', 'bonding'))
> - self.assertIsNone(net.generate_fallback_config())
> -
> -
> -class TestGetDeviceList(CiTestCase):
> -
> - def setUp(self):
> - super(TestGetDeviceList, self).setUp()
> - sys_mock = mock.patch('cloudinit.net.get_sys_class_path')
> - self.m_sys_path = sys_mock.start()
> - self.sysdir = self.tmp_dir() + '/'
> - self.m_sys_path.return_value = self.sysdir
> - self.addCleanup(sys_mock.stop)
> -
> - def test_get_devicelist_raise_oserror(self):
> - """get_devicelist raise any non-ENOENT OSerror."""
> - error = OSError('Can not do it')
> - error.errno = errno.EPERM # Set non-ENOENT
> - self.m_sys_path.side_effect = error
> - with self.assertRaises(OSError) as context_manager:
> - net.get_devicelist()
> - exception = context_manager.exception
> - self.assertEqual('Can not do it', str(exception))
> -
> - def test_get_devicelist_empty_without_sys_net(self):
> - """get_devicelist returns empty list when missing SYS_CLASS_NET."""
> - self.m_sys_path.return_value = 'idontexist'
> - self.assertEqual([], net.get_devicelist())
> -
> - def test_get_devicelist_empty_with_no_devices_in_sys_net(self):
> - """get_devicelist returns empty directoty listing for SYS_CLASS_NET."""
> - self.assertEqual([], net.get_devicelist())
> -
> - def test_get_devicelist_lists_any_subdirectories_in_sys_net(self):
> - """get_devicelist returns a directory listing for SYS_CLASS_NET."""
> - write_file(os.path.join(self.sysdir, 'eth0', 'operstate'), 'up')
> - write_file(os.path.join(self.sysdir, 'eth1', 'operstate'), 'up')
> - self.assertItemsEqual(['eth0', 'eth1'], net.get_devicelist())
> -
> -
> -class TestGetInterfaceMAC(CiTestCase):
> -
> - def setUp(self):
> - super(TestGetInterfaceMAC, self).setUp()
> - sys_mock = mock.patch('cloudinit.net.get_sys_class_path')
> - self.m_sys_path = sys_mock.start()
> - self.sysdir = self.tmp_dir() + '/'
> - self.m_sys_path.return_value = self.sysdir
> - self.addCleanup(sys_mock.stop)
> -
> - def test_get_interface_mac_false_with_no_mac(self):
> - """get_device_list returns False when no mac is reported."""
> - ensure_file(os.path.join(self.sysdir, 'eth0', 'bonding'))
> - mac_path = os.path.join(self.sysdir, 'eth0', 'address')
> - self.assertFalse(os.path.exists(mac_path))
> - self.assertFalse(net.get_interface_mac('eth0'))
> -
> - def test_get_interface_mac(self):
> - """get_interfaces returns the mac from SYS_CLASS_NET/dev/address."""
> - mac = 'aa:bb:cc:aa:bb:cc'
> - write_file(os.path.join(self.sysdir, 'eth1', 'address'), mac)
> - self.assertEqual(mac, net.get_interface_mac('eth1'))
> -
> - def test_get_interface_mac_grabs_bonding_address(self):
> - """get_interfaces returns the source device mac for bonded devices."""
> - source_dev_mac = 'aa:bb:cc:aa:bb:cc'
> - bonded_mac = 'dd:ee:ff:dd:ee:ff'
> - write_file(os.path.join(self.sysdir, 'eth1', 'address'), bonded_mac)
> - write_file(
> - os.path.join(self.sysdir, 'eth1', 'bonding_slave', 'perm_hwaddr'),
> - source_dev_mac)
> - self.assertEqual(source_dev_mac, net.get_interface_mac('eth1'))
> -
> - def test_get_interfaces_empty_list_without_sys_net(self):
> - """get_interfaces returns an empty list when missing SYS_CLASS_NET."""
> - self.m_sys_path.return_value = 'idontexist'
> - self.assertEqual([], net.get_interfaces())
> -
> - def test_get_interfaces_by_mac_skips_empty_mac(self):
> - """Ignore 00:00:00:00:00:00 addresses from get_interfaces_by_mac."""
> - empty_mac = '00:00:00:00:00:00'
> - mac = 'aa:bb:cc:aa:bb:cc'
> - write_file(os.path.join(self.sysdir, 'eth1', 'address'), empty_mac)
> - write_file(os.path.join(self.sysdir, 'eth1', 'addr_assign_type'), '0')
> - write_file(os.path.join(self.sysdir, 'eth2', 'addr_assign_type'), '0')
> - write_file(os.path.join(self.sysdir, 'eth2', 'address'), mac)
> - expected = [('eth2', 'aa:bb:cc:aa:bb:cc', None, None)]
> - self.assertEqual(expected, net.get_interfaces())
> -
> - def test_get_interfaces_by_mac_skips_missing_mac(self):
> - """Ignore interfaces without an address from get_interfaces_by_mac."""
> - write_file(os.path.join(self.sysdir, 'eth1', 'addr_assign_type'), '0')
> - address_path = os.path.join(self.sysdir, 'eth1', 'address')
> - self.assertFalse(os.path.exists(address_path))
> - mac = 'aa:bb:cc:aa:bb:cc'
> - write_file(os.path.join(self.sysdir, 'eth2', 'addr_assign_type'), '0')
> - write_file(os.path.join(self.sysdir, 'eth2', 'address'), mac)
> - expected = [('eth2', 'aa:bb:cc:aa:bb:cc', None, None)]
> - self.assertEqual(expected, net.get_interfaces())
> -
> -
> -class TestInterfaceHasOwnMAC(CiTestCase):
> -
> - def setUp(self):
> - super(TestInterfaceHasOwnMAC, self).setUp()
> - sys_mock = mock.patch('cloudinit.net.get_sys_class_path')
> - self.m_sys_path = sys_mock.start()
> - self.sysdir = self.tmp_dir() + '/'
> - self.m_sys_path.return_value = self.sysdir
> - self.addCleanup(sys_mock.stop)
> -
> - def test_interface_has_own_mac_false_when_stolen(self):
> - """Return False from interface_has_own_mac when address is stolen."""
> - write_file(os.path.join(self.sysdir, 'eth1', 'addr_assign_type'), '2')
> - self.assertFalse(net.interface_has_own_mac('eth1'))
> -
> - def test_interface_has_own_mac_true_when_not_stolen(self):
> - """Return False from interface_has_own_mac when mac isn't stolen."""
> - valid_assign_types = ['0', '1', '3']
> - assign_path = os.path.join(self.sysdir, 'eth1', 'addr_assign_type')
> - for _type in valid_assign_types:
> - write_file(assign_path, _type)
> - self.assertTrue(net.interface_has_own_mac('eth1'))
> -
> - def test_interface_has_own_mac_strict_errors_on_absent_assign_type(self):
> - """When addr_assign_type is absent, interface_has_own_mac errors."""
> - with self.assertRaises(ValueError):
> - net.interface_has_own_mac('eth1', strict=True)
> -
> -
> -@mock.patch('cloudinit.net.util.subp')
> -class TestEphemeralIPV4Network(CiTestCase):
> -
> - with_logs = True
> -
> - def setUp(self):
> - super(TestEphemeralIPV4Network, self).setUp()
> - sys_mock = mock.patch('cloudinit.net.get_sys_class_path')
> - self.m_sys_path = sys_mock.start()
> - self.sysdir = self.tmp_dir() + '/'
> - self.m_sys_path.return_value = self.sysdir
> - self.addCleanup(sys_mock.stop)
> -
> - def test_ephemeral_ipv4_network_errors_on_missing_params(self, m_subp):
> - """No required params for EphemeralIPv4Network can be None."""
> - required_params = {
> - 'interface': 'eth0', 'ip': '192.168.2.2',
> - 'prefix_or_mask': '255.255.255.0', 'broadcast': '192.168.2.255'}
> - for key in required_params.keys():
> - params = copy.deepcopy(required_params)
> - params[key] = None
> - with self.assertRaises(ValueError) as context_manager:
> - net.EphemeralIPv4Network(**params)
> - error = context_manager.exception
> - self.assertIn('Cannot init network on', str(error))
> - self.assertEqual(0, m_subp.call_count)
> -
> - def test_ephemeral_ipv4_network_errors_invalid_mask_prefix(self, m_subp):
> - """Raise an error when prefix_or_mask is not a netmask or prefix."""
> - params = {
> - 'interface': 'eth0', 'ip': '192.168.2.2',
> - 'broadcast': '192.168.2.255'}
> - invalid_masks = ('invalid', 'invalid.', '123.123.123')
> - for error_val in invalid_masks:
> - params['prefix_or_mask'] = error_val
> - with self.assertRaises(ValueError) as context_manager:
> - with net.EphemeralIPv4Network(**params):
> - pass
> - error = context_manager.exception
> - self.assertIn('Cannot setup network: netmask', str(error))
> - self.assertEqual(0, m_subp.call_count)
> -
> - def test_ephemeral_ipv4_network_performs_teardown(self, m_subp):
> - """EphemeralIPv4Network performs teardown on the device if setup."""
> - expected_setup_calls = [
> - mock.call(
> - ['ip', '-family', 'inet', 'addr', 'add', '192.168.2.2/24',
> - 'broadcast', '192.168.2.255', 'dev', 'eth0'],
> - capture=True, update_env={'LANG': 'C'}),
> - mock.call(
> - ['ip', '-family', 'inet', 'link', 'set', 'dev', 'eth0', 'up'],
> - capture=True)]
> - expected_teardown_calls = [
> - mock.call(
> - ['ip', '-family', 'inet', 'link', 'set', 'dev', 'eth0',
> - 'down'], capture=True),
> - mock.call(
> - ['ip', '-family', 'inet', 'addr', 'del', '192.168.2.2/24',
> - 'dev', 'eth0'], capture=True)]
> - params = {
> - 'interface': 'eth0', 'ip': '192.168.2.2',
> - 'prefix_or_mask': '255.255.255.0', 'broadcast': '192.168.2.255'}
> - with net.EphemeralIPv4Network(**params):
> - self.assertEqual(expected_setup_calls, m_subp.call_args_list)
> - m_subp.assert_has_calls(expected_teardown_calls)
> -
> - @mock.patch('cloudinit.net.readurl')
> - def test_ephemeral_ipv4_no_network_if_url_connectivity(
> - self, m_readurl, m_subp):
> - """No network setup is performed if we can successfully connect to
> - connectivity_url."""
> - params = {
> - 'interface': 'eth0', 'ip': '192.168.2.2',
> - 'prefix_or_mask': '255.255.255.0', 'broadcast': '192.168.2.255',
> - 'connectivity_url': 'http://example.org/index.html'}
> -
> - with net.EphemeralIPv4Network(**params):
> - self.assertEqual([mock.call('http://example.org/index.html',
> - timeout=5)], m_readurl.call_args_list)
> - # Ensure that no teardown happens:
> - m_subp.assert_has_calls([])
> -
> - def test_ephemeral_ipv4_network_noop_when_configured(self, m_subp):
> - """EphemeralIPv4Network handles exception when address is setup.
> -
> - It performs no cleanup as the interface was already setup.
> - """
> - params = {
> - 'interface': 'eth0', 'ip': '192.168.2.2',
> - 'prefix_or_mask': '255.255.255.0', 'broadcast': '192.168.2.255'}
> - m_subp.side_effect = ProcessExecutionError(
> - '', 'RTNETLINK answers: File exists', 2)
> - expected_calls = [
> - mock.call(
> - ['ip', '-family', 'inet', 'addr', 'add', '192.168.2.2/24',
> - 'broadcast', '192.168.2.255', 'dev', 'eth0'],
> - capture=True, update_env={'LANG': 'C'})]
> - with net.EphemeralIPv4Network(**params):
> - pass
> - self.assertEqual(expected_calls, m_subp.call_args_list)
> - self.assertIn(
> - 'Skip ephemeral network setup, eth0 already has address',
> - self.logs.getvalue())
> -
> - def test_ephemeral_ipv4_network_with_prefix(self, m_subp):
> - """EphemeralIPv4Network takes a valid prefix to setup the network."""
> - params = {
> - 'interface': 'eth0', 'ip': '192.168.2.2',
> - 'prefix_or_mask': '24', 'broadcast': '192.168.2.255'}
> - for prefix_val in ['24', 16]: # prefix can be int or string
> - params['prefix_or_mask'] = prefix_val
> - with net.EphemeralIPv4Network(**params):
> - pass
> - m_subp.assert_has_calls([mock.call(
> - ['ip', '-family', 'inet', 'addr', 'add', '192.168.2.2/24',
> - 'broadcast', '192.168.2.255', 'dev', 'eth0'],
> - capture=True, update_env={'LANG': 'C'})])
> - m_subp.assert_has_calls([mock.call(
> - ['ip', '-family', 'inet', 'addr', 'add', '192.168.2.2/16',
> - 'broadcast', '192.168.2.255', 'dev', 'eth0'],
> - capture=True, update_env={'LANG': 'C'})])
> -
> - def test_ephemeral_ipv4_network_with_new_default_route(self, m_subp):
> - """Add the route when router is set and no default route exists."""
> - params = {
> - 'interface': 'eth0', 'ip': '192.168.2.2',
> - 'prefix_or_mask': '255.255.255.0', 'broadcast': '192.168.2.255',
> - 'router': '192.168.2.1'}
> - m_subp.return_value = '', '' # Empty response from ip route gw check
> - expected_setup_calls = [
> - mock.call(
> - ['ip', '-family', 'inet', 'addr', 'add', '192.168.2.2/24',
> - 'broadcast', '192.168.2.255', 'dev', 'eth0'],
> - capture=True, update_env={'LANG': 'C'}),
> - mock.call(
> - ['ip', '-family', 'inet', 'link', 'set', 'dev', 'eth0', 'up'],
> - capture=True),
> - mock.call(
> - ['ip', 'route', 'show', '0.0.0.0/0'], capture=True),
> - mock.call(['ip', '-4', 'route', 'add', '192.168.2.1',
> - 'dev', 'eth0', 'src', '192.168.2.2'], capture=True),
> - mock.call(
> - ['ip', '-4', 'route', 'add', 'default', 'via',
> - '192.168.2.1', 'dev', 'eth0'], capture=True)]
> - expected_teardown_calls = [
> - mock.call(['ip', '-4', 'route', 'del', 'default', 'dev', 'eth0'],
> - capture=True),
> - mock.call(['ip', '-4', 'route', 'del', '192.168.2.1',
> - 'dev', 'eth0', 'src', '192.168.2.2'], capture=True),
> - ]
> -
> - 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
--
https://code.launchpad.net/~i.galic/cloud-init/+git/cloud-init/+merge/358228
Your team cloud-init commiters is requested to review the proposed merge of ~i.galic/cloud-init:refactor/net-fbsd into cloud-init:master.
References