示例#1
0
文件: utils.py 项目: windskyer/k_nova
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
示例#2
0
    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
示例#3
0
    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)
示例#4
0
文件: utils.py 项目: windskyer/k_nova
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
示例#5
0
文件: utils.py 项目: windskyer/k_nova
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
示例#6
0
文件: utils.py 项目: windskyer/k_nova
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
示例#7
0
文件: utils.py 项目: windskyer/k_nova
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
示例#8
0
文件: utils.py 项目: windskyer/k_nova
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
示例#9
0
    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
示例#10
0
    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
示例#11
0
    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)
示例#12
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
示例#13
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