X-Git-Url: https://osm.etsi.org/gitweb/?a=blobdiff_plain;f=osm_ro%2Fvimconn_openstack.py;h=fd16f544d2cc721d32ea8054af3dac72d55f169e;hb=refs%2Fchanges%2F80%2F5880%2F2;hp=e90497a6e49c223010307ac252b728fb6b377a5f;hpb=3cb8dc36bb85b97ccf0e930fc56494d38d4bfc7d;p=osm%2FRO.git diff --git a/osm_ro/vimconn_openstack.py b/osm_ro/vimconn_openstack.py index e90497a6..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 @@ -936,7 +939,7 @@ class vimconnector(vimconn.vimconnector): def new_vminstance(self, name, description, start, image_id, flavor_id, net_list, cloud_config=None, disk_list=None, availability_zone_index=None, availability_zone_list=None): - '''Adds a VM instance to VIM + """Adds a VM instance to VIM Params: start: indicates if VM must start or boot in pause mode. Ignored image_id,flavor_id: iamge and flavor uuid @@ -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: @@ -971,20 +974,25 @@ class vimconnector(vimconn.vimconnector): availability_zone_list: list of availability zones given by user in the VNFD descriptor. Ignore if availability_zone_index is None #TODO ip, security groups - Returns the instance identifier - ''' + Returns a tuple with the instance identifier and created_items or raises an exception on error + created_items can be None or a dictionary where this method can include key-values that will be passed to + the method delete_vminstance and action_vminstance. Can be used to store created ports, volumes, etc. + Format is vimconnector dependent, but do not use nested dictionaries and a value of None should be the same + as not present. + """ self.logger.debug("new_vminstance input: image='%s' flavor='%s' nics='%s'",image_id, flavor_id,str(net_list)) try: server = None - metadata={} - net_list_vim=[] - external_network=[] # list of external networks to be connected to instance, later on used to create floating_ip + created_items = {} + # 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 + if not net.get("net_id"): # skip non connected iface continue port_dict={ @@ -993,37 +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 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 @@ -1050,24 +1061,24 @@ 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 + # cloud config config_drive, userdata = self._create_user_data(cloud_config) - #Create additional volumes in case these are present in disk_list + # Create additional volumes in case these are present in disk_list base_disk_index = ord('b') if disk_list != None: block_device_mapping = {} @@ -1078,10 +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 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: @@ -1093,28 +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: - #delete the volumes we just created - for volume_id in block_device_mapping.itervalues(): - self.cinder.volumes.delete(volume_id) - - #delete ports we just created - for net_item in net_list_vim: - if 'port-id' in net_item: - self.neutron.delete_port(net_item['port-id']) - 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'), @@ -1130,23 +1133,21 @@ class vimconnector(vimconn.vimconnector): for port_id in no_secured_ports: try: self.neutron.update_port(port_id, {"port": {"port_security_enabled": False, "security_groups": None} }) - except Exception as e: self.logger.error("It was not possible to disable port security for port {}".format(port_id)) - self.delete_vminstance(server.id) raise - #print "DONE :-)", server - pool_id = None - floating_ips = self.neutron.list_floatingips().get("floatingips", ()) + # print "DONE :-)", server + pool_id = None if external_network: + floating_ips = self.neutron.list_floatingips().get("floatingips", ()) self.__wait_for_vm(server.id, 'ACTIVE') for floating_network in external_network: try: assigned = False - while(assigned == False): + while not assigned: if floating_ips: ip = floating_ips.pop(0) if not ip.get("port_id", False) and ip.get('tenant_id') == server.tenant_id: @@ -1190,7 +1191,7 @@ class vimconnector(vimconn.vimconnector): continue raise - return server.id + return server.id, created_items # except nvExceptions.NotFound as e: # error_value=-vimconn.HTTP_Not_Found # error_text= "vm instance %s not found" % vm_id @@ -1198,19 +1199,13 @@ class vimconnector(vimconn.vimconnector): # raise vimconn.vimconnException(type(e).__name__ + ": "+ str(e), http_code=vimconn.HTTP_Bad_Request) except Exception as e: - # delete the volumes we just created - if block_device_mapping: - for volume_id in block_device_mapping.itervalues(): - self.cinder.volumes.delete(volume_id) - - # Delete the VM - if server != None: - self.delete_vminstance(server.id) - else: - # delete ports we just created - for net_item in net_list_vim: - if 'port-id' in net_item: - self.neutron.delete_port(net_item['port-id']) + server_id = None + if server: + server_id = server.id + try: + self.delete_vminstance(server_id, created_items) + except Exception as e2: + self.logger.error("new_vminstance rollback fail {}".format(e2)) self._format_exception(e) @@ -1276,50 +1271,59 @@ class vimconnector(vimconn.vimconnector): except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.BadRequest, ConnectionError) as e: self._format_exception(e) - def delete_vminstance(self, vm_id): + def delete_vminstance(self, vm_id, created_items=None): '''Removes a VM instance from VIM. Returns the old identifier ''' #print "osconnector: Getting VM from VIM" + if created_items == None: + created_items = {} try: self._reload_connection() - #delete VM ports attached to this networks before the virtual machine - ports = self.neutron.list_ports(device_id=vm_id) - for p in ports['ports']: + # delete VM ports attached to this networks before the virtual machine + for k, v in created_items.items(): + if not v: # skip already deleted + continue try: - self.neutron.delete_port(p["id"]) + 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 - server = self.nova.servers.get(vm_id) - volumes_attached_dict = server._info['os-extended-volumes:volumes_attached'] - #for volume in volumes_attached_dict: - # self.cinder.volumes.detach(volume['id']) + # #commented because detaching the volumes makes the servers.delete not work properly ?!? + # #dettach volumes attached + # server = self.nova.servers.get(vm_id) + # volumes_attached_dict = server._info['os-extended-volumes:volumes_attached'] #volume['id'] + # #for volume in volumes_attached_dict: + # # self.cinder.volumes.detach(volume['id']) - self.nova.servers.delete(vm_id) + if vm_id: + self.nova.servers.delete(vm_id) - #delete volumes. - #Although having detached them should have them in active status - #we ensure in this loop + # delete volumes. Although having detached, they should have in active status before deleting + # we ensure in this loop keep_waiting = True elapsed_time = 0 while keep_waiting and elapsed_time < volume_timeout: keep_waiting = False - for volume in volumes_attached_dict: - if self.cinder.volumes.get(volume['id']).status != 'available': - keep_waiting = True - else: - self.cinder.volumes.delete(volume['id']) + for k, v in created_items.items(): + if not v: # skip already deleted + continue + try: + 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_id) + except Exception as e: + self.logger.error("Error deleting volume: {}: {}".format(type(e).__name__, e)) if keep_waiting: time.sleep(1) elapsed_time += 1 - - return vm_id + return None except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e: self._format_exception(e) - #TODO insert exception vimconn.HTTP_Unauthorized - #if reaching here is because an exception def refresh_vms_status(self, vm_list): '''Get the status of the virtual machines and their interfaces/ports @@ -1423,9 +1427,9 @@ class vimconnector(vimconn.vimconnector): vm_dict[vm_id] = vm return vm_dict - def action_vminstance(self, vm_id, action_dict): + def action_vminstance(self, vm_id, action_dict, created_items={}): '''Send and action over a VM instance from VIM - Returns the vm_id if the action was successfully sent to the VIM''' + Returns None or the console dict if the action was successfully sent to the VIM''' self.logger.debug("Action over VM '%s': %s", vm_id, str(action_dict)) try: self._reload_connection() @@ -1492,7 +1496,7 @@ class vimconnector(vimconn.vimconnector): except Exception as e: raise vimconn.vimconnException("Unexpected response from VIM " + str(console_dict)) - return vm_id + return None except (ksExceptions.ClientException, nvExceptions.ClientException, nvExceptions.NotFound, ConnectionError) as e: self._format_exception(e) #TODO insert exception vimconn.HTTP_Unauthorized @@ -1688,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, @@ -1714,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 @@ -1730,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, @@ -1745,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 " @@ -1761,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( @@ -1795,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 @@ -1810,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, @@ -1825,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( @@ -1869,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 @@ -1883,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, @@ -1896,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 ' @@ -1940,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 @@ -1955,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,