From: Anderson Bravalheri Date: Wed, 28 Nov 2018 17:21:26 +0000 (+0000) Subject: Merge remote-tracking branch 'upstream/master' into gerrit-submission X-Git-Tag: v5.0.1~1^2~2 X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FRO.git;a=commitdiff_plain;h=c5293def02d95ed4ee086dd8842437b76ec05c4e;hp=0446cd5df24c38f95cea13b995c553e9b2403f21 Merge remote-tracking branch 'upstream/master' into gerrit-submission Sync with master branch Change-Id: Ic26d043a84f50f48eeebffb512ccea2eedc053a4 Signed-off-by: Anderson Bravalheri --- diff --git a/.gitignore-common b/.gitignore-common index 756a1fc5..85235b2f 100644 --- a/.gitignore-common +++ b/.gitignore-common @@ -1,5 +1,5 @@ ## -# 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. # diff --git a/LICENSE b/LICENSE index e06d2081..8dada3ed 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Apache License + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -199,4 +199,3 @@ Apache License WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - diff --git a/charms/layers/openmano/scripts/init_mano_db.sh b/charms/layers/openmano/scripts/init_mano_db.sh index 9d8b1581..752bff8c 100755 --- a/charms/layers/openmano/scripts/init_mano_db.sh +++ b/charms/layers/openmano/scripts/init_mano_db.sh @@ -1,7 +1,7 @@ #!/bin/bash ## -# 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. # diff --git a/database_utils/dump_db.sh b/database_utils/dump_db.sh index c6c1dfd4..89c83f02 100755 --- a/database_utils/dump_db.sh +++ b/database_utils/dump_db.sh @@ -1,7 +1,7 @@ #!/bin/bash ## -# 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. # @@ -23,7 +23,7 @@ LICENSE_HEAD='/** -* Copyright 2017 Telefónica Investigación y Desarrollo, S.A.U. +* Copyright 2017 Telefonica Investigacion y Desarrollo, S.A.U. * This file is part of openmano * All Rights Reserved. * diff --git a/database_utils/init_mano_db.sh b/database_utils/init_mano_db.sh index 29a3ed06..be7d3eea 100755 --- a/database_utils/init_mano_db.sh +++ b/database_utils/init_mano_db.sh @@ -1,7 +1,7 @@ #!/bin/bash ## -# 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. # diff --git a/database_utils/mano_db_structure.sql b/database_utils/mano_db_structure.sql index 08f3f89f..2bedc389 100644 --- a/database_utils/mano_db_structure.sql +++ b/database_utils/mano_db_structure.sql @@ -1,5 +1,5 @@ /** -* Copyright 2017 Telefónica Investigación y Desarrollo, S.A.U. +* Copyright 2017 Telefonica Investigacion y Desarrollo, S.A.U. * This file is part of openmano * All Rights Reserved. * diff --git a/database_utils/migrate_mano_db.sh b/database_utils/migrate_mano_db.sh index 2657cda3..aa2e7186 100755 --- a/database_utils/migrate_mano_db.sh +++ b/database_utils/migrate_mano_db.sh @@ -1,7 +1,7 @@ #!/bin/bash ## -# 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. # @@ -201,6 +201,7 @@ fi #[ $OPENMANO_VER_NUM -ge 5060 ] && DB_VERSION=30 #0.5.60 => 30 #[ $OPENMANO_VER_NUM -ge 5061 ] && DB_VERSION=31 #0.5.61 => 31 #[ $OPENMANO_VER_NUM -ge 5070 ] && DB_VERSION=32 #0.5.70 => 32 +#[ $OPENMANO_VER_NUM -ge 5082 ] && DB_VERSION=33 #0.5.82 => 33 #[ $OPENMANO_VER_NUM -ge 6000 ] && DB_VERSION=34 #0.6.00 => 34 #TODO ... put next versions here @@ -1294,6 +1295,21 @@ function downgrade_from_32(){ sql "DELETE FROM schema_version WHERE version_int='32';" } +function upgrade_to_33(){ + echo " Add PDU information to 'vms" + sql "ALTER TABLE vms ADD COLUMN pdu_type VARCHAR(255) NULL DEFAULT NULL AFTER osm_id;" + sql "ALTER TABLE instance_nets ADD COLUMN vim_name VARCHAR(255) NULL DEFAULT NULL AFTER vim_net_id;" + sql "INSERT INTO schema_version (version_int, version, openmano_ver, comments, date) "\ + "VALUES (33, '0.33', '0.5.82', 'Add pdu information to vms', '2018-11-13');" +} +function downgrade_from_33(){ + echo " Remove back PDU information from' vms'" + sql "ALTER TABLE vms DROP COLUMN pdu_type;" + sql "ALTER TABLE instance_nets DROP COLUMN vim_name;" + sql "DELETE FROM schema_version WHERE version_int='33';" +} + + function upgrade_to_X(){ echo " change 'datacenter_nets'" sql "ALTER TABLE datacenter_nets ADD COLUMN vim_tenant_id VARCHAR(36) NOT NULL AFTER datacenter_id, DROP INDEX name_datacenter_id, ADD UNIQUE INDEX name_datacenter_id (name, datacenter_id, vim_tenant_id);" diff --git a/docker/Dockerfile-local b/docker/Dockerfile-local index 3e605cc4..e7e05ce4 100644 --- a/docker/Dockerfile-local +++ b/docker/Dockerfile-local @@ -2,40 +2,32 @@ from ubuntu:xenial LABEL authors="Gennadiy Dubina, Alfonso Tierno, Gerardo Garcia" -COPY . /root/RO - RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get -y install software-properties-common && \ DEBIAN_FRONTEND=noninteractive add-apt-repository -y cloud-archive:queens && \ apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get -y install git make python python-pip debhelper python3 python3-all python3-pip python3-setuptools && \ + DEBIAN_FRONTEND=noninteractive apt-get -y install git python python-pip && \ DEBIAN_FRONTEND=noninteractive apt-get -y install wget tox && \ - DEBIAN_FRONTEND=noninteractive pip install pip==9.0.3 && \ - DEBIAN_FRONTEND=noninteractive pip3 install pip==9.0.3 && \ - DEBIAN_FRONTEND=noninteractive pip install -U setuptools setuptools-version-command stdeb && \ - DEBIAN_FRONTEND=noninteractive pip install -U pyang pyangbind && \ - DEBIAN_FRONTEND=noninteractive pip3 install -U pyang pyangbind && \ - DEBIAN_FRONTEND=noninteractive apt-get -y install python-yaml python-netaddr python-boto python-networkx && \ - DEBIAN_FRONTEND=noninteractive apt-get -y install software-properties-common && \ + DEBIAN_FRONTEND=noninteractive pip2 install pip==9.0.3 && \ + DEBIAN_FRONTEND=noninteractive pip2 install -U progressbar pyvmomi pyvcloud==19.1.1 && \ DEBIAN_FRONTEND=noninteractive apt-get -y install python-novaclient python-keystoneclient python-glanceclient python-cinderclient python-neutronclient && \ - DEBIAN_FRONTEND=noninteractive pip install -U progressbar pyvmomi pyvcloud==19.1.1 && \ - DEBIAN_FRONTEND=noninteractive apt-get -y install python-argcomplete python-bottle python-cffi python-packaging python-paramiko python-pkgconfig libmysqlclient-dev libssl-dev libffi-dev python-mysqldb && \ - DEBIAN_FRONTEND=noninteractive apt-get -y install python-logutils python-openstackclient python-openstacksdk && \ - DEBIAN_FRONTEND=noninteractive pip install untangle && \ - DEBIAN_FRONTEND=noninteractive pip install -e git+https://github.com/python-oca/python-oca#egg=oca && \ - DEBIAN_FRONTEND=noninteractive apt-get -y install python-bitarray && \ - DEBIAN_FRONTEND=noninteractive apt-get -y install mysql-client && \ - mkdir -p /root/RO && \ - make -C /root/RO clean all BRANCH=master && \ - dpkg -i /root/RO/IM/deb_dist/python-pyang_*.deb && \ - dpkg -i /root/RO/IM/deb_dist/python-pyangbind_*.deb && \ - dpkg -i /root/RO/IM/deb_dist/python-osm-im*.deb && \ - dpkg -i /root/RO/openvim/.build/python-lib-osm-openvim*.deb && \ - dpkg -i /root/RO/.build/python-osm-ro*.deb && \ + DEBIAN_FRONTEND=noninteractive apt-get -y install python-cffi libmysqlclient-dev libssl-dev libffi-dev python-mysqldb && \ + DEBIAN_FRONTEND=noninteractive apt-get -y install python-openstacksdk python-openstackclient && \ + DEBIAN_FRONTEND=noninteractive apt-get -y install python-networkx && \ + DEBIAN_FRONTEND=noninteractive pip2 install untangle && \ + DEBIAN_FRONTEND=noninteractive pip2 install -e git+https://github.com/python-oca/python-oca#egg=oca && \ + DEBIAN_FRONTEND=noninteractive apt-get -y install mysql-client + +COPY . /root/RO + +RUN /root/RO/scripts/install-osm-im.sh --develop && \ + /root/RO/scripts/install-lib-osm-openvim.sh --develop && \ + make -C /root/RO prepare && \ + mkdir -p /var/log/osm && \ + pip2 install -e /root/RO/build && \ rm -rf /root/.cache && \ apt-get clean && \ - rm -rf /var/lib/apt/lists/* && \ - rm -rf /root/RO + rm -rf /var/lib/apt/lists/* VOLUME /var/log/osm @@ -55,6 +47,7 @@ EXPOSE 9090 # RO_DB_OVIM_PORT: default value '3306' # RO_DB_NAME: default value 'mano_db' # RO_DB_OVIM_NAME: default value 'mano_vim_db' +# RO_LOG_FILE: default log to stderr if not defined ENV RO_DB_HOST="" \ RO_DB_OVIM_HOST="" \ @@ -68,7 +61,7 @@ ENV RO_DB_HOST="" \ RO_DB_OVIM_PORT=3306 \ RO_DB_NAME=mano_db \ RO_DB_OVIM_NAME=mano_vim_db \ - OPENMANO_TENANT=osm + OPENMANO_TENANT=osm \ + RO_LOG_LEVEL=DEBUG CMD RO-start.sh - diff --git a/instance-scenarios/examples/instance-creation-complex2.yaml b/instance-scenarios/examples/instance-creation-complex2.yaml index e4ebb047..7493d52a 100644 --- a/instance-scenarios/examples/instance-creation-complex2.yaml +++ b/instance-scenarios/examples/instance-creation-complex2.yaml @@ -1,5 +1,5 @@ ## -# 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. # diff --git a/instance-scenarios/examples/instance-creation-complex4.yaml b/instance-scenarios/examples/instance-creation-complex4.yaml index 8f20e4bb..b43010a9 100644 --- a/instance-scenarios/examples/instance-creation-complex4.yaml +++ b/instance-scenarios/examples/instance-creation-complex4.yaml @@ -1,5 +1,5 @@ ## -# 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. # diff --git a/openmano b/openmano index 98ea191e..15776561 100755 --- a/openmano +++ b/openmano @@ -3,7 +3,7 @@ # PYTHON_ARGCOMPLETE_OK ## -# 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. # @@ -28,8 +28,8 @@ openmano client used to interact with openmano-server (openmanod) """ __author__ = "Alfonso Tierno, Gerardo Garcia, Pablo Montes" __date__ = "$09-oct-2014 09:09:48$" -__version__ = "0.4.23-r533" -version_date = "May 2018" +__version__ = "0.4.24-r534" +version_date = "Nov 2018" from argcomplete.completers import FilesCompleter import os @@ -303,13 +303,13 @@ def vnf_create(args): if not vnfds: vnfds = vnfd_catalog.get("vnfd") vnfd = vnfds[0] - vdu_list = vnfd["vdu"] + vdu_list = vnfd.get("vdu") else: # old API api_version = "" token = "vnfs" vnfd = myvnf['vnf'] - vdu_list = vnfd["VNFC"] + vdu_list = vnfd.get("VNFC") if args.name or args.description or args.image_path or args.image_name or args.image_checksum: # TODO, change this for API v3 @@ -319,62 +319,63 @@ def vnf_create(args): vnfd['name'] = args.name if args.description: vnfd['description'] = args.description - if args.image_path: - index = 0 - for image_path_ in args.image_path.split(","): - # print "image-path", image_path_ - if api_version == "/v3": - if vdu_list[index].get("image"): - vdu_list[index]['image'] = image_path_ - if "image-checksum" in vdu_list[index]: - del vdu_list[index]["image-checksum"] - else: # image name in volumes - vdu_list[index]["volumes"][0]["image"] = image_path_ - if "image-checksum" in vdu_list[index]["volumes"][0]: - del vdu_list[index]["volumes"][0]["image-checksum"] - else: - vdu_list[index]['VNFC image'] = image_path_ - if "image name" in vdu_list[index]: - del vdu_list[index]["image name"] - if "image checksum" in vdu_list[index]: - del vdu_list[index]["image checksum"] - index += 1 - if args.image_name: # image name precedes if both are supplied - index = 0 - for image_name_ in args.image_name.split(","): - if api_version == "/v3": - if vdu_list[index].get("image"): - vdu_list[index]['image'] = image_name_ - if "image-checksum" in vdu_list[index]: - del vdu_list[index]["image-checksum"] - if vdu_list[index].get("alternative-images"): - for a_image in vdu_list[index]["alternative-images"]: - a_image['image'] = image_name_ - if "image-checksum" in a_image: - del a_image["image-checksum"] - else: # image name in volumes - vdu_list[index]["volumes"][0]["image"] = image_name_ - if "image-checksum" in vdu_list[index]["volumes"][0]: - del vdu_list[index]["volumes"][0]["image-checksum"] - else: - vdu_list[index]['image name'] = image_name_ - if "VNFC image" in vdu_list[index]: - del vdu_list[index]["VNFC image"] - index += 1 - if args.image_checksum: - index = 0 - for image_checksum_ in args.image_checksum.split(","): - if api_version == "/v3": - if vdu_list[index].get("image"): - vdu_list[index]['image-checksum'] = image_checksum_ - if vdu_list[index].get("alternative-images"): - for a_image in vdu_list[index]["alternative-images"]: - a_image['image-checksum'] = image_checksum_ - else: # image name in volumes - vdu_list[index]["volumes"][0]["image-checksum"] = image_checksum_ - else: - vdu_list[index]['image checksum'] = image_checksum_ - index += 1 + if vdu_list: + if args.image_path: + index = 0 + for image_path_ in args.image_path.split(","): + # print "image-path", image_path_ + if api_version == "/v3": + if vdu_list[index].get("image"): + vdu_list[index]['image'] = image_path_ + if "image-checksum" in vdu_list[index]: + del vdu_list[index]["image-checksum"] + else: # image name in volumes + vdu_list[index]["volumes"][0]["image"] = image_path_ + if "image-checksum" in vdu_list[index]["volumes"][0]: + del vdu_list[index]["volumes"][0]["image-checksum"] + else: + vdu_list[index]['VNFC image'] = image_path_ + if "image name" in vdu_list[index]: + del vdu_list[index]["image name"] + if "image checksum" in vdu_list[index]: + del vdu_list[index]["image checksum"] + index += 1 + if args.image_name: # image name precedes if both are supplied + index = 0 + for image_name_ in args.image_name.split(","): + if api_version == "/v3": + if vdu_list[index].get("image"): + vdu_list[index]['image'] = image_name_ + if "image-checksum" in vdu_list[index]: + del vdu_list[index]["image-checksum"] + if vdu_list[index].get("alternative-images"): + for a_image in vdu_list[index]["alternative-images"]: + a_image['image'] = image_name_ + if "image-checksum" in a_image: + del a_image["image-checksum"] + else: # image name in volumes + vdu_list[index]["volumes"][0]["image"] = image_name_ + if "image-checksum" in vdu_list[index]["volumes"][0]: + del vdu_list[index]["volumes"][0]["image-checksum"] + else: + vdu_list[index]['image name'] = image_name_ + if "VNFC image" in vdu_list[index]: + del vdu_list[index]["VNFC image"] + index += 1 + if args.image_checksum: + index = 0 + for image_checksum_ in args.image_checksum.split(","): + if api_version == "/v3": + if vdu_list[index].get("image"): + vdu_list[index]['image-checksum'] = image_checksum_ + if vdu_list[index].get("alternative-images"): + for a_image in vdu_list[index]["alternative-images"]: + a_image['image-checksum'] = image_checksum_ + else: # image name in volumes + vdu_list[index]["volumes"][0]["image-checksum"] = image_checksum_ + else: + vdu_list[index]['image checksum'] = image_checksum_ + index += 1 except (KeyError, TypeError), e: if str(e) == 'vnf': error_pos= "missing field 'vnf'" elif str(e) == 'name': error_pos= "missing field 'vnf':'name'" @@ -722,7 +723,8 @@ def instance_create(args): if not scenario: print "you must provide a scenario in the file descriptor or with --scenario" return -1 - myInstance["instance"]["scenario"] = _get_item_uuid("scenarios", scenario, tenant) + if isinstance(scenario, str): + myInstance["instance"]["scenario"] = _get_item_uuid("scenarios", scenario, tenant) if args.netmap_use: if "networks" not in myInstance["instance"]: myInstance["instance"]["networks"] = {} diff --git a/openmanoconfig.py b/openmanoconfig.py index 07c5e247..70268665 100755 --- a/openmanoconfig.py +++ b/openmanoconfig.py @@ -2,7 +2,7 @@ # -*- 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. # diff --git a/openmanod b/openmanod index 4ebac750..5e9cc92f 100755 --- a/openmanod +++ b/openmanod @@ -2,7 +2,7 @@ # -*- 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. # @@ -36,7 +36,7 @@ import time import sys import getopt import yaml -from os import getenv as os_getenv, path as os_path +from os import environ, path as os_path from jsonschema import validate as js_v, exceptions as js_e import logging import logging.handlers as log_handlers @@ -51,10 +51,9 @@ import osm_ro __author__ = "Alfonso Tierno, Gerardo Garcia, Pablo Montes" __date__ = "$26-aug-2014 11:09:29$" __version__ = "0.6.00" -version_date = "Sep 2018" +version_date = "Nov 2018" database_version = 34 # expected database schema version - global global_config global logger @@ -157,17 +156,21 @@ def set_logging_file(log_file): if __name__=="__main__": - env_config = { - 'db_host': 'RO_DB_HOST', - 'db_name': 'RO_DB_NAME', - 'db_user': 'RO_DB_USER', - 'db_passwd': 'RO_DB_PASSWORD', - 'db_ovim_host': 'RO_DB_OVIM_HOST', - 'db_ovim_name': 'RO_DB_OVIM_NAME', - 'db_ovim_user': 'RO_DB_OVIM_USER', - 'db_ovim_passwd': 'RO_DB_OVIM_PASSWORD', - 'db_port': 'RO_DB_PORT', - 'db_port': 'RO_DB_PORT', + # env2config contains envioron variable names and the correspondence with configuration file openmanod.cfg keys. + # If this environ is defined, this value is taken instead of the one at at configuration file + env2config = { + 'RO_DB_HOST': 'db_host', + 'RO_DB_NAME': 'db_name', + 'RO_DB_USER': 'db_user', + 'RO_DB_PASSWORD': 'db_passwd', + # 'RO_DB_PORT': 'db_port', + 'RO_DB_OVIM_HOST': 'db_ovim_host', + 'RO_DB_OVIM_NAME': 'db_ovim_name', + 'RO_DB_OVIM_USER': 'db_ovim_user', + 'RO_DB_OVIM_PASSWORD': 'db_ovim_passwd', + # 'RO_DB_OVIM_PORT': 'db_ovim_port', + 'RO_LOG_LEVEL': 'log_level', + 'RO_LOG_FILE': 'log_file', } # Configure logging step 1 hostname = socket.gethostname() @@ -177,7 +180,7 @@ if __name__=="__main__": 'severity:%(levelname)s logger:%(name)s log:%(message)s'.format( host=hostname), datefmt='%Y-%m-%dT%H:%M:%S') - log_format_simple = "%(asctime)s %(levelname)s %(name)s %(filename)s:%(lineno)s %(message)s" + log_format_simple = "%(asctime)s %(levelname)s %(name)s %(thread)d %(filename)s:%(lineno)s %(message)s" log_formatter_simple = logging.Formatter(log_format_simple, datefmt='%Y-%m-%dT%H:%M:%S') logging.basicConfig(format=log_format_simple, level= logging.DEBUG) logger = logging.getLogger('openmano') @@ -242,10 +245,15 @@ if __name__=="__main__": global_config['log_socket_port'] = log_socket_port # override with ENV - for config_key, env_var in env_config.items(): - if os_getenv(env_var): - global_config[config_key] = os_getenv(env_var) - + for env_k, env_v in environ.items(): + try: + if not env_k.startswith("RO_") or env_k not in env2config or not env_v: + continue + global_config[env2config[env_k]] = env_v + if env_k.endswith("PORT"): # convert to int, skip if not possible + global_config[env2config[env_k]] = int(env_v) + except Exception as e: + logger.warn("skipping environ '{}={}' because exception '{}'".format(env_k, env_v, e)) # if vnf_repository is not None: # global_config['vnf_repository'] = vnf_repository diff --git a/osm_ro/console_proxy_thread.py b/osm_ro/console_proxy_thread.py index 460a4aaa..032c774a 100644 --- a/osm_ro/console_proxy_thread.py +++ b/osm_ro/console_proxy_thread.py @@ -1,7 +1,7 @@ # -*- 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. # diff --git a/osm_ro/db_base.py b/osm_ro/db_base.py index 2bfa4cde..7b48f43c 100644 --- a/osm_ro/db_base.py +++ b/osm_ro/db_base.py @@ -1,7 +1,7 @@ # -*- 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. # diff --git a/osm_ro/httpserver.py b/osm_ro/httpserver.py index 11aee157..613fb084 100644 --- a/osm_ro/httpserver.py +++ b/osm_ro/httpserver.py @@ -1,7 +1,7 @@ # -*- 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. # diff --git a/osm_ro/nfvo.py b/osm_ro/nfvo.py index bc5e624a..f625b4f6 100644 --- a/osm_ro/nfvo.py +++ b/osm_ro/nfvo.py @@ -1,7 +1,7 @@ # -*- 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. # @@ -989,6 +989,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): cp_name2iface_uuid = {} cp_name2vm_uuid = {} cp_name2db_interface = {} + vdu_id2cp_name = {} # stored only when one external connection point is presented at this VDU # table vms (vdus) vdu_id2uuid = {} @@ -1006,6 +1007,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): "osm_id": vdu_id, "name": get_str(vdu, "name", 255), "description": get_str(vdu, "description", 255), + "pdu_type": get_str(vdu, "pdu-type", 255), "vnf_id": vnf_uuid, } vdu_id2uuid[db_vm["osm_id"]] = vm_uuid @@ -1095,7 +1097,6 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): # table interfaces (internal/external interfaces) flavor_epa_interfaces = [] - vdu_id2cp_name = {} # stored only when one external connection point is presented at this VDU # for iface in chain(vdu.get("internal-interface").itervalues(), vdu.get("external-interface").itervalues()): for iface in vdu.get("interface").itervalues(): flavor_epa_interface = {} @@ -1118,7 +1119,7 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): if iface.get("virtual-interface").get("type") == "OM-MGMT": db_interface["type"] = "mgmt" - elif iface.get("virtual-interface").get("type") in ("VIRTIO", "E1000"): + elif iface.get("virtual-interface").get("type") in ("VIRTIO", "E1000", "PARAVIRT"): db_interface["type"] = "bridge" db_interface["model"] = get_str(iface.get("virtual-interface"), "type", 12) elif iface.get("virtual-interface").get("type") in ("SR-IOV", "PCI-PASSTHROUGH"): @@ -1286,7 +1287,8 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): "'member-vdus':'{vdu}'. Reference to a non-existing vdu".format( vnf=vnfd_id, pg=pg_name, vdu=vdu_id), httperrors.Bad_Request) - db_vms[vdu_id2db_table_index[vdu_id]]["availability_zone"] = pg_name + if vdu_id2db_table_index[vdu_id]: + db_vms[vdu_id2db_table_index[vdu_id]]["availability_zone"] = pg_name # TODO consider the case of isolation and not colocation # if pg.get("strategy") == "ISOLATION": @@ -1302,20 +1304,22 @@ def new_vnfd_v3(mydb, tenant_id, vnf_descriptor): mgmt_access["vm_id"] = vdu_id2uuid[vnfd["mgmt-interface"]["vdu-id"]] # if only one cp is defined by this VDU, mark this interface as of type "mgmt" if vdu_id2cp_name.get(mgmt_vdu_id): - cp_name2db_interface[vdu_id2cp_name[mgmt_vdu_id]]["type"] = "mgmt" + if cp_name2db_interface[vdu_id2cp_name[mgmt_vdu_id]]: + cp_name2db_interface[vdu_id2cp_name[mgmt_vdu_id]]["type"] = "mgmt" if vnfd["mgmt-interface"].get("ip-address"): mgmt_access["ip-address"] = str(vnfd["mgmt-interface"].get("ip-address")) if vnfd["mgmt-interface"].get("cp"): if vnfd["mgmt-interface"]["cp"] not in cp_name2iface_uuid: - raise NfvoException("Error. Invalid VNF descriptor at 'vnfd[{vnf}]':'mgmt-interface':'cp':'{cp}'. " + raise NfvoException("Error. Invalid VNF descriptor at 'vnfd[{vnf}]':'mgmt-interface':'cp'['{cp}']. " "Reference to a non-existing connection-point".format( vnf=vnfd_id, cp=vnfd["mgmt-interface"]["cp"]), httperrors.Bad_Request) mgmt_access["vm_id"] = cp_name2vm_uuid[vnfd["mgmt-interface"]["cp"]] mgmt_access["interface_id"] = cp_name2iface_uuid[vnfd["mgmt-interface"]["cp"]] # mark this interface as of type mgmt - cp_name2db_interface[vnfd["mgmt-interface"]["cp"]]["type"] = "mgmt" + if cp_name2db_interface[vnfd["mgmt-interface"]["cp"]]: + cp_name2db_interface[vnfd["mgmt-interface"]["cp"]]["type"] = "mgmt" default_user = get_str(vnfd.get("vnf-configuration", {}).get("config-access", {}).get("ssh-access", {}), "default-user", 64) @@ -1646,15 +1650,15 @@ def get_vnf_id(mydb, tenant_id, vnf_id): SELECT=('vms.uuid as uuid', 'vms.osm_id as osm_id', 'vms.name as name', 'vms.description as description', 'boot_data'), WHERE={'vnfs.uuid': vnf_id} ) - if len(content)==0: - raise NfvoException("vnf '{}' not found".format(vnf_id), httperrors.Not_Found) + if len(content) != 0: + #raise NfvoException("vnf '{}' not found".format(vnf_id), httperrors.Not_Found) # change boot_data into boot-data - for vm in content: - if vm.get("boot_data"): - vm["boot-data"] = yaml.safe_load(vm["boot_data"]) - del vm["boot_data"] + for vm in content: + if vm.get("boot_data"): + vm["boot-data"] = yaml.safe_load(vm["boot_data"]) + del vm["boot_data"] - data['vnf']['VNFC'] = content + data['vnf']['VNFC'] = content #TODO: GET all the information from a VNFC and include it in the output. #GET NET @@ -2982,8 +2986,12 @@ def create_instance(mydb, tenant_id, instance_dict): rollbackList = [] # print "Checking that the scenario exists and getting the scenario dictionary" - scenarioDict = mydb.get_scenario(scenario, tenant_id, datacenter_vim_id=myvim_threads_id[default_datacenter_id], - datacenter_id=default_datacenter_id) + if isinstance(scenario, str): + scenarioDict = mydb.get_scenario(scenario, tenant_id, datacenter_vim_id=myvim_threads_id[default_datacenter_id], + datacenter_id=default_datacenter_id) + else: + scenarioDict = scenario + scenarioDict["uuid"] = None # logger.debug(">>>>>> Dictionaries before merging") # logger.debug(">>>>>> InstanceDict:\n{}".format(yaml.safe_dump(instance_dict,default_flow_style=False, width=256))) @@ -3154,9 +3162,10 @@ def create_instance(mydb, tenant_id, instance_dict): number_mgmt_networks = 0 db_instance_nets = [] for sce_net in scenarioDict['nets']: + sce_net_uuid = sce_net.get('uuid', sce_net["name"]) # get involved datacenters where this network need to be created involved_datacenters = [] - for sce_vnf in scenarioDict.get("vnfs"): + for sce_vnf in scenarioDict.get("vnfs", ()): vnf_datacenter = sce_vnf.get("datacenter", default_datacenter_id) if vnf_datacenter in involved_datacenters: continue @@ -3165,13 +3174,20 @@ def create_instance(mydb, tenant_id, instance_dict): if sce_vnf_ifaces.get("sce_net_id") == sce_net["uuid"]: involved_datacenters.append(vnf_datacenter) break + if not involved_datacenters: + involved_datacenters.append(default_datacenter_id) descriptor_net = {} if instance_dict.get("networks") and instance_dict["networks"].get(sce_net["name"]): descriptor_net = instance_dict["networks"][sce_net["name"]] net_name = descriptor_net.get("vim-network-name") - sce_net2instance[sce_net['uuid']] = {} - net2task_id['scenario'][sce_net['uuid']] = {} + # add datacenters from instantiation parameters + if descriptor_net.get("sites"): + for site in descriptor_net["sites"]: + if site.get("datacenter") and site["datacenter"] not in involved_datacenters: + involved_datacenters.append(site["datacenter"]) + sce_net2instance[sce_net_uuid] = {} + net2task_id['scenario'][sce_net_uuid] = {} if sce_net["external"]: number_mgmt_networks += 1 @@ -3190,6 +3206,7 @@ def create_instance(mydb, tenant_id, instance_dict): myvim_thread_id = myvim_threads_id[datacenter_id] net_type = sce_net['type'] + net_vim_name = None lookfor_filter = {'admin_state_up': True, 'status': 'ACTIVE'} # 'shared': True if not net_name: @@ -3258,12 +3275,13 @@ def create_instance(mydb, tenant_id, instance_dict): # fill database content net_uuid = str(uuid4()) uuid_list.append(net_uuid) - sce_net2instance[sce_net['uuid']][datacenter_id] = net_uuid + sce_net2instance[sce_net_uuid][datacenter_id] = net_uuid db_net = { "uuid": net_uuid, 'vim_net_id': None, + "vim_name": net_vim_name, "instance_scenario_id": instance_uuid, - "sce_net_id": sce_net["uuid"], + "sce_net_id": sce_net.get("uuid"), "created": create_network, 'datacenter_id': datacenter_id, 'datacenter_tenant_id': myvim_thread_id, @@ -3280,7 +3298,7 @@ def create_instance(mydb, tenant_id, instance_dict): "item_id": net_uuid, "extra": yaml.safe_dump(task_extra, default_flow_style=True, width=256) } - net2task_id['scenario'][sce_net['uuid']][datacenter_id] = task_index + net2task_id['scenario'][sce_net_uuid][datacenter_id] = task_index task_index += 1 db_vim_actions.append(db_vim_action) @@ -3307,6 +3325,7 @@ def create_instance(mydb, tenant_id, instance_dict): "myvims": myvims, "cloud_config": cloud_config, "RO_pub_key": tenant[0].get('RO_pub_key'), + "instance_parameters": instance_dict, } vnf_params_out = { "task_index": task_index, @@ -3321,14 +3340,14 @@ def create_instance(mydb, tenant_id, instance_dict): "sce_net2instance": sce_net2instance, } # sce_vnf_list = sorted(scenarioDict['vnfs'], key=lambda k: k['name']) - for sce_vnf in scenarioDict['vnfs']: # sce_vnf_list: + for sce_vnf in scenarioDict.get('vnfs', ()): # sce_vnf_list: instantiate_vnf(mydb, sce_vnf, vnf_params, vnf_params_out, rollbackList) task_index = vnf_params_out["task_index"] uuid_list = vnf_params_out["uuid_list"] # Create VNFFGs # task_depends_on = [] - for vnffg in scenarioDict['vnffgs']: + for vnffg in scenarioDict.get('vnffgs', ()): for rsp in vnffg['rsps']: sfs_created = [] for cp in rsp['connection_points']: @@ -3585,6 +3604,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): db_net = { "uuid": net_uuid, 'vim_net_id': None, + "vim_name": net_name, "instance_scenario_id": instance_uuid, "net_id": net["uuid"], "created": True, @@ -3636,7 +3656,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): if sce_vnf.get('mgmt_access'): ssh_access = sce_vnf['mgmt_access'].get('config-access', {}).get('ssh-access') vnf_availability_zones = [] - for vm in sce_vnf['vms']: + for vm in sce_vnf.get('vms'): vm_av = vm.get('availability_zone') if vm_av and vm_av not in vnf_availability_zones: vnf_availability_zones.append(vm_av) @@ -3670,6 +3690,10 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): db_instance_vnfs.append(db_instance_vnf) for vm in sce_vnf['vms']: + # skip PDUs + if vm.get("pdu_type"): + continue + myVMDict = {} sce_vnf_name = sce_vnf['member_vnf_index'] if sce_vnf['member_vnf_index'] else sce_vnf['name'] myVMDict['name'] = "{}-{}-{}".format(instance_name[:64], sce_vnf_name[:64], vm["name"][:64]) @@ -3721,6 +3745,7 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): myVMDict['networks'] = [] task_depends_on = [] # TODO ALF. connect_mgmt_interfaces. Connect management interfaces if this is true + is_management_vm = False db_vm_ifaces = [] for iface in vm['interfaces']: netDict = {} @@ -3753,7 +3778,10 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): Try to delete and create the scenarios and VNFs again", httperrors.Conflict) else: raise NfvoException(e_text, httperrors.Internal_Server_Error) - if netDict["use"] == "mgmt" or netDict["use"] == "bridge": + if netDict["use"] == "mgmt": + is_management_vm = True + netDict["type"] = "virtual" + if netDict["use"] == "bridge": netDict["type"] = "virtual" if iface.get("vpci"): netDict['vpci'] = iface['vpci'] @@ -3807,9 +3835,16 @@ def instantiate_vnf(mydb, sce_vnf, params, params_out, rollbackList): # We add the RO key to cloud_config if vnf will need ssh access cloud_config_vm = cloud_config - if ssh_access and ssh_access['required'] and ssh_access['default-user'] and tenant[0].get('RO_pub_key'): - RO_key = {"key-pairs": [tenant[0]['RO_pub_key']]} - cloud_config_vm = unify_cloud_config(cloud_config_vm, RO_key) + if is_management_vm and params["instance_parameters"].get("mgmt_keys"): + cloud_config_vm = unify_cloud_config({"key-pairs": params["instance_parameters"]["mgmt_keys"]}, + cloud_config_vm) + + if vm.get("instance_parameters") and vm["instance_parameters"].get("mgmt_keys"): + cloud_config_vm = unify_cloud_config({"key-pairs": vm["instance_parameters"]["mgmt_keys"]}, + cloud_config_vm) + # if ssh_access and ssh_access['required'] and ssh_access['default-user'] and tenant[0].get('RO_pub_key'): + # RO_key = {"key-pairs": [tenant[0]['RO_pub_key']]} + # cloud_config_vm = unify_cloud_config(cloud_config_vm, RO_key) if vm.get("boot_data"): cloud_config_vm = unify_cloud_config(vm["boot_data"], cloud_config_vm) @@ -3916,68 +3951,21 @@ def delete_instance(mydb, tenant_id, instance_id): # "number_tasks": 0 # filled bellow } - # 2.1 deleting VMs - # vm_fail_list=[] - for sce_vnf in instanceDict['vnfs']: - datacenter_key = (sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"]) - vimthread_affected[sce_vnf["datacenter_tenant_id"]] = None - if datacenter_key not in myvims: - try: - _,myvim_thread = get_vim_thread(mydb, tenant_id, sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"]) - except NfvoException as e: - logger.error(str(e)) - myvim_thread = None - myvim_threads[datacenter_key] = myvim_thread - vims = get_vim(mydb, tenant_id, datacenter_id=sce_vnf["datacenter_id"], - datacenter_tenant_id=sce_vnf["datacenter_tenant_id"]) - if len(vims) == 0: - logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf["datacenter_id"], - sce_vnf["datacenter_tenant_id"])) - myvims[datacenter_key] = None - else: - myvims[datacenter_key] = vims.values()[0] - myvim = myvims[datacenter_key] - myvim_thread = myvim_threads[datacenter_key] - for vm in sce_vnf['vms']: - if not myvim: - error_msg += "\n VM id={} cannot be deleted because datacenter={} not found".format(vm['vim_vm_id'], sce_vnf["datacenter_id"]) - continue - db_vim_action = { - "instance_action_id": instance_action_id, - "task_index": task_index, - "datacenter_vim_id": sce_vnf["datacenter_tenant_id"], - "action": "DELETE", - "status": "SCHEDULED", - "item": "instance_vms", - "item_id": vm["uuid"], - "extra": yaml.safe_dump({"params": vm["interfaces"]}, - default_flow_style=True, width=256) - } - db_vim_actions.append(db_vim_action) - for interface in vm["interfaces"]: - if not interface.get("instance_net_id"): - continue - if interface["instance_net_id"] not in net2vm_dependencies: - net2vm_dependencies[interface["instance_net_id"]] = [] - net2vm_dependencies[interface["instance_net_id"]].append(task_index) - task_index += 1 - - # 2.2 deleting NETS - # net_fail_list=[] - for net in instanceDict['nets']: - vimthread_affected[net["datacenter_tenant_id"]] = None - datacenter_key = (net["datacenter_id"], net["datacenter_tenant_id"]) + # 2.1 deleting VNFFGs + for sfp in instanceDict.get('sfps', ()): + vimthread_affected[sfp["datacenter_tenant_id"]] = None + datacenter_key = (sfp["datacenter_id"], sfp["datacenter_tenant_id"]) if datacenter_key not in myvims: try: - _,myvim_thread = get_vim_thread(mydb, tenant_id, sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"]) + _, myvim_thread = get_vim_thread(mydb, tenant_id, sfp["datacenter_id"], sfp["datacenter_tenant_id"]) except NfvoException as e: logger.error(str(e)) myvim_thread = None myvim_threads[datacenter_key] = myvim_thread - vims = get_vim(mydb, tenant_id, datacenter_id=net["datacenter_id"], - datacenter_tenant_id=net["datacenter_tenant_id"]) + vims = get_vim(mydb, tenant_id, datacenter_id=sfp["datacenter_id"], + datacenter_tenant_id=sfp["datacenter_tenant_id"]) if len(vims) == 0: - logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net["datacenter_id"], net["datacenter_tenant_id"])) + logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sfp["datacenter_id"], sfp["datacenter_tenant_id"])) myvims[datacenter_key] = None else: myvims[datacenter_key] = vims.values()[0] @@ -3985,40 +3973,37 @@ def delete_instance(mydb, tenant_id, instance_id): myvim_thread = myvim_threads[datacenter_key] if not myvim: - error_msg += "\n Net VIM_id={} cannot be deleted because datacenter={} not found".format(net['vim_net_id'], net["datacenter_id"]) + error_msg += "\n vim_sfp_id={} cannot be deleted because datacenter={} not found".format(sfp['vim_sfp_id'], sfp["datacenter_id"]) continue - extra = {"params": (net['vim_net_id'], net['sdn_net_id'])} - if net2vm_dependencies.get(net["uuid"]): - extra["depends_on"] = net2vm_dependencies[net["uuid"]] + extra = {"params": (sfp['vim_sfp_id'])} db_vim_action = { "instance_action_id": instance_action_id, "task_index": task_index, - "datacenter_vim_id": net["datacenter_tenant_id"], + "datacenter_vim_id": sfp["datacenter_tenant_id"], "action": "DELETE", "status": "SCHEDULED", - "item": "instance_nets", - "item_id": net["uuid"], + "item": "instance_sfps", + "item_id": sfp["uuid"], "extra": yaml.safe_dump(extra, default_flow_style=True, width=256) } task_index += 1 db_vim_actions.append(db_vim_action) - # 2.3 deleting VNFFGs - - for sfp in instanceDict.get('sfps', ()): - vimthread_affected[sfp["datacenter_tenant_id"]] = None - datacenter_key = (sfp["datacenter_id"], sfp["datacenter_tenant_id"]) + for classification in instanceDict['classifications']: + vimthread_affected[classification["datacenter_tenant_id"]] = None + datacenter_key = (classification["datacenter_id"], classification["datacenter_tenant_id"]) if datacenter_key not in myvims: try: - _,myvim_thread = get_vim_thread(mydb, tenant_id, sfp["datacenter_id"], sfp["datacenter_tenant_id"]) + _, myvim_thread = get_vim_thread(mydb, tenant_id, classification["datacenter_id"], classification["datacenter_tenant_id"]) except NfvoException as e: logger.error(str(e)) myvim_thread = None myvim_threads[datacenter_key] = myvim_thread - vims = get_vim(mydb, tenant_id, datacenter_id=sfp["datacenter_id"], - datacenter_tenant_id=sfp["datacenter_tenant_id"]) + vims = get_vim(mydb, tenant_id, datacenter_id=classification["datacenter_id"], + datacenter_tenant_id=classification["datacenter_tenant_id"]) if len(vims) == 0: - logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sfp["datacenter_id"], sfp["datacenter_tenant_id"])) + logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(classification["datacenter_id"], + classification["datacenter_tenant_id"])) myvims[datacenter_key] = None else: myvims[datacenter_key] = vims.values()[0] @@ -4026,17 +4011,19 @@ def delete_instance(mydb, tenant_id, instance_id): myvim_thread = myvim_threads[datacenter_key] if not myvim: - error_msg += "\n vim_sfp_id={} cannot be deleted because datacenter={} not found".format(sfp['vim_sfp_id'], sfp["datacenter_id"]) + error_msg += "\n vim_classification_id={} cannot be deleted because datacenter={} not found".format(classification['vim_classification_id'], + classification["datacenter_id"]) continue - extra = {"params": (sfp['vim_sfp_id'])} + depends_on = [action["task_index"] for action in db_vim_actions if action["item"] == "instance_sfps"] + extra = {"params": (classification['vim_classification_id']), "depends_on": depends_on} db_vim_action = { "instance_action_id": instance_action_id, "task_index": task_index, - "datacenter_vim_id": sfp["datacenter_tenant_id"], + "datacenter_vim_id": classification["datacenter_tenant_id"], "action": "DELETE", "status": "SCHEDULED", - "item": "instance_sfps", - "item_id": sfp["uuid"], + "item": "instance_classifications", + "item_id": classification["uuid"], "extra": yaml.safe_dump(extra, default_flow_style=True, width=256) } task_index += 1 @@ -4047,7 +4034,7 @@ def delete_instance(mydb, tenant_id, instance_id): datacenter_key = (sf["datacenter_id"], sf["datacenter_tenant_id"]) if datacenter_key not in myvims: try: - _,myvim_thread = get_vim_thread(mydb, tenant_id, sf["datacenter_id"], sf["datacenter_tenant_id"]) + _, myvim_thread = get_vim_thread(mydb, tenant_id, sf["datacenter_id"], sf["datacenter_tenant_id"]) except NfvoException as e: logger.error(str(e)) myvim_thread = None @@ -4065,7 +4052,8 @@ def delete_instance(mydb, tenant_id, instance_id): if not myvim: error_msg += "\n vim_sf_id={} cannot be deleted because datacenter={} not found".format(sf['vim_sf_id'], sf["datacenter_id"]) continue - extra = {"params": (sf['vim_sf_id'])} + depends_on = [action["task_index"] for action in db_vim_actions if action["item"] == "instance_sfps"] + extra = {"params": (sf['vim_sf_id']), "depends_on": depends_on} db_vim_action = { "instance_action_id": instance_action_id, "task_index": task_index, @@ -4084,7 +4072,7 @@ def delete_instance(mydb, tenant_id, instance_id): datacenter_key = (sfi["datacenter_id"], sfi["datacenter_tenant_id"]) if datacenter_key not in myvims: try: - _,myvim_thread = get_vim_thread(mydb, tenant_id, sfi["datacenter_id"], sfi["datacenter_tenant_id"]) + _, myvim_thread = get_vim_thread(mydb, tenant_id, sfi["datacenter_id"], sfi["datacenter_tenant_id"]) except NfvoException as e: logger.error(str(e)) myvim_thread = None @@ -4102,7 +4090,8 @@ def delete_instance(mydb, tenant_id, instance_id): if not myvim: error_msg += "\n vim_sfi_id={} cannot be deleted because datacenter={} not found".format(sfi['vim_sfi_id'], sfi["datacenter_id"]) continue - extra = {"params": (sfi['vim_sfi_id'])} + depends_on = [action["task_index"] for action in db_vim_actions if action["item"] == "instance_sfs"] + extra = {"params": (sfi['vim_sfi_id']), "depends_on": depends_on} db_vim_action = { "instance_action_id": instance_action_id, "task_index": task_index, @@ -4116,20 +4105,70 @@ def delete_instance(mydb, tenant_id, instance_id): task_index += 1 db_vim_actions.append(db_vim_action) - for classification in instanceDict['classifications']: - vimthread_affected[classification["datacenter_tenant_id"]] = None - datacenter_key = (classification["datacenter_id"], classification["datacenter_tenant_id"]) + # 2.2 deleting VMs + # vm_fail_list=[] + for sce_vnf in instanceDict.get('vnfs', ()): + datacenter_key = (sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"]) + vimthread_affected[sce_vnf["datacenter_tenant_id"]] = None if datacenter_key not in myvims: try: - _,myvim_thread = get_vim_thread(mydb, tenant_id, classification["datacenter_id"], classification["datacenter_tenant_id"]) + _, myvim_thread = get_vim_thread(mydb, tenant_id, sce_vnf["datacenter_id"], sce_vnf["datacenter_tenant_id"]) except NfvoException as e: logger.error(str(e)) myvim_thread = None myvim_threads[datacenter_key] = myvim_thread - vims = get_vim(mydb, tenant_id, datacenter_id=classification["datacenter_id"], - datacenter_tenant_id=classification["datacenter_tenant_id"]) + vims = get_vim(mydb, tenant_id, datacenter_id=sce_vnf["datacenter_id"], + datacenter_tenant_id=sce_vnf["datacenter_tenant_id"]) if len(vims) == 0: - logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(classification["datacenter_id"], classification["datacenter_tenant_id"])) + logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(sce_vnf["datacenter_id"], + sce_vnf["datacenter_tenant_id"])) + myvims[datacenter_key] = None + else: + myvims[datacenter_key] = vims.values()[0] + myvim = myvims[datacenter_key] + myvim_thread = myvim_threads[datacenter_key] + + for vm in sce_vnf['vms']: + if not myvim: + error_msg += "\n VM id={} cannot be deleted because datacenter={} not found".format(vm['vim_vm_id'], sce_vnf["datacenter_id"]) + continue + sfi_dependencies = [action["task_index"] for action in db_vim_actions if action["item"] == "instance_sfis"] + db_vim_action = { + "instance_action_id": instance_action_id, + "task_index": task_index, + "datacenter_vim_id": sce_vnf["datacenter_tenant_id"], + "action": "DELETE", + "status": "SCHEDULED", + "item": "instance_vms", + "item_id": vm["uuid"], + "extra": yaml.safe_dump({"params": vm["interfaces"], "depends_on": sfi_dependencies}, + default_flow_style=True, width=256) + } + db_vim_actions.append(db_vim_action) + for interface in vm["interfaces"]: + if not interface.get("instance_net_id"): + continue + if interface["instance_net_id"] not in net2vm_dependencies: + net2vm_dependencies[interface["instance_net_id"]] = [] + net2vm_dependencies[interface["instance_net_id"]].append(task_index) + task_index += 1 + + # 2.3 deleting NETS + # net_fail_list=[] + for net in instanceDict['nets']: + vimthread_affected[net["datacenter_tenant_id"]] = None + datacenter_key = (net["datacenter_id"], net["datacenter_tenant_id"]) + if datacenter_key not in myvims: + try: + _,myvim_thread = get_vim_thread(mydb, tenant_id, net["datacenter_id"], net["datacenter_tenant_id"]) + except NfvoException as e: + logger.error(str(e)) + myvim_thread = None + myvim_threads[datacenter_key] = myvim_thread + vims = get_vim(mydb, tenant_id, datacenter_id=net["datacenter_id"], + datacenter_tenant_id=net["datacenter_tenant_id"]) + if len(vims) == 0: + logger.error("datacenter '{}' with datacenter_tenant_id '{}' not found".format(net["datacenter_id"], net["datacenter_tenant_id"])) myvims[datacenter_key] = None else: myvims[datacenter_key] = vims.values()[0] @@ -4137,17 +4176,25 @@ def delete_instance(mydb, tenant_id, instance_id): myvim_thread = myvim_threads[datacenter_key] if not myvim: - error_msg += "\n vim_classification_id={} cannot be deleted because datacenter={} not found".format(classification['vim_classification_id'], classification["datacenter_id"]) + error_msg += "\n Net VIM_id={} cannot be deleted because datacenter={} not found".format(net['vim_net_id'], net["datacenter_id"]) continue - extra = {"params": (classification['vim_classification_id'])} + extra = {"params": (net['vim_net_id'], net['sdn_net_id'])} + if net2vm_dependencies.get(net["uuid"]): + extra["depends_on"] = net2vm_dependencies[net["uuid"]] + sfi_dependencies = [action["task_index"] for action in db_vim_actions if action["item"] == "instance_sfis"] + if len(sfi_dependencies) > 0: + if "depends_on" in extra: + extra["depends_on"] += sfi_dependencies + else: + extra["depends_on"] = sfi_dependencies db_vim_action = { "instance_action_id": instance_action_id, "task_index": task_index, - "datacenter_vim_id": classification["datacenter_tenant_id"], + "datacenter_vim_id": net["datacenter_tenant_id"], "action": "DELETE", "status": "SCHEDULED", - "item": "instance_classifications", - "item_id": classification["uuid"], + "item": "instance_nets", + "item_id": net["uuid"], "extra": yaml.safe_dump(extra, default_flow_style=True, width=256) } task_index += 1 @@ -4392,6 +4439,8 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict): "description": "SCALE", } vm_result["instance_action_id"] = instance_action_id + vm_result["created"] = [] + vm_result["deleted"] = [] task_index = 0 for vdu in action_dict["vdu-scaling"]: vdu_id = vdu.get("vdu-id") @@ -4399,56 +4448,60 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict): member_vnf_index = vdu.get("member-vnf-index") vdu_count = vdu.get("count", 1) if vdu_id: - target_vm = mydb.get_rows( + target_vms = mydb.get_rows( FROM="instance_vms as vms join instance_vnfs as vnfs on vms.instance_vnf_id=vnfs.uuid", WHERE={"vms.uuid": vdu_id}, ORDER_BY="vms.created_at" ) - if not target_vm: + if not target_vms: raise NfvoException("Cannot find the vdu with id {}".format(vdu_id), httperrors.Not_Found) else: if not osm_vdu_id and not member_vnf_index: - raise NfvoException("Invalid imput vdu parameters. Must supply either 'vdu-id' of 'osm_vdu_id','member-vnf-index'") - target_vm = mydb.get_rows( + raise NfvoException("Invalid input vdu parameters. Must supply either 'vdu-id' of 'osm_vdu_id','member-vnf-index'") + target_vms = mydb.get_rows( # SELECT=("ivms.uuid", "ivnfs.datacenter_id", "ivnfs.datacenter_tenant_id"), FROM="instance_vms as ivms join instance_vnfs as ivnfs on ivms.instance_vnf_id=ivnfs.uuid"\ " join sce_vnfs as svnfs on ivnfs.sce_vnf_id=svnfs.uuid"\ " join vms on ivms.vm_id=vms.uuid", - WHERE={"vms.osm_id": osm_vdu_id, "svnfs.member_vnf_index": member_vnf_index}, + WHERE={"vms.osm_id": osm_vdu_id, "svnfs.member_vnf_index": member_vnf_index, + "ivnfs.instance_scenario_id": instance_id}, ORDER_BY="ivms.created_at" ) - if not target_vm: + if not target_vms: raise NfvoException("Cannot find the vdu with osm_vdu_id {} and member-vnf-index {}".format(osm_vdu_id, member_vnf_index), httperrors.Not_Found) - vdu_id = target_vm[-1]["uuid"] - vm_result[vdu_id] = {"created": [], "deleted": [], "description": "scheduled"} - target_vm = target_vm[-1] + vdu_id = target_vms[-1]["uuid"] + target_vm = target_vms[-1] datacenter = target_vm["datacenter_id"] myvim_threads_id[datacenter], _ = get_vim_thread(mydb, nfvo_tenant, datacenter) + if vdu["type"] == "delete": - # look for nm - vm_interfaces = None - for sce_vnf in instanceDict['vnfs']: - for vm in sce_vnf['vms']: - if vm["uuid"] == vdu_id: - vm_interfaces = vm["interfaces"] - break + for index in range(0, vdu_count): + target_vm = target_vms[-1-index] + vdu_id = target_vm["uuid"] + # look for nm + vm_interfaces = None + for sce_vnf in instanceDict['vnfs']: + for vm in sce_vnf['vms']: + if vm["uuid"] == vdu_id: + vm_interfaces = vm["interfaces"] + break - db_vim_action = { - "instance_action_id": instance_action_id, - "task_index": task_index, - "datacenter_vim_id": target_vm["datacenter_tenant_id"], - "action": "DELETE", - "status": "SCHEDULED", - "item": "instance_vms", - "item_id": target_vm["uuid"], - "extra": yaml.safe_dump({"params": vm_interfaces}, - default_flow_style=True, width=256) - } - task_index += 1 - db_vim_actions.append(db_vim_action) - vm_result[vdu_id]["deleted"].append(vdu_id) - # delete from database - db_instance_vms.append({"TO-DELETE": vdu_id}) + db_vim_action = { + "instance_action_id": instance_action_id, + "task_index": task_index, + "datacenter_vim_id": target_vm["datacenter_tenant_id"], + "action": "DELETE", + "status": "SCHEDULED", + "item": "instance_vms", + "item_id": vdu_id, + "extra": yaml.safe_dump({"params": vm_interfaces}, + default_flow_style=True, width=256) + } + task_index += 1 + db_vim_actions.append(db_vim_action) + vm_result["deleted"].append(vdu_id) + # delete from database + db_instance_vms.append({"TO-DELETE": vdu_id}) else: # vdu["type"] == "create": iface2iface = {} @@ -4483,7 +4536,7 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict): vm_name = target_vm.get('vim_name') try: suffix = vm_name.rfind("-") - vm_name = vm_name[:suffix+1] + str(1 + int(vm_name[suffix+1:])) + vm_name = vm_name[:suffix+1] + str(index + 1 + int(vm_name[suffix+1:])) except Exception: pass db_instance_vm = { @@ -4540,7 +4593,7 @@ def instance_action(mydb,nfvo_tenant,instance_id, action_dict): } task_index += 1 db_vim_actions.append(db_vim_action) - vm_result[vdu_id]["created"].append(vm_uuid) + vm_result["created"].append(vm_uuid) db_instance_action["number_tasks"] = task_index db_tables = [ @@ -4787,7 +4840,7 @@ def edit_datacenter(mydb, datacenter_id_name, datacenter_descriptor): try: datacenter_sdn_port_mapping_delete(mydb, None, datacenter_id) except ovimException as e: - raise NfvoException("Error deleting datacenter-port-mapping " + str(e), HTTP_Conflict) + raise NfvoException("Error deleting datacenter-port-mapping " + str(e), httperrors.Conflict) mydb.update_rows('datacenters', datacenter_descriptor, where) if new_sdn_port_mapping: @@ -4796,7 +4849,7 @@ def edit_datacenter(mydb, datacenter_id_name, datacenter_descriptor): except ovimException as e: # Rollback mydb.update_rows('datacenters', datacenter, where) - raise NfvoException("Error adding datacenter-port-mapping " + str(e), HTTP_Conflict) + raise NfvoException("Error adding datacenter-port-mapping " + str(e), httperrors.Conflict) return datacenter_id diff --git a/osm_ro/nfvo_db.py b/osm_ro/nfvo_db.py index b1224436..9d528030 100644 --- a/osm_ro/nfvo_db.py +++ b/osm_ro/nfvo_db.py @@ -1,7 +1,7 @@ # -*- 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. # @@ -612,7 +612,7 @@ class nfvo_db(db_base.db_base): # vms cmd = "SELECT vms.uuid as uuid, flavor_id, image_id, image_list, vms.name as name," \ " vms.description as description, vms.boot_data as boot_data, count," \ - " vms.availability_zone as availability_zone, vms.osm_id as osm_id" \ + " vms.availability_zone as availability_zone, vms.osm_id as osm_id, vms.pdu_type" \ " FROM vnfs join vms on vnfs.uuid=vms.vnf_id" \ " WHERE vnfs.uuid='" + vnf['vnf_id'] + "'" \ " ORDER BY vms.created_at" @@ -997,7 +997,7 @@ class nfvo_db(db_base.db_base): self.cur.execute(cmd) instance_dict['vnfs'] = self.cur.fetchall() for vnf in instance_dict['vnfs']: - + vnf["ip_address"] = None vnf_mgmt_access_iface = None vnf_mgmt_access_vm = None if vnf["mgmt_access"]: @@ -1026,7 +1026,8 @@ class nfvo_db(db_base.db_base): vm['interfaces'] = self.cur.fetchall() for iface in vm['interfaces']: if vnf_mgmt_access_iface and vnf_mgmt_access_iface == iface["uuid"]: - vnf["ip_address"] = iface["ip_address"] + if not vnf["ip_address"]: + vnf["ip_address"] = iface["ip_address"] if iface["type"] == "mgmt" and iface["ip_address"]: vm_manage_iface_list.append(iface["ip_address"]) if not verbose: @@ -1034,9 +1035,7 @@ class nfvo_db(db_base.db_base): del iface["uuid"] if vm_manage_iface_list: vm["ip_address"] = ",".join(vm_manage_iface_list) - if vnf_mgmt_access_vm == vm["vm_uuid"]: - vnf["ip_address"] = vm["ip_address"] - elif not vnf.get("ip_address"): + if not vnf["ip_address"] and vnf_mgmt_access_vm == vm["vm_uuid"]: vnf["ip_address"] = vm["ip_address"] del vm["vm_uuid"] @@ -1045,9 +1044,12 @@ class nfvo_db(db_base.db_base): #from_text = "instance_nets join instance_scenarios on instance_nets.instance_scenario_id=instance_scenarios.uuid " + \ # "join sce_nets on instance_scenarios.scenario_id=sce_nets.scenario_id" #where_text = "instance_nets.instance_scenario_id='"+ instance_dict['uuid'] + "'" - cmd = "SELECT uuid,vim_net_id,status,error_msg,vim_info,created, sce_net_id, net_id as vnf_net_id, datacenter_id, datacenter_tenant_id, sdn_net_id"\ - " FROM instance_nets" \ - " WHERE instance_scenario_id='{}' ORDER BY created_at".format(instance_dict['uuid']) + cmd = "SELECT inets.uuid as uuid,vim_net_id,status,error_msg,vim_info,created, sce_net_id, " \ + "net_id as vnf_net_id, datacenter_id, datacenter_tenant_id, sdn_net_id, " \ + "snets.osm_id as ns_net_osm_id, nets.osm_id as vnf_net_osm_id, inets.vim_name " \ + "FROM instance_nets as inets left join sce_nets as snets on inets.sce_net_id=snets.uuid " \ + "left join nets on inets.net_id=nets.uuid " \ + "WHERE instance_scenario_id='{}' ORDER BY inets.created_at".format(instance_dict['uuid']) self.logger.debug(cmd) self.cur.execute(cmd) instance_dict['nets'] = self.cur.fetchall() diff --git a/osm_ro/openmano_schemas.py b/osm_ro/openmano_schemas.py index 2d9dfae8..d10f8621 100644 --- a/osm_ro/openmano_schemas.py +++ b/osm_ro/openmano_schemas.py @@ -1,7 +1,7 @@ # -*- 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. # @@ -37,7 +37,8 @@ description_schema={"type" : ["string","null"], "maxLength":255, "pattern" : "^[ id_schema_fake = {"type" : "string", "minLength":2, "maxLength":36 } #"pattern": "^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$" id_schema = {"type" : "string", "pattern": "^[a-fA-F0-9]{8}(-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}$"} pci_schema={"type":"string", "pattern":"^[0-9a-fA-F]{4}(:[0-9a-fA-F]{2}){2}\.[0-9a-fA-F]$"} -pci_extended_schema = {"type": "string", "pattern": "^[0-9a-fA-F.:-\[\]]$"} +# allows [] for wildcards. For that reason huge length limit is set +pci_extended_schema = {"type": "string", "pattern": "^[0-9a-fA-F.:-\[\]]{12,40}$"} http_schema={"type":"string", "pattern":"^https?://[^'\"=]+$"} bandwidth_schema={"type":"string", "pattern" : "^[0-9]+ *([MG]bps)?$"} @@ -466,7 +467,7 @@ bridge_interfaces_schema={ "bandwidth":bandwidth_schema, "vpci":pci_schema, "mac_address": mac_schema, - "model": {"type":"string", "enum":["virtio","e1000","ne2k_pci","pcnet","rtl8139"]}, + "model": {"type":"string", "enum":["virtio","e1000","ne2k_pci","pcnet","rtl8139", "paravirt"]}, "port-security": {"type" : "boolean"}, "floating-ip": {"type" : "boolean"} }, @@ -964,19 +965,45 @@ scenario_action_schema = { "additionalProperties": False } +instance_scenario_object = { + "title": "scenario object used to create an instance not based on any nsd", + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "properties": { + "nets": { + "type": "array", + "minLength": 1, + "items": { + "type": "object", + "properties": { + "name": name_schema, + "external": {"type": "boolean"}, + "type": {"enum": ["bridge", "ptp", "data"]}, # for overlay, underlay E-LINE, underlay E-LAN + }, + "additionalProperties": False, + "required": ["name", "external", "type"] + } + } + }, + "additionalProperties": False, + "required": ["nets"] +} + instance_scenario_create_schema_v01 = { - "title":"instance scenario create information schema v0.1", + "title": "instance scenario create information schema v0.1", "$schema": "http://json-schema.org/draft-04/schema#", - "type":"object", - "properties":{ + "type": "object", + "properties": { "schema_version": {"type": "string", "enum": ["0.1"]}, - "instance":{ - "type":"object", - "properties":{ - "name":name_schema, + "instance": { + "type": "object", + "properties": { + "mgmt_keys": {"type": "array", "items": {"type":"string"}}, + "vduImage": name_schema, + "name": name_schema, "description":description_schema, "datacenter": name_schema, - "scenario" : name_schema, #can be an UUID or name + "scenario" : {"oneOff": [name_schema, instance_scenario_object]}, # can be an UUID or name or a dict "action":{"enum": ["deploy","reserve","verify" ]}, "connect_mgmt_interfaces": {"oneOf": [{"type":"boolean"}, {"type":"object"}]},# can be true or a dict with datacenter: net_name "cloud-config": cloud_config_schema, #common to all vnfs in the instance scenario @@ -997,7 +1024,9 @@ instance_scenario_create_schema_v01 = { ".": { "type": "object", "properties": { - "name": name_schema, # overrides vdu name schema + "name": name_schema, # overrides vdu name schema + "mgmt_keys": {"type": "array", "items": {"type": "string"}}, + "vduImage": name_schema, "devices": { "type": "object", "patternProperties": { diff --git a/osm_ro/openmanoclient.py b/osm_ro/openmanoclient.py index ece30aad..e15824ab 100644 --- a/osm_ro/openmanoclient.py +++ b/osm_ro/openmanoclient.py @@ -2,7 +2,7 @@ # -*- 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. # diff --git a/osm_ro/openmanod.cfg b/osm_ro/openmanod.cfg index cf3d00c4..3565bbfc 100644 --- a/osm_ro/openmanod.cfg +++ b/osm_ro/openmanod.cfg @@ -1,5 +1,5 @@ ## -# 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. # @@ -62,7 +62,7 @@ auto_push_VNF_to_VIMs: False # by default True #general logging parameters #choose among: DEBUG, INFO, WARNING, ERROR, CRITICAL -log_level: DEBUG #general log levels for internal logging +log_level: INFO #general log levels for internal logging #standard output is used unless 'log_file' is specify #log_file: /var/log/openmano/openmano.log diff --git a/osm_ro/tests/test_vimconn_openstack.py b/osm_ro/tests/test_vimconn_openstack.py index aa6cf3c0..5eb23f07 100644 --- a/osm_ro/tests/test_vimconn_openstack.py +++ b/osm_ro/tests/test_vimconn_openstack.py @@ -45,7 +45,7 @@ class TestSfcOperations(unittest.TestCase): '123', 'openstackvim', '456', '789', 'http://dummy.url', None, 'user', 'pass') - def _test_new_sfi(self, create_port_pair, sfc_encap, + def _test_new_sfi(self, create_sfc_port_pair, sfc_encap, ingress_ports=['5311c75d-d718-4369-bbda-cdcc6da60fcc'], egress_ports=['230cdf1b-de37-4891-bc07-f9010cf1f967']): # input to VIM connector @@ -53,7 +53,7 @@ class TestSfcOperations(unittest.TestCase): # + ingress_ports # + egress_ports # TODO(igordc): must be changed to NSH in Queens (MPLS is a workaround) - correlation = 'mpls' + correlation = 'nsh' if sfc_encap is not None: if not sfc_encap: correlation = None @@ -69,7 +69,7 @@ class TestSfcOperations(unittest.TestCase): 'egress': egress_ports[0] if len(egress_ports) else None, 'service_function_parameters': {'correlation': correlation} }} - create_port_pair.return_value = dict_from_neutron + create_sfc_port_pair.return_value = dict_from_neutron # what the VIM connector is expected to # send to OpenStack based on the input @@ -88,11 +88,11 @@ class TestSfcOperations(unittest.TestCase): sfc_encap) # assert that the VIM connector made the expected call to OpenStack - create_port_pair.assert_called_with(dict_to_neutron) + create_sfc_port_pair.assert_called_with(dict_to_neutron) # assert that the VIM connector had the expected result / return value self.assertEqual(result, dict_from_neutron['port_pair']['id']) - def _test_new_sf(self, create_port_pair_group): + def _test_new_sf(self, create_sfc_port_pair_group): # input to VIM connector name = 'osm_sf' instances = ['bbd01220-cf72-41f2-9e70-0669c2e5c4cd', @@ -115,7 +115,7 @@ class TestSfcOperations(unittest.TestCase): "egress_n_tuple": {} }} }} - create_port_pair_group.return_value = dict_from_neutron + create_sfc_port_pair_group.return_value = dict_from_neutron # what the VIM connector is expected to # send to OpenStack based on the input @@ -130,11 +130,11 @@ class TestSfcOperations(unittest.TestCase): result = self.vimconn.new_sf(name, instances) # assert that the VIM connector made the expected call to OpenStack - create_port_pair_group.assert_called_with(dict_to_neutron) + create_sfc_port_pair_group.assert_called_with(dict_to_neutron) # assert that the VIM connector had the expected result / return value self.assertEqual(result, dict_from_neutron['port_pair_group']['id']) - def _test_new_sfp(self, create_port_chain, sfc_encap, spi): + def _test_new_sfp(self, create_sfc_port_chain, sfc_encap, spi): # input to VIM connector name = 'osm_sfp' classifications = ['2bd2a2e5-c5fd-4eac-a297-d5e255c35c19', @@ -143,11 +143,8 @@ class TestSfcOperations(unittest.TestCase): 'd8bfdb5d-195e-4f34-81aa-6135705317df'] # TODO(igordc): must be changed to NSH in Queens (MPLS is a workaround) - correlation = 'mpls' + correlation = 'nsh' chain_id = 33 - if sfc_encap is not None: - if not sfc_encap: - correlation = None if spi: chain_id = spi @@ -163,7 +160,7 @@ class TestSfcOperations(unittest.TestCase): 'port_pair_groups': sfs, 'chain_parameters': {'correlation': correlation} }} - create_port_chain.return_value = dict_from_neutron + create_sfc_port_chain.return_value = dict_from_neutron # what the VIM connector is expected to # send to OpenStack based on the input @@ -194,11 +191,11 @@ class TestSfcOperations(unittest.TestCase): sfc_encap, spi) # assert that the VIM connector made the expected call to OpenStack - create_port_chain.assert_called_with(dict_to_neutron) + create_sfc_port_chain.assert_called_with(dict_to_neutron) # assert that the VIM connector had the expected result / return value self.assertEqual(result, dict_from_neutron['port_chain']['id']) - def _test_new_classification(self, create_flow_classifier, ctype): + def _test_new_classification(self, create_sfc_flow_classifier, ctype): # input to VIM connector name = 'osm_classification' definition = {'ethertype': 'IPv4', @@ -219,7 +216,7 @@ class TestSfcOperations(unittest.TestCase): 'tenant_id'] = '130b1e97-b0f1-40a8-8804-b6ad9b8c3e0c' dict_from_neutron['flow_classifier'][ 'project_id'] = '130b1e97-b0f1-40a8-8804-b6ad9b8c3e0c' - create_flow_classifier.return_value = dict_from_neutron + create_sfc_flow_classifier.return_value = dict_from_neutron # what the VIM connector is expected to # send to OpenStack based on the input @@ -230,100 +227,96 @@ class TestSfcOperations(unittest.TestCase): result = self.vimconn.new_classification(name, ctype, definition) # assert that the VIM connector made the expected call to OpenStack - create_flow_classifier.assert_called_with(dict_to_neutron) + create_sfc_flow_classifier.assert_called_with(dict_to_neutron) # assert that the VIM connector had the expected result / return value self.assertEqual(result, dict_from_neutron['flow_classifier']['id']) - @mock.patch.object(Client, 'create_flow_classifier') - def test_new_classification(self, create_flow_classifier): - self._test_new_classification(create_flow_classifier, + @mock.patch.object(Client, 'create_sfc_flow_classifier') + def test_new_classification(self, create_sfc_flow_classifier): + self._test_new_classification(create_sfc_flow_classifier, 'legacy_flow_classifier') - @mock.patch.object(Client, 'create_flow_classifier') - def test_new_classification_unsupported_type(self, create_flow_classifier): + @mock.patch.object(Client, 'create_sfc_flow_classifier') + def test_new_classification_unsupported_type(self, create_sfc_flow_classifier): self.assertRaises(vimconn.vimconnNotSupportedException, self._test_new_classification, - create_flow_classifier, 'h265') + create_sfc_flow_classifier, 'h265') - @mock.patch.object(Client, 'create_port_pair') - def test_new_sfi_with_sfc_encap(self, create_port_pair): - self._test_new_sfi(create_port_pair, True) + @mock.patch.object(Client, 'create_sfc_port_pair') + def test_new_sfi_with_sfc_encap(self, create_sfc_port_pair): + self._test_new_sfi(create_sfc_port_pair, True) - @mock.patch.object(Client, 'create_port_pair') - def test_new_sfi_without_sfc_encap(self, create_port_pair): - self._test_new_sfi(create_port_pair, False) + @mock.patch.object(Client, 'create_sfc_port_pair') + def test_new_sfi_without_sfc_encap(self, create_sfc_port_pair): + self._test_new_sfi(create_sfc_port_pair, False) - @mock.patch.object(Client, 'create_port_pair') - def test_new_sfi_default_sfc_encap(self, create_port_pair): - self._test_new_sfi(create_port_pair, None) + @mock.patch.object(Client, 'create_sfc_port_pair') + def test_new_sfi_default_sfc_encap(self, create_sfc_port_pair): + self._test_new_sfi(create_sfc_port_pair, None) - @mock.patch.object(Client, 'create_port_pair') - def test_new_sfi_bad_ingress_ports(self, create_port_pair): + @mock.patch.object(Client, 'create_sfc_port_pair') + def test_new_sfi_bad_ingress_ports(self, create_sfc_port_pair): ingress_ports = ['5311c75d-d718-4369-bbda-cdcc6da60fcc', 'a0273f64-82c9-11e7-b08f-6328e53f0fa7'] self.assertRaises(vimconn.vimconnNotSupportedException, self._test_new_sfi, - create_port_pair, True, ingress_ports=ingress_ports) + create_sfc_port_pair, True, ingress_ports=ingress_ports) ingress_ports = [] self.assertRaises(vimconn.vimconnNotSupportedException, self._test_new_sfi, - create_port_pair, True, ingress_ports=ingress_ports) + create_sfc_port_pair, True, ingress_ports=ingress_ports) - @mock.patch.object(Client, 'create_port_pair') - def test_new_sfi_bad_egress_ports(self, create_port_pair): + @mock.patch.object(Client, 'create_sfc_port_pair') + def test_new_sfi_bad_egress_ports(self, create_sfc_port_pair): egress_ports = ['230cdf1b-de37-4891-bc07-f9010cf1f967', 'b41228fe-82c9-11e7-9b44-17504174320b'] self.assertRaises(vimconn.vimconnNotSupportedException, self._test_new_sfi, - create_port_pair, True, egress_ports=egress_ports) + create_sfc_port_pair, True, egress_ports=egress_ports) egress_ports = [] self.assertRaises(vimconn.vimconnNotSupportedException, self._test_new_sfi, - create_port_pair, True, egress_ports=egress_ports) + create_sfc_port_pair, True, egress_ports=egress_ports) @mock.patch.object(vimconnector, 'get_sfi') - @mock.patch.object(Client, 'create_port_pair_group') - def test_new_sf(self, create_port_pair_group, get_sfi): - get_sfi.return_value = {'sfc_encap': 'mpls'} - self._test_new_sf(create_port_pair_group) + @mock.patch.object(Client, 'create_sfc_port_pair_group') + def test_new_sf(self, create_sfc_port_pair_group, get_sfi): + get_sfi.return_value = {'sfc_encap': True} + self._test_new_sf(create_sfc_port_pair_group) @mock.patch.object(vimconnector, 'get_sfi') - @mock.patch.object(Client, 'create_port_pair_group') - def test_new_sf_inconsistent_sfc_encap(self, create_port_pair_group, + @mock.patch.object(Client, 'create_sfc_port_pair_group') + def test_new_sf_inconsistent_sfc_encap(self, create_sfc_port_pair_group, get_sfi): get_sfi.return_value = {'sfc_encap': 'nsh'} self.assertRaises(vimconn.vimconnNotSupportedException, - self._test_new_sf, create_port_pair_group) + self._test_new_sf, create_sfc_port_pair_group) - @mock.patch.object(Client, 'create_port_chain') - def test_new_sfp_with_sfc_encap(self, create_port_chain): - self._test_new_sfp(create_port_chain, True, None) + @mock.patch.object(Client, 'create_sfc_port_chain') + def test_new_sfp_with_sfc_encap(self, create_sfc_port_chain): + self._test_new_sfp(create_sfc_port_chain, True, None) - @mock.patch.object(Client, 'create_port_chain') - def test_new_sfp_without_sfc_encap(self, create_port_chain): - self.assertRaises(vimconn.vimconnNotSupportedException, - self._test_new_sfp, - create_port_chain, False, None) - self.assertRaises(vimconn.vimconnNotSupportedException, - self._test_new_sfp, - create_port_chain, False, 25) + @mock.patch.object(Client, 'create_sfc_port_chain') + def test_new_sfp_without_sfc_encap(self, create_sfc_port_chain): + self._test_new_sfp(create_sfc_port_chain, False, None) + self._test_new_sfp(create_sfc_port_chain, False, 25) - @mock.patch.object(Client, 'create_port_chain') - def test_new_sfp_default_sfc_encap(self, create_port_chain): - self._test_new_sfp(create_port_chain, None, None) + @mock.patch.object(Client, 'create_sfc_port_chain') + def test_new_sfp_default_sfc_encap(self, create_sfc_port_chain): + self._test_new_sfp(create_sfc_port_chain, None, None) - @mock.patch.object(Client, 'create_port_chain') - def test_new_sfp_with_sfc_encap_spi(self, create_port_chain): - self._test_new_sfp(create_port_chain, True, 25) + @mock.patch.object(Client, 'create_sfc_port_chain') + def test_new_sfp_with_sfc_encap_spi(self, create_sfc_port_chain): + self._test_new_sfp(create_sfc_port_chain, True, 25) - @mock.patch.object(Client, 'create_port_chain') - def test_new_sfp_default_sfc_encap_spi(self, create_port_chain): - self._test_new_sfp(create_port_chain, None, 25) + @mock.patch.object(Client, 'create_sfc_port_chain') + def test_new_sfp_default_sfc_encap_spi(self, create_sfc_port_chain): + self._test_new_sfp(create_sfc_port_chain, None, 25) - @mock.patch.object(Client, 'list_flow_classifier') - def test_get_classification_list(self, list_flow_classifier): + @mock.patch.object(Client, 'list_sfc_flow_classifiers') + def test_get_classification_list(self, list_sfc_flow_classifiers): # what OpenStack is assumed to return to the VIM connector - list_flow_classifier.return_value = {'flow_classifiers': [ + list_sfc_flow_classifiers.return_value = {'flow_classifiers': [ {'source_port_range_min': 2000, 'destination_ip_prefix': '192.168.3.0/24', 'protocol': 'udp', @@ -346,7 +339,7 @@ class TestSfcOperations(unittest.TestCase): result = self.vimconn.get_classification_list(filter_dict.copy()) # assert that VIM connector called OpenStack with the expected filter - list_flow_classifier.assert_called_with(**filter_dict) + list_sfc_flow_classifiers.assert_called_with(**filter_dict) # assert that the VIM connector successfully # translated and returned the OpenStack result self.assertEqual(result, [ @@ -400,18 +393,18 @@ class TestSfcOperations(unittest.TestCase): 'id': 'c121ebdd-7f2d-4213-b933-3325298a6966', 'name': 'osm_sfi'}]) - @mock.patch.object(Client, 'list_port_pair') - def test_get_sfi_list_with_sfc_encap(self, list_port_pair): - self._test_get_sfi_list(list_port_pair, 'nsh', True) + @mock.patch.object(Client, 'list_sfc_port_pairs') + def test_get_sfi_list_with_sfc_encap(self, list_sfc_port_pairs): + self._test_get_sfi_list(list_sfc_port_pairs, 'nsh', True) - @mock.patch.object(Client, 'list_port_pair') - def test_get_sfi_list_without_sfc_encap(self, list_port_pair): - self._test_get_sfi_list(list_port_pair, None, False) + @mock.patch.object(Client, 'list_sfc_port_pairs') + def test_get_sfi_list_without_sfc_encap(self, list_sfc_port_pairs): + self._test_get_sfi_list(list_sfc_port_pairs, None, False) - @mock.patch.object(Client, 'list_port_pair_group') - def test_get_sf_list(self, list_port_pair_group): + @mock.patch.object(Client, 'list_sfc_port_pair_groups') + def test_get_sf_list(self, list_sfc_port_pair_groups): # what OpenStack is assumed to return to the VIM connector - list_port_pair_group.return_value = {'port_pair_groups': [ + list_sfc_port_pair_groups.return_value = {'port_pair_groups': [ {'port_pairs': ['08fbdbb0-82d6-11e7-ad95-9bb52fbec2f2', '0d63799c-82d6-11e7-8deb-a746bb3ae9f5'], 'description': '', @@ -426,11 +419,11 @@ class TestSfcOperations(unittest.TestCase): result = self.vimconn.get_sf_list(filter_dict.copy()) # assert that VIM connector called OpenStack with the expected filter - list_port_pair_group.assert_called_with(**filter_dict) + list_sfc_port_pair_groups.assert_called_with(**filter_dict) # assert that the VIM connector successfully # translated and returned the OpenStack result self.assertEqual(result, [ - {'instances': ['08fbdbb0-82d6-11e7-ad95-9bb52fbec2f2', + {'sfis': ['08fbdbb0-82d6-11e7-ad95-9bb52fbec2f2', '0d63799c-82d6-11e7-8deb-a746bb3ae9f5'], 'description': '', 'tenant_id': '8f3019ef06374fa880a0144ad4bc1d7b', @@ -438,9 +431,9 @@ class TestSfcOperations(unittest.TestCase): 'id': 'f4a0bde8-82d5-11e7-90e1-a72b762fa27f', 'name': 'osm_sf'}]) - def _test_get_sfp_list(self, list_port_chain, correlation, sfc_encap): + def _test_get_sfp_list(self, list_sfc_port_chains, correlation, sfc_encap): # what OpenStack is assumed to return to the VIM connector - list_port_chain.return_value = {'port_chains': [ + list_sfc_port_chains.return_value = {'port_chains': [ {'port_pair_groups': ['7d8e3bf8-82d6-11e7-a032-8ff028839d25', '7dc9013e-82d6-11e7-a5a6-a3a8d78a5518'], 'flow_classifiers': ['1333c2f4-82d7-11e7-a5df-9327f33d104e', @@ -458,7 +451,7 @@ class TestSfcOperations(unittest.TestCase): result = self.vimconn.get_sfp_list(filter_dict.copy()) # assert that VIM connector called OpenStack with the expected filter - list_port_chain.assert_called_with(**filter_dict) + list_sfc_port_chains.assert_called_with(**filter_dict) # assert that the VIM connector successfully # translated and returned the OpenStack result self.assertEqual(result, [ @@ -474,18 +467,18 @@ class TestSfcOperations(unittest.TestCase): 'id': '821bc9be-82d7-11e7-8ce3-23a08a27ab47', 'name': 'osm_sfp'}]) - @mock.patch.object(Client, 'list_port_chain') - def test_get_sfp_list_with_sfc_encap(self, list_port_chain): - self._test_get_sfp_list(list_port_chain, 'nsh', True) + @mock.patch.object(Client, 'list_sfc_port_chains') + def test_get_sfp_list_with_sfc_encap(self, list_sfc_port_chains): + self._test_get_sfp_list(list_sfc_port_chains, 'nsh', True) - @mock.patch.object(Client, 'list_port_chain') - def test_get_sfp_list_without_sfc_encap(self, list_port_chain): - self._test_get_sfp_list(list_port_chain, None, False) + @mock.patch.object(Client, 'list_sfc_port_chains') + def test_get_sfp_list_without_sfc_encap(self, list_sfc_port_chains): + self._test_get_sfp_list(list_sfc_port_chains, None, False) - @mock.patch.object(Client, 'list_flow_classifier') - def test_get_classification(self, list_flow_classifier): + @mock.patch.object(Client, 'list_sfc_flow_classifiers') + def test_get_classification(self, list_sfc_flow_classifiers): # what OpenStack is assumed to return to the VIM connector - list_flow_classifier.return_value = {'flow_classifiers': [ + list_sfc_flow_classifiers.return_value = {'flow_classifiers': [ {'source_port_range_min': 2000, 'destination_ip_prefix': '192.168.3.0/24', 'protocol': 'udp', @@ -509,7 +502,7 @@ class TestSfcOperations(unittest.TestCase): '22198366-d4e8-4d6b-b4d2-637d5d6cbb7d') # assert that VIM connector called OpenStack with the expected filter - list_flow_classifier.assert_called_with( + list_sfc_flow_classifiers.assert_called_with( id='22198366-d4e8-4d6b-b4d2-637d5d6cbb7d') # assert that VIM connector successfully returned the OpenStack result self.assertEqual(result, @@ -534,10 +527,10 @@ class TestSfcOperations(unittest.TestCase): 'aaab0ab0-1452-4636-bb3b-11dca833fa2b'} }) - @mock.patch.object(Client, 'list_flow_classifier') - def test_get_classification_many_results(self, list_flow_classifier): + @mock.patch.object(Client, 'list_sfc_flow_classifiers') + def test_get_classification_many_results(self, list_sfc_flow_classifiers): # what OpenStack is assumed to return to the VIM connector - list_flow_classifier.return_value = {'flow_classifiers': [ + list_sfc_flow_classifiers.return_value = {'flow_classifiers': [ {'source_port_range_min': 2000, 'destination_ip_prefix': '192.168.3.0/24', 'protocol': 'udp', @@ -578,13 +571,13 @@ class TestSfcOperations(unittest.TestCase): '3196bafc-82dd-11e7-a205-9bf6c14b0721') # assert the VIM connector called OpenStack with the expected filter - list_flow_classifier.assert_called_with( + list_sfc_flow_classifiers.assert_called_with( id='3196bafc-82dd-11e7-a205-9bf6c14b0721') - @mock.patch.object(Client, 'list_flow_classifier') - def test_get_classification_no_results(self, list_flow_classifier): + @mock.patch.object(Client, 'list_sfc_flow_classifiers') + def test_get_classification_no_results(self, list_sfc_flow_classifiers): # what OpenStack is assumed to return to the VIM connector - list_flow_classifier.return_value = {'flow_classifiers': []} + list_sfc_flow_classifiers.return_value = {'flow_classifiers': []} # call the VIM connector self.assertRaises(vimconn.vimconnNotFoundException, @@ -592,13 +585,13 @@ class TestSfcOperations(unittest.TestCase): '3196bafc-82dd-11e7-a205-9bf6c14b0721') # assert the VIM connector called OpenStack with the expected filter - list_flow_classifier.assert_called_with( + list_sfc_flow_classifiers.assert_called_with( id='3196bafc-82dd-11e7-a205-9bf6c14b0721') - @mock.patch.object(Client, 'list_port_pair') - def test_get_sfi(self, list_port_pair): + @mock.patch.object(Client, 'list_sfc_port_pairs') + def test_get_sfi(self, list_sfc_port_pairs): # what OpenStack is assumed to return to the VIM connector - list_port_pair.return_value = {'port_pairs': [ + list_sfc_port_pairs.return_value = {'port_pairs': [ {'ingress': '5311c75d-d718-4369-bbda-cdcc6da60fcc', 'description': '', 'tenant_id': '8f3019ef06374fa880a0144ad4bc1d7b', @@ -613,7 +606,7 @@ class TestSfcOperations(unittest.TestCase): result = self.vimconn.get_sfi('c121ebdd-7f2d-4213-b933-3325298a6966') # assert the VIM connector called OpenStack with the expected filter - list_port_pair.assert_called_with( + list_sfc_port_pairs.assert_called_with( id='c121ebdd-7f2d-4213-b933-3325298a6966') # assert the VIM connector successfully returned the OpenStack result self.assertEqual(result, @@ -628,10 +621,10 @@ class TestSfcOperations(unittest.TestCase): 'id': 'c121ebdd-7f2d-4213-b933-3325298a6966', 'name': 'osm_sfi1'}) - @mock.patch.object(Client, 'list_port_pair') - def test_get_sfi_many_results(self, list_port_pair): + @mock.patch.object(Client, 'list_sfc_port_pairs') + def test_get_sfi_many_results(self, list_sfc_port_pairs): # what OpenStack is assumed to return to the VIM connector - list_port_pair.return_value = {'port_pairs': [ + list_sfc_port_pairs.return_value = {'port_pairs': [ {'ingress': '5311c75d-d718-4369-bbda-cdcc6da60fcc', 'description': '', 'tenant_id': '8f3019ef06374fa880a0144ad4bc1d7b', @@ -656,13 +649,13 @@ class TestSfcOperations(unittest.TestCase): 'c0436d92-82db-11e7-8f9c-5fa535f1261f') # assert that VIM connector called OpenStack with the expected filter - list_port_pair.assert_called_with( + list_sfc_port_pairs.assert_called_with( id='c0436d92-82db-11e7-8f9c-5fa535f1261f') - @mock.patch.object(Client, 'list_port_pair') - def test_get_sfi_no_results(self, list_port_pair): + @mock.patch.object(Client, 'list_sfc_port_pairs') + def test_get_sfi_no_results(self, list_sfc_port_pairs): # what OpenStack is assumed to return to the VIM connector - list_port_pair.return_value = {'port_pairs': []} + list_sfc_port_pairs.return_value = {'port_pairs': []} # call the VIM connector self.assertRaises(vimconn.vimconnNotFoundException, @@ -670,13 +663,13 @@ class TestSfcOperations(unittest.TestCase): 'b22892fc-82d9-11e7-ae85-0fea6a3b3757') # assert that VIM connector called OpenStack with the expected filter - list_port_pair.assert_called_with( + list_sfc_port_pairs.assert_called_with( id='b22892fc-82d9-11e7-ae85-0fea6a3b3757') - @mock.patch.object(Client, 'list_port_pair_group') - def test_get_sf(self, list_port_pair_group): + @mock.patch.object(Client, 'list_sfc_port_pair_groups') + def test_get_sf(self, list_sfc_port_pair_groups): # what OpenStack is assumed to return to the VIM connector - list_port_pair_group.return_value = {'port_pair_groups': [ + list_sfc_port_pair_groups.return_value = {'port_pair_groups': [ {'port_pairs': ['08fbdbb0-82d6-11e7-ad95-9bb52fbec2f2'], 'description': '', 'tenant_id': '8f3019ef06374fa880a0144ad4bc1d7b', @@ -690,22 +683,21 @@ class TestSfcOperations(unittest.TestCase): result = self.vimconn.get_sf('b22892fc-82d9-11e7-ae85-0fea6a3b3757') # assert that VIM connector called OpenStack with the expected filter - list_port_pair_group.assert_called_with( + list_sfc_port_pair_groups.assert_called_with( id='b22892fc-82d9-11e7-ae85-0fea6a3b3757') # assert that VIM connector successfully returned the OpenStack result self.assertEqual(result, - {'instances': [ - '08fbdbb0-82d6-11e7-ad95-9bb52fbec2f2'], - 'description': '', + {'description': '', 'tenant_id': '8f3019ef06374fa880a0144ad4bc1d7b', 'project_id': '8f3019ef06374fa880a0144ad4bc1d7b', + 'sfis': ['08fbdbb0-82d6-11e7-ad95-9bb52fbec2f2'], 'id': 'aabba8a6-82d9-11e7-a18a-d3c7719b742d', 'name': 'osm_sf1'}) - @mock.patch.object(Client, 'list_port_pair_group') - def test_get_sf_many_results(self, list_port_pair_group): + @mock.patch.object(Client, 'list_sfc_port_pair_groups') + def test_get_sf_many_results(self, list_sfc_port_pair_groups): # what OpenStack is assumed to return to the VIM connector - list_port_pair_group.return_value = {'port_pair_groups': [ + list_sfc_port_pair_groups.return_value = {'port_pair_groups': [ {'port_pairs': ['08fbdbb0-82d6-11e7-ad95-9bb52fbec2f2'], 'description': '', 'tenant_id': '8f3019ef06374fa880a0144ad4bc1d7b', @@ -728,13 +720,13 @@ class TestSfcOperations(unittest.TestCase): 'b22892fc-82d9-11e7-ae85-0fea6a3b3757') # assert that VIM connector called OpenStack with the expected filter - list_port_pair_group.assert_called_with( + list_sfc_port_pair_groups.assert_called_with( id='b22892fc-82d9-11e7-ae85-0fea6a3b3757') - @mock.patch.object(Client, 'list_port_pair_group') - def test_get_sf_no_results(self, list_port_pair_group): + @mock.patch.object(Client, 'list_sfc_port_pair_groups') + def test_get_sf_no_results(self, list_sfc_port_pair_groups): # what OpenStack is assumed to return to the VIM connector - list_port_pair_group.return_value = {'port_pair_groups': []} + list_sfc_port_pair_groups.return_value = {'port_pair_groups': []} # call the VIM connector self.assertRaises(vimconn.vimconnNotFoundException, @@ -742,13 +734,13 @@ class TestSfcOperations(unittest.TestCase): 'b22892fc-82d9-11e7-ae85-0fea6a3b3757') # assert that VIM connector called OpenStack with the expected filter - list_port_pair_group.assert_called_with( + list_sfc_port_pair_groups.assert_called_with( id='b22892fc-82d9-11e7-ae85-0fea6a3b3757') - @mock.patch.object(Client, 'list_port_chain') - def test_get_sfp(self, list_port_chain): + @mock.patch.object(Client, 'list_sfc_port_chains') + def test_get_sfp(self, list_sfc_port_chains): # what OpenStack is assumed to return to the VIM connector - list_port_chain.return_value = {'port_chains': [ + list_sfc_port_chains.return_value = {'port_chains': [ {'port_pair_groups': ['7d8e3bf8-82d6-11e7-a032-8ff028839d25'], 'flow_classifiers': ['1333c2f4-82d7-11e7-a5df-9327f33d104e'], 'description': '', @@ -763,7 +755,7 @@ class TestSfcOperations(unittest.TestCase): result = self.vimconn.get_sfp('821bc9be-82d7-11e7-8ce3-23a08a27ab47') # assert that VIM connector called OpenStack with the expected filter - list_port_chain.assert_called_with( + list_sfc_port_chains.assert_called_with( id='821bc9be-82d7-11e7-8ce3-23a08a27ab47') # assert that VIM connector successfully returned the OpenStack result self.assertEqual(result, @@ -779,10 +771,10 @@ class TestSfcOperations(unittest.TestCase): 'id': '821bc9be-82d7-11e7-8ce3-23a08a27ab47', 'name': 'osm_sfp1'}) - @mock.patch.object(Client, 'list_port_chain') - def test_get_sfp_many_results(self, list_port_chain): + @mock.patch.object(Client, 'list_sfc_port_chains') + def test_get_sfp_many_results(self, list_sfc_port_chains): # what OpenStack is assumed to return to the VIM connector - list_port_chain.return_value = {'port_chains': [ + list_sfc_port_chains.return_value = {'port_chains': [ {'port_pair_groups': ['7d8e3bf8-82d6-11e7-a032-8ff028839d25'], 'flow_classifiers': ['1333c2f4-82d7-11e7-a5df-9327f33d104e'], 'description': '', @@ -809,13 +801,13 @@ class TestSfcOperations(unittest.TestCase): '5d002f38-82de-11e7-a770-f303f11ce66a') # assert that VIM connector called OpenStack with the expected filter - list_port_chain.assert_called_with( + list_sfc_port_chains.assert_called_with( id='5d002f38-82de-11e7-a770-f303f11ce66a') - @mock.patch.object(Client, 'list_port_chain') - def test_get_sfp_no_results(self, list_port_chain): + @mock.patch.object(Client, 'list_sfc_port_chains') + def test_get_sfp_no_results(self, list_sfc_port_chains): # what OpenStack is assumed to return to the VIM connector - list_port_chain.return_value = {'port_chains': []} + list_sfc_port_chains.return_value = {'port_chains': []} # call the VIM connector self.assertRaises(vimconn.vimconnNotFoundException, @@ -823,37 +815,37 @@ class TestSfcOperations(unittest.TestCase): '5d002f38-82de-11e7-a770-f303f11ce66a') # assert that VIM connector called OpenStack with the expected filter - list_port_chain.assert_called_with( + list_sfc_port_chains.assert_called_with( id='5d002f38-82de-11e7-a770-f303f11ce66a') - @mock.patch.object(Client, 'delete_flow_classifier') - def test_delete_classification(self, delete_flow_classifier): + @mock.patch.object(Client, 'delete_sfc_flow_classifier') + def test_delete_classification(self, delete_sfc_flow_classifier): result = self.vimconn.delete_classification( '638f957c-82df-11e7-b7c8-132706021464') - delete_flow_classifier.assert_called_with( + delete_sfc_flow_classifier.assert_called_with( '638f957c-82df-11e7-b7c8-132706021464') self.assertEqual(result, '638f957c-82df-11e7-b7c8-132706021464') - @mock.patch.object(Client, 'delete_port_pair') - def test_delete_sfi(self, delete_port_pair): + @mock.patch.object(Client, 'delete_sfc_port_pair') + def test_delete_sfi(self, delete_sfc_port_pair): result = self.vimconn.delete_sfi( '638f957c-82df-11e7-b7c8-132706021464') - delete_port_pair.assert_called_with( + delete_sfc_port_pair.assert_called_with( '638f957c-82df-11e7-b7c8-132706021464') self.assertEqual(result, '638f957c-82df-11e7-b7c8-132706021464') - @mock.patch.object(Client, 'delete_port_pair_group') - def test_delete_sf(self, delete_port_pair_group): + @mock.patch.object(Client, 'delete_sfc_port_pair_group') + def test_delete_sf(self, delete_sfc_port_pair_group): result = self.vimconn.delete_sf('638f957c-82df-11e7-b7c8-132706021464') - delete_port_pair_group.assert_called_with( + delete_sfc_port_pair_group.assert_called_with( '638f957c-82df-11e7-b7c8-132706021464') self.assertEqual(result, '638f957c-82df-11e7-b7c8-132706021464') - @mock.patch.object(Client, 'delete_port_chain') - def test_delete_sfp(self, delete_port_chain): + @mock.patch.object(Client, 'delete_sfc_port_chain') + def test_delete_sfp(self, delete_sfc_port_chain): result = self.vimconn.delete_sfp( '638f957c-82df-11e7-b7c8-132706021464') - delete_port_chain.assert_called_with( + delete_sfc_port_chain.assert_called_with( '638f957c-82df-11e7-b7c8-132706021464') self.assertEqual(result, '638f957c-82df-11e7-b7c8-132706021464') diff --git a/osm_ro/utils.py b/osm_ro/utils.py index 592abc12..2afbc85c 100644 --- a/osm_ro/utils.py +++ b/osm_ro/utils.py @@ -1,7 +1,7 @@ # -*- 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. # diff --git a/osm_ro/vim_thread.py b/osm_ro/vim_thread.py index 2713c760..48c8e326 100644 --- a/osm_ro/vim_thread.py +++ b/osm_ro/vim_thread.py @@ -1,7 +1,7 @@ # -*- 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 openvim # All Rights Reserved. # @@ -1064,15 +1064,14 @@ class vim_thread(threading.Thread): def new_sfi(self, task): vim_sfi_id = None try: - params = task["params"] + dep_id = "TASK-" + str(task["extra"]["depends_on"][0]) task_id = task["instance_action_id"] + "." + str(task["task_index"]) - depends = task.get("depends") error_text = "" - interfaces = task.get("depends").values()[0].get("extra").get("params")[5] + interfaces = task.get("depends").get(dep_id).get("extra").get("interfaces").keys() # At the moment, every port associated with the VM will be used both as ingress and egress ports. # Bear in mind that different VIM connectors might support SFI differently. In the case of OpenStack, only the # first ingress and first egress ports will be used to create the SFI (Port Pair). - port_id_list = [interfaces[0].get("vim_id")] + port_id_list = [interfaces[0]] name = "sfi-%s" % task["item_id"][:8] # By default no form of IETF SFC Encapsulation will be used vim_sfi_id = self.vim.new_sfi(name, port_id_list, port_id_list, sfc_encap=False) @@ -1113,12 +1112,11 @@ class vim_thread(threading.Thread): def new_sf(self, task): vim_sf_id = None try: - params = task["params"] task_id = task["instance_action_id"] + "." + str(task["task_index"]) - depends = task.get("depends") error_text = "" + depending_tasks = [ "TASK-" + str(dep_id) for dep_id in task["extra"]["depends_on"]] #sfis = task.get("depends").values()[0].get("extra").get("params")[5] - sfis = task.get("depends").values() + sfis = [task.get("depends").get(dep_task) for dep_task in depending_tasks] sfi_id_list = [] for sfi in sfis: sfi_id_list.append(sfi.get("vim_id")) @@ -1164,9 +1162,9 @@ class vim_thread(threading.Thread): try: params = task["params"] task_id = task["instance_action_id"] + "." + str(task["task_index"]) - depends = task.get("depends") + depending_task = "TASK-" + str(task.get("extra").get("depends_on")[0]) error_text = "" - interfaces = task.get("depends").values()[0].get("extra").get("params")[5] + interfaces = task.get("depends").get(depending_task).get("vim_interfaces").keys() # Bear in mind that different VIM connectors might support Classifications differently. # In the case of OpenStack, only the first VNF attached to the classifier will be used # to create the Classification(s) (the "logical source port" of the "Flow Classifier"). @@ -1188,7 +1186,7 @@ class vim_thread(threading.Thread): if '/' not in destination_ip: destination_ip += '/32' definition = { - "logical_source_port": interfaces[0].get("vim_id"), + "logical_source_port": interfaces[0], "protocol": ip_proto, "source_ip_prefix": source_ip, "destination_ip_prefix": destination_ip, @@ -1239,12 +1237,11 @@ class vim_thread(threading.Thread): try: params = task["params"] task_id = task["instance_action_id"] + "." + str(task["task_index"]) - depends = task.get("depends") + depending_tasks = [task.get("depends").get("TASK-" + str(tsk_id)) for tsk_id in task.get("extra").get("depends_on")] error_text = "" - deps = task.get("depends").values() sf_id_list = [] classification_id_list = [] - for dep in deps: + for dep in depending_tasks: vim_id = dep.get("vim_id") resource = dep.get("item") if resource == "instance_sfs": diff --git a/osm_ro/vimconn.py b/osm_ro/vimconn.py index fd8f9be0..4a7cc095 100644 --- a/osm_ro/vimconn.py +++ b/osm_ro/vimconn.py @@ -1,7 +1,7 @@ # -*- 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. # @@ -480,7 +480,7 @@ class vimconnector(): 'name': (optional) name for the interface. 'net_id': VIM network id where this interface must be connect to. Mandatory for type==virtual 'vpci': (optional) virtual vPCI address to assign at the VM. Can be ignored depending on VIM capabilities - 'model': (optional and only have sense for type==virtual) interface model: virtio, e2000, ... + 'model': (optional and only have sense for type==virtual) interface model: virtio, e1000, ... 'mac_address': (optional) mac address to assign to this interface 'ip_address': (optional) IP address to assign to this interface #TODO: CHECK if an optional 'vlan' parameter is needed for VIMs when type if VF and net_id is not provided, diff --git a/osm_ro/vimconn_aws.py b/osm_ro/vimconn_aws.py index e35318f2..22103d0c 100644 --- a/osm_ro/vimconn_aws.py +++ b/osm_ro/vimconn_aws.py @@ -604,7 +604,7 @@ class vimconnector(vimconn.vimconnector): name net_id - subnet_id from AWS vpci - (optional) virtual vPCI address to assign at the VM. Can be ignored depending on VIM capabilities - model: (optional and only have sense for type==virtual) interface model: virtio, e2000, ... + model: (optional and only have sense for type==virtual) interface model: virtio, e1000, ... mac_address: (optional) mac address to assign to this interface type: (mandatory) can be one of: virtual, in this case always connected to a network of type 'net_type=bridge' diff --git a/osm_ro/vimconn_opennebula.py b/osm_ro/vimconn_opennebula.py index ab4ebf46..2e63d53a 100644 --- a/osm_ro/vimconn_opennebula.py +++ b/osm_ro/vimconn_opennebula.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- ## -# Copyright 2017 Telefónica Digital España S.L.U. +# Copyright 2017 Telefonica Digital Spain S.L.U. # This file is part of ETSI OSM # All Rights Reserved. # @@ -26,7 +26,7 @@ vimconnector implements all the methods to interact with OpenNebula using the XML-RPC API. """ __author__ = "Jose Maria Carmona Perez,Juan Antonio Hernando Labajo, Emilio Abraham Garrido Garcia,Alberto Florez " \ - "Pages, Andres Pozo Muñoz, Santiago Perez Marin, Onlife Networks Telefonica I+D Product Innovation " + "Pages, Andres Pozo Munoz, Santiago Perez Marin, Onlife Networks Telefonica I+D Product Innovation " __date__ = "$13-dec-2017 11:09:29$" import vimconn import requests @@ -453,7 +453,7 @@ class vimconnector(vimconn.vimconnector): name: net_id: network uuid to connect vpci: virtual vcpi to assign - model: interface model, virtio, e2000, ... + model: interface model, virtio, e1000, ... mac_address: use: 'data', 'bridge', 'mgmt' type: 'virtual', 'PF', 'VF', 'VFnotShared' diff --git a/osm_ro/vimconn_openstack.py b/osm_ro/vimconn_openstack.py index 2b156d74..876fa2f4 100644 --- a/osm_ro/vimconn_openstack.py +++ b/osm_ro/vimconn_openstack.py @@ -1,7 +1,7 @@ # -*- 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. # @@ -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 @@ -380,15 +380,16 @@ class vimconnector(vimconn.vimconnector): 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): @@ -432,7 +433,7 @@ class vimconnector(vimconn.vimconnector): 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): @@ -445,7 +446,7 @@ class vimconnector(vimconn.vimconnector): 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): @@ -694,83 +695,84 @@ class vimconnector(vimconn.vimconnector): retry=0 max_retries=3 name_suffix = 0 - name=flavor_data['name'] - while retry 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"="