X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FRO.git;a=blobdiff_plain;f=RO-VIM-openstack%2Fosm_rovim_openstack%2Fvimconn_openstack.py;h=289c8278e5669e662e91db4958082a8e4be28fd3;hp=ba8b004cf4bd7bc3dc48c72b160e699033c595ee;hb=1ec592d80c7f07874b08a14984deb21fddb31441;hpb=d60bdd09bf04c8e7add7c7bfe2cfd0d74113db40 diff --git a/RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py b/RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py index ba8b004c..289c8278 100644 --- a/RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py +++ b/RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py @@ -18,7 +18,7 @@ # under the License. ## -''' +""" osconnector implements all the methods to interact with openstack using the python-neutronclient. For the VNF forwarding graph, The OpenStack VIM connector calls the @@ -28,9 +28,7 @@ to the VIM connector's SFC resources as follows: - Service Function Instance (OSM) -> Port Pair (Neutron) - Service Function (OSM) -> Port Pair Group (Neutron) - Service Function Path (OSM) -> Port Chain (Neutron) -''' -__author__ = "Alfonso Tierno, Gerardo Garcia, Pablo Montes, xFlow Research, Igor D.C., Eduardo Sousa" -__date__ = "$22-sep-2017 23:59:59$" +""" from osm_ro_plugin import vimconn # import json @@ -51,27 +49,35 @@ import keystoneclient.v3.client as ksClient_v3 import keystoneclient.v2_0.client as ksClient_v2 from glanceclient import client as glClient import glanceclient.exc as gl1Exceptions -from cinderclient import client as cClient -from http.client import HTTPException # TODO py3 check that this base exception matches python2 httplib.HTTPException +from cinderclient import client as cClient +from http.client import HTTPException # TODO py3 check that this base exception matches python2 httplib.HTTPException from neutronclient.neutron import client as neClient from neutronclient.common import exceptions as neExceptions from requests.exceptions import ConnectionError +__author__ = "Alfonso Tierno, Gerardo Garcia, Pablo Montes, xFlow Research, Igor D.C., Eduardo Sousa" +__date__ = "$22-sep-2017 23:59:59$" """contain the openstack virtual machine status to openmano status""" -vmStatus2manoFormat={'ACTIVE':'ACTIVE', - 'PAUSED':'PAUSED', - 'SUSPENDED': 'SUSPENDED', - 'SHUTOFF':'INACTIVE', - 'BUILD':'BUILD', - 'ERROR':'ERROR','DELETED':'DELETED' - } -netStatus2manoFormat={'ACTIVE':'ACTIVE','PAUSED':'PAUSED','INACTIVE':'INACTIVE','BUILD':'BUILD','ERROR':'ERROR','DELETED':'DELETED' - } +vmStatus2manoFormat = {'ACTIVE': 'ACTIVE', + 'PAUSED': 'PAUSED', + 'SUSPENDED': 'SUSPENDED', + 'SHUTOFF': 'INACTIVE', + 'BUILD': 'BUILD', + 'ERROR': 'ERROR', + 'DELETED': 'DELETED' + } +netStatus2manoFormat = {'ACTIVE': 'ACTIVE', + 'PAUSED': 'PAUSED', + 'INACTIVE': 'INACTIVE', + 'BUILD': 'BUILD', + 'ERROR': 'ERROR', + 'DELETED': 'DELETED' + } supportedClassificationTypes = ['legacy_flow_classifier'] -#global var to have a timeout creating and deleting volumes +# global var to have a timeout creating and deleting volumes volume_timeout = 1800 server_timeout = 1800 @@ -90,10 +96,10 @@ class SafeDumper(yaml.SafeDumper): class vimconnector(vimconn.VimConnector): def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None, log_level=None, config={}, persistent_info={}): - '''using common constructor parameters. In this case + """using common constructor parameters. In this case 'url' is the keystone authorization url, 'url_admin' is not use - ''' + """ api_version = config.get('APIversion') if api_version and api_version not in ('v3.3', 'v2.0', '2', '3'): raise vimconn.VimConnException("Invalid value '{}' for config:APIversion. " @@ -101,14 +107,14 @@ class vimconnector(vimconn.VimConnector): vim_type = config.get('vim_type') if vim_type and vim_type not in ('vio', 'VIO'): raise vimconn.VimConnException("Invalid value '{}' for config:vim_type." - "Allowed values are 'vio' or 'VIO'".format(vim_type)) + "Allowed values are 'vio' or 'VIO'".format(vim_type)) if config.get('dataplane_net_vlan_range') is not None: - #validate vlan ranges provided by user + # validate vlan ranges provided by user self._validate_vlan_ranges(config.get('dataplane_net_vlan_range'), 'dataplane_net_vlan_range') if config.get('multisegment_vlan_range') is not None: - #validate vlan ranges provided by user + # validate vlan ranges provided by user self._validate_vlan_ranges(config.get('multisegment_vlan_range'), 'multisegment_vlan_range') vimconn.VimConnector.__init__(self, uuid, name, tenant_id, tenant_name, url, url_admin, user, passwd, log_level, @@ -153,12 +159,12 @@ class vimconnector(vimconn.VimConnector): self.config['security_groups'] = [self.config['security_groups']] self.security_groups_id = None - ####### VIO Specific Changes ######### + # ###### VIO Specific Changes ######### if self.vim_type == "VIO": self.logger = logging.getLogger('openmano.vim.vio') if log_level: - self.logger.setLevel( getattr(logging, log_level)) + self.logger.setLevel(getattr(logging, log_level)) def __getitem__(self, index): """Get individuals parameters. @@ -176,7 +182,7 @@ class vimconnector(vimconn.VimConnector): if index == 'project_domain_id': self.config["project_domain_id"] = value elif index == 'user_domain_id': - self.config["user_domain_id"] = value + self.config["user_domain_id"] = value else: vimconn.VimConnector.__setitem__(self, index, value) self.session['reload_client'] = True @@ -195,20 +201,20 @@ class vimconnector(vimconn.VimConnector): return yaml.dump(value, Dumper=SafeDumper, default_flow_style=True, width=256) except yaml.representer.RepresenterError: - self.logger.debug('The following entity cannot be serialized in YAML:\n\n%s\n\n', pformat(value), - exc_info=True) - return str(value) + self.logger.debug('The following entity cannot be serialized in YAML:\n\n%s\n\n', pformat(value), + exc_info=True) + return str(value) def _reload_connection(self): - '''Called before any operation, it check if credentials has changed + """Called before any operation, it check if credentials has changed Throw keystoneclient.apiclient.exceptions.AuthorizationFailure - ''' - #TODO control the timing and possible token timeout, but it seams that python client does this task for us :-) + """ + # TODO control the timing and possible token timeout, but it seams that python client does this task for us :-) if self.session['reload_client']: if self.config.get('APIversion'): self.api_version3 = self.config['APIversion'] == 'v3.3' or self.config['APIversion'] == '3' else: # get from ending auth_url that end with v3 or with v2.0 - self.api_version3 = self.url.endswith("/v3") or self.url.endswith("/v3/") + self.api_version3 = self.url.endswith("/v3") or self.url.endswith("/v3/") self.session['api_version3'] = self.api_version3 if self.api_version3: if self.config.get('project_domain_id') or self.config.get('project_domain_name'): @@ -235,10 +241,12 @@ class vimconnector(vimconn.VimConnector): tenant_name=self.tenant_name, tenant_id=self.tenant_id) sess = session.Session(auth=auth, verify=self.verify) - # addedd region_name to keystone, nova, neutron and cinder to support distributed cloud for Wind River Titanium cloud and StarlingX + # addedd region_name to keystone, nova, neutron and cinder to support distributed cloud for Wind River + # Titanium cloud and StarlingX region_name = self.config.get('region_name') if self.api_version3: - self.keystone = ksClient_v3.Client(session=sess, endpoint_type=self.endpoint_type, region_name=region_name) + self.keystone = ksClient_v3.Client(session=sess, endpoint_type=self.endpoint_type, + region_name=region_name) else: self.keystone = ksClient_v2.Client(session=sess, endpoint_type=self.endpoint_type) self.session['keystone'] = self.keystone @@ -251,13 +259,18 @@ class vimconnector(vimconn.VimConnector): version = self.config.get("microversion") if not version: version = "2.1" - # addedd region_name to keystone, nova, neutron and cinder to support distributed cloud for Wind River Titanium cloud and StarlingX - self.nova = self.session['nova'] = nClient.Client(str(version), session=sess, endpoint_type=self.endpoint_type, region_name=region_name) - self.neutron = self.session['neutron'] = neClient.Client('2.0', session=sess, endpoint_type=self.endpoint_type, region_name=region_name) - self.cinder = self.session['cinder'] = cClient.Client(2, session=sess, endpoint_type=self.endpoint_type, region_name=region_name) + # addedd region_name to keystone, nova, neutron and cinder to support distributed cloud for Wind River + # Titanium cloud and StarlingX + self.nova = self.session['nova'] = nClient.Client(str(version), session=sess, + endpoint_type=self.endpoint_type, region_name=region_name) + self.neutron = self.session['neutron'] = neClient.Client('2.0', session=sess, + endpoint_type=self.endpoint_type, + region_name=region_name) + self.cinder = self.session['cinder'] = cClient.Client(2, session=sess, endpoint_type=self.endpoint_type, + region_name=region_name) try: self.my_tenant_id = self.session['my_tenant_id'] = sess.get_project_id() - except Exception as e: + except Exception: self.logger.error("Cannot get project_id from session", exc_info=True) if self.endpoint_type == "internalURL": glance_service_id = self.keystone.services.list(name="glance")[0].id @@ -276,19 +289,19 @@ class vimconnector(vimconn.VimConnector): self.security_groups_id = None # force to get again security_groups_ids next time they are needed def __net_os2mano(self, net_list_dict): - '''Transform the net openstack format to mano format - net_list_dict can be a list of dict or a single dict''' + """Transform the net openstack format to mano format + net_list_dict can be a list of dict or a single dict""" if type(net_list_dict) is dict: - net_list_=(net_list_dict,) + net_list_ = (net_list_dict,) elif type(net_list_dict) is list: - net_list_=net_list_dict + net_list_ = net_list_dict else: raise TypeError("param net_list_dict must be a list or a dictionary") for net in net_list_: if net.get('provider:network_type') == "vlan": - net['type']='data' + net['type'] = 'data' else: - net['type']='bridge' + net['type'] = 'bridge' def __classification_os2mano(self, class_list_dict): """Transform the openstack format (Flow Classifier) to mano format @@ -299,8 +312,7 @@ class vimconnector(vimconn.VimConnector): elif isinstance(class_list_dict, list): class_list_ = class_list_dict else: - raise TypeError( - "param class_list_dict must be a list or a dictionary") + raise TypeError("param class_list_dict must be a list or a dictionary") for classification in class_list_: id = classification.pop('id') name = classification.pop('name') @@ -447,13 +459,13 @@ class vimconnector(vimconn.VimConnector): self.get_network_list(filter_dict={}) def get_tenant_list(self, filter_dict={}): - '''Obtain tenants of VIM + """Obtain tenants of VIM filter_dict can contain the following keys: name: filter by tenant name id: filter by tenant uuid/id Returns the tenant list of dictionaries: [{'name':', 'id':', ...}, ...] - ''' + """ self.logger.debug("Getting tenants from VIM filter: '%s'", str(filter_dict)) try: self._reload_connection() @@ -461,7 +473,7 @@ class vimconnector(vimconn.VimConnector): project_class_list = self.keystone.projects.list(name=filter_dict.get("name")) else: project_class_list = self.keystone.tenants.findall(**filter_dict) - project_list=[] + project_list = [] for project in project_class_list: if filter_dict.get('id') and filter_dict["id"] != project.id: continue @@ -471,7 +483,7 @@ class vimconnector(vimconn.VimConnector): self._format_exception(e) def new_tenant(self, tenant_name, tenant_description): - '''Adds a new tenant to openstack VIM. Returns the tenant identifier''' + """Adds a new tenant to openstack VIM. Returns the tenant identifier""" self.logger.debug("Adding a new tenant name: %s", tenant_name) try: self._reload_connection() @@ -481,11 +493,12 @@ class vimconnector(vimconn.VimConnector): else: project = self.keystone.tenants.create(tenant_name, tenant_description) return project.id - except (ksExceptions.ConnectionError, ksExceptions.ClientException, ksExceptions.BadRequest, ConnectionError) as e: + except (ksExceptions.ConnectionError, ksExceptions.ClientException, ksExceptions.BadRequest, ConnectionError)\ + as e: self._format_exception(e) def delete_tenant(self, tenant_id): - '''Delete a tenant from openstack VIM. Returns the old tenant identifier''' + """Delete a tenant from openstack VIM. Returns the old tenant identifier""" self.logger.debug("Deleting tenant %s from VIM", tenant_id) try: self._reload_connection() @@ -494,7 +507,8 @@ class vimconnector(vimconn.VimConnector): else: self.keystone.tenants.delete(tenant_id) return tenant_id - except (ksExceptions.ConnectionError, ksExceptions.ClientException, ksExceptions.NotFound, ConnectionError) as e: + except (ksExceptions.ConnectionError, ksExceptions.ClientException, ksExceptions.NotFound, ConnectionError)\ + as e: self._format_exception(e) def new_network(self, net_name, net_type, ip_profile=None, shared=False, provider_network_profile=None): @@ -561,7 +575,7 @@ class vimconnector(vimconn.VimConnector): if provider_network_profile and "network-type" in provider_network_profile: network_dict["provider:network_type"] = provider_network_profile["network-type"] else: - network_dict["provider:network_type"] = self.config.get('dataplane_network_type','vlan') + network_dict["provider:network_type"] = self.config.get('dataplane_network_type', 'vlan') if vlan: network_dict["provider:segmentation_id"] = vlan else: @@ -583,7 +597,8 @@ class vimconnector(vimconn.VimConnector): segment2_dict["provider:segmentation_id"] = vlanID # else # raise vimconn.VimConnConflictException( - # "You must provide 'multisegment_vlan_range' at config dict before creating a multisegment network") + # "You must provide 'multisegment_vlan_range' at config dict before creating a multisegment + # network") segment_list.append(segment2_dict) network_dict["segments"] = segment_list @@ -598,22 +613,22 @@ class vimconnector(vimconn.VimConnector): network_dict["shared"] = shared if self.config.get("disable_network_port_security"): network_dict["port_security_enabled"] = False - new_net = self.neutron.create_network({'network':network_dict}) + new_net = self.neutron.create_network({'network': network_dict}) # print new_net # create subnetwork, even if there is no profile if not ip_profile: ip_profile = {} if not ip_profile.get('subnet_address'): - #Fake subnet is required + # Fake subnet is required subnet_rand = random.randint(0, 255) ip_profile['subnet_address'] = "192.168.{}.0/24".format(subnet_rand) if 'ip_version' not in ip_profile: ip_profile['ip_version'] = "IPv4" subnet = {"name": net_name+"-subnet", - "network_id": new_net["network"]["id"], - "ip_version": 4 if ip_profile['ip_version']=="IPv4" else 6, - "cidr": ip_profile['subnet_address'] - } + "network_id": new_net["network"]["id"], + "ip_version": 4 if ip_profile['ip_version'] == "IPv4" else 6, + "cidr": ip_profile['subnet_address'] + } # Gateway should be set to None if not needed. Otherwise openstack assigns one by default if ip_profile.get('gateway_address'): subnet['gateway_ip'] = ip_profile['gateway_address'] @@ -623,34 +638,35 @@ class vimconnector(vimconn.VimConnector): subnet['dns_nameservers'] = ip_profile['dns_address'].split(";") if 'dhcp_enabled' in ip_profile: subnet['enable_dhcp'] = False if \ - ip_profile['dhcp_enabled']=="false" or ip_profile['dhcp_enabled']==False else True + ip_profile['dhcp_enabled'] == "false" or ip_profile['dhcp_enabled'] is False else True if ip_profile.get('dhcp_start_address'): subnet['allocation_pools'] = [] subnet['allocation_pools'].append(dict()) subnet['allocation_pools'][0]['start'] = ip_profile['dhcp_start_address'] if ip_profile.get('dhcp_count'): - #parts = ip_profile['dhcp_start_address'].split('.') - #ip_int = (int(parts[0]) << 24) + (int(parts[1]) << 16) + (int(parts[2]) << 8) + int(parts[3]) + # parts = ip_profile['dhcp_start_address'].split('.') + # ip_int = (int(parts[0]) << 24) + (int(parts[1]) << 16) + (int(parts[2]) << 8) + int(parts[3]) ip_int = int(netaddr.IPAddress(ip_profile['dhcp_start_address'])) ip_int += ip_profile['dhcp_count'] - 1 ip_str = str(netaddr.IPAddress(ip_int)) subnet['allocation_pools'][0]['end'] = ip_str - #self.logger.debug(">>>>>>>>>>>>>>>>>> Subnet: %s", str(subnet)) - self.neutron.create_subnet({"subnet": subnet} ) + # self.logger.debug(">>>>>>>>>>>>>>>>>> Subnet: %s", str(subnet)) + self.neutron.create_subnet({"subnet": subnet}) if net_type == "data" and self.config.get('multisegment_support'): if self.config.get('l2gw_support'): l2gw_list = self.neutron.list_l2_gateways().get("l2_gateways", ()) for l2gw in l2gw_list: - l2gw_conn = {} - l2gw_conn["l2_gateway_id"] = l2gw["id"] - l2gw_conn["network_id"] = new_net["network"]["id"] - l2gw_conn["segmentation_id"] = str(vlanID) + l2gw_conn = { + "l2_gateway_id": l2gw["id"], + "network_id": new_net["network"]["id"], + "segmentation_id": str(vlanID), + } new_l2gw_conn = self.neutron.create_l2_gateway_connection({"l2_gateway_connection": l2gw_conn}) created_items["l2gwconn:" + str(new_l2gw_conn["l2_gateway_connection"]["id"])] = True return new_net["network"]["id"], created_items except Exception as e: - #delete l2gw connections (if any) before deleting the network + # delete l2gw connections (if any) before deleting the network for k, v in created_items.items(): if not v: # skip already deleted continue @@ -665,7 +681,7 @@ class vimconnector(vimconn.VimConnector): self._format_exception(e) def get_network_list(self, filter_dict={}): - '''Obtain tenant networks of VIM + """Obtain tenant networks of VIM Filter_dict can be: name: network name id: network uuid @@ -674,33 +690,34 @@ class vimconnector(vimconn.VimConnector): admin_state_up: boolean status: 'ACTIVE' Returns the network list of dictionaries - ''' + """ self.logger.debug("Getting network from VIM filter: '%s'", str(filter_dict)) try: self._reload_connection() filter_dict_os = filter_dict.copy() if self.api_version3 and "tenant_id" in filter_dict_os: - filter_dict_os['project_id'] = filter_dict_os.pop('tenant_id') #T ODO check + filter_dict_os['project_id'] = filter_dict_os.pop('tenant_id') # TODO check net_dict = self.neutron.list_networks(**filter_dict_os) net_list = net_dict["networks"] self.__net_os2mano(net_list) return net_list - except (neExceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException, ConnectionError) as e: + except (neExceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException, + ConnectionError) as e: self._format_exception(e) def get_network(self, net_id): - '''Obtain details of network from VIM - Returns the network information from a network id''' + """Obtain details of network from VIM + Returns the network information from a network id""" self.logger.debug(" Getting tenant network %s from VIM", net_id) - filter_dict={"id": net_id} + filter_dict = {"id": net_id} net_list = self.get_network_list(filter_dict) - if len(net_list)==0: + if len(net_list) == 0: raise vimconn.VimConnNotFoundException("Network '{}' not found".format(net_id)) - elif len(net_list)>1: + elif len(net_list) > 1: raise vimconn.VimConnConflictException("Found more than one network with this criteria") net = net_list[0] - subnets=[] - for subnet_id in net.get("subnets", () ): + subnets = [] + for subnet_id in net.get("subnets", ()): try: subnet = self.neutron.show_subnet(subnet_id) except Exception as e: @@ -722,11 +739,11 @@ class vimconnector(vimconn.VimConnector): Returns the network identifier or raises an exception upon error or when network is not found """ self.logger.debug("Deleting network '%s' from VIM", net_id) - if created_items == None: + if created_items is None: created_items = {} try: self._reload_connection() - #delete l2gw connections (if any) before deleting the network + # delete l2gw connections (if any) before deleting the network for k, v in created_items.items(): if not v: # skip already deleted continue @@ -736,7 +753,7 @@ class vimconnector(vimconn.VimConnector): self.neutron.delete_l2_gateway_connection(k_id) except Exception as e: self.logger.error("Error deleting l2 gateway connection: {}: {}".format(type(e).__name__, e)) - #delete VM ports attached to this networks before the network + # delete VM ports attached to this networks before the network ports = self.neutron.list_ports(network_id=net_id) for p in ports['ports']: try: @@ -750,7 +767,7 @@ class vimconnector(vimconn.VimConnector): self._format_exception(e) def refresh_nets_status(self, net_list): - '''Get the status of the networks + """Get the status of the networks Params: the list of network identifiers Returns a dictionary with: net_id: #VIM id of this network @@ -765,14 +782,14 @@ class vimconnector(vimconn.VimConnector): error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR vim_info: #Text with plain information obtained from vim (yaml.safe_dump) - ''' - net_dict={} + """ + net_dict = {} for net_id in net_list: net = {} try: net_vim = self.get_network(net_id) if net_vim['status'] in netStatus2manoFormat: - net["status"] = netStatus2manoFormat[ net_vim['status'] ] + net["status"] = netStatus2manoFormat[net_vim['status']] else: net["status"] = "OTHER" net["error_msg"] = "VIM status reported " + net_vim['status'] @@ -782,7 +799,7 @@ class vimconnector(vimconn.VimConnector): net['vim_info'] = self.serialize(net_vim) - if net_vim.get('fault'): #TODO + if net_vim.get('fault'): # TODO net['error_msg'] = str(net_vim['fault']) except vimconn.VimConnNotFoundException as e: self.logger.error("Exception getting net status: %s", str(e)) @@ -796,14 +813,15 @@ class vimconnector(vimconn.VimConnector): return net_dict def get_flavor(self, flavor_id): - '''Obtain flavor details from the VIM. Returns the flavor dict details''' + """Obtain flavor details from the VIM. Returns the flavor dict details""" self.logger.debug("Getting flavor '%s'", flavor_id) try: self._reload_connection() flavor = self.nova.flavors.find(id=flavor_id) - #TODO parse input and translate to VIM format (openmano_schemas.new_vminstance_response_schema) + # TODO parse input and translate to VIM format (openmano_schemas.new_vminstance_response_schema) return flavor.to_dict() - except (nvExceptions.NotFound, nvExceptions.ClientException, ksExceptions.ClientException, ConnectionError) as e: + except (nvExceptions.NotFound, nvExceptions.ClientException, ksExceptions.ClientException, + ConnectionError) as e: self._format_exception(e) def get_flavor_id_from_data(self, flavor_dict): @@ -823,7 +841,7 @@ class vimconnector(vimconn.VimConnector): # numa=None extended = flavor_dict.get("extended", {}) if extended: - #TODO + # TODO raise vimconn.VimConnNotFoundException("Flavor with EPA still not implemented") # if len(numas) > 1: # raise vimconn.VimConnNotFoundException("Cannot find any flavor with more than one numa") @@ -842,8 +860,9 @@ class vimconnector(vimconn.VimConnector): flavor_candidate_data = flavor_data if not exact_match and flavor_candidate_id: return flavor_candidate_id - raise vimconn.VimConnNotFoundException("Cannot find any flavor matching '{}'".format(str(flavor_dict))) - except (nvExceptions.NotFound, nvExceptions.ClientException, ksExceptions.ClientException, ConnectionError) as e: + raise vimconn.VimConnNotFoundException("Cannot find any flavor matching '{}'".format(flavor_dict)) + except (nvExceptions.NotFound, nvExceptions.ClientException, ksExceptions.ClientException, + ConnectionError) as e: self._format_exception(e) def process_resource_quota(self, quota, prefix, extra_specs): @@ -861,37 +880,38 @@ class vimconnector(vimconn.VimConnector): extra_specs["quota:" + prefix + "_shares_share"] = quota['shares'] def new_flavor(self, flavor_data, change_name_if_used=True): - '''Adds a tenant flavor to openstack VIM - if change_name_if_used is True, it will change name in case of conflict, because it is not supported name repetition + """Adds a tenant flavor to openstack VIM + if change_name_if_used is True, it will change name in case of conflict, because it is not supported name + repetition Returns the flavor identifier - ''' + """ self.logger.debug("Adding flavor '%s'", str(flavor_data)) - retry=0 - max_retries=3 + retry = 0 + max_retries = 3 name_suffix = 0 try: - name=flavor_data['name'] - while retry 1: @@ -904,31 +924,37 @@ class vimconnector(vimconn.VimConnector): extra_specs["vmware:extra_config"] = '{"numa.nodeAffinity":"0"}' extra_specs["vmware:latency_sensitivity_level"] = "high" for numa in numas: - #overwrite ram and vcpus - #check if key 'memory' is present in numa else use ram value at flavor + # overwrite ram and vcpus + # check if key 'memory' is present in numa else use ram value at flavor if 'memory' in numa: ram = numa['memory']*1024 - #See for reference: https://specs.openstack.org/openstack/nova-specs/specs/mitaka/implemented/virt-driver-cpu-thread-pinning.html + # See for reference: https://specs.openstack.org/openstack/nova-specs/specs/mitaka/ + # implemented/virt-driver-cpu-thread-pinning.html extra_specs["hw:cpu_sockets"] = 1 if 'paired-threads' in numa: vcpus = numa['paired-threads']*2 - #cpu_thread_policy "require" implies that the compute node must have an STM architecture + # cpu_thread_policy "require" implies that the compute node must have an + # STM architecture extra_specs["hw:cpu_thread_policy"] = "require" extra_specs["hw:cpu_policy"] = "dedicated" elif 'cores' in numa: vcpus = numa['cores'] - # cpu_thread_policy "prefer" implies that the host must not have an SMT architecture, or a non-SMT architecture will be emulated + # cpu_thread_policy "prefer" implies that the host must not have an SMT + # architecture, or a non-SMT architecture will be emulated extra_specs["hw:cpu_thread_policy"] = "isolate" extra_specs["hw:cpu_policy"] = "dedicated" elif 'threads' in numa: vcpus = numa['threads'] - # cpu_thread_policy "prefer" implies that the host may or may not have an SMT architecture + # cpu_thread_policy "prefer" implies that the host may or may not have an SMT + # architecture extra_specs["hw:cpu_thread_policy"] = "prefer" extra_specs["hw:cpu_policy"] = "dedicated" # for interface in numa.get("interfaces",() ): # if interface["dedicated"]=="yes": - # raise vimconn.VimConnException("Passthrough interfaces are not supported for the openstack connector", http_code=vimconn.HTTP_Service_Unavailable) - # #TODO, add the key 'pci_passthrough:alias"="