def _add_nic(iface, nics): if not iface or iface == IFACE_TEMPLATE: return # no information gathered LOG.debug("Found new interface: %s", iface) # Each missing detail is marked as None. nic = service_base.NetworkDetails(**iface) nics.append(nic)
def _preprocess_nics(network_details, network_adapters): """Check NICs and fill missing data if possible.""" # Initial checks. if not network_adapters: raise exception.CloudbaseInitException("no network adapters available") # Sort VM adapters by name (assuming that those # from the context are in correct order). # Do this for a better matching by order # if hardware address is missing. network_adapters = sorted(network_adapters, key=lambda arg: arg[0]) refined_network_details = [] # store here processed interfaces # Check and update every NetworkDetails object. total = len(network_adapters) for nic in network_details: if not isinstance(nic, service_base.NetworkDetails): raise exception.CloudbaseInitException( "invalid NetworkDetails object {!r}".format(type(nic))) # Check requirements. final_status = True for fields, status in NET_REQUIRE.items(): if not status: continue # skip 'not required' entries if not isinstance(fields, tuple): fields = (fields, ) final_status = any([getattr(nic, field) for field in fields]) if not final_status: break address, netmask = nic.address, nic.netmask if final_status: # Additional check for info version. if not (address and netmask): final_status = nic.address6 and nic.netmask6 if final_status: address = address or network.address6_to_4_truncate( nic.address6) netmask = netmask or network.netmask6_to_4_truncate( nic.netmask6) if not final_status: LOG.error("Incomplete NetworkDetails object %s", nic) continue # Complete hardware address if missing by selecting # the corresponding MAC in terms of naming, then ordering. if not nic.mac: # By name... macs = [ adapter[1] for adapter in network_adapters if adapter[0] == nic.name ] mac = macs[0] if macs else None # ...or by order. idx = _name2idx(nic.name) if not mac and idx < total: mac = network_adapters[idx][1] nic = service_base.NetworkDetails(nic.name, mac, address, nic.address6, netmask, nic.netmask6, nic.broadcast, nic.gateway, nic.gateway6, nic.dnsnameservers) refined_network_details.append(nic) return refined_network_details
def get_network_details(self): """Return a list of NetworkDetails objects. With each object from that list, the corresponding NIC (by mac) can be statically configured. If no such object is present, then is believed that this is handled by DHCP (user didn't provide sufficient data). """ network_details = [] ncount = self._nic_count() # for every interface for iid in range(ncount): try: # get existing values mac = self._get_cache_data(MAC, iid=iid).upper() address = self._get_cache_data(ADDRESS, iid=iid) gateway = self._get_cache_data(GATEWAY, iid=iid) # try to find/predict and compute the rest try: netmask = self._get_cache_data(NETMASK, iid=iid) except base.NotExistingMetadataException: netmask = self._calculate_netmask(address, gateway) broadcast = self._compute_broadcast(address, netmask) # gather them as namedtuple objects details = base.NetworkDetails( mac, address, netmask, broadcast, gateway, self._get_cache_data(DNSNS, iid=iid).split(" ")) except base.NotExistingMetadataException: LOG.debug("Incomplete NIC details") else: network_details.append(details) return network_details
def _convert_network_data(self): """Parses network_data and converts to NetworkDetails namedtuple.""" network_data = self._get_network_data() # Create a template because namedtuples are immutable nic_template = dict.fromkeys(base.NetworkDetails._fields) nics = [] dns_nameservers = self._get_dns_nameservers(network_data) for link in network_data.get('links', []): nic = AttributeDict(nic_template) # Must make mac uppercase to match windows adapter mac. nic.mac = link["ethernet_mac_address"].upper() nic.name = link["name"] nic.dnsnameservers = dns_nameservers for network in network_data.get('networks', []): # Each link can have multiple networks for ipv4 and ipv6. # Skip if they don't match. if network["link"] != link["id"]: continue if network["type"] == "ipv4": self._set_ipv4_network_details(network, nic) elif network["type"] == "ipv6": self._set_ipv6_network_details(network, nic) LOG.debug('Appending NetworkDetails object: %s', nic.mac) nics.append(base.NetworkDetails(**nic)) return nics
def _test_execute_missing_smth(self, name=False, mac=False, address=False, address6=False, netmask=False, netmask6=False, gateway=False, fail=False): ind = self._count - 1 nic = self._network_details[ind] nic2 = service_base.NetworkDetails( None if name else nic.name, None if mac else nic.mac, None if address else nic.address, None if address6 else nic.address6, None if netmask else nic.netmask, None if netmask6 else nic.netmask6, nic.broadcast, None if gateway else nic.gateway, None if gateway else nic.gateway6, nic.dnsnameservers) self._network_details[ind] = nic2 # Excluding address and gateway switches... if not fail: # Even this way, all adapters should be configured. missed_adapters = [] extra_network_details = [nic] else: # Both name and MAC are missing, so we can't make the match. # Or other vital details. missed_adapters = [self._network_adapters[ind]] extra_network_details = [] self._partial_test_execute(missed_adapters=missed_adapters, extra_network_details=extra_network_details)
def test_execute_missing_all(self): nic = self._network_details[0] nic = service_base.NetworkDetails(nic.name, "00" + nic.mac[2:], nic.address, nic.netmask, nic.broadcast, nic.gateway, nic.dnsnameservers) self._network_details[:] = [nic] self._partial_test_execute(missed_adapters=self._network_adapters)
def _add_nic(iface, nics): if not iface: return details = [iface[key] for key in sorted(iface)] LOG.debug("Found new interface: %s", details) # each missing detail is marked as None nic = service_base.NetworkDetails(*details) nics.append(nic)
def _setUp(self, same_names=True, wrong_names=False, no_macs=False): # Generate fake pairs of NetworkDetails objects and # local ethernet network adapters. iface_name = "Ethernet" if wrong_names else "eth" self._count = 3 details_names = [ "{}{}".format(iface_name, idx) for idx in range(self._count) ] if same_names: adapters_names = details_names[:] else: adapters_names = ["vm " + name for name in details_names] macs = ["54:EE:75:19:F4:61", "54:EE:75:19:F4:62", "54:EE:75:19:F4:63"] addresses = [ "192.168.122.101", "192.168.103.104", "192.168.122.105", ] netmasks = [ "255.255.255.0", "255.255.0.0", "255.255.255.128", ] broadcasts = [ "192.168.122.255", "192.168.255.255", "192.168.122.127", ] gateways = [ "192.168.122.1", "192.168.122.16", "192.168.122.32", ] dnsnses = [ "8.8.8.8", "8.8.8.8 8.8.4.4", "8.8.8.8 0.0.0.0", ] self._network_adapters = [] self._network_details = [] for ind in range(self._count): adapter = (adapters_names[ind], macs[ind]) nic = service_base.NetworkDetails(details_names[ind], None if no_macs else macs[ind], addresses[ind], netmasks[ind], broadcasts[ind], gateways[ind], dnsnses[ind].split()) self._network_adapters.append(adapter) self._network_details.append(nic) # get the network config plugin self._network_plugin = networkconfig.NetworkConfigPlugin() # execution wrapper self._partial_test_execute = functools.partial( self._test_execute, network_adapters=self._network_adapters, network_details=self._network_details)
def _test_parse_nics(self, no_nics=False): nics = debiface.parse(self.data) if no_nics: self.assertFalse(nics) return # check what we've got nic0 = service_base.NetworkDetails(fake_json_response.NAME0, fake_json_response.MAC0.upper(), fake_json_response.ADDRESS0, fake_json_response.NETMASK0, fake_json_response.BROADCAST0, fake_json_response.GATEWAY0, fake_json_response.DNSNS0.split()) nic1 = service_base.NetworkDetails(fake_json_response.NAME1, None, fake_json_response.ADDRESS1, fake_json_response.NETMASK1, fake_json_response.BROADCAST1, fake_json_response.GATEWAY1, None) self.assertEqual([nic0, nic1], nics)
def _test_get_network_details(self, mock_get_meta_data, mock_get_content, network_config=None, content=None, search_fail=False, no_path=False): # mock obtained data mock_get_meta_data().get.return_value = network_config mock_get_content.return_value = content # actual tests if search_fail: ret = self._service.get_network_details() self.assertFalse(ret) return ret = self._service.get_network_details() mock_get_meta_data().get.assert_called_once_with("network_config") if network_config and not no_path: mock_get_content.assert_called_once_with("network") if not network_config: self.assertIsNone(ret) return if no_path: self.assertIsNone(ret) return # check returned NICs details nic1 = base.NetworkDetails(fake_json_response.NAME0, fake_json_response.MAC0.upper(), fake_json_response.ADDRESS0, fake_json_response.NETMASK0, fake_json_response.BROADCAST0, fake_json_response.GATEWAY0, fake_json_response.DNSNS0.split()) nic2 = base.NetworkDetails(fake_json_response.NAME1, None, fake_json_response.ADDRESS1, fake_json_response.NETMASK1, fake_json_response.BROADCAST1, fake_json_response.GATEWAY1, None) self.assertEqual([nic1, nic2], ret)
def _test_parse_nics(self, no_nics=False): with testutils.LogSnatcher('cloudbaseinit.utils.' 'debiface') as snatcher: nics = debiface.parse(self.data) if no_nics: expected_logging = 'Invalid Debian config to parse:' self.assertTrue(snatcher.output[0].startswith(expected_logging)) self.assertFalse(nics) return # check what we've got nic0 = service_base.NetworkDetails( fake_json_response.NAME0, fake_json_response.MAC0.upper(), fake_json_response.ADDRESS0, fake_json_response.ADDRESS60, fake_json_response.NETMASK0, fake_json_response.NETMASK60, fake_json_response.BROADCAST0, fake_json_response.GATEWAY0, fake_json_response.GATEWAY60, fake_json_response.DNSNS0.split()) nic1 = service_base.NetworkDetails( fake_json_response.NAME1, None, fake_json_response.ADDRESS1, fake_json_response.ADDRESS61, fake_json_response.NETMASK1, fake_json_response.NETMASK61, fake_json_response.BROADCAST1, fake_json_response.GATEWAY1, fake_json_response.GATEWAY61, None) self.assertEqual([nic0, nic1], nics)
def _preprocess_nics(network_details, network_adapters): """Check NICs and fill missing data if possible.""" # initial checks if not network_adapters: raise exception.CloudbaseInitException("no network adapters available") # Sort VM adapters by name (assuming that those # from the context are in correct order). network_adapters = sorted(network_adapters, key=lambda arg: arg[0]) _network_details = [] # store here processed data # check and update every NetworkDetails object ind = 0 total = len(network_adapters) for nic in network_details: if not isinstance(nic, service_base.NetworkDetails): raise exception.CloudbaseInitException( "invalid NetworkDetails object {!r}".format(type(nic))) # check requirements final_status = True for fields, status in NET_REQUIRE.items(): if not status: continue # skip 'not required' entries if not isinstance(fields, tuple): fields = (fields, ) final_status = any([getattr(nic, field) for field in fields]) if not final_status: LOG.error("Incomplete NetworkDetails object %s", nic) break if final_status: # Complete hardware address if missing by selecting # the corresponding MAC in terms of naming, then ordering. if not nic.mac: mac = None # by name macs = [ adapter[1] for adapter in network_adapters if adapter[0] == nic.name ] mac = macs[0] if macs else None # or by order if not mac and ind < total: mac = network_adapters[ind][1] nic = service_base.NetworkDetails(nic.name, mac, nic.address, nic.netmask, nic.broadcast, nic.gateway, nic.dnsnameservers) _network_details.append(nic) ind += 1 return _network_details
def _get_nic_details(): details = base.NetworkDetails(MAC, ADDRESS, NETMASK, BROADCAST, GATEWAY, DNSNS.split(" ")) return details
def _get_nic_details(iid=0): details = base.NetworkDetails(opennebulaservice.IF_FORMAT.format(iid=iid), MAC, ADDRESS, NETMASK, BROADCAST, GATEWAY, DNSNS.split(" ")) return details
def _test_execute(self, mock_get_os_utils, search_result=mock.MagicMock(), no_adapter_name=False, no_adapters=False, using_content=0, details_list=None, missing_content_path=False): fake_adapter = ("fake_name_0", "fake_mac_0") mock_service = mock.MagicMock() mock_osutils = mock.MagicMock() mock_ndetails = mock.Mock() re.search = mock.MagicMock(return_value=search_result) fake_shared_data = 'fake shared data' network_config = self.fake_data['network_config'] if not details_list: details_list = [None] * 6 details_list[0] = fake_adapter[1] # set MAC for matching if no_adapter_name: # nothing provided in the config file CONF.set_override("network_adapter", None) else: CONF.set_override("network_adapter", fake_adapter[0]) mock_osutils.get_network_adapters.return_value = [ fake_adapter, # and other adapters ("name1", "mac1"), ("name2", "mac2") ] mock_get_os_utils.return_value = mock_osutils mock_osutils.set_static_network_config.return_value = False # service method setup methods = ["get_network_config", "get_content", "get_network_details"] for method in methods: mock_method = getattr(mock_service, method) mock_method.return_value = None if using_content == 1: mock_service.get_network_config.return_value = network_config mock_service.get_content.return_value = search_result elif using_content == 2: mock_service.get_network_details.return_value = [mock_ndetails] # actual tests if search_result is None and using_content == 1: self.assertRaises(exception.CloudbaseInitException, self._network_plugin.execute, mock_service, fake_shared_data) return if no_adapters: mock_osutils.get_network_adapters.return_value = [] self.assertRaises(exception.CloudbaseInitException, self._network_plugin.execute, mock_service, fake_shared_data) return attrs = [ "address", "netmask", "broadcast", "gateway", "dnsnameservers", ] if using_content == 0: response = self._network_plugin.execute(mock_service, fake_shared_data) elif using_content == 1: if missing_content_path: mock_service.get_network_config.return_value.pop( "content_path", None) response = self._network_plugin.execute(mock_service, fake_shared_data) if not missing_content_path: mock_service.get_network_config.assert_called_once_with() mock_service.get_content.assert_called_once_with( network_config['content_path']) adapters = mock_osutils.get_network_adapters() if CONF.network_adapter: mac = [ pair[1] for pair in adapters if pair == fake_adapter ][0] else: mac = adapters[0][1] (address, netmask, broadcast, gateway, dnsnameserver) = map(search_result.group, attrs) dnsnameservers = dnsnameserver.strip().split(" ") elif using_content == 2: with self.assertRaises(exception.CloudbaseInitException): self._network_plugin.execute(mock_service, fake_shared_data) mock_service.get_network_details.reset_mock() mock_ndetails = service_base.NetworkDetails(*details_list) mock_service.get_network_details.return_value = [mock_ndetails] response = self._network_plugin.execute(mock_service, fake_shared_data) mock_service.get_network_details.assert_called_once_with() mac = mock_ndetails.mac (address, netmask, broadcast, gateway, dnsnameservers) = map(lambda attr: getattr(mock_ndetails, attr), attrs) if using_content in (1, 2) and not missing_content_path: mock_osutils.set_static_network_config.assert_called_once_with( mac, address, netmask, broadcast, gateway, dnsnameservers) self.assertEqual((plugin_base.PLUGIN_EXECUTION_DONE, False), response)
def execute(self, service, shared_data): # FIXME(cpoieana): `network_config` is deprecated # * refactor all services by providing NetworkDetails objects * # Also, the old method is not supporting multiple NICs. osutils = osutils_factory.get_os_utils() network_details = service.get_network_details() if not network_details: network_config = service.get_network_config() if not network_config: return (plugin_base.PLUGIN_EXECUTION_DONE, False) # ---- BEGIN deprecated code ---- if not network_details: if 'content_path' not in network_config: return (plugin_base.PLUGIN_EXECUTION_DONE, False) content_path = network_config['content_path'] content_name = content_path.rsplit('/', 1)[-1] debian_network_conf = service.get_content(content_name) LOG.debug('network config content:\n%s' % debian_network_conf) # TODO(alexpilotti): implement a proper grammar m = re.search( r'iface eth0 inet static\s+' r'address\s+(?P<address>[^\s]+)\s+' r'netmask\s+(?P<netmask>[^\s]+)\s+' r'broadcast\s+(?P<broadcast>[^\s]+)\s+' r'gateway\s+(?P<gateway>[^\s]+)\s+' r'dns\-nameservers\s+' r'(?P<dnsnameservers>[^\r\n]+)\s+', debian_network_conf) if not m: raise exception.CloudbaseInitException( "network_config format not recognized") mac = None network_adapters = osutils.get_network_adapters() if network_adapters: adapter_name = CONF.network_adapter if adapter_name: # configure with the specified one for network_adapter in network_adapters: if network_adapter[0] == adapter_name: mac = network_adapter[1] break else: # configure with the first one mac = network_adapters[0][1] network_details = [ service_base.NetworkDetails( mac, m.group('address'), m.group('netmask'), m.group('broadcast'), m.group('gateway'), m.group('dnsnameservers').strip().split(' ')) ] # ---- END deprecated code ---- # check NICs' type and save them by MAC macnics = {} for nic in network_details: if not isinstance(nic, service_base.NetworkDetails): raise exception.CloudbaseInitException( "invalid NetworkDetails object {!r}".format(type(nic))) # assuming that the MAC address is unique macnics[nic.mac] = nic # try configuring all the available adapters adapter_macs = [pair[1] for pair in osutils.get_network_adapters()] if not adapter_macs: raise exception.CloudbaseInitException( "no network adapters available") # configure each one reboot_required = False configured = False for mac in adapter_macs: nic = macnics.pop(mac, None) if not nic: LOG.warn("Missing details for adapter %s", mac) continue LOG.info("Configuring network adapter %s", mac) reboot = osutils.set_static_network_config(mac, nic.address, nic.netmask, nic.broadcast, nic.gateway, nic.dnsnameservers) reboot_required = reboot or reboot_required configured = True for mac in macnics: LOG.warn("Details not used for adapter %s", mac) if not configured: LOG.error("No adapters were configured") return (plugin_base.PLUGIN_EXECUTION_DONE, reboot_required)