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)
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)
def _delete_vea_on_vios(self, vios, vea_dev, sea_dev, virt_adpts_list): """ This method will remove the given VEA from the given SEA on the system and delete it. :param vios: VioServer DOM object representing VIOS this is being removed from. :param vea_dev: VirtualEthernetAdapter DOM object :param sea_dev: SharedEthernetAdapter DOM object :param virt_adpts_list: List of VEA devnames that should remain on the SEA """ # Run the first two commands in a loop in case the rmdev fails. # Running the first command repeatedly isn't a problem because # it's setting the SEA to what we want, and that doesn't change. # If this fails, it'll be on the rmdev. for x in range(RMDEV_ATTEMPTS): try: cmds = \ (utils.change_sea_virt_adapters_cmd(seaname=sea_dev.name, pveaname=sea_dev. get_primary_vea().name, virt_list= virt_adpts_list) + ' && ' + utils.remove_virtual_device(vea_dev.name) + ' && ' + utils.remove_virtual_slot_cmd(lpar_id=vea_dev. vio_server.lpar_id, slot_num=vea_dev.slot)) self._pvmops.run_vios_command(cmds) # If we got here, all is well break except Exception as e: ras.trace(LOG, __name__, ras.TRACE_ERROR, ras.msg('error', 'VETH_FAILTOREMOVE') % {'slotnum': vea_dev.slot} + '(' + _('%s') % e + ')') # Sleep before we try again if x < (RMDEV_ATTEMPTS - 1): time.sleep(1) else: # This was our last attempt. Re-raise the exception. raise
def _find_all_host_names(self, context): """ 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 set of compute nodes. """ compute_nodes = db.compute_node_get_all(context) return_nodes = [] for compute in compute_nodes: if not compute['service']: ras.trace(LOG, __name__, ras.TRACE_WARNING, _('No service for compute ID %s' % compute['id'])) continue host_to_send = compute['service']['host'] return_nodes.append(host_to_send) return return_nodes
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)
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)
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)
def _find_peer_network_sea(self, context, host_name, vlanid, session): """ This method finds whether a given vlanid exists for a host network or not. If it finds that this VLAN is part of an existing network, it returns the corresponding SEA. :param context: The context used to call the dom API :param host_id: The host_id of the host for which the network associations are fetched. :param vlanid: The vlan id for which the match is needed. :param session: The database session object. :returns: either an SEA or None """ # The VLAN ID may be none here, indicating a pull for all SEAs. if vlanid is None: return None network_associations = dom_api.\ network_association_find_all(context, host_name, session) # net_map should always be of size 1 for network_association in network_associations: if network_association: try: net_api = self._build_network_api() neutron_net = net_api.get(context, network_association. neutron_net_id) except Exception as e: # Will throw an exception if the neutron client could # not be found ras.trace(LOG, __name__, ras.TRACE_WARNING, _('Neutron client not found for net_id %s' % network_association.neutron_net_id)) if 'neutron_net' in locals() and neutron_net: if neutron_net.get("provider:segmentation_id") == vlanid: # There should be only one SEA per VLAN so we return # as soon as we find one. return network_association.sea if neutron_net.get("vlan") == vlanid: return network_association.sea return None
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)
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)
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)
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)
def _get_sea_from_ivm(self, vios, sea_devname, virt_eths, dom_factory=model.No_DB_DOM_Factory()): """ Connect to an IVM endpoint and retrieve all of the configuration for a SEA and the VEAs associated with it. :param vios: The VioServer DOM object that represents this IVM :param sea_devname: The device name for the SEA to query :param virt_eths: Dictionary of physical adapter info from IVM :param dom_factory: Factory used to create the DOM objects, optional. :returns SharedEthernetAdapter: An SEA DOM object """ # Got the SEA logical device name on VIOS. # Need to find out its pvid_adapter and virt_adapters and pvid cmd = utils.get_sea_attribute_cmd(sea_devname) output = self._pvmops.run_vios_command(cmd) # Output example: # ['value', '', '100', 'ent4', 'ent4,ent13,ent14', # 'ent24 Available Shared Ethernet Adapter'] if len(output) == 0 or output[0] != "value": ras.trace(LOG, __name__, ras.TRACE_ERROR, ras.vif_get_msg("error", "VIOS_CMDFAIL") % {"cmd": cmd}) return None # Get rid of 'value','' from the list output[0:2] = [] # Find out pvid adapter and all the virt_adapters for # the give SEA and create SeaDevices object based # on the information retrieved from HMC/IVM. sea_pvid = int(output[0].strip()) sea_pvid_adpt = output[1].strip() sea_virt_adpts = output[2].strip().split(",") sea_state = output[3].split()[1] # virt_adpts has at least pvid_adpt if sea_pvid_adpt not in sea_virt_adpts: msg = ras.vif_get_msg("error", "SEA_INVALIDSTATE") ras.function_tracepoint(LOG, __name__, ras.TRACE_ERROR, msg) return None # Get the full virt_adapters list without the pvid_adapter sea_virt_adpts.remove(sea_pvid_adpt) # Get the slot number for this adapter vea_slot_num = utils.parse_slot_num(virt_eths, sea_pvid_adpt) # Create the VEA and SEA dom objects vea_dev = self._get_vea_for_slot(vios, sea_pvid_adpt, vea_slot_num, sea_pvid, dom_factory) sea_dev = dom_factory.create_sea( name=sea_devname, vio_server=vios, slot=vea_slot_num, state=sea_state, primary_vea=vea_dev, control_channel=None, additional_veas=None, ) ras.trace(LOG, __name__, ras.TRACE_DEBUG, ("SEA %(devname)s is discovered" % {"devname": sea_devname})) # Find all the virt_adapters if there are any in sea_virt_adpts # list for devname in sea_virt_adpts: # Get the slot number for this adapter vea_slot_num = utils.parse_slot_num(virt_eths, devname) vea_dev = self._get_vea_for_slot(vios, devname, vea_slot_num, sea_pvid, dom_factory) try: sea_dev.add_vea_to_sea(vea_dev) except excp.IBMPowerVMInvalidSEAConfig: msg = ras.vif_get_msg("error", "SEA_FAILTOADDVEA") % {"veaname": vea_dev.name, "seaname": sea_dev.name} ras.trace(LOG, __name__, ras.TRACE_EXCEPTION, msg) return None # End of for loop to discovery all the virtual adapters # for the SEA. It is the end of the inner for loop return sea_dev
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
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)
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)
def _populate_adapters_into_vios(self, vios, dom_factory=model.No_DB_DOM_Factory()): """ Overridden method from powervc_nova.virt.ibmpowervm.vif.topo.IBMPowerVMNetworkTopo This method returns all the adapters, both SEA and VEA, for the VIOS this IVM runs on. Each VEA will be attached to it's owning SEA, if it has one. :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 adapter was found, False otherwise. """ ras.function_tracepoint(LOG, __name__, ras.TRACE_DEBUG, "Enter") try: # If the VIOS RMC state is down, we can't use adapters on it. if vios.rmc_state.lower() != "active": ras.trace(LOG, __name__, ras.TRACE_INFO, _("RMC state is not active on VIOS lpar %s") % vios.lpar_name) return False # Find all of the adapters on the VIOS cmd = utils.get_all_sea_with_physloc_cmd() output = self._pvmops.run_vios_command(cmd) virt_eths = utils.parse_physloc_adapter_output(output) # Find all of the SEAs on this IVM seas_found = {} for vea in virt_eths: if virt_eths[vea][0].strip() != "Shared Ethernet Adapter": # this is not a SEA device. continue seas_found[vea] = virt_eths[vea] # Go through the SEAs and get their current configuration from IVM veas_attached_to_seas = [] for sea_devname in seas_found: # Connect to the IVM endpoint and collect the SEA info sea_dev = self._get_sea_from_ivm(vios, sea_devname, virt_eths, dom_factory) # Keep track of which VEAs are owned by an SEA so we can later # detect orphan VEAs veas_attached_to_seas.append(sea_dev.primary_vea.name) for vea in sea_dev.additional_veas: veas_attached_to_seas.append(vea.name) # Any VEA not on an SEA is considered an orphan self._find_orphaned_veas(vios, virt_eths, veas_attached_to_seas, dom_factory) # Return True if adapters were found if len(seas_found.values()) > 0: ras.trace(LOG, __name__, ras.TRACE_DEBUG, "SEA discover finished successfully.") return True ras.trace(LOG, __name__, ras.TRACE_ERROR, ras.vif_get_msg("error", "VIOS_NOSEA")) raise excp.IBMPowerVMValidSEANotFound() except pvmexcp.IBMPowerVMCommandFailed: ras.trace(LOG, __name__, ras.TRACE_EXCEPTION, ras.vif_get_msg("error", "VIOS_CMDFAIL") % {"cmd": cmd}) return False except Exception as e: ras.trace( LOG, __name__, ras.TRACE_EXCEPTION, ras.vif_get_msg("error", "VIOS_UNKNOWN") + " (" + _("%s") % e + ")" ) return False