From 88b05dd155545d1ed2bc8af21d73a5906ff3bc8f Mon Sep 17 00:00:00 2001 From: Aldinson Esto Date: Tue, 9 Feb 2021 03:05:04 +0900 Subject: [PATCH] Add response information for Individual Subscription Response information was added to Individual Subscription. Added data is supported in POST Subscription patch. So, we added UT test code for supporting this API and updated inc file to include the additional response parameters. Implements: blueprint support-fundamental-lcm Spec: https://specs.openstack.org/openstack/tacker-specs/specs/wallaby/support-fundamental-vnf-lcm-based-on-ETSI-NFV.html Change-Id: I6e5d10a68b34f5e78e6d56d2aba5646b272e54d0 --- api-ref/source/v1/parameters_vnflcm.yaml | 7 ++ .../vnflcm/show-subscription-response.json | 64 +++++++++++++++---- api-ref/source/v1/vnflcm.inc | 2 + tacker/api/views/vnf_lcm.py | 3 + tacker/tests/unit/vnflcm/fakes.py | 55 +++++++++++++++- tacker/tests/unit/vnflcm/test_controller.py | 57 +++++++++++++++++ 6 files changed, 172 insertions(+), 16 deletions(-) diff --git a/api-ref/source/v1/parameters_vnflcm.yaml b/api-ref/source/v1/parameters_vnflcm.yaml index 55eba26dc..726f23c60 100644 --- a/api-ref/source/v1/parameters_vnflcm.yaml +++ b/api-ref/source/v1/parameters_vnflcm.yaml @@ -655,6 +655,13 @@ filter_operation_types: in: body required: false type: string +filter_vnf_instance_subscription_filter: + description: | + This type represents subscription filter + criteria to match VNF instances. + in: body + required: false + type: object fixed_addresses: description: | Fixed addresses to assign (from the subnet defined by "subnetId" diff --git a/api-ref/source/v1/samples/vnflcm/show-subscription-response.json b/api-ref/source/v1/samples/vnflcm/show-subscription-response.json index b8e6df5b8..34f99628a 100644 --- a/api-ref/source/v1/samples/vnflcm/show-subscription-response.json +++ b/api-ref/source/v1/samples/vnflcm/show-subscription-response.json @@ -1,14 +1,52 @@ -{ - "id": "76057f8e65ab37fb82d9382dfc3f3c8b", - "filter": { - "notificationTypes": [ - "VnfLcmOperationOccurrenceNotification" - ] - }, - "callbackUri": "http://sample1.com/notification", - "_links": { - "self": { - "href": "https://sample1.com/vnflcm/v1/subscriptions/76057f8e65ab37fb82d9382dfc3f3c8b" - } - } +{ + "id": "76057f8e65ab37fb82d9382dfc3f3c8b", + "filter": { + "vnfInstanceSubscriptionFilter": { + "vnfdIds": [], + "vnfProductsFromProviders": { + "vnfProvider": "Vnf Provider 1", + "vnfProducts": [ + { + "vnfProductName": "Vnf Product 1", + "versions": [ + { + "vnfSoftwareVersion": "v1", + "vnfdVersions": [ + "vnfd.v1.1" + ] + } + ] + } + ] + } + }, + "notificationTypes": [ + "VnfLcmOperationOccurrenceNotification", + "VnfIdentifierCreationNotification", + "VnfIdentifierDeletionNotification" + ], + "operationTypes": [ + "INSTANTIATE", + "SCALE", + "TERMINATE", + "HEAL", + "CHANGE_EXT_CONN", + "MODIFY_INFO" + ], + "operationStates": [ + "STARTING", + "PROCESSING", + "COMPLETED", + "FAILED_TEMP", + "FAILED", + "ROLLING_BACK", + "ROLLED_BACK" + ] + }, + "callbackUri": "http://sample1.com/notification", + "_links": { + "self": { + "href": "https://sample1.com/vnflcm/v1/subscriptions/76057f8e65ab37fb82d9382dfc3f3c8b" + } + } } \ No newline at end of file diff --git a/api-ref/source/v1/vnflcm.inc b/api-ref/source/v1/vnflcm.inc index 64017edc7..d233ea1c6 100644 --- a/api-ref/source/v1/vnflcm.inc +++ b/api-ref/source/v1/vnflcm.inc @@ -1258,8 +1258,10 @@ Response Parameters - id: subscription_id_response - filter: filter + - vnfInstanceSubscriptionFilter: filter_vnf_instance_subscription_filter - notificationTypes: filter_notification_types - operationTypes: filter_operation_types + - operationStates: filter_operation_states - callbackUri: callback_uri - _links: vnf_instance_links diff --git a/tacker/api/views/vnf_lcm.py b/tacker/api/views/vnf_lcm.py index c951a205e..8f1fb0fae 100644 --- a/tacker/api/views/vnf_lcm.py +++ b/tacker/api/views/vnf_lcm.py @@ -282,6 +282,9 @@ class ViewBuilder(base.BaseViewBuilder): return self._subscription_filter( vnf_lcm_subscriptions, nextpage_opaque_marker, paging) + # TODO(esto.aln): To remove show subscription related processing + # in vnf_lcm.py. Current processing for show subscription is in + # vnf_subscriptions.py. def subscription_show(self, vnf_lcm_subscriptions): return self._get_vnf_lcm_subscription(vnf_lcm_subscriptions) diff --git a/tacker/tests/unit/vnflcm/fakes.py b/tacker/tests/unit/vnflcm/fakes.py index 9a452020f..4c9015e78 100644 --- a/tacker/tests/unit/vnflcm/fakes.py +++ b/tacker/tests/unit/vnflcm/fakes.py @@ -16,6 +16,7 @@ from copy import deepcopy import datetime import iso8601 +import json import os import webob @@ -1692,10 +1693,27 @@ def _fake_subscription_obj(**updates): "vnfInstanceNames": ["Vnf Name 1"] }, "notificationTypes": [ - "VnfLcmOperationOccurrenceNotification" + "VnfLcmOperationOccurrenceNotification", + "VnfIdentifierCreationNotification", + "VnfIdentifierDeletionNotification" ], - "operationTypes": ["INSTANTIATE"], - "operationStates": ["STARTING"] + "operationTypes": [ + "INSTANTIATE", + "SCALE", + "TERMINATE", + "HEAL", + "CHANGE_EXT_CONN", + "MODIFY_INFO" + ], + "operationStates": [ + "STARTING", + "PROCESSING", + "COMPLETED", + "FAILED_TEMP", + "FAILED", + "ROLLING_BACK", + "ROLLED_BACK" + ] }, 'callback_uri': 'http://localhost/sample_callback_uri'} @@ -1713,3 +1731,34 @@ def return_subscription_object(**updates): def return_vnf_subscription_list(**updates): vnc_lcm_subscription = return_subscription_object(**updates) return [vnc_lcm_subscription] + + +def _subscription_links(subscription_dict): + links = { + "_links": { + "self": { + "href": "%(endpoint)s/vnflcm/v1/subscriptions/%(id)s" + % {'id': subscription_dict['id'], + 'endpoint': CONF.vnf_lcm.endpoint_url} + } + } + } + subscription_dict.update(links) + + return subscription_dict + + +def return_subscription_obj(**updates): + subscription = _fake_subscription_obj(**updates) + subscription['filter'] = json.dumps(subscription['filter']) + obj = objects.LccnSubscriptionRequest(**subscription) + + return obj + + +def fake_subscription_response(**updates): + data = _fake_subscription_obj(**updates) + data = utils.convert_snakecase_to_camelcase(data) + data = _subscription_links(data) + + return data diff --git a/tacker/tests/unit/vnflcm/test_controller.py b/tacker/tests/unit/vnflcm/test_controller.py index 9950dcb18..99f06ec02 100644 --- a/tacker/tests/unit/vnflcm/test_controller.py +++ b/tacker/tests/unit/vnflcm/test_controller.py @@ -3943,6 +3943,27 @@ class TestController(base.TestCase): resp = req.get_response(self.app) self.assertEqual(500, resp.status_code) + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': + test_nfvo_plugin.FakeVNFMPlugin()}) + @mock.patch.object(objects.LccnSubscriptionRequest, + "vnf_lcm_subscriptions_show") + def test_subscription_show(self, mock_get_subscription, + mock_get_service_plugins): + mock_get_subscription.return_value =\ + fakes.return_subscription_obj() + + req = fake_request.HTTPRequest.blank( + '/subscriptions/%s' % uuidsentinel.subscription_id) + req.method = 'GET' + + resp = req.get_response(self.app) + + expected_vnf = fakes.fake_subscription_response() + + self.assertEqual(http_client.OK, resp.status_code) + self.assertEqual(expected_vnf, resp.json) + @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': test_nfvo_plugin.FakeVNFMPlugin()}) @@ -3999,6 +4020,26 @@ class TestController(base.TestCase): else: self.assertEqual(expected_result, resp.json) + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': + test_nfvo_plugin.FakeVNFMPlugin()}) + @mock.patch.object(objects.LccnSubscriptionRequest, + "vnf_lcm_subscriptions_show") + def test_subscription_show_not_found(self, mock_get_subscription, + mock_get_service_plugins): + req = fake_request.HTTPRequest.blank( + '/subscriptions/%s' % uuidsentinel.subscription_id) + req.method = 'GET' + + mock_get_subscription.return_value = None + + msg = _("Can not find requested vnf lcm subscriptions: %s" + % uuidsentinel.subscription_id) + res = self._make_problem_detail(msg, 404, title='Not Found') + + resp = req.get_response(self.app) + self.assertEqual(res.text, resp.text) + @mock.patch.object(TackerManager, 'get_service_plugins', return_value={'VNFM': test_nfvo_plugin.FakeVNFMPlugin()}) @@ -4011,3 +4052,19 @@ class TestController(base.TestCase): resp = req.get_response(self.app) self.assertEqual(400, resp.status_code) + + @mock.patch.object(TackerManager, 'get_service_plugins', + return_value={'VNFM': + test_nfvo_plugin.FakeVNFMPlugin()}) + @mock.patch.object(objects.LccnSubscriptionRequest, + "vnf_lcm_subscriptions_show") + def test_subscription_show_error(self, mock_get_subscription, + mock_get_service_plugins): + req = fake_request.HTTPRequest.blank( + '/subscriptions/%s' % uuidsentinel.subscription_id) + req.method = 'GET' + + mock_get_subscription.side_effect = Exception + + resp = req.get_response(self.app) + self.assertEqual(500, resp.status_code)