# -*- coding: utf-8 -*-
##
-# Copyright 2015 Telefónica Investigación y Desarrollo, S.A.U.
+# Copyright 2015 Telefonica Investigacion y Desarrollo, S.A.U.
# This file is part of openmano
# All Rights Reserved.
#
- 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."
+__author__ = "Alfonso Tierno, Gerardo Garcia, Pablo Montes, xFlow Research, Igor D.C., Eduardo Sousa"
__date__ = "$22-sep-2017 23:59:59$"
import vimconn
-import json
+# import json
import logging
import netaddr
import time
import random
import re
import copy
+from pprint import pformat
+from types import StringTypes
from novaclient import client as nClient, exceptions as nvExceptions
from keystoneauth1.identity import v2, v3
import keystoneclient.v3.client as ksClient_v3
import keystoneclient.v2_0.client as ksClient_v2
from glanceclient import client as glClient
-import glanceclient.client as gl1Client
import glanceclient.exc as gl1Exceptions
from cinderclient import client as cClient
from httplib import HTTPException
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 SafeDumper(yaml.SafeDumper):
+ def represent_data(self, data):
+ # Openstack APIs use custom subclasses of dict and YAML safe dumper
+ # is designed to not handle that (reference issue 142 of pyyaml)
+ if isinstance(data, dict) and data.__class__ != dict:
+ # A simple solution is to convert those items back to dicts
+ data = dict(data.items())
+
+ return super(SafeDumper, self).represent_data(data)
+
class vimconnector(vimconn.vimconnector):
def __init__(self, uuid, name, tenant_id, tenant_name, url, url_admin=None, user=None, passwd=None,
vimconn.vimconnector.__init__(self, uuid, name, tenant_id, tenant_name, url, url_admin, user, passwd, log_level,
config)
- self.insecure = self.config.get("insecure", False)
+ if self.config.get("insecure") and self.config.get("ca_cert"):
+ raise vimconn.vimconnException("options insecure and ca_cert are mutually exclusive")
+ self.verify = True
+ if self.config.get("insecure"):
+ self.verify = False
+ if self.config.get("ca_cert"):
+ self.verify = self.config.get("ca_cert")
+
if not url:
raise TypeError('url param can not be NoneType')
self.persistent_info = persistent_info
self.neutron = self.session.get('neutron')
self.cinder = self.session.get('cinder')
self.glance = self.session.get('glance')
- self.glancev1 = self.session.get('glancev1')
+ # self.glancev1 = self.session.get('glancev1')
self.keystone = self.session.get('keystone')
self.api_version3 = self.session.get('api_version3')
self.vim_type = self.config.get("vim_type")
vimconn.vimconnector.__setitem__(self, index, value)
self.session['reload_client'] = True
+ def serialize(self, value):
+ """Serialization of python basic types.
+
+ In the case value is not serializable a message will be logged and a
+ simple representation of the data that cannot be converted back to
+ python is returned.
+ """
+ if isinstance(value, StringTypes):
+ return value
+
+ try:
+ 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)
+
def _reload_connection(self):
'''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'
password=self.passwd,
tenant_name=self.tenant_name,
tenant_id=self.tenant_id)
- sess = session.Session(auth=auth, verify=not self.insecure)
+ sess = session.Session(auth=auth, verify=self.verify)
if self.api_version3:
self.keystone = ksClient_v3.Client(session=sess, endpoint_type=self.endpoint_type)
else:
glance_endpoint = None
self.glance = self.session['glance'] = glClient.Client(2, session=sess, endpoint=glance_endpoint)
#using version 1 of glance client in new_image()
- self.glancev1 = self.session['glancev1'] = glClient.Client('1', session=sess,
- endpoint=glance_endpoint)
+ # self.glancev1 = self.session['glancev1'] = glClient.Client('1', session=sess,
+ # endpoint=glance_endpoint)
self.session['reload_client'] = False
self.persistent_info['session'] = self.session
# add availablity zone info inside self.persistent_info
def _format_exception(self, exception):
'''Transform a keystone, nova, neutron exception into a vimconn exception'''
- if isinstance(exception, (HTTPException, gl1Exceptions.HTTPException, gl1Exceptions.CommunicationError,
- ConnectionError, ksExceptions.ConnectionError, neExceptions.ConnectionFailed
- )):
+ if isinstance(exception, (neExceptions.NetworkNotFoundClient, nvExceptions.NotFound, ksExceptions.NotFound, gl1Exceptions.HTTPNotFound)):
+ raise vimconn.vimconnNotFoundException(type(exception).__name__ + ": " + str(exception))
+ elif isinstance(exception, (HTTPException, gl1Exceptions.HTTPException, gl1Exceptions.CommunicationError,
+ ConnectionError, ksExceptions.ConnectionError, neExceptions.ConnectionFailed)):
raise vimconn.vimconnConnectionException(type(exception).__name__ + ": " + str(exception))
+ elif isinstance(exception, (KeyError, nvExceptions.BadRequest, ksExceptions.BadRequest)):
+ raise vimconn.vimconnException(type(exception).__name__ + ": " + str(exception))
elif isinstance(exception, (nvExceptions.ClientException, ksExceptions.ClientException,
- neExceptions.NeutronException, nvExceptions.BadRequest)):
+ neExceptions.NeutronException)):
raise vimconn.vimconnUnexpectedResponse(type(exception).__name__ + ": " + str(exception))
- elif isinstance(exception, (neExceptions.NetworkNotFoundClient, nvExceptions.NotFound)):
- raise vimconn.vimconnNotFoundException(type(exception).__name__ + ": " + str(exception))
elif isinstance(exception, nvExceptions.Conflict):
raise vimconn.vimconnConflictException(type(exception).__name__ + ": " + str(exception))
elif isinstance(exception, vimconn.vimconnException):
- raise
+ raise exception
else: # ()
self.logger.error("General Exception " + str(exception), exc_info=True)
raise vimconn.vimconnConnectionException(type(exception).__name__ + ": " + str(exception))
else:
project = self.keystone.tenants.create(tenant_name, tenant_description)
return project.id
- except (ksExceptions.ConnectionError, ksExceptions.ClientException, ConnectionError) as e:
+ except (ksExceptions.ConnectionError, ksExceptions.ClientException, ksExceptions.BadRequest, ConnectionError) as e:
self._format_exception(e)
def delete_tenant(self, tenant_id):
else:
self.keystone.tenants.delete(tenant_id)
return tenant_id
- except (ksExceptions.ConnectionError, ksExceptions.ClientException, 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, vlan=None):
#create subnetwork, even if there is no profile
if not ip_profile:
ip_profile = {}
- if 'subnet_address' not in ip_profile:
+ if not ip_profile.get('subnet_address'):
#Fake subnet is required
subnet_rand = random.randint(0, 255)
ip_profile['subnet_address'] = "192.168.{}.0/24".format(subnet_rand)
"cidr": ip_profile['subnet_address']
}
# Gateway should be set to None if not needed. Otherwise openstack assigns one by default
- subnet['gateway_ip'] = ip_profile.get('gateway_address')
+ if ip_profile.get('gateway_address'):
+ subnet['gateway_ip'] = ip_profile['gateway_address']
+ else:
+ subnet['gateway_ip'] = None
if ip_profile.get('dns_address'):
subnet['dns_nameservers'] = ip_profile['dns_address'].split(";")
if 'dhcp_enabled' in ip_profile:
- subnet['enable_dhcp'] = False if ip_profile['dhcp_enabled']=="false" else True
- if 'dhcp_start_address' in ip_profile:
+ subnet['enable_dhcp'] = False if \
+ ip_profile['dhcp_enabled']=="false" or ip_profile['dhcp_enabled']==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 'dhcp_count' in ip_profile:
+ 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])
ip_int = int(netaddr.IPAddress(ip_profile['dhcp_start_address']))
#self.logger.debug(">>>>>>>>>>>>>>>>>> Subnet: %s", str(subnet))
self.neutron.create_subnet({"subnet": subnet} )
return new_net["network"]["id"]
- except (neExceptions.ConnectionFailed, ksExceptions.ClientException, neExceptions.NeutronException, ConnectionError) as e:
+ except Exception as e:
if new_net:
self.neutron.delete_network(new_net['network']['id'])
self._format_exception(e)
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:
subnets.append(subnet)
net["subnets"] = subnets
net["encapsulation"] = net.get('provider:network_type')
+ net["encapsulation_type"] = net.get('provider:network_type')
net["segmentation_id"] = net.get('provider:segmentation_id')
+ net["encapsulation_id"] = net.get('provider:segmentation_id')
return net
def delete_network(self, net_id):
net_id: #VIM id of this network
status: #Mandatory. Text with one of:
# DELETED (not found at vim)
- # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
+ # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
# OTHER (Vim reported other status not understood)
# ERROR (VIM indicates an ERROR status)
- # ACTIVE, INACTIVE, DOWN (admin down),
+ # ACTIVE, INACTIVE, DOWN (admin down),
# BUILD (on building process)
#
- error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
+ 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)
'''
if net['status'] == "ACTIVE" and not net_vim['admin_state_up']:
net['status'] = 'DOWN'
- try:
- net['vim_info'] = yaml.safe_dump(net_vim, default_flow_style=True, width=256)
- except yaml.representer.RepresenterError:
- net['vim_info'] = str(net_vim)
+
+ net['vim_info'] = self.serialize(net_vim)
+
if net_vim.get('fault'): #TODO
net['error_msg'] = str(net_vim['fault'])
except vimconn.vimconnNotFoundException as e:
retry=0
max_retries=3
name_suffix = 0
- name=flavor_data['name']
- while retry<max_retries:
- retry+=1
- try:
- self._reload_connection()
- if change_name_if_used:
- #get used names
- fl_names=[]
- fl=self.nova.flavors.list()
- for f in fl:
- fl_names.append(f.name)
- while name in fl_names:
- name_suffix += 1
- name = flavor_data['name']+"-" + str(name_suffix)
-
- ram = flavor_data.get('ram',64)
- vcpus = flavor_data.get('vcpus',1)
- numa_properties=None
-
- extended = flavor_data.get("extended")
- if extended:
- numas=extended.get("numas")
- if numas:
- numa_nodes = len(numas)
- if numa_nodes > 1:
- return -1, "Can not add flavor with more than one numa"
- numa_properties = {"hw:numa_nodes":str(numa_nodes)}
- numa_properties["hw:mem_page_size"] = "large"
- numa_properties["hw:cpu_policy"] = "dedicated"
- numa_properties["hw:numa_mempolicy"] = "strict"
- if self.vim_type == "VIO":
- numa_properties["vmware:extra_config"] = '{"numa.nodeAffinity":"0"}'
- numa_properties["vmware:latency_sensitivity_level"] = "high"
- for numa in numas:
- #overwrite ram and vcpus
- 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
- #cpu_thread_policy "require" implies that the compute node must have an STM architecture
- numa_properties["hw:cpu_thread_policy"] = "require"
- numa_properties["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
- numa_properties["hw:cpu_thread_policy"] = "isolate"
- numa_properties["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
- numa_properties["hw:cpu_thread_policy"] = "prefer"
- numa_properties["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"="<label at config>:<number ifaces>"' when a way to connect it is available
-
- #create flavor
- new_flavor=self.nova.flavors.create(name,
- ram,
- vcpus,
- flavor_data.get('disk',1),
- is_public=flavor_data.get('is_public', True)
- )
- #add metadata
- if numa_properties:
- new_flavor.set_keys(numa_properties)
- return new_flavor.id
- except nvExceptions.Conflict as e:
- if change_name_if_used and retry < max_retries:
- continue
- self._format_exception(e)
- #except nvExceptions.BadRequest as e:
- except (ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError) as e:
- self._format_exception(e)
+ try:
+ name=flavor_data['name']
+ while retry<max_retries:
+ retry+=1
+ try:
+ self._reload_connection()
+ if change_name_if_used:
+ #get used names
+ fl_names=[]
+ fl=self.nova.flavors.list()
+ for f in fl:
+ fl_names.append(f.name)
+ while name in fl_names:
+ name_suffix += 1
+ name = flavor_data['name']+"-" + str(name_suffix)
+
+ ram = flavor_data.get('ram',64)
+ vcpus = flavor_data.get('vcpus',1)
+ numa_properties=None
+
+ extended = flavor_data.get("extended")
+ if extended:
+ numas=extended.get("numas")
+ if numas:
+ numa_nodes = len(numas)
+ if numa_nodes > 1:
+ return -1, "Can not add flavor with more than one numa"
+ numa_properties = {"hw:numa_nodes":str(numa_nodes)}
+ numa_properties["hw:mem_page_size"] = "large"
+ numa_properties["hw:cpu_policy"] = "dedicated"
+ numa_properties["hw:numa_mempolicy"] = "strict"
+ if self.vim_type == "VIO":
+ numa_properties["vmware:extra_config"] = '{"numa.nodeAffinity":"0"}'
+ numa_properties["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
+ 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
+ #cpu_thread_policy "require" implies that the compute node must have an STM architecture
+ numa_properties["hw:cpu_thread_policy"] = "require"
+ numa_properties["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
+ numa_properties["hw:cpu_thread_policy"] = "isolate"
+ numa_properties["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
+ numa_properties["hw:cpu_thread_policy"] = "prefer"
+ numa_properties["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"="<label at config>:<number ifaces>"' when a way to connect it is available
+
+ #create flavor
+ new_flavor=self.nova.flavors.create(name,
+ ram,
+ vcpus,
+ flavor_data.get('disk',0),
+ is_public=flavor_data.get('is_public', True)
+ )
+ #add metadata
+ if numa_properties:
+ new_flavor.set_keys(numa_properties)
+ return new_flavor.id
+ except nvExceptions.Conflict as e:
+ if change_name_if_used and retry < max_retries:
+ continue
+ self._format_exception(e)
+ #except nvExceptions.BadRequest as e:
+ except (ksExceptions.ClientException, nvExceptions.ClientException, ConnectionError, KeyError) as e:
+ self._format_exception(e)
def delete_flavor(self,flavor_id):
'''Deletes a tenant flavor from openstack VIM. Returns the old flavor_id
if "disk_format" in image_dict:
disk_format=image_dict["disk_format"]
else: #autodiscover based on extension
- if image_dict['location'][-6:]==".qcow2":
+ if image_dict['location'].endswith(".qcow2"):
disk_format="qcow2"
- elif image_dict['location'][-4:]==".vhd":
+ elif image_dict['location'].endswith(".vhd"):
disk_format="vhd"
- elif image_dict['location'][-5:]==".vmdk":
+ elif image_dict['location'].endswith(".vmdk"):
disk_format="vmdk"
- elif image_dict['location'][-4:]==".vdi":
+ elif image_dict['location'].endswith(".vdi"):
disk_format="vdi"
- elif image_dict['location'][-4:]==".iso":
+ elif image_dict['location'].endswith(".iso"):
disk_format="iso"
- elif image_dict['location'][-4:]==".aki":
+ elif image_dict['location'].endswith(".aki"):
disk_format="aki"
- elif image_dict['location'][-4:]==".ari":
+ elif image_dict['location'].endswith(".ari"):
disk_format="ari"
- elif image_dict['location'][-4:]==".ami":
+ elif image_dict['location'].endswith(".ami"):
disk_format="ami"
else:
disk_format="raw"
self.logger.debug("new_image: '%s' loading from '%s'", image_dict['name'], image_dict['location'])
- if image_dict['location'][0:4]=="http":
- new_image = self.glancev1.images.create(name=image_dict['name'], is_public=image_dict.get('public',"yes")=="yes",
- container_format="bare", location=image_dict['location'], disk_format=disk_format)
+ if self.vim_type == "VIO":
+ container_format = "bare"
+ if 'container_format' in image_dict:
+ container_format = image_dict['container_format']
+ new_image = self.glance.images.create(name=image_dict['name'], container_format=container_format,
+ disk_format=disk_format)
+ else:
+ new_image = self.glance.images.create(name=image_dict['name'])
+ if image_dict['location'].startswith("http"):
+ # TODO there is not a method to direct download. It must be downloaded locally with requests
+ raise vimconn.vimconnNotImplemented("Cannot create image from URL")
else: #local path
with open(image_dict['location']) as fimage:
- new_image = self.glancev1.images.create(name=image_dict['name'], is_public=image_dict.get('public',"yes")=="yes",
- container_format="bare", data=fimage, disk_format=disk_format)
- #insert metadata. We cannot use 'new_image.properties.setdefault'
- #because nova and glance are "INDEPENDENT" and we are using nova for reading metadata
- new_image_nova=self.nova.images.find(id=new_image.id)
- new_image_nova.metadata.setdefault('location',image_dict['location'])
+ self.glance.images.upload(new_image.id, fimage)
+ #new_image = self.glancev1.images.create(name=image_dict['name'], is_public=image_dict.get('public',"yes")=="yes",
+ # container_format="bare", data=fimage, disk_format=disk_format)
metadata_to_load = image_dict.get('metadata')
- if metadata_to_load:
- for k,v in yaml.load(metadata_to_load).iteritems():
- new_image_nova.metadata.setdefault(k,v)
+ # TODO location is a reserved word for current openstack versions. fixed for VIO please check for openstack
+ if self.vim_type == "VIO":
+ metadata_to_load['upload_location'] = image_dict['location']
+ else:
+ metadata_to_load['location'] = image_dict['location']
+ self.glance.images.update(new_image.id, **metadata_to_load)
return new_image.id
except (nvExceptions.Conflict, ksExceptions.ClientException, nvExceptions.ClientException) as e:
self._format_exception(e)
'''
try:
self._reload_connection()
- self.nova.images.delete(image_id)
+ self.glance.images.delete(image_id)
return image_id
- except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, ConnectionError) as e: #TODO remove
+ except (nvExceptions.NotFound, ksExceptions.ClientException, nvExceptions.ClientException, gl1Exceptions.CommunicationError, gl1Exceptions.HTTPNotFound, ConnectionError) as e: #TODO remove
self._format_exception(e)
def get_image_id_from_path(self, path):
'''Get the image id from image path in the VIM database. Returns the image_id'''
try:
self._reload_connection()
- images = self.nova.images.list()
+ images = self.glance.images.list()
for image in images:
if image.metadata.get("location")==path:
return image.id
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)
- image_list = self.nova.images.findall(**filter_dict_os)
- if len(image_list) == 0:
- return []
- #Then we filter by the rest of filter fields: checksum
+ image_list = self.glance.images.list()
filtered_list = []
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'):
- filtered_list.append(image_class.copy())
+ if filter_dict.get("name") and image["name"] != filter_dict["name"]:
+ continue
+ if filter_dict.get("id") and image["id"] != filter_dict["id"]:
+ continue
+ if filter_dict.get("checksum") and image["checksum"] != filter_dict["checksum"]:
+ continue
+
+ filtered_list.append(image.copy())
except gl1Exceptions.HTTPNotFound:
pass
return filtered_list
return True
if vm_status == 'ERROR':
return False
- time.sleep(1)
- elapsed_time += 1
+ time.sleep(5)
+ elapsed_time += 5
# if we exceeded the timeout rollback
if elapsed_time >= server_timeout:
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:
- 'key-pairs': (optional) list of strings with the public key to be inserted to the default user
- 'users': (optional) list of users to be inserted, each item is a dict with:
- 'name': (mandatory) user name,
- 'key-pairs': (optional) list of strings with the public key to be inserted to the user
- 'user-data': (optional) string is a text script to be passed directly to cloud-init
- 'config-files': (optional). List of files to be transferred. Each item is a dict with:
- 'dest': (mandatory) string with the destination absolute path
- 'encoding': (optional, by default text). Can be one of:
- 'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64'
- 'content' (mandatory): string with the content of the file
- 'permissions': (optional) string with file permissions, typically octal notation '0644'
- 'owner': (optional) file owner, string with the format 'owner:group'
- 'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk)
+ 'cloud_config': (optional) dictionary with:
+ 'key-pairs': (optional) list of strings with the public key to be inserted to the default user
+ 'users': (optional) list of users to be inserted, each item is a dict with:
+ 'name': (mandatory) user name,
+ 'key-pairs': (optional) list of strings with the public key to be inserted to the user
+ 'user-data': (optional) string is a text script to be passed directly to cloud-init
+ 'config-files': (optional). List of files to be transferred. Each item is a dict with:
+ 'dest': (mandatory) string with the destination absolute path
+ 'encoding': (optional, by default text). Can be one of:
+ 'b64', 'base64', 'gz', 'gz+b64', 'gz+base64', 'gzip+b64', 'gzip+base64'
+ 'content' (mandatory): string with the content of the file
+ 'permissions': (optional) string with file permissions, typically octal notation '0644'
+ 'owner': (optional) file owner, string with the format 'owner:group'
+ 'boot-data-drive': boolean to indicate if user-data must be passed using a boot drive (hard disk)
'disk_list': (optional) list with additional disks to the VM. Each item is a dict with:
'image_id': (optional). VIM id of an existing image. If not provided an empty disk must be mounted
'size': (mandatory) string with the size of the disk in GB
+ 'vim_id' (optional) should use this existing volume id
availability_zone_index: Index of availability_zone_list to use for this this VM. None if not AV required
availability_zone_list: list of availability zones given by user in the VNFD descriptor. Ignore if
availability_zone_index is None
pass
# if "vpci" in net:
# metadata_vpci[ net["net_id"] ] = [[ net["vpci"], "" ]]
- elif net["type"]=="VF": # for VF
+ elif net["type"] == "VF" or net["type"] == "SR-IOV": # for VF
# if "vpci" in net:
# if "VF" not in metadata_vpci:
# metadata_vpci["VF"]=[]
port_dict["port_security_enabled"]=False
port_dict["provider_security_groups"]=[]
port_dict["security_groups"]=[]
- else: #For PT
+ 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.
port_dict["name"]=name
if net.get("mac_address"):
port_dict["mac_address"]=net["mac_address"]
+ if net.get("ip_address"):
+ port_dict["fixed_ips"] = [{'ip_address': net["ip_address"]}]
+ # TODO add 'subnet_id': <subnet_id>
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
elif net['use'] == 'mgmt' and self.config.get('use_floating_ip'):
net['exit_on_floating_ip_error'] = False
external_network.append(net)
+ net['floating_ip'] = self.config.get('use_floating_ip')
# If port security is disabled when the port has not yet been attached to the VM, then all vm traffic is dropped.
# As a workaround we wait until the VM is active and then disable the port-security
- if net.get("port_security") == False:
+ if net.get("port_security") == False and not self.config.get("no_port_security_extension"):
no_secured_ports.append(new_port["port"]["id"])
# if metadata_vpci:
# Create additional volumes in case these are present in disk_list
base_disk_index = ord('b')
- if disk_list != None:
+ if disk_list:
block_device_mapping = {}
for disk in disk_list:
- if 'image_id' in disk:
- volume = self.cinder.volumes.create(size = disk['size'],name = name + '_vd' +
- chr(base_disk_index), imageRef = disk['image_id'])
+ if disk.get('vim_id'):
+ block_device_mapping['_vd' + chr(base_disk_index)] = disk['vim_id']
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
+ if 'image_id' in disk:
+ volume = self.cinder.volumes.create(size=disk['size'], name=name + '_vd' +
+ chr(base_disk_index), imageRef=disk['image_id'])
+ 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
- keep_waiting = True
+ # Wait until created volumes are with status available
elapsed_time = 0
- while keep_waiting and elapsed_time < volume_timeout:
- keep_waiting = False
- for volume_id in block_device_mapping.itervalues():
- if self.cinder.volumes.get(volume_id).status != 'available':
- keep_waiting = True
- if keep_waiting:
- time.sleep(1)
- elapsed_time += 1
-
+ while elapsed_time < volume_timeout:
+ for created_item in created_items:
+ v, _, volume_id = created_item.partition(":")
+ if v == 'volume':
+ if self.cinder.volumes.get(volume_id).status != 'available':
+ break
+ else: # all ready: break from while
+ break
+ time.sleep(5)
+ elapsed_time += 5
# If we exceeded the timeout rollback
if elapsed_time >= volume_timeout:
raise vimconn.vimconnException('Timeout creating volumes for instance ' + name,
block_device_mapping=block_device_mapping
) # , description=description)
+ vm_start_time = time.time()
# Previously mentioned workaround to wait until the VM is active and then disable the port-security
if no_secured_ports:
self.__wait_for_vm(server.id, 'ACTIVE')
for port_id in no_secured_ports:
try:
- self.neutron.update_port(port_id, {"port": {"port_security_enabled": False, "security_groups": None} })
+ 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))
- raise
-
+ raise vimconn.vimconnException("It was not possible to disable port security for port {}".format(
+ port_id))
# print "DONE :-)", server
- pool_id = None
+ # 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 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:
- free_floating_ip = ip.get("floating_ip_address")
- try:
- fix_ip = floating_network.get('ip')
- server.add_floating_ip(free_floating_ip, fix_ip)
- assigned = True
- except Exception as e:
- raise vimconn.vimconnException(type(e).__name__ + ": Cannot create floating_ip "+ str(e), http_code=vimconn.HTTP_Conflict)
+ if ip.get("port_id", False) or ip.get('tenant_id') != server.tenant_id:
+ continue
+ if isinstance(floating_network['floating_ip'], str):
+ if ip.get("floating_network_id") != floating_network['floating_ip']:
+ continue
+ free_floating_ip = ip.get("floating_ip_address")
else:
- #Find the external network
- external_nets = list()
- for net in self.neutron.list_networks()['networks']:
- if net['router:external']:
- external_nets.append(net)
-
- if len(external_nets) == 0:
- raise vimconn.vimconnException("Cannot create floating_ip automatically since no external "
- "network is present",
- http_code=vimconn.HTTP_Conflict)
- if len(external_nets) > 1:
- raise vimconn.vimconnException("Cannot create floating_ip automatically since multiple "
- "external networks are present",
- http_code=vimconn.HTTP_Conflict)
-
- pool_id = external_nets[0].get('id')
+ if isinstance(floating_network['floating_ip'], str) and \
+ floating_network['floating_ip'].lower() != "true":
+ pool_id = floating_network['floating_ip']
+ else:
+ # Find the external network
+ external_nets = list()
+ for net in self.neutron.list_networks()['networks']:
+ if net['router:external']:
+ external_nets.append(net)
+
+ if len(external_nets) == 0:
+ raise vimconn.vimconnException("Cannot create floating_ip automatically since no external "
+ "network is present",
+ http_code=vimconn.HTTP_Conflict)
+ if len(external_nets) > 1:
+ raise vimconn.vimconnException("Cannot create floating_ip automatically since multiple "
+ "external networks are present",
+ http_code=vimconn.HTTP_Conflict)
+
+ pool_id = external_nets[0].get('id')
param = {'floatingip': {'floating_network_id': pool_id, 'tenant_id': server.tenant_id}}
try:
- #self.logger.debug("Creating floating IP")
+ # self.logger.debug("Creating floating IP")
new_floating_ip = self.neutron.create_floatingip(param)
free_floating_ip = new_floating_ip['floatingip']['floating_ip_address']
- fix_ip = floating_network.get('ip')
+ except Exception as e:
+ raise vimconn.vimconnException(type(e).__name__ + ": Cannot create new floating_ip " +
+ str(e), http_code=vimconn.HTTP_Conflict)
+
+ fix_ip = floating_network.get('ip')
+ while not assigned:
+ try:
server.add_floating_ip(free_floating_ip, fix_ip)
- assigned=True
+ assigned = True
except Exception as e:
- raise vimconn.vimconnException(type(e).__name__ + ": Cannot assign floating_ip "+ str(e), http_code=vimconn.HTTP_Conflict)
+ # openstack need some time after VM creation to asign an IP. So retry if fails
+ vm_status = self.nova.servers.get(server.id).status
+ if vm_status != 'ACTIVE' and vm_status != 'ERROR':
+ if time.time() - vm_start_time < server_timeout:
+ time.sleep(5)
+ continue
+ raise vimconn.vimconnException(
+ "Cannot create floating_ip: {} {}".format(type(e).__name__, e),
+ http_code=vimconn.HTTP_Conflict)
+
except Exception as e:
if not floating_network['exit_on_floating_ip_error']:
self.logger.warn("Cannot create floating_ip. %s", str(e))
Params:
vm_id: uuid of the VM
console_type, can be:
- "novnc" (by default), "xvpvnc" for VNC types,
+ "novnc" (by default), "xvpvnc" for VNC types,
"rdp-html5" for RDP types, "spice-html5" for SPICE types
Returns dict with the console parameters:
protocol: ssh, ftp, http, https, ...
- server: usually ip address
- port: the http, ssh, ... port
- suffix: extra text, e.g. the http path and query string
+ server: usually ip address
+ port: the http, ssh, ... port
+ suffix: extra text, e.g. the http path and query string
'''
self.logger.debug("Getting VM CONSOLE from VIM")
try:
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
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
vm_id: #VIM id of this Virtual Machine
status: #Mandatory. Text with one of:
# DELETED (not found at vim)
- # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
+ # VIM_ERROR (Cannot connect to VIM, VIM response error, ...)
# OTHER (Vim reported other status not understood)
# ERROR (VIM indicates an ERROR status)
- # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
+ # ACTIVE, PAUSED, SUSPENDED, INACTIVE (not running),
# CREATING (on building process), ERROR
# ACTIVE:NoMgmtIP (Active but any of its interface has an IP address
#
- error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR
+ 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)
interfaces:
- vim_info: #Text with plain information obtained from vim (yaml.safe_dump)
else:
vm['status'] = "OTHER"
vm['error_msg'] = "VIM status reported " + vm_vim['status']
- try:
- vm['vim_info'] = yaml.safe_dump(vm_vim, default_flow_style=True, width=256)
- except yaml.representer.RepresenterError:
- vm['vim_info'] = str(vm_vim)
+
+ vm['vim_info'] = self.serialize(vm_vim)
+
vm["interfaces"] = []
if vm_vim.get('fault'):
vm['error_msg'] = str(vm_vim['fault'])
#get interfaces
try:
self._reload_connection()
- port_dict=self.neutron.list_ports(device_id=vm_id)
+ port_dict = self.neutron.list_ports(device_id=vm_id)
for port in port_dict["ports"]:
interface={}
- try:
- interface['vim_info'] = yaml.safe_dump(port, default_flow_style=True, width=256)
- except yaml.representer.RepresenterError:
- interface['vim_info'] = str(port)
+ interface['vim_info'] = self.serialize(port)
interface["mac_address"] = port.get("mac_address")
interface["vim_net_id"] = port["network_id"]
interface["vim_interface_id"] = port["id"]
- # check if OS-EXT-SRV-ATTR:host is there,
+ # check if OS-EXT-SRV-ATTR:host is there,
# in case of non-admin credentials, it will be missing
if vm_vim.get('OS-EXT-SRV-ATTR:host'):
interface["compute_node"] = vm_vim['OS-EXT-SRV-ATTR:host']
interface["pci"] = None
- # check if binding:profile is there,
+ # check if binding:profile is there,
# in case of non-admin credentials, it will be missing
if port.get('binding:profile'):
if port['binding:profile'].get('pci_slot'):
interface["vlan"] = network['network'].get('provider:segmentation_id')
ips=[]
#look for floating ip address
- floating_ip_dict = self.neutron.list_floatingips(port_id=port["id"])
- if floating_ip_dict.get("floatingips"):
- ips.append(floating_ip_dict["floatingips"][0].get("floating_ip_address") )
+ try:
+ floating_ip_dict = self.neutron.list_floatingips(port_id=port["id"])
+ if floating_ip_dict.get("floatingips"):
+ ips.append(floating_ip_dict["floatingips"][0].get("floating_ip_address") )
+ except Exception:
+ pass
for subnet in port["fixed_ips"]:
ips.append(subnet["ip_address"])
interface["ip_address"] = ";".join(ips)
vm["interfaces"].append(interface)
except Exception as e:
- self.logger.error("Error getting vm interface information " + type(e).__name__ + ": "+ str(e))
+ self.logger.error("Error getting vm interface information {}: {}".format(type(e).__name__, e),
+ exc_info=True)
except vimconn.vimconnNotFoundException as e:
self.logger.error("Exception getting vm status: %s", str(e))
vm['status'] = "DELETED"
self.logger.debug("osconnector: Adding a new user to VIM")
try:
self._reload_connection()
- user=self.keystone.users.create(user_name, user_passwd, tenant_id=tenant_id)
+ user=self.keystone.users.create(user_name, password=user_passwd, default_project=tenant_id)
#self.keystone.tenants.add_user(self.k_creds["username"], #role)
return user.id
except ksExceptions.ConnectionError as e:
error_text= type(e).__name__ + ": "+ (str(e) if len(e.args)==0 else str(e.args[0]))
#TODO insert exception vimconn.HTTP_Unauthorized
#if reaching here is because an exception
- if self.debug:
- self.logger.debug("new_user " + error_text)
+ self.logger.debug("new_user " + error_text)
return error_value, error_text
def delete_user(self, user_id):
error_text= type(e).__name__ + ": "+ (str(e) if len(e.args)==0 else str(e.args[0]))
#TODO insert exception vimconn.HTTP_Unauthorized
#if reaching here is because an exception
- if self.debug:
- print("delete_tenant " + error_text)
+ self.logger.debug("delete_tenant " + error_text)
return error_value, error_text
def get_hosts_info(self):
error_text= type(e).__name__ + ": "+ (str(e) if len(e.args)==0 else str(e.args[0]))
#TODO insert exception vimconn.HTTP_Unauthorized
#if reaching here is because an exception
- if self.debug:
- print("get_hosts_info " + error_text)
+ self.logger.debug("get_hosts_info " + error_text)
return error_value, error_text
def get_hosts(self, vim_tenant):
error_text= type(e).__name__ + ": "+ (str(e) if len(e.args)==0 else str(e.args[0]))
#TODO insert exception vimconn.HTTP_Unauthorized
#if reaching here is because an exception
- if self.debug:
- print("get_hosts " + error_text)
+ self.logger.debug("get_hosts " + error_text)
return error_value, error_text
def new_classification(self, name, ctype, definition):
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,
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
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,
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 "
'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(
"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
"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,
try:
new_sf = None
self._reload_connection()
- correlation = None
- if sfc_encap:
- # TODO(igordc): must be changed to NSH in Queens
- # (MPLS is a workaround)
- correlation = 'mpls'
+ # correlation = None
+ # if sfc_encap:
+ # 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(
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
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,
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)
+ # In networking-sfc the MPLS encapsulation is legacy
+ # should be used when no full SFC Encapsulation is intended
correlation = '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 '
"'%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
"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,