diff --git a/api-ref/source/v1/vnflcm.inc b/api-ref/source/v1/vnflcm.inc index d233ea1c6..5a5da373a 100644 --- a/api-ref/source/v1/vnflcm.inc +++ b/api-ref/source/v1/vnflcm.inc @@ -616,7 +616,7 @@ Request Example Modify a VNF instance ======================== -.. rest_method:: POST /vnflcm/v1/vnf_instances/{vnfInstanceId} +.. rest_method:: PATCH /vnflcm/v1/vnf_instances/{vnfInstanceId} This method modifies an "Individual VNF instance" resource. diff --git a/tacker/api/vnflcm/v1/controller.py b/tacker/api/vnflcm/v1/controller.py index 2e468256e..d4239b83e 100644 --- a/tacker/api/vnflcm/v1/controller.py +++ b/tacker/api/vnflcm/v1/controller.py @@ -802,7 +802,7 @@ class VnfLcmController(wsgi.Controller): return self._view_builder.show_lcm_op_occs(vnf_lcm_op_occs) - @wsgi.response(http_client.OK) + @wsgi.response(http_client.ACCEPTED) @wsgi.expected_errors((http_client.FORBIDDEN, http_client.NOT_FOUND)) def update(self, request, id, body): context = request.environ['tacker.context'] @@ -906,7 +906,7 @@ class VnfLcmController(wsgi.Controller): vnf_lcm_opoccs = { 'vnf_instance_id': id, 'id': op_occs_uuid, - 'state_entered_time': vnf_data.get('updated_at'), + 'state_entered_time': timeutils.utcnow(), 'operationParams': str(body)} self.rpc_api.update( diff --git a/tacker/conductor/conductor_server.py b/tacker/conductor/conductor_server.py index 6a52d8d28..4a963b429 100644 --- a/tacker/conductor/conductor_server.py +++ b/tacker/conductor/conductor_server.py @@ -2113,7 +2113,7 @@ class Conductor(manager.Manager): lcm_op_obj.operation = fields.InstanceOperation.MODIFY_INFO lcm_op_obj.is_automatic_invocation = 0 lcm_op_obj.is_cancel_pending = 0 - lcm_op_obj.operationParams = vnf_lcm_opoccs.get('operationParams') + lcm_op_obj.operation_params = vnf_lcm_opoccs.get('operationParams') try: lcm_op_obj.create() @@ -2161,7 +2161,9 @@ class Conductor(manager.Manager): vnfd_pkg_data) else: changed_info = objects.vnf_lcm_op_occs.VnfInfoModifications() + if body_data.get('vnf_instance_name'): changed_info.vnf_instance_name = body_data.get('vnf_instance_name') + if body_data.get('vnf_instance_description'): changed_info.vnf_instance_description = body_data.get( 'vnf_instance_description') diff --git a/tacker/objects/vnf_lcm_op_occs.py b/tacker/objects/vnf_lcm_op_occs.py index 19db410fb..4c5e5966b 100644 --- a/tacker/objects/vnf_lcm_op_occs.py +++ b/tacker/objects/vnf_lcm_op_occs.py @@ -854,19 +854,24 @@ class VnfInfoModifications(base.TackerObject, return obj def to_dict(self): - return { - 'vnf_instance_name': self.vnf_instance_name, - 'vnf_instance_description': self.vnf_instance_description, - 'metadata': self.metadata, - 'vim_connection_info': self.vim_connection_info, - 'vim_connection_info_delete_ids': - self.vim_connection_info_delete_ids, - 'vnf_pkg_id': self.vnf_pkg_id, - 'vnfd_id': self.vnfd_id, - 'vnf_provider': self.vnf_provider, - 'vnf_product_name': self.vnf_product_name, - 'vnf_software_version': self.vnf_software_version, - 'vnfd_version': self.vnfd_version} + """For the attributes of this class, if an attribute exists and is not + + null, it means that the attribute has been modified. This method + + returns a dictionary containing the modified attributes. + """ + dct = {} + for field in self.fields: + if field in self and getattr(self, field): + value = getattr(self, field) + # Since the type of vim_connection_info is ListOfObjectsField, + # the objects in vim_connection_info also need to be converted + # into dictionary, otherwise an error will occur + # when serialized. + if field == "vim_connection_info": + value = [vim_conn.to_dict() for vim_conn in value] + dct[field] = value + return dct @base.TackerObjectRegistry.register diff --git a/tacker/tests/unit/conductor/test_conductor_server.py b/tacker/tests/unit/conductor/test_conductor_server.py index eb7696ab4..74f1470f2 100644 --- a/tacker/tests/unit/conductor/test_conductor_server.py +++ b/tacker/tests/unit/conductor/test_conductor_server.py @@ -158,8 +158,8 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): 'state_entered_time': datetime.datetime( 1900, 1, 1, 1, 1, 1, tzinfo=iso8601.UTC), - 'operationParams': { - "key": "value"}} + 'operationParams': 'operationParams' + } return vnf_lcm_opoccs def _create_vnfd_pkg_data(self): @@ -2974,6 +2974,50 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase): 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_without_vnf_instance_name(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.body_data.pop('vnf_instance_name') + self.conductor.update( + self.context, + self.vnf_lcm_opoccs, + 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_without_vnf_instance_description(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.body_data.pop('vnf_instance_description') + self.conductor.update( + self.context, + self.vnf_lcm_opoccs, + self.body_data, + self.vnfd_pkg_data, + vnfd_id) + def test_update_vim(self): vim_id = uuidsentinel.vim_id status = "REACHABLE" diff --git a/tacker/tests/unit/vnflcm/fakes.py b/tacker/tests/unit/vnflcm/fakes.py index 2d6d12894..6ba84e435 100644 --- a/tacker/tests/unit/vnflcm/fakes.py +++ b/tacker/tests/unit/vnflcm/fakes.py @@ -968,9 +968,18 @@ def vnflcm_fail_check_added_params(error_point=7): vim_level_resource_type="OS::Neutron::Net"), ext_link_ports=[ext_link_port_info] ) + vim_connection_info = {"id": 'f8c35bd0-4d67-4436-9f11-14b8a84c92aa', + "vim_id": 'f8c35bd0-4d67-4436-9f11-14b8a84c92aa', + "vim_type": 'openstack', + "access_info": {"key1": 'value1', "key2": 'value2'}} changed_info_values = objects.VnfInfoModifications( vnf_instance_name="fake_name", vnf_instance_description="fake_vnf_instance_description", + metadata={'key': 'value'}, + vim_connection_info=[VimConnectionInfo(**vim_connection_info)], + vim_connection_info_delete_ids=[ + 'f8c35bd0-4d67-4436-9f11-14b8a84c92bb'], + vnf_pkg_id='f26f181d-7891-4720-b022-b074ec1733ef', vnfd_id="f26f181d-7891-4720-b022-b074ec1733ef", vnf_provider="fake_vnf_provider", vnf_product_name="fake_vnf_product_name", @@ -1413,10 +1422,15 @@ VNFLCMOPOCC_RESPONSE = { }] }, 'changedInfo': { - 'metadata': {}, - 'vimConnectionInfo': [], - 'vimConnectionInfoDeleteIds': [], - 'vnfPkgId': None, + 'metadata': {'key': 'value'}, + 'vimConnectionInfo': [ + {"id": 'f8c35bd0-4d67-4436-9f11-14b8a84c92aa', + "vimId": 'f8c35bd0-4d67-4436-9f11-14b8a84c92aa', + "vimType": 'openstack', + 'interfaceInfo': {}, + "accessInfo": {"key1": 'value1', "key2": 'value2'}}], + 'vimConnectionInfoDeleteIds': ['f8c35bd0-4d67-4436-9f11-14b8a84c92bb'], + 'vnfPkgId': 'f26f181d-7891-4720-b022-b074ec1733ef', 'vnfInstanceName': 'fake_name', 'vnfInstanceDescription': "fake_vnf_instance_description", 'vnfdId': 'f26f181d-7891-4720-b022-b074ec1733ef', @@ -1528,11 +1542,20 @@ def fake_vnf_lcm_op_occs(): } resource_changes_obj = objects.ResourceChanges(**resource_changes) + vim_connection_info = { + "id": 'f8c35bd0-4d67-4436-9f11-14b8a84c92aa', + "vim_id": 'f8c35bd0-4d67-4436-9f11-14b8a84c92aa', + "vim_type": 'openstack', + "access_info": {"key1": 'value1', "key2": 'value2'}} changed_info = { "vnf_instance_name": "fake_name", "vnf_instance_description": "fake_vnf_instance_description", - "metadata": {}, + 'metadata': {'key': 'value'}, + 'vim_connection_info': [VimConnectionInfo(**vim_connection_info)], + 'vim_connection_info_delete_ids': [ + 'f8c35bd0-4d67-4436-9f11-14b8a84c92bb'], + 'vnf_pkg_id': 'f26f181d-7891-4720-b022-b074ec1733ef', "vnfd_id": "f26f181d-7891-4720-b022-b074ec1733ef", "vnf_provider": "fake_vnf_provider", "vnf_product_name": "fake_vnf_product_name",