Beispiel #1
0
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
Beispiel #2
0
    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
Beispiel #3
0
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
Beispiel #4
0
    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