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_default_generation(self, mock_get_devicelist, mock_sys_netdev_info, mock_sys_dev_path): tmp_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, tmp_dir) _setup_test(tmp_dir, mock_get_devicelist, mock_sys_netdev_info, mock_sys_dev_path) network_cfg = net.generate_fallback_config() ns = network_state.parse_net_config_data(network_cfg, skip_broken=False) render_dir = os.path.join(tmp_dir, "render") os.makedirs(render_dir) renderer = sysconfig.Renderer() renderer.render_network_state(render_dir, ns) render_file = 'etc/sysconfig/network-scripts/ifcfg-eth1000' with open(os.path.join(render_dir, render_file)) as fh: content = fh.read() expected_content = """ # Created by cloud-init on instance boot automatically, do not edit. # BOOTPROTO=dhcp DEVICE=eth1000 HWADDR=07-1C-C6-75-A4-BE NM_CONTROLLED=no ONBOOT=yes TYPE=Ethernet USERCTL=no """.lstrip() self.assertEqual(expected_content, content)
def test_default_generation(self, mock_get_devicelist, mock_sys_netdev_info, mock_sys_dev_path): tmp_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, tmp_dir) _setup_test(tmp_dir, mock_get_devicelist, mock_sys_netdev_info, mock_sys_dev_path) network_cfg = net.generate_fallback_config() ns = network_state.parse_net_config_data(network_cfg, skip_broken=False) render_dir = os.path.join(tmp_dir, "render") os.makedirs(render_dir) renderer = eni.Renderer( {'links_path_prefix': None, 'eni_path': 'interfaces', 'netrules_path': None, }) renderer.render_network_state(render_dir, ns) self.assertTrue(os.path.exists(os.path.join(render_dir, 'interfaces'))) with open(os.path.join(render_dir, 'interfaces')) as fh: contents = fh.read() expected = """ auto lo iface lo inet loopback auto eth1000 iface eth1000 inet dhcp """ self.assertEqual(expected.lstrip(), contents.lstrip())
def test_default_generation(self, mock_get_devicelist, mock_read_sys_net, mock_sys_dev_path): tmp_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, tmp_dir) _setup_test(tmp_dir, mock_get_devicelist, mock_read_sys_net, mock_sys_dev_path) network_cfg = net.generate_fallback_config() ns = network_state.parse_net_config_data(network_cfg, skip_broken=False) render_dir = os.path.join(tmp_dir, "render") os.makedirs(render_dir) renderer = sysconfig.Renderer() renderer.render_network_state(render_dir, ns) render_file = 'etc/sysconfig/network-scripts/ifcfg-eth1000' with open(os.path.join(render_dir, render_file)) as fh: content = fh.read() expected_content = """ # Created by cloud-init on instance boot automatically, do not edit. # BOOTPROTO=dhcp DEVICE=eth1000 HWADDR=07-1C-C6-75-A4-BE NM_CONTROLLED=no ONBOOT=yes TYPE=Ethernet USERCTL=no """.lstrip() self.assertEqual(expected_content, content)
def test_default_generation(self, mock_get_devicelist, mock_read_sys_net, mock_sys_dev_path): tmp_dir = tempfile.mkdtemp() self.addCleanup(shutil.rmtree, tmp_dir) _setup_test(tmp_dir, mock_get_devicelist, mock_read_sys_net, mock_sys_dev_path) network_cfg = net.generate_fallback_config() ns = network_state.parse_net_config_data(network_cfg, skip_broken=False) render_dir = os.path.join(tmp_dir, "render") os.makedirs(render_dir) renderer = eni.Renderer( {'links_path_prefix': None, 'eni_path': 'interfaces', 'netrules_path': None, }) renderer.render_network_state(render_dir, ns) self.assertTrue(os.path.exists(os.path.join(render_dir, 'interfaces'))) with open(os.path.join(render_dir, 'interfaces')) as fh: contents = fh.read() expected = """ auto lo iface lo inet loopback auto eth1000 iface eth1000 inet dhcp """ self.assertEqual(expected.lstrip(), contents.lstrip())
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())
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 generate_fallback_config(self): key = "disable_fallback_netcfg" disable_fallback_netcfg = self._cfg.get(key, True) LOG.debug("%s value is: %s", key, disable_fallback_netcfg) if not disable_fallback_netcfg: return net.generate_fallback_config() LOG.info("Skipping generate_fallback_config. Rely on PhotonOS default " "network config") return None
def generate_fallback_config(self): key = 'disable_fallback_netcfg' disable_fallback_netcfg = self._cfg.get(key, True) LOG.debug('%s value is: %s', key, disable_fallback_netcfg) if not disable_fallback_netcfg: return net.generate_fallback_config() LOG.info('Skipping generate_fallback_config. Rely on PhotonOS default ' 'network config') return None
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 = { 'ethernets': { 'eth0': { 'dhcp4': True, 'match': { 'macaddress': mac }, 'set-name': 'eth0' } }, 'version': 2 } 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 parse_network_config(imds_metadata): """Convert imds_metadata dictionary to network v2 configuration. Parses network configuration from imds metadata if present or generate fallback network config excluding mlx4_core devices. @param: imds_metadata: Dict of content read from IMDS network service. @return: Dictionary containing network version 2 standard configuration. """ if imds_metadata != sources.UNSET and imds_metadata: netconfig = {'version': 2, 'ethernets': {}} LOG.debug('Azure: generating network configuration from IMDS') network_metadata = imds_metadata['network'] for idx, intf in enumerate(network_metadata['interface']): nicname = 'eth{idx}'.format(idx=idx) dev_config = {} for addr4 in intf['ipv4']['ipAddress']: privateIpv4 = addr4['privateIpAddress'] if privateIpv4: if dev_config.get('dhcp4', False): # Append static address config for nic > 1 netPrefix = intf['ipv4']['subnet'][0].get( 'prefix', '24') if not dev_config.get('addresses'): dev_config['addresses'] = [] dev_config['addresses'].append('{ip}/{prefix}'.format( ip=privateIpv4, prefix=netPrefix)) else: dev_config['dhcp4'] = True for addr6 in intf['ipv6']['ipAddress']: privateIpv6 = addr6['privateIpAddress'] if privateIpv6: dev_config['dhcp6'] = True break if dev_config: mac = ':'.join(re.findall(r'..', intf['macAddress'])) dev_config.update({ 'match': { 'macaddress': mac.lower() }, 'set-name': nicname }) netconfig['ethernets'][nicname] = dev_config else: blacklist = ['mlx4_core'] LOG.debug('Azure: generating fallback configuration') # generate a network config, blacklist picking mlx4_core devs netconfig = net.generate_fallback_config(blacklist_drivers=blacklist, config_driver=True) return netconfig
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 = { 'ethernets': { 'eth0': { 'match': { 'macaddress': mac }, 'dhcp4': True, 'set-name': 'eth0' } }, 'version': 2 } self.assertEqual(expected, net.generate_fallback_config())
def _find_networking_config(self): disable_file = os.path.join( self.paths.get_cpath('data'), 'upgraded-network') if os.path.exists(disable_file): return (None, disable_file) cmdline_cfg = ('cmdline', net.read_kernel_cmdline_config()) dscfg = ('ds', None) if self.datasource and hasattr(self.datasource, 'network_config'): dscfg = ('ds', self.datasource.network_config) sys_cfg = ('system_cfg', self.cfg.get('network')) for loc, ncfg in (cmdline_cfg, dscfg, sys_cfg): if net.is_disabled_cfg(ncfg): LOG.debug("network config disabled by %s", loc) return (None, loc) if ncfg: return (ncfg, loc) return (net.generate_fallback_config(), "fallback")
def network_config(self): """Generate a network config like net.generate_fallback_network() with the following execptions. 1. Probe the drivers of the net-devices present and inject them in the network configuration under params: driver: <driver> value 2. Generate a fallback network config that does not include any of the blacklisted devices. """ blacklist = ['mlx4_core'] if not self._network_config: LOG.debug('Azure: generating fallback configuration') # generate a network config, blacklist picking any mlx4_core devs netconfig = net.generate_fallback_config( blacklist_drivers=blacklist, config_driver=True) self._network_config = netconfig return self._network_config
def _find_networking_config(self): disable_file = os.path.join(self.paths.get_cpath('data'), 'upgraded-network') if os.path.exists(disable_file): return (None, disable_file) cmdline_cfg = ('cmdline', cmdline.read_kernel_cmdline_config()) dscfg = ('ds', None) if self.datasource and hasattr(self.datasource, 'network_config'): dscfg = ('ds', self.datasource.network_config) sys_cfg = ('system_cfg', self.cfg.get('network')) for loc, ncfg in (cmdline_cfg, sys_cfg, dscfg): if net.is_disabled_cfg(ncfg): LOG.debug("network config disabled by %s", loc) return (None, loc) if ncfg: return (ncfg, loc) return (net.generate_fallback_config(), "fallback")
def network_config(self): """Generate a network config like net.generate_fallback_network() with the following execptions. 1. Probe the drivers of the net-devices present and inject them in the network configuration under params: driver: <driver> value 2. If the driver value is 'mlx4_core', the control mode should be set to manual. The device will be later used to build a bond, for now we want to ensure the device gets named but does not break any network configuration """ blacklist = ['mlx4_core'] if not self._network_config: LOG.debug('Azure: generating fallback configuration') # generate a network config, blacklist picking any mlx4_core devs netconfig = net.generate_fallback_config( blacklist_drivers=blacklist, config_driver=True) # if we have any blacklisted devices, update the network_config to # include the device, mac, and driver values, but with no ip # config; this ensures udev rules are generated but won't affect # ip configuration bl_found = 0 for bl_dev in [ dev for dev in net.get_devicelist() if net.device_driver(dev) in blacklist ]: bl_found += 1 cfg = { 'type': 'physical', 'name': 'vf%d' % bl_found, 'mac_address': net.get_interface_mac(bl_dev), 'params': { 'driver': net.device_driver(bl_dev), 'device_id': net.device_devid(bl_dev), }, } netconfig['config'].append(cfg) self._network_config = netconfig return self._network_config
def test_default_generation(self, mock_get_devicelist, mock_read_sys_net, mock_sys_dev_path): tmp_dir = self.tmp_dir() _setup_test(tmp_dir, mock_get_devicelist, mock_read_sys_net, mock_sys_dev_path) network_cfg = net.generate_fallback_config() ns = network_state.parse_net_config_data(network_cfg, skip_broken=False) render_dir = os.path.join(tmp_dir, "render") os.makedirs(render_dir) render_target = 'netplan.yaml' renderer = netplan.Renderer({ 'netplan_path': render_target, 'postcmds': False }) renderer.render_network_state(render_dir, ns) self.assertTrue(os.path.exists(os.path.join(render_dir, render_target))) with open(os.path.join(render_dir, render_target)) as fh: contents = fh.read() print(contents) expected = """ network: version: 2 ethernets: eth1000: dhcp4: true match: macaddress: 07-1c-c6-75-a4-be set-name: eth1000 """ self.assertEqual(expected.lstrip(), contents.lstrip())
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 generate_fallback_config(self): return net.generate_fallback_config()
def generate_fallback_config(self, *, blacklist_drivers=None, config_driver: bool = False): return net.generate_fallback_config( blacklist_drivers=blacklist_drivers, config_driver=config_driver)