def get_k2element_for_sea(k2vios, sea): """ This method returns the K2Element that corresponds to the SEA on the specific VIOS passed in. :param k2vios: K2Entry for the VIOS we're searching :param sea: SharedEthernetAdapter DOM object :returns K2Element: K2Element in the K2Response that corresponds to the SEA passed in. Returns None if not found. """ if not k2vios or not sea: ras.trace(LOG, __name__, ras.TRACE_INFO, _("No VIOS or SEA passed in for SEA Gather")) return None # Now get all the SharedEthernetAdapters seas = k2vios.element.findall("./SharedEthernetAdapters/" "SharedEthernetAdapter") # Be sure we found some SEAs in the K2Response if seas: # Loop through all trunk adapters found and grab adapter attributes for s in seas: # Device names match? if sea.name == s.findtext("DeviceName"): # Score! return s # TODO: Remove once everyone's at 1340A HMC if sea.name == s.findtext("InterfaceName"): return s # If we got here, didn't find it. return None
def _supports_dynamic_update(self, vios=None): """ This method returns whether the VIOS supports dynamically updating VLAN ids on VEAs or not. On HMC, this depends on the system's capabilities. :param vios: VioServer DOM object representing VIOS running against :returns boolean: True if dynamic updates supported, False otherwise """ ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, "Enter") if self._supports_dynamic_vlans is None: # Older firmware cannot dynamically update a VEA with vlans (boo). # We cache the ManagedSystem K2Response because that shouldn't # ever change. ras.trace(LOG, __name__, ras.TRACE_DEBUG, ras.msg('info', 'K2_GET_MS')) # Make the K2 call to get the ManagedSystem response ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, 'Getting ManagedSystem') k2entry_ms = self._topo._find_k2_managed_system() ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, 'Got ManagedSystem') # Now check to see if the system supports dynamic vlan additions caps = k2entry_ms.element.find('AssociatedSystem' 'Capabilities') dynamic_lpar = caps.findtext('VirtualEthernetAdapterDynamic' 'LogicalPartitionCapable') # Convert and return what we found as a boolean self._supports_dynamic_vlans = (dynamic_lpar == 'true') return self._supports_dynamic_vlans
def _update_vnet_tag(self, k2_virt_net, new_tag): """ Will validate the the tagged network entry is set properly and is updated in the network. If the tagged entry is set properly, no changes are made. :param k2_virt_net: The K2 Entry for the Virtual Network :param new_tag: The Boolean that states whether or not the network should be tagged or not. """ k2_tag_element = k2_virt_net.element.find('TaggedNetwork') old_tag = k2_tag_element.gettext() if old_tag.lower() != str(new_tag).lower(): k2_tag_element.settext(str(new_tag).lower()) # The TaggedNetwork Attribute can not be 'updated' regardless # of what the schema says. K2 will throw an error. They # will only support this flow by first deleting the virtual # network and then creating a new one. try: self._k2op.delete(rootType='ManagedSystem', rootId=self._topo._find_managed_system(), childType='VirtualNetwork', childId=k2_virt_net.properties['id'], timeout=hmc.K2_WRITE_SEC) except Exception as e: # This should be very rare and only occur in the case where # there were existing client lpars with the vlan we're # plugging. If we disallowed those vlans, we'd break VM # import, so instead just tolerate this. ras.trace(LOG, __name__, ras.TRACE_WARNING, 'Unable to flip TaggedNetwork for VirtualNetwork ' '%(net)s due to exception: %(excpt)s' % {'net': k2_virt_net.properties['id'], 'excpt': e}) return # Do the update of the Virtual Network self._k2op.create(element=k2_virt_net.element, rootType='ManagedSystem', rootId=self._topo._find_managed_system(), childType='VirtualNetwork', timeout=hmc.K2_WRITE_SEC)
def get_k2entry_for_vios(k2response, vios): """ This method returns the K2Entry in K2Response.entries that corresponds to the vios passed in. :param k2response: VirtualIOServer K2Response :param vios: VioServer DOM object :returns K2Entry: K2Entry in the K2Response that corresponds to the VIOS passed in. Returns None if not found. """ # Be sure they passed in a vios if not vios: ras.trace(LOG, __name__, ras.TRACE_INFO, _("No VIOS passed in")) return None # Be sure the response they gave us has entries to loop over if not k2response or not k2response.feed or not k2response.feed.entries: ras.trace(LOG, __name__, ras.TRACE_INFO, _("Empty K2 response given")) return None # Loop through all VIOSes in the K2 response for entry in k2response.feed.entries: # Get the id and name of this VIOS in the response lpar_id = int(entry.element.findtext("PartitionID")) lpar_name = entry.element.findtext("PartitionName") # See if it matches what we're looking for if lpar_id == vios.lpar_id and lpar_name == vios.lpar_name: return entry # If we got here, we didn't find a match. This really shouldn't # happen, but better to be paranoid... ras.trace(LOG, __name__, ras.TRACE_ERROR, _("Failed to find VIOS in K2 response")) return None
def _get_k2entry_for_lpar_tag(k2response, lpar_key, lpar_id): """ This method returns the K2Entry in K2Response.entries that corresponds to the lpar id passed in. :param k2response: VirtualIOServer K2Response :param lpar_key: The key to search for within the lpar :param lpar_id: The lpar_id passed in :returns K2Entry: K2Entry in the K2Response that corresponds to the VIOS passed in. Returns None if not found. """ # Be sure they passed in an id if not lpar_id: ras.trace(LOG, __name__, ras.TRACE_INFO, _("No lpar_id passed in")) return None # Be sure the response they gave us has entries to loop over if not k2response or not k2response.feed or not k2response.feed.entries: ras.trace(LOG, __name__, ras.TRACE_INFO, _("Empty K2 response given")) return None # Loop through all VIOSes in the K2 response for entry in k2response.feed.entries: # Get the id and name of this VIOS in the response k2_lpar_id = entry.element.findtext(lpar_key) # See if it matches what we're looking for if str(lpar_id) == k2_lpar_id: return entry # If we got here, we didn't find a match. This really shouldn't # happen, but better to be paranoid... ras.trace(LOG, __name__, ras.TRACE_ERROR, _("Failed to find VIOS in K2 response")) return None
def build_seas_from_K2_response( k2response, vios, k2_net_bridges, vswitch_map, k2_oper, dom_factory=model.No_DB_DOM_Factory() ): """ This method takes in a VirtualIOServer K2Response and builds the K2 SharedEthernetAdapters into SharedEthernetAdapter DOM objects. Each SEA's VEAs (trunk adapters in K2-speak) will also be built and all adapters (both SEAs and VEAs) will be added to the passed in VioServer object. :param k2response: VirtualIOServer K2Response :param vios: VioServer DOM object to add VEAs to :param k2_net_bridges: The NetworkBridge K2Response :param vswitch_map: The map of vswitches on the CEC :param k2_oper: The k2 operator :param dom_factory: Factory used to create the DOM objects, optional. :returns sea_list: List of SharedEthernetAdapter DOM objects """ sea_list = [] entry = get_k2entry_for_vios(k2response, vios) # If VIOS not found, return empty list if not entry: ras.trace(LOG, __name__, ras.TRACE_ERROR, ras.vif_get_msg("error", "VIOS_UNKNOWN")) return sea_list # Now get all the SharedEthernetAdapters seas, ctrl_chan_map, sea_pvid_map = _find_seas_from_bridge(entry, k2_net_bridges) # Be sure we found some SEAs in the K2Response if seas: # Loop through all trunk adapters found and grab adapter attributes for sea in seas: # Device name name = sea.findtext("DeviceName") # TODO: Remove once everyone's at 1340A HMC if name is None: name = sea.findtext("InterfaceName") # If we got no interface name, we can't proceed. if not name: raise excp.IBMPowerVMInvalidHostConfig(attr="DeviceName") # Find all VEAs and add them to this SEA # First, we need the SEA's pvid so we can identify the # primary VEA sea_pvid = sea_pvid_map.get(name) primary_vea = None slot = 0 control_channel = None additional_veas = [] vswitch_name = None # Now get all VEAs under this SEA for vea in build_veas_from_K2_sea_k2_entry(sea, vios, vswitch_map, k2_oper): # Grab the vswitch name. We may need this for the control # channel lookup below. vswitch_name = vea.vswitch_name if vea.pvid == sea_pvid: # Found the primary VEA primary_vea = vea slot = vea.slot else: # Must just be an additional VEA additional_veas.append(vea) # If this SEA has a control channel, find the right VEA for it. ctrl_chan_ifname = sea.findtext("ControlChannelInterfaceName") if ctrl_chan_ifname: # Look in the map for the <devicename,vswitchid> key that # matches this SEA's control channel info. find_key = ctrl_chan_ifname + "," + find_vswitch_id_for_name(vswitch_name, vswitch_map) ctrl_chan_id = int(ctrl_chan_map.get(find_key, 0)) # We know that topo_hmc._populate_adapters_into_vios() # already built the VIOS DOM object with ALL VEAs in it... # so spin through and find the CNAs to find our control # channel. for vea in vios.get_all_virtual_ethernet_adapters(): # If this is a CNA (non-trunk adapter) and the pvid # matches the control channel id and it's on the same # vswitch as this SEA if not vea.is_trunk and vea.pvid == ctrl_chan_id and vea.vswitch_name == vswitch_name: # We've got our match! control_channel = vea # Break out of the loop break # If we get here, we expect to have found the control # channel. Log if we don't. if control_channel is None: ras.trace( LOG, __name__, ras.TRACE_WARNING, _( "Didn't find control channel for device " "%(dev)s, vswitch %(vswitch)s, and id " "%(c_id)d)" % {"dev": ctrl_chan_ifname, "vswitch": vswitch_name, "c_id": ctrl_chan_id} ), ) # Build and add the DOM object to the return list. This # should raise an exception if there is something wrong with # the configuration of this SEA. sea_list.append( dom_factory.create_sea( name=name, vio_server=vios, slot=slot, state="Available", primary_vea=primary_vea, control_channel=control_channel, additional_veas=additional_veas, ) ) ras.trace(LOG, __name__, ras.TRACE_DEBUG, "Built SEA %s on VIOS %s" % (name, vios.name)) # Return what we found (which could be nothing, but that's bad) ras.trace(LOG, __name__, ras.TRACE_DEBUG, "Found %d SEAs" % len(sea_list)) return sea_list
def _find_seas_from_bridge(k2_vios_entry, k2_net_bridges): """ Will query the K2 Bridges and find all of the associated SEAs on that Bridge list for this VIOS. This is needed because K2 only stores the full data for the SEA's on the NetworkBridge, and no longer on the VirtualIOServer object itself. :param k2_vios_entry: The K2Entry representing the VIOS :param k2_net_bridges: The K2 NetworkBridge response :returns sea_list: A list of K2 Entry's for the SEAs on this VIOS :returns cc_map: A dictionary mapping ControlChannelInterfaceNames to ControlChannelIDs. The format of the dictionary is: { '<ifname>,<vswitchid>': <controlchannelid> } Or, with real data: { 'ent6,0': 4094 } :returns pvid_map: A dictionary mapping SEA device names to their pvids. It looks as follows: {'ent11': 1, 'ent12': 2} """ sea_list = [] cc_map = {} pvid_map = {} vios_uuid = k2_vios_entry.element.findtext("PartitionUUID") for entry in k2_net_bridges.feed.entries: seas = entry.element.findall("./SharedEthernetAdapters/" "SharedEthernetAdapter") # Grab the NetworkBridge's pvid. This will be the SEA's pvid since # legacy VIOS code allows the SEA to have a pvid that doesn't match # the primary adapter's pvid. We need the primary adapters pvid, not # a value that the VIOS could allow a user to configure with something # completely different. nb_pvid = entry.element.findtext("PortVLANID") if nb_pvid is not None: nb_pvid = int(nb_pvid) for sea in seas: assigned_vio = sea.find("AssignedVirtualIOServer").get("href") # Found an SEA for this VIOS if assigned_vio.endswith(vios_uuid): # Save off the SEA K2Element sea_list.append(sea) # Create entry in the pvid map sea_name = sea.findtext("DeviceName") # TODO: Remove once everyone's at 1340A HMC if sea_name is None: sea_name = sea.findtext("InterfaceName") if sea_name is not None: pvid_map[sea_name] = nb_pvid # Save off Control Channel info, if this SEA has one. ctrl_ifname = sea.findtext("ControlChannelInterfaceName") if ctrl_ifname: # Control Channel ID comes from the overall NetworkBridge ctrl_id = entry.element.findtext("ControlChannelID") # The control channel is also tied to a vswitch, so find # the vswitch of this SEA by looking at its TrunkAdapters vswitch_id = None trunk_adapters = sea.findall("./TrunkAdapters/" "TrunkAdapter") if trunk_adapters: vswitch_id = trunk_adapters[0].findtext("VirtualSwitch" "ID") # Should always find it, but check out of paranoia if ctrl_id is not None: # Make the key <ifname>,<vswitchid> so the user of # this map can exactly match based on ifname and # vswitchid. cc_map[ctrl_ifname + "," + vswitch_id] = int(ctrl_id) else: ras.trace( LOG, __name__, ras.TRACE_WARNING, "Found ControlChannelInterfaceName %s, " "but no ControlChannelID." % ctrl_ifname, ) return sea_list, cc_map, pvid_map
def _build_veas_from_K2_response(k2_entry, vios, vswitch_map, k2_oper, dom_factory=model.No_DB_DOM_Factory()): """ This method takes in a VirtualIOServer K2Response and builds the TrunkAdapters into VirtualEthernetAdapter DOM objects, which are added to the passed in VioServer DOM object. :param k2_entry: K2 entry to searched for TrunkAdapters and ClientNetworkAdapters :param vios: VioServer DOM object that owns the adapters in k2_entry :param vswitch_map: The map of vswitches on the CEC :param k2_oper: The k2 operator :param dom_factory: Factory used to create the DOM objects, optional. :returns veas: List of VirtualEthernetAdapter DOM objects built from the passed in TrunkAdapters list """ vea_list = [] # If VIOS not found, return empty list if not k2_entry: ras.trace(LOG, __name__, ras.TRACE_ERROR, ras.vif_get_msg("error", "VIOS_UNKNOWN")) return vea_list # First, get all the VirtualEthernetAdapters (TrunkAdapters) net_adapters = k2_entry.findall("./TrunkAdapters/TrunkAdapter") if not net_adapters: net_adapters = [] # A VIOS can have 'Client Network Adapters' - which are adapters with # a single VLAN that are not yet part of a SEA. We need to take these # into account as they are also VEAs, just with a special situation. cnas = k2_entry.findall("./ClientNetworkAdapters/link") if cnas: uri = cnas[0].get("href").rsplit("/", 1)[0] if uri: # Get all CNAs in one K2 call k2_cna_resp = k2_oper.readbyhref(href=uri + "?group=None", timeout=hmc.K2_READ_SEC) # If we found some if k2_cna_resp and k2_cna_resp.feed and k2_cna_resp.feed.entries: # Add each to the adapters list for entry in k2_cna_resp.feed.entries: net_adapters.append(entry.element) # Loop through all trunk adapters found and grab adapter attributes for adapter in net_adapters: # Device name if "ClientNetworkAdapter" == adapter.tag: name = "CNA_" + adapter.findtext("LocationCode") else: name = adapter.findtext("DeviceName") # TODO: Remove once everyone's at 1340A HMC if name is None: name = adapter.findtext("InterfaceName") if not name: ras.trace(LOG, __name__, ras.TRACE_WARNING, "Missing name") # Slot number slot = adapter.findtext("VirtualSlotNumber") if slot: slot = int(slot) else: # Set to an invalid value so constructor blows up slot = 0 ras.trace(LOG, __name__, ras.TRACE_WARNING, "Missing slot") # Port VLAN ID pvid = adapter.findtext("PortVLANID") if pvid: pvid = int(pvid) else: # Set to an invalid value so constructor blows up pvid = 0 ras.trace(LOG, __name__, ras.TRACE_WARNING, "Missing pvid") # This is a TrunkAdapter..so by definition is_trunk is true. if "ClientNetworkAdapter" == adapter.tag: is_trunk = False trunk_priority = 1 else: # Trunk adapter case. is_trunk = True trunk_priority = adapter.findtext("TrunkPriority") if trunk_priority: trunk_priority = int(trunk_priority) else: # Set to an invalid value so constructor blows up trunk_priority = 0 ras.trace(LOG, __name__, ras.TRACE_WARNING, "Missing trunk_priority") # State (we'll have to map from K2 terminology to ours) state = adapter.findtext("VariedOn") if state and state == "true": state = "Available" else: if not state: ras.trace(LOG, __name__, ras.TRACE_WARNING, "Missing state") state = "Defined" # 8021Q enabled ieee_eth = adapter.findtext("TaggedVLANSupported") if ieee_eth and ieee_eth == "true": ieee_eth = True else: if not ieee_eth: ras.trace(LOG, __name__, ras.TRACE_WARNING, _("Missing ieee_eth")) ieee_eth = False # Addl vlans addl_vlan_ids = adapter.findtext("TaggedVLANIDs") if addl_vlan_ids: # VirtualEthernetAdapter requires list of ints addl_vlan_ids = map(int, addl_vlan_ids.split(" ")) else: # VirtualEthernetAdapter requires empty list, not None addl_vlan_ids = [] # vswitch name vswitch_id = adapter.findtext("VirtualSwitchID") vswitch_name = find_vswitch_name_for_id(vswitch_id, vswitch_map) if vswitch_name and vswitch_name != "": vswitch_name = vswitch_name else: # Use a default value ras.trace(LOG, __name__, ras.TRACE_DEBUG, "Using default virtual switch name. " "Found %s." % vswitch_name) vswitch_name = "ETHERNET0" # Build and add the DOM object to the return list. This # should raise an exception if there is something wrong with # the configuration of this VEA. try: vea = dom_factory.create_vea( name=name, vio_server=vios, slot=slot, pvid=pvid, is_trunk=is_trunk, trunk_pri=trunk_priority, state=state, ieee_eth=ieee_eth, vswitch_name=vswitch_name, addl_vlan_ids=addl_vlan_ids, ) vea_list.append(vea) except Exception as e: # Took an exception creating the VEA. Log the failing VEA info # and proceed ras.trace(LOG, __name__, ras.TRACE_WARNING, _("Failed to create VEA DOM. (%s)" % e)) ras.trace( LOG, __name__, ras.TRACE_WARNING, _( "Invalid VEA attributes - tag: %(tag)s, name: " "%(name)s, slot: %(slot)d, pvid: %(pvid)d, is_trunk: " "%(is_trunk)s, trunk_priority: %(trunk_priority)d, " "state: %(state)s, ieee_eth: %(ieee_eth)s, " "addl_vlan_ids: %(addl_vlan_ids)s" % { "tag": adapter.tag, "name": name, "slot": slot, "pvid": pvid, "is_trunk": is_trunk, "trunk_priority": trunk_priority, "state": state, "ieee_eth": ieee_eth, "addl_vlan_ids": addl_vlan_ids, } ), ) # Return what we found (which could be nothing, but that's bad) ras.trace(LOG, __name__, ras.TRACE_DEBUG, "Found %d VEAs" % len(vea_list)) return vea_list
def list_ports(self, lpar_id): """ Will query the endpoint and determine the network configuration of the VM. :param lpar_id: The lpar identifier :returns: A list of dictionary objects which represents the networking information. Each dictionary will contain a 'mac_address' and a 'provider:segmentation_id' - which represents the VLAN. """ # A return list of dictionary objects. ret_adapter_list = [] # Get the adapter information for this LPAR, note that UUIDs are # passed in logical_partition = utils.get_k2entry_for_lpar_uuid(self.k2resp, lpar_id).element cna_links = logical_partition.findall('./ClientNetworkAdapters/link') orphaned_pairs = self._get_orphan_pairs() for cna_link in cna_links: try: vea = self._k2op.readbyhref(href=cna_link.get('href') + '?group=None', timeout=hmc.K2_READ_SEC) except Exception: LOG.info(_('Read failed for K2 Client Network Adapter (CNA) ' 'link, skipping the element.')) continue # If we didn't get an entry back for some reason... if not vea.entry: ras.trace(LOG, __name__, ras.TRACE_WARNING, 'Failed to obtain href link from vea.entry') continue elem = vea.entry.element # Elements needed for import adapter_dict = {} adapter_dict['slot_num'] = elem.find('VirtualSlotNumber')\ .gettext() adapter_dict['mac_address'] = elem.find('MACAddress').gettext() adapter_dict['provider:segmentation_id'] = elem.find('PortVLANID')\ .gettext() adapter_dict['status'] = 'Available' adapter_dict['physical_network'] = 'default' k2_vswitch_id = elem.findtext('VirtualSwitchID') k2_vswitch = self._topo.vswitch_map.get(k2_vswitch_id) adapter_dict['vswitch'] = k2_vswitch.element.findtext('SwitchName') # Elements for internal disection adapter_dict['tagged'] = elem.find('TaggedVLANSupported').gettext() adapter_dict['is_veth'] = True qbg_type = elem.findtext('VirtualStationInterfaceTypeID') if qbg_type is not None and len(qbg_type) > 0: adapter_dict['is_qbg'] = True else: adapter_dict['is_qbg'] = False # Determine whether the adapter is orphaned orphan = False vlanid = int(adapter_dict['provider:segmentation_id']) pair = '%(vs)s:%(vlan)d' % {'vs': adapter_dict['vswitch'], 'vlan': vlanid} if pair in orphaned_pairs: orphan = True adapter_dict['is_orphan'] = orphan ret_adapter_list.append(adapter_dict) # Need to check for Host Ethernet Adapters... K2 has a bug in some # versions where we need to check for Port and Ports... s = './HostEthernetAdapterLogicalPort/HostEthernetAdapterLogicalPort' adpts = logical_partition.findall(s) s = './HostEthernetAdapterLogicalPorts/HostEthernetAdapterLogicalPort' adpts.extend(logical_partition.findall(s)) s = ('./PartitionIOConfiguration/ProfileIOSlots/ProfileIOSlot/' 'AssociatedIOSlot/RelatedIOAdapter') adpts.extend(logical_partition.findall(s)) if len(adpts) > 0: # Make a fake adapter...to get it to fail adapter_dict = {} adapter_dict['is_veth'] = False adapter_dict['addl_vlan_ids'] = [] adapter_dict['slot_num'] = -1 adapter_dict['lpar_id'] = lpar_id adapter_dict['mac_address'] = "" adapter_dict['provider:segmentation_id'] = -1 # Only need one adapter to tell this is bad. ret_adapter_list.append(adapter_dict) return ret_adapter_list
def _find_vlan_users(self, vios, vlanid, vswitch=None): """ This method will search for the given vlanid on the system and return two things. First, the pvid of the SEA on the VIOS containing the vlanid. Second, the number of users of that vlanid total (ie, client LPARs in addition to VIOS). :param vios: VIOS dom object we're operating on :param vlanid: VLANID to search for :param vswitch: vswitch name to associate with this vlanid :returns pvid: port vlanid of the SEA on the VIOS containing the vlanid. Will be 0 if not found. :returns num_users: Total number of adapters found with this vlanid. """ ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, "Enter") pvid = 0 num_users = 0 # Find the VIOS's VEA (if any) that has this vlanid configured on it. # Note that this is coming from the database, not the live system. # We assume the database is up to date and if we had a race condition # where two processes were unplugging the same vlanid (and this is # protected by a lock, so only one runs at a time) and the first guy # totally removed the vlanid from the system, the database would # have been updated and the second unplug will see no evidence of that # vlanid on the VIOS reflected in the database at this point. for vea in vios.get_all_virtual_ethernet_adapters(): if vea.is_vlan_configured(vlanid, vswitch): # Found a user of the vlanid num_users += 1 # Remember pvid of adapter containing vlanid pvid = vea.pvid break # Now, get all client lpar adapters to see if any of them have the # vlanid configured. This will be an actual K2 call to the HMC... # which means if there are a lot of LPARs, this will be SLOOOOWWW.... # Apparently this will be coming from the database at some point, so # we got that going for us. Note, we don't cache the LogicalPartition # K2Response because client LPARs come and go. ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, 'Getting LPARs') k2response = self._k2op.read( rootType='ManagedSystem', rootId=self._topo._find_managed_system(), childType='LogicalPartition', timeout=hmc.K2_READ_SEC, xag=[None]) ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, 'Got LPARs') # If we found no client LPARs, just return if not k2response.feed or not k2response.feed.entries: ras.trace(LOG, __name__, ras.TRACE_INFO, ras.msg('info', 'NO_CLIENT_LPAR') % self._topo.host_name) return pvid, num_users # For each LPAR for lpar in k2response.feed.entries: # Build a link to all the ClientNetworkAdapters. cna_links = lpar.element.findall('./ClientNetworkAdapters/link') # If there were some ClientNetworkAdapters if cna_links: # Get the link for the next K2 call. Just use the first # CNA link found because we're going to strip the UUID to get # all adapters in one K2 call anyways. href = cna_links[0].getattrib()['href'] # Strip the UUID href = href[0:href.rfind('/')] + '?group=None' # Get the adapters ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, 'Getting client adapters') k2_adapter_response = self._k2op.readbyhref( href=href, timeout=hmc.K2_READ_SEC) ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, 'Got client adapters') # Be sure we found some client adapters if not k2_adapter_response.feed or \ not k2_adapter_response.feed.entries: ras.trace(LOG, __name__, ras.TRACE_INFO, ras.msg('info', 'NO_CLIENT_ADAPTERS') % {'lpar': lpar.element.findtext('PartitionName'), 'lparid': lpar.element.findtext('PartitionID')}) # Move on to the next client lpar continue # Loop through all adapters and look for our vlanid for adapter in k2_adapter_response.feed.entries: # Get the client adapter's PVID client_pvid = adapter.element.findtext('PortVLANID') # If we found a pvid and it matches our vlanid if client_pvid and int(client_pvid) == vlanid: # Bump the users count num_users += 1 # I don't think we have additional vlans to worry about, # but just in case... addl_vlans = adapter.element.findtext('TaggedVLANIDs') # If we found some additional vlans if addl_vlans: # Make a string list addl_vlans = addl_vlans.split(',') # Now search for our vlanid. Our vlanid is an int, # so we use list comprehension to convert the list of # strings to a list of ints if vlanid in [str(x) for x in addl_vlans]: num_users += 1 return pvid, num_users
def _find_or_build_k2_vnet(self, k2_virt_nets, vlan_id, vswitch_id, tagged, force_tag_update=False): """ This method will find, and if not found - build, the appropriate K2 VirtualNetwork object for the provided input. :param k2_virt_nets: The K2 entity that has the feed of all the Virtual Networks in the system. :param vlan_id: The VLAN of the network. :param vswitch_id: The virtual switch within the system. This is the K2 ID (usually a number) for the vSwitch. :param tagged: Returns whether or not the network should be tagged. :param force_tag_update: If set to true, will force a tag network update """ for k2_virt_net in k2_virt_nets.feed.entries: k2_elem = k2_virt_net.element k2_vlan = k2_elem.findtext('NetworkVLANID') k2_vswitchid = k2_elem.findtext('VswitchID') if k2_vlan == str(vlan_id) and k2_vswitchid == vswitch_id: # We found the appropriate virtual network, however we need # to check that the tag is correct. If not, we need to update # the tag on the network. if force_tag_update: self._update_vnet_tag(k2_virt_net, tagged) # Simply return the update vnet return k2_virt_net # Didn't find it...try to build one attrs = [] vswitch_uri = utils.find_vswitch_uri_for_id(vswitch_id, self._topo.vswitch_map) attrs.append(k2.K2Element('AssociatedSwitch', attrib={'href': vswitch_uri, 'rel': 'related'})) vswitch_name = utils.find_vswitch_name_for_id(vswitch_id, self._topo.vswitch_map) # Network name has some constraints... net_name = '%(vlan)d-%(vswitch)s' % {'vlan': vlan_id, 'vswitch': vswitch_name} net_name = net_name.replace('(Default)', '') attrs.append(k2.K2Element('NetworkName', text=net_name)) attrs.append(k2.K2Element('NetworkVLANID', text=str(vlan_id))) attrs.append(k2.K2Element('TaggedNetwork', text=str(tagged).lower())) # Create the element... new_vnet = k2.K2Element('VirtualNetwork', attrib={'schemaVersion': 'V1_0'}, children=attrs) ras.trace(LOG, __name__, ras.TRACE_DEBUG, 'Creating vnet %s' % net_name) self._k2op.create(element=new_vnet, rootType='ManagedSystem', rootId=self._topo._find_managed_system(), childType='VirtualNetwork', timeout=hmc.K2_WRITE_SEC) ras.trace(LOG, __name__, ras.TRACE_DEBUG, 'Created vnet %s' % net_name) # Recurse to find it now ras.trace(LOG, __name__, ras.TRACE_DEBUG, 'Getting ManagedSystem/VirtualNetwork') k2_virt_nets = self._k2op.read( rootType='ManagedSystem', rootId=self._topo._find_managed_system(), childType='VirtualNetwork', timeout=hmc.K2_READ_SEC, xag=[None]) ras.trace(LOG, __name__, ras.TRACE_DEBUG, 'Got ManagedSystem/VirtualNetwork') return self._find_or_build_k2_vnet(k2_virt_nets, vlan_id, vswitch_id, tagged)
def _populate_adapters_into_vios(self, vios, dom_factory=model.No_DB_DOM_Factory()): """ This method will populate the given VIOS with all the adapters, both SEA and VEA, found on that VIOS. :param vios: VioServer to fetch adapters from :param dom_factory: Factory used to create the DOM objects, optional. :returns boolean: True if at least one SEA was found, False otherwise. """ # Now populate the VIOS information # If the VIOS RMC state is down, we can't use adapters on it. curr_state = vios.rmc_state.lower() if curr_state != 'active': # send notification to UI if RMC is in a busy state # and notification hasn't been sent during the # interval specified. if curr_state == 'busy' and CONF.send_rmc_busy_message: curr_time = time.time() send_interval = 3600 # 60 minutes if((curr_time - IBMPowerVMNetworkTopoHMC.last_rmc_busy_notification) > send_interval): IBMPowerVMNetworkTopoHMC.last_rmc_busy_notification = \ curr_time payload = {} payload['msg'] = _('The RMC for %(vio)s on %(host)s has ' 'a status code of busy. One reason ' 'for this can be the incorrect sizing ' 'of the VIOS. Refer to the IBM PowerVM ' 'Best Practices red book to ensure ' 'that the VIOS has the appropriate set ' 'of resources to service the ' 'requests.') \ % {'vio': vios.name, 'host': CONF.host_display_name} notifier = rpc.get_notifier(service='compute', host=CONF.host) notifier.warn(ctx.get_admin_context(), 'compute.instance.log', payload) ras.trace(LOG, __name__, ras.TRACE_WARNING, _('RMC state is not active on VIOS lpar %s') % vios.lpar_name) return False # If we found NO VEAs, then we can't proceed. An SEA backed by # no VEA is useless. if not utils.build_veas_from_K2_vios_response(self.k2_vios_resp, vios, self.vswitch_map, self.operator, dom_factory): ras.trace(LOG, __name__, ras.TRACE_WARNING, ras.vif_get_msg('info', 'VIOS_NOVEA')) return False # If we find at least one SEA, we're successful. NOTE: It may # seem like we're building duplicate VEAs into the VIOS with the # call below since we already built them with the call above. # This is ok because the VioServer object will filter out # duplicates. It's necessary to do the first build above because # that's the only way we'll find orphaned VEAs. if utils.build_seas_from_K2_response(self.k2_vios_resp, vios, self.k2_net_bridge_resp, self.vswitch_map, self.operator, dom_factory): ras.trace(LOG, __name__, ras.TRACE_DEBUG, ras.vif_get_msg('info', 'FOUND_SEAS') % {'num_seas': len(vios.get_shared_ethernet_adapters()), 'vios_name': vios.name}) return True else: # Found no SEAs... this means the VIOS is not usable for deploy. ras.trace(LOG, __name__, ras.TRACE_WARNING, ras.vif_get_msg('error', 'VIOS_NOSEA')) return False
def _get_all_vios(self, dom_factory=model.No_DB_DOM_Factory()): """ This method will return all VIOSes available on the current host (as identified in the operator). :param dom_factory: Factory used to create the DOM objects, optional. :returns vioses: A list of VioServer objects """ # Get the system we are managing managed_system_uuid = self._find_managed_system() # Clear out the data self.vio_server_map = {} self._repopulate_vswitch_data() # Move on to VIOS info. Start with an empty list vios_list = [] # Get all the VIOSes on the HMC. The response will contain all the # info we need for adapters, so save it off so we don't have to # make unnecessary K2 calls later on. ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, 'Getting VIOS') self.k2_vios_resp = self.operator.read(rootType='ManagedSystem', rootId=managed_system_uuid, childType='VirtualIOServer', timeout=hmc.K2_RMC_READ_SEC, xag=[k2const.VIOS_NET_EXT_PROP], age=self.read_age) ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, 'Got VIOS') # Get the network bridges ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, 'Getting Network Bridges') self.k2_net_bridge_resp = self.operator.read( rootType='ManagedSystem', rootId=managed_system_uuid, childType='NetworkBridge', timeout=hmc.K2_RMC_READ_SEC, age=self.read_age) ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, 'Got Network Bridges') # If we find no VIOS, just return if not self.k2_vios_resp.feed or not self.k2_vios_resp.feed.entries: ras.trace(LOG, __name__, ras.TRACE_DEBUG, ras.vif_get_msg('error', 'VIOS_NONE') % self.host_name) return vios_list # Loop through all VIOSes found for entry in self.k2_vios_resp.feed.entries: # Grab the necessary attributes lpar_id = int(entry.element.findtext('PartitionID')) lpar_name = entry.element.findtext('PartitionName') state = entry.element.findtext('PartitionState') rmc_state = entry.element.findtext('ResourceMonitoring' 'ControlState') # If RMC is down, we want to log why. Could be helpful down the # road... if rmc_state is None or rmc_state.lower() != 'active': LOG.warn(_('K2 RMC state for lpar %(lpid)d (%(lname)s): ' '%(state)s') % {'lpid': lpar_id, 'lname': lpar_name, 'state': rmc_state}) data = self.k2_vios_resp.body LOG.warn(_('K2Response: %(resp)s') % {'resp': data}) # Add the data to the map self.vio_server_map[lpar_id] = entry.properties['link'] # Create a VIOS DOM object vios = dom_factory.create_vios(lpar_name=lpar_name, lpar_id=lpar_id, host_name=self.host_name, state=state, rmc_state=rmc_state) vios_list.append(vios) ras.trace(LOG, __name__, ras.TRACE_DEBUG, ras.vif_get_msg('info', 'FOUND_VIOS') % {'lpar_id': lpar_id, 'lpar_name': lpar_name}) return vios_list