From 4fa204b3709022020add8b70d9b39a0d17f4008e Mon Sep 17 00:00:00 2001 From: Niraj Singh Date: Thu, 8 Aug 2019 10:09:11 +0000 Subject: [PATCH] Add vnf packages RestFul APIs Implemented following APIs:- * GET /vnf_packages * POST /vnf_packages/ * GET /vnf_packages/{vnfPkgId} * DELETE /vnf_packages/{vnfPkgId} * PUT /vnf_packages/{vnfPkgId}/package_content * POST /vnf_packages/{vnfPkgId}/package_content/upload_from_uri Partial-Implements: blueprint tosca-csar-mgmt-driver Depends-On: If8155399df12a96cb86631dfa22eaca7a5a8d398 Co-Author: Neha Alhat Change-Id: Id3b4812e24a1ed84fe94429e074f96ae11530517 --- etc/config-generator.conf | 1 + lower-constraints.txt | 3 +- requirements.txt | 5 +- samples/vnf_packages/sample_vnf_pkg.zip | Bin 0 -> 18104 bytes tacker/api/views/vnf_packages.py | 105 ++++++ tacker/api/vnfpkgm/v1/controller.py | 206 +++++++++++- tacker/common/csar_utils.py | 310 ++++++++++++++++++ tacker/common/exceptions.py | 36 +- tacker/common/rpc.py | 7 +- tacker/common/safe_utils.py | 41 +++ tacker/common/utils.py | 225 +++++++++++++ tacker/conductor/conductor_server.py | 237 ++++++++++++- tacker/conf/__init__.py | 2 + tacker/glance_store/__init__.py | 0 tacker/glance_store/store.py | 117 +++++++ tacker/objects/base.py | 1 + tacker/tests/constants.py | 2 + .../csar_invalid_instantiation_level.zip | Bin 0 -> 16848 bytes ...sar_with_flavour_info_in_main_template.zip | Bin 0 -> 16922 bytes ...th_invalid_default_instantiation_level.zip | Bin 0 -> 16815 bytes ...missing_sw_image_data_in_main_template.zip | Bin 0 -> 16371 bytes .../csar_with_multiple_sw_image_data.zip | Bin 0 -> 17056 bytes .../etc/samples/csar_without_flavour_info.zip | Bin 0 -> 16624 bytes ..._without_flavour_info_in_main_template.zip | Bin 0 -> 16208 bytes .../csar_without_instantiation_level.zip | Bin 0 -> 16716 bytes .../samples/csar_without_sw_image_data.zip | Bin 0 -> 16911 bytes .../etc/samples/csar_without_vnfd_info.zip | Bin 0 -> 17136 bytes .../etc/samples/sample_vnf_package_csar.zip | Bin 0 -> 17664 bytes tacker/tests/etc/samples/test_data.zip | 0 tacker/tests/functional/base.py | 56 +++- tacker/tests/functional/vnfpkgm/__init__.py | 0 .../functional/vnfpkgm/test_vnf_package.py | 134 ++++++++ tacker/tests/unit/common/test_csar_utils.py | 164 +++++++++ .../unit/conductor/conductorrpc/__init__.py | 0 tacker/tests/unit/conductor/fakes.py | 9 + .../unit/conductor/test_conductor_server.py | 135 ++++++++ tacker/tests/unit/db/test_vnf_package.py | 94 ++++++ tacker/tests/unit/fake_request.py | 43 +++ tacker/tests/unit/vnfm/tosca/test_utils.py | 6 +- tacker/tests/unit/vnfpkgm/__init__.py | 0 tacker/tests/unit/vnfpkgm/fakes.py | 126 +++++++ tacker/tests/unit/vnfpkgm/test_controller.py | 258 +++++++++++++++ tacker/wsgi.py | 76 ++++- 43 files changed, 2369 insertions(+), 30 deletions(-) create mode 100644 samples/vnf_packages/sample_vnf_pkg.zip create mode 100644 tacker/api/views/vnf_packages.py create mode 100644 tacker/common/csar_utils.py create mode 100644 tacker/common/safe_utils.py create mode 100644 tacker/glance_store/__init__.py create mode 100644 tacker/glance_store/store.py create mode 100644 tacker/tests/etc/samples/csar_invalid_instantiation_level.zip create mode 100644 tacker/tests/etc/samples/csar_with_flavour_info_in_main_template.zip create mode 100644 tacker/tests/etc/samples/csar_with_invalid_default_instantiation_level.zip create mode 100644 tacker/tests/etc/samples/csar_with_missing_sw_image_data_in_main_template.zip create mode 100644 tacker/tests/etc/samples/csar_with_multiple_sw_image_data.zip create mode 100644 tacker/tests/etc/samples/csar_without_flavour_info.zip create mode 100644 tacker/tests/etc/samples/csar_without_flavour_info_in_main_template.zip create mode 100644 tacker/tests/etc/samples/csar_without_instantiation_level.zip create mode 100644 tacker/tests/etc/samples/csar_without_sw_image_data.zip create mode 100644 tacker/tests/etc/samples/csar_without_vnfd_info.zip create mode 100644 tacker/tests/etc/samples/sample_vnf_package_csar.zip create mode 100644 tacker/tests/etc/samples/test_data.zip create mode 100644 tacker/tests/functional/vnfpkgm/__init__.py create mode 100644 tacker/tests/functional/vnfpkgm/test_vnf_package.py create mode 100644 tacker/tests/unit/common/test_csar_utils.py create mode 100644 tacker/tests/unit/conductor/conductorrpc/__init__.py create mode 100644 tacker/tests/unit/conductor/test_conductor_server.py create mode 100644 tacker/tests/unit/db/test_vnf_package.py create mode 100644 tacker/tests/unit/fake_request.py create mode 100644 tacker/tests/unit/vnfpkgm/__init__.py create mode 100644 tacker/tests/unit/vnfpkgm/fakes.py create mode 100644 tacker/tests/unit/vnfpkgm/test_controller.py diff --git a/etc/config-generator.conf b/etc/config-generator.conf index d67670de6..1154b0d65 100644 --- a/etc/config-generator.conf +++ b/etc/config-generator.conf @@ -1,6 +1,7 @@ [DEFAULT] output_file = etc/tacker/tacker.conf.sample wrap_width = 79 +namespace = glance.store namespace = tacker.common.config namespace = tacker.conf namespace = tacker.wsgi diff --git a/lower-constraints.txt b/lower-constraints.txt index ca6e460a5..a85637a54 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -33,6 +33,7 @@ fixtures==3.0.0 flake8==2.5.5 future==0.16.0 futurist==1.6.0 +glance-store==0.26.1 google-auth==1.4.1 greenlet==0.4.13 hacking==0.12.0 @@ -151,7 +152,7 @@ tenacity==4.9.0 testresources==2.0.1 testscenarios==0.5.0 testtools==2.2.0 -tosca-parser==0.8.1 +tosca-parser==1.6.0 traceback2==1.4.0 unittest2==1.1.0 urllib3==1.22 diff --git a/requirements.txt b/requirements.txt index edf99c8e5..c16103368 100644 --- a/requirements.txt +++ b/requirements.txt @@ -39,7 +39,7 @@ oslo.versionedobjects>=1.33.3 # Apache-2.0 openstackdocstheme>=1.20.0 # Apache-2.0 python-neutronclient>=6.7.0 # Apache-2.0 python-novaclient>=9.1.0 # Apache-2.0 -tosca-parser>=0.8.1 # Apache-2.0 +tosca-parser>=1.6.0 # Apache-2.0 heat-translator>=1.3.1 # Apache-2.0 cryptography>=2.1 # BSD/Apache-2.0 paramiko>=2.0.0 # LGPLv2.1+ @@ -50,3 +50,6 @@ castellan>=0.16.0 # Apache-2.0 kubernetes>=5.0.0 # Apache-2.0 setuptools!=24.0.0,!=34.0.0,!=34.0.1,!=34.0.2,!=34.0.3,!=34.1.0,!=34.1.1,!=34.2.0,!=34.3.0,!=34.3.1,!=34.3.2,!=36.2.0,>=21.0.0 # PSF/ZPL PyYAML>=3.12 # MIT + +# Glance Store +glance-store>=0.26.1 # Apache-2.0 diff --git a/samples/vnf_packages/sample_vnf_pkg.zip b/samples/vnf_packages/sample_vnf_pkg.zip new file mode 100644 index 0000000000000000000000000000000000000000..52b460e0d8a8d7ffa1feabedfec62872795a1215 GIT binary patch literal 18104 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 literal 0 HcmV?d00001 diff --git a/tacker/api/views/vnf_packages.py b/tacker/api/views/vnf_packages.py new file mode 100644 index 000000000..1ca358ae6 --- /dev/null +++ b/tacker/api/views/vnf_packages.py @@ -0,0 +1,105 @@ +# Copyright (C) 2019 NTT DATA +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, 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. + +from tacker.objects import fields + + +class ViewBuilder(object): + + def _get_links(self, vnf_package): + return { + "_links": { + "self": { + "href": '/vnfpkgm/v1/vnf_packages/%s' + % vnf_package.id + }, + "packageContent": { + "href": '/vnfpkgm/v1/vnf_packages/%s/package_content' + % vnf_package.id + } + } + } + + def _get_software_images(self, vnf_deployment_flavours): + software_images = list() + for vnf_deployment_flavour in vnf_deployment_flavours: + for sw_image in vnf_deployment_flavour.software_images: + software_images.append({ + "id": sw_image.software_image_id, + "name": sw_image.name, + "provider": "provider", + "version": sw_image.version, + "checksum": { + "algorithm": sw_image.algorithm, + "hash": sw_image.hash + }, + "containerFormat": sw_image.container_format, + "diskFormat": sw_image.disk_format, + "minDisk": sw_image.min_disk, + "minRam": sw_image.min_ram, + "size": sw_image.size, + "imagePath": sw_image.image_path, + "userMetadata": sw_image.metadata + }) + + return {'softwareImages': software_images} + + def _get_vnfd(self, vnf_package): + vnfd = vnf_package.vnfd + return { + 'vnfdId': vnfd.vnfd_id, + 'vnfProvider': vnfd.vnf_provider, + 'vnfProductName': vnfd.vnf_product_name, + 'vnfSoftwareVersion': vnfd.vnf_software_version, + 'vnfdVersion': vnfd.vnfd_version + } + + def _basic_vnf_package_info(self, vnf_package): + return { + 'id': vnf_package.id, + 'onboardingState': vnf_package.onboarding_state, + 'operationalState': vnf_package.operational_state, + 'usageState': vnf_package.usage_state, + 'userDefinedData': vnf_package.user_data, + } + + def _get_vnf_package(self, vnf_package): + vnf_package_response = self._basic_vnf_package_info(vnf_package) + + links = self._get_links(vnf_package) + vnf_package_response.update(links) + + if (vnf_package.onboarding_state == + fields.PackageOnboardingStateType.ONBOARDED): + # add software images + vnf_deployment_flavours = vnf_package.vnf_deployment_flavours + vnf_package_response.update(self._get_software_images( + vnf_deployment_flavours)) + + vnf_package_response.update(self._get_vnfd(vnf_package)) + + return vnf_package_response + + def create(self, request, vnf_package): + + return self._get_vnf_package(vnf_package) + + def show(self, request, vnf_package): + + return self._get_vnf_package(vnf_package) + + def index(self, request, vnf_packages): + return {'vnf_packages': [self._get_vnf_package( + vnf_package) for vnf_package in vnf_packages]} diff --git a/tacker/api/vnfpkgm/v1/controller.py b/tacker/api/vnfpkgm/v1/controller.py index ede79905f..4ceb15f3f 100644 --- a/tacker/api/vnfpkgm/v1/controller.py +++ b/tacker/api/vnfpkgm/v1/controller.py @@ -13,30 +13,224 @@ # License for the specific language governing permissions and limitations # under the License. +from oslo_config import cfg +from oslo_log import log as logging +from oslo_utils import excutils +from oslo_utils import uuidutils +from six.moves import http_client +from six.moves import urllib import webob +from tacker._i18n import _ +from tacker.api.schemas import vnf_packages +from tacker.api import validation +from tacker.api.views import vnf_packages as vnf_packages_view +from tacker.common import exceptions +from tacker.conductor.conductorrpc import vnf_pkgm_rpc +from tacker.glance_store import store as glance_store +from tacker.objects import fields +from tacker.objects import vnf_package as vnf_package_obj +from tacker.policies import vnf_package as vnf_package_policies from tacker import wsgi +LOG = logging.getLogger(__name__) + + +CONF = cfg.CONF + class VnfPkgmController(wsgi.Controller): + _view_builder_class = vnf_packages_view.ViewBuilder + + def __init__(self): + super(VnfPkgmController, self).__init__() + self.rpc_api = vnf_pkgm_rpc.VNFPackageRPCAPI() + glance_store.initialize_glance_store() + + @wsgi.response(http_client.CREATED) + @wsgi.expected_errors((http_client.BAD_REQUEST, http_client.FORBIDDEN)) + @validation.schema(vnf_packages.create) def create(self, request, body): - raise webob.exc.HTTPNotImplemented() + context = request.environ['tacker.context'] + context.can(vnf_package_policies.VNFPKGM % 'create') + vnf_package = vnf_package_obj.VnfPackage(context=request.context) + vnf_package.onboarding_state = ( + fields.PackageOnboardingStateType.CREATED) + vnf_package.operational_state = ( + fields.PackageOperationalStateType.DISABLED) + vnf_package.usage_state = fields.PackageUsageStateType.NOT_IN_USE + vnf_package.user_data = body.get('userDefinedData', dict()) + vnf_package.tenant_id = request.context.project_id + + vnf_package.create() + + return self._view_builder.create(request, vnf_package) + + @wsgi.response(http_client.OK) + @wsgi.expected_errors((http_client.FORBIDDEN, http_client.NOT_FOUND)) def show(self, request, id): - raise webob.exc.HTTPNotImplemented() + context = request.environ['tacker.context'] + context.can(vnf_package_policies.VNFPKGM % 'show') + # check if id is of type uuid format + if not uuidutils.is_uuid_like(id): + msg = _("Can not find requested vnf package: %s") % id + raise webob.exc.HTTPNotFound(explanation=msg) + + try: + vnf_package = vnf_package_obj.VnfPackage.get_by_id( + request.context, id, + expected_attrs=["vnf_deployment_flavours", "vnfd"]) + except exceptions.VnfPackageNotFound: + msg = _("Can not find requested vnf package: %s") % id + raise webob.exc.HTTPNotFound(explanation=msg) + + return self._view_builder.show(request, vnf_package) + + @wsgi.response(http_client.OK) + @wsgi.expected_errors((http_client.FORBIDDEN)) def index(self, request): - raise webob.exc.HTTPNotImplemented() + context = request.environ['tacker.context'] + context.can(vnf_package_policies.VNFPKGM % 'index') + vnf_packages = vnf_package_obj.VnfPackagesList.get_all( + request.context, + expected_attrs=["vnf_deployment_flavours", "vnfd"]) + + return self._view_builder.index(request, vnf_packages) + + @wsgi.response(http_client.NO_CONTENT) + @wsgi.expected_errors((http_client.FORBIDDEN, http_client.NOT_FOUND)) def delete(self, request, id): - raise webob.exc.HTTPNotImplemented() + context = request.environ['tacker.context'] + context.can(vnf_package_policies.VNFPKGM % 'delete') + # check if id is of type uuid format + if not uuidutils.is_uuid_like(id): + msg = _("Can not find requested vnf package: %s") % id + raise webob.exc.HTTPNotFound(explanation=msg) + + try: + vnf_package = vnf_package_obj.VnfPackage.get_by_id( + request.context, id) + except exceptions.VnfPackageNotFound: + msg = _("Can not find requested vnf package: %s") % id + raise webob.exc.HTTPNotFound(explanation=msg) + + if vnf_package.operational_state == \ + fields.PackageUsageStateType.IN_USE: + msg = _("VNF Package %(id)s usage state is %(state)s") + raise webob.exc.HTTPConflict( + explanation=msg % { + "id": id, + "state": fields.PackageOperationalStateType.ENABLED}) + + # Delete vnf_package + self.rpc_api.delete_vnf_package(context, vnf_package) + + @wsgi.response(http_client.ACCEPTED) + @wsgi.expected_errors((http_client.FORBIDDEN, http_client.NOT_FOUND, + http_client.CONFLICT)) def upload_vnf_package_content(self, request, id, body): - raise webob.exc.HTTPNotImplemented() + context = request.environ['tacker.context'] + context.can(vnf_package_policies.VNFPKGM % 'upload_package_content') + # check if id is of type uuid format + if not uuidutils.is_uuid_like(id): + msg = _("Can not find requested vnf package: %s") % id + raise webob.exc.HTTPNotFound(explanation=msg) + + try: + vnf_package = vnf_package_obj.VnfPackage.get_by_id( + request.context, id) + except exceptions.VnfPackageNotFound: + msg = _("Can not find requested vnf package: %s") % id + raise webob.exc.HTTPNotFound(explanation=msg) + + if vnf_package.onboarding_state != \ + fields.PackageOnboardingStateType.CREATED: + msg = _("VNF Package %(id)s onboarding state " + "is not %(onboarding)s") + raise webob.exc.HTTPConflict(explanation=msg % {"id": id, + "onboarding": fields.PackageOnboardingStateType.CREATED}) + + vnf_package.onboarding_state = ( + fields.PackageOnboardingStateType.UPLOADING) + + vnf_package.save() + + try: + (location, size, checksum, multihash, + loc_meta) = glance_store.store_csar(context, id, body) + except exceptions.UploadFailedToGlanceStore: + with excutils.save_and_reraise_exception(): + vnf_package.onboarding_state = ( + fields.PackageOnboardingStateType.CREATED) + vnf_package.save() + + vnf_package.onboarding_state = ( + fields.PackageOnboardingStateType.PROCESSING) + + vnf_package.algorithm = CONF.vnf_package.hashing_algorithm + vnf_package.hash = multihash + vnf_package.location_glance_store = location + + vnf_package.save() + + # process vnf_package + self.rpc_api.upload_vnf_package_content(context, vnf_package) + + @wsgi.response(http_client.ACCEPTED) + @wsgi.expected_errors((http_client.BAD_REQUEST, http_client.FORBIDDEN, + http_client.NOT_FOUND, http_client.CONFLICT)) + @validation.schema(vnf_packages.upload_from_uri) def upload_vnf_package_from_uri(self, request, id, body): - raise webob.exc.HTTPNotImplemented() + + context = request.environ['tacker.context'] + context.can(vnf_package_policies.VNFPKGM % 'upload_from_uri') + + # check if id is of type uuid format + if not uuidutils.is_uuid_like(id): + msg = _("Can not find requested vnf package: %s") % id + raise webob.exc.HTTPNotFound(explanation=msg) + + url = body['addressInformation'] + try: + data_iter = urllib.request.urlopen(url) + except Exception: + data_iter = None + msg = _("Failed to open URL %s") + raise webob.exc.HTTPBadRequest(explanation=msg % url) + finally: + if hasattr(data_iter, 'close'): + data_iter.close() + + try: + vnf_package = vnf_package_obj.VnfPackage.get_by_id( + request.context, id) + except exceptions.VnfPackageNotFound: + msg = _("Can not find requested vnf package: %s") % id + raise webob.exc.HTTPNotFound(explanation=msg) + + if vnf_package.onboarding_state != \ + fields.PackageOnboardingStateType.CREATED: + msg = _("VNF Package %(id)s onboarding state is not " + "%(onboarding)s") + raise webob.exc.HTTPConflict(explanation=msg % {"id": id, + "onboarding": fields.PackageOnboardingStateType.CREATED}) + + vnf_package.onboarding_state = ( + fields.PackageOnboardingStateType.UPLOADING) + + vnf_package.save() + + # process vnf_package + self.rpc_api.upload_vnf_package_from_uri(context, vnf_package, + body['addressInformation'], + user_name=body.get('userName'), + password=body.get('password')) def create_resource(): diff --git a/tacker/common/csar_utils.py b/tacker/common/csar_utils.py new file mode 100644 index 000000000..5c3f6ece3 --- /dev/null +++ b/tacker/common/csar_utils.py @@ -0,0 +1,310 @@ +# Copyright (C) 2019 NTT DATA +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, 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. + +import os +import shutil + +from oslo_log import log as logging +from oslo_utils import encodeutils +from oslo_utils import excutils +from toscaparser.tosca_template import ToscaTemplate +import zipfile + +from tacker.common import exceptions +import tacker.conf + + +CONF = tacker.conf.CONF +LOG = logging.getLogger(__name__) + + +def _check_type(custom_def, node_type, type_list): + for node_data_type, node_data_type_value in custom_def.items(): + if node_data_type == node_type and node_type in type_list: + return True, node_data_type_value + for k, v in node_data_type_value.items(): + if k == 'derived_from': + if v in type_list and node_type == node_data_type: + return True, node_data_type_value + return False, None + + +def _get_sw_image_artifact(artifacts): + if not artifacts: + return + + for artifact_value in artifacts.values(): + if 'type' in artifact_value: + if artifact_value['type'] == 'tosca.artifacts.nfv.SwImage': + return artifact_value + + +def _update_default_vnfd_data(node_value, node_type_value): + vnf_properties = node_value['properties'] + type_properties = node_type_value['properties'] + for property_key, property_value in type_properties.items(): + if property_key == 'descriptor_id': + # if descriptor_id is parameterized, then get the value from the + # default property and set it in the vnf_properties. + if vnf_properties and isinstance( + vnf_properties.get('descriptor_id'), dict): + vnf_properties['descriptor_id'] = property_value.get("default") + return vnf_properties + + +def _get_vnf_data(nodetemplates): + type_list = ['tosca.nodes.nfv.VNF'] + for nt in nodetemplates: + for node_name, node_value in nt.templates.items(): + type_status, node_type_value = _check_type(nt.custom_def, + node_value['type'], type_list) + if type_status and node_type_value: + return _update_default_vnfd_data(node_value, node_type_value) + + +def _get_instantiation_levels(policies): + if policies: + for policy in policies: + if policy.type_definition.type == \ + 'tosca.policies.nfv.InstantiationLevels': + return policy.properties + + +def _update_flavour_data_from_vnf(custom_defs, node_tpl, flavour): + type_list = ['tosca.nodes.nfv.VNF'] + + type_status, _ = _check_type(custom_defs, node_tpl['type'], type_list) + if type_status and node_tpl['properties']: + vnf_properties = node_tpl['properties'] + if 'flavour_description' in vnf_properties: + flavour.update( + {'flavour_description': vnf_properties[ + 'flavour_description']}) + if 'flavour_id' in vnf_properties: + flavour.update({'flavour_id': vnf_properties['flavour_id']}) + + +def _get_software_image(custom_defs, nodetemplate_name, node_tpl): + type_list = ['tosca.nodes.nfv.Vdu.Compute', + 'tosca.nodes.nfv.Vdu.VirtualBlockStorage'] + type_status, _ = _check_type(custom_defs, node_tpl['type'], type_list) + if type_status: + properties = node_tpl['properties'] + sw_image_artifact = _get_sw_image_artifact(node_tpl.get('artifacts')) + if sw_image_artifact: + properties['sw_image_data'].update( + {'software_image_id': nodetemplate_name}) + sw_image_data = properties['sw_image_data'] + if 'metadata' in sw_image_artifact: + sw_image_data.update({'metadata': + sw_image_artifact['metadata']}) + return sw_image_data + + +def _populate_flavour_data(tosca): + flavours = [] + for tp in tosca.nested_tosca_templates_with_topology: + sw_image_list = [] + + # Setting up flavour data + flavour_id = tp.substitution_mappings.properties.get('flavour_id') + if flavour_id: + flavour = {'flavour_id': flavour_id} + else: + flavour = {} + instantiation_levels = _get_instantiation_levels(tp.policies) + if instantiation_levels: + flavour.update({'instantiation_levels': instantiation_levels}) + for template_name, node_tpl in tp.tpl.get('node_templates').items(): + # check the flavour property in vnf data + _update_flavour_data_from_vnf(tp.custom_defs, node_tpl, flavour) + + # Update the software image data + sw_image = _get_software_image(tp.custom_defs, template_name, + node_tpl) + if sw_image: + sw_image_list.append(sw_image) + + # Add software images for flavour + if sw_image_list: + flavour.update({'sw_images': sw_image_list}) + + if flavour: + flavours.append(flavour) + + return flavours + + +def _get_instantiation_levels_from_policy(tpl_policies): + """Get defined instantiation levels + + Getting instantiation levels defined under policy type + 'tosca.policies.nfv.InstantiationLevels'. + """ + + levels = [] + for policy in tpl_policies: + for key, value in policy.items(): + if value.get('type') == 'tosca.policies.nfv.InstantiationLevels'\ + and value.get('properties', {}).get('levels', {}): + levels = value.get('properties').get('levels').keys() + default_level = value.get( + 'properties').get('default_level') + + if default_level and default_level not in levels: + error_msg = "Level {} not found in defined levels" \ + " {}".format(default_level, + ",".join(sorted(levels))) + raise exceptions.InvalidCSAR(error_msg) + return levels + + +def _validate_instantiation_levels(policy, instantiation_levels): + expected_policy_type = ['tosca.policies.nfv.VduInstantiationLevels', + 'tosca.policies.nfv.' + 'VirtualLinkInstantiationLevels'] + for policy_name, policy_tpl in policy.items(): + if policy_tpl.get('type') not in expected_policy_type: + return + + if not instantiation_levels: + msg = ('Policy of type' + ' "tosca.policies.nfv.InstantiationLevels is not defined.') + raise exceptions.InvalidCSAR(msg) + if policy_tpl.get('properties'): + levels_in_policy = policy_tpl.get( + 'properties').get('levels') + + if levels_in_policy: + invalid_levels = set(levels_in_policy.keys()) - set( + instantiation_levels) + else: + invalid_levels = set() + + if invalid_levels: + error_msg = "Level(s) {} not found in defined levels" \ + " {}".format(",".join(sorted(invalid_levels)), + ",".join(sorted(instantiation_levels) + )) + raise exceptions.InvalidCSAR(error_msg) + + +def _validate_sw_image_data_for_artifact(node_tpl, template_name): + artifact_type = [] + artifacts = node_tpl.get('artifacts') + if artifacts: + for key, value in artifacts.items(): + if value.get('type') == 'tosca.artifacts.nfv.SwImage': + artifact_type.append(value.get('type')) + + if len(artifact_type) > 1: + error_msg = ('artifacts of type "tosca.artifacts.nfv.SwImage"' + ' is added more than one time for' + ' node %(node)s.') % {'node': template_name} + raise exceptions.InvalidCSAR(error_msg) + + if artifact_type and node_tpl.get('properties'): + if not node_tpl.get('properties').get('sw_image_data'): + error_msg = ('Node property "sw_image_data" is missing for' + ' artifact type %(type)s for ' + 'node %(node)s.') % { + 'type': artifact_type[0], 'node': template_name} + raise exceptions.InvalidCSAR(error_msg) + + +def _validate_sw_image_data_for_artifacts(tosca): + for tp in tosca.nested_tosca_templates_with_topology: + for template_name, node_tpl in tp.tpl.get('node_templates').items(): + _validate_sw_image_data_for_artifact(node_tpl, template_name) + + for template in tosca.nodetemplates: + _validate_sw_image_data_for_artifact( + template.entity_tpl, template.name) + + +def _get_data_from_csar(tosca, context, id): + for tp in tosca.nested_tosca_templates_with_topology: + levels = _get_instantiation_levels_from_policy(tp.tpl.get("policies")) + for policy_tpl in tp.tpl.get("policies"): + _validate_instantiation_levels(policy_tpl, levels) + + _validate_sw_image_data_for_artifacts(tosca) + vnf_data = _get_vnf_data(tosca.nodetemplates) + if not vnf_data: + error_msg = "VNF properties are mandatory" + raise exceptions.InvalidCSAR(error_msg) + + flavours = _populate_flavour_data(tosca) + if not flavours: + error_msg = "No VNF flavours are available" + raise exceptions.InvalidCSAR(error_msg) + + return vnf_data, flavours + + +def _extract_csar_zip_file(file_path, extract_path): + try: + with zipfile.ZipFile(file_path, 'r') as zf: + zf.extractall(extract_path) + except (RuntimeError, zipfile.BadZipfile) as exp: + with excutils.save_and_reraise_exception(): + LOG.error("Error encountered while extracting " + "csar zip file %(path)s. Error: %(error)s.", + {'path': file_path, + 'error': encodeutils.exception_to_unicode(exp)}) + exp.reraise = False + raise exceptions.InvalidZipFile(path=file_path) + + +def load_csar_data(context, package_uuid, zip_path): + + extract_zip_path = os.path.join(CONF.vnf_package.vnf_package_csar_path, + package_uuid) + _extract_csar_zip_file(zip_path, extract_zip_path) + + try: + tosca = ToscaTemplate(zip_path, None, True) + return _get_data_from_csar(tosca, context, package_uuid) + except exceptions.InvalidCSAR as exp: + with excutils.save_and_reraise_exception(): + LOG.error("Error processing CSAR file %(path)s for vnf package" + " %(uuid)s: Error: %(error)s. ", + {'path': zip_path, 'uuid': package_uuid, + 'error': encodeutils.exception_to_unicode(exp)}) + except Exception as exp: + with excutils.save_and_reraise_exception(): + LOG.error("Tosca parser failed for vnf package %(uuid)s: " + "Error: %(error)s. ", {'uuid': package_uuid, + 'error': encodeutils.exception_to_unicode(exp)}) + exp.reraise = False + raise exceptions.InvalidCSAR(encodeutils.exception_to_unicode + (exp)) + + +def delete_csar_data(package_uuid): + # Remove zip and folder from the vnf_package_csar_path + csar_zip_temp_path = os.path.join(CONF.vnf_package.vnf_package_csar_path, + package_uuid) + csar_path = os.path.join(CONF.vnf_package.vnf_package_csar_path, + package_uuid + ".zip") + + try: + shutil.rmtree(csar_zip_temp_path) + os.remove(csar_path) + except OSError as exc: + exc_message = encodeutils.exception_to_unicode(exc) + msg = _('Failed to delete csar folder: ' + '%(csar_path)s, Error: %(exc)s') + LOG.warning(msg, {'csar_path': csar_path, 'exc': exc_message}) diff --git a/tacker/common/exceptions.py b/tacker/common/exceptions.py index 8dfe1b196..94ecbf4c5 100644 --- a/tacker/common/exceptions.py +++ b/tacker/common/exceptions.py @@ -136,9 +136,7 @@ class MalformedRequestBody(BadRequest): class Invalid(TackerException): - def __init__(self, message=None): - self.message = message - super(Invalid, self).__init__() + message = _("Bad Request - Invalid Parameters") class InvalidInput(BadRequest): @@ -219,3 +217,35 @@ class VnfSoftwareImageNotFound(NotFound): class OrphanedObjectError(TackerException): msg_fmt = _('Cannot call %(method)s on orphaned %(objtype)s object') + + +class CSARFileSizeLimitExceeded(TackerException): + message = _("The provided CSAR file is too large.") + + +class VNFPackageURLInvalid(Invalid): + message = _("Failed to open URL %(url)s") + + +class InvalidZipFile(Invalid): + message = _("Invalid zip file : %(path)s") + + +class UploadFailedToGlanceStore(Invalid): + message = _("Failed to upload vnf package %(uuid)s to glance store: " + "%(error)s") + + +class InvalidCSAR(Invalid): + message = _("Invalid csar: %(error)s") + + +class LimitExceeded(TackerException): + message = _("The request returned a 413 Request Entity Too Large. This " + "generally means that rate limiting or a quota threshold was " + "breached.\n\nThe response body:\n%(body)s") + + def __init__(self, *args, **kwargs): + self.retry_after = (int(kwargs['retry']) if kwargs.get('retry') + else None) + super(LimitExceeded, self).__init__(*args, **kwargs) diff --git a/tacker/common/rpc.py b/tacker/common/rpc.py index 505598254..e7dd4437a 100644 --- a/tacker/common/rpc.py +++ b/tacker/common/rpc.py @@ -27,6 +27,7 @@ from oslo_utils import excutils from tacker.common import exceptions from tacker import context +from tacker.objects import base as objects_base LOG = logging.getLogger(__name__) @@ -60,7 +61,8 @@ def init(conf): allowed_remote_exmods=exmods) NOTIFICATION_TRANSPORT = oslo_messaging.get_notification_transport( conf, allowed_remote_exmods=exmods) - serializer = RequestContextSerializer() + json_serializer = oslo_messaging.JsonPayloadSerializer() + serializer = RequestContextSerializer(json_serializer) NOTIFIER = oslo_messaging.Notifier(NOTIFICATION_TRANSPORT, serializer=serializer) @@ -298,7 +300,8 @@ class Connection(object): target = oslo_messaging.Target( topic=topic, server=host or cfg.CONF.host, fanout=fanout, exchange=exchange) - server = get_server(target, endpoints) + serializer = objects_base.TackerObjectSerializer() + server = get_server(target, endpoints, serializer) self.servers.append(server) def consume_in_threads(self): diff --git a/tacker/common/safe_utils.py b/tacker/common/safe_utils.py new file mode 100644 index 000000000..0ee71620a --- /dev/null +++ b/tacker/common/safe_utils.py @@ -0,0 +1,41 @@ +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# Copyright 2011 Justin Santa Barbara +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, 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. + +"""Utilities and helper functions that won't produce circular imports.""" + + +def get_wrapped_function(function): + """Get the method at the bottom of a stack of decorators.""" + if not hasattr(function, '__closure__') or not function.__closure__: + return function + + def _get_wrapped_function(function): + if not hasattr(function, '__closure__') or not function.__closure__: + return None + + for closure in function.__closure__: + func = closure.cell_contents + + deeper_func = _get_wrapped_function(func) + if deeper_func: + return deeper_func + elif hasattr(closure.cell_contents, '__call__'): + return closure.cell_contents + + return function + + return _get_wrapped_function(function) diff --git a/tacker/common/utils.py b/tacker/common/utils.py index 1c6b1656b..392e136df 100644 --- a/tacker/common/utils.py +++ b/tacker/common/utils.py @@ -18,6 +18,8 @@ """Utilities and helper functions.""" +import functools +import inspect import logging as std_logging import os import random @@ -32,11 +34,18 @@ import netaddr from oslo_concurrency import lockutils from oslo_config import cfg from oslo_log import log as logging +from oslo_utils import excutils from oslo_utils import importutils from stevedore import driver +try: + from eventlet import sleep +except ImportError: + from time import sleep from tacker._i18n import _ from tacker.common import constants as q_const +from tacker.common import exceptions +from tacker.common import safe_utils TIME_FORMAT = "%Y-%m-%dT%H:%M:%SZ" @@ -66,6 +75,12 @@ MEM_UNITS = { } CONF = cfg.CONF synchronized = lockutils.synchronized_with_prefix(SYNCHRONIZED_PREFIX) +MAX_COOP_READER_BUFFER_SIZE = 134217728 + +if hasattr(inspect, 'getfullargspec'): + getargspec = inspect.getfullargspec +else: + getargspec = inspect.getargspec def find_config_file(options, config_file): @@ -231,3 +246,213 @@ def none_from_string(orig_str): return None else: return orig_str + + +def expects_func_args(*args): + def _decorator_checker(dec): + @functools.wraps(dec) + def _decorator(f): + base_f = safe_utils.get_wrapped_function(f) + argspec = getargspec(base_f) + if argspec[1] or argspec[2] or set(args) <= set(argspec[0]): + # NOTE (nirajsingh): We can't really tell if correct stuff will + # be passed if it's a function with *args or **kwargs so + # we still carry on and hope for the best + return dec(f) + else: + raise TypeError("Decorated function %(f_name)s does not " + "have the arguments expected by the " + "decorator %(d_name)s" % + {'f_name': base_f.__name__, + 'd_name': dec.__name__}) + + return _decorator + + return _decorator_checker + + +def cooperative_iter(iter): + """Prevent eventlet thread starvation during iteration + + Return an iterator which schedules after each + iteration. This can prevent eventlet thread starvation. + + :param iter: an iterator to wrap + """ + try: + for chunk in iter: + sleep(0) + yield chunk + except Exception as err: + with excutils.save_and_reraise_exception(): + msg = _("Error: cooperative_iter exception %s") % err + LOG.error(msg) + + +def cooperative_read(fd): + """Prevent eventlet thread starvationafter each read operation. + + Wrap a file descriptor's read with a partial function which schedules + after each read. This can prevent eventlet thread starvation. + + :param fd: a file descriptor to wrap + """ + def readfn(*args): + result = fd.read(*args) + sleep(0) + return result + return readfn + + +def chunkreadable(iter, chunk_size=65536): + """Wrap a readable iterator. + + Wrap a readable iterator with a reader yielding chunks of + a preferred size, otherwise leave iterator unchanged. + + :param iter: an iter which may also be readable + :param chunk_size: maximum size of chunk + """ + return chunkiter(iter, chunk_size) if hasattr(iter, 'read') else iter + + +def chunkiter(fp, chunk_size=65536): + """Convert iterator to a file-like object. + + Return an iterator to a file-like obj which yields fixed size chunks + + :param fp: a file-like object + :param chunk_size: maximum size of chunk + """ + while True: + chunk = fp.read(chunk_size) + if chunk: + yield chunk + else: + break + + +class CooperativeReader(object): + """An eventlet thread friendly class for reading in image data. + + When accessing data either through the iterator or the read method + we perform a sleep to allow a co-operative yield. When there is more than + one image being uploaded/downloaded this prevents eventlet thread + starvation, ie allows all threads to be scheduled periodically rather than + having the same thread be continuously active. + """ + def __init__(self, fd): + """Construct an CooperativeReader object. + + :param fd: Underlying image file object + + """ + self.fd = fd + self.iterator = None + # NOTE(nirajsingh): if the underlying supports read(), overwrite the + # default iterator-based implementation with cooperative_read which + # is more straightforward + if hasattr(fd, 'read'): + self.read = cooperative_read(fd) + else: + self.iterator = None + self.buffer = b'' + self.position = 0 + + def read(self, length=None): + """Return the requested amount of bytes. + + Fetching the next chunk of the underlying iterator when needed. + This is replaced with cooperative_read in __init__ if the underlying + fd already supports read(). + + """ + + if length is None: + if len(self.buffer) - self.position > 0: + # if no length specified but some data exists in buffer, + # return that data and clear the buffer + result = self.buffer[self.position:] + self.buffer = b'' + self.position = 0 + return bytes(result) + else: + # otherwise read the next chunk from the underlying iterator + # and return it as a whole. Reset the buffer, as subsequent + # calls may specify the length + try: + if self.iterator is None: + self.iterator = self.__iter__() + return next(self.iterator) + except StopIteration: + return b'' + finally: + self.buffer = b'' + self.position = 0 + else: + result = bytearray() + while len(result) < length: + if self.position < len(self.buffer): + to_read = length - len(result) + chunk = self.buffer[self.position:self.position + to_read] + result.extend(chunk) + + # This check is here to prevent potential OOM issues if + # this code is called with unreasonably high values of read + # size. Currently it is only called from the HTTP clients + # of Glance backend stores, which use httplib for data + # streaming, which has readsize hardcoded to 8K, so this + # check should never fire. Regardless it still worths to + # make the check, as the code may be reused somewhere else. + if len(result) >= MAX_COOP_READER_BUFFER_SIZE: + raise exceptions.LimitExceeded() + self.position += len(chunk) + else: + try: + if self.iterator is None: + self.iterator = self.__iter__() + self.buffer = next(self.iterator) + self.position = 0 + except StopIteration: + self.buffer = b'' + self.position = 0 + return bytes(result) + return bytes(result) + + def __iter__(self): + return cooperative_iter(self.fd.__iter__()) + + +class LimitingReader(object): + """Limit Reader to read data past to configured allowed amount. + + Reader designed to fail when reading image data past the configured + allowable amount. + """ + def __init__(self, data, limit, + exception_class=exceptions.CSARFileSizeLimitExceeded): + """Construct an LimitingReader object. + + :param data: Underlying image data object + :param limit: maximum number of bytes the reader should allow + :param exception_class: Type of exception to be raised + """ + self.data = data + self.limit = limit + self.bytes_read = 0 + self.exception_class = exception_class + + def __iter__(self): + for chunk in self.data: + self.bytes_read += len(chunk) + if self.bytes_read > self.limit: + raise self.exception_class() + else: + yield chunk + + def read(self, i): + result = self.data.read(i) + self.bytes_read += len(result) + if self.bytes_read > self.limit: + raise self.exception_class() + return result diff --git a/tacker/conductor/conductor_server.py b/tacker/conductor/conductor_server.py index b24283003..2abc8e4af 100644 --- a/tacker/conductor/conductor_server.py +++ b/tacker/conductor/conductor_server.py @@ -13,38 +13,111 @@ # License for the specific language governing permissions and limitations # under the License. +import datetime +import functools +import inspect +import os +import shutil import sys -from oslo_config import cfg from oslo_log import log as logging import oslo_messaging +from oslo_service import periodic_task from oslo_service import service +from oslo_utils import excutils from oslo_utils import timeutils from sqlalchemy.orm import exc as orm_exc +from tacker.common import csar_utils +from tacker.common import exceptions +from tacker.common import safe_utils from tacker.common import topics +from tacker.common import utils +import tacker.conf from tacker import context as t_context from tacker.db.common_services import common_services_db from tacker.db.nfvo import nfvo_db from tacker.extensions import nfvo +from tacker.glance_store import store as glance_store from tacker import manager from tacker import objects +from tacker.objects import fields +from tacker.objects.vnf_package import VnfPackagesList from tacker.plugins.common import constants from tacker import service as tacker_service from tacker import version +CONF = tacker.conf.CONF LOG = logging.getLogger(__name__) +def _delete_csar(context, vnf_package): + # Delete from glance store + glance_store.delete_csar(context, vnf_package.id, + vnf_package.location_glance_store) + + csar_utils.delete_csar_data(vnf_package.id) + + +@utils.expects_func_args('vnf_package') +def revert_upload_vnf_package(function): + """Decorator to revert upload_vnf_package on failure.""" + + @functools.wraps(function) + def decorated_function(self, context, *args, **kwargs): + try: + return function(self, context, *args, **kwargs) + except Exception as exp: + with excutils.save_and_reraise_exception(): + wrapped_func = safe_utils.get_wrapped_function(function) + keyed_args = inspect.getcallargs(wrapped_func, self, context, + *args, **kwargs) + context = keyed_args['context'] + vnf_package = keyed_args['vnf_package'] + if not isinstance(exp, exceptions.UploadFailedToGlanceStore): + # Delete the csar file from the glance store. + glance_store.delete_csar(context, vnf_package.id, + vnf_package.location_glance_store) + + csar_utils.delete_csar_data(vnf_package.id) + + # Delete the vnf_deployment_flavour if created. + if vnf_package.vnf_deployment_flavours: + for flavour in vnf_package.vnf_deployment_flavours: + flavour.destroy(context) + + # Set the vnf package onboarding status to created, + # so that user can retry uploading vnf package + # after correcting the csar zip file. + vnf_package.onboarding_state = ( + fields.PackageOnboardingStateType.CREATED) + + vnf_package.save() + + return decorated_function + + class Conductor(manager.Manager): def __init__(self, host, conf=None): if conf: self.conf = conf else: - self.conf = cfg.CONF + self.conf = CONF super(Conductor, self).__init__(host=self.conf.host) + def init_host(self): + glance_store.initialize_glance_store() + self._basic_config_check() + + def _basic_config_check(self): + if not os.path.isdir(CONF.vnf_package.vnf_package_csar_path): + LOG.error("Config option 'vnf_package_csar_path' is not " + "configured correctly. VNF package CSAR path directory" + " %s doesn't exist", + CONF.vnf_package.vnf_package_csar_path) + sys.exit(1) + def update_vim(self, context, vim_id, status): t_admin_context = t_context.get_admin_context() update_time = timeutils.utcnow() @@ -67,27 +140,171 @@ class Conductor(manager.Manager): t_admin_context.session.add(event_db) return status + def _create_software_images(self, context, sw_image, flavour_uuid): + vnf_sw_image = objects.VnfSoftwareImage(context=context) + vnf_sw_image.flavour_uuid = flavour_uuid + vnf_sw_image.name = sw_image.get('name') + + # TODO(nirajsingh) Provider is mandatory as per SOL005 but it's not + # a required parameter in SwImageData as per SOL001. SOL001 will be + # amended to make `provider` a required parameter as per + # 'https://docbox.etsi.org/ISG/NFV/SOL/05-CONTRIBUTIONS/2019/ + # NFVSOL000338_SOL001ed271_SwImage_Provider.docx'. + vnf_sw_image.provider = sw_image.get('provider', "") + + vnf_sw_image.version = sw_image.get('version') + if sw_image.get('checksum'): + checksum = sw_image.get('checksum') + if checksum.get('algorithm'): + vnf_sw_image.algorithm = checksum.get('algorithm') + if checksum.get('hash'): + vnf_sw_image.hash = checksum.get('hash') + vnf_sw_image.container_format = sw_image.get('container_format') + vnf_sw_image.disk_format = sw_image.get('disk_format') + if sw_image.get('min_ram'): + min_ram = sw_image.get('min_ram') + vnf_sw_image.min_ram = int(min_ram.split()[0]) + else: + vnf_sw_image.min_ram = 0 + vnf_sw_image.min_disk = int(sw_image.get('min_disk').split()[0]) + vnf_sw_image.size = int(sw_image.get('size').split()[0]) + vnf_sw_image.image_path = '' + vnf_sw_image.software_image_id = sw_image['software_image_id'] + vnf_sw_image.metadata = sw_image.get('metadata', dict()) + vnf_sw_image.create() + + def _create_flavour(self, context, package_uuid, flavour): + deploy_flavour = objects.VnfDeploymentFlavour(context=context) + deploy_flavour.package_uuid = package_uuid + deploy_flavour.flavour_id = flavour['flavour_id'] + deploy_flavour.flavour_description = flavour['flavour_description'] + deploy_flavour.instantiation_levels = \ + flavour['instantiation_levels'] + deploy_flavour.create() + + sw_images = flavour.get('sw_images') + if sw_images: + for sw_image in sw_images: + self._create_software_images( + context, sw_image, deploy_flavour.id) + + def _onboard_vnf_package(self, context, vnf_package, vnf_data, flavours): + package_vnfd = objects.VnfPackageVnfd(context=context) + package_vnfd.package_uuid = vnf_package.id + + package_vnfd.vnfd_id = vnf_data.get('descriptor_id') + package_vnfd.vnf_provider = vnf_data.get('provider') + package_vnfd.vnf_product_name = vnf_data.get('product_name') + package_vnfd.vnf_software_version = vnf_data.get('software_version') + package_vnfd.vnfd_version = vnf_data.get('descriptor_version') + package_vnfd.create() + + for flavour in flavours: + self._create_flavour(context, vnf_package.id, flavour) + + @revert_upload_vnf_package + def upload_vnf_package_content(self, context, vnf_package): + location = vnf_package.location_glance_store + zip_path = glance_store.load_csar(vnf_package.id, location) + vnf_data, flavours = csar_utils.load_csar_data( + context.elevated(), vnf_package.id, zip_path) + self._onboard_vnf_package(context, vnf_package, vnf_data, flavours) + vnf_package.onboarding_state = ( + fields.PackageOnboardingStateType.ONBOARDED) + vnf_package.operational_state = ( + fields.PackageOperationalStateType.ENABLED) + + vnf_package.save() + + @revert_upload_vnf_package + def upload_vnf_package_from_uri(self, context, vnf_package, + address_information, user_name=None, + password=None): + + body = {"address_information": address_information} + (location, size, checksum, multihash, + loc_meta) = glance_store.store_csar(context, vnf_package.id, body) + + vnf_package.onboarding_state = ( + fields.PackageOnboardingStateType.PROCESSING) + + vnf_package.algorithm = CONF.vnf_package.hashing_algorithm + vnf_package.hash = multihash + vnf_package.location_glance_store = location + + vnf_package.save() + + zip_path = glance_store.load_csar(vnf_package.id, location) + vnf_data, flavours = csar_utils.load_csar_data( + context.elevated(), vnf_package.id, zip_path) + + self._onboard_vnf_package(context, vnf_package, vnf_data, flavours) + + vnf_package.onboarding_state = ( + fields.PackageOnboardingStateType.ONBOARDED) + vnf_package.operational_state = ( + fields.PackageOperationalStateType.ENABLED) + + vnf_package.save() + + def delete_vnf_package(self, context, vnf_package): + if (vnf_package.onboarding_state == + fields.PackageOnboardingStateType.ONBOARDED): + + _delete_csar(context, vnf_package) + + vnf_package.destroy(context) + + @periodic_task.periodic_task(spacing=CONF.vnf_package_delete_interval) + def _run_cleanup_vnf_packages(self, context): + """Delete orphan extracted csar zip and files from extracted path + + This periodic task will get all deleted packages for the period + (now - CONF.vnf_package_delete_interval) and delete any left out + csar zip files and vnf packages files from the extracted path. + """ + + time_duration = datetime.datetime.utcnow() - datetime.timedelta( + seconds=CONF.vnf_package_delete_interval) + filters = {'deleted_at': time_duration} + deleted_vnf_packages = VnfPackagesList.get_by_filters( + context.elevated(), read_deleted='only', **filters) + for vnf_pack in deleted_vnf_packages: + csar_zip_temp_path = (CONF.vnf_package.vnf_package_csar_path + + vnf_pack.id) + csar_path = (CONF.vnf_package.vnf_package_csar_path + + vnf_pack.id + '.zip') + try: + if os.path.exists(csar_zip_temp_path): + shutil.rmtree(csar_zip_temp_path) + os.remove(csar_path) + except OSError: + LOG.warning("Failed to delete csar zip %(zip)s and" + " folder $(folder)s for vnf package %(uuid)s.", + {'zip': csar_path, 'folder': csar_zip_temp_path, + 'uuid': vnf_pack.id}) + def init(args, **kwargs): - cfg.CONF(args=args, project='tacker', - version='%%prog %s' % version.version_info.release_string(), - **kwargs) + CONF(args=args, project='tacker', + version='%%prog %s' % version.version_info.release_string(), + **kwargs) # FIXME(ihrachys): if import is put in global, circular import # failure occurs from tacker.common import rpc as n_rpc - n_rpc.init(cfg.CONF) + n_rpc.init(CONF) def main(manager='tacker.conductor.conductor_server.Conductor'): init(sys.argv[1:]) objects.register_all() - logging.setup(cfg.CONF, "tacker") + logging.setup(CONF, "tacker") oslo_messaging.set_transport_defaults(control_exchange='tacker') - logging.setup(cfg.CONF, "tacker") - cfg.CONF.log_opt_values(LOG, logging.DEBUG) + logging.setup(CONF, "tacker") + CONF.log_opt_values(LOG, logging.DEBUG) server = tacker_service.Service.create( binary='tacker-conductor', topic=topics.TOPIC_CONDUCTOR, manager=manager) - service.launch(cfg.CONF, server, restart_method='mutate').wait() + service.launch(CONF, server, restart_method='mutate').wait() diff --git a/tacker/conf/__init__.py b/tacker/conf/__init__.py index 072466c27..e1d20cb69 100644 --- a/tacker/conf/__init__.py +++ b/tacker/conf/__init__.py @@ -13,6 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. +import glance_store from oslo_config import cfg from tacker.conf import conductor @@ -23,3 +24,4 @@ CONF = cfg.CONF vnf_package.register_opts(CONF) conductor.register_opts(CONF) +glance_store.register_opts(CONF) diff --git a/tacker/glance_store/__init__.py b/tacker/glance_store/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tacker/glance_store/store.py b/tacker/glance_store/store.py new file mode 100644 index 000000000..e5f6c2ede --- /dev/null +++ b/tacker/glance_store/store.py @@ -0,0 +1,117 @@ +# Copyright (C) 2019 NTT DATA +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, 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. + +import os + +import glance_store +from glance_store import exceptions as store_exceptions +from oslo_log import log as logging +from oslo_utils import encodeutils +from oslo_utils import units +from six.moves import urllib + +from tacker.common import exceptions +from tacker.common import utils +import tacker.conf + + +CONF = tacker.conf.CONF +LOG = logging.getLogger(__name__) + + +def initialize_glance_store(): + """Initialize glance store.""" + glance_store.create_stores(CONF) + glance_store.verify_default_store() + + +def get_csar_data_iter(body): + try: + if isinstance(body, dict): + url = body['address_information'] + data_iter = urllib.request.urlopen(url) + else: + data_iter = body + + return data_iter + except Exception: + LOG.warn("Failed to open csar URL: %s", url) + raise exceptions.VNFPackageURLInvalid(url=url) + + +def store_csar(context, package_uuid, body): + + data_iter = get_csar_data_iter(body) + + try: + # store CSAR file in glance_store + (location, size, checksum, multihash, + loc_meta) = glance_store.add_to_backend_with_multihash( + CONF, package_uuid, + utils.LimitingReader( + utils.CooperativeReader(data_iter), + CONF.vnf_package.csar_file_size_cap * units.Gi), + 0, + CONF.vnf_package.hashing_algorithm, + context=context) + except Exception as e: + error = encodeutils.exception_to_unicode(e) + LOG.warn("Failed to store csar data in glance store for " + "package %(uuid)s due to error: %(error)s", + {"uuid": package_uuid, + "error": error}) + raise exceptions.UploadFailedToGlanceStore(uuid=package_uuid, + error=error) + finally: + if hasattr(data_iter, 'close'): + data_iter.close() + + return location, size, checksum, multihash, loc_meta + + +def delete_csar(context, package_uuid, location): + + try: + glance_store.delete_from_backend(location, context) + except store_exceptions.NotFound: + LOG.info("Failed to find csar data in glance store for " + "package %(uuid)s", + {"uuid": package_uuid}) + + +def load_csar(package_uuid, location): + zip_path = os.path.join(CONF.vnf_package.vnf_package_csar_path, + package_uuid + ".zip") + + try: + resp, size = glance_store.backend.get_from_backend(location) + except Exception as exp: + LOG.info("Failed to get csar data from glance store %(location)s for " + "package %(uuid)s", + {"location": location, "uuid": package_uuid}) + + try: + temp_data = open(zip_path, 'wb') + for chunk in resp: + temp_data.write(chunk) + temp_data.close() + except Exception as exp: + LOG.exception("Exception encountered while tee'ing " + "csar '%(package_uuid)s' into csar path %(zip_path)s:" + "%(error)s. ", {'package_uuid': package_uuid, + 'zip_path': zip_path, + 'error': encodeutils.exception_to_unicode(exp)}) + + return zip_path diff --git a/tacker/objects/base.py b/tacker/objects/base.py index c699b0d68..c52b598d6 100644 --- a/tacker/objects/base.py +++ b/tacker/objects/base.py @@ -144,6 +144,7 @@ class TackerObjectSerializer(messaging.NoOpSerializer): :returns: A new container of the same type (except set) with items from values having had action applied. """ + iterable = values.__class__ if issubclass(iterable, dict): return iterable(**{k: action_fn(context, v) diff --git a/tacker/tests/constants.py b/tacker/tests/constants.py index d82ce4a97..de615b560 100644 --- a/tacker/tests/constants.py +++ b/tacker/tests/constants.py @@ -36,3 +36,5 @@ LEASE_EVENT_STATUS = 'DONE' START_LEASE_EVET_TYPE = 'start_lease' LEASE_CHECK_EVENT_TIMEOUT = 300 LEASE_CHECK_SLEEP_TIME = 3 +UUID = 'f26f181d-7891-4720-b022-b074ec1733ef' +INVALID_UUID = 'f181d-7891-4720-b022-b074ec3ef' diff --git a/tacker/tests/etc/samples/csar_invalid_instantiation_level.zip b/tacker/tests/etc/samples/csar_invalid_instantiation_level.zip new file mode 100644 index 0000000000000000000000000000000000000000..152b395217290999cc968b736efb1919a56d0a45 GIT binary patch literal 16848 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 literal 0 HcmV?d00001 diff --git a/tacker/tests/etc/samples/csar_with_flavour_info_in_main_template.zip b/tacker/tests/etc/samples/csar_with_flavour_info_in_main_template.zip new file mode 100644 index 0000000000000000000000000000000000000000..7a0c87ce8f799d4c5b03e8472351ef97a1dcd1a4 GIT binary patch literal 16922 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 literal 0 HcmV?d00001 diff --git a/tacker/tests/etc/samples/csar_with_invalid_default_instantiation_level.zip b/tacker/tests/etc/samples/csar_with_invalid_default_instantiation_level.zip new file mode 100644 index 0000000000000000000000000000000000000000..07e734169a85254545e3eda7af07d75bc9d88b6a GIT binary patch literal 16815 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 A?*IS* literal 0 HcmV?d00001 diff --git a/tacker/tests/etc/samples/csar_with_missing_sw_image_data_in_main_template.zip b/tacker/tests/etc/samples/csar_with_missing_sw_image_data_in_main_template.zip new file mode 100644 index 0000000000000000000000000000000000000000..e66216ac5efb07cc92a2c3b49ebf68f1f0a52dea GIT binary patch literal 16371 zcmai*1DGUB+V87v+cu|dyQgj2wr$(CZBDzVZA^DhW7@WL=bYXB_Uzg3-W&B~MMgbu z{(lvf5pP9R=3ibK1QZqUM~MrilKXS#pHHyAYY`Ju3tJ0k3p-mU2Kj$RLIPT~$>n@F z9U|Ny0RV7P0D$gqktWVg7J9a(u6j;(){Kl_^o;CmZ0v0HoIUJKoaj9aY^={Uwd@uc zQGGA#I07-^r552p&Fz8$S)fMrQFsVZJ0cda6FF98#XoruSEp+%mSIHwK@E%U_n$Uq z4vj7br@D^2n%Za?G%{-mHS4{ni4>TE$ka5y%ob`g zdtvjy$%FG8dwP8!r*lW3OQt*MYesoY8@-In2YF1Bbd|*uvjeRfL6gDMM%NRs z@?%8_$x%C#GUaAjqF2LB>yw*|YuJi=o#|rmAVbZACa6E~@R}b5*f(z52e_g#CqOp= zXKX)nW;u0*?thU$qibgykH|{yNC65XN~0VS1s*_N*oe<(uiP`jy}5HMUfwT6h7S9d zCUlKC6>KbNAZ+UEjmoS?)q%<}-@uqPHs6QS`U@Igcsz}#=8o!y^T<5lm&OisDW(`e zt^BA^LUhQK%5B-tgVoqp;jQg~-0F3QG^L$8FRYkiqj!i0@iWttI?>)?zefCQWvD9N z_Xp@18d$X&FznSjJH>VDG!-?7+~(v_@;r6p@#8uk&<3r$8R(r*s)aSm*OQxx8b%n# z9v2e@2~prFRaZ7L4EQ;am}uilt={lh0h;dtW6lJ(drJtnjjMzf1Bz2s4&xTaI?C`J zPVa|Ev6Y`WCwYjF zcYaxNKoHPRXgiq3D>do6pBS^m2gWA)pKvYA2pH!Z9pnu5G^;@8l#RKr{b+e9&|4@M z46Ay>PM9sQ_1W*~M0VcKIKk`Y^mMZiVokG6J9eNsvHFyiI~5U7)l<55tv6gjP%ba} z6;GFtz_+OvJNk`wba*M(5ElGNzFYO!CxYwshsV!ufR`dh=Mh6IG&zCA$ zaQjniZwvgF6R%d?DKFZZwd%QOG*JlH3{6{Mz3U0?aB(5VbGT2RL&JCn7D%9tvjtXK z*{E;0!?ymF~~x99d<;{{G*Iv4rVuUeHOMIz%iae`BgiRGVtRyN`eS!$QFyZ=&+lR z{3!khrN%UdsKr{gE#bk`KBjkHkcYga0COFF4^fB~de<)dGN^UzcN5tlBpUVL(ub~T z1_E2S&>C}zN<_CtRHTGFanRg11r;Qanoa?W8r3`*EFI^?DA0+f1!j+MrD9?AIzS6J z^RQ#*EDtO^LMGe`PPM#fh-EAowE`-25fk!cbqYkD6Ve_w1dg48(^DV2pt6ZQueG~I;vN>oJ z0V65JQ{X54t85|xVuJHVYZ7=Gs->nRHezt=lqTl%*>%$yT!gB4&2&X3#0Xh9UEJiq zzIhtd9XF#f8g*I@K-y@yXh^Pl=Rp}|o81y%(iRi8)nB)4DQqx3?5^ya@qY+DLkPY0 z@IY&OG1LX9a!Z)nk#Tx^2k{+urz8N|`y`B~(7j8Jr#31Nwvk&?id4CD5h`H<;-tJ= zAfx+Q$KIu_f^`@r4klF-LVcQH+*}d`UVi{zif(Kh!J$*oGK_~@UdHdxc*F&ge3$Q% z(2G?zbZO$0v-k?dujl5AE|1nL);EsRl=AlPN&|YT^szy^Up@e6u zpzSo#!C>a_+-P6IBc}<=3cb8+$K%iZm8kN*u>TOx=KOj++`P65Y}9hHR}gHfvOl^V zYisU(N(dv&Kw3p&DvT@ZTT_B_7vfx@*auFW8wU7Zk5gG?`m&bN^wzSk0`e}76YT_K zBP+u%jJg>L3X1w{(3!wdGek53`yC?x*%3}WC9UL_HS|K2nrnj6Od$mn(3%|ESlfP1 z@9aulJNh~V*+kx-KMn>~e^!5sUM~4jMW@33R5+wIAg(TE2wm0kI(ZSxN2z;W+U509 zr(L_;;gwI&s?SkdgsM-Z`6=pfk|D5b!>U2S=i1rs@(N)KGpzkVH_3>0ejn~RI`MQq z0G|HM0)AZAzaHL87#8pafRHOE8ebci(F9*Nj}5i0yt!@rb41?dt-qEda+|HtSot`ZgWS?6=D77%{m&JQK-geuJ2e0x0RaS{`Twk7 zTy0H_|FV8L!?RF26+83t9iA>?4x!p>sbkmULiIETrv%gGzq{dx72Y^ptvCl9-;Jux zZ}P3k=GTdrmFRo5B&t>|S(2UOcfDVnb?w6NYrHyi8}tvzT?nzw%#(E?H1SBGJoG=I z(I`G`y%rHqfox@k+)_qByQg{mDl!_;+n;kp3)>vg8`*@|teVrkL~mk5Xf#)urO^Ai z`E_-Fg}*-Qa{9;XrC;Ag(sMLgmP$G^NU6~M(o@nkM3IU56Z5yLIPqvSBLByzS?MKONfnXtztj#}V$3-Xp8Uq#!Q=+f20QFD%C5)(WUq zZ%_LZ9+^KwjD~Dszx7NGEJ^p>kd5A$9PoE{mwo7_LP5^&Gs$p385#dF4=%oi=mSje zf8pER5?H@RP*4T5rWstvo7#~}BAGhzL)Hy$ttg<=4;JT_!n$XRKJH8kTgKAl*Df^Y z&s2ZmF5)j`6v_aK1H$oko#8fxy37!5v=Xyd)#!w7A|{?ZCctHV<}M20H}yym9mC_T zcJ@svc|_s~=tVy*$pgR>LN9QTO2Dp8Mv9snvWa0Lr+a_l{*9d;R49r1NoeFfGVcLa z0`Git4{h=tB%Tq|qLqq-Rc3+XF3Gc+e2fK-pd& zvq`B4dVXUi#W8w)ZDcZ(<)myqC!6`_MHvXn%n=&{ND;KtANp5gz! zY>_9rvZf={Mn{zX(u3oT{9FZuFiru^j4AVg+g&BUeYqkIYPLbNrqo|wUHiO$fW+5y z=2KlXr5LM?_;PsZ)aA2M$_3r9P}bD}=S})2F{a5|aqU3yh}~fyEGSiceVU8Nso=qB zF@@NipuFZ%|B5a-lOpMaMb)ocxUacRbG#AKS8HM^S_y*B4+2(MhqoaAq@RX{AB_%6 z7)@R+&qyawYVgrjCx@-kqikN{8g3<$zRj*r)}b%+er^ng)uI)SvBNagD$i-SHitnFO$53eqn@MV@QK?xH{8i*sNOR?LG8OA16G3%5 ztle5FJAcJsYgocH905Hu$6YLMSRZO3yqhG4HAOBT_gq)$KW%We*cbYQSJq%P0iitT zbfD}yI{-M)$y<$Ft2XCMd#|>Fqd_yi7GZb*IfF9H8r&PU2H;V@eF>Gp_s$Nx3h{;R z2^Vd0d7xnk^u^q9hAPCma_QX3S{xfrKQ9ssnCoaad1aqNURL9WT5y@B-(ER7N>v7* zwbzH63mA~y)f1&x#PK@6f&}0MmqD~~!T#WaAH8&)o-Jhs;l!EZncgybK-oRQW9k=q zfcflfxNHRU8B?#}RZ2kngq{f?a*q4&f%UoIl2sIPTe!{1#w2lNK$IDNXlf#l{wO;%YDTG$pVcU7NQsP;be95{i* zD61SJi#F?9aLgOEeKj+unpx#a>pg?~ zz;W-=9?rCk6+Ew#-VE4zK%kP6QtXO_PA>c7;CcoRj^!?mS%GpPyXqjNF@YKofxXAd z4F`6JB>~0ZFWy+^qD>lo;x8{am~bxn_6L9UW61I9R$D!|U*nRH=26gs1QS0aj)-7U zWWJyecT57cWglP`u*E_%G!2f+Pp6?b22~L!Sof?-G{tYeGwRXNc!^tQ9`$=``%-2> zKcpoW(nO@R(`^b)Nb)iXjCo|CygkzJxr2fG#YfVn#_7`2qP-!9QHV`sCADJ2Lga+y zeW%(wyg=Q)l>6!P6CS!~uY>Z9*M<1tbrI_Nav@7`wclGy`}7UrOFjC^9WmVes_@sJ zG3q!5P$F`OJuL&eBU)>vbn9P}<7no1b3S9$^Jc=TV0s)&Bl-hYxBN>(P?&ddReEYD z5u>CpDvJe^j_`SfgyCwR@;iBLc#n{ZOPs8top80Lz7~Sy&J_?!{o>1^8^F3H0wEyI zh6xCGK8Y8tdW}1x;6PFHXwNMXM<9fR@NX_wJ!f(dmFSa*xwzJb`;t0z!W?xXQmrSu z_Tb*bsKVX%q~bBpA#wUlBQ23JSj^?O#9OyI1^f_YEoBzQ35%0^enWyp2YW~f)9B@6 zJW9MDdNnmI;qC;rl83yCs&S9FU#`7&==ipS_~5;o$4j94L)fx@sNiSA(crlTiy{1c z15A$dhvlJ^S$EM9TaE6dIVz|UMlG^NvokFzGUiFNE{8@TSwVS>4qD85$knjI*-Y~5 zW|KL1vB6i_R@vA{^B*0^k5}UTg#NjmaqpnMeDj|d&5DH>_y8$K#_s{&df<;x@41*r zQ_42=U9+{B;5b(o9YKG_ORizvsd2?Cfg8?Uc9$hTfI?c*D(u>Xat#eiCMtepPLP~O9}=gHCeU#VGn*EF@IBl ze3;Yd98zCAb=KKN5}<4Pf&PLLVfGaU>@h8>Nr_P|?7|?L88UDX0{uZtLvX?e@>8aE zmOUP*VMDG>YrOR*l8h=vWGD@xAWLTu=i|0rw>hhKIT-AeKLxp8E2Qe6p$xTPtl5@O z^yNne$H+4q*vwMJeq7qiGvHmjP!1X-&hh2lf@=8r2rAce`}MNKPUhV8GXfhMlo|YR ztJLydwPgcAXw0GrgVHC!yvLl~$!#PMpNlrmho3{_8t@i-6-^&3p!^DST&Snd>zYYA zsAg>38+l#goZ)P15&j~YQiYlxb1>!C%bJ`iSc2yw}{!USvFUj;(?UEC8&W;Gj%(NB^3_YUVTamng zfYx7=CoD;U1`DxGDhZ281lws5I6}<;Do|%0p}dC5P-Uq$sXy7U_0|dC@KP=ZJnq=3 z(>vRiBPoV~NBO4|*vrEkhSSxl@oZ#;)u0dDIAm zJvGe-CV@*u!C>%?x4udX?m_Ry4iSw9&6bm7LosLf!zPoAPD3C0hCZ)_zIpQKMPs~5&s-iC6t(y_+bibZuESvm9la{=_I_M1aF z`JzW%u_J8--_{ib{Ck2SH3v1yUyFN6F5P%dI2U_S(D|K5agjDzHzBJTmW4J4M+caF z_)MtPyN>+s)w8i{+@w?pz5F*PWnaFAAmLO$gw@$;oWG37aQN|I9N=|#tz6gENP~~4 z!Knj>D%tZU2cF!_)yqpKEo9mDmBokbl|1On?FY;_?n6y9ms#zTcLs%Ho~vsFY{dz! z1tSoK(h9pr>qMMqv4Glfu(8j&)tWSfR8pobH}Rl^Qs@u6WX;At^U+)FT>;_K7RH=f zEd=<9HPF>tY*XcKNPTx>=@SaCyk7By)Z23exhZs*^|T#)j(mQIh9cf&IRqx?#`M{k ziPT^yKZco7!#doey3h)Bz9oCMQJharm_=suOnV0E{NS-&xBukl!r56ZpsR!7w?H68 z6Npw4{(-^#q8M;&S@xsdY*E2iBRs^GQPT4P6*SyPz6c`=)9@Q4b6FrV>Qu$|DE2jZ z+PRU6rGnfyV{bSeV_N_IfEdOLdXGh8Ur0}XZ@Lp>Hre-#4*>3HIktP>TF-a-{*S$_ zZPWTaF>E?R_yGd>7GS6ER5F2HPJQP%;Q;|N{ zK*cgoNjZ&a-->$XX@k#3G^=bWMzGcw1erA^h?`EGDbQBUDau;*h_0*Um}i#t1`%2$ zB~0J?iHjj1cF74GFLvBmMh0V_U=m`4AfRyrDNi2~r_Wq=*c3rm*AqmXdS!oq)hM%v z$vh=iG$cpLR`+}d9VRmOgUoYsE&q=9L+H|H4OEyJ@OdQPiiESasAAI)x#@YaH$hGu zlCB+(NfeEO#Jel2EjNxrVp!fu8JWvw^gs~FEh z7!`Lz{Z} z=?X6$m>2vlaU2Lm9xmoqd7~w_BCi)jf{5N4jjflPE7em(`=lOTT%$rzBV}J64R#Q5 zBWU6ve8;=*R8>rq4AommLEq2uq#m3?Oy9V$5`QUap_w!`<+sfYS+US{Ma>19)(J;nJ zZp1?rv>b>}5|2Bel!!lb4PG5HY~M5Ok+$+hcxVgt6$V!B5aA!$Q;cfg*^$1!lYM;O z9!2d8^0x|ag=-QHe|oqc)h+P}NrwBsva+b{Rr`2YVy)uDk{ZD0xv3Vas|a zmxY}@68iY_7_`p-6t7K@-qa_LMoHeZr#I{MFqz*@!&S}pmwA!8Rtd}68nXikoR}IC zD%28aKuVSPzhS=46T-w&w-t|*p1kZCQgX&tfZE(~psk#fgY)5(i*mof$VB@Iz*S!?dUB!>pMcbIGdj4%%>UO5`z2Bm;Q&TIg!w+jp~ePldr z1Zk|?9<-R80#?JnoMu7sF&`*Wpi;fsdy26d!U$ zmxJEV4WMt4jEo!dmw)L(pv@f1r2%iwWx=eR`gW4d4=0G|J#KCw|I<=4S0u!sUvYB| zec3PSddlFj^IOs2(F(;t4!ir+w3p7hAWF!678US_wYiSD2RKn9Iq4ep{oBjguVODn z?oe+BpjX=$91d2g+qO|y`h;1~rD}NLOIMC4q_~sd#W1rai(`&2II<(R^QiAdrje1S zVc21nO&rn-*5{bhb^Vl^_xjN3O9iATZyw-|W7O~fvETo?6PomKb*|nkCpie9H-cX^Ihu(Np6~OvHn!pN#gppf zR$uG*e(ETsc~Oh>PCMWsTF*R@$Fx{-W0j;}1p1X#@J zzXJB3!VmdthHxNhyQL@W#Apa`BSd|eKWb|WYW0&wh+~oJ+9KzF)KkiH>*WbY0%w={ z5^2|nQghQFbft5~vd=qTsG5jYEDNoE(gb{_^zn;8iAZWdC2u9W2;A#*{QTq+$ol-O z3TzWYdt!~IT&a@0jo*5a(S6n&2E6JJJ#IlYu!rL8LJh4$$zs0N?Df`uO_ZH$`>q83 z#*J9djjd?7l(GaR*xN`5!ojZ>m6ILeifA;B{p$P%RNoWK&lfO#&P$gfq)@xxX~V#i zv|w!@J!e{8S$#4d$@eA7U_G<^?Sa3>Zt?!aj3`{GdzfuaAUn1+KcgI9Mi+PvAtbM) z15s-c7cLTHAo2Re{rj!Gi(U70q0&3wA- z31nl!tbjNsbhQ|+%pTiCFR?b$ecnreH6;guij>Io=rlSmA09P1f4G=5oiWVikdz+) zK8xcvp1CmAAMS!MWh?qM=I4DdWm!RtO8DJg)q33z)?}!ctJ@hq1Ad?&XU{*R6 z>$oZ%crPPivA&idQUOa1kWD8M?#0}1p-ZHLjmVQSXL80to;-`E*ved?c(JA!AnpU$ z8A6D78ivHc>|rKZKMjQlA@Z3ZD7b60x`xGs&O>IyT_T5UO|?4WGof#-kmydq0sg8v zQ8JbMVJR?PTXbP)>fn&W%zaHs!SIrREW1%fe?+%X{B%=pF$BU3;2xyY=u;f}RvRRdEME3^<(?P_e93dY-}-4x2pQhI=fYZ*kUsTqbFw~W zzn7|)(kEJ&e^cbN5IUcw{B9EhiNzEWHs|x|af_4`J$^3{ADhB6eyBQW-$Z#bGovgp zlD^hF46nA^!hz>ZL!pm_dL4>9?4dDeDUkw?4>oXhhT%?iK!VS|d#ptoo6mylGbpj2 zjcI#Rxzh*A0&|4?1O2YK5(#bc#VO}b31w*-*^Q5Rj>&NnpoEkGT zrr+WitnRxLx9+Ocl)1c@xF>7*08z`JN0sreBRvy5!0wd8D=L!*7btB5Yg1w?=rkiD zH&gPW!Lmhd-Qsz)LnT7i16in!Oj0beTqr0AaqtX3WraJm##A(siQIde-WK!=9DTVU z#Ci&()0GfZmLO;1Noh;D=c_#e?hduB8YmH%IY0j@z92L`+Kx2ug&1Ffn^<3B^nHI5 zxcz8+mt|Di>+HIHA4pl_DO|MuODM434vv)@DLgYmY0X z)U-|mM^`2)1DZ##!k0c0Clv+h(%nSmF!vTRED0i(CwdFs%qtY9n#Qy)Ds3*5HMB|v z-K)z5G(AfwH)J^5y~q=fK=OyAA}oLhei1r&w!NMk!Y}SPW9_5RhML*hx@%@k`|!La z$tG_FI2*8}giRF^G6-fRp${;!uO7G)zsU5CP_8)C*&0>+Hv5z+t&N|J1iKVaQ;~vv zUVly#z!Z8Gx16tCk23MAZGhA-$B`Ck+!UT<~>hNt1SD2^p1! zW@Ng7P0Xqq-`|0%cPG75H;TsX(^CK5T570Bm8@DWZmS zb3#QC>=*m8mbF%(Vv>8-tIDNguSS0ecVrk5+*3c((E2&2BN;E}jgV1WHIQ)y^UR&# zxGQ|bR?BV#l)O4n%0v{r5xx)q`68lJs5KbtRp z_&)}Kj$6{Bz$+VGh3K`$CnR2=fK*sN^#HE)01o7fqBy-O)7V}5b@_OWnF_f_n76ir z_oiqrc+ogXxxA{-T9n*gFapVa)$(2?Jt&}?_#52Mv`{?TmqAW+%uIcs_QQesfw1BrybPQ|M05?9d^a}(YX zs-=73D2mRieQd$Pg9s*&q2sc{mI?G6KeMhI z49^2!NWH*vKWr`=*qHaNr=zN0{*j9)pH=Z)6OG-hJPJ6w8+v@jP<|XZ;rp{1Rkk1tz^mfhzJj0GU#O`*442 zVd(%z=IBgP9xUc4&StYM=ueK&k9gD8W4qiqH=%pA2A1tMk}Cf5(aDQbtDj#Wl2e1D zjGo=x;5dL0T3TY|dxP4>8dv36hi(8<$ECg0!Yg&|f# zjG0@%`KoT|g9h<@O+ny8jAfZpd~F%Qjej4i#`m4<>OOf~pm3v>7-`C2salNd#!6s2 z$WvXJ?*YFN%%0vk#pRNIU-s^yYe#_HmT%ma_Mj%rI}9ye10-ieHjsR8`(4Z{!Cki_ z_a&A6q3gE2cejaFHH)_l)2e49(^ zP{--T^vRgr=*A*df~UB0l@XpwzL!ZPyr)$XtCga-4!vKp?z{Oi#e=)zm+vmowLG&( zYG>SQ1;_}GQTCqLgl6ZaInBWb3AZvUYIiPXxrH;J>WLyfz2VU89{bBx6F36PvcZo_ zV)5z`1E62@rk{o4=fO?n_!8h z-0vn{!_GjUZGRZ8ndm1Lv3=vBQ;*6tOx?U~^wF>lU)1?&`;m`b>F8m!zZSW@OS$N1jJ@AqF)waW;e42z($ z%vAK%BQ0HOm}$~~NfprH6QCUoe2bg^`jgyaJh!(U6nXccX8pNw>*qZxIP^HpI&qJz#q!rnvCr)iRG&20 zQxBlG00ki>-D||_eA_Uq!SsbzZ60u_IG*GAqY}RsWt=HdU$p7F2#b)saTxx&AGA)e+*-0>c{AX& z;){VPw_cch%q*WD@MD*#9>`ZDmvzT{rKakrwzrwx!SuVLY)YuqY}dEin3<2PJw9n< z&_zPLi=jE)=&ti^y%@@a8OikkDRif)X515z#Gv=4@g(3=elK$>Y@=&IUEx!nt;F#~ zd_deUJ)t0f&~Q@TtYP5WUAgb>=B!h%l#k#tlFAdlvyS6rQD2DzN&b)e( z>p&vMIJX70iBOU87W^79Xls#J6nee`(acNh!V+V?wOmJ%kTSo#a5};8&CAE*VF~MX z*g%Ocu`Lwq7f(&mw;k$4)3vrmbTXF_8_tFjW-sW>)`Q5S^R}G)8q&BVAg3S3mOAKF zJ{3XJCg-cViZs}Xd~1zVDpUPX7KM^KvF^qQ*%SS3NpYXYmOgJYv!^y|;RrHvHl)G% zF{4Y`*7?O7r|k~QDorDRiZ+AIYcEVsIi5}Hqsd+GBhGu!(wL+=-;4J_GH@rTE$ZL@ zE0nc0>lYO?2I3x3QLX;`CM#Q+Dp}L!=dVz>VZj@d*yuF7-`wm725dN$bDc`jYoH1H z7-Q9eL2qGt09Vdpu=Suf8v~wBS?&7R&UPIcJ&)tNxmy^Kc!ikU#fUOjvI?B|uye@+ zdS-gBcx!Uc1~sS3u0n}$<&^b7wCv)rh|=+DC$iJDfs9!NABQczgu!rFWLwMMGmg{E za&=Ojg&=o$Y4+8Nq-tQ+9S~Tv=s}C`2l<(`AxmAc&;Cuo`=}~NmYUlte;L*l8LY5Y zK2E2l1meg`P;$lpV}~t&kg`T~KxQ^R76FMy;7xupnM;$7jT66|^Bid_Hz{*|(*skn zJ!})4%G%COrvg-AeMfrmx?FJon$YTd;(+CLTFnoJZ??-9%Qpc{{bN<;rHq>c3##X% z3CfS0D$`ao4s?Zj4M%Cw;>l&=2VrtfY(@ad zD{8-gEa5%6Xh>7EWM%W5a>9(7PdJ?Ti3=RE5guT79`g0go)&e{>ZnnJ%?WSrL3?*J zH+l!nSl(yb&KDn96E+UzcmSnQ6LCT`2;gAq?#z3V5~xdUV&YlQuD8@zuSK39GkCm| z!C62u78lI{*BrkgdZJy?X04TUwBY93_gffgXxNqQbjsyfz^<82F%3;5IQ(j(a|^?Z z!m9&mmNEdPHo-csKy8cg01wfymSH`1nONp2#daTJ$8YXKDui&AO(0N08tz;_w|A?; zg)mH~YmyB`dl^v(jm95BlT!`~wlx;;&|$xduJkMimUEV5eKWDU8h1QsTc#RNPtD^q zrw*LvuB90teYiSVGy3Q^W^-hWzb>cHIlSl5dMbo3<+5brERQW(He^8EPxQ-S7rRp{ zQ-M0()Y=w3c1Yh4ba8$V!n zue2~W=w*s%Gst#fxWK(eh-^Bu!l(IBB>1Eb4-lG-3cZ5Th}~=MP#_sj_**9L;`mlv zK;;Ib4(_85F9YwBmiD>2RMpL7Suo=Um_eKSMKp<()@8HOU!yNFcb9u`KUaVq(~5`Aqq|{U zcZvm8ypbQPUUO}Pc;ElfJw~o&W$y3I7nr3drLaRolC_M=pU4gGN1=eTvR7+G{|U&I zDh9JM5Hrq7d@8%;Qt*R5e^Ffp6>7Njj%>f%<}s>9`?bYy@nLznmXRGAU_Vo5FCG9j zQrj@n2go*}e?t}~n5Pk@ey3ZVb z(|$X3yjG}U)rHT#OmB* zL=a0Vxp_X=jFC5w*>d@Kk=Z_bW1irrw-eO_t?h>VBU_SgtE3~SUIyi_DGzGPN0y(x zoUw_UD6G#p(y<;eN2;TRiR^27jk&hB-NCQFB+xk7LN3N#FeaOyvz6BntO*!U6*%&aDHg<(3b+{eMUz|0D>G5B=*S0r3|uBezreK@Ak8UALd{i2 zg8CJNzzK-ZA+5Y{<_n|ca;l&Q_oLK?%Lfkl7MwtKU-W}OmnX6){5;$&@!P40IeCj) zNlrjW;IkHBsDsiZY-gsaIO(HTOBP#&{@m$u$dsbwja-`i8dA$B>cdJ0|4ZQ23df-B zi&r>rfJA%v@9Wlt((IBt`)Yo>hDwssC99JO%T%&`Jc4$_NabwFD?jKqmZFsv^CiL* zXS!EQ;H_xRvJK6yZqw#SUkbx<$dPEY>9&EOC)z5+=v}KTLJb715ow8>I27o@@l7Kl z+571@$T^(j2a3AU7J~c7&i9Vd2(f}OLy}1i@{y~^L9MDtA*Zn>15HLX!*eT$Jjn@@ zNFH%2X$dp{LsVY{f+)Aud{Jbr;>ziuBr5YB0j;ErOADlUpnVdxtlZ&x;=+Eg)uoG) zfBl(~?+of#%K4tf_(9R{%=__e7s(8N@mjA;`o!Rt-AH(FL_2 zK72#Y{}~_eCg;^U)NKl=ZfxLR8^IkS{SaUcQC)Bm)6JkbH5MmRDN6@!_3>Y zl%O_MG`+}z3Tdl^uafIZNNst&j0~|1dLf%r+RuU7rhZ(@AoQ&?8R|aMr2~*PZl#Mq zCm;1w19{Xh)@HDs!<@}kH}JwZAE$FR;o9b1?O#%GT0~ry{h`?R_Ya3~^ai^8ei~H; zX=%o4WUXJn%Z%SjC*9=9BtKI1J__w*YcMbRj#Q5{U8Rbbnuy5t z7{RnFu8|=|5bI;M?yT@U$aQ@~vh!~?6JXU#tvBAe&j(r8?ce-99M=>Bv1US$Wz9_- zreZ=EyimWYqL%En6NL<6ZHgf6reZ5_#XWD=gkLM3lx~j~XeVl_f$y*7BMfQTZT3VG z11xvX_=G6MHZ%fMbd9P^GELJ@3TL6aO83|-glh^dQ<^wOUJwz9tVLzhG*66z@E|}O zy5T65HJ)edJzv)J`}HU4mXGl@%!0Y5<$LfSg`|tD`rA1n^wC_@69Ttj8oAushOVM^ z1cHHKQckIapievD$^$LxOY}ShJ!j_?)XMV*z`mF7RjIEwE%kHlRH6sLD5lnLQPr~S za%>k&lPSo|Tcrx@c*aQCW^aE?M&m>C9>InB)dla^RKd+^VyYoUl*n%}eskKOBz`<% z?)1##%~qdFql6BA`8WarPT2ejRw>;$(JB;nW-mdtHT)(Z**!Hz@B0zl#@s><;#+LsUR(qz+d*cZ>SG^HBXjEH*??3}GL`4O+y`L+L zwwfeTNF+H%aPNXoK8(1JnPM@fd`*iM+VQNAPU$i(_>O<0*P@@K+AK10Z;s~4kf5b^ zI|$mSIcC8)tN8k7Q`yroo9TeBw1~smn7m?QP<&yU?b=5U7sa6B@pD2T#u`hIjYY`y zC&+icF}9=gC>4z6>Vrc;1sOdR~ed1SF!P?Q2u*j|yna{wjnii4DZGAH#F0 zrK*>d1-wJc5-)mkn`BetFg8nJ;O|k~5A@3`^}#94px#O(U(B0qULkysAWy0Y%tNmC zL9gxV_gK?5Tdk|@8&7N4ca2s)l%0KjVQb~A=s2biDrEh*&_xE`oIVO?`~?(mK8`bL zv~0GYu|i!S)bSBWx1sg+Iyfh8Gt+nd@;f3%uALMmS2C7cVm|&d)k!_b^yG@zTg@AcS+u zk&qFvG8+(Wed$PC3zO&Yk(azkIwENu zh6K4;N!=@UN#a?yP)`gF_B?(j_WSRyA*9z>YaCi+(Iv1sWVLGvT6DMF+c6hhHBZ^b zO&a&{td*)8hon+4umbV-#JuHHr!n}F`D5OA_>Y5f<|6%CMO`jX88i1>x;~{~sWYc@ z9MF~qLn;=7k|OaTEh>{-!Y8lL(--3;0^@ZFK1L)G$QynTu(zG%r``Qb!<_+li$WQ_ zeo@4{J>2_+lLeIHi9Z|H%h?~{!H+A=OmdfS*v}dZ>!N7C@l{(w)!17$S{%06S+ZR}pkcHrfWsb22-uzxBbh z{qiuFp*^QzaWjv#Trbk9PGLORxmj=QW(X^_I!iF%d6v5zDs^%}V+`VlU|M~ywRz+- zA;Dtz-%DJ?8{LAB0oM3=iG3%ZM9Mx4VIoY~OA|Fh!2ooxc-_HPfw2IuNXPQ}>Qbcn z!x;ewnT*5>O}l)|?_cR20O(^oll^_#|EGZe-V?L1Hu<-!^S@)@{wK!5#=z_^p^$&d z1vdD(fB7B4^n0WFd#I6xqobV@9V0ypJtLhv2b&%n3!SlrlNG&%jTzZ!0~CM|7Hn>l zijPCGFB~XHv@rh_!Ek7lH4UUYf`~Y|qEn%S*}KpDnjmTLyIkkLyYYwd^f&5%3c~L_ zWjQ5bK{^=|X9HscXM?}FRGApjD@%R{&Hdi6{yX^3W9e;vA1f0h2pztOjj}s-QrC1EpuEvNg^?@!>5HtZ4j2(E?0$4y1l~RzEq)Knp18W)tf?*JZB)E z%Y8IZ@B5D@yl_1l^3$6Jn~T*kP>h{&K4VJS3Wlcd)x8yVVB>a%`yh+QTCcwcQbllmc37XnJ#$fl(iKd*MoK_L!rGbF? z0sl9*?r$URp9S%s^w-*K_%G=WtV{dt^U6`eE+5X zht6-)%zrq8|G$3Uzv2acBAa*^F9D(5N!;_9ECG?U{iFSN{D0bW{)#{QZ9D#J=l+iW zn_1_t@Y{_i<3HeZWKw^^M_T{U{ww^ymqveupELg_{BH}Tzrsk;B1ZrCpfM2={;YpU z{iFR?*ncPIzrt48{}c9~srs+1G=IFoDWfGI9rHf*KGP*22hD%9|IPaE2@VeU7weB9 zv%&eVl<-$w07rqBJjW6ck1VfU!f#zE>92nqEdQ+w_aC|du7BzNGmZRj^2rl?f6Ci9 z{9XQkOE&*{+kcEjn!n5czf#ZthW^)3h)nxC8t|vl{Ws%(3c`Q%tmrrTZ`tRsfQvlD zKL`2|o#3B+o8A38;2-nsKXcSy`!@UEfPZJKzoKYdp#DVtt1mEe|7goggZ+`|0noo6 NUqAtXYVJQ;{|5uz2IBw# literal 0 HcmV?d00001 diff --git a/tacker/tests/etc/samples/csar_with_multiple_sw_image_data.zip b/tacker/tests/etc/samples/csar_with_multiple_sw_image_data.zip new file mode 100644 index 0000000000000000000000000000000000000000..63e76fb763795607605e277d44eb4d03fd295f92 GIT binary patch literal 17056 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 VKdvnRnBSiwPypcYw?hEn{{ZG&J1qbJ literal 0 HcmV?d00001 diff --git a/tacker/tests/etc/samples/csar_without_flavour_info.zip b/tacker/tests/etc/samples/csar_without_flavour_info.zip new file mode 100644 index 0000000000000000000000000000000000000000..f9dbbc162b563e229343da3414ced1d3cc5a1b27 GIT binary patch literal 16624 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 literal 0 HcmV?d00001 diff --git a/tacker/tests/etc/samples/csar_without_flavour_info_in_main_template.zip b/tacker/tests/etc/samples/csar_without_flavour_info_in_main_template.zip new file mode 100644 index 0000000000000000000000000000000000000000..32a5aa9663bf927c8a888519b19eacfb0032b005 GIT binary patch literal 16208 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 DUV_e- literal 0 HcmV?d00001 diff --git a/tacker/tests/etc/samples/csar_without_instantiation_level.zip b/tacker/tests/etc/samples/csar_without_instantiation_level.zip new file mode 100644 index 0000000000000000000000000000000000000000..c7e43ba656a31bb2f09854e5804d0e01730499fc GIT binary patch literal 16716 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%0Dp>_>t%OybaKp5;DB`%!RiqBYhg&=45@$ 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 literal 0 HcmV?d00001 diff --git a/tacker/tests/etc/samples/csar_without_vnfd_info.zip b/tacker/tests/etc/samples/csar_without_vnfd_info.zip new file mode 100644 index 0000000000000000000000000000000000000000..085092f5c278850586b5ff0442e90b9b6eff6fee GIT binary patch literal 17136 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 Ju<`!U`#-N_NB{r; literal 0 HcmV?d00001 diff --git a/tacker/tests/etc/samples/sample_vnf_package_csar.zip b/tacker/tests/etc/samples/sample_vnf_package_csar.zip new file mode 100644 index 0000000000000000000000000000000000000000..c6233e5186d8e4cbd7ad974f530a2fd6dc65d82b GIT binary patch literal 17664 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 literal 0 HcmV?d00001 diff --git a/tacker/tests/etc/samples/test_data.zip b/tacker/tests/etc/samples/test_data.zip new file mode 100644 index 000000000..e69de29bb diff --git a/tacker/tests/functional/base.py b/tacker/tests/functional/base.py index 8678f16cc..3b53fa14d 100644 --- a/tacker/tests/functional/base.py +++ b/tacker/tests/functional/base.py @@ -19,9 +19,11 @@ from blazarclient import client as blazar_client from glanceclient.v2 import client as glance_client from keystoneauth1.identity import v3 from keystoneauth1 import session +from keystoneclient import adapter from neutronclient.v2_0 import client as neutron_client from novaclient import client as nova_client from oslo_config import cfg +from oslo_serialization import jsonutils from tempest.lib import base from tacker.plugins.common import constants as evt_constants @@ -36,6 +38,40 @@ from tackerclient.v1_0 import client as tacker_client CONF = cfg.CONF +class SessionClient(adapter.Adapter): + def request(self, *args, **kwargs): + kwargs.setdefault('authenticated', False) + kwargs.setdefault('raise_exc', False) + + content_type = kwargs.pop('content_type', None) or 'application/json' + + headers = kwargs.setdefault('headers', {}) + headers.setdefault('Accept', content_type) + + try: + kwargs.setdefault('data', kwargs.pop('body')) + except KeyError: + pass + + if kwargs.get('data'): + headers.setdefault('Content-Type', content_type) + + return super(SessionClient, self).request(*args, **kwargs) + + def _decode_json(self, response): + body = response.text + if body: + return jsonutils.loads(body) + else: + return "" + + def do_request(self, url, method, **kwargs): + kwargs.setdefault('authenticated', True) + resp = self.request(url, method, **kwargs) + body = self._decode_json(resp) + return resp, body + + class BaseTackerTest(base.BaseTestCase): """Base test case class for all Tacker API tests.""" @@ -50,6 +86,7 @@ class BaseTackerTest(base.BaseTestCase): **kwargs) cls.client = cls.tackerclient() + cls.http_client = cls.tacker_http_client() cls.h_client = cls.heatclient() @classmethod @@ -59,9 +96,10 @@ class BaseTackerTest(base.BaseTestCase): return vim_params @classmethod - def tackerclient(cls): + def get_auth_session(cls): vim_params = cls.get_credentials() - auth = v3.Password(auth_url=vim_params['auth_url'], + auth = v3.Password( + auth_url=vim_params['auth_url'], username=vim_params['username'], password=vim_params['password'], project_name=vim_params['project_name'], @@ -69,7 +107,19 @@ class BaseTackerTest(base.BaseTestCase): project_domain_name=vim_params['project_domain_name']) verify = 'True' == vim_params.pop('cert_verify', 'False') auth_ses = session.Session(auth=auth, verify=verify) - return tacker_client.Client(session=auth_ses) + return auth_ses + + @classmethod + def tacker_http_client(cls): + auth_session = cls.get_auth_session() + return SessionClient(session=auth_session, + service_type='nfv-orchestration', + region_name='RegionOne') + + @classmethod + def tackerclient(cls): + auth_session = cls.get_auth_session() + return tacker_client.Client(session=auth_session) @classmethod def novaclient(cls): diff --git a/tacker/tests/functional/vnfpkgm/__init__.py b/tacker/tests/functional/vnfpkgm/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tacker/tests/functional/vnfpkgm/test_vnf_package.py b/tacker/tests/functional/vnfpkgm/test_vnf_package.py new file mode 100644 index 000000000..d1a0bf51f --- /dev/null +++ b/tacker/tests/functional/vnfpkgm/test_vnf_package.py @@ -0,0 +1,134 @@ +# Copyright (C) 2019 NTT DATA +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, 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. + +import os +import time + +from oslo_serialization import jsonutils + +from tacker.tests.functional import base + + +class VnfPackageTest(base.BaseTackerTest): + + VNF_PACKAGE_DELETE_TIMEOUT = 120 + VNF_PACKAGE_UPLOAD_TIMEOUT = 300 + + def setUp(self): + super(VnfPackageTest, self).setUp() + self.base_url = "/vnfpkgm/v1/vnf_packages" + + def _wait_for_delete(self, package_uuid): + show_url = self.base_url + "/" + package_uuid + timeout = self.VNF_PACKAGE_DELETE_TIMEOUT + start_time = int(time.time()) + while True: + resp, body = self.http_client.do_request(show_url, "GET") + if (404 == resp.status_code): + break + if (int(time.time()) - start_time) > timeout: + raise Exception("Failed to delete package") + time.sleep(1) + + def _wait_for_onboard(self, package_uuid): + show_url = self.base_url + "/" + package_uuid + timeout = self.VNF_PACKAGE_UPLOAD_TIMEOUT + start_time = int(time.time()) + while True: + resp, body = self.http_client.do_request(show_url, "GET") + if body['onboardingState'] == "ONBOARDED": + break + + if ((int(time.time()) - start_time) > timeout): + raise Exception("Failed to onboard vnf package") + + time.sleep(1) + + def _create_vnf_package(self, body): + resp, response_body = self.http_client.do_request(self.base_url, + "POST", body=body) + self.assertIsNotNone(response_body['id']) + self.assertEqual(201, resp.status_code) + return response_body + + def _delete_vnf_package(self, package_uuid): + url = self.base_url + "/" + package_uuid + resp, body = self.http_client.do_request(url, "DELETE") + self.assertEqual(204, resp.status_code) + + def test_create_show_delete_vnf_package(self): + """Creates and deletes a vnf package.""" + + # Create vnf package + body = jsonutils.dumps({"userDefinedData": {"foo": "bar"}}) + vnf_package = self._create_vnf_package(body) + package_uuid = vnf_package['id'] + + # show vnf package + show_url = self.base_url + "/" + package_uuid + resp, body = self.http_client.do_request(show_url, "GET") + self.assertEqual(200, resp.status_code) + + # Delete vnf package + self._delete_vnf_package(package_uuid) + self._wait_for_delete(package_uuid) + + # show vnf package should fail as it's deleted + resp, body = self.http_client.do_request(show_url, "GET") + self.assertEqual(404, resp.status_code) + + def test_list(self): + vnf_package_list = [] + body = jsonutils.dumps({"userDefinedData": {"foo": "bar"}}) + + # create two vnf packages + vnf_package = self._create_vnf_package(body) + self.addCleanup(self._delete_vnf_package, vnf_package['id']) + vnf_package_list.append(vnf_package['id']) + + vnf_package = self._create_vnf_package(body) + vnf_package_list.append(vnf_package['id']) + self.addCleanup(self._delete_vnf_package, vnf_package['id']) + + # list vnf package + resp, body = self.http_client.do_request(self.base_url, "GET") + self.assertEqual(200, resp.status_code) + + package_uuids = [obj['id'] for obj in body['vnf_packages']] + self.assertIn(vnf_package_list[0], package_uuids) + self.assertIn(vnf_package_list[1], package_uuids) + + def _get_csar_file_path(self, file_name): + file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), + '../../etc/samples/' + file_name)) + return file_path + + def test_upload_from_file_and_delete(self): + body = jsonutils.dumps({"userDefinedData": {"foo": "bar"}}) + vnf_package = self._create_vnf_package(body) + file_path = self._get_csar_file_path("sample_vnf_package_csar.zip") + with open(file_path, 'r') as file_object: + resp, resp_body = self.http_client.do_request( + '{base_path}/{id}/package_content'.format( + id=vnf_package['id'], + base_path=self.base_url), + "PUT", body=file_object, content_type='application/zip') + + self.assertEqual(202, resp.status_code) + + self._wait_for_onboard(vnf_package['id']) + + self._delete_vnf_package(vnf_package['id']) + self._wait_for_delete(vnf_package['id']) diff --git a/tacker/tests/unit/common/test_csar_utils.py b/tacker/tests/unit/common/test_csar_utils.py new file mode 100644 index 000000000..29ebb3ed6 --- /dev/null +++ b/tacker/tests/unit/common/test_csar_utils.py @@ -0,0 +1,164 @@ +# Copyright (c) 2019 NTT DATA. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, 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. + +import mock +import os +import shutil +import testtools + +from tacker.common import csar_utils +from tacker.common import exceptions +from tacker import context +from tacker.tests import constants + + +class TestCSARUtils(testtools.TestCase): + + def setUp(self): + super(TestCSARUtils, self).setUp() + self.context = context.get_admin_context() + self.base_path = os.path.dirname(os.path.abspath(__file__)) + + @mock.patch('tacker.common.csar_utils._extract_csar_zip_file') + def test_load_csar_data(self, mock_extract_csar_zip_file): + file_path = os.path.join( + self.base_path, "../../etc/samples/sample_vnf_package_csar.zip") + vnf_data, flavours = csar_utils.load_csar_data( + self.context, constants.UUID, file_path) + self.assertEqual(vnf_data['descriptor_version'], '1.0') + self.assertEqual(vnf_data['vnfm_info'], ['Tacker']) + self.assertEqual(flavours[0]['flavour_id'], 'simple') + self.assertIsNotNone(flavours[0]['sw_images']) + + @mock.patch('tacker.common.csar_utils._extract_csar_zip_file') + def test_load_csar_data_without_instantiation_level( + self, mock_extract_csar_zip_file): + file_path = os.path.join( + self.base_path, + "../../etc/samples/csar_without_instantiation_level.zip") + exc = self.assertRaises(exceptions.InvalidCSAR, + csar_utils.load_csar_data, + self.context, constants.UUID, file_path) + msg = ('Policy of type' + ' "tosca.policies.nfv.InstantiationLevels is not defined.') + self.assertEqual(msg, exc.format_message()) + + @mock.patch('tacker.common.csar_utils._extract_csar_zip_file') + def test_load_csar_data_with_invalid_instantiation_level( + self, mock_extract_csar_zip_file): + file_path = os.path.join( + self.base_path, + "../../etc/samples/csar_invalid_instantiation_level.zip") + exc = self.assertRaises(exceptions.InvalidCSAR, + csar_utils.load_csar_data, + self.context, constants.UUID, file_path) + levels = ['instantiation_level_1', 'instantiation_level_2'] + msg = ("Level(s) instantiation_level_3 not found in " + "defined levels %s") % ",".join(sorted(levels)) + self.assertEqual(msg, exc.format_message()) + + @mock.patch('tacker.common.csar_utils._extract_csar_zip_file') + def test_load_csar_data_with_invalid_default_instantiation_level( + self, mock_extract_csar_zip_file): + file_path = os.path.join( + self.base_path, + "../../etc/samples/csar_with_invalid_" + "default_instantiation_level.zip") + exc = self.assertRaises(exceptions.InvalidCSAR, + csar_utils.load_csar_data, + self.context, constants.UUID, file_path) + levels = ['instantiation_level_1', 'instantiation_level_2'] + msg = ("Level instantiation_level_3 not found in " + "defined levels %s") % ",".join(sorted(levels)) + self.assertEqual(msg, exc.format_message()) + + @mock.patch('tacker.common.csar_utils._extract_csar_zip_file') + def test_load_csar_data_without_vnfd_info( + self, mock_extract_csar_zip_file): + file_path = os.path.join( + self.base_path, + "../../etc/samples/csar_without_vnfd_info.zip") + exc = self.assertRaises(exceptions.InvalidCSAR, + csar_utils.load_csar_data, + self.context, constants.UUID, file_path) + self.assertEqual("VNF properties are mandatory", exc.format_message()) + + @mock.patch('tacker.common.csar_utils._extract_csar_zip_file') + def test_load_csar_data_with_artifacts_and_without_sw_image_data( + self, mock_extract_csar_zip_file): + file_path = os.path.join( + self.base_path, + "../../etc/samples/csar_without_sw_image_data.zip") + exc = self.assertRaises(exceptions.InvalidCSAR, + csar_utils.load_csar_data, + self.context, constants.UUID, file_path) + msg = ('Node property "sw_image_data" is missing for artifact' + ' type tosca.artifacts.nfv.SwImage for node VDU1.') + self.assertEqual(msg, exc.format_message()) + + @mock.patch('tacker.common.csar_utils._extract_csar_zip_file') + def test_load_csar_data_with_multiple_sw_image_data( + self, mock_extract_csar_zip_file): + file_path = os.path.join( + self.base_path, + "../../etc/samples/csar_with_multiple_sw_image_data.zip") + exc = self.assertRaises(exceptions.InvalidCSAR, + csar_utils.load_csar_data, + self.context, constants.UUID, file_path) + msg = ('artifacts of type "tosca.artifacts.nfv.SwImage"' + ' is added more than one time for node VDU1.') + self.assertEqual(msg, exc.format_message()) + + @mock.patch('tacker.common.csar_utils._extract_csar_zip_file') + def test_csar_with_missing_sw_image_data_in_main_template( + self, mock_extract_csar_zip_file): + file_path = os.path.join( + self.base_path, + "../../etc/samples/" + "csar_with_missing_sw_image_data_in_main_template.zip") + exc = self.assertRaises(exceptions.InvalidCSAR, + csar_utils.load_csar_data, + self.context, constants.UUID, file_path) + msg = ('Node property "sw_image_data" is missing for artifact' + ' type tosca.artifacts.nfv.SwImage for node VDU1.') + self.assertEqual(msg, exc.format_message()) + + @mock.patch('tacker.common.csar_utils._extract_csar_zip_file') + def test_load_csar_data_without_flavour_info( + self, mock_extract_csar_zip_file): + file_path = os.path.join( + self.base_path, "../../etc/samples/csar_without_flavour_info.zip") + exc = self.assertRaises(exceptions.InvalidCSAR, + csar_utils.load_csar_data, + self.context, constants.UUID, file_path) + self.assertEqual("No VNF flavours are available", exc.format_message()) + + @mock.patch('tacker.common.csar_utils._extract_csar_zip_file') + def test_load_csar_data_without_flavour_info_in_main_template( + self, mock_extract_csar_zip_file): + file_path = os.path.join( + self.base_path, "../../etc/samples/" + "csar_without_flavour_info_in_main_template.zip") + exc = self.assertRaises(exceptions.InvalidCSAR, + csar_utils.load_csar_data, + self.context, constants.UUID, file_path) + self.assertEqual("No VNF flavours are available", + exc.format_message()) + + @mock.patch.object(os, 'remove') + @mock.patch.object(shutil, 'rmtree') + def test_delete_csar_data(self, mock_rmtree, mock_remove): + csar_utils.delete_csar_data(constants.UUID) + mock_rmtree.assert_called() + mock_remove.assert_called() diff --git a/tacker/tests/unit/conductor/conductorrpc/__init__.py b/tacker/tests/unit/conductor/conductorrpc/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tacker/tests/unit/conductor/fakes.py b/tacker/tests/unit/conductor/fakes.py index d8ba326d2..dc29ab4db 100644 --- a/tacker/tests/unit/conductor/fakes.py +++ b/tacker/tests/unit/conductor/fakes.py @@ -40,3 +40,12 @@ VNF_DATA = { 'usage_state': 'NOT_IN_USE', 'user_data': {'abc': 'xyz'} } + +VNF_PACKAGE_DATA = {'algorithm': None, 'hash': None, + 'location_glance_store': None, + 'onboarding_state': 'CREATED', + 'operational_state': 'DISABLED', + 'tenant_id': uuidsentinel.tenant_id, + 'usage_state': 'NOT_IN_USE', + 'user_data': {'abc': 'xyz'} + } diff --git a/tacker/tests/unit/conductor/test_conductor_server.py b/tacker/tests/unit/conductor/test_conductor_server.py new file mode 100644 index 000000000..5d8357387 --- /dev/null +++ b/tacker/tests/unit/conductor/test_conductor_server.py @@ -0,0 +1,135 @@ +# Copyright (c) 2019 NTT DATA +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# 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. + +import mock +import os +import shutil +import sys + +from tacker.common import csar_utils +from tacker.conductor import conductor_server +from tacker import context +from tacker.glance_store import store as glance_store +from tacker import objects +from tacker.objects import vnf_package +from tacker.tests.unit.conductor import fakes +from tacker.tests.unit.db.base import SqlTestCase +from tacker.tests import uuidsentinel + + +class TestConductor(SqlTestCase): + + def setUp(self): + super(TestConductor, self).setUp() + self.context = context.get_admin_context() + self.conductor = conductor_server.Conductor('host') + self.vnf_package = self._create_vnf_package() + + def _create_vnf_package(self): + vnfpkgm = vnf_package.VnfPackage(context=self.context, + **fakes.VNF_PACKAGE_DATA) + vnfpkgm.create() + return vnfpkgm + + @mock.patch.object(conductor_server.Conductor, '_onboard_vnf_package') + @mock.patch.object(conductor_server, 'revert_upload_vnf_package') + @mock.patch.object(csar_utils, 'load_csar_data') + @mock.patch.object(glance_store, 'load_csar') + def test_upload_vnf_package_content(self, mock_load_csar, + mock_load_csar_data, + mock_revert, mock_onboard): + mock_load_csar_data.return_value = (mock.ANY, mock.ANY) + mock_load_csar.return_value = '/var/lib/tacker/5f5d99c6-844a-4c3' \ + '1-9e6d-ab21b87dcfff.zip' + self.conductor.upload_vnf_package_content( + self.context, self.vnf_package) + mock_load_csar.assert_called() + mock_load_csar_data.assert_called() + mock_onboard.assert_called() + + @mock.patch.object(conductor_server.Conductor, '_onboard_vnf_package') + @mock.patch.object(glance_store, 'store_csar') + @mock.patch.object(conductor_server, 'revert_upload_vnf_package') + @mock.patch.object(csar_utils, 'load_csar_data') + @mock.patch.object(glance_store, 'load_csar') + def test_upload_vnf_package_from_uri(self, mock_load_csar, + mock_load_csar_data, + mock_revert, mock_store, + mock_onboard): + address_information = "http://test.zip" + mock_load_csar_data.return_value = (mock.ANY, mock.ANY) + mock_load_csar.return_value = '/var/lib/tacker/5f5d99c6-844a' \ + '-4c31-9e6d-ab21b87dcfff.zip' + mock_store.return_value = 'location', 'size', 'checksum',\ + 'multihash', 'loc_meta' + self.conductor.upload_vnf_package_from_uri(self.context, + self.vnf_package, + address_information, + user_name=None, + password=None) + mock_load_csar.assert_called() + mock_load_csar_data.assert_called() + mock_store.assert_called() + mock_onboard.assert_called() + self.assertEqual('multihash', self.vnf_package.hash) + self.assertEqual('location', self.vnf_package.location_glance_store) + + @mock.patch.object(glance_store, 'delete_csar') + def test_delete_vnf_package(self, mock_delete_csar): + self.vnf_package.__setattr__('onboarding_state', 'ONBOARDED') + self.conductor.delete_vnf_package(self.context, self.vnf_package) + mock_delete_csar.assert_called() + + @mock.patch.object(os, 'remove') + @mock.patch.object(shutil, 'rmtree') + @mock.patch.object(os.path, 'exists') + @mock.patch.object(vnf_package.VnfPackagesList, 'get_by_filters') + def test_run_cleanup_vnf_packages(self, mock_get_by_filter, + mock_exists, mock_rmtree, + mock_remove): + vnf_package_data = {'algorithm': None, 'hash': None, + 'location_glance_store': None, + 'onboarding_state': 'CREATED', + 'operational_state': 'DISABLED', + 'tenant_id': uuidsentinel.tenant_id, + 'usage_state': 'NOT_IN_USE', + 'user_data': {'abc': 'xyz'} + } + + vnfpkgm = objects.VnfPackage(context=self.context, **vnf_package_data) + vnfpkgm.create() + vnfpkgm.destroy(self.context) + + mock_get_by_filter.return_value = [vnfpkgm] + mock_exists.return_value = True + conductor_server.Conductor('host')._run_cleanup_vnf_packages( + self.context) + mock_get_by_filter.assert_called() + mock_rmtree.assert_called() + mock_remove.assert_called() + + @mock.patch.object(sys, 'exit') + @mock.patch.object(conductor_server.LOG, 'error') + @mock.patch.object(glance_store, 'initialize_glance_store') + @mock.patch.object(os.path, 'isdir') + def test_init_host(self, mock_isdir, mock_initialize_glance_store, + mock_log_error, mock_exit): + mock_isdir.return_value = False + self.conductor.init_host() + mock_log_error.assert_called() + mock_exit.assert_called_with(1) + self.assertIn("Config option 'vnf_package_csar_path' is not configured" + " correctly. VNF package CSAR path directory %s doesn't" + " exist", mock_log_error.call_args[0][0]) diff --git a/tacker/tests/unit/db/test_vnf_package.py b/tacker/tests/unit/db/test_vnf_package.py new file mode 100644 index 000000000..fe2c5f66a --- /dev/null +++ b/tacker/tests/unit/db/test_vnf_package.py @@ -0,0 +1,94 @@ +# Copyright (C) 2019 NTT DATA +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, 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. + +from tacker.common import exceptions +from tacker import context +from tacker.db.db_sqlalchemy import models +from tacker import objects +from tacker.objects import vnf_package +from tacker.tests.unit.db.base import SqlTestCase +from tacker.tests.unit.objects import fakes as fake_data +from tacker.tests.unit.vnfpkgm import fakes + + +class TestVnfPackage(SqlTestCase): + + def setUp(self): + super(TestVnfPackage, self).setUp() + self.context = context.get_admin_context() + self.vnf_package = self._create_vnf_package() + self.vnf_deployment_flavour = self._create_vnf_deployment_flavour() + + def _create_vnf_package(self): + vnfpkgm = objects.VnfPackage(context=self.context, + **fake_data.vnf_package_data) + vnfpkgm.create() + return vnfpkgm + + def _create_vnf_deployment_flavour(self): + flavour_data = fake_data.vnf_deployment_flavour + flavour_data.update({'package_uuid': self.vnf_package.id}) + vnf_deployment_flavour = objects.VnfDeploymentFlavour( + context=self.context, **flavour_data) + vnf_deployment_flavour.create() + return vnf_deployment_flavour + + def test_add_user_defined_data(self): + vnf_package_db = models.VnfPackage() + vnf_package_db.update(fakes.fake_vnf_package()) + vnf_package_db.save(self.context.session) + result = vnf_package._add_user_defined_data( + self.context, vnf_package_db.id, vnf_package_db.user_data) + self.assertEqual(None, result) + + def test_vnf_package_get_by_id(self): + result = vnf_package._vnf_package_get_by_id( + self.context, self.vnf_package.id, + columns_to_join=['vnf_deployment_flavours']) + self.assertEqual(self.vnf_package.id, result.id) + self.assertTrue(result.vnf_deployment_flavours) + + def test_vnf_package_create(self): + result = vnf_package._vnf_package_create(self.context, + fakes.fake_vnf_package()) + self.assertTrue(result.id) + + def test_vnf_package_list(self): + result = vnf_package._vnf_package_list( + self.context, columns_to_join=['vnf_deployment_flavours']) + self.assertTrue(isinstance(result, list)) + self.assertTrue(result) + + def test_vnf_package_update(self): + update = {'user_data': {'test': 'xyz'}} + result = vnf_package._vnf_package_update( + self.context, self.vnf_package.id, update) + self.assertEqual({'test': 'xyz'}, result.user_data) + + def test_destroy_vnf_package(self): + vnf_package._destroy_vnf_package(self.context, + self.vnf_package.id) + self.assertRaises( + exceptions.VnfPackageNotFound, + objects.VnfPackage.get_by_id, self.context, + self.vnf_package.id) + + def test_make_vnf_packages_list(self): + response = vnf_package._vnf_package_list(self.context) + vnf_pack_list_obj = objects.VnfPackagesList(self.context) + result = vnf_package._make_vnf_packages_list( + self.context, vnf_pack_list_obj, response, None) + self.assertTrue(isinstance(result, objects.VnfPackagesList)) + self.assertTrue(result.objects[0].id) diff --git a/tacker/tests/unit/fake_request.py b/tacker/tests/unit/fake_request.py new file mode 100644 index 000000000..1d11596b3 --- /dev/null +++ b/tacker/tests/unit/fake_request.py @@ -0,0 +1,43 @@ +# Copyright (C) 2019 NTT DATA +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, 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. + + +import webob +import webob.request + +from tacker import context +from tacker.tests import uuidsentinel +from tacker import wsgi as os_wsgi + + +class FakeRequestContext(context.ContextBaseWithSession): + def __init__(self, *args, **kwargs): + kwargs['auth_token'] = kwargs.get( + uuidsentinel.user_id, uuidsentinel.project_id) + super(FakeRequestContext, self).__init__(*args, **kwargs) + + +class HTTPRequest(webob.Request): + + @classmethod + def blank(cls, *args, **kwargs): + kwargs['base_url'] = 'http://localhost/' + use_admin_context = kwargs.pop(context.get_admin_context(), True) + out = os_wsgi.Request.blank(*args, **kwargs) + out.environ['tacker.context'] = FakeRequestContext( + uuidsentinel.user_id, + uuidsentinel.project_id, + is_admin=use_admin_context) + return out diff --git a/tacker/tests/unit/vnfm/tosca/test_utils.py b/tacker/tests/unit/vnfm/tosca/test_utils.py index 92d15eea5..42eb1bdd1 100644 --- a/tacker/tests/unit/vnfm/tosca/test_utils.py +++ b/tacker/tests/unit/vnfm/tosca/test_utils.py @@ -35,12 +35,12 @@ class TestToscaUtils(testtools.TestCase): tosca_openwrt = _get_template('test_tosca_openwrt.yaml') vnfd_dict = yaml.safe_load(tosca_openwrt) toscautils.updateimports(vnfd_dict) - tosca = tosca_template.ToscaTemplate(parsed_params={}, a_file=False, - yaml_dict_tpl=vnfd_dict) - tosca_flavor = _get_template('test_tosca_flavor.yaml') def setUp(self): super(TestToscaUtils, self).setUp() + self.tosca = tosca_template.ToscaTemplate( + parsed_params={}, a_file=False, yaml_dict_tpl=self.vnfd_dict) + self.tosca_flavor = _get_template('test_tosca_flavor.yaml') def test_updateimport(self): importspath = os.path.abspath('./tacker/tosca/lib/') diff --git a/tacker/tests/unit/vnfpkgm/__init__.py b/tacker/tests/unit/vnfpkgm/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tacker/tests/unit/vnfpkgm/fakes.py b/tacker/tests/unit/vnfpkgm/fakes.py new file mode 100644 index 000000000..3d26da810 --- /dev/null +++ b/tacker/tests/unit/vnfpkgm/fakes.py @@ -0,0 +1,126 @@ +# Copyright (C) 2019 NTT DATA +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, 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. + + +import datetime +import iso8601 +import webob + +from tacker.api.vnfpkgm.v1.router import VnfpkgmAPIRouter +from tacker import context +from tacker.db.db_sqlalchemy import models +from tacker.objects import vnf_package as vnf_package_obj +from tacker.tests import constants +from tacker.tests import uuidsentinel +from tacker import wsgi + + +VNFPACKAGE_RESPONSE = {'_links': { + 'packageContent': { + 'href': + '/vnfpkgm/v1/vnf_packages/' + 'f26f181d-7891-4720-b022-b074ec1733ef/package_content'}, + 'self': { + 'href': + '/vnfpkgm/v1/vnf_packages/' + 'f26f181d-7891-4720-b022-b074ec1733ef'}, +}, + 'id': 'f26f181d-7891-4720-b022-b074ec1733ef', + 'onboardingState': 'CREATED', + 'operationalState': 'DISABLED', + 'usageState': 'NOT_IN_USE', + 'userDefinedData': {'abc': 'xyz'} +} + +VNFPACKAGE_INDEX_RESPONSE = {'vnf_packages': [{'_links': { + 'packageContent': { + 'href': + '/vnfpkgm/v1/vnf_packages/' + 'f26f181d-7891-4720-b022-b074ec1733ef/package_content'}, + 'self': { + 'href': '/vnfpkgm/v1/vnf_packages/' + 'f26f181d-7891-4720-b022-b074ec1733ef'}}, + 'id': 'f26f181d-7891-4720-b022-b074ec1733ef', + 'onboardingState': 'CREATED', + 'operationalState': 'DISABLED', + 'usageState': 'NOT_IN_USE', + 'userDefinedData': {}}] +} + + +def fake_vnf_package(**updates): + vnf_package = { + 'algorithm': None, + 'deleted': False, + 'deleted_at': None, + 'updated_at': None, + 'created_at': datetime.datetime(1900, 1, 1, 1, 1, 1, + tzinfo=iso8601.UTC), + 'hash': None, + 'location_glance_store': None, + 'onboarding_state': 'CREATED', + 'operational_state': 'DISABLED', + 'tenant_id': uuidsentinel.tenant_id, + 'usage_state': 'NOT_IN_USE', + 'user_data': {'abc': 'xyz'}, + 'id': constants.UUID, + } + + if updates: + vnf_package.update(updates) + + return vnf_package + + +class InjectContext(wsgi.Middleware): + """Add a 'tacker.context' to WSGI environ.""" + + def __init__(self, context, *args, **kwargs): + self.context = context + super(InjectContext, self).__init__(*args, **kwargs) + + @webob.dec.wsgify(RequestClass=wsgi.Request) + def __call__(self, req): + req.environ['tacker.context'] = self.context + return self.application + + +def return_vnf_package(): + model_obj = models.VnfPackage() + model_obj.update(fake_vnf_package()) + return model_obj + + +def return_vnfpkg_obj(): + vnf_package = vnf_package_obj.VnfPackage._from_db_object( + context, vnf_package_obj.VnfPackage(), + return_vnf_package(), expected_attrs=None) + return vnf_package + + +def return_vnf_package_list(): + vnf_package = return_vnfpkg_obj() + return [vnf_package] + + +def wsgi_app_v1(fake_auth_context=None): + inner_app_v1 = VnfpkgmAPIRouter() + if fake_auth_context is not None: + ctxt = fake_auth_context + else: + ctxt = context.ContextBase(uuidsentinel.user_id, + uuidsentinel.project_id, is_admin=True) + api_v1 = InjectContext(ctxt, inner_app_v1) + return api_v1 diff --git a/tacker/tests/unit/vnfpkgm/test_controller.py b/tacker/tests/unit/vnfpkgm/test_controller.py new file mode 100644 index 000000000..7b2a7e33b --- /dev/null +++ b/tacker/tests/unit/vnfpkgm/test_controller.py @@ -0,0 +1,258 @@ +# Copyright (C) 2019 NTT DATA +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, 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. + +import mock +from oslo_serialization import jsonutils +from six.moves import http_client +from six.moves import urllib +from webob import exc + +from tacker.api.vnfpkgm.v1 import controller +from tacker.conductor.conductorrpc.vnf_pkgm_rpc import VNFPackageRPCAPI +from tacker.glance_store import store as glance_store +from tacker.objects import vnf_package +from tacker.objects.vnf_package import VnfPackagesList +from tacker.tests import constants +from tacker.tests.unit import base +from tacker.tests.unit import fake_request +from tacker.tests.unit.vnfpkgm import fakes + + +class TestController(base.TestCase): + + def setUp(self): + super(TestController, self).setUp() + self.controller = controller.VnfPkgmController() + + @property + def app(self): + return fakes.wsgi_app_v1() + + @mock.patch.object(vnf_package, '_vnf_package_create') + @mock.patch.object(vnf_package.VnfPackage, '_from_db_object') + def test_create_with_status_202(self, mock_from_db, mock_vnf_pack): + body = {'userDefinedData': {'abc': 'xyz'}} + req = fake_request.HTTPRequest.blank('/vnf_packages') + req.body = jsonutils.dump_as_bytes(body) + req.headers['Content-Type'] = 'application/json' + req.method = 'POST' + resp = req.get_response(self.app) + self.assertEqual(http_client.CREATED, resp.status_code) + + @mock.patch.object(vnf_package, '_vnf_package_create') + @mock.patch.object(vnf_package.VnfPackage, '_from_db_object') + def test_create_without_userdefine_data(self, mock_from_db, + mock_vnf_pack): + body = {'userDefinedData': {}} + req = fake_request.HTTPRequest.blank('/vnf_packages') + req.body = jsonutils.dump_as_bytes(body) + req.headers['Content-Type'] = 'application/json' + req.method = 'POST' + resp = req.get_response(self.app) + self.assertEqual(http_client.CREATED, resp.status_code) + + @mock.patch.object(vnf_package.VnfPackage, "get_by_id") + def test_show(self, mock_vnf_by_id): + req = fake_request.HTTPRequest.blank( + '/vnfpkgm/v1/vnf_packages/%s' % constants.UUID) + mock_vnf_by_id.return_value = fakes.return_vnf_package() + expected_result = fakes.VNFPACKAGE_RESPONSE + res_dict = self.controller.show(req, constants.UUID) + self.assertEqual(expected_result, res_dict) + + def test_show_with_invalid_uuid(self): + req = fake_request.HTTPRequest.blank( + '/vnfpkgm/v1/vnf_packages/%s' % constants.INVALID_UUID) + self.assertRaises(exc.HTTPNotFound, self.controller.show, + req, constants.INVALID_UUID) + + @mock.patch.object(vnf_package.VnfPackage, "get_by_id") + def test_show_no_vnf_package(self, mock_vnf_by_id): + req = fake_request.HTTPRequest.blank( + '/vnfpkgm/v1/vnf_packages/%s' % constants.UUID) + msg = _("Can not find requested vnf package: %s") % constants.UUID + mock_vnf_by_id.side_effect = exc.HTTPNotFound(explanation=msg) + self.assertRaises(exc.HTTPNotFound, self.controller.show, + req, constants.UUID) + + @mock.patch.object(VnfPackagesList, "get_all") + def test_index(self, mock_vnf_list): + req = fake_request.HTTPRequest.blank('/vnfpkgm/v1/vnf_packages/') + mock_vnf_list.return_value = fakes.return_vnf_package_list() + res_dict = self.controller.index(req) + expected_result = fakes.VNFPACKAGE_INDEX_RESPONSE + self.assertEqual(expected_result, res_dict) + + @mock.patch.object(vnf_package.VnfPackage, "get_by_id") + @mock.patch.object(VNFPackageRPCAPI, "delete_vnf_package") + def test_delete_with_204_status(self, mock_delete_rpc, mock_vnf_by_id): + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj() + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s' % constants.UUID) + req.headers['Content-Type'] = 'application/json' + req.method = 'DELETE' + resp = req.get_response(self.app) + self.assertEqual(http_client.NO_CONTENT, resp.status_code) + + @mock.patch.object(vnf_package.VnfPackage, "get_by_id") + def test_delete_no_vnf_package(self, mock_vnf_by_id): + req = fake_request.HTTPRequest.blank( + '/vnfpkgm/v1/vnf_packages/%s' % constants.UUID) + msg = _("Can not find requested vnf package: %s") % constants.UUID + mock_vnf_by_id.side_effect = exc.HTTPNotFound(explanation=msg) + self.assertRaises(exc.HTTPNotFound, self.controller.delete, + req, constants.UUID) + + def test_delete_with_invalid_uuid(self): + req = fake_request.HTTPRequest.blank( + '/vnfpkgm/v1/vnf_packages/%s' % constants.INVALID_UUID) + self.assertRaises(exc.HTTPNotFound, self.controller.delete, + req, constants.INVALID_UUID) + + @mock.patch.object(glance_store, 'store_csar') + @mock.patch.object(VNFPackageRPCAPI, "upload_vnf_package_content") + @mock.patch.object(vnf_package.VnfPackage, "get_by_id") + @mock.patch.object(vnf_package.VnfPackage, "save") + def test_upload_vnf_package_content(self, mock_vnf_pack_save, + mock_vnf_by_id, + mock_upload_vnf_package_content, + mock_glance_store): + file_path = "tacker/tests/etc/samples/test_data.zip" + file_obj = open(file_path, "rb") + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj() + mock_vnf_pack_save.return_value = fakes.return_vnfpkg_obj() + mock_glance_store.return_value = 'location', 'size', 'checksum',\ + 'multihash', 'loc_meta' + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s/package_content' + % constants.UUID) + req.headers['Content-Type'] = 'application/zip' + req.method = 'PUT' + req.body = jsonutils.dump_as_bytes(file_obj) + resp = req.get_response(self.app) + mock_glance_store.assert_called() + self.assertEqual(http_client.ACCEPTED, resp.status_code) + + def test_upload_vnf_package_content_with_invalid_uuid(self): + file_path = "tacker/tests/etc/samples/test_data.zip" + file_obj = open(file_path, "rb") + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s/package_content' + % constants.INVALID_UUID) + exception = self.assertRaises(exc.HTTPNotFound, + self.controller.upload_vnf_package_content, + req, constants.INVALID_UUID, body=file_obj) + self.assertEqual( + "Can not find requested vnf package: %s" % constants.INVALID_UUID, + exception.explanation) + + @mock.patch.object(vnf_package.VnfPackage, "get_by_id") + def test_upload_vnf_package_content_without_vnf_pack(self, + mock_vnf_by_id): + file_path = "tacker/tests/etc/samples/test_data.zip" + file_obj = open(file_path, "rb") + msg = _("Can not find requested vnf package: %s") % constants.UUID + mock_vnf_by_id.side_effect = exc.HTTPNotFound(explanation=msg) + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s/package_content' % constants.UUID) + exception = self.assertRaises( + exc.HTTPNotFound, self.controller.upload_vnf_package_content, + req, constants.UUID, body=file_obj) + self.assertEqual( + "Can not find requested vnf package: %s" % constants.UUID, + exception.explanation) + + @mock.patch.object(vnf_package.VnfPackage, "get_by_id") + def test_upload_vnf_package_content_with_invalid_status(self, + mock_vnf_by_id): + file_path = "tacker/tests/etc/samples/test_data.zip" + file_obj = open(file_path, "rb") + vnf_obj = fakes.return_vnfpkg_obj() + vnf_obj.__setattr__('onboarding_state', 'test') + mock_vnf_by_id.return_value = vnf_obj + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s/package_content' % constants.UUID) + self.assertRaises(exc.HTTPConflict, + self.controller.upload_vnf_package_content, + req, constants.UUID, body=file_obj) + + @mock.patch.object(urllib.request, 'urlopen') + @mock.patch.object(VNFPackageRPCAPI, "upload_vnf_package_from_uri") + @mock.patch.object(vnf_package.VnfPackage, "get_by_id") + @mock.patch.object(vnf_package.VnfPackage, "save") + def test_upload_vnf_package_from_uri(self, mock_vnf_pack_save, + mock_vnf_by_id, + mock_upload_vnf_package_from_uri, + mock_url_open): + body = {"addressInformation": "http://test_data.zip"} + mock_vnf_by_id.return_value = fakes.return_vnfpkg_obj() + mock_vnf_pack_save.return_value = fakes.return_vnfpkg_obj() + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s/package_content/upload_from_uri' + % constants.UUID) + req.headers['Content-Type'] = 'application/json' + req.method = 'POST' + req.body = jsonutils.dump_as_bytes(body) + resp = req.get_response(self.app) + self.assertEqual(http_client.ACCEPTED, resp.status_code) + + def test_upload_vnf_package_from_uri_with_invalid_uuid(self): + body = {"addressInformation": "http://test_data.zip"} + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s/package_content/upload_from_uri' + % constants.INVALID_UUID) + self.assertRaises(exc.HTTPNotFound, + self.controller.upload_vnf_package_from_uri, + req, constants.INVALID_UUID, body=body) + + @mock.patch.object(urllib.request, 'urlopen') + @mock.patch.object(vnf_package.VnfPackage, "get_by_id") + def test_upload_vnf_package_from_uri_without_vnf_pack(self, + mock_vnf_by_id, + mock_url_open): + body = {"addressInformation": "http://test_data.zip"} + msg = _("Can not find requested vnf package: %s") % constants.UUID + mock_vnf_by_id.side_effect = exc.HTTPNotFound(explanation=msg) + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s/package_content/upload_from_uri' + % constants.UUID) + self.assertRaises(exc.HTTPNotFound, + self.controller.upload_vnf_package_from_uri, + req, constants.UUID, body=body) + + @mock.patch.object(urllib.request, 'urlopen') + @mock.patch.object(vnf_package.VnfPackage, "get_by_id") + def test_upload_vnf_package_from_uri_with_invalid_status(self, + mock_vnf_by_id, + mock_url_open): + body = {"addressInformation": "http://test.zip"} + vnf_obj = fakes.return_vnfpkg_obj() + vnf_obj.__setattr__('onboarding_state', 'test') + mock_vnf_by_id.return_value = vnf_obj + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s/package_content/upload_from_uri' + % constants.UUID) + self.assertRaises(exc.HTTPConflict, + self.controller.upload_vnf_package_from_uri, + req, constants.UUID, body=body) + + def test_upload_vnf_package_from_uri_with_invalid_url(self): + body = {"addressInformation": "http://test_data.zip"} + req = fake_request.HTTPRequest.blank( + '/vnf_packages/%s/package_content/upload_from_uri' + % constants.UUID) + self.assertRaises(exc.HTTPBadRequest, + self.controller.upload_vnf_package_from_uri, + req, constants.UUID, body=body) diff --git a/tacker/wsgi.py b/tacker/wsgi.py index 5c742cabc..18dd3ca42 100644 --- a/tacker/wsgi.py +++ b/tacker/wsgi.py @@ -17,6 +17,7 @@ Utility methods for working with WSGI servers """ from __future__ import print_function +import functools import errno import os @@ -93,6 +94,54 @@ def encode_body(body): return encodeutils.to_utf8(body) +def expected_errors(errors): + """Decorator for Restful API methods which specifies expected exceptions. + + Specify which exceptions may occur when an API method is called. If an + unexpected exception occurs then return a 500 instead and ask the user + of the API to file a bug report. + """ + def decorator(f): + @functools.wraps(f) + def wrapped(*args, **kwargs): + try: + return f(*args, **kwargs) + except Exception as exc: + if isinstance(exc, webob.exc.WSGIHTTPException): + if isinstance(errors, int): + t_errors = (errors,) + else: + t_errors = errors + if exc.code in t_errors: + raise + elif isinstance(exc, exception.Forbidden): + # Note(nirajsingh): Special case to handle + # Forbidden exceptions so every + # extension method does not need to wrap authorize + # calls. ResourceExceptionHandler silently + # converts NotAuthorized to HTTPForbidden + raise + elif isinstance(exc, exception.ValidationError): + # Note(nirajsingh): Handle a validation error, which + # happens due to invalid API parameters, as an + # expected error. + raise + elif isinstance(exc, exception.NotAuthorized): + # Handle an authorized exception, will be + # automatically converted to a HTTP 401. + raise + + LOG.exception("Unexpected exception in API method") + msg = _('Unexpected API Error. Please report this at ' + 'http://bugs.launchpad.net/tacker/ and attach the Tacker ' + 'API log if possible.\n%s') % type(exc) + raise webob.exc.HTTPInternalServerError(explanation=msg) + + return wrapped + + return decorator + + class WorkerService(common_service.ServiceBase): """Wraps a worker to be handled by ProcessLauncher.""" @@ -354,7 +403,7 @@ class Request(webob.Request): return bm or 'application/json' def get_content_type(self): - allowed_types = ("application/json") + allowed_types = ("application/json", "application/zip") if "Content-Type" not in self.headers: LOG.debug("Missing Content-Type") return None @@ -429,6 +478,7 @@ class ResponseSerializer(object): def __init__(self, body_serializers=None, headers_serializer=None): self.body_serializers = { 'application/json': JSONDictSerializer(), + 'application/zip': JSONDictSerializer() } self.body_serializers.update(body_serializers or {}) @@ -827,6 +877,21 @@ class ResourceExceptionHandler(object): return False +def response(code): + """Attaches response code to a method. + + This decorator associates a response code with a method. Note + that the function attributes are directly manipulated; the method + is not wrapped. + """ + + def decorator(func): + func.wsgi_code = code + return func + + return decorator + + class ResponseObject(object): """Bundles a response object @@ -1084,6 +1149,15 @@ class Controller(object): """ + _view_builder_class = None + + def __init__(self): + """Initialize controller with a view builder instance.""" + if self._view_builder_class: + self._view_builder = self._view_builder_class() + else: + self._view_builder = None + @webob.dec.wsgify(RequestClass=Request) def __call__(self, req): """Call the method specified in req.environ by RoutesMiddleware."""