X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=osm_ro%2Fvimconn_openstack.py;h=fd16f544d2cc721d32ea8054af3dac72d55f169e;hb=69b590eb0469efa021bada0d2bf867bbdff27a10;hp=24033da783fafa2ef878b4d75ad7242b80053b87;hpb=98e909c77827a222ad5658554dee51ecffbdaff0;p=osm%2FRO.git diff --git a/osm_ro/vimconn_openstack.py b/osm_ro/vimconn_openstack.py index 24033da7..fd16f544 100644 --- a/osm_ro/vimconn_openstack.py +++ b/osm_ro/vimconn_openstack.py @@ -36,7 +36,7 @@ __author__ = "Alfonso Tierno, Gerardo Garcia, Pablo Montes, xFlow Research, Igor __date__ = "$22-sep-2017 23:59:59$" import vimconn -import json +# import json import logging import netaddr import time @@ -75,8 +75,8 @@ netStatus2manoFormat={'ACTIVE':'ACTIVE','PAUSED':'PAUSED','INACTIVE':'INACTIVE', supportedClassificationTypes = ['legacy_flow_classifier'] #global var to have a timeout creating and deleting volumes -volume_timeout = 60 -server_timeout = 300 +volume_timeout = 600 +server_timeout = 600 class vimconnector(vimconn.vimconnector): def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None, @@ -493,10 +493,11 @@ class vimconnector(vimconn.vimconnector): self.logger.debug("Getting network from VIM filter: '%s'", str(filter_dict)) try: self._reload_connection() - if self.api_version3 and "tenant_id" in filter_dict: - filter_dict['project_id'] = filter_dict.pop('tenant_id') #TODO check - net_dict=self.neutron.list_networks(**filter_dict) - net_list=net_dict["networks"] + 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 + 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: @@ -686,7 +687,9 @@ class vimconnector(vimconn.vimconnector): numa_properties["vmware:latency_sensitivity_level"] = "high" for numa in numas: #overwrite ram and vcpus - ram = numa['memory']*1024 + #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 if 'paired-threads' in numa: vcpus = numa['paired-threads']*2 @@ -712,7 +715,7 @@ class vimconnector(vimconn.vimconnector): new_flavor=self.nova.flavors.create(name, ram, vcpus, - flavor_data.get('disk',1), + flavor_data.get('disk',0), is_public=flavor_data.get('is_public', True) ) #add metadata @@ -838,9 +841,9 @@ class vimconnector(vimconn.vimconnector): self.logger.debug("Getting image list from VIM filter: '%s'", str(filter_dict)) try: self._reload_connection() - filter_dict_os=filter_dict.copy() + filter_dict_os = filter_dict.copy() #First we filter by the available filter fields: name, id. The others are removed. - filter_dict_os.pop('checksum',None) + filter_dict_os.pop('checksum', None) image_list = self.nova.images.findall(**filter_dict_os) if len(image_list) == 0: return [] @@ -849,7 +852,7 @@ class vimconnector(vimconn.vimconnector): for image in image_list: try: image_class = self.glance.images.get(image.id) - if 'checksum' not in filter_dict or image_class['checksum']==filter_dict.get('checksum'): + if 'checksum' not in filter_dict or image_class['checksum'] == filter_dict.get('checksum'): filtered_list.append(image_class.copy()) except gl1Exceptions.HTTPNotFound: pass @@ -947,7 +950,7 @@ class vimconnector(vimconn.vimconnector): model: interface model, ignored #TODO mac_address: used for SR-IOV ifaces #TODO for other types use: 'data', 'bridge', 'mgmt' - type: 'virtual', 'PF', 'VF', 'VFnotShared' + type: 'virtual', 'PCI-PASSTHROUGH'('PF'), 'SR-IOV'('VF'), 'VFnotShared' vim_id: filled/added by this function floating_ip: True/False (or it can be None) 'cloud_config': (optional) dictionary with: @@ -981,12 +984,12 @@ class vimconnector(vimconn.vimconnector): try: server = None created_items = {} - metadata = {} + # metadata = {} net_list_vim = [] external_network = [] # list of external networks to be connected to instance, later on used to create floating_ip no_secured_ports = [] # List of port-is with port-security disabled self._reload_connection() - metadata_vpci = {} # For a specific neutron plugin + # metadata_vpci = {} # For a specific neutron plugin block_device_mapping = None for net in net_list: if not net.get("net_id"): # skip non connected iface @@ -998,38 +1001,40 @@ class vimconnector(vimconn.vimconnector): "admin_state_up": True } if net["type"]=="virtual": - if "vpci" in net: - metadata_vpci[ net["net_id"] ] = [[ net["vpci"], "" ]] - elif net["type"]=="VF": # for VF - if "vpci" in net: - if "VF" not in metadata_vpci: - metadata_vpci["VF"]=[] - metadata_vpci["VF"].append([ net["vpci"], "" ]) + pass + # if "vpci" in net: + # metadata_vpci[ net["net_id"] ] = [[ net["vpci"], "" ]] + elif net["type"] == "VF" or net["type"] == "SR-IOV": # for VF + # if "vpci" in net: + # if "VF" not in metadata_vpci: + # metadata_vpci["VF"]=[] + # metadata_vpci["VF"].append([ net["vpci"], "" ]) port_dict["binding:vnic_type"]="direct" - ########## VIO specific Changes ####### + # VIO specific Changes if self.vim_type == "VIO": - #Need to create port with port_security_enabled = False and no-security-groups + # Need to create port with port_security_enabled = False and no-security-groups port_dict["port_security_enabled"]=False port_dict["provider_security_groups"]=[] port_dict["security_groups"]=[] - else: #For PT - ########## VIO specific Changes ####### - #Current VIO release does not support port with type 'direct-physical' - #So no need to create virtual port in case of PCI-device. - #Will update port_dict code when support gets added in next VIO release + else: # For PT PCI-PASSTHROUGH + # VIO specific Changes + # Current VIO release does not support port with type 'direct-physical' + # So no need to create virtual port in case of PCI-device. + # Will update port_dict code when support gets added in next VIO release if self.vim_type == "VIO": - raise vimconn.vimconnNotSupportedException("Current VIO release does not support full passthrough (PT)") - if "vpci" in net: - if "PF" not in metadata_vpci: - metadata_vpci["PF"]=[] - metadata_vpci["PF"].append([ net["vpci"], "" ]) + raise vimconn.vimconnNotSupportedException( + "Current VIO release does not support full passthrough (PT)") + # if "vpci" in net: + # if "PF" not in metadata_vpci: + # metadata_vpci["PF"]=[] + # metadata_vpci["PF"].append([ net["vpci"], "" ]) port_dict["binding:vnic_type"]="direct-physical" if not port_dict["name"]: port_dict["name"]=name if net.get("mac_address"): port_dict["mac_address"]=net["mac_address"] new_port = self.neutron.create_port({"port": port_dict }) - created_items[("port", str(new_port["port"]["id"]))] = True + created_items["port:" + str(new_port["port"]["id"])] = True net["mac_adress"] = new_port["port"]["mac_address"] net["vim_id"] = new_port["port"]["id"] # if try to use a network without subnetwork, it will return a emtpy list @@ -1056,18 +1061,18 @@ class vimconnector(vimconn.vimconnector): if net.get("port_security") == False: no_secured_ports.append(new_port["port"]["id"]) - if metadata_vpci: - metadata = {"pci_assignement": json.dumps(metadata_vpci)} - if len(metadata["pci_assignement"]) >255: - #limit the metadata size - #metadata["pci_assignement"] = metadata["pci_assignement"][0:255] - self.logger.warn("Metadata deleted since it exceeds the expected length (255) ") - metadata = {} + # if metadata_vpci: + # metadata = {"pci_assignement": json.dumps(metadata_vpci)} + # if len(metadata["pci_assignement"]) >255: + # #limit the metadata size + # #metadata["pci_assignement"] = metadata["pci_assignement"][0:255] + # self.logger.warn("Metadata deleted since it exceeds the expected length (255) ") + # metadata = {} - self.logger.debug("name '%s' image_id '%s'flavor_id '%s' net_list_vim '%s' description '%s' metadata %s", - name, image_id, flavor_id, str(net_list_vim), description, str(metadata)) + self.logger.debug("name '%s' image_id '%s'flavor_id '%s' net_list_vim '%s' description '%s'", + name, image_id, flavor_id, str(net_list_vim), description) - security_groups = self.config.get('security_groups') + security_groups = self.config.get('security_groups') if type(security_groups) is str: security_groups = ( security_groups, ) # cloud config @@ -1084,11 +1089,11 @@ class vimconnector(vimconn.vimconnector): else: volume = self.cinder.volumes.create(size=disk['size'], name=name + '_vd' + chr(base_disk_index)) - created_items[("volume", str(volume.id))] = True + created_items["volume:" + str(volume.id)] = True block_device_mapping['_vd' + chr(base_disk_index)] = volume.id base_disk_index += 1 - # wait until volumes are with status available + # Wait until volumes are with status available keep_waiting = True elapsed_time = 0 while keep_waiting and elapsed_time < volume_timeout: @@ -1100,19 +1105,19 @@ class vimconnector(vimconn.vimconnector): time.sleep(1) elapsed_time += 1 - # if we exceeded the timeout rollback + # If we exceeded the timeout rollback if elapsed_time >= volume_timeout: raise vimconn.vimconnException('Timeout creating volumes for instance ' + name, http_code=vimconn.HTTP_Request_Timeout) # get availability Zone vm_av_zone = self._get_vm_availability_zone(availability_zone_index, availability_zone_list) - self.logger.debug("nova.servers.create({}, {}, {}, nics={}, meta={}, security_groups={}, " + self.logger.debug("nova.servers.create({}, {}, {}, nics={}, security_groups={}, " "availability_zone={}, key_name={}, userdata={}, config_drive={}, " - "block_device_mapping={})".format(name, image_id, flavor_id, net_list_vim, metadata, + "block_device_mapping={})".format(name, image_id, flavor_id, net_list_vim, security_groups, vm_av_zone, self.config.get('keypair'), - userdata, config_drive, block_device_mapping)) - server = self.nova.servers.create(name, image_id, flavor_id, nics=net_list_vim, meta=metadata, + userdata, config_drive, block_device_mapping)) + server = self.nova.servers.create(name, image_id, flavor_id, nics=net_list_vim, security_groups=security_groups, availability_zone=vm_av_zone, key_name=self.config.get('keypair'), @@ -1279,10 +1284,11 @@ class vimconnector(vimconn.vimconnector): if not v: # skip already deleted continue try: - if k[0] == "port": - self.neutron.delete_port(k[1]) + k_item, _, k_id = k.partition(":") + if k_item == "port": + self.neutron.delete_port(k_id) except Exception as e: - self.logger.error("Error deleting port: " + type(e).__name__ + ": "+ str(e)) + self.logger.error("Error deleting port: {}: {}".format(type(e).__name__, e)) # #commented because detaching the volumes makes the servers.delete not work properly ?!? # #dettach volumes attached @@ -1304,13 +1310,14 @@ class vimconnector(vimconn.vimconnector): if not v: # skip already deleted continue try: - if k[0] == "volume": - if self.cinder.volumes.get(k[1]).status != 'available': + k_item, _, k_id = k.partition(":") + if k_item == "volume": + if self.cinder.volumes.get(k_id).status != 'available': keep_waiting = True else: - self.cinder.volumes.delete(k[1]) + self.cinder.volumes.delete(k_id) except Exception as e: - self.logger.error("Error deleting volume: " + type(e).__name__ + ": " + str(e)) + self.logger.error("Error deleting volume: {}: {}".format(type(e).__name__, e)) if keep_waiting: time.sleep(1) elapsed_time += 1 @@ -1685,7 +1692,7 @@ class vimconnector(vimconn.vimconnector): classification_dict = definition classification_dict['name'] = name - new_class = self.neutron.create_flow_classifier( + new_class = self.neutron.create_sfc_flow_classifier( {'flow_classifier': classification_dict}) return new_class['flow_classifier']['id'] except (neExceptions.ConnectionFailed, ksExceptions.ClientException, @@ -1711,11 +1718,12 @@ class vimconnector(vimconn.vimconnector): self.logger.debug("Getting Classifications from VIM filter: '%s'", str(filter_dict)) try: + filter_dict_os = filter_dict.copy() self._reload_connection() - if self.api_version3 and "tenant_id" in filter_dict: - filter_dict['project_id'] = filter_dict.pop('tenant_id') - classification_dict = self.neutron.list_flow_classifier( - **filter_dict) + if self.api_version3 and "tenant_id" in filter_dict_os: + filter_dict_os['project_id'] = filter_dict_os.pop('tenant_id') + classification_dict = self.neutron.list_sfc_flow_classifiers( + **filter_dict_os) classification_list = classification_dict["flow_classifiers"] self.__classification_os2mano(classification_list) return classification_list @@ -1727,7 +1735,7 @@ class vimconnector(vimconn.vimconnector): self.logger.debug("Deleting Classification '%s' from VIM", class_id) try: self._reload_connection() - self.neutron.delete_flow_classifier(class_id) + self.neutron.delete_sfc_flow_classifier(class_id) return class_id except (neExceptions.ConnectionFailed, neExceptions.NeutronException, ksExceptions.ClientException, neExceptions.NeutronException, @@ -1742,9 +1750,7 @@ class vimconnector(vimconn.vimconnector): self._reload_connection() correlation = None if sfc_encap: - # TODO(igordc): must be changed to NSH in Queens - # (MPLS is a workaround) - correlation = 'mpls' + correlation = 'nsh' if len(ingress_ports) != 1: raise vimconn.vimconnNotSupportedException( "OpenStack VIM connector can only have " @@ -1758,13 +1764,13 @@ class vimconnector(vimconn.vimconnector): 'egress': egress_ports[0], 'service_function_parameters': { 'correlation': correlation}} - new_sfi = self.neutron.create_port_pair({'port_pair': sfi_dict}) + new_sfi = self.neutron.create_sfc_port_pair({'port_pair': sfi_dict}) return new_sfi['port_pair']['id'] except (neExceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException, ConnectionError) as e: if new_sfi: try: - self.neutron.delete_port_pair_group( + self.neutron.delete_sfc_port_pair( new_sfi['port_pair']['id']) except Exception: self.logger.error( @@ -1792,9 +1798,10 @@ class vimconnector(vimconn.vimconnector): "VIM filter: '%s'", str(filter_dict)) try: self._reload_connection() - if self.api_version3 and "tenant_id" in filter_dict: - filter_dict['project_id'] = filter_dict.pop('tenant_id') - sfi_dict = self.neutron.list_port_pair(**filter_dict) + 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') + sfi_dict = self.neutron.list_sfc_port_pairs(**filter_dict_os) sfi_list = sfi_dict["port_pairs"] self.__sfi_os2mano(sfi_list) return sfi_list @@ -1807,7 +1814,7 @@ class vimconnector(vimconn.vimconnector): "from VIM", sfi_id) try: self._reload_connection() - self.neutron.delete_port_pair(sfi_id) + self.neutron.delete_sfc_port_pair(sfi_id) return sfi_id except (neExceptions.ConnectionFailed, neExceptions.NeutronException, ksExceptions.ClientException, neExceptions.NeutronException, @@ -1822,25 +1829,23 @@ class vimconnector(vimconn.vimconnector): self._reload_connection() correlation = None if sfc_encap: - # TODO(igordc): must be changed to NSH in Queens - # (MPLS is a workaround) - correlation = 'mpls' + correlation = 'nsh' for instance in sfis: sfi = self.get_sfi(instance) - if sfi.get('sfc_encap') != correlation: + if sfi.get('sfc_encap') != sfc_encap: raise vimconn.vimconnNotSupportedException( "OpenStack VIM connector requires all SFIs of the " "same SF to share the same SFC Encapsulation") sf_dict = {'name': name, 'port_pairs': sfis} - new_sf = self.neutron.create_port_pair_group({ + new_sf = self.neutron.create_sfc_port_pair_group({ 'port_pair_group': sf_dict}) return new_sf['port_pair_group']['id'] except (neExceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException, ConnectionError) as e: if new_sf: try: - self.neutron.delete_port_pair_group( + self.neutron.delete_sfc_port_pair_group( new_sf['port_pair_group']['id']) except Exception: self.logger.error( @@ -1866,9 +1871,10 @@ class vimconnector(vimconn.vimconnector): str(filter_dict)) try: self._reload_connection() - if self.api_version3 and "tenant_id" in filter_dict: - filter_dict['project_id'] = filter_dict.pop('tenant_id') - sf_dict = self.neutron.list_port_pair_group(**filter_dict) + 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') + sf_dict = self.neutron.list_sfc_port_pair_groups(**filter_dict_os) sf_list = sf_dict["port_pair_groups"] self.__sf_os2mano(sf_list) return sf_list @@ -1880,7 +1886,7 @@ class vimconnector(vimconn.vimconnector): self.logger.debug("Deleting Service Function '%s' from VIM", sf_id) try: self._reload_connection() - self.neutron.delete_port_pair_group(sf_id) + self.neutron.delete_sfc_port_pair_group(sf_id) return sf_id except (neExceptions.ConnectionFailed, neExceptions.NeutronException, ksExceptions.ClientException, neExceptions.NeutronException, @@ -1893,26 +1899,24 @@ class vimconnector(vimconn.vimconnector): try: new_sfp = None self._reload_connection() - if not sfc_encap: - raise vimconn.vimconnNotSupportedException( - "OpenStack VIM connector only supports " - "SFC-Encapsulated chains") - # TODO(igordc): must be changed to NSH in Queens - # (MPLS is a workaround) - correlation = 'mpls' + # In networking-sfc the MPLS encapsulation is legacy + # should be used when no full SFC Encapsulation is intended + sfc_encap = 'mpls' + if sfc_encap: + correlation = 'nsh' sfp_dict = {'name': name, 'flow_classifiers': classifications, 'port_pair_groups': sfs, 'chain_parameters': {'correlation': correlation}} if spi: sfp_dict['chain_id'] = spi - new_sfp = self.neutron.create_port_chain({'port_chain': sfp_dict}) + new_sfp = self.neutron.create_sfc_port_chain({'port_chain': sfp_dict}) return new_sfp["port_chain"]["id"] except (neExceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException, ConnectionError) as e: if new_sfp: try: - self.neutron.delete_port_chain(new_sfp['port_chain']['id']) + self.neutron.delete_sfc_port_chain(new_sfp['port_chain']['id']) except Exception: self.logger.error( 'Creation of Service Function Path failed, with ' @@ -1937,9 +1941,10 @@ class vimconnector(vimconn.vimconnector): "'%s'", str(filter_dict)) try: self._reload_connection() - if self.api_version3 and "tenant_id" in filter_dict: - filter_dict['project_id'] = filter_dict.pop('tenant_id') - sfp_dict = self.neutron.list_port_chain(**filter_dict) + 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') + sfp_dict = self.neutron.list_sfc_port_chains(**filter_dict_os) sfp_list = sfp_dict["port_chains"] self.__sfp_os2mano(sfp_list) return sfp_list @@ -1952,7 +1957,7 @@ class vimconnector(vimconn.vimconnector): "Deleting Service Function Path '%s' from VIM", sfp_id) try: self._reload_connection() - self.neutron.delete_port_chain(sfp_id) + self.neutron.delete_sfc_port_chain(sfp_id) return sfp_id except (neExceptions.ConnectionFailed, neExceptions.NeutronException, ksExceptions.ClientException, neExceptions.NeutronException,