From e29026f3fcdb3b5e4d91e52e43a72ec72f48a18c Mon Sep 17 00:00:00 2001 From: Aldinson Esto Date: Tue, 25 Aug 2020 19:03:59 +0900 Subject: [PATCH] Support of version 2.4.1 on Modify VNF Version 2.4.1 of Modify VNF is supported. Implements: blueprint support-etsi-nfv-specs Spec: https://specs.openstack.org/openstack/tacker-specs/specs/victoria/enhancement_enhance-vnf-lcm-api-support.html Change-Id: I6dd978463511672bc26034cc3ff339bd92090c33 --- api-ref/source/v1/vnflcm.inc | 1 + tacker/api/vnflcm/v1/controller.py | 47 ++-- tacker/conductor/conductor_server.py | 25 +- tacker/conductor/conductorrpc/vnf_lcm_rpc.py | 20 ++ tacker/db/db_sqlalchemy/models.py | 33 ++- tacker/objects/vnf_instance.py | 38 +-- tacker/objects/vnf_package_vnfd.py | 34 +-- tacker/tests/unit/conductor/fakes.py | 27 +- .../unit/conductor/test_conductor_server.py | 121 +++++---- tacker/tests/unit/objects/fakes.py | 37 ++- .../tests/unit/objects/test_vnf_instance.py | 201 ++++----------- tacker/tests/unit/vnflcm/fakes.py | 21 +- tacker/tests/unit/vnflcm/test_controller.py | 231 +++++++++++------- 13 files changed, 465 insertions(+), 371 deletions(-) diff --git a/api-ref/source/v1/vnflcm.inc b/api-ref/source/v1/vnflcm.inc index ff6117aef..7d28c9bef 100644 --- a/api-ref/source/v1/vnflcm.inc +++ b/api-ref/source/v1/vnflcm.inc @@ -611,6 +611,7 @@ Request Parameters - vnfInstanceName: vnf_instance_modify_request_name - vnfInstanceDescription: vnf_instance_modify_request_description - vnfdId: vnf_instance_modify_request_vnfd_id + - vnfPkgId: vnf_instance_modify_request_vnf_pkg_id - metadata: vnf_instance_modify_request_metadata - vimConnectionInfo: vnf_instance_modify_request_vim_connection_info - id: vim_connection_info_id diff --git a/tacker/api/vnflcm/v1/controller.py b/tacker/api/vnflcm/v1/controller.py index 506c44bac..b4bc6ccd3 100644 --- a/tacker/api/vnflcm/v1/controller.py +++ b/tacker/api/vnflcm/v1/controller.py @@ -600,8 +600,9 @@ class VnfLcmController(wsgi.Controller): self._instantiate(context, vnf_instance, vnf, body) @check_vnf_state(action="terminate", - instantiation_state=[fields.VnfInstanceState.INSTANTIATED], - task_state=[None]) + instantiation_state=[ + fields.VnfInstanceState.INSTANTIATED], + task_state=[None]) def _terminate(self, context, vnf_instance, request_body, vnf): req_body = utils.convert_camelcase_to_snakecase(request_body) terminate_vnf_req = \ @@ -641,8 +642,9 @@ class VnfLcmController(wsgi.Controller): req_body = utils.convert_camelcase_to_snakecase(request_body) heal_vnf_request = objects.HealVnfRequest(context=context, **req_body) inst_vnf_info = vnf_instance.instantiated_vnf_info - vnfc_resource_info_ids = [vnfc_resource_info.id for - vnfc_resource_info in inst_vnf_info.vnfc_resource_info] + vnfc_resource_info_ids = [ + vnfc_resource_info.id for vnfc_resource_info in + inst_vnf_info.vnfc_resource_info] for vnfc_id in heal_vnf_request.vnfc_instance_id: # check if vnfc_id exists in vnfc_resource_info @@ -702,7 +704,13 @@ class VnfLcmController(wsgi.Controller): context.can(vnf_lcm_policies.VNFLCM % 'update_vnf') # get body - req_body = utils.convert_camelcase_to_snakecase(body) + body_data = {} + body_data['vnf_instance_name'] = body.get('vnfInstanceName') + body_data['vnf_instance_description'] = body.get( + 'vnfInstanceDescription') + body_data['vnfd_id'] = body.get('vnfdId') + if (body.get('vnfdId') is None and body.get('vnfPkgId')): + body_data['vnf_pkg_id'] = body.get('vnfPkgId') # According to the ETSI NFV SOL document, # there is no API request/response @@ -725,8 +733,12 @@ class VnfLcmController(wsgi.Controller): if (vnf_data.get("status") != fields.VnfStatus.ACTIVE and vnf_data.get("status") != fields.VnfStatus.INACTIVE): msg = _("VNF %(id)s status is %(state)s") - return self._make_problem_detail(msg % {"id": id, - "state": vnf_data.get("status")}, 409, 'Conflict') + return self._make_problem_detail( + msg % { + "id": id, + "state": vnf_data.get("status")}, + 409, + 'Conflict') try: vnf_instance_data = objects.VnfInstanceList.vnf_instance_list( @@ -739,19 +751,27 @@ class VnfLcmController(wsgi.Controller): return self._make_problem_detail( str(e), 500, 'Internal Server Error') - if req_body['vnfd_id']: + vnfd_pkg_data = {} + if (body_data.get('vnfd_id') or body_data.get('vnf_pkg_id')): try: pkg_obj = objects.VnfPackageVnfd(context=context) - vnfd_pkg = pkg_obj.get_vnf_package_vnfd(req_body['vnfd_id']) + if (body_data.get('vnfd_id')): + input_id = 'vnfd_id' + vnfd_pkg = pkg_obj.get_vnf_package_vnfd( + body_data[input_id]) + elif (body_data.get('vnf_pkg_id')): + input_id = 'vnf_pkg_id' + vnfd_pkg = pkg_obj.get_vnf_package_vnfd( + body_data[input_id], package_uuid=True) if not vnfd_pkg: msg = _( "Can not find requested vnf package vnfd: %s") %\ - req_body['vnfd_id'] + body_data[input_id] return self._make_problem_detail(msg, 400, 'Bad Request') except Exception as e: return self._make_problem_detail( str(e), 500, 'Internal Server Error') - vnfd_pkg_data = {} + vnfd_pkg_data['vnf_provider'] = vnfd_pkg.get('vnf_provider') vnfd_pkg_data['vnf_product_name'] = vnfd_pkg.get( 'vnf_product_name') @@ -759,13 +779,12 @@ class VnfLcmController(wsgi.Controller): 'vnf_software_version') vnfd_pkg_data['vnfd_version'] = vnfd_pkg.get('vnfd_version') vnfd_pkg_data['package_uuid'] = vnfd_pkg.get('package_uuid') + vnfd_pkg_data['vnfd_id'] = vnfd_pkg.get('vnfd_id') # make op_occs_uuid op_occs_uuid = uuidutils.generate_uuid() # process vnf - if not req_body['vnfd_id']: - vnfd_pkg_data = "" vnf_lcm_opoccs = { 'vnf_instance_id': id, 'id': op_occs_uuid, @@ -775,7 +794,7 @@ class VnfLcmController(wsgi.Controller): self.rpc_api.update( context, vnf_lcm_opoccs, - req_body, + body_data, vnfd_pkg_data, vnf_data.get('vnfd_id')) diff --git a/tacker/conductor/conductor_server.py b/tacker/conductor/conductor_server.py index 3603c9321..2845a036e 100644 --- a/tacker/conductor/conductor_server.py +++ b/tacker/conductor/conductor_server.py @@ -475,8 +475,8 @@ class Conductor(manager.Manager): except (store_exceptions.GlanceStoreException) as e: exc_msg = encodeutils.exception_to_unicode(e) msg = (_("Exception raised from glance store can be " - "unrecoverable if it is not related to connection" - " error. Error: %s.") % exc_msg) + "unrecoverable if it is not related to connection" + " error. Error: %s.") % exc_msg) raise exceptions.FailedToGetVnfdData(error=msg) try: return self._read_vnfd_files(csar_path) @@ -1241,18 +1241,15 @@ class Conductor(manager.Manager): raise Exception(str(msg)) # update lcm_op_occs - changed_info = objects.vnf_lcm_op_occs.VnfInfoModifications() - changed_info.vnf_instance_name = body_data.get('vnf_instance_name') - changed_info.vnf_instance_description = body_data.get( - 'vnf_instance_description') - if body_data.get('vnfd_id'): - changed_info.vnfd_id = body_data.get('vnfd_id') - changed_info.vnf_provider = vnfd_pkg_data.get('vnf_provider') - changed_info.vnf_product_name = vnfd_pkg_data.get( - 'vnf_product_name') - changed_info.vnf_software_version = vnfd_pkg_data.get( - 'vnf_software_version') - changed_info.vnfd_version = vnfd_pkg_data.get('vnfd_version') + if vnfd_pkg_data and len(vnfd_pkg_data) > 0: + changed_info = \ + objects.vnf_lcm_op_occs.VnfInfoModifications._from_dict( + vnfd_pkg_data) + else: + changed_info = objects.vnf_lcm_op_occs.VnfInfoModifications() + changed_info.vnf_instance_name = body_data.get('vnf_instance_name') + changed_info.vnf_instance_description = body_data.get( + 'vnf_instance_description') # update vnf_lcm_op_occs now = timeutils.utcnow() diff --git a/tacker/conductor/conductorrpc/vnf_lcm_rpc.py b/tacker/conductor/conductorrpc/vnf_lcm_rpc.py index 46bd3b587..688d285a8 100644 --- a/tacker/conductor/conductorrpc/vnf_lcm_rpc.py +++ b/tacker/conductor/conductorrpc/vnf_lcm_rpc.py @@ -85,6 +85,26 @@ class VNFLcmRPCAPI(object): vnfd_pkg_data=vnfd_pkg_data, vnfd_id=vnfd_id) + def update_vnf_instance_content( + self, + context, + vnf_lcm_opoccs, + body_data, + vnfd_pkg_data, + vnfd_id, + cast=True): + serializer = objects_base.TackerObjectSerializer() + + client = rpc.get_client(self.target, version_cap=None, + serializer=serializer) + cctxt = client.prepare() + rpc_method = cctxt.cast if cast else cctxt.call + return rpc_method(context, 'update_lcm', + vnf_lcm_opoccs=vnf_lcm_opoccs, + body_data=body_data, + vnfd_pkg_data=vnfd_pkg_data, + vnfd_id=vnfd_id) + def send_notification(self, context, notification, cast=True): serializer = objects_base.TackerObjectSerializer() diff --git a/tacker/db/db_sqlalchemy/models.py b/tacker/db/db_sqlalchemy/models.py index 5b96d1efd..2a5f7f786 100644 --- a/tacker/db/db_sqlalchemy/models.py +++ b/tacker/db/db_sqlalchemy/models.py @@ -80,6 +80,19 @@ class VnfSoftwareImage(model_base.BASE, models.SoftDeleteMixin, return {m.key: m.value for m in self._metadata} +class VnfArtifactMetadata(model_base.BASE, models.SoftDeleteMixin, + models.TimestampMixin): + """Contains all info about vnf packages artifacts metadata.""" + + __tablename__ = 'vnf_artifact_metadata' + id = sa.Column(sa.Integer, nullable=False, primary_key=True) + artifact_uuid = sa.Column(sa.String(36), + sa.ForeignKey('vnf_artifacts.id'), + nullable=False) + key = sa.Column(sa.String(255), nullable=False) + value = sa.Column(sa.String(255), nullable=False) + + class VnfDeploymentFlavour(model_base.BASE, models.SoftDeleteMixin, models.TimestampMixin, models_v1.HasId): """Contains all info about vnf packages Deployment Flavours.""" @@ -115,7 +128,9 @@ class VnfPackageVnfd(model_base.BASE, VnfPackageVnfdSoftDeleteMixin, __tablename__ = 'vnf_package_vnfd' __table_args__ = ( - sa.schema.UniqueConstraint("vnfd_id", "deleted", + sa.schema.UniqueConstraint( + "vnfd_id", + "deleted", name="uniq_vnf_package_vnfd0vnfd_id0deleted"), ) @@ -201,6 +216,7 @@ class VnfInstance(model_base.BASE, models.SoftDeleteMixin, task_state = sa.Column(sa.String(255), nullable=True) vim_connection_info = sa.Column(sa.JSON(), nullable=True) tenant_id = sa.Column('tenant_id', sa.String(length=64), nullable=False) + vnf_pkg_id = sa.Column(types.Uuid, nullable=False) vnf_metadata = sa.Column(sa.JSON(), nullable=True) @@ -211,8 +227,8 @@ class VnfInstantiatedInfo(model_base.BASE, models.SoftDeleteMixin, __tablename__ = 'vnf_instantiated_info' id = sa.Column(sa.Integer, primary_key=True, autoincrement=True) vnf_instance_id = sa.Column(sa.String, - sa.ForeignKey('vnf_instances.id'), - nullable=False) + sa.ForeignKey('vnf_instances.id'), + nullable=False) flavour_id = sa.Column(sa.String(255), nullable=False) ext_cp_info = sa.Column(sa.JSON(), nullable=False) ext_virtual_link_info = sa.Column(sa.JSON(), nullable=True) @@ -226,8 +242,11 @@ class VnfInstantiatedInfo(model_base.BASE, models.SoftDeleteMixin, instantiation_level_id = sa.Column(sa.String(255), nullable=True) additional_params = sa.Column(sa.JSON(), nullable=True) - vnf_instance = orm.relationship(VnfInstance, - backref=orm.backref('instantiated_vnf_info', uselist=False), + vnf_instance = orm.relationship( + VnfInstance, + backref=orm.backref( + 'instantiated_vnf_info', + uselist=False), foreign_keys=vnf_instance_id, primaryjoin='and_(VnfInstantiatedInfo.vnf_instance_id == ' 'VnfInstance.id, VnfInstantiatedInfo.deleted == 0)') @@ -264,8 +283,8 @@ class VnfLcmFilters(model_base.BASE): __maxsize__ = 65536 id = sa.Column(sa.Integer, nullable=True, primary_key=True) subscription_uuid = sa.Column(sa.String(36), - sa.ForeignKey('vnf_lcm_subscriptions.id'), - nullable=False) + sa.ForeignKey('vnf_lcm_subscriptions.id'), + nullable=False) filter = sa.Column(sa.JSON, nullable=False) notification_types = sa.Column(sa.VARBINARY(255), nullable=True) notification_types_len = sa.Column(sa.Integer, nullable=True) diff --git a/tacker/objects/vnf_instance.py b/tacker/objects/vnf_instance.py index 4f0527585..87439f06d 100644 --- a/tacker/objects/vnf_instance.py +++ b/tacker/objects/vnf_instance.py @@ -238,24 +238,30 @@ def _update_vnf_instances( updated_values['vim_connection_info'] = merge_vim_connection_info - if body_data.get('vnfd_id'): - updated_values['vnfd_id'] = body_data.get('vnfd_id') + if vnfd_pkg_data and len(vnfd_pkg_data) > 0: + updated_values['vnfd_id'] = vnfd_pkg_data.get('vnfd_id') updated_values['vnf_provider'] = vnfd_pkg_data.get('vnf_provider') updated_values['vnf_product_name'] = vnfd_pkg_data.get( 'vnf_product_name') updated_values['vnf_software_version'] = vnfd_pkg_data.get( 'vnf_software_version') + updated_values['vnf_pkg_id'] = vnfd_pkg_data.get('package_uuid') api.model_query(context, models.VnfInstance). \ filter_by(id=vnf_lcm_opoccs.get('vnf_instance_id')). \ update(updated_values, synchronize_session=False) vnf_now = timeutils.utcnow() - if body_data.get('vnfd_id'): + if (body_data.get('vnfd_id') or body_data.get('vnf_pkg_id')): # update vnf - updated_values = {'vnfd_id': body_data.get('vnfd_id'), - 'updated_at': vnf_now - } + if body_data.get('vnfd_id'): + updated_values = {'vnfd_id': body_data.get('vnfd_id'), + 'updated_at': vnf_now + } + elif body_data.get('vnf_pkg_id'): + updated_values = {'vnfd_id': vnfd_pkg_data.get('vnfd_id'), + 'updated_at': vnf_now + } api.model_query(context, vnfm_db.VNF).\ filter_by(id=vnf_lcm_opoccs.get('vnf_instance_id')). \ update(updated_values, synchronize_session=False) @@ -308,7 +314,9 @@ class VnfInstance(base.TackerObject, base.TackerPersistentObject, 'id': fields.UUIDField(nullable=False), 'vnf_instance_name': fields.StringField(nullable=True), 'vnf_instance_description': fields.StringField(nullable=True), - 'instantiation_state': fields.VnfInstanceStateField(nullable=False, + 'instantiation_state': + fields.VnfInstanceStateField( + nullable=False, default=fields.VnfInstanceState.NOT_INSTANTIATED), 'task_state': fields.StringField(nullable=True, default=None), 'vnfd_id': fields.StringField(nullable=False), @@ -320,6 +328,7 @@ class VnfInstance(base.TackerObject, base.TackerPersistentObject, 'VimConnectionInfo', nullable=True, default=[]), 'tenant_id': fields.StringField(nullable=False), 'vnf_metadata': fields.DictOfStringsField(nullable=True, default={}), + 'vnf_pkg_id': fields.StringField(nullable=False), 'instantiated_vnf_info': fields.ObjectField('InstantiatedVnfInfo', nullable=True, default=None) } @@ -367,8 +376,8 @@ class VnfInstance(base.TackerObject, base.TackerPersistentObject, setattr(vnf_instance, key, db_vnf_instance[key]) - VnfInstance._load_instantiated_vnf_info_from_db_object(context, - vnf_instance, db_vnf_instance) + VnfInstance._load_instantiated_vnf_info_from_db_object( + context, vnf_instance, db_vnf_instance) vim_connection_info = db_vnf_instance['vim_connection_info'] vim_connection_list = [objects.VimConnectionInfo.obj_from_primitive( @@ -384,9 +393,8 @@ class VnfInstance(base.TackerObject, base.TackerPersistentObject, def _load_instantiated_vnf_info_from_db_object(context, vnf_instance, db_vnf_instance): if db_vnf_instance['instantiated_vnf_info']: - inst_vnf_info = \ - objects.InstantiatedVnfInfo.obj_from_db_obj(context, - db_vnf_instance['instantiated_vnf_info']) + inst_vnf_info = objects.InstantiatedVnfInfo.obj_from_db_obj( + context, db_vnf_instance['instantiated_vnf_info']) vnf_instance.instantiated_vnf_info = inst_vnf_info @base.remotable @@ -440,8 +448,8 @@ class VnfInstance(base.TackerObject, base.TackerPersistentObject, expected_attrs = ["instantiated_vnf_info"] db_vnf_instance = _vnf_instance_update(self._context, - self.id, updates, - columns_to_join=expected_attrs) + self.id, updates, + columns_to_join=expected_attrs) self._from_db_object(self._context, self, db_vnf_instance) def _save_instantiated_vnf_info(self, context): @@ -481,7 +489,7 @@ class VnfInstance(base.TackerObject, base.TackerPersistentObject, if (self.instantiation_state == fields.VnfInstanceState.INSTANTIATED and self.instantiated_vnf_info): data.update({'instantiated_vnf_info': - self.instantiated_vnf_info.to_dict()}) + self.instantiated_vnf_info.to_dict()}) vim_connection_info_list = [] for vim_connection_info in self.vim_connection_info: diff --git a/tacker/objects/vnf_package_vnfd.py b/tacker/objects/vnf_package_vnfd.py index c49034562..d5676a69c 100644 --- a/tacker/objects/vnf_package_vnfd.py +++ b/tacker/objects/vnf_package_vnfd.py @@ -92,7 +92,7 @@ def _vnf_package_vnfd_get_by_id(context, vnfd_id): read_deleted="no", project_only=False). \ filter_by(vnfd_id=vnfd_id).\ join((models.VnfPackage, models.VnfPackage.id == - models.VnfPackageVnfd.package_uuid)) + models.VnfPackageVnfd.package_uuid)) if tacker.context.is_user_context(context): query = query.filter(models.VnfPackage.tenant_id == context.project_id) @@ -125,9 +125,9 @@ def _vnf_package_vnfd_get_by_packageId(context, packageId): @db_api.context_manager.reader def _vnf_package_vnfd_get_by_vnfdId(context, vnfdId): query = api.model_query(context, - models.VnfPackageVnfd, - read_deleted="no", - project_only=True).filter_by(vnfd_id=vnfdId) + models.VnfPackageVnfd, + read_deleted="no", + project_only=True).filter_by(vnfd_id=vnfdId) result = query.first() @@ -141,19 +141,19 @@ def _vnf_package_vnfd_get_by_vnfdId(context, vnfdId): def _get_vnf_package_vnfd_by_vnfid(context, vnfpkgid): sql = ("select" - " t1.vnfd_id," - " t1.vnf_provider," - " t1.vnf_product_name," - " t1.vnf_software_version," - " t1.vnfd_version," - " t2.name" - " from " - " vnf_package_vnfd t1," - " vnf t2 " - " where" - " t1.vnfd_id=t2.vnfd_id" - " and" - " t2.id= :vnfpkgid") + " t1.vnfd_id," + " t1.vnf_provider," + " t1.vnf_product_name," + " t1.vnf_software_version," + " t1.vnfd_version," + " t2.name" + " from " + " vnf_package_vnfd t1," + " vnf t2 " + " where" + " t1.vnfd_id=t2.vnfd_id" + " and" + " t2.id= :vnfpkgid") result = context.session.execute(sql, {'vnfpkgid': vnfpkgid}) for line in result: diff --git a/tacker/tests/unit/conductor/fakes.py b/tacker/tests/unit/conductor/fakes.py index 242a05bd3..6e67b213c 100644 --- a/tacker/tests/unit/conductor/fakes.py +++ b/tacker/tests/unit/conductor/fakes.py @@ -111,9 +111,9 @@ def get_lcm_op_occs_data(): 'operation_state': 'PROCESSING', 'state_entered_time': datetime.datetime(1900, 1, 1, 1, 1, 1, - tzinfo=iso8601.UTC), + tzinfo=iso8601.UTC), 'start_time': datetime.datetime(1900, 1, 1, 1, 1, 1, - tzinfo=iso8601.UTC), + tzinfo=iso8601.UTC), 'operation': 'MODIFY_INFO', 'is_automatic_invocation': 0, 'is_cancel_pending': 0, @@ -201,7 +201,8 @@ def _model_non_instantiated_vnf_instance(**updates): 'vnf_software_version': '1.0', 'tenant_id': uuidsentinel.tenant_id, 'vnfd_id': uuidsentinel.vnfd_id, - 'vnfd_version': '1.0'} + 'vnfd_version': '1.0', + 'vnfPkgId': uuidsentinel.vnf_pkg_id} if updates: vnf_instance.update(**updates) @@ -236,16 +237,16 @@ def return_vnf_instance( instantiated_vnf_info.update( {"ext_cp_info": [], - 'ext_virtual_link_info': [], - 'ext_managed_virtual_link_info': [], - 'vnfc_resource_info': [], - 'vnf_virtual_link_resource_info': [], - 'virtual_storage_resource_info': [], - "flavour_id": "simple", - "scale_status": [scale_status], - "vnf_instance_id": "171f3af2-a753-468a-b5a7-e3e048160a79", - "additional_params": {"key": "value"}, - 'vnf_state': "STARTED"}) + 'ext_virtual_link_info': [], + 'ext_managed_virtual_link_info': [], + 'vnfc_resource_info': [], + 'vnf_virtual_link_resource_info': [], + 'virtual_storage_resource_info': [], + "flavour_id": "simple", + "scale_status": [scale_status], + "vnf_instance_id": "171f3af2-a753-468a-b5a7-e3e048160a79", + "additional_params": {"key": "value"}, + 'vnf_state': "STARTED"}) info_data = objects.InstantiatedVnfInfo(**instantiated_vnf_info) vnf_instance_obj.instantiated_vnf_info = info_data diff --git a/tacker/tests/unit/conductor/test_conductor_server.py b/tacker/tests/unit/conductor/test_conductor_server.py index 1b4625d13..56c3fad5e 100644 --- a/tacker/tests/unit/conductor/test_conductor_server.py +++ b/tacker/tests/unit/conductor/test_conductor_server.py @@ -133,6 +133,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): body_data['vnfd_id'] = "2c69a161-0000-4b0f-bcf8-391f8fc76600" body_data['vnf_configurable_properties'] = {"test": "test_value"} body_data['vnfc_info_modifications_delete_ids'] = ["test1"] + body_data['vnf_pkg_id'] = uuidsentinel.vnf_pkg_id return body_data def _create_vnf_lcm_opoccs(self): @@ -263,7 +264,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): @mock.patch.object(glance_store, 'load_csar') def test_get_vnf_package_vnfd_exception_from_glance_store(self, - mock_load_csar): + mock_load_csar): mock_load_csar.side_effect = store_exceptions.NotFound self.assertRaises(exceptions.FailedToGetVnfdData, self.conductor.get_vnf_package_vnfd, self.context, @@ -310,7 +311,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): lcm_op_occs_data = fakes.get_lcm_op_occs_data() mock_vnf_by_id.return_value = \ objects.VnfLcmOpOcc(context=self.context, - **lcm_op_occs_data) + **lcm_op_occs_data) vnf_package_vnfd = self._create_and_upload_vnf_package() vnf_instance_data = fake_obj.get_vnf_instance_data( @@ -337,13 +338,13 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): @mock.patch.object(objects.VnfPackage, 'is_package_in_use') @mock.patch('tacker.conductor.conductor_server.LOG') @mock.patch.object(objects.VnfLcmOpOcc, "get_by_id") - def test_instantiate_vnf_instance_already_instantiated(self, - mock_vnf_by_id, mock_log, mock_package_in_use, mock_get_lock, + def test_instantiate_vnf_instance_already_instantiated( + self, mock_vnf_by_id, mock_log, mock_package_in_use, mock_get_lock, mock_save): lcm_op_occs_data = fakes.get_lcm_op_occs_data() mock_vnf_by_id.return_value = \ objects.VnfLcmOpOcc(context=self.context, - **lcm_op_occs_data) + **lcm_op_occs_data) vnf_package_vnfd = self._create_and_upload_vnf_package() vnf_instance_data = fake_obj.get_vnf_instance_data( @@ -361,9 +362,10 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): self.vnflcm_driver.instantiate_vnf.assert_not_called() mock_package_in_use.assert_not_called() expected_log = 'Vnf instance %(id)s is already in %(state)s state.' - mock_log.error.assert_called_once_with(expected_log, - {'id': vnf_instance.id, - 'state': fields.VnfInstanceState.INSTANTIATED}) + mock_log.error.assert_called_once_with( + expected_log, { + 'id': vnf_instance.id, + 'state': fields.VnfInstanceState.INSTANTIATED}) @unittest.skip("Such test is no longer feasible.") @mock.patch.object(objects.VnfLcmOpOcc, "save") @@ -372,14 +374,17 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): @mock.patch.object(objects.LccnSubscriptionRequest, 'vnf_lcm_subscriptions_get') @mock.patch.object(objects.VnfLcmOpOcc, "get_by_id") - def test_instantiate_vnf_instance_with_vnf_package_in_use(self, + def test_instantiate_vnf_instance_with_vnf_package_in_use( + self, mock_vnf_by_id, mock_vnf_lcm_subscriptions_get, - mock_vnf_package_in_use, mock_get_lock, mock_save): + mock_vnf_package_in_use, + mock_get_lock, + mock_save): lcm_op_occs_data = fakes.get_lcm_op_occs_data() mock_vnf_by_id.return_value = \ objects.VnfLcmOpOcc(context=self.context, - **lcm_op_occs_data) + **lcm_op_occs_data) vnf_package_vnfd = self._create_and_upload_vnf_package() vnf_instance_data = fake_obj.get_vnf_instance_data( @@ -420,7 +425,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): lcm_op_occs_data = fakes.get_lcm_op_occs_data() mock_vnf_by_id.return_value = \ objects.VnfLcmOpOcc(context=self.context, - **lcm_op_occs_data) + **lcm_op_occs_data) vnf_package_vnfd = self._create_and_upload_vnf_package() vnf_instance_data = fake_obj.get_vnf_instance_data( @@ -515,7 +520,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): vnf_instance_data['instantiation_state'] =\ fields.VnfInstanceState.NOT_INSTANTIATED vnf_instance = objects.VnfInstance(context=self.context, - **vnf_instance_data) + **vnf_instance_data) vnf_instance.create() terminate_vnf_req = objects.TerminateVnfRequest( @@ -530,10 +535,11 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): self.vnflcm_driver.terminate_vnf.assert_not_called() mock_package_in_use.assert_not_called() expected_log = ('Terminate action cannot be performed on vnf %(id)s ' - 'which is in %(state)s state.') - mock_log.error.assert_called_once_with(expected_log, - {'id': vnf_instance.id, - 'state': fields.VnfInstanceState.NOT_INSTANTIATED}) + 'which is in %(state)s state.') + mock_log.error.assert_called_once_with( + expected_log, { + 'id': vnf_instance.id, + 'state': fields.VnfInstanceState.NOT_INSTANTIATED}) @unittest.skip("Such test is no longer feasible.") @mock.patch('tacker.conductor.conductor_server.Conductor.' @@ -549,7 +555,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): vnf_instance_data['instantiation_state'] =\ fields.VnfInstanceState.INSTANTIATED vnf_instance = objects.VnfInstance(context=self.context, - **vnf_instance_data) + **vnf_instance_data) vnf_instance.create() mock_vnf_package_is_package_in_use.return_value = False @@ -581,7 +587,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): vnf_instance_data['instantiation_state'] =\ fields.VnfInstanceState.INSTANTIATED vnf_instance = objects.VnfInstance(context=self.context, - **vnf_instance_data) + **vnf_instance_data) vnf_instance.create() mock_vnf_package_is_package_in_use.return_value = True @@ -630,7 +636,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): vnf_lcm_op_occs_id) expected_msg = "Failed to update usage_state of vnf package %s" mock_log.error.assert_called_once_with(expected_msg, - vnf_package_vnfd.package_uuid) + vnf_package_vnfd.package_uuid) @mock.patch('tacker.conductor.conductor_server.Conductor.' '_add_additional_vnf_info') @@ -647,7 +653,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): lcm_op_occs_data = fakes.get_lcm_op_occs_data() mock_vnf_by_id.return_value = \ objects.VnfLcmOpOcc(context=self.context, - **lcm_op_occs_data) + **lcm_op_occs_data) vnf_package_vnfd = self._create_and_upload_vnf_package() vnf_instance_data = fake_obj.get_vnf_instance_data( vnf_package_vnfd.vnfd_id) @@ -707,8 +713,8 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): @unittest.skip("Such test is no longer feasible.") @mock.patch.object(coordination.Coordinator, 'get_lock') @mock.patch('tacker.conductor.conductor_server.LOG') - def test_heal_vnf_instance_already_not_instantiated(self, - mock_log, mock_get_lock): + def test_heal_vnf_instance_already_not_instantiated( + self, mock_log, mock_get_lock): vnf_package_vnfd = self._create_and_upload_vnf_package() vnf_instance_data = fake_obj.get_vnf_instance_data( vnf_package_vnfd.vnfd_id) @@ -723,14 +729,15 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): vnf_dict = {"fake": "fake_dict"} vnf_lcm_op_occs_id = uuidsentinel.vnf_lcm_op_occs_id self.conductor.heal(self.context, vnf_instance, vnf_dict, - heal_vnf_req, vnf_lcm_op_occs_id) + heal_vnf_req, vnf_lcm_op_occs_id) self.vnflcm_driver.heal_vnf.assert_not_called() expected_log = ('Heal action cannot be performed on vnf %(id)s ' 'which is in %(state)s state.') - mock_log.error.assert_called_once_with(expected_log, - {'id': vnf_instance.id, - 'state': fields.VnfInstanceState.NOT_INSTANTIATED}) + mock_log.error.assert_called_once_with( + expected_log, { + 'id': vnf_instance.id, + 'state': fields.VnfInstanceState.NOT_INSTANTIATED}) @mock.patch.object(os, 'remove') @mock.patch.object(shutil, 'rmtree') @@ -812,7 +819,8 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): mock_subscriptions_get): self.requests_mock.register_uri('POST', "https://localhost/callback", - headers={'Content-Type': 'application/json'}, + headers={ + 'Content-Type': 'application/json'}, status_code=204) mock_subscriptions_get.return_value = self._create_subscriptions() @@ -837,9 +845,11 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): 'vnf_lcm_subscriptions_get') def test_sendNotification_vnfIdentifierCreation(self, mock_subscriptions_get): - self.requests_mock.register_uri('POST', + self.requests_mock.register_uri( + 'POST', "https://localhost/callback", - headers={'Content-Type': 'application/json'}, + headers={ + 'Content-Type': 'application/json'}, status_code=204) mock_subscriptions_get.return_value = self._create_subscriptions() @@ -861,9 +871,11 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): @mock.patch.object(objects.LccnSubscriptionRequest, 'vnf_lcm_subscriptions_get') def test_sendNotification_with_auth_basic(self, mock_subscriptions_get): - self.requests_mock.register_uri('POST', + self.requests_mock.register_uri( + 'POST', "https://localhost/callback", - headers={'Content-Type': 'application/json'}, + headers={ + 'Content-Type': 'application/json'}, status_code=204) auth_user_name = 'test_user' @@ -897,17 +909,19 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): def test_sendNotification_with_auth_client_credentials( self, mock_subscriptions_get): auth.auth_manager = auth._AuthManager() - self.requests_mock.register_uri('POST', + self.requests_mock.register_uri( + 'POST', "https://localhost/callback", - headers={'Content-Type': 'application/json'}, + headers={ + 'Content-Type': 'application/json'}, status_code=204) auth_user_name = 'test_user' auth_password = 'test_password' token_endpoint = 'https://oauth2/tokens' - self.requests_mock.register_uri('GET', - token_endpoint, - json={'access_token': 'test_token', 'token_type': 'bearer'}, + self.requests_mock.register_uri( + 'GET', token_endpoint, json={ + 'access_token': 'test_token', 'token_type': 'bearer'}, headers={'Content-Type': 'application/json'}, status_code=200) @@ -938,10 +952,12 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): @mock.patch.object(objects.LccnSubscriptionRequest, 'vnf_lcm_subscriptions_get') def test_sendNotification_retyNotification(self, - mock_subscriptions_get): - self.requests_mock.register_uri('POST', + mock_subscriptions_get): + self.requests_mock.register_uri( + 'POST', "https://localhost/callback", - headers={'Content-Type': 'application/json'}, + headers={ + 'Content-Type': 'application/json'}, status_code=400) mock_subscriptions_get.return_value = self._create_subscriptions() @@ -964,7 +980,8 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): 'vnf_lcm_subscriptions_get') def test_sendNotification_sendError(self, mock_subscriptions_get): - self.requests_mock.register_uri('POST', + self.requests_mock.register_uri( + 'POST', "https://localhost/callback", exc=requests.exceptions.HTTPError("MockException")) @@ -1019,3 +1036,25 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): self.body_data, self.vnfd_pkg_data, vnfd_id) + + @mock.patch.object(conductor_server, 'revert_update_lcm') + @mock.patch.object(t_context.get_admin_context().session, "add") + @mock.patch.object(objects.vnf_lcm_op_occs.VnfLcmOpOcc, "save") + @mock.patch.object(objects.VnfInstance, "update") + @mock.patch.object(objects.vnf_lcm_op_occs.VnfLcmOpOcc, "create") + def test_update_lcm_with_vnf_pkg_id(self, mock_create, + mock_update, mock_save, + mock_add, mock_revert): + mock_create.return_value = "OK" + mock_update.return_value = datetime.datetime( + 1900, 1, 1, 1, 1, 1, tzinfo=iso8601.UTC) + mock_add.return_value = "OK" + mock_save.return_value = "OK" + vnfd_id = "2c69a161-0000-4b0f-bcf8-391f8fc76600" + + self.conductor.update( + self.context, + self.vnf_lcm_opoccs, + self.body_data, + self.vnfd_pkg_data, + vnfd_id) diff --git a/tacker/tests/unit/objects/fakes.py b/tacker/tests/unit/objects/fakes.py index 9539d9fbc..ced1380fe 100644 --- a/tacker/tests/unit/objects/fakes.py +++ b/tacker/tests/unit/objects/fakes.py @@ -118,7 +118,7 @@ lcm_op_occs_data = { "tenant_id": uuidsentinel.tenant_id, 'operation_state': 'PROCESSING', 'state_entered_time': datetime.datetime(1900, 1, 1, 1, 1, 1, - tzinfo=iso8601.UTC), + tzinfo=iso8601.UTC), 'start_time': datetime.datetime(1900, 1, 1, 1, 1, 1, tzinfo=iso8601.UTC), 'operation': 'MODIFY_INFO', @@ -178,6 +178,28 @@ vnf_artifacts = { } +def fake_vnf_package_vnfd_dict(**updates): + vnf_pkg_vnfd = { + 'package_uuid': uuidsentinel.package_uuid, + 'vnfd_id': uuidsentinel.vnfd_id, + 'vnf_provider': 'test vnf provider', + 'vnf_product_name': 'Sample VNF', + 'vnf_software_version': '1.0', + 'vnfd_version': '1.0' + } + + if updates: + vnf_pkg_vnfd.update(updates) + + return vnf_pkg_vnfd + + +def return_vnf_package_vnfd_data(): + model_obj = models.VnfPackageVnfd() + model_obj.update(fake_vnf_package_vnfd_dict()) + return model_obj + + def get_vnf_package_vnfd_data(vnf_package_id, vnfd_id): return { 'package_uuid': vnf_package_id, @@ -185,6 +207,7 @@ def get_vnf_package_vnfd_data(vnf_package_id, vnfd_id): 'vnf_provider': 'test vnf provider', 'vnf_product_name': 'Sample VNF', 'vnf_software_version': '1.0', + "vnf_pkg_id": uuidsentinel.vnf_pkg_id, 'vnfd_version': '1.0', } @@ -201,7 +224,7 @@ def get_vnf_instance_data(vnfd_id): "vnfd_version": "1.0", "tenant_id": uuidsentinel.tenant_id, "vnf_pkg_id": uuidsentinel.vnf_pkg_id, - "vnf_metadata": {"key": "value"} + "vnf_metadata": {"key": "value"}, } @@ -218,7 +241,7 @@ def get_vnf_instance_data_with_id(vnfd_id): "vnfd_version": "1.0", "tenant_id": uuidsentinel.tenant_id, "vnf_pkg_id": uuidsentinel.vnf_pkg_id, - "vnf_metadata": {"key": "value"} + "vnf_metadata": {"key": "value"}, } @@ -227,7 +250,7 @@ def get_lcm_op_occs_data(vnf_instance_id): "tenant_id": uuidsentinel.tenant_id, 'operation_state': 'PROCESSING', 'state_entered_time': datetime.datetime(1900, 1, 1, 1, 1, 1, - tzinfo=iso8601.UTC), + tzinfo=iso8601.UTC), 'start_time': datetime.datetime(1900, 1, 1, 1, 1, 1, tzinfo=iso8601.UTC), 'vnf_instance_id': vnf_instance_id, @@ -254,9 +277,9 @@ def fake_vnf_instance_model_dict(**updates): 'instantiation_state': 'NOT_INSTANTIATED', 'vim_connection_info': [], 'tenant_id': '33f8dbdae36142eebf214c1869eb4e4c', - 'id': constants.UUID, 'vnf_pkg_id': uuidsentinel.vnf_pkg_id, - 'vnf_metadata': {'key': 'value'} + 'id': constants.UUID, + 'vnf_metadata': {"key": "value"}, } if updates: @@ -454,7 +477,7 @@ def vnf_instance_model_object(vnf_instance): 'tenant_id': vnf_instance.tenant_id, 'created_at': vnf_instance.created_at, 'vnf_pkg_id': vnf_instance.vnf_pkg_id, - 'vnf_metadata': vnf_instance.vnf_metadata + 'vnf_metadata': vnf_instance.vnf_metadata, } vnf_instance_db_obj = models.VnfInstance() diff --git a/tacker/tests/unit/objects/test_vnf_instance.py b/tacker/tests/unit/objects/test_vnf_instance.py index d2a26716c..0c49c7a18 100644 --- a/tacker/tests/unit/objects/test_vnf_instance.py +++ b/tacker/tests/unit/objects/test_vnf_instance.py @@ -13,16 +13,17 @@ # License for the specific language governing permissions and limitations # under the License. +import ddt from unittest import mock from tacker.common import exceptions from tacker import context from tacker.db import api as sqlalchemy_api -from tacker.db.db_sqlalchemy import api from tacker.db.nfvo import nfvo_db from tacker import objects from tacker.tests.unit.db.base import SqlTestCase from tacker.tests.unit.objects import fakes +from tacker.tests.unit.vnflcm import fakes as fakes_vnflcm from tacker.tests import uuidsentinel get_engine = sqlalchemy_api.get_engine @@ -54,6 +55,7 @@ class FakeApiModelQuery: return self +@ddt.ddt class TestVnfInstance(SqlTestCase): maxDiff = None @@ -65,8 +67,12 @@ class TestVnfInstance(SqlTestCase): self.vims = nfvo_db.Vim(**fakes.vim_data) self.engine = get_engine() self.conn = self.engine.connect() + self.body_data = self._create_body_data() + self.vnfd_pkg_data = self._create_vnfd_pkg_data() + self.vim = nfvo_db.Vim() - def _create_and_upload_vnf_package(self): + @mock.patch.object(objects.VnfPackageVnfd, 'create') + def _create_and_upload_vnf_package(self, mock_create): vnf_package = objects.VnfPackage(context=self.context, **fakes.vnf_package_data) vnf_package.create() @@ -74,6 +80,7 @@ class TestVnfInstance(SqlTestCase): vnf_pack_vnfd = fakes.get_vnf_package_vnfd_data( vnf_package.id, uuidsentinel.vnfd_id) + mock_create.return_value = fakes.return_vnf_package_vnfd_data() vnf_pack_vnfd_obj = objects.VnfPackageVnfd( context=self.context, **vnf_pack_vnfd) vnf_pack_vnfd_obj.create() @@ -83,6 +90,32 @@ class TestVnfInstance(SqlTestCase): return vnf_pack_vnfd_obj + def _create_body_data(self): + body_data = {} + body_data['vnf_instance_name'] = "new_instance_name" + body_data['vnf_instance_description'] = "new_instance_discription" + body_data['vnfd_id'] = "2c69a161-0000-4b0f-bcf8-391f8fc76600" + body_data['vnf_configurable_properties'] = {"test": "test_value"} + body_data['vnfc_info_modifications_delete_ids'] = ["test1"] + body_data['vnf_pkg_id'] = uuidsentinel.vnf_pkg_id + return body_data + + def _create_vnfd_pkg_data(self): + vnfd_pkg_data = {} + vnfd_pkg_data['vnf_provider'] =\ + fakes.return_vnf_package_vnfd_data().get('vnf_provider') + vnfd_pkg_data['vnf_product_name'] =\ + fakes.return_vnf_package_vnfd_data().get('vnf_product_name') + vnfd_pkg_data['vnf_software_version'] =\ + fakes.return_vnf_package_vnfd_data().get('vnf_software_version') + vnfd_pkg_data['vnfd_version'] =\ + fakes.return_vnf_package_vnfd_data().get('vnfd_version') + vnfd_pkg_data['package_uuid'] =\ + fakes.return_vnf_package_vnfd_data().get('package_uuid') + vnfd_pkg_data['vnfd_id'] =\ + fakes.return_vnf_package_vnfd_data().get('vnfd_id') + return vnfd_pkg_data + def test_create(self): vnf_instance_data = fakes.get_vnf_instance_data( self.vnf_package.vnfd_id) @@ -189,155 +222,21 @@ class TestVnfInstance(SqlTestCase): self.assertRaises(exceptions.ObjectActionError, vnf_instance_obj.destroy, self.context) - @mock.patch('tacker.objects.vnf_instance._get_vnf_instance') - @mock.patch('tacker.objects.vnf_package.VnfPackage.get_by_id') - @mock.patch.object(api, 'model_query') - def test_update_vnf_instances( - self, - mock_model_query, - mock_get_vnf_package, - mock_get_vnf): - - vnf_instance_data = fakes.fake_vnf_instance_model_dict(**{ - "vim_connection_info": [ - objects.VimConnectionInfo._from_dict({ - "id": "testid", - "vim_id": "aaa", - "vim_type": "openstack-1", - "interface_info": {"endpoint": "endpoint"}, - "access_info": {"username": "xxxxx", - "region": "region", - "password": "password", - "tenant": "tenant"}}), - objects.VimConnectionInfo._from_dict({ - "id": "testid3", - "vim_id": "ccc", - "vim_type": "openstack-2", - "interface_info": {"endpoint": "endpoint22"}, - "access_info": {"username": "xxxxx", - "region": "region", - "password": "password"}}), - objects.VimConnectionInfo._from_dict({ - "id": "testid5", - "vim_id": "eee", - "vim_type": "openstack-4"}) - ], - "vnf_metadata": {"testkey": "test_value"}}) - vnf_instance = objects.VnfInstance( - context=self.context, **vnf_instance_data) - mock_get_vnf.return_value = \ - fakes.vnf_instance_model_object(vnf_instance) - - def mock_filter(id=None): - print('### mock_filter ###', id) - - def mock_update(updated_values, synchronize_session=False): - print('### mock_update ###', updated_values) - - if 'vim_connection_info' not in updated_values: - return - - compar_updated_values = {} - compar_updated_values['vnf_instance_name'] = "new_instance_name" - compar_updated_values['vnf_instance_description'] = \ - "new_instance_discription" - compar_updated_values['vnf_metadata'] = { - "testkey": "test_value1", "testkey2": "test_value2"} - compar_updated_values['vim_connection_info'] = [ - objects.VimConnectionInfo._from_dict({ - "id": "testid", - "vim_id": "bbb", - "vim_type": "openstack-1A", - "interface_info": {"endpoint": "endpoint11"}, - "access_info": {"username": "xxxxx1", - "region": "region1", - "password": "password1", - "tenant": "tenant1"}}), - objects.VimConnectionInfo._from_dict({ - "id": "testid3", - "vim_id": "ccc", - "vim_type": "openstack-2", - "interface_info": {"endpoint": "endpoint22"}, - "access_info": {"username": "xxxxx", - "region": "region", - "password": "password2", - "tenant": "tenant2"}}), - objects.VimConnectionInfo._from_dict({ - "id": "testid5", - "vim_id": "eee", - "vim_type": "openstack-4"}), - objects.VimConnectionInfo._from_dict({ - "id": "testid7", - "vim_id": "fff", - "vim_type": "openstack-5A", - "interface_info": {"endpoint": "endpoint55"}, - "access_info": {"username": "xxxxx5", - "region": "region5", - "password": "password5", - "tenant": "tenant5"}}) - ] - compar_updated_values['vnfd_id'] = \ - "2c69a161-0000-4b0f-bcf8-391f8fc76600" - compar_updated_values['vnf_provider'] = \ - self.vnf_package.get('vnf_provider') - compar_updated_values['vnf_product_name'] = \ - self.vnf_package.get('vnf_product_name') - compar_updated_values['vnf_software_version'] = \ - self.vnf_package.get('vnf_software_version') - - expected_vci = sorted(compar_updated_values.pop( - 'vim_connection_info'), key=lambda x: x.id) - actual_vci = sorted( - updated_values.pop('vim_connection_info'), - key=lambda x: x.id) - for e, a in zip(expected_vci, actual_vci): - self.assertDictEqual( - e.to_dict(), - a.to_dict()) - - self.assertDictEqual( - compar_updated_values, - updated_values) - - fake_api_model_query = FakeApiModelQuery( - callback_filter_by=mock_filter, callback_update=mock_update) - mock_model_query.return_value = fake_api_model_query - - vnf_lcm_opoccs = {} - - body = {"vnf_instance_name": "new_instance_name", - "vnf_instance_description": "new_instance_discription", - "vnfd_id": "2c69a161-0000-4b0f-bcf8-391f8fc76600", - "vnf_configurable_properties": {"test": "test_value1"}, - "vnfc_info_modifications_delete_ids": ["test1"], - "metadata": {"testkey": "test_value1", - "testkey2": "test_value2"}, - "vim_connection_info": [ - {"id": "testid", - "vim_id": "bbb", - "vim_type": "openstack-1A", - "interface_info": {"endpoint": "endpoint11"}, - "access_info": {"username": "xxxxx1", - "region": "region1", - "password": "password1", - "tenant": "tenant1"}}, - {"id": "testid3", - "vim_type": "openstack-2", - "access_info": {"password": "password2", - "tenant": "tenant2"}}, - {"id": "testid7", - "vim_id": "fff", - "vim_type": "openstack-5A", - "interface_info": {"endpoint": "endpoint55"}, - "access_info": {"username": "xxxxx5", - "region": "region5", - "password": "password5", - "tenant": "tenant5"}}, - ]} + @mock.patch.object(objects.vnf_package.VnfPackage, 'get_by_id') + def test_update(self, mock_get_by_id): + mock_get_by_id.return_value =\ + fakes_vnflcm.return_vnf_package_with_deployment_flavour() + vnf_instance_data = fakes.get_vnf_instance_data( + self.vnf_package.vnfd_id) + vnf_instance = objects.VnfInstance(context=self.context, + **vnf_instance_data) + vnf_instance.create() + vnf_lcm_oppccs = fakes.get_lcm_op_occs_data( + vnf_instance.id) vnf_instance.update( self.context, - vnf_lcm_opoccs, - body, - self.vnf_package, - self.vnf_package.id) + vnf_lcm_oppccs, + self.body_data, + self.vnfd_pkg_data, + vnf_instance_data['vnfd_id']) diff --git a/tacker/tests/unit/vnflcm/fakes.py b/tacker/tests/unit/vnflcm/fakes.py index 6a3fdc182..3f060c83b 100644 --- a/tacker/tests/unit/vnflcm/fakes.py +++ b/tacker/tests/unit/vnflcm/fakes.py @@ -120,6 +120,7 @@ def _model_non_instantiated_vnf_instance(**updates): 'tenant_id': uuidsentinel.tenant_id, 'vnfd_id': uuidsentinel.vnfd_id, 'vnfd_version': '1.0', + 'vnf_pkg_id': uuidsentinel.vnf_pkg_id, 'vnf_metadata': {"key": "value"}} if updates: @@ -204,9 +205,9 @@ def _instantiated_vnf_links(vnf_instance_id): links = { "self": {"href": "/vnflcm/v1/vnf_instances/%s" % vnf_instance_id}, "terminate": {"href": "/vnflcm/v1/vnf_instances/%s/terminate" % - vnf_instance_id}, + vnf_instance_id}, "heal": {"href": "/vnflcm/v1/vnf_instances/%s/heal" % - vnf_instance_id}} + vnf_instance_id}} return links @@ -218,13 +219,15 @@ def _fake_vnf_instance_not_instantiated_response( 'vnfInstanceName': 'Vnf instance name', 'vnfProductName': 'Sample VNF', '_links': { - 'self': {'href': os.path.join('/vnflcm/v1/vnf_instances/', - uuidsentinel.vnf_instance_id)}, + 'self': { + 'href': os.path.join( + '/vnflcm/v1/vnf_instances/', + uuidsentinel.vnf_instance_id)}, 'instantiate': { - 'href': os.path.join('/vnflcm/v1/vnf_instances', - uuidsentinel.vnf_instance_id, 'instantiate') - } - }, + 'href': os.path.join( + '/vnflcm/v1/vnf_instances', + uuidsentinel.vnf_instance_id, + 'instantiate')}}, 'instantiationState': 'NOT_INSTANTIATED', 'vnfProvider': 'Vnf provider', 'vnfdId': uuidsentinel.vnfd_id, @@ -621,7 +624,7 @@ def get_vnfd_dict(image_path=None): {'layer_protocol': 'ipv4', 'l3_protocol_data': {} }]}}, - 'type': 'tosca.nodes.nfv.VnfVirtualLink'}, + 'type': 'tosca.nodes.nfv.VnfVirtualLink'}, 'VL4': {'properties': {'connectivity_type': { 'layer_protocols': ['ipv4']}, 'description': 'Internal virtual link in VNF', diff --git a/tacker/tests/unit/vnflcm/test_controller.py b/tacker/tests/unit/vnflcm/test_controller.py index 7dcd4dad1..0d1bf444f 100644 --- a/tacker/tests/unit/vnflcm/test_controller.py +++ b/tacker/tests/unit/vnflcm/test_controller.py @@ -195,7 +195,7 @@ class TestController(base.TestCase): with mock.patch.object(tacker.db.vnfm.vnfm_db.VNFMPluginDb, 'get_vnfs', return_value=[]): with mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}): + return_value={'VNFM': FakeVNFMPlugin()}): self.controller = controller.VnfLcmController() def tearDown(self): @@ -246,7 +246,7 @@ class TestController(base.TestCase): 'VnfLcmController._create_vnf') @mock.patch.object(objects.vnf_package.VnfPackage, 'save') @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch.object(objects.vnf_instance, '_vnf_instance_create') @mock.patch.object(objects.vnf_package_vnfd.VnfPackageVnfd, 'get_by_id') def test_create_without_name_and_description( @@ -310,8 +310,10 @@ class TestController(base.TestCase): 'expected_type': 'description'} ) @ddt.unpack + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) def test_create_with_invalid_request_body( - self, attribute, value, expected_type): + self, mock_get_service_plugins, attribute, value, expected_type): """value of attribute in body is of invalid type""" body = {"vnfInstanceName": "SampleVnf", "vnfdId": "29c770a3-02bc-4dfc-b4be-eb173ac00567", @@ -500,8 +502,11 @@ class TestController(base.TestCase): self.assertEqual(http_client.BAD_REQUEST, resp.status_code) + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) @ddt.data('PATCH', 'PUT', 'HEAD', 'DELETE') - def test_create_not_allowed_http_method(self, method): + def test_create_not_allowed_http_method(self, method, + mock_get_service_plugins): """Wrong HTTP method""" body = {"vnfdId": uuidsentinel.vnfd_id} req = fake_request.HTTPRequest.blank('/vnf_instances') @@ -544,7 +549,7 @@ class TestController(base.TestCase): self.assertEqual(http_client.BAD_REQUEST, resp.status_code) @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._notification_process') @mock.patch('tacker.api.vnflcm.v1.controller.' @@ -586,7 +591,7 @@ class TestController(base.TestCase): mock_instantiate.assert_called_once() @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._get_vnf') @mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id") @@ -624,7 +629,7 @@ class TestController(base.TestCase): mock_get_vnf.assert_called_once() @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._notification_process') @mock.patch('tacker.api.vnflcm.v1.controller.' @@ -669,7 +674,7 @@ class TestController(base.TestCase): mock_insta_notif_process.assert_called_once() @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._get_vnf') @mock.patch.object(vim_client.VimClient, "get_vim") @@ -715,7 +720,7 @@ class TestController(base.TestCase): mock_get_vnf.assert_called_once() @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._get_vnf') @mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id") @@ -755,7 +760,7 @@ class TestController(base.TestCase): mock_get_vnf.assert_called_once() @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch('tacker.api.vnflcm.v1.controller.VnfLcmController.' '_notification_process') @mock.patch('tacker.api.vnflcm.v1.controller.' @@ -805,7 +810,7 @@ class TestController(base.TestCase): mock_insta_notif_process.assert_called_once() @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._get_vnf') @mock.patch.object(vim_client.VimClient, "get_vim") @@ -851,7 +856,7 @@ class TestController(base.TestCase): mock_get_vnf.assert_called_once() @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._get_vnf') @mock.patch.object(vim_client.VimClient, "get_vim") @@ -898,7 +903,7 @@ class TestController(base.TestCase): mock_get_vnf.assert_called_once() @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._get_vnf') @mock.patch.object(vim_client.VimClient, "get_vim") @@ -938,12 +943,12 @@ class TestController(base.TestCase): mock_get_vnf.assert_called_once() @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._get_vnf') @mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id") - def test_instantiate_incorrect_instantiation_state(self, mock_vnf_by_id, - mock_get_vnf, mock_get_service_plugins): + def test_instantiate_incorrect_instantiation_state( + self, mock_vnf_by_id, mock_get_vnf, mock_get_service_plugins): vnf_instance = fakes.return_vnf_instance_model() vnf_instance.instantiation_state = 'INSTANTIATED' mock_vnf_by_id.return_value = vnf_instance @@ -960,12 +965,15 @@ class TestController(base.TestCase): self.assertEqual(http_client.CONFLICT, resp.status_code) @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._get_vnf') @mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id") - def test_instantiate_incorrect_task_state(self, mock_vnf_by_id, - mock_get_vnf, mock_get_service_plugins): + def test_instantiate_incorrect_task_state( + self, + mock_vnf_by_id, + mock_get_vnf, + mock_get_service_plugins): vnf_instance = fakes.return_vnf_instance_model( task_state=fields.VnfInstanceTaskState.INSTANTIATING) mock_vnf_by_id.return_value = vnf_instance @@ -1001,8 +1009,10 @@ class TestController(base.TestCase): 'expected_type': 'object'}, ) @ddt.unpack + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) def test_instantiate_with_invalid_request_body( - self, attribute, value, expected_type): + self, mock_get_service_plugins, attribute, value, expected_type): body = fakes.get_vnf_instantiation_request_body() req = fake_request.HTTPRequest.blank( '/vnf_instances/%s/instantiate' % uuidsentinel.vnf_instance_id) @@ -1023,7 +1033,10 @@ class TestController(base.TestCase): self.assertEqual(expected_message, exception.msg) - def test_instantiate_without_flavour_id(self): + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) + def test_instantiate_without_flavour_id(self, + mock_get_service_plugins): req = fake_request.HTTPRequest.blank( '/vnf_instances/%s/instantiate' % uuidsentinel.vnf_instance_id) req.body = jsonutils.dump_as_bytes({}) @@ -1037,7 +1050,10 @@ class TestController(base.TestCase): self.assertEqual("'flavourId' is a required property", resp.json['badRequest']['message']) - def test_instantiate_invalid_request_parameter(self): + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) + def test_instantiate_invalid_request_parameter(self, + mock_get_service_plugins): body = {"flavourId": "simple"} req = fake_request.HTTPRequest.blank( '/vnf_instances/%s/instantiate' % uuidsentinel.vnf_instance_id) @@ -1058,7 +1074,10 @@ class TestController(base.TestCase): "('additional_property' was unexpected)", resp.json['badRequest']['message']) - def test_instantiate_with_invalid_uuid(self): + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) + def test_instantiate_with_invalid_uuid(self, + mock_get_service_plugins): req = fake_request.HTTPRequest.blank( '/vnf_instances/%s/instantiate' % constants.INVALID_UUID) body = {"flavourId": "simple"} @@ -1075,7 +1094,7 @@ class TestController(base.TestCase): resp.json['itemNotFound']['message']) @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._get_vnf') @mock.patch.object(objects.VnfInstance, "get_by_id") @@ -1099,8 +1118,11 @@ class TestController(base.TestCase): resp.json['itemNotFound']['message']) mock_get_vnf.assert_called_once() + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) @ddt.data('HEAD', 'PUT', 'DELETE', 'PATCH', 'GET') - def test_instantiate_invalid_http_method(self, method): + def test_instantiate_invalid_http_method(self, method, + mock_get_service_plugins): # Wrong HTTP method body = fakes.get_vnf_instantiation_request_body() req = fake_request.HTTPRequest.blank( @@ -1120,8 +1142,11 @@ class TestController(base.TestCase): res_dict = self.controller.show(req, uuidsentinel.instance_id) self.assertEqual(expected_result, res_dict) + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch.object(objects.VnfInstance, "get_by_id") - def test_show_vnf_instantiated(self, mock_vnf_by_id): + def test_show_vnf_instantiated(self, mock_vnf_by_id, + mock_get_service_plugins): req = fake_request.HTTPRequest.blank( '/vnf_instances/%s' % uuidsentinel.instance_id) mock_vnf_by_id.return_value = fakes.return_vnf_instance( @@ -1131,8 +1156,11 @@ class TestController(base.TestCase): res_dict = self.controller.show(req, uuidsentinel.instance_id) self.assertEqual(expected_result, res_dict) + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id") - def test_show_with_non_existing_vnf_instance(self, mock_vnf_by_id): + def test_show_with_non_existing_vnf_instance(self, mock_vnf_by_id, + mock_get_service_plugins): mock_vnf_by_id.side_effect = exceptions.VnfInstanceNotFound req = fake_request.HTTPRequest.blank( '/vnf_instances/%s' % uuidsentinel.vnf_instance_id) @@ -1145,9 +1173,9 @@ class TestController(base.TestCase): resp.json['itemNotFound']['message']) @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) def test_show_with_invalid_uuid(self, - mock_get_service_plugins): + mock_get_service_plugins): req = fake_request.HTTPRequest.blank( '/vnf_instances/%s' % constants.INVALID_UUID) @@ -1158,10 +1186,10 @@ class TestController(base.TestCase): resp.json['itemNotFound']['message']) @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @ddt.data('HEAD', 'PUT', 'POST') def test_show_invalid_http_method(self, http_method, - mock_get_service_plugins): + mock_get_service_plugins): req = fake_request.HTTPRequest.blank( '/vnf_instances/%s' % constants.UUID) req.headers['Content-Type'] = 'application/json' @@ -1171,7 +1199,7 @@ class TestController(base.TestCase): self.assertEqual(http_client.METHOD_NOT_ALLOWED, resp.status_code) @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._notification_process') @mock.patch('tacker.api.vnflcm.v1.controller.' @@ -1206,7 +1234,7 @@ class TestController(base.TestCase): mock_notification_process.assert_called_once() @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @ddt.data( {'attribute': 'terminationType', 'value': "TEST", 'expected_type': 'enum'}, @@ -1241,7 +1269,10 @@ class TestController(base.TestCase): req, constants.UUID, body=body) self.assertIn(expected_message, exception.msg) - def test_terminate_missing_termination_type(self): + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) + def test_terminate_missing_termination_type(self, + mock_get_service_plugins): body = {'gracefulTerminationTimeout': 10} req = fake_request.HTTPRequest.blank( '/vnf_instances/%s/terminate' % uuidsentinel.vnf_instance_id) @@ -1255,8 +1286,11 @@ class TestController(base.TestCase): self.assertEqual("'terminationType' is a required property", resp.json['badRequest']['message']) + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) @ddt.data('GET', 'HEAD', 'PUT', 'DELETE', 'PATCH') - def test_terminate_invalid_http_method(self, method): + def test_terminate_invalid_http_method(self, method, + mock_get_service_plugins): # Wrong HTTP method body = {'terminationType': 'GRACEFUL', 'gracefulTerminationTimeout': 10} @@ -1269,12 +1303,12 @@ class TestController(base.TestCase): self.assertEqual(http_client.METHOD_NOT_ALLOWED, resp.status_code) @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._get_vnf') @mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id") - def test_terminate_non_existing_vnf_instance(self, mock_vnf_by_id, - mock_get_vnf, mock_get_service_plugins): + def test_terminate_non_existing_vnf_instance( + self, mock_vnf_by_id, mock_get_vnf, mock_get_service_plugins): body = {'terminationType': 'GRACEFUL', 'gracefulTerminationTimeout': 10} mock_vnf_by_id.side_effect = exceptions.VnfInstanceNotFound @@ -1293,12 +1327,12 @@ class TestController(base.TestCase): mock_get_vnf.assert_called_once() @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._get_vnf') @mock.patch.object(objects.vnf_instance, "_vnf_instance_get_by_id") - def test_terminate_incorrect_instantiation_state(self, mock_vnf_by_id, - mock_get_vnf, mock_get_service_plugins): + def test_terminate_incorrect_instantiation_state( + self, mock_vnf_by_id, mock_get_vnf, mock_get_service_plugins): mock_vnf_by_id.return_value = fakes.return_vnf_instance() body = {"terminationType": "FORCEFUL"} req = fake_request.HTTPRequest.blank( @@ -1318,12 +1352,15 @@ class TestController(base.TestCase): mock_get_vnf.assert_called_once() @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._get_vnf') @mock.patch.object(objects.VnfInstance, "get_by_id") - def test_terminate_incorrect_task_state(self, mock_vnf_by_id, - mock_get_vnf, mock_get_service_plugins): + def test_terminate_incorrect_task_state( + self, + mock_vnf_by_id, + mock_get_vnf, + mock_get_service_plugins): vnf_instance = fakes.return_vnf_instance( instantiated_state=fields.VnfInstanceState.INSTANTIATED, task_state=fields.VnfInstanceTaskState.TERMINATING) @@ -1346,7 +1383,7 @@ class TestController(base.TestCase): mock_get_vnf.assert_called_once() @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._notification_process') @mock.patch('tacker.api.vnflcm.v1.controller.' @@ -1376,7 +1413,10 @@ class TestController(base.TestCase): self.assertEqual(http_client.ACCEPTED, resp.status_code) mock_rpc_heal.assert_called_once() - def test_heal_cause_max_length_exceeded(self): + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) + def test_heal_cause_max_length_exceeded(self, + mock_get_service_plugins): body = {'cause': 'A' * 256} req = fake_request.HTTPRequest.blank( '/vnf_instances/%s/heal' % uuidsentinel.vnf_instance_id) @@ -1388,14 +1428,18 @@ class TestController(base.TestCase): self.assertEqual(http_client.BAD_REQUEST, resp.status_code) @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._notification_process') @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._get_vnf') @mock.patch.object(objects.VnfInstance, "get_by_id") - def test_heal_incorrect_instantiated_state(self, mock_vnf_by_id, - mock_get_vnf, mock_notif, mock_get_service_plugins): + def test_heal_incorrect_instantiated_state( + self, + mock_vnf_by_id, + mock_get_vnf, + mock_notif, + mock_get_service_plugins): vnf_instance_obj = fakes.return_vnf_instance( fields.VnfInstanceState.NOT_INSTANTIATED) mock_vnf_by_id.return_value = vnf_instance_obj @@ -1416,14 +1460,14 @@ class TestController(base.TestCase): resp.json['conflictingRequest']['message']) @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._notification_process') @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._get_vnf') @mock.patch.object(objects.VnfInstance, "get_by_id") def test_heal_incorrect_task_state(self, mock_vnf_by_id, mock_get_vnf, - mock_notif, mock_get_service_plugins): + mock_notif, mock_get_service_plugins): vnf_instance_obj = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED, task_state=fields.VnfInstanceTaskState.HEALING) @@ -1445,14 +1489,18 @@ class TestController(base.TestCase): resp.json['conflictingRequest']['message']) @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._notification_process') @mock.patch('tacker.api.vnflcm.v1.controller.' 'VnfLcmController._get_vnf') @mock.patch.object(objects.VnfInstance, "get_by_id") - def test_heal_with_invalid_vnfc_id(self, mock_vnf_by_id, - mock_get_vnf, mock_notif, mock_get_service_plugins): + def test_heal_with_invalid_vnfc_id( + self, + mock_vnf_by_id, + mock_get_vnf, + mock_notif, + mock_get_service_plugins): vnf_instance_obj = fakes.return_vnf_instance( fields.VnfInstanceState.INSTANTIATED) mock_vnf_by_id.return_value = vnf_instance_obj @@ -1470,11 +1518,14 @@ class TestController(base.TestCase): self.assertEqual(http_client.BAD_REQUEST, resp.status_code) expected_msg = "Vnfc id %s not present in vnf instance %s" self.assertEqual(expected_msg % (uuidsentinel.vnfc_instance_id, - uuidsentinel.vnf_instance_id), + uuidsentinel.vnf_instance_id), resp.json['badRequest']['message']) + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) @ddt.data('HEAD', 'PUT', 'DELETE', 'PATCH', 'GET') - def test_heal_invalid_http_method(self, method): + def test_heal_invalid_http_method(self, method, + mock_get_service_plugins): body = {} req = fake_request.HTTPRequest.blank( '/vnf_instances/%s/heal' % uuidsentinel.vnf_instance_id) @@ -1496,8 +1547,10 @@ class TestController(base.TestCase): 'expected_type': 'array'}, ) @ddt.unpack + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) def test_heal_with_invalid_request_body( - self, attribute, value, expected_type): + self, mock_get_service_plugins, attribute, value, expected_type): body = {} req = fake_request.HTTPRequest.blank( '/vnf_instances/29c770a3-02bc-4dfc-b4be-eb173ac00567/heal') @@ -1537,8 +1590,11 @@ class TestController(base.TestCase): resp = self.controller.index(req) self.assertEqual([], resp) + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) @ddt.data('HEAD', 'PUT', 'DELETE', 'PATCH') - def test_index_invalid_http_method(self, method): + def test_index_invalid_http_method(self, method, + mock_get_service_plugins): # Wrong HTTP method req = fake_request.HTTPRequest.blank( '/vnf_instances') @@ -1566,8 +1622,11 @@ class TestController(base.TestCase): self.assertEqual(http_client.NO_CONTENT, resp.status_code) + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch.object(objects.VnfInstance, "get_by_id") - def test_delete_with_non_existing_vnf_instance(self, mock_vnf_by_id): + def test_delete_with_non_existing_vnf_instance(self, mock_vnf_by_id, + mock_get_service_plugins): req = fake_request.HTTPRequest.blank( '/vnf_instances/%s' % uuidsentinel.vnf_instance_id) req.method = 'DELETE' @@ -1582,7 +1641,9 @@ class TestController(base.TestCase): uuidsentinel.vnf_instance_id, resp.json['itemNotFound']['message']) - def test_delete_with_invalid_uuid(self): + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) + def test_delete_with_invalid_uuid(self, mock_get_service_plugins): req = fake_request.HTTPRequest.blank( '/vnf_instances/%s' % constants.INVALID_UUID) req.method = 'DELETE' @@ -1595,8 +1656,11 @@ class TestController(base.TestCase): constants.INVALID_UUID, resp.json['itemNotFound']['message']) + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch.object(objects.VnfInstance, "get_by_id") - def test_delete_with_incorrect_instantiation_state(self, mock_vnf_by_id): + def test_delete_with_incorrect_instantiation_state( + self, mock_vnf_by_id, mock_get_service_plugins): req = fake_request.HTTPRequest.blank( '/vnf_instances/%s' % uuidsentinel.vnf_instance_id) req.method = 'DELETE' @@ -1615,8 +1679,11 @@ class TestController(base.TestCase): self.assertEqual(expected_msg % uuidsentinel.vnf_instance_id, resp.json['conflictingRequest']['message']) + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch.object(objects.VnfInstance, "get_by_id") - def test_delete_with_incorrect_task_state(self, mock_vnf_by_id): + def test_delete_with_incorrect_task_state(self, mock_vnf_by_id, + mock_get_service_plugins): req = fake_request.HTTPRequest.blank( '/vnf_instances/%s' % uuidsentinel.vnf_instance_id) req.method = 'DELETE' @@ -1851,7 +1918,7 @@ class TestController(base.TestCase): self.assertEqual(http_client.NOT_FOUND, resp.status_code) @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch.object(objects.VNF, "vnf_index_list") @mock.patch.object(objects.VnfInstanceList, "vnf_instance_list") @mock.patch.object(objects.VnfPackageVnfd, 'get_vnf_package_vnfd') @@ -1892,7 +1959,7 @@ class TestController(base.TestCase): mock_update.assert_called_once() @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch.object(objects.VNF, "vnf_index_list") def test_update_vnf_none_vnf_data( self, @@ -1923,7 +1990,7 @@ class TestController(base.TestCase): self.assertEqual(res.text, resp.text) @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch.object(objects.VNF, "vnf_index_list") def test_update_vnf_status_err( self, @@ -1951,13 +2018,13 @@ class TestController(base.TestCase): msg = _("VNF %(id)s status is %(state)s") % { "id": constants.UUID, "state": "ERROR"} res = self._make_problem_detail(msg % - {"state": "ERROR"}, 409, 'Conflict') + {"state": "ERROR"}, 409, 'Conflict') resp = req.get_response(self.app) self.assertEqual(res.text, resp.text) @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch.object(objects.VNF, "vnf_index_list") @mock.patch.object(objects.VnfInstanceList, "vnf_instance_list") def test_update_vnf_none_instance_data( @@ -1985,22 +2052,23 @@ class TestController(base.TestCase): req.method = 'PATCH' vnf_data = fakes._get_vnf() - msg = _("Can not find requested vnf instance data: %s") % vnf_data.get( + msg = ("Can not find requested vnf instance data: %s") % vnf_data.get( 'vnfd_id') res = self._make_problem_detail(msg, 404, title='Not Found') resp = req.get_response(self.app) self.assertEqual(res.text, resp.text) + @ddt.data('vnfdId', 'vnfPkgId') @mock.patch.object(TackerManager, 'get_service_plugins', - return_value={'VNFM': FakeVNFMPlugin()}) + return_value={'VNFM': FakeVNFMPlugin()}) @mock.patch.object(objects.VNF, "vnf_index_list") @mock.patch.object(objects.VnfInstanceList, "vnf_instance_list") @mock.patch.object(objects.VnfPackageVnfd, 'get_vnf_package_vnfd') - @mock.patch.object(VNFLcmRPCAPI, "update") + @mock.patch.object(VNFLcmRPCAPI, "update_vnf_instance_content") def test_update_vnf_none_vnfd_data( - self, - mock_update, + self, input_id, + mock_update_vnf_instance_content, mock_vnf_package_vnf_get_vnf_package_vnfd, mock_vnf_instance_list, mock_vnf_index_list, @@ -2011,15 +2079,12 @@ class TestController(base.TestCase): fields.VnfInstanceState.INSTANTIATED) mock_vnf_package_vnf_get_vnf_package_vnfd.return_value = "" - body = {"vnfInstanceName": "new_instance_name", - "vnfInstanceDescription": "new_instance_discription", - "vnfdId": "2c69a161-0000-4b0f-bcf8-391f8fc76600", - "vnfConfigurableProperties": { - "test": "test_value" - }, - "vnfcInfoModificationsDeleteIds": ["test1"], - "metadata": {"testkey": "test_value"}, - "vimConnectionInfo": {"id": "testid"}} + body = {"vnfInstanceName": "new_instance_name\ + ", "vnfInstanceDescription": "new_instance_discription\ + ", input_id: "2c69a161-0000-4b0f-bcf8-391f8fc76600\ + ", "vnfConfigurableProperties\ + ": {"test": "test_value\ + "}, "vnfcInfoModificationsDeleteIds": ["test1"]} req = fake_request.HTTPRequest.blank( '/vnf_instances/%s' % constants.UUID) req.body = jsonutils.dump_as_bytes(body) @@ -2027,8 +2092,8 @@ class TestController(base.TestCase): req.method = 'PATCH' fakes._get_vnf() - msg = _("Can not find requested vnf package vnfd: %s") %\ - body.get('vnfdId') + msg = ("Can not find requested vnf package vnfd: %s") %\ + body.get(input_id) res = self._make_problem_detail(msg, 400, 'Bad Request') resp = req.get_response(self.app)