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 _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)
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 _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
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
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
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__()
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)
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 _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
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 _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 __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
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 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))
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)
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))
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'))
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)
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)
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
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, ) ]
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
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 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
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_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)