def has_client_wwpns(vios_wraps, client_wwpn_pair): """Returns the vios wrapper and vfc map if the client WWPNs already exist. :param vios_wraps: The VIOS wrappers. Should be queried with the VIO_FMAP extended attribute. :param client_wwpn_pair: The pair (list or set) of the client WWPNs. :return vios_w: The VIOS wrapper containing the wwpn pair. None if none of the wrappers contain the pair. :return vfc_map: The mapping containing the client pair. May be None. """ client_wwpn_pair = set( [u.sanitize_wwpn_for_api(x) for x in client_wwpn_pair]) for vios_wrap in vios_wraps: for vfc_map in vios_wrap.vfc_mappings: if vfc_map.client_adapter is None: continue pair = set([ u.sanitize_wwpn_for_api(x) for x in vfc_map.client_adapter.wwpns ]) if pair == client_wwpn_pair: return vios_wrap, vfc_map return None, None
def intersect_wwpns(wwpn_set1, wwpn_set2): """Will return the intersection of WWPNs between the two sets. :param wwpn_set1: A list of WWPNs. :param wwpn_set2: A list of WWPNs. :return: The intersection of the WWPNs. Will maintain the WWPN format of wwpn_set1, but the comparison done will be agnostic of formats (ex. colons and/or upper/lower case). """ wwpn_set2 = [u.sanitize_wwpn_for_api(x) for x in wwpn_set2] return [y for y in wwpn_set1 if u.sanitize_wwpn_for_api(y) in wwpn_set2]
def find_vios_for_vfc_wwpns(vios_wraps, vfc_wwpns): """Will find the VIOS that is hosting the vfc_wwpns. :param vios_wraps: A list or set of VIOS wrappers. :param vfc_wwpns: The list or set of virtual fibre channel WWPNs. :return: The VIOS wrapper that supports the vfc adapters. If there is not one, then None will be returned. :return: The VFCMapping on the VIOS that supports the client adapters. """ # Sanitize our input vfc_wwpns = {u.sanitize_wwpn_for_api(x) for x in vfc_wwpns} for vios_w in vios_wraps: for vfc_map in vios_w.vfc_mappings: # If the map has no client adapter...then move on if not vfc_map.client_adapter: continue # Maps without backing ports are effectively stale. We shouldn't # consider them. if vfc_map.backing_port is None: continue # If the WWPNs match, return it if vfc_wwpns == set(vfc_map.client_adapter.wwpns): return vios_w, vfc_map return None, None
def find_vios_for_wwpn(vios_wraps, p_port_wwpn): """Will find the VIOS that has a PhysFCPort for the p_port_wwpn. :param vios_wraps: A list or set of VIOS wrappers. :param p_port_wwpn: The physical port's WWPN. :return: The VIOS wrapper that contains a physical port with the WWPN. If there is not one, then None will be returned. :return: The port (which is a PhysFCPort wrapper) on the VIOS wrapper that represents the physical port. """ # Sanitize our input s_p_port_wwpn = u.sanitize_wwpn_for_api(p_port_wwpn) for vios_w in vios_wraps: for port in vios_w.pfc_ports: # No need to sanitize the API WWPN, it comes from the API. if u.sanitize_wwpn_for_api(port.wwpn) == s_p_port_wwpn: return vios_w, port return None, None
def add_map(vios_w, host_uuid, lpar_uuid, port_map, error_if_invalid=True): """Adds a vFC mapping to a given VIOS wrapper. These changes are not flushed back to the REST server. The wrapper itself is simply modified. :param vios_w: VIOS EntryWrapper representing the Virtual I/O Server whose VFC mappings are to be updated. :param host_uuid: The pypowervm UUID of the host. :param lpar_uuid: The pypowervm UUID of the client LPAR to attach to. :param port_map: The port mapping (as defined by the derive_npiv_map method). :param error_if_invalid: (Optional, Default: True) If the port mapping physical port can not be found, raise an error. :return: The VFCMapping that was added. If the mapping already existed then None is returned. """ # This is meant to find the physical port. Can run against a single # element. We assume invoker has passed correct VIOS. new_vios_w, p_port = find_vios_for_wwpn([vios_w], port_map[0]) if new_vios_w is None: if error_if_invalid: # Log the payload in the response. LOG.warn(_("Unable to find appropriate VIOS. The payload " "provided was likely insufficient. The payload data " "is:\n %s)"), vios_w.toxmlstring()) raise e.UnableToDerivePhysicalPortForNPIV(wwpn=port_map[0], vio_uri=vios_w.href) else: return None v_wwpns = None if port_map[1] != _FUSED_ANY_WWPN: v_wwpns = [u.sanitize_wwpn_for_api(x) for x in port_map[1].split()] if v_wwpns is not None: for vfc_map in vios_w.vfc_mappings: if (vfc_map.client_adapter is None or vfc_map.client_adapter.wwpns is None): continue if set(vfc_map.client_adapter.wwpns) != set(v_wwpns): continue # If we reach this point, we know that we have a matching map. So # the attach of this volume, for this vFC mapping is complete. # Nothing else needs to be done, exit the method. return None # However, if we hit here, then we need to create a new mapping and # attach it to the VIOS mapping vfc_map = pvm_vios.VFCMapping.bld(vios_w.adapter, host_uuid, lpar_uuid, p_port.name, client_wwpns=v_wwpns) vios_w.vfc_mappings.append(vfc_map) return vfc_map
def _find_ports_on_vio(vio_w, p_port_wwpns): """Will return a list of Physical FC Ports on the vio_w. :param vio_w: The VIOS wrapper. :param p_port_wwpns: The list of all physical ports. May exceed the ports on the VIOS. :return: List of the physical FC Port wrappers that are on the VIOS for the WWPNs that exist on this system. """ return [port for port in vio_w.pfc_ports if u.sanitize_wwpn_for_api(port.wwpn) in p_port_wwpns]
def has_client_wwpns(vios_wraps, client_wwpn_pair): """Returns the vios wrapper and vfc map if the client WWPNs already exist. :param vios_wraps: The VIOS wrappers. Should be queried with the FC_MAPPING extended attribute. :param client_wwpn_pair: The pair (list or set) of the client WWPNs. :return vios_w: The VIOS wrapper containing the wwpn pair. None if none of the wrappers contain the pair. :return vfc_map: The mapping containing the client pair. May be None. """ client_wwpn_pair = set([u.sanitize_wwpn_for_api(x) for x in client_wwpn_pair]) for vios_wrap in vios_wraps: for vfc_map in vios_wrap.vfc_mappings: if vfc_map.client_adapter is None: continue pair = set([u.sanitize_wwpn_for_api(x) for x in vfc_map.client_adapter.wwpns]) if pair == client_wwpn_pair: return vios_wrap, vfc_map return None, None
def find_vios_for_vfc_wwpns(vios_wraps, vfc_wwpns): """Will find the VIOS that is hosting the vfc_wwpns. :param vios_wraps: A list or set of VIOS wrappers. :param vfc_wwpns: The list or set of virtual fibre channel WWPNs. :return: The VIOS wrapper that supports the vfc adapters. If there is not one, then None will be returned. :return: The VFCMapping on the VIOS that supports the client adapters. """ # Sanitize our input vfc_wwpns = {u.sanitize_wwpn_for_api(x) for x in vfc_wwpns} for vios_w in vios_wraps: for vfc_map in vios_w.vfc_mappings: # If the map has no client adapter...then move on if not vfc_map.client_adapter: continue # If the WWPNs match, return it if vfc_wwpns == set(vfc_map.client_adapter.wwpns): return vios_w, vfc_map return None, None
def c_wwpn_to_vfc_mapping(vios_w, c_wwpn): """Finds the vFC mapping (if any) for a given client WWPN. This is a helper method that will parse through a given VIOS wrapper (retrieved with pypowervm.const.XAG.VIO_FMAP) and will find the client vFC mapping for that WWPN. :param vios_w: The Virtual I/O Server wrapper. Should have pypowervm.const.XAG.VIO_FMAP associated with it. :param c_wwpn: One of the client's WWPNs. :return: The vFC mapping (or None) """ wwpn = util.sanitize_wwpn_for_api(c_wwpn) for vfc_map in vios_w.vfc_mappings: # If there is not a client adapter, it isn't properly attached. if not vfc_map.client_adapter: continue if wwpn in vfc_map.client_adapter.wwpns: return vfc_map return None
def find_maps(mapping_list, client_lpar_id, client_adpt=None, port_map=None): """Filter a list of VFC mappings by LPAR ID. This is based on scsi_mapper.find_maps, but does not yet provide all the same functionality. :param mapping_list: The mappings to filter. Iterable of VFCMapping. :param client_lpar_id: Integer short ID or string UUID of the LPAR on the client side of the mapping. Note that the UUID form relies on the presence of the client_lpar_href field. Some mappings lack this field, and would therefore be ignored. :param client_adpt: (Optional, Default=None) If set, will only include the mapping if the client adapter's WWPNs match as well. :param port_map: (Optional, Default=None) If set, will look for a matching mapping based off the client WWPNs as specified by the port mapping. The format of this is defined by the derive_npiv_map method. :return: A list comprising the subset of the input mapping_list whose client LPAR IDs match client_lpar_id. """ is_uuid, client_id = uuid.id_or_uuid(client_lpar_id) matching_maps = [] if port_map: v_wwpns = [u.sanitize_wwpn_for_api(x) for x in port_map[1].split()] for vfc_map in mapping_list: # If to a different VM, continue on. href = vfc_map.client_lpar_href if is_uuid and (not href or client_id != u.get_req_path_uuid( href, preserve_case=True)): continue elif (not is_uuid and # Use the server adapter in case this is an orphan. vfc_map.server_adapter.lpar_id != client_id): continue # If there is a client adapter, and it is not a 'ANY WWPN', then # check to see if the mappings match. if client_adpt and client_adpt.wwpns != {_ANY_WWPN}: # If they passed in a client adapter, but the map doesn't have # one, then we have to ignore if not vfc_map.client_adapter: continue # Check to make sure the WWPNs between the two match. This should # be an order independence check (as this query shouldn't care... # but the API itself does care about order). if set(client_adpt.wwpns) != set(vfc_map.client_adapter.wwpns): continue # If the user had a port map, do the virtual WWPNs from that port # map match the client adapter wwpn map. if port_map: if vfc_map.client_adapter is None: continue # If it is a new mapping with generated WWPNs, then the client # adapter can't have WWPNs. if v_wwpns == [_ANY_WWPN, _ANY_WWPN]: if vfc_map.client_adapter.wwpns != []: continue elif set(vfc_map.client_adapter.wwpns) != set(v_wwpns): continue # Found a match! matching_maps.append(vfc_map) return matching_maps
def add_map(vios_w, host_uuid, lpar_uuid, port_map, error_if_invalid=True, lpar_slot_num=None): """Adds a vFC mapping to a given VIOS wrapper. These changes are not flushed back to the REST server. The wrapper itself is simply modified. :param vios_w: VIOS EntryWrapper representing the Virtual I/O Server whose VFC mappings are to be updated. :param host_uuid: The pypowervm UUID of the host. :param lpar_uuid: The pypowervm UUID of the client LPAR to attach to. :param port_map: The port mapping (as defined by the derive_npiv_map method). :param error_if_invalid: (Optional, Default: True) If the port mapping physical port can not be found, raise an error. :param lpar_slot_num: (Optional, Default: None) The client adapter VirtualSlotNumber to be set. If None the next available slot would be used. :return: The VFCMapping that was added or updated with a missing backing port. If the mapping already existed then None is returned. """ # This is meant to find the physical port. Can run against a single # element. We assume invoker has passed correct VIOS. new_vios_w, p_port = find_vios_for_wwpn([vios_w], port_map[0]) if new_vios_w is None: if error_if_invalid: # Log the payload in the response. LOG.warning(_("Unable to find appropriate VIOS. The payload " "provided was likely insufficient. The payload " "data is:\n %s)"), vios_w.toxmlstring(pretty=True)) raise e.UnableToDerivePhysicalPortForNPIV(wwpn=port_map[0], vio_uri=vios_w.href) else: return None v_wwpns = None if port_map[1] != _FUSED_ANY_WWPN: v_wwpns = [u.sanitize_wwpn_for_api(x) for x in port_map[1].split()] if v_wwpns is not None: for vfc_map in vios_w.vfc_mappings: if (vfc_map.client_adapter is None or vfc_map.client_adapter.wwpns is None): continue if set(vfc_map.client_adapter.wwpns) != set(v_wwpns): continue # If we reach this point, we know that we have a matching map. # Check that the physical port is set in the mapping. if vfc_map.backing_port: LOG.debug("Matching existing vfc map found with backing port:" " %s", vfc_map.backing_port.wwpn) # The attach of this volume, for this vFC mapping is complete. # Nothing else needs to be done, exit the method. return None else: LOG.info(_("The matched VFC port map has no backing port set." " Adding %(port)s to mapping for client wwpns: " "%(wwpns)s"), {'port': p_port.name, 'wwpns': v_wwpns}) # Build the backing_port and add it to the vfc_map. vfc_map.backing_port = bp.PhysFCPort.bld_ref( vios_w.adapter, p_port.name, ref_tag='Port') return vfc_map # However, if we hit here, then we need to create a new mapping and # attach it to the VIOS mapping vfc_map = pvm_vios.VFCMapping.bld(vios_w.adapter, host_uuid, lpar_uuid, p_port.name, client_wwpns=v_wwpns, lpar_slot_num=lpar_slot_num) vios_w.vfc_mappings.append(vfc_map) return vfc_map