Пример #1
0
def _remove_sea(db_sea, db_vio_server, context, db_session):
    """
    Will remove a SharedEthernetAdapter from the database.

    :param db_sea: The DOM object that represents the SharedEthernetAdapter
                   to remove from the database.
    :param db_vio_server: The VioServer that represents the corresponding
                          VioServer for this object.
    :param context: The context for the operations
    :param db_session: The database session to use for this transaction
    """
    msg = (ras.vif_get_msg('info', 'RECONCILE_SEA_DEL_START') %
           {'host': db_vio_server.get_host_name(),
            'vios': db_vio_server.lpar_id,
            'adpt': db_sea.name})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)

    db_sea.delete(context, db_session)
    db_vio_server.remove_adapter(db_sea)

    msg = (ras.vif_get_msg('info', 'RECONCILE_SEA_DEL_END') %
           {'host': db_vio_server.get_host_name(),
            'vios': db_vio_server.lpar_id,
            'adpt': db_sea.name})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)
Пример #2
0
    def _discover_vios_config(self):
        """
        This function will discover the SEA configuration on the managed
        VIOSes. If it detects any faulty configuration, an exception will
        be thrown.  The exception should include data on what the issue was.
        """
        ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, "Enter")

        try:
            # Get all the VIOS under this host, and verify we have at least one
            vio_servers = self._get_all_vios()
            if not vio_servers:
                ras.function_tracepoint(LOG,
                                        __name__,
                                        ras.TRACE_ERROR,
                                        ras.vif_get_msg('error',
                                                        'VIOS_NONE') %
                                        self.host_name)
                raise excp.IBMPowerVMInvalidHostConfig(attr='vios')

            # Loop through every VIOS on the host.
            for vios in vio_servers:
                # See if we find some adapters
                if not self._populate_adapters_into_vios(vios):
                    # Found no adapters... this could be fine, but log it.
                    ras.function_tracepoint(LOG,
                                            __name__,
                                            ras.TRACE_WARNING,
                                            vios.lpar_name + ': ' +
                                            ras.vif_get_msg('error',
                                                            'VIOS_NOADAPTERS'))

            # If we get here, we've found all adapters, added them to their
            # respective VioServer, and verified every VioServer has at least
            # one SharedEthernetAdapter.  Create the Host object with those
            # VioServers and we're done!
            self.host = dom.Host(self.host_name, vio_servers)

            # Update the available pool of VLAN IDs
            self.host.maintain_available_vid_pool()

#         except K2Error as e:  # Bug0002104,NameError: global name 'K2Error' is not defined
#             # If this was a K2Error, we want to reraise it so we don't put
#             # out a message about an invalid configuration, which is misleading
#             if e.k2response is not None:
#                 LOG.error(_('Request headers:'))
#                 LOG.error(e.k2response.reqheaders)
#                 LOG.error(_('Request body:'))
#                 LOG.error(e.k2response.reqbody)
#                 LOG.error(_('Response headers:'))
#                 LOG.error(e.k2response.headers)
#                 LOG.error(_('Response body:'))
#                 LOG.error(e.k2response.body)
#             raise

        except Exception as e:
            msg = (ras.vif_get_msg('error', 'VIOS_UNKNOWN') + " (" +
                   (_('%s') % e) + ")")

            ras.function_tracepoint(LOG, __name__, ras.TRACE_EXCEPTION, msg)
Пример #3
0
def _cascade_save(db_vios, context, db_session):
    """
    The save semantics throw errors (until Issue 3749 is resolved) that causes
    the objects to require a specific order when saved.  This method handles
    the saving of the objects.
    """
    msg = (ras.vif_get_msg('info', 'RECONCILE_SAVE_START') %
           {'host': db_vios.get_host_name(),
            'vios': db_vios.lpar_id})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)

    # Loop through the VEAs...
    for vea in db_vios.get_all_virtual_ethernet_adapters():
        db_session.add(vea)

    # Loop through the SEAs
    for sea in db_vios.get_shared_ethernet_adapters():
        db_session.add(sea)
        sea.primary_vea  # If not called...may set pvea to None?
        sea.control_channel
        sea.additional_veas

    # Save the VioServer
    # Removing 'add': 5278 fix causes InvalidRequestError--SEA already deleted
    #db_session.add(db_vios)
    db_session.flush()

    msg = (ras.vif_get_msg('info', 'RECONCILE_SAVE_END') %
           {'host': db_vios.get_host_name(),
            'vios': db_vios.lpar_id})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)
Пример #4
0
    def _find_veths_by_vlan(self, vlan_id):
        """
        Will run the command to list the virtual eth's on the system and return
        all of the lines that match this vlan. This may include the veth
        that bridges the vlan and the client veth that using the vlan.
        need to check both veth pvid and addl_vlan_ids.

        :param vlan_id: The additional VLAN id to search for
        :return: Will return a comma delimited string.  The output may look
                 like the following:
                    ['1,13,4093,1,1,"201,207"',
                     '1,19,4000,1,1,"300,301,302"']
                 The order is...
                   0 - lpar_id
                   1 - slot_num
                   2 - port_vlan_id
                   3 - is_trunk
                   4 - ieee_virtual_eth
                   5..n - addl_vlan_ids - Notice the quotes around this!
        """
        cmds = utils.get_veth_list_by_vlan_id_cmd()
        output = self._pvmops.run_vios_command(cmds)
        msg = (ras.vif_get_msg('info', 'LIST_VETH') % {'cmd': output})
        ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, msg)
        results = []
        for output_line in output:
            spots = output_line.split(',')

            # check port_vlan_id first
            if int(spots[2]) == vlan_id:
                results.append(output_line)
                msg = (ras.vif_get_msg('info', 'PVID_FOUND') %
                       {'pvid': output_line})
                ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, msg)
                # no need to check addl_vlan_ids then , continue
                continue
            # Based on the first four...and the fact that we only need to check
            # additional vlans, pop off 0 through 4 and then check to see if
            # this VLAN is in the list
            spots[0:5] = []

            # Loop through all the additional VLANs (which may need to be
            # trimmed) and if one matches, add it to results
            for addl_vlan_str in spots:
                if (addl_vlan_str == 'none'):
                    continue

                addl_vlan_int = vif.parse_to_int(addl_vlan_str)
                if addl_vlan_int == vlan_id:
                    msg = (ras.vif_get_msg('info', 'VLANID_IN_ADDL') %
                           {'vlanid': vlan_id})
                    ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG,
                                            msg)
                    results.append(output_line)
                    break

        return results
Пример #5
0
    def _find_first_avail_slot(self, vios):
        """
        This method will return the first available virtual slot on the VIOS.
        To be used when creating a VEA.

        :param vios: VioServer DOM object representing VIOS we're working with.
        :returns slotnum: Virtual slot number of the first available slot
        """
        ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, "Enter")

        # find out all the available virtual adapters and their physloc
        cmds = utils.get_virt_adapters_with_physloc_cmd(vios.lpar_id)
        physloc_list = self._pvmops.run_vios_command(cmds)
        msg = (ras.vif_get_msg('info', 'PHYSC_LOC_LIST') %
               {'output': physloc_list})
        ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, msg)

        # Output example:
        #['U9117.MMC.0604C17-V100-C2-T1',
        # .....]
        cmd = utils.get_curr_max_virtual_slots_cmd(vios.lpar_id)
        maxslots = int(self._pvmops.run_vios_command(cmd)[0])
        msg = (ras.vif_get_msg('info', 'MAX_SLOTS') %
               {'output': maxslots})
        ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, msg)
        if not physloc_list:
            return
        used_slots = []

        #Need to delte column descriptions that command returns
        physloc_list.reverse()
        physloc_list.pop()

        #loop through all slots used
        for slot in physloc_list:
            if len(slot.strip()) == 0:
                continue
            # get the first column from output , adapter details
            slot = slot.split(' ')[0]
            snum = int(slot.split('-')[2].lstrip('C'))
            if snum < maxslots:
                used_slots.append(snum)
        used_slots.sort()
        # vslot 0-9 are reserved on IVM.
        for snum in range(10, maxslots):
            if snum not in used_slots:
                break
        if snum == (maxslots - 1):  # The - 1 is because 0 is a valid slot
            return
        else:
            msg = (ras.vif_get_msg('info', 'SLOT_NUM') %
                   {'snum': snum})
            ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, msg)
            return snum
Пример #6
0
    def _find_default_with_no_vlan(self, primary_seas):
        """
        This method finds the default adapter when there's no vlanid specified.
        The default SEA is the one that has the lowest pvid in all the primary
        seas.

        :param: primary_seas: This is a list of all primary_seas for a given
        host

        :return: A default adapter. Note there can be only one in this case?
        """
        lowest_sea = None
        # A None should never be returned however
        low = 4096
        for i in range(0, len(primary_seas)):
            # if the sea is not available - we need to find the next available
            if primary_seas[i].pvid < low and primary_seas[i].is_available():
                low = primary_seas[i].pvid
                lowest_sea = primary_seas[i]
                msg = (ras.vif_get_msg
                      ('info', 'LOWEST_PVID') % {'lowest_sea':
                                                 lowest_sea.name})
                ras.function_tracepoint(LOG, __name__, ras.TRACE_INFO,
                                        msg)
        # Let's say that none of the seas are available, in this case we pick
        # anyone and return
        if lowest_sea is None and len(primary_seas) >= 1:
            lowest_sea = primary_seas[0]
            LOG.info(_('None of the seas are in available state, picking %s'
                       'as default' % lowest_sea.name))
        return lowest_sea
Пример #7
0
    def __init__(self, host_name, pvm_op=None):
        """
        IBMPowerVMVlanVIFDriver's constructor.

        :param host_name: The name of the host machine for nova, not to be
                          confused with the networking concept of hostname.
        :param pvm_op: It is the PowerVMOperator._operator initialized
                       by __init__() of PowerVMOperator.
        """
        # IVMOperator for IVM ssh command execution..
        if pvm_op:
            self._pvmops = pvm_op
        else:
            pvm_conn = pvmcom.Connection(CONF.powervm_mgr,
                                         CONF.powervm_mgr_user,
                                         CONF.powervm_mgr_passwd,
                                         CONF.powervm_mgr_port)
            msg = (ras.vif_get_msg
                   ('info', 'CONNECTION_IVM'))
            ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, msg)
            self._pvmops = operator.IVMOperator(pvm_conn)

        # Centralized topology service for IVM
        self._topo = topo_ivm.IBMPowerVMNetworkTopoIVM(host_name, self._pvmops)

        # Call parent constructor
        super(IBMPowerVMVlanVIFDriver, self).__init__()
Пример #8
0
def reconcile(context, host_data, dom_factory=dom.DOM_Factory(),
              db_session=None):
    """
    This is the entry method to reconcile the host data from the system with
    that stored in the database.

    :param context: The database context.
    :param host_data: A dictionary of data that represents the latest inventory
                      information on the server.  The data should be in the
                      network DOM format.
    :param dom_factory: Optional factory used to create the DOM objects.  Not
                        required to be set.
    :param db_session: The database session.  Should be started and finalized
                       outside this class.
    """
    if not db_session:
        db_session = session.get_session()

    try:
        with db_session.begin():
            _reconcile_host(context, host_data, dom_factory, db_session)
    except Exception as e:
        _log_before_and_after(context, host_data, db_session)
        msg = ras.vif_get_msg('error', 'HOST_RECONCILE_ERROR')
        ras.function_tracepoint(LOG, __name__, ras.TRACE_ERROR, msg)
        ras.function_tracepoint(
            LOG, __name__, ras.TRACE_EXCEPTION, e.message)
        raise

    # We only want to run the used port clean up rarely, as it is expensive
    global USED_PORT_COUNT
    USED_PORT_COUNT = USED_PORT_COUNT + 1
    if USED_PORT_COUNT >= USED_PORT_THRESHOLD:
        USED_PORT_COUNT = 0
        _neutron_unused_port_cleanup(context)
Пример #9
0
def _reconcile_sea(db_sea, server_sea, db_vio_server, context, db_session):
    """
    Will reconcile the database SharedEthernetAdapter to match that of the
    Server side SharedEthernetAdapter.

    :param db_sea: The DOM object that represents the SharedEthernetAdapter to
                   update.
    :param server_sea: The DOM object that represents the master data for the
                       database.
    :param db_vio_server: The VioServer that represents the corresponding
                          VioServer for this object.
    :param context: The context for the operations
    :param db_session: The database session to use for this transaction
    """
    msg = (ras.vif_get_msg('info', 'RECONCILE_SEA_START') %
           {'host': db_vio_server.get_host_name(),
            'vios': db_vio_server.lpar_id,
            'adpt': db_sea.name})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)

    db_sea.name = server_sea.name
    db_sea.vio_server = db_vio_server
    db_sea.slot = server_sea.slot
    db_sea.state = server_sea.state

    current_db_veas = db_vio_server.get_all_virtual_ethernet_adapters()

    db_sea.primary_vea = _find_adapter(current_db_veas,
                                       server_sea.primary_vea.name)

    if server_sea.control_channel:
        db_sea.control_channel = _find_adapter(current_db_veas,
                                               server_sea.control_channel.name)
    else:
        db_sea.control_channel = None

    db_sea.additional_veas = _find_adapter_list(current_db_veas,
                                                server_sea.additional_veas)

    msg = (ras.vif_get_msg('info', 'RECONCILE_SEA_END') %
           {'host': db_vio_server.get_host_name(),
            'vios': db_vio_server.lpar_id,
            'adpt': db_sea.name})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)
Пример #10
0
def _add_sea(server_sea, db_vio_server, context, db_session, dom_factory):
    """
    Adds the SharedEthernetAdapter object to the database.

    :param server_sea: The server side SharedEthernetAdapter object to merge
                       into the database.
    :param db_vio_server: The VioServer that represents the corresponding
                          VioServer for this object.
    :param context: The context for the operations
    :param db_session: The database session to use for this transaction
    :param dom_factory: The factory to use to convert the DOM objects.
    """
    msg = (ras.vif_get_msg('info', 'RECONCILE_SEA_ADD_START') %
           {'host': db_vio_server.get_host_name(),
            'vios': db_vio_server.lpar_id,
            'adpt': server_sea.name})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)

    # Swap in the Server (non-DB backed) VEAs with the real DB backed VEAs
    db_veas = db_vio_server.get_all_virtual_ethernet_adapters()
    db_pvea = _find_adapter(db_veas, server_sea.primary_vea.name)
    db_ctl = None
    if server_sea.control_channel:
        db_ctl = _find_adapter(db_veas, server_sea.control_channel.name)

    db_addl_veas = []
    if server_sea.additional_veas:
        db_addl_veas = _find_adapter_list(db_veas,
                                          server_sea.additional_veas)

    dom_factory.create_sea(server_sea.name,
                           db_vio_server,
                           server_sea.slot,
                           server_sea.state,
                           db_pvea,
                           db_ctl,
                           db_addl_veas)

    msg = (ras.vif_get_msg('info', 'RECONCILE_SEA_ADD_END') %
           {'host': db_vio_server.get_host_name(),
            'vios': db_vio_server.lpar_id,
            'adpt': server_sea.name})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)
Пример #11
0
    def _match_network_models(self, networks, net_infos, context):
        """
        Will match the neutron network model into the Nova network model and
        will embed the vSwitch and VLAN ID into the bridge name.

        :param networks: A set of Neutron Networks (the values returned from
                         the REST API)
        :param net_infos: The NOVA Network objects used by the compute layer.
                          These objects will be updated to contain the
                          provider:segmentation_id into the bridge attribute
                          in this object
        :param context: This is the context object to access the DB.
        :returns: The original net_infos, however updated with the bridge
                  which will be vSwitch/VLAN_ID
        """
        LOG.debug(('Enter _match_network_models with networks:\n%s\n\n'
                   'net_infos:\n%s' % (networks, net_infos)))
        # For each element, add in the proper VLAN ID into the bridge
        for network in networks:
            net_info = self._find_net_info_for_network(net_infos, network)
            if net_info is None:
                LOG.debug('Found no net_info for network %s' % network)
                continue

            # Get the VLAN off the network.  If one doesn't exist, default
            # to a value of 1.
            if network.get('provider:segmentation_id') is not None:
                vlanid = int(network['provider:segmentation_id'])
                LOG.info(ras.vif_get_msg('info', 'NET_VLAND_ID') %
                         {'vlan': vlanid})
            else:
                # Since there was no vlan id - setting it to 1
                vlanid = 1
                LOG.info(ras.vif_get_msg('info', 'NO_NET_VLAN'))

            # Set the data for this network into its corresponding net_info
            net_info['vlan'] = ("%(vlan)s" % {"vlan": vlanid})

        LOG.debug('Exiting _match_network_models with net_infos %s' %
                  net_infos)
        return net_infos
Пример #12
0
def _add_vios(server_vios, host, context, db_session, dom_factory):
    """
    Adds the VioServer object to the database.

    :param server_vios: The server side VioServer object to merge into the
                        database.
    :param host: The host for the VioServer
    :param context: The context for the operations
    :param db_session: The database session to use for this transaction
    :param dom_factory: The factory to use to convert the DOM objects.
    """
    msg = (ras.vif_get_msg('info', 'RECONCILE_VIOS_ADD_START') %
           {'host': server_vios.get_host_name(),
            'vios': server_vios.lpar_id})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)

    # Copy into a database backed DOM, because the DOM doesn't yet support
    # a single object to represent both DB and non-DB backed elements.
    db_vio = dom_factory.create_vios(lpar_name=server_vios.lpar_name,
                                     lpar_id=server_vios.lpar_id,
                                     host_name=server_vios.get_host_name(),
                                     state=server_vios.state,
                                     rmc_state=server_vios.rmc_state)

    # The VioServer passed in is a no-DB VioServer object.  First must convert
    # that over to the proper DB backed object and save it.
    db_vio.save(context, db_session)
    host.vio_servers.append(db_vio)

    # Cascade down into the adapters.
    for vea in server_vios.get_all_virtual_ethernet_adapters():
        _add_vea(vea, db_vio, context, db_session, dom_factory)
    for sea in server_vios.get_shared_ethernet_adapters():
        _add_sea(sea, db_vio, context, db_session, dom_factory)

    _cascade_save(db_vio, context, db_session)

    msg = (ras.vif_get_msg('info', 'RECONCILE_VIOS_ADD_END') %
           {'host': server_vios.get_host_name(),
            'vios': server_vios.lpar_id})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)
Пример #13
0
def _remove_vios(db_vios, host, context, db_session):
    """
    Will remove a VioServer from the database.

    :param db_vios: The DOM object that represents the VioServer to remove from
                    the database.
    :param host: The host for the VioServer
    :param context: The context for the operations
    :param db_session: The database session to use for this transaction
    """
    msg = (ras.vif_get_msg('info', 'RECONCILE_VIOS_DEL_START') %
           {'host': db_vios.get_host_name(),
            'vios': db_vios.lpar_id})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)

    db_vios.delete(context, db_session)
    host.vio_servers.remove(db_vios)

    msg = (ras.vif_get_msg('info', 'RECONCILE_VIOS_DEL_END') %
           {'host': db_vios.get_host_name(),
            'vios': db_vios.lpar_id})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)
Пример #14
0
    def __init__(self, host_name, operator=None):
        if operator:
            self._pvmops = operator
        else:
            self._pvmops = ivm_local_oper.IVMLocalOperator()

        self.host = None
        if not host_name:
            ras.function_tracepoint(
                LOG, __name__, ras.TRACE_ERROR, ras.vif_get_msg("error", "DEVNAME_INVALID") % {"devname": host_name}
            )
            raise excp.IBMPowerVMInvalidHostConfig(attr="host_name")
        self.host_name = host_name
        self.operator = operator
Пример #15
0
def _remove_vea(db_vea, db_vio_server, context, db_session):
    """
    Will remove a VirtualEthernetAdapter from the database.

    :param db_vea: The DOM object that represents the VirtualEthernetAdapter
                   to remove from the database.
    :param db_vio_server: The VioServer that represents the corresponding
                          VioServer for this object.
    :param context: The context for the operations
    :param db_session: The database session to use for this transaction
    """
    msg = (ras.vif_get_msg('info', 'RECONCILE_VEA_DEL_START') %
           {'host': db_vio_server.get_host_name(),
            'vios': db_vio_server.lpar_id,
            'adpt': db_vea.name})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)

    # Need to remove the VEA from the parent SEA.
    owning_sea = db_vio_server.get_sea_for_vea(db_vea)
    if owning_sea is not None:
        # If it is the primary VEA...just ignore...that means the SEA is also
        # being deleted...
        if owning_sea.primary_vea == db_vea:
            pass
        elif owning_sea.control_channel == db_vea:
            owning_sea.control_channel = None
        elif db_vea in owning_sea.additional_veas:
            owning_sea.additional_veas.remove(db_vea)

    db_vea.delete(context, db_session)
    db_vio_server.remove_adapter(db_vea)

    msg = (ras.vif_get_msg('info', 'RECONCILE_VEA_DEL_END') %
           {'host': db_vio_server.get_host_name(),
            'vios': db_vio_server.lpar_id,
            'adpt': db_vea.name})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)
Пример #16
0
def _add_vea(server_vea, db_vio_server, context, db_session, dom_factory):
    """
    Adds the VirtualEthernetAdapter object to the database.

    :param server_vea: The server side VirtualEthernetAdapter object to merge
                       into the database.
    :param db_vio_server: The VioServer that represents the corresponding
                          VioServer for this object.
    :param context: The context for the operations
    :param db_session: The database session to use for this transaction
    :param dom_factory: The factory to use to convert the DOM objects.
    """
    msg = (ras.vif_get_msg('info', 'RECONCILE_VEA_ADD_START') %
           {'host': db_vio_server.get_host_name(),
            'vios': db_vio_server.lpar_id,
            'adpt': server_vea.name})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)

    # Copy into a database backed DOM, because the DOM doesn't yet support
    # a single object to represent both DB and non-DB backed elements.
    vea = dom_factory.create_vea(server_vea.name,
                                 db_vio_server,
                                 server_vea.slot,
                                 server_vea.pvid,
                                 server_vea.is_trunk,
                                 server_vea.trunk_pri,
                                 server_vea.state,
                                 server_vea.ieee_eth,
                                 server_vea.vswitch_name,
                                 server_vea.addl_vlan_ids)
    vea.save(context, db_session)

    msg = (ras.vif_get_msg('info', 'RECONCILE_VEA_ADD_END') %
           {'host': db_vio_server.get_host_name(),
            'vios': db_vio_server.lpar_id,
            'adpt': server_vea.name})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)
Пример #17
0
def _reconcile_vea(db_vea, server_vea, db_vio_server, context, db_session):
    """
    Will reconcile the database VirtualEthernetAdapter to match that of the
    Server side VirtualEthernetAdapter.

    :param db_vea: The DOM object that represents the VirtualEthernetAdapter to
                   update.
    :param server_vea: The DOM object that represents the master data for the
                       database.
    :param db_vio_server: The VioServer that represents the corresponding
                          VioServer for this object.
    :param context: The context for the operations
    :param db_session: The database session to use for this transaction
    """
    msg = (ras.vif_get_msg('info', 'RECONCILE_VEA_START') %
           {'host': db_vio_server.get_host_name(),
            'vios': db_vio_server.lpar_id,
            'adpt': server_vea.name})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)

    db_vea.name = server_vea.name
    db_vea.pvid = server_vea.pvid
    db_vea.vio_server = db_vio_server
    db_vea.slot = server_vea.slot
    db_vea.is_trunk = server_vea.is_trunk
    db_vea.state = server_vea.state
    db_vea.trunk_pri = server_vea.trunk_pri
    db_vea.ieee_eth = server_vea.ieee_eth
    db_vea.vswitch_name = server_vea.vswitch_name
    db_vea.addl_vlan_ids = server_vea.addl_vlan_ids

    msg = (ras.vif_get_msg('info', 'RECONCILE_VEA_END') %
           {'host': db_vio_server.get_host_name(),
            'vios': db_vio_server.lpar_id,
            'adpt': server_vea.name})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)
Пример #18
0
    def index(self, req):
        """
        This method handles GET requests to fetch placement data.
        :param req: HTTP Request
        :returns: HTTP Response with host network placement data.
        """
        context = self._validate_authorization(req.environ['nova.context'],
                                               authorize_method=auth_index)

        # Parse the network_id from the URI, if present
        network_id = None
        if 'network_id' in req.GET:
            network_id = req.GET['network_id']

        # Parse the list_only param from the URI, if present
        list_only = None
        if 'return_only_id_list' in req.GET:
            list_only = req.GET['return_only_id_list'].lower()

        # If a network was provided, validate that the network exists
        if network_id or network_id == '':
            try:
                novanetwork.API().get(context, network_id)
            except:
                return Response(request=req,
                                status=httplib.NOT_FOUND,
                                content_type='application/json',
                                body='')

        if list_only == 'true' and not network_id:
            msg = ras.vif_get_msg('error', 'PLACEMENT_PARAM_MISSING')
            return Response(request=req,
                            status=httplib.BAD_REQUEST,
                            content_type='application/json',
                            body=json.dumps({'message': msg}))

        # Get the placement dictionary
        placement_dict = self.placement_module.get_placement(context,
                                                             None,
                                                             network_id,
                                                             list_only)

        # Return the results
        return webob.Response(request=req,
                              status=httplib.OK,
                              content_type='application/json',
                              body=json.dumps(placement_dict))
Пример #19
0
    def _determine_vlan(self, vlan, net_id, host, context):
        """
        Determines the VLAN that should be used.

        :param vlan: The passed in VLAN from the user.  May be None.
        :param net_id: The neutron network identifier.  May be None.
        :param host: The host being queried.  String value
        :param context: The context for neturon queries
        :return: The VLAN identifier to use.  If both parameters are none, then
                 None will be returned, indicating 'all seas' should be
                 returned
        """
        # This is the scenario where the user wants all SEAs.
        if vlan is None and net_id is None:
            return None

        # If a network id is passed in, we will override any VLAN info
        # with the info from the network ID.
        if net_id:
            msg = (ras.vif_get_msg('info', 'NET_ID_SUPPLIED') %
                   {'vlan_id': vlan, 'host_name': host, 'net_id': net_id})
            ras.function_tracepoint(LOG, __name__, ras.TRACE_INFO, msg)
            try:
                net_api = self._build_network_api()
                neutron_net = net_api.get(context, net_id)
            except neutronv2.exceptions.NeutronClientException as e:
                ras.function_tracepoint(LOG, __name__,
                                        ras.TRACE_ERROR, e.message)
                # We need to stop execution here. Since we didn't get
                # the client
                raise

            if neutron_net and neutron_net.\
                    get('provider:segmentation_id'):
                vlan = neutron_net.get('provider:segmentation_id', 1)
            elif neutron_net and neutron_net.get('vlan'):
                vlan = neutron_net.get('vlan', 1)
            else:
                msg = _("Couldn't retrieve VLAN associated with Net_id"
                        "setting default to 1")
                ras.function_tracepoint(LOG, __name__,
                                        ras.TRACE_WARNING, msg)
                vlan = 1

        # Return the passed in value, but make sure its an int
        return int(vlan)
Пример #20
0
    def show(self, req, id):
        """
        This method handles GET requests to fetch placement data for a specific
        host.
        :param req: HTTP Request
        :param id: host
        :returns: HTTP Response with placement data.
        """
        context = self._validate_authorization(req.environ['nova.context'],
                                               authorize_method=auth_show)

        # Validate the specified host exists
        hosts = self._find_all_host_names(context)
        if not id in hosts:
            raise novaexception.ComputeHostNotFound(host=id)

        # Parse the network_id from the URI, if present
        network_id = None
        if 'network_id' in req.GET:
            network_id = req.GET['network_id']

        # If a network was provided, throw an error
        if network_id:
            msg = ras.vif_get_msg('error', 'PLACEMENT_PARAM_ERROR_BOTH')
            return Response(request=req,
                            status=httplib.BAD_REQUEST,
                            content_type='application/json',
                            body=json.dumps({'message': msg}))

        # Parse the list_only param from the URI, if present
        list_only = None
        if 'return_only_id_list' in req.GET:
            list_only = req.GET['return_only_id_list'].lower()

        # Get the placement dictionary
        placement_dict = self.placement_module.get_placement(context,
                                                             id,
                                                             None,
                                                             list_only)

        # Return the results
        return webob.Response(request=req,
                              status=httplib.OK,
                              content_type='application/json',
                              body=json.dumps(placement_dict))
Пример #21
0
def parse_slot_num(virt_eths, adapter_name):
    """
    Parse the adapter slot data from the IVM output.

    :param virt_eths: A dictionary with adapter data from IVM
    :param adapter_name: The name of a SEA or VEA
    :returns: An integer of the slot the adapter occupies
    """
    try:
        physloc = virt_eths[adapter_name][1].strip()
    except KeyError:
        msg = (ras.vif_get_msg('error', 'VIOS_SEAINVALIDLOCS') %
               {'devname': adapter_name})
        ras.function_tracepoint(LOG, __name__, ras.TRACE_ERROR,
                                msg)
        return None

    return int(physloc.split('-')[2].lstrip('C'))
Пример #22
0
    def __init__(self, host_name, operator=None):
        """
        IBMPowerVMNetworkTopoIVM constructor

        :param host_name: Host_name for this compute process's node
        :param operator: PowerVMOperator to interface with PowerVM host
        """
        if operator:
            self._pvmops = operator
        else:
            msg = ras.vif_get_msg("info", "CONNECTION_IVM_TOPO")
            ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, msg)
            pvm_conn = pvmcom.Connection(
                CONF.powervm_mgr, CONF.powervm_mgr_user, CONF.powervm_mgr_passwd, CONF.powervm_mgr_port
            )
            self._pvmops = ivm_oper.IVMOperator(pvm_conn)

        topo.IBMPowerVMNetworkTopo.__init__(self, host_name=host_name, operator=self._pvmops)
Пример #23
0
    def _build_network_info_model(self, context, instance, networks=None,
                                  port_ids=None):
        LOG.debug('Enter _build_network_info_model with instance %s and '
                  'networks %s' % (instance['project_id'], networks))

        # Get all the nova networks associated with the neutron network passed
        # in.  If no neutron network was passed in, this will return all nova
        # networks.
        net_infos = []
        if networks is None and port_ids is None:
            # We need to check to see if the cache thinks we're none as well
            network_info = compute_utils.get_nw_info_for_instance(instance)

            # If the network info is an empty list...it may be valid.  However,
            # it is improbable.  We should go query against the master list,
            # which is neutron.
            if network_info is None or len(network_info) == 0:
                net_infos = self._update_instance_nw_cache(instance, context)
        # We didn't get the network infos - this could mean that the cache data
        # on the instance is proper. So let's call neutron's parent API and
        # get network details.
        if net_infos == []:
            net_infos = super(PowerVMAPI,
                              self)._build_network_info_model(context,
                                                              instance,
                                                              networks,
                                                              port_ids)
        LOG.debug('Found net_infos %s' % net_infos)

        # Get the neutron networks related to our instance if the invoker did
        # not pass them in.
        if not networks:
            networks = self._get_available_networks(context,
                                                    instance['project_id'])
            msg = (ras.vif_get_msg
                  ('info', 'NO_NET_FOUND') % {'host': instance['host']})
            ras.function_tracepoint(LOG, __name__, ras.TRACE_INFO, msg)

        # Pare down the nova networks list to only include those that map to
        # the neutron network we're interested in.  This will also add in the
        # vlan id to the nova network object.
        return self._match_network_models(networks, net_infos, context)
Пример #24
0
    def __init__(self, host_name, operator=None):
        """
        Initialize the DOM objects to None and set the operator we'll use
        to interface with the system.  NOTE: Subclasses' __init__ should call
        this __init__() and then set up their specific operator.  For IVM, this
        will be an IVMOperator object.  For HMC, this will be a K2 operator.

        :param host_name: Host_name for this compute process's node
        :param operator: Operator used to interface with the system.
        """
        self.host = None
        if not host_name:
            ras.function_tracepoint(LOG,
                                    __name__,
                                    ras.TRACE_ERROR,
                                    ras.vif_get_msg('error',
                                                    'DEVNAME_INVALID') %
                                    {'devname': host_name})
            raise excp.IBMPowerVMInvalidHostConfig(attr='host_name')
        self.host_name = host_name
        self.operator = operator
Пример #25
0
    def _get_all_vios(self, dom_factory=model.No_DB_DOM_Factory()):
        """
        Overridden method from
        powervc_nova.virt.ibmpowervm.vif.topo.IBMPowerVMNetworkTopo

        IVM systems only have a single VIOS by definition, so this returns a
        list with a single element.

        :param dom_factory: Factory used to create the DOM objects, optional.
        :returns vioses: A list of VioServer objects
        """
        ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, "Enter")

        # Find the LPAR name and ID
        cmd = utils.get_vios_lpar_id_name()
        output = self._pvmops.run_vios_command(cmd)
        # Split the LPAR name and ID apart
        output_array = output[0].split()
        vio_lpar_id = output_array.pop(0)
        vio_lpar_name = " ".join(output_array)
        msg = ras.vif_get_msg("info", "LPAR_DETAILS") % {"lpar_id": vio_lpar_id, "lpar_name": vio_lpar_name}
        ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, msg)

        # Get the RMC status
        cmd = utils.get_rmc_status()
        output = self._pvmops.run_vios_command(cmd)
        rmc_state = utils.parse_rmc_status(output, vio_lpar_id)

        # Use the factory to build the VIOS DOM object
        # NOTE: By virtue of the fact that we're running VIOS commands over
        #       SSH, the VIOS state is 'running'... so just hard code it below.
        return [
            dom_factory.create_vios(
                lpar_name=vio_lpar_name,
                lpar_id=vio_lpar_id,
                host_name=self.host_name,
                state="running",
                rmc_state=rmc_state,
            )
        ]
Пример #26
0
    def _find_vlan_users(self, vios, vlanid, vswitch):
        """
        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: Not needed for IvM.  Only here because superclass has it.
        :param vlanid: VLANID to search for
        :param vswitch: Not needed for IVM since there's only one vswitch.
        :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.
        """
        pvid = 0

        # Get the VEA slot that bridges this vlanid
        # output looks like the following:
        # lparid, slot,port_vlan_id, is_trunk,
        # ieee_virtual_eth,addl_vlan_ids
        # [1,13,4093,1,1,"201,207"],
        output = self._find_veths_by_vlan(vlanid)
        num_users = len(output)
        msg = (ras.vif_get_msg('info', 'VLAN_USERS') %
               {'vlanid': vlanid, 'num': num_users})
        ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, msg)
        if output:
            # Find the veth that represents the bridging veth
            for veth in output:
                # There can only be one is_trunk adapter (ie, adapter on the
                # VIOS)
                elements = veth.split(',')
                if int(elements[3]):
                    pvid = int(elements[2])

        return pvid, num_users
Пример #27
0
def _reconcile_host(context, host_data, dom_factory=dom.DOM_Factory(),
                    db_session=None):
    """
    Performs the actual reconciliation at the host level

    :param context: The database context.
    :param host_data: A dictionary of data that represents the latest inventory
                      information on the server.  The data should be in the
                      network DOM format.
    :param dom_factory: Optional factory used to create the DOM objects.  Not
                        required to be set.
    :param db_session: The database session.  Should be started and finalized
                       outside this class.
    """
    if not db_session:
        db_session = session.get_session()

    # Parse the inventory data into a DOM object.  Use the no_db DOM factory
    # as we want to parse into non-DB backed elements to start...
    non_db_fact = dom.No_DB_DOM_Factory()
    server_dom = dom.parse_to_host(host_data, non_db_fact)

    msg = (ras.vif_get_msg('info', 'RECONCILE_HOST_START') %
           {'host': server_dom.host_name})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)

    # Get the inventory data from the database.
    db_vio_servers = db.vio_server_find_all(context, server_dom.host_name,
                                            db_session)

    # If there are no VIO Servers, the system may be turned off.  It is very
    # unlikely that they are actually removed (all of them at least).
    # Therefore, we flip the SEAs in each VioServer to a state of unavailable
    # and they do not show up in the UI...but are not deleted.
    if len(server_dom.vio_servers) == 0:
        LOG.info(_("Flipping host %s to unavailable due to lack of VioServers"
                   % server_dom.host_name))
        _make_system_unavailable(db_vio_servers, context, db_session)
        return

    # The first step is to find VIO Servers do add/remove/modify.  Those are
    # the three passes that need to be made.
    #
    # We start with the idea that all of the data base items should be removed.
    # From there, we parse down which are still on the system (therefore need
    # to be modified) and then the new adds.
    db_vios_to_del = dom.shallow_copy_as_ordinary_list(db_vio_servers)
    srv_vios_to_add = []
    srv_vios_to_modify = []

    for vio_server in server_dom.vio_servers:
        db_vios = _find_vios(db_vio_servers, vio_server.lpar_id)
        if db_vios:
            srv_vios_to_modify.append(vio_server)
            db_vios_to_del.remove(db_vios)
        else:
            srv_vios_to_add.append(vio_server)

    # Now that we know what to modify/create/delete...loop through each and
    # execute the commands to reconcile
    db_host_dom = dom.Host(server_dom.host_name, db_vio_servers)

    # Save off the network associations first so we can recreate any that
    # need to be later on.
    net_assns = _build_net_assn_dict(
        db.network_association_find_all(context,
                                        db_host_dom.host_name,
                                        db_session))

    for db_vios in db_vios_to_del:
        _remove_vios(db_vios, db_host_dom, context, db_session)
    for server_vios in srv_vios_to_modify:
        _reconcile_vios(_find_vios(db_vio_servers, server_vios.lpar_id),
                        server_vios, context, db_session, dom_factory)
    for server_vios in srv_vios_to_add:
        _add_vios(server_vios, db_host_dom, context, db_session, dom_factory)

    msg = (ras.vif_get_msg('info', 'RECONCILE_HOST_END') %
           {'host': server_dom.host_name})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)

    # Cleanup NetworkAssociations in case any VIOSes went away or came back.
    _cleanup_network_associations(db_host_dom, net_assns, context, db_session)
Пример #28
0
    def refresh(self, must_discover_sea=True):
        """
        This method will refresh the topology such that it will reset its
        internal data model and then run a discovery on the system.  This
        ensures that any changes done on the system itself will be picked up
        and added to the data model.
        """
        # Reset the data model
        self.host = None

        # If the CEC is not running, do not discover the host.
        if self._is_cec_running():
            # Discover the VIOSes and remember if discovery succeeds
            self._discover_vios_config()

        # If we were told we must discover at least one SEA, verify we did.
        if must_discover_sea:
            if self.host is None:
                msg = ras.vif_get_msg('error', 'NET_INVALIDCFG')
                ras.function_tracepoint(LOG, __name__, ras.TRACE_ERROR, msg)
                raise excp.IBMPowerVMInvalidMgmtNetworkCfg(msg=msg)
            elif not self.host.find_all_primary_seas():
                # If any of the VIOSes have RMC down, they could have been the
                # one with an SEA on it.  Raise an exception pointing to RMC
                # as the problem.
                at_least_one_rmc_active = False
                at_least_one_rmc_inactive = False
                for vios in self.host.vio_servers:
                    if vios.rmc_state.lower() != 'active':
                        ras.function_tracepoint(LOG, __name__, ras.TRACE_ERROR,
                                                ras.vif_get_msg('error',
                                                                'VIOS_NORMC') %
                                                {'lpar': vios.lpar_name,
                                                 'state': vios.rmc_state})
                        at_least_one_rmc_inactive = True
                    else:
                        at_least_one_rmc_active = True

                if at_least_one_rmc_active and at_least_one_rmc_inactive:
                    # We found a mixture of both active and inactive RMC
                    # connections.  We can't definitively point to RMC as the
                    # problem, so put out a message that it COULD be the
                    # reason we found no SEAs.
                    raise excp.IBMPowerVMRMCDownNoSEA(host=self.host_name)
                elif at_least_one_rmc_active:
                    # We found an active RMC connection but no inactive ones,
                    # so we really have a situation where no SEAs were found.
                    raise excp.IBMPowerVMValidSEANotFound()
                elif at_least_one_rmc_inactive:
                    # We must've found NO active RMC connections.  Put out
                    # the very specific message about this.
                    raise excp.IBMPowerVMAllRMCDown(host=self.host_name)
                else:
                    # This can only be reached if neither active nor inactive
                    # RMC connections were found.  In other words, if no
                    # VIOSes were found.  I doubt this will ever happen, but
                    # better safe than sorry.
                    msg = ras.vif_get_msg('error', 'NET_INVALIDCFG')
                    raise excp.IBMPowerVMInvalidHostConfig(attr='No VIOS')
        else:
            return
Пример #29
0
    def _create_vea_on_vios(self, vios, sea, slotnum, port_vlan_id,
                            addl_vlan_ids):
        """
        This method will create the 802.1Q VirtualEthernetAdapter on the
        VIOS and return the device name of the newly created adapter.  A
        IBMPowerVMFailToAddDataVlan should be raised if unable to create the
        new VEA.

        :param vios: VioServer DOM object representing VIOS this is being
                     created on.
        :param sea: SEA that owns the VEA.  Not needed on IVM as the VEA is
                    attached to the SEA in a separate step.
        :param slotnum: Virtual slot number to create the new VEA in.
        :param port_vlan_id: pvid to set on the new VEA
        :param addl_vlan_ids: Additional vlan ids to set on the new VEA
        :returns vea_devname: Device name of the newly created VEA
        :returns slot_number: Always returns None
        """
        ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, "Enter")

        try:
            cmd = utils.create_8021Q_vea_cmd(lpar_id=vios.lpar_id,
                                             slotnum=slotnum,
                                             port_vlan_id=port_vlan_id,
                                             addl_vlan_ids=addl_vlan_ids)
            self._pvmops.run_vios_command(cmd)

            # find out the new slot's devname. Even though DR slot add
            # operation will call cfgmgr on the VIOS, just invoke cfgdev
            # again on vio0 to make sure the device is discovered by VIOS.
            cmd = utils.get_newly_added_slot_name_cmd(lpar_id=vios.lpar_id,
                                                      mts=self._get_mts(),
                                                      slotnum=slotnum)

            vea_devname = self._pvmops.run_vios_command(cmd)[0]
            msg = (ras.vif_get_msg('info', 'VEA_DEV_NAME') %
                   {'vea_dev': vea_devname, 'cmd': cmd})
        except Exception as e:  # catch the hmc/vios command exception
            ras.trace(LOG, __name__, ras.TRACE_EXCEPTION,
                      ras.msg('error', 'VETH_NOTCFG') % {'slotnum': slotnum} +
                      "(" + (_('%s') % e) + ")")
            raise

        if not vea_devname:
            # failed to find the newly created veth slot on VIOS. clean it up.
            ras.trace(LOG, __name__, ras.TRACE_ERROR,
                      ras.msg('error', 'VETH_NOTCFG') % {'slotnum': slotnum})
            try:
                cmds = utils.remove_virtual_slot_cmd(lpar_id=vios.lpar_id,
                                                     slot_num=slotnum)
                self._pvmops.run_vios_command(cmds)

                ras.trace(LOG, __name__, ras.TRACE_DEBUG,
                          'Clean up: slot %(slotnum)d has been removed' %
                          {'slotnum': slotnum})

            except Exception:
                ras.trace(LOG, __name__, ras.TRACE_EXCEPTION,
                          ras.msg('error', 'VETH_FAILTOREMOVE') %
                          {'slotnum': slotnum} + "(" + _('%s') % e + ")")

            raise excp.IBMPowerVMFailToAddDataVlan(data_vlan_id=addl_vlan_ids)

        # If we got here, we succeeded!
        return vea_devname, None
Пример #30
0
def _reconcile_vios(db_vios, server_vios, context, db_session, dom_factory):
    """
    Will reconcile the database VioServer object to match that of the Server
    VioServer object.

    :param db_vios: The VioServer object in the database.
    :param server_vios: The VioServer object that represents the current state
                        on the server system.
    :param context: The context for the operations
    :param db_session: The database session to use for this transaction
    :param dom_factory: The factory to use to convert the DOM objects.
    """

    msg = (ras.vif_get_msg('info', 'RECONCILE_VIOS_START') %
           {'host': server_vios.get_host_name(),
            'vios': server_vios.lpar_id})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)

    db_veas = db_vios.get_all_virtual_ethernet_adapters()
    db_seas = db_vios.get_shared_ethernet_adapters()

    srv_veas = server_vios.get_all_virtual_ethernet_adapters()
    srv_seas = server_vios.get_shared_ethernet_adapters()

    # Have to 'load' these objects due to an issue found in 3749.  By calling
    # these, the attributes are loaded into memory.  If we don't do this
    # then when the VEAs change, they may remove themselves from the SEA.
    for db_sea in db_seas:
        db_sea.primary_vea
        db_sea.control_channel
        db_sea.additional_veas

    # Save the rmc_state of the vios.  This may or may not be different than
    # what's already in the db.
    db_vios.rmc_state = server_vios.rmc_state
    ras.trace(LOG, __name__, ras.TRACE_DEBUG,
              'RMC state for lpar %d (%s): %s, ' % (server_vios.lpar_id,
                                                    server_vios.lpar_name,
                                                    server_vios.rmc_state))

    # If the RMC connection is down, then we'll just update the VIOS's
    # rmc_state in the db, no other reconciliation will occur.  Since rmc_state
    # is taken into account when checking whether an adapter is available, we
    # don't need to update all the adapters.
    if server_vios.rmc_state.lower() == 'active':
        # RMC is up, proceed as normal.

        # The first step to reconciliation is the VEAs, as they are input into
        # the SEAs.
        #
        # We start with the idea that all of the VEAs on the VIOS should be
        # removed.  Then the code will parse out from that delete list and
        # create lists of adapters to add and merge.
        db_veas_to_del = dom.shallow_copy_as_ordinary_list(db_veas)
        srv_veas_to_add = []
        srv_veas_to_modify = []

        for srv_vea in srv_veas:
            db_vea = _find_adapter(db_veas, srv_vea.name)
            if db_vea:
                srv_veas_to_modify.append(srv_vea)
                db_veas_to_del.remove(db_vea)
            else:
                srv_veas_to_add.append(srv_vea)

        # We have sorted how each object should be handled.  Handle these
        # before moving on to the SEAs.
        for db_vea in db_veas_to_del:
            _remove_vea(db_vea, db_vios, context, db_session)
        for server_vea in srv_veas_to_modify:
            _reconcile_vea(_find_adapter(db_veas, server_vea.name),
                           server_vea, db_vios, context, db_session)
        for server_vea in srv_veas_to_add:
            _add_vea(server_vea, db_vios, context, db_session, dom_factory)

        # At this point, we have reconciled the VirtualEthernetAdapters.  Next
        # up is the SharedEthernetAdapters, that contain the
        # VirtualEthernetAdapters.
        db_seas_to_del = dom.shallow_copy_as_ordinary_list(db_seas)
        srv_seas_to_add = []
        srv_seas_to_modify = []

        for srv_sea in srv_seas:
            db_sea = _find_adapter(db_seas, srv_sea.name)
            if db_sea:
                srv_seas_to_modify.append(srv_sea)
                db_seas_to_del.remove(db_sea)
            else:
                srv_seas_to_add.append(srv_sea)

        # Now that we have sorted how each object should be handle (Create,
        # Update, or Delete), execute those actions...
        for db_sea in db_seas_to_del:
            _remove_sea(db_sea, db_vios, context, db_session)
        for server_sea in srv_seas_to_modify:
            _reconcile_sea(_find_adapter(db_seas, server_sea.name),
                           server_sea, db_vios, context, db_session)
        for server_sea in srv_seas_to_add:
            _add_sea(server_sea, db_vios, context, db_session, dom_factory)
    else:
        ras.trace(LOG, __name__, ras.TRACE_WARNING,
                  _('RMC state for lpar %(lpar)d (%(lpar_name)s): %(state)s' %
                    {'lpar': server_vios.lpar_id,
                     'lpar_name': server_vios.lpar_name,
                     'state': server_vios.rmc_state}))

    # Whether reconciled or just set rmc_state, we need to save back to the DB.
    _cascade_save(db_vios, context, db_session)

    msg = (ras.vif_get_msg('info', 'RECONCILE_VIOS_END') %
           {'host': server_vios.get_host_name(),
            'vios': server_vios.lpar_id})
    ras.trace(LOG, __name__, ras.TRACE_DEBUG, msg)