def before_update(self, introspection_data, node_info, **kwargs): """Detect root disk from root device hints and IPA inventory.""" hints = node_info.node().properties.get('root_device') if not hints: LOG.debug('Root device hints are not provided', node_info=node_info, data=introspection_data) return inventory = utils.get_inventory(introspection_data, node_info=node_info) try: device = il_utils.match_root_device_hints(inventory['disks'], hints) except (TypeError, ValueError) as e: raise utils.Error( _('No disks could be found using the root device hints ' '%(hints)s because they failed to validate. ' 'Error: %(error)s') % {'hints': hints, 'error': e}, node_info=node_info, data=introspection_data) if not device: raise utils.Error(_('No disks satisfied root device hints'), node_info=node_info, data=introspection_data) LOG.debug('Disk %(disk)s of size %(size)s satisfies ' 'root device hints', {'disk': device.get('name'), 'size': device['size']}, node_info=node_info, data=introspection_data) introspection_data['root_disk'] = device
def before_update(self, introspection_data, node_info, **kwargs): """Process LLDP data and patch Ironic port local link connection""" inventory = utils.get_inventory(introspection_data) ironic_ports = node_info.ports() for iface in inventory['interfaces']: if iface['name'] not in introspection_data['all_interfaces']: continue mac_address = iface['mac_address'] port = ironic_ports.get(mac_address) if not port: LOG.debug("Skipping LLC processing for interface %s, matching " "port not found in Ironic.", mac_address, node_info=node_info, data=introspection_data) continue lldp_data = iface.get('lldp') if lldp_data is None: LOG.warning("No LLDP Data found for interface %s", mac_address, node_info=node_info, data=introspection_data) continue patches = [] # First check if lldp data was already processed by lldp_basic # plugin which stores data in 'all_interfaces' proc_data = introspection_data['all_interfaces'][iface['name']] for name, item in LLDP_PROC_DATA_MAPPING.items(): patch = self._get_lldp_processed_patch(name, item, proc_data, port, node_info) if patch is not None: patches.append(patch) # If no processed lldp data was available then parse raw lldp data if not patches: for tlv_type, tlv_value in lldp_data: patch = self._get_local_link_patch(tlv_type, tlv_value, port, node_info) if patch is not None: patches.append(patch) try: node_info.patch_port(port, patches) except exceptions.BadRequest as e: LOG.warning("Failed to update port %(uuid)s: %(error)s", {'uuid': port.uuid, 'error': e}, node_info=node_info)
def before_update(self, introspection_data, node_info, **kwargs): """Process LLDP data and patch Ironic port local link connection""" inventory = utils.get_inventory(introspection_data) ironic_ports = node_info.ports() for iface in inventory['interfaces']: if iface['name'] not in introspection_data['all_interfaces']: continue mac_address = iface['mac_address'] port = ironic_ports.get(mac_address) if not port: LOG.debug( "Skipping LLC processing for interface %s, matching " "port not found in Ironic.", mac_address, node_info=node_info, data=introspection_data) continue lldp_data = iface.get('lldp') if lldp_data is None: LOG.warning("No LLDP Data found for interface %s", mac_address, node_info=node_info, data=introspection_data) continue patches = [] # First check if lldp data was already processed by lldp_basic # plugin which stores data in 'all_interfaces' proc_data = introspection_data['all_interfaces'][iface['name']] for name, item in LLDP_PROC_DATA_MAPPING.items(): patch = self._get_lldp_processed_patch(name, item, proc_data, port) if patch is not None: patches.append(patch) # If no processed lldp data was available then parse raw lldp data if not patches: for tlv_type, tlv_value in lldp_data: patch = self._get_local_link_patch(tlv_type, tlv_value, port, node_info) if patch is not None: patches.append(patch) node_info.patch_port(port, patches)
def _get_interfaces(self, data=None): """Convert inventory to a dict with interfaces. :return: dict interface name -> dict with keys 'mac' and 'ip' """ result = {} inventory = utils.get_inventory(data) for iface in inventory['interfaces']: name = iface.get('name') mac = iface.get('mac_address') ip = iface.get('ipv4_address') client_id = iface.get('client_id') if not name: LOG.error('Malformed interface record: %s', iface, data=data) continue if not mac: LOG.debug('Skipping interface %s without link information', name, data=data) continue if not netutils.is_valid_mac(mac): LOG.warning( 'MAC %(mac)s for interface %(name)s is ' 'not valid, skipping', { 'mac': mac, 'name': name }, data=data) continue mac = mac.lower() LOG.debug( 'Found interface %(name)s with MAC "%(mac)s", ' 'IP address "%(ip)s" and client_id "%(client_id)s"', { 'name': name, 'mac': mac, 'ip': ip, 'client_id': client_id }, data=data) result[name] = {'ip': ip, 'mac': mac, 'client_id': client_id} return result
def before_update(self, introspection_data, node_info, **kwargs): """Process LLDP data and patch Ironic port local link connection""" inventory = utils.get_inventory(introspection_data) ironic_ports = node_info.ports() for iface in inventory['interfaces']: if iface['name'] not in introspection_data['all_interfaces']: continue mac_address = iface['mac_address'] port = ironic_ports.get(mac_address) if not port: LOG.debug("Skipping LLC processing for interface %s, matching " "port not found in Ironic.", mac_address, node_info=node_info, data=introspection_data) continue lldp_data = iface.get('lldp') if lldp_data is None: LOG.warning(_LW("No LLDP Data found for interface %s"), mac_address, node_info=node_info, data=introspection_data) continue patches = [] for tlv_type, tlv_value in lldp_data: patch = self._get_local_link_patch(tlv_type, tlv_value, port) if patch is not None: patches.append(patch) try: # NOTE(sambetts) We need a newer version of Ironic API for this # transaction, so create a new ironic client and explicitly # pass it into the function. cli = ironic.get_client(api_version=REQUIRED_IRONIC_VERSION) node_info.patch_port(port, patches, ironic=cli) except client_exc.NotAcceptable: LOG.error(_LE("Unable to set Ironic port local link " "connection information because Ironic does not " "support the required version"), node_info=node_info, data=introspection_data) # NOTE(sambetts) May as well break out out of the loop here # because Ironic version is not going to change for the other # interfaces. break
def before_update(self, introspection_data, node_info, **kwargs): inventory = utils.get_inventory(introspection_data) caps = {} if CONF.capabilities.boot_mode: caps.update(self._detect_boot_mode(inventory, node_info, introspection_data)) caps.update(self._detect_cpu_flags(inventory, node_info, introspection_data)) if caps: LOG.debug('New capabilities: %s', caps, node_info=node_info, data=introspection_data) node_info.update_capabilities(**caps) else: LOG.debug('No new capabilities detected', node_info=node_info, data=introspection_data)
def before_update(self, introspection_data, node_info, **kwargs): """Update node with scheduler properties.""" inventory = utils.get_inventory(introspection_data, node_info=node_info) errors = [] root_disk = introspection_data.get('root_disk') if root_disk: introspection_data['local_gb'] = root_disk['size'] // units.Gi if CONF.processing.disk_partitioning_spacing: introspection_data['local_gb'] -= 1 else: introspection_data['local_gb'] = 0 try: introspection_data['cpus'] = int(inventory['cpu']['count']) introspection_data['cpu_arch'] = six.text_type( inventory['cpu']['architecture']) except (KeyError, ValueError, TypeError): errors.append(_('malformed or missing CPU information: %s') % inventory.get('cpu')) try: introspection_data['memory_mb'] = int( inventory['memory']['physical_mb']) except (KeyError, ValueError, TypeError): errors.append(_('malformed or missing memory information: %s; ' 'introspection requires physical memory size ' 'from dmidecode') % inventory.get('memory')) if errors: raise utils.Error(_('The following problems encountered: %s') % '; '.join(errors), node_info=node_info, data=introspection_data) LOG.info(_LI('Discovered data: CPUs: %(cpus)s %(cpu_arch)s, ' 'memory %(memory_mb)s MiB, disk %(local_gb)s GiB'), {key: introspection_data.get(key) for key in self.KEYS}, node_info=node_info, data=introspection_data) overwrite = CONF.processing.overwrite_existing properties = {key: str(introspection_data[key]) for key in self.KEYS if overwrite or not node_info.node().properties.get(key)} node_info.update_properties(**properties)
def before_update(self, introspection_data, node_info, **kwargs): """Update node with scheduler properties.""" inventory = utils.get_inventory(introspection_data, node_info=node_info) errors = [] try: introspection_data['cpus'] = int(inventory['cpu']['count']) introspection_data['cpu_arch'] = six.text_type( inventory['cpu']['architecture']) except (KeyError, ValueError, TypeError): errors.append( _('malformed or missing CPU information: %s') % inventory.get('cpu')) try: introspection_data['memory_mb'] = int( inventory['memory']['physical_mb']) except (KeyError, ValueError, TypeError): errors.append( _('malformed or missing memory information: %s; ' 'introspection requires physical memory size ' 'from dmidecode') % inventory.get('memory')) if errors: raise utils.Error(_('The following problems encountered: %s') % '; '.join(errors), node_info=node_info, data=introspection_data) LOG.info( 'Discovered data: CPUs: %(cpus)s %(cpu_arch)s, ' 'memory %(memory_mb)s MiB', {key: introspection_data.get(key) for key in self.KEYS}, node_info=node_info, data=introspection_data) overwrite = CONF.processing.overwrite_existing properties = { key: str(introspection_data[key]) for key in self.KEYS if overwrite or not node_info.node().properties.get(key) } node_info.update_properties(**properties)
def before_update(self, introspection_data, node_info, **kwargs): """Detect root disk from root device hints and IPA inventory.""" hints = node_info.node().properties.get('root_device') if not hints: LOG.debug('Root device hints are not provided', node_info=node_info, data=introspection_data) return inventory = utils.get_inventory(introspection_data, node_info=node_info) try: device = il_utils.match_root_device_hints(inventory['disks'], hints) except (TypeError, ValueError) as e: raise utils.Error( _('No disks could be found using the root device hints ' '%(hints)s because they failed to validate. ' 'Error: %(error)s') % { 'hints': hints, 'error': e }, node_info=node_info, data=introspection_data) if not device: raise utils.Error(_('No disks satisfied root device hints'), node_info=node_info, data=introspection_data) LOG.debug( 'Disk %(disk)s of size %(size)s satisfies ' 'root device hints', { 'disk': device.get('name'), 'size': device['size'] }, node_info=node_info, data=introspection_data) introspection_data['root_disk'] = device
def _get_interfaces(self, data=None): """Convert inventory to a dict with interfaces. :return: dict interface name -> dict with keys 'mac' and 'ip' """ result = {} inventory = utils.get_inventory(data) for iface in inventory['interfaces']: name = iface.get('name') mac = iface.get('mac_address') ip = iface.get('ipv4_address') if not name: LOG.error(_LE('Malformed interface record: %s'), iface, data=data) continue if not mac: LOG.debug('Skipping interface %s without link information', name, data=data) continue if not netutils.is_valid_mac(mac): LOG.warning(_LW('MAC %(mac)s for interface %(name)s is ' 'not valid, skipping'), {'mac': mac, 'name': name}, data=data) continue mac = mac.lower() LOG.debug('Found interface %(name)s with MAC "%(mac)s" and ' 'IP address "%(ip)s"', {'name': name, 'mac': mac, 'ip': ip}, data=data) result[name] = {'ip': ip, 'mac': mac} return result
def before_update(self, introspection_data, node_info, **kwargs): """Process LLDP data and update all_interfaces with processed data""" inventory = utils.get_inventory(introspection_data) for iface in inventory['interfaces']: if_name = iface['name'] tlvs = iface.get('lldp') if tlvs is None: LOG.warning("No LLDP Data found for interface %s", if_name, node_info=node_info) continue LOG.debug("Processing LLDP Data for interface %s", if_name, node_info=node_info) nv = self._parse_lldp_tlvs(tlvs, node_info) if nv: # Store lldp data per interface in "all_interfaces" iface_to_update = introspection_data['all_interfaces'][if_name] iface_to_update['lldp_processed'] = nv
def before_update(self, introspection_data, node_info, **kwargs): """Process LLDP data and update all_interfaces with processed data""" inventory = utils.get_inventory(introspection_data) for iface in inventory['interfaces']: if_name = iface['name'] tlvs = iface.get('lldp') if tlvs is None: LOG.warning(_LW("No LLDP Data found for interface %s"), if_name, node_info=node_info) continue LOG.debug("Processing LLDP Data for interface %s", if_name, node_info=node_info) nv = self._parse_lldp_tlvs(tlvs, node_info) if nv: # Store lldp data per interface in "all_interfaces" iface_to_update = introspection_data['all_interfaces'][if_name] iface_to_update['lldp_processed'] = nv
def before_update(self, introspection_data, node_info, **kwargs): """Update node with scheduler properties.""" inventory = utils.get_inventory(introspection_data, node_info=node_info) try: introspection_data['cpus'] = int(inventory['cpu']['count']) introspection_data['cpu_arch'] = six.text_type( inventory['cpu']['architecture']) except (KeyError, ValueError, TypeError): LOG.warning('malformed or missing CPU information: %s', inventory.get('cpu')) try: introspection_data['memory_mb'] = int( inventory['memory']['physical_mb']) except (KeyError, ValueError, TypeError): LOG.warning( 'malformed or missing memory information: %s; ' 'introspection requires physical memory size ' 'from dmidecode', inventory.get('memory')) LOG.info( 'Discovered data: CPUs: count %(cpus)s, architecture ' '%(cpu_arch)s, memory %(memory_mb)s MiB', {key: introspection_data.get(key) for key in self.KEYS}, node_info=node_info, data=introspection_data) overwrite = CONF.processing.overwrite_existing properties = { key: str(introspection_data[key]) for key in self.KEYS if introspection_data.get(key) and ( overwrite or not node_info.node().properties.get(key)) } if properties: node_info.update_properties(**properties)
def before_update(self, introspection_data, node_info, **kwargs): """Process root disk information.""" inventory = utils.get_inventory(introspection_data, node_info=node_info) self._process_root_device_hints(introspection_data, node_info, inventory) root_disk = introspection_data.get('root_disk') if root_disk: local_gb = root_disk['size'] // units.Gi if CONF.processing.disk_partitioning_spacing: local_gb -= 1 LOG.info('Root disk %(disk)s, local_gb %(local_gb)s GiB', {'disk': root_disk, 'local_gb': local_gb}, node_info=node_info, data=introspection_data) else: local_gb = 0 LOG.info('No root device found, assuming a diskless node', node_info=node_info, data=introspection_data) introspection_data['local_gb'] = local_gb if (CONF.processing.overwrite_existing or not node_info.node().properties.get('local_gb')): node_info.update_properties(local_gb=str(local_gb))
def before_update(self, introspection_data, node_info, **kwargs): """Process introspection data and patch port physical network.""" inventory = utils.get_inventory(introspection_data) LOG.info("Plugin: %s", type(self)) # Use a client with a version set explicitly. client = ironic.get_client(api_version=REQUIRED_IRONIC_VERSION) ironic_ports = node_info.ports() if (ironic_ports and not all(hasattr(port, 'physical_network') for port in ironic_ports.values())): # If the ports do not have a physical network field, use our newer # versioned client to fetch some that do. port_list = client.node.list_ports(node_info.uuid, limit=0, detail=True) ironic_ports = {p.address: p for p in port_list} for iface in inventory['interfaces']: if iface['name'] not in introspection_data['all_interfaces']: continue mac_address = iface['mac_address'] port = ironic_ports.get(mac_address) if not port: LOG.debug("Skipping physical network processing for interface " "%s, matching port not found in Ironic.", mac_address, node_info=node_info, data=introspection_data) continue # Determine the physical network for this port. # Port not touched in here. physnet = self.get_physnet(port, iface['name'], introspection_data) if physnet is None: LOG.debug("Skipping physical network processing for interface " "%s, no physical network mapping", mac_address, node_info=node_info, data=introspection_data) continue patch = self._get_physnet_patch(physnet, port) if patch is None: LOG.debug("Skipping physical network processing for interface " "%s, no update required", mac_address, node_info=node_info, data=introspection_data) continue try: node_info.patch_port(port, [patch], ironic=client) except client_exc.NotAcceptable: LOG.error("Unable to set Ironic port physical network " "because Ironic does not support the required " "version (%(version)s)", node_info=node_info, data=introspection_data, version=REQUIRED_IRONIC_VERSION) # NOTE(sambetts) May as well break out out of the loop here # because Ironic version is not going to change for the other # interfaces. break
def _get_interfaces(self, data=None): """Convert inventory to a dict with interfaces. :return: dict interface name -> dict with keys 'mac' and 'ip' """ result = {} inventory = utils.get_inventory(data) pxe_mac = utils.get_pxe_mac(data) for iface in inventory['interfaces']: name = iface.get('name') mac = iface.get('mac_address') ipv4_address = iface.get('ipv4_address') ipv6_address = iface.get('ipv6_address') # NOTE(kaifeng) ipv6 address may in the form of fd00::1%enp2s0, # which is not supported by netaddr, remove the suffix if exists. if ipv6_address and '%' in ipv6_address: ipv6_address = ipv6_address.split('%')[0] ip = ipv4_address or ipv6_address client_id = iface.get('client_id') if not name: LOG.error('Malformed interface record: %s', iface, data=data) continue if not mac: LOG.debug('Skipping interface %s without link information', name, data=data) continue if not netutils.is_valid_mac(mac): LOG.warning( 'MAC %(mac)s for interface %(name)s is ' 'not valid, skipping', { 'mac': mac, 'name': name }, data=data) continue mac = mac.lower() LOG.debug( 'Found interface %(name)s with MAC "%(mac)s", ' 'IP address "%(ip)s" and client_id "%(client_id)s"', { 'name': name, 'mac': mac, 'ip': ip, 'client_id': client_id }, data=data) result[name] = { 'ip': ip, 'mac': mac, 'client_id': client_id, 'pxe': (mac == pxe_mac) } return result