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 _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 _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 _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