Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
def log_k2ex_and_get_msg(ex, prefix, topology):
    """ LOG K2 exception and extracted message. Return NLS message """
    LOG.exception(ex)
    detail = {}
    k2msg = _("None")
    if isinstance(ex, K2Error) and ex.k2response:
        detail['Request_headers'] = ex.k2response.reqheaders
        detail['Response_headers'] = ex.k2response.headers
        detail['Response_body'] = ex.k2response.body
        detail['Response_status'] = ex.k2response.status
        if hasattr(ex.k2response, 'k2err'):
            m = ex.k2response.k2err.find('./Message')
            if m is not None:
                k2msg = m.text
    msg = _("%(prefix)s ***K2 Operator Error***: %(ex_msg)s  [K2 Error body "
            "Message: %(k2msg)s]") %\
        dict(prefix=prefix, ex_msg=ex, k2msg=k2msg)
    LOG.error(msg)
    if detail:
        LOG.error(_("Error details: %s") % detail)
    if topology is not None:
        if 'error' in topology:
            topology['error'].append(msg)
        else:
            topology['error'] = [msg]
    return msg
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
def get_vios_info(vios_entry):
    """
    Get the specific data for the VIOS from the K2 VIOS entry.
    """
    # Initialize the empty dictionary.
    vios_info = {}
    if not vios_entry:
        LOG.warn(_("No Virtual I/O Servers returned in HMC response."))
        return vios_info

    vios_info['k2element'] = vios_entry  # track for later logging
    # Get the Partition Name Element
    partitionNameElement = \
        vios_entry.element.find('./PartitionName')
    # If the Partition Name element exists
    if partitionNameElement is not None:
        # Save the partition name into the vios info object.
        vios_info['name'] = partitionNameElement.gettext()
    else:
        vios_info['name'] = None

    vios_info['uuid'] = uuid = vios_entry.properties['id']
    LOG.debug("Processing VIOS partition '%s' with uuid: %s" %
              (vios_info['name'], uuid))
    #Get the Partition State Element
    partitionStateElement = \
        vios_entry.element.find('./PartitionState')

    if partitionStateElement is not None:
        #Save the partition State into the vios info object.
        vios_info['state'] = partitionStateElement.gettext()

    #Get the RMC State Element
    RMCStateElement = \
        vios_entry.element.find('./ResourceMonitoringControlState')

    if RMCStateElement is not None:
        #Save the RMC State into the vios info object.
        vios_info['rmc_state'] = RMCStateElement.gettext()

    # Get the Partition ID Element.
    partitionIDElement = vios_entry.element.find('./PartitionID')
    # If the partition ID Element exists
    if partitionIDElement is not None:
        # Save the partition id to the vios info object.
        vios_info['lpar_id'] = partitionIDElement.gettext()

        # For each VIOS, also call the helper method to extract
        # the FC Port info from call already done.
        LOG.debug("Getting FC ports for vios '%s'." % uuid)
        vios_info['fcports'] = parse_fcports(vios_entry, vios_info)
    else:
        LOG.warn(_("HMC Problem: No PartitionID element for VIOS '%s'.") %
                 uuid)

    return vios_info
Ejemplo n.º 5
0
    def execute(self):
        """
        Overrides parent method.

        Restarts networking on the host endpoint to pick up configuration
        changes. Checks and starts neutron-openvswitch-agent if it is not
        running already on host.
        """
        LOG.info(_("Running 'systemctl restart network.service' on host."))
        self.commandex.send_network_restart()
        LOG.info(_("Running 'systemctl restart " "neutron-openvswitch-agent.service' on host."))
        self.commandex.restart_neutron_agent()
Ejemplo n.º 6
0
    def execute(self):
        """
        Overrides parent method.

        Will throw an error if the ping to the Qpid server fails.  If it
        succeeds this method does nothing.
        """
        LOG.info(_("Attempting to ping the Qpid Server"))
        if self.rollback:
            LOG.error(_("Rollback due to API parameter."))
            raise exception.QpidPingFailure(timeout="0")
        adapter = self.dom_obj_converter.find_management_adapter()
        if adapter is None:
            LOG.error(_("Failed to ping the Qpid Server."))
            raise exception.QpidPingFailure(timeout="1")
Ejemplo n.º 7
0
    def _gen_ovs_port_name(self, desired_name, host_obj):
        """
        Typically an OVSPort is named the same as the component it contains,
        however there be cases where this name is already taken.  This function
        handles generating an OVSPort name if needed.

        :param desired_name: The desired name for the OVSPort, typically this
                             is the name of the component contained by the
                             OVSPort.
        :param host_obj: A host KVM DOM object to search for existing ports.
        :returns: A string that can be used as an OVSPort name.
        """
        if not desired_name:
            desired_name = 'pvc-ovs-port'

        # Check to see if the desired name can be used
        if not self._does_ovs_port_exist(desired_name, host_obj):
            return desired_name

        # Increment a number after the desired name until a spot is found
        for i in range(0, 100000):
            name = desired_name + '-' + str(i)
            if not self._does_ovs_port_exist(name, host_obj):
                return name

        # Something is wrong, thousands of OVSPorts with this name exist.
        LOG.error(_('Failed to generate OVSPort name from desired_name %s') %
                  desired_name)
        return ''
Ejemplo n.º 8
0
def get_scg_by_id(context, scg_id):
    """
    Look up storage connectivity group by id.
    :param context: A context object that is used to authorize
            any DB access.
    :param scg_id: The 'id' of the storage connectivity group to lookup.
    :returns: The SCG object looked up. Otherwise an error is raised.
    """
    # DB facing logic comes next.
    # Now construct and use a transaction.
    scg_factory = storage_dom.StorageConnectivityGroupFactory.get_factory()
    txn = scg_factory.get_resource_transaction()
    with txn.begin(subtransactions=True):
        scg = None
        try:
            scg = scg_factory.find_scg_by_id(context, scg_id, transaction=txn)
        except Exception as e:
            LOG.exception(e)
            LOG.error(_("Exception trying to find a storage connectivity group"
                      " using resource id = %s") % scg_id)

        if scg is None:
            msg = stgex.IBMPowerVCSCGNotFound.msg_fmt % locals()
            ex = stgex.IBMPowerVCSCGNotFound(msg)
            LOG.exception(ex)
            raise ex
        scg_dict = scg.to_dict(context=context, transaction=txn)
        # Since to_dict() is called within the transaction,
        # the hydrated dictionary will be cached on the scg object
        # and future references to it will have the host_list
        # nested dictionary data.
        LOG.debug("Looked up SCG: %s" % scg_dict)
    return scg
Ejemplo n.º 9
0
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
Ejemplo n.º 10
0
def get_compute_nodes_from_DB(context, msg_dict=None):
    """
    This returns a list of compute nodes after querying the Nova DB.

    :param context: A context object that is used to authorize
                    the DB access.
    :returns: A list of compute nodes that are in service
    """
    context = context.elevated()  # What is the purpose of elevation?
    compute_nodes = nova_db.compute_node_get_all(context)
    return_nodes = []
    for compute in compute_nodes:
        service = compute['service']
        if not service:
            msg = _("No service entry for compute ID %s.") % compute['id']
            LOG.warn(msg)
            if msg_dict:
                msg_dict['messages'].append(msg)
            continue
        return_nodes.append(service["host"])
        #  host_to_send = {'db_id': compute['id'],
        #                  'host_name': service['host'],
        #                  'hyp_hostname': compute['hypervisor_hostname']}
    LOG.debug("db_hosts: %s" % return_nodes)
    return return_nodes
Ejemplo n.º 11
0
def http_error_if_ivm():
    host_types = get_supported_host_types()
    mgr_type = CONF.powervm_mgr_type.lower()
    if mgr_type == 'ivm' and 'kvm' not in host_types:
        msg = _("Storage connectivity group based requests are not "
                "supported for PowerVC Express installations (IVM mode).")
        raise exc.HTTPBadRequest(explanation=six.text_type(msg))
Ejemplo n.º 12
0
    def _update_port_remove_pass(self, current_ovs, desired_ovs):
        """
        Determines the micro ops to run for the update port flow, where we are
        removing ports from a given vSwitch.

        :param current_ovs: The current systems Open vSwitch DOM (single
                            vswitch)
        :param desired_ovs: The Open vSwitch DOM for a single vSwitch that the
                            user passed in, which represents what the desired
                            final state will be.
        :return: The micro ops that should be run to delete the desired ports
                 on the vSwitch.
        """

        # Sort the OVS ports into lists based on desired action
        ports_to_delete = self._get_ports_to_delete(current_ovs, desired_ovs)

        micro_op_list = []

        # Remove any ports from the vswitch that are no longer desired.
        for port in ports_to_delete:
            LOG.info(_('Remove port operation for Virtual Switch %(vswitch)s '
                       'and port %(port)s.' %
                       {'vswitch': current_ovs.name,
                        'port': port.name}))
            op = ovs_port_remove.OvsPortRemove(current_ovs.name, port.name)
            micro_op_list.append(op)

        return micro_op_list
Ejemplo n.º 13
0
def _find_managed_system(oper, host_dict):
    """
    Finds the ManagedSystem entry for this specific host that the HMC is
    managing.

    :param oper: The HMC operator for interacting with the HMC.
    :param host_dict: has the machine, model, and serial info for
                      managed system to look up
    :return: The K2 object for the managed system
    """
    # Get the ManagedSystem entry we want by Machine type, model, and serial
    # from the K2 API. We use the 'search' suffix to achieve this.
    k2resp = None
    try:
        suffix = '(MachineType==%s&&Model==%s&&SerialNumber==%s)' % \
            (host_dict['machine'], host_dict['model'], host_dict['serial'])
        k2resp = k2_read(oper, 'ManagedSystem', suffixType='search',
                         suffixParm=suffix, timeout=K2_MNG_SYS_READ_SEC,
                         xag=XAG_DEFAULT)
    except Exception as ex:
        LOG.exception(ex)

    if k2resp is None:
        LOG.error(_("Managed System K2 response was none or failed."))
        return None

    xpath = './MachineTypeModelAndSerialNumber/SerialNumber'
    entries = k2resp.feed.findentries(xpath, host_dict['serial'])
    if entries is None:
        LOG.warn(_("Managed System HMC response did not have any entries "
                   "for host '%s'.") % host_dict)
        return None

    # Confirm same model and type
    machine_xpath = './MachineTypeModelAndSerialNumber/MachineType'
    model_xpath = './MachineTypeModelAndSerialNumber/Model'
    for entry in entries:
        entry_machine = entry.element.findtext(machine_xpath)
        entry_model = entry.element.findtext(model_xpath)
        if (entry_machine == host_dict['machine'] and
                entry_model == host_dict['model']):
            host_dict['uuid'] = entry.properties['id']
            return entry
    LOG.warn(_("Managed System HMC response did not have an 'entry' "
               "element for host '%s'.") % host_dict)
    return None
Ejemplo n.º 14
0
    def undo(self):
        """
        Overrides parent method.

        Undoing a restart isn't really possible.
        """
        LOG.info(_("Running undo 'service restart network.service' on host."))
        self.commandex.send_network_restart()
Ejemplo n.º 15
0
    def _update_port_update_pass(self, current_ovs, desired_ovs):
        """
        Determines the micro ops to run for the update port flow, where we are
        modifying (but not adding/removing) ports to a given vSwitch.

        :param current_ovs: The current systems Open vSwitch DOM (single
                            vswitch)
        :param desired_ovs: The Open vSwitch DOM for a single vSwitch that the
                            user passed in, which represents what the desired
                            final state will be.
        :return: The micro ops that should be run to update the desired ports
                 on the vSwitch.
        """
        micro_op_list = []
        prev_voted_ports = []

        # Determine which ports have changes...
        for desired_port in desired_ovs.ovs_port_list:
            current_port = self._find_ovs_port_by_voting(
                desired_port.name,
                desired_port.port_list,
                current_ovs.ovs_port_list,
                prev_voted_ports)
            if current_port:
                prev_voted_ports.append(current_port)
                # The desired port already exists, check for changes
                if desired_port != current_port:
                    pt_names = []
                    for port in desired_port.port_list:
                        # if we are trying to add a linux bridge,
                        # we need to remove ports from bridge to
                        # add directly to vswitch
                        is_bridge = isinstance(port, dom_kvm.LinuxBridge)
                        if is_bridge:
                            op = move_bridge_ports.\
                                MoveBridgePorts(port.name)
                            micro_op_list.append(op)
                            # need to add micro op to move ip address
                            # from bridge to the vswitch
                            op = move_ip_address.MoveIpAddress(
                                port.name, desired_ovs.name)
                            micro_op_list.append(op)
                            for bridge_port in port.port_list:
                                pt_names.append(bridge_port.name)
                        else:
                            pt_names.append(port.name)
                    op = ovs_port_update.OvsPortUpdate(current_ovs.name,
                                                       current_port.name,
                                                       desired_port.name,
                                                       pt_names)
                    micro_op_list.append(op)
                    LOG.info(_('Update port operation for Virtual Switch '
                               '%(vswitch)s and port %(port)s.' %
                               {'vswitch': current_ovs.name,
                                'port': current_port.name}))

        return micro_op_list
Ejemplo n.º 16
0
    def validate(self, current_dom):
        """
        No validation required.

        :param current_dom: State of the system prior to running
        :returns updated_dom: State of the system post running
        :returns warning_list: List of warnings that were found during
                               validation
        """
        LOG.info(_("Validating if a network restart can be performed"))
        return current_dom, [warning.OVSPortModificationVMActionWarning()]
Ejemplo n.º 17
0
    def validate(self, current_dom):
        """
        No validation required.

        :param current_dom: State of the system prior to running
        :returns updated_dom: State of the system post running
        :returns warning_list: List of warnings that were found during
                               validation
        """
        LOG.info(_("Validating if a ping to Qpid server can be "
                   "performed"))
        return current_dom, []
Ejemplo n.º 18
0
    def update_host_ovs(self, context):
        """update host ovs data on current host"""
        LOG.info(_('Updating Open vSwitch host data...'))
        LOG.debug("Current DOM: %s" % self.current_dom.to_dict())
        LOG.debug("Requested DOM: %s" % self.desired_dom.to_dict())

        builder = mob.MicroOperationBuilder(context,
                                            self.current_dom,
                                            self.desired_dom,
                                            self.rollback)

        mo_list = builder.get_micro_ops_for_update()

        # run validation
        return self._run_micro_op_list(mo_list)
Ejemplo n.º 19
0
def cleanup_ovs_tap_ports():
    """
    This method will be periodically invoked to cleans up orphaned OVS tap
    ports.  This prevents Neutron from filling up the logs (and eventually the
    disk) with warnings about the orphaned OVS ports.
    """
    LOG.debug('Entry: OVS TAP port cleanup task')

    # Create command runner
    commandex = commandlet.CommandExecutor

    # Get a list of all OVS ports on the integration bridge
    args = ['list-ports', CONF.integration_bridge]
    result = commandex.run_vsctl(args, check_error=True)
    port_names = []
    if result:
        port_names = result.strip().split('\n')

    # Dump all OVS data with JSON formatting and OpenStack OVS agent data
    args = ['--format=json', '--', '--columns=name,external_ids,ofport',
            'list', 'Interface']
    result = commandex.run_vsctl(args, check_error=True)
    if not result:
        return

    # Parse JSON data into one row per OVS port
    for row in jsonutils.loads(result)['data']:
        # Verify we're looking at a port on the integration bridge
        name = row[0]
        if name not in port_names:
            continue

        # Check the status of the port
        ofport = row[2]
        try:
            int_ofport = int(ofport)
        except (ValueError, TypeError):
            # The status is not an integer, just continue
            continue
        else:
            # A status of 0 or negative means there is a problem
            if int_ofport <= 0:
                LOG.info(_('Deleting openvswitch port: %s'), row)
                args = ['--', '--if-exists', 'del-port',
                        CONF.integration_bridge, name]
                commandex.run_vsctl(args, check_error=True)

    LOG.debug('Exit: OVS TAP port cleanup task')
Ejemplo n.º 20
0
def is_rmc_state_allowed(vios_ref, rmc_state):
    """ Use this helper method to return True if the RMC state of a
        VIOS is one of the allowed states that will not prevent a VIOS
        from being flagged as storage-ready for SCGs. Not hanging this
        method off the storage VIOS DOM yet as it can be used with live
        K2 data in addition to DB values.

        Current impl accepts ['active', 'busy']
        A busy state may mean that a VIOS is not ready for storage
        connectivity, but that will be determined at attach time rather
        than when an SCG is evaluated through public APIs.
    """
    if rmc_state == 'busy':
        LOG.info(_("The Virtual I/O Server '%(vios)s' has an RMC state of "
                   "'busy', which may impact its connectivity capability "
                   "for storage operations.") % dict(vios=vios_ref))
    return (rmc_state in ['active', 'busy'])
Ejemplo n.º 21
0
    def _is_cec_running(self):
        """
        Will return if the CEC is up.
        """
        k2_mg_sys = self._find_k2_managed_system()
        state_elem = k2_mg_sys.element.find('State')
        if state_elem is None:
            LOG.info(_("State is not found.  Assuming CEC is powered off."))
            return False

        # It *should* always be a K2 element, and if so, get the actual state
        # off of it
        if isinstance(state_elem, k2.K2Element):
            state_elem = state_elem.gettext()

        state = (state_elem.lower() in ('operating', 'standby'))
        LOG.debug("State of the system is %s" % state_elem)
        return state
Ejemplo n.º 22
0
def get_fcport_by_id(context, transaction, fc_id):
    """
    Look up fc port by id.
    :param context: A context object that is used to authorize
            any DB access.
    :param fc_id: The 'udid' of the fc port to lookup.
    :returns: The fc port object looked up. Otherwise an error is raised.
    """

    # Regular DB facing logic comes next.
    # Now construct and use a transaction.
    LOG.debug("Look for FC port with id: %s" % fc_id)
    fcport_factory = storage_dom.FcPortFactory.get_factory()
    fcport = fcport_factory.find_fcport_by_id(context, fc_id,
                                              transaction=transaction)
    if fcport is None:
        LOG.error(_("Did not find an FC port with id: %s" % fc_id))
        msg = stgex.IBMPowerVCFCPortNotFound.msg_fmt % locals()
        ex = stgex.IBMPowerVCFCPortNotFound(msg)
        LOG.exception(ex)
        raise ex
    return fcport
Ejemplo n.º 23
0
def cluster_registration_verification(oper):
    """Method to verify the HMC level is good for cluster reg. support"""
    if not CONF.ibmpowervm_ssp_hmc_version_check:
        return True
    else:
        try:
            #Get the ManagementConsole information from the K2 API.
            mc_info = oper.read('ManagementConsole')
            #Parse the feed for the HMC version info
            ver_info = mc_info.feed.entries[0].element.find('VersionInfo')
            #Get the maintenance number from the version info
            maintenance = ver_info.findtext('Maintenance')
            #Get the minor number from the version info
            minor = ver_info.findtext('Minor')
            #Get the version number from the version info
            version = ver_info.findtext('Version')
            #Combine to get the HMC release version
            release = version + maintenance + minor
            LOG.info(_("Management Console release is '%s'.") % release)
            return int(release) >= 810
        except Exception as exc:
            LOG.exception(exc)
            LOG.error("There was an error getting the HMC release version")
            return True
Ejemplo n.º 24
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
Ejemplo n.º 25
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
Ejemplo n.º 26
0
    def get_micro_ops_for_update(self):
        """
        Determines the list of micro ops need to transform the current DOM into
        the desired DOM for an HTTP PUT operation, or an "update".  This will
        not create or delete vswitches, but it will update the configuration
        of a vswitch by adding, removing or changing vswitch ports.

        :returns micro_op_list: A list of MicroOperation objects.
        """

        LOG.info(_('Network micro operations builder for network is '
                   'starting.'))

        # Update ports for each vswitch.  Each pass runs against all vSwitches.
        # The first pass is all remove operations.  Followed by update (which
        # may add or remove).  Finally it runs the add pass.

        micro_op_list = []

        # do preliminary validation of each ovs in desired dom
        for ovs in self.desired_dom.ovs_list:
            LOG.info(_('Adding beginning Virtual Switch validate to operation '
                       'list for Virtual Switch %s.' % ovs.name))
            op = beginning_vswitch_validator.\
                BeginningVswitchValidator(ovs.name, self.desired_dom)
            micro_op_list.append(op)

        micro_op_list.extend(self._update_pass(self.current_dom,
                                               self.desired_dom,
                                               self._update_port_remove_pass))
        micro_op_list.extend(self._update_pass(self.current_dom,
                                               self.desired_dom,
                                               self._update_port_update_pass))
        micro_op_list.extend(self._update_pass(self.current_dom,
                                               self.desired_dom,
                                               self._update_port_add_pass))

        # Add any needed micro ops to the end of the op list
        if len(micro_op_list) > 0:
            # If ports were changed, a service network restart is needed
            # as well as end user warnings
            restart = False
            ovs_list = []
            for op in micro_op_list:
                if(isinstance(op, ovs_port_add.OvsPortAdd) or
                   isinstance(op, ovs_port_remove.OvsPortRemove) or
                   isinstance(op, ovs_port_update.OvsPortUpdate)):
                    ovs_list.append(op.ovs_name)
                    restart = True

            if restart:
                LOG.info(_('Adding service network restart to operation '
                           'list.'))
                op = service_network_restart.ServiceNetworkRestart()
                micro_op_list.append(op)
                op = management_host_ping.PingQpid(self.context, self.rollback)
                micro_op_list.append(op)

            # Add a validator for general OVSPort change warnings
            for ovs_name in set(ovs_list):
                op = ovs_port_warn_add_remove.OvsPortWarnAddRemove(ovs_name)
                micro_op_list.append(op)

            # Validate that each vswitch has a valid config
            for ovs in self.desired_dom.ovs_list:
                LOG.info(_('Adding end Virtual Switch validate to operation '
                           'list for Virtual Switch %s.' % ovs.name))
                op = end_vswitch_validator.EndVswitchValidator(ovs.name)
                micro_op_list.append(op)

        return micro_op_list
Ejemplo n.º 27
0
    def _update_port_add_pass(self, current_ovs, desired_ovs):
        """
        Determines the micro ops to run for the update port flow, where we are
        adding ports to a given vSwitch.

        :param current_ovs: The current systems Open vSwitch DOM (single
                            vswitch)
        :param desired_ovs: The Open vSwitch DOM for a single vSwitch that the
                            user passed in, which represents what the desired
                            final state will be.
        :return: The micro ops that should be run to add the desired ports
                 to the vSwitch.
        """
        micro_op_list = []
        prev_voted_ports = []

        # Find ports to create
        ports_to_create = {}
        for desired_port in desired_ovs.ovs_port_list:
            ovs_port = self._find_ovs_port_by_voting(desired_port.name,
                                                     desired_port.port_list,
                                                     current_ovs.ovs_port_list,
                                                     prev_voted_ports)
            if not ovs_port and desired_port and desired_port.name:
                cmp_list = []
                for port in desired_port.port_list:
                    # if we are trying to add a linux bridge,
                    # we need to remove ports from bridge to
                    # add directly to vswitch
                    is_bridge = isinstance(port, dom_kvm.LinuxBridge)
                    if is_bridge:
                        op = move_bridge_ports.MoveBridgePorts(port.name)
                        micro_op_list.append(op)
                        # need to add micro op to move ip address
                        # from bridge to the vswitch
                        op = move_ip_address.MoveIpAddress(port.name,
                                                           desired_ovs.name)
                        micro_op_list.append(op)

                        # Since the request came in to add all the bridge ports
                        # to this port, rather than break them out into unique
                        # OVS ports (like one may expect) we add them into
                        # the bonded port.
                        #
                        # This is safer so as not to create loops.
                        for bridge_port in port.port_list:
                            cmp_list.append(bridge_port.name)
                    else:
                        cmp_list.append(port.name)

                if len(cmp_list) > 0:
                    ports_to_create[desired_port.name] = cmp_list
            elif ovs_port:
                prev_voted_ports.append(ovs_port)

        # Add new ports to the vswitch.
        for port in ports_to_create:
            LOG.info(_('Add port operation for Virtual Switch %(vswitch)s '
                       'and port %(port)s.' %
                       {'vswitch': current_ovs.name, 'port': port}))
            cmp_names = []
            for comp in ports_to_create[port]:
                cmp_names.append(comp)
            op = ovs_port_add.OvsPortAdd(current_ovs.name, port, cmp_names)
            micro_op_list.append(op)

        return micro_op_list
Ejemplo n.º 28
0
    def _run_micro_op_list(self, mo_list):
        """
        Run validation and, if force_flag is true or no warnings, run
        execute.  Any errors encountered during execute will result in
        an undo call, in reverse order, on all previously executed
        micro ops.
        :param mo_list: A list of all micro ops needed to run the
                        desired operation.  This list should be
                        generated by the micro ops builder.
        :returns: A dictionary containing all warnings and errors
                    encountered during the running of the micro ops.

        """
        current_dom = copy.deepcopy(self.current_dom)
        warning_list = []
        return_dict = {}
        ifcfgs = ''
        ovsvsctl_show = {}

        # always run validation, even if force flag is
        # set to True to make sure there are no errors
        # encountered.
        ops_ran_list = []
        for micro_op in mo_list:
            try:
                ops_ran_list.append(micro_op.__class__.__name__)
                LOG.debug("running micro op %s with DOM %s" %
                          (micro_op.__class__,
                           current_dom))
                current_dom, curr_warning_list = \
                    micro_op.validate(current_dom)
                warning_list.extend(curr_warning_list)
                for warning in curr_warning_list:
                    LOG.warn(_('Warning "%(warn_name)s" occurred during '
                               'validation of operation %(oper)s: %(warn)s') %
                             {'warn_name': warning.name,
                              'oper': micro_op.__class__.__name__,
                              'warn': warning})
            except Exception as exc:
                LOG.exception(exc)
                LOG.error(_("List of operations run: %s" % ops_ran_list))
                return_dict[agent.ERRORS_KEY] = [{'message': '%s' % exc}]
                break

        # if the force flag is set we can ignore warnings but
        # we cannot avoid errors, so check to be sure there
        # were no errors
        ops_ran_list = []

        if((self.force_flag or len(warning_list) == 0)
           and agent.ERRORS_KEY not in return_dict):

            # in case of error, last_index is used to determine
            # where to start undo from
            last_index = -1

            # execute micro op list
            for i in range(0, len(mo_list)):
                try:
                    ops_ran_list.append(mo_list[i].__class__.__name__)
                    mo_list[i].execute()
                except Exception as exc:
                    LOG.exception(exc)
                    LOG.error(_("List of operations run: %s" % ops_ran_list))
                    return_dict[agent.ERRORS_KEY] = [{'message': "%s" % exc}]
                    last_index = i
                    break

            # do we need to undo because of error?
            if last_index != -1:
                LOG.error(_("Error during operation execution, undoing "
                            "operations..."))

                # Get the current state of the ifcfg files and ovs to log later
                try:
                    ifcfgs = commandlet.CommandExecutor.\
                        get_all_ifcfg_files_for_logging()
                    ovsvsctl_show = \
                        commandlet.CommandExecutor.send_vsctl_command()
                except Exception as e:
                    LOG.exception(e)

                undo_list = []
                # yes, undo needed; undo in reverse order
                reversed_list = self._reorder_ops_for_undo(mo_list,
                                                           last_index)
                for op in reversed_list:
                    try:
                        op.undo()
                        undo_list.append(op.__class__.__name__)
                    except Exception as exc:
                        # if we hit an error during undo, we will
                        # add the error to the error list and continue
                        # to attempt to undo the remaining micro ops
                        LOG.exception(exc)
                        return_dict[agent.ERRORS_KEY].append(
                            {'message': '%s' % exc})

                LOG.error(_("Undone operations: %s" % undo_list))

        # we are not doing an execution, so return the warnings
        else:
            # add warnings to return list
            if len(warning_list) > 0:
                return_dict[agent.WARNINGS_KEY] = []
                for warning in warning_list:
                    return_dict[agent.WARNINGS_KEY].append(
                        {'message': '%s' % warning})

        # Errors/warnings occurred.  Log initial dom, request dom, the dom as
        # it was when the error occurred, operations run, ifcfg files, and
        # ovs-vsctl show output
        if return_dict is not {}:
            debug_info_list = []
            debug_info_list.append(_('Initial Object Model is:'))
            debug_info_list.append(json.dumps(self.current_dom.to_dict(),
                                              sort_keys=True, indent=4))
            debug_info_list.append(_('Requested Object Model is:'))
            debug_info_list.append(json.dumps(self.desired_dom.to_dict(),
                                              sort_keys=True, indent=4))
            debug_info_list.append(_('Current Object Model is:'))
            debug_info_list.append(json.dumps(current_dom.to_dict(),
                                              sort_keys=True, indent=4))
            debug_info_list.append(_("List of operations returned by builder: "
                                     "%s" % [mo_list[i].__class__.__name__
                                             for i in range(0, len(mo_list))]))
            if ifcfgs:
                # These are only logged on errors, not on warnings
                debug_info_list.append(_("Contents of ifcfg files: %s" %
                                         ifcfgs))
                debug_info_list.append(_("ovs-vsctl show: "))
                debug_info_list.append(json.dumps(ovsvsctl_show,
                                                  sort_keys=True,
                                                  indent=4))

            if agent.ERRORS_KEY in return_dict:
                for message in debug_info_list:
                    LOG.error(message)
            else:
                for message in debug_info_list:
                    LOG.warn(message)

        return return_dict
Ejemplo n.º 29
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
Ejemplo n.º 30
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