From 261eb147ac54ecfb9b41c643658e1f07c83b4401 Mon Sep 17 00:00:00 2001 From: laili Date: Thu, 13 Sep 2018 20:13:29 +0800 Subject: [PATCH] Add a subscription api on gvnfmdriver. Add serializers, view, and tests supscription. Change-Id: I64cf560520038d9396c810307ac022d303f9ddfe Issue-ID: VFC-1118 Signed-off-by: laili --- .../interfaces/serializers/lccn_subscription.py | 47 +++++++++++++++++ .../serializers/lccn_subscription_request.py | 34 ++++++++++++ gvnfmadapter/driver/interfaces/tests.py | 61 +++++++++++++++++++++- gvnfmadapter/driver/interfaces/urls.py | 19 ++++--- gvnfmadapter/driver/interfaces/views.py | 44 ++++++++++++++++ 5 files changed, 193 insertions(+), 12 deletions(-) create mode 100644 gvnfmadapter/driver/interfaces/serializers/lccn_subscription.py create mode 100644 gvnfmadapter/driver/interfaces/serializers/lccn_subscription_request.py diff --git a/gvnfmadapter/driver/interfaces/serializers/lccn_subscription.py b/gvnfmadapter/driver/interfaces/serializers/lccn_subscription.py new file mode 100644 index 0000000..829c927 --- /dev/null +++ b/gvnfmadapter/driver/interfaces/serializers/lccn_subscription.py @@ -0,0 +1,47 @@ +# Copyright 2018 ZTE Corporation. +# +# 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 rest_framework import serializers + +from driver.interfaces.serializers.link import LinkSerializer +from driver.interfaces.serializers.lccn_filter import LifeCycleChangeNotificationsFilterSerializer + + +class _LinkSerializer(serializers.Serializer): + self = LinkSerializer( + help_text="URI of this resource.", + required=True, + allow_null=False) + + +class LccnSubscriptionSerializer(serializers.Serializer): + id = serializers.CharField( + help_text="Identifier of this subscription resource.", + max_length=255, + required=True + ) + callbackUri = serializers.CharField( + help_text="The URI of the endpoint to send the notification to.", + max_length=255, + required=True + ) + filter = LifeCycleChangeNotificationsFilterSerializer( + help_text="Filter settings for this subscription, to define the " + + "of all notifications this subscription relates to.", + required=False + ) + _links = _LinkSerializer( + help_text="Links to resources related to this resource.", + required=True + ) diff --git a/gvnfmadapter/driver/interfaces/serializers/lccn_subscription_request.py b/gvnfmadapter/driver/interfaces/serializers/lccn_subscription_request.py new file mode 100644 index 0000000..88797bc --- /dev/null +++ b/gvnfmadapter/driver/interfaces/serializers/lccn_subscription_request.py @@ -0,0 +1,34 @@ +# Copyright 2018 ZTE Corporation. +# +# 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 rest_framework import serializers + +from driver.interfaces.serializers.lccn_filter import LifeCycleChangeNotificationsFilterSerializer +from driver.interfaces.serializers.subscription_authentication import SubscriptionAuthenticationSerializer + +class LccnSubscriptionRequestSerializer(serializers.Serializer): + callbackUri = serializers.URLField( + help_text="The URI of the endpoint to send the notification to.", + required=True, + allow_null=False) + filter = LifeCycleChangeNotificationsFilterSerializer( + help_text="Filter settings for the subscription, to define the subset of all " + + "notifications this subscription relates to.", + required=False, + allow_null=True) + authentication = SubscriptionAuthenticationSerializer( + help_text="Authentication parameters to configure the use of Authorization when sending " + + "notifications corresponding to this subscription.", + required=False, + allow_null=True) diff --git a/gvnfmadapter/driver/interfaces/tests.py b/gvnfmadapter/driver/interfaces/tests.py index 9c50466..4d58137 100644 --- a/gvnfmadapter/driver/interfaces/tests.py +++ b/gvnfmadapter/driver/interfaces/tests.py @@ -40,7 +40,7 @@ class InterfacesTest(TestCase): 'vnfmId': 'b0797c9b-3da9-459c-b25c-3813e9d8fd70', 'password': 'admin', 'type': 'gvnfmdriver', - 'createTime': '2016-10-3111: 08: 39', + 'createTime': '2016-10-3T11:08:39', 'description': '' } create_vnf_resp = { @@ -583,7 +583,7 @@ class InterfacesTest(TestCase): "url": "http://10.74.44.11", "userName": "admin", "password": "admin", - "createTime": "2016-07-06 15:33:18" + "createTime": "2016-07-06T15:33:18" } dummy_single_vnf_lcm_op = { "id": vnfLcmOpOccId, @@ -633,3 +633,60 @@ class InterfacesTest(TestCase): mock_call_req.return_value = [1, json.JSONEncoder().encode({}), status.HTTP_500_INTERNAL_SERVER_ERROR] resp = self.client.get("/api/gvnfmdriver/v1/%s/vnf_lcm_op_occs/%s" % (vnfm_info['vnfmId'], vnfLcmOpOccId)) self.assertEqual(status.HTTP_500_INTERNAL_SERVER_ERROR, resp.status_code) + + @mock.patch.object(restcall, 'call_req') + def test_subscribe_successfully(self, mock_call_req): + lccn_subscription_request_data = { + "filter": { + "notificationTypes": ["VnfLcmOperationOccurrenceNotification"], + "operationTypes": ["INSTANTIATE"], + "operationStates": ["STARTING"], + }, + "callbackUri": "http://aurl.com", + "authentication": { + "authType": ["BASIC"], + "paramsBasic": { + "username": "username", + "password": "password" + } + } + } + lccn_subscription_data = { + "id": "cd552c9c-ab6f-11e8-b354-236c32aa91a1", + "callbackUri": "http://aurl.com", + "filter": { + "notificationTypes": ["VnfLcmOperationOccurrenceNotification"], + "operationTypes": ["INSTANTIATE"], + "operationStates": ["STARTING"] + }, + "_links": { + "self": {"href": "URI of this resource."} + }, + } + mock_call_req.return_value = [0, json.JSONEncoder().encode(lccn_subscription_data), status.HTTP_201_CREATED] + response = self.client.post("/api/gvnfmdriver/v1/subscriptions", json.dumps(lccn_subscription_request_data), + content_type='application/json') + self.assertEqual(status.HTTP_201_CREATED, response.status_code) + self.assertEqual(lccn_subscription_data, response.data) + + @mock.patch.object(restcall, 'call_req') + def test_subscribe_failed(self, mock_call_req): + lccn_subscription_request_data = { + "filter": { + "notificationTypes": ["VnfLcmOperationOccurrenceNotification"], + "operationTypes": ["INSTANTIATE"], + "operationStates": ["STARTING"], + }, + "callbackUri": "http://aurl.com", + "authentication": { + "authType": ["BASIC"], + "paramsBasic": { + "username": "username", + "password": "password" + } + } + } + mock_call_req.return_value = [1, None, status.HTTP_303_SEE_OTHER] + response = self.client.post("/api/gvnfmdriver/v1/subscriptions", json.dumps(lccn_subscription_request_data), + content_type='application/json') + self.assertEqual(status.HTTP_500_INTERNAL_SERVER_ERROR, response.status_code) diff --git a/gvnfmadapter/driver/interfaces/urls.py b/gvnfmadapter/driver/interfaces/urls.py index 6adb6f9..40b8f3b 100644 --- a/gvnfmadapter/driver/interfaces/urls.py +++ b/gvnfmadapter/driver/interfaces/urls.py @@ -14,20 +14,19 @@ from django.conf.urls import url from driver.interfaces.views import VnfInstInfo, VnfTermInfo, VnfQueryInfo, VnfOperInfo +from driver.interfaces.views import Subscription from driver.interfaces.views import VnfPkgsInfo, VnfGrantInfo, VnfNotifyInfo, QuerySingleVnfLcmOpOcc urlpatterns = [ url(r'^api/(?P[0-9a-zA-Z\-\_]+)/v1/(?P[0-9a-zA-Z\-\_]+)/vnfs$', VnfInstInfo.as_view()), - url(r'^api/(?P[0-9a-zA-Z\-\_]+)/v1/(?P[0-9a-zA-Z\-\_]+)/vnfs/(?P' - r'[0-9a-zA-Z\-\_]+)/terminate$', VnfTermInfo.as_view()), - url(r'^api/(?P[0-9a-zA-Z\-\_]+)/v1/(?P[0-9a-zA-Z\-\_]+)/vnfs/(?P' - r'[0-9a-zA-Z\-\_]+)$', VnfQueryInfo.as_view()), - url(r'^api/(?P[0-9a-zA-Z\-\_]+)/v1/(?P[0-9a-zA-Z\-\_]+)/jobs/(?P[0-9a-zA-Z\-\_]+)$', - VnfOperInfo.as_view()), + url(r'^api/(?P[0-9a-zA-Z\-\_]+)/v1/(?P[0-9a-zA-Z\-\_]+)/vnfs/(?P[0-9a-zA-Z\-\_]+)/terminate$', VnfTermInfo.as_view()), + url(r'^api/(?P[0-9a-zA-Z\-\_]+)/v1/(?P[0-9a-zA-Z\-\_]+)/vnfs/(?P[0-9a-zA-Z\-\_]+)$', VnfQueryInfo.as_view()), + url(r'^api/(?P[0-9a-zA-Z\-\_]+)/v1/(?P[0-9a-zA-Z\-\_]+)/jobs/(?P[0-9a-zA-Z\-\_]+)$', VnfOperInfo.as_view()), + url(r'^api/(?P[0-9a-zA-Z\-\_]+)/v1/subscriptions$', Subscription.as_view()), + + url(r'^api/(?P[0-9a-zA-Z\-\_]+)/v1/vnfpackages$', VnfPkgsInfo.as_view()), url(r'^api/(?P[0-9a-zA-Z\-\_]+)/v1/resource/grant$', VnfGrantInfo.as_view()), - url(r'^api/(?P[0-9a-zA-Z\-\_]+)/v1/vnfs/lifecyclechangesnotification$', - VnfNotifyInfo.as_view()), - url(r'^api/(?P[0-9a-zA-Z\-\_]+)/v1/(?P[0-9a-zA-Z\-\_]+)/vnf_lcm_op_occs/(?P[0-9a-zA-Z_-]+)$', - QuerySingleVnfLcmOpOcc.as_view()), + url(r'^api/(?P[0-9a-zA-Z\-\_]+)/v1/vnfs/lifecyclechangesnotification$', VnfNotifyInfo.as_view()), + url(r'^api/(?P[0-9a-zA-Z\-\_]+)/v1/(?P[0-9a-zA-Z\-\_]+)/vnf_lcm_op_occs/(?P[0-9a-zA-Z_-]+)$', QuerySingleVnfLcmOpOcc.as_view()), ] diff --git a/gvnfmadapter/driver/interfaces/views.py b/gvnfmadapter/driver/interfaces/views.py index 362fe12..1cf6fa2 100644 --- a/gvnfmadapter/driver/interfaces/views.py +++ b/gvnfmadapter/driver/interfaces/views.py @@ -29,6 +29,8 @@ from driver.interfaces.serializers.serializers import VnfOperRespSerializer from driver.interfaces.serializers.serializers import VnfTermReqSerializer, VnfQueryRespSerializer from driver.interfaces.serializers.grant_request import GrantRequestSerializer from driver.interfaces.serializers.grant import GrantSerializer +from driver.interfaces.serializers.lccn_subscription import LccnSubscriptionSerializer +from driver.interfaces.serializers.lccn_subscription_request import LccnSubscriptionRequestSerializer from driver.pub.exceptions import GvnfmDriverException from driver.pub.utils import restcall from driver.pub.utils.restcall import req_by_msb @@ -345,6 +347,38 @@ class QuerySingleVnfLcmOpOcc(APIView): return Response(data={'error': traceback.format_exc()}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) +class Subscription(APIView): + @swagger_auto_schema( + request_body=LccnSubscriptionRequestSerializer(), + responses={ + status.HTTP_201_CREATED: LccnSubscriptionSerializer(), + status.HTTP_303_SEE_OTHER: None, + status.HTTP_500_INTERNAL_SERVER_ERROR: "INTERNAL_SERVER_ERROR" + } + ) + def post(self, request, vnfmtype): + logger.debug("Subscription--post::> %s" % request.data) + logger.debug("Subscription begin!") + try: + lccn_subscription_request_serializer = LccnSubscriptionRequestSerializer(data=request.data) + if not lccn_subscription_request_serializer.is_valid(): + raise GvnfmDriverException(lccn_subscription_request_serializer.error_messages) + resp_data = do_subscription(request.data) + lccn_subscription_serializer = LccnSubscriptionSerializer(data=resp_data) + if not lccn_subscription_serializer.is_valid(): + logger.debug("[%s]resp_data=%s" % (fun_name(), resp_data)) + raise GvnfmDriverException(lccn_subscription_serializer.errors) + logger.debug("Subscription end!") + return Response(data=lccn_subscription_serializer.data, status=status.HTTP_201_CREATED) + except GvnfmDriverException as e: + logger.error(e.message) + return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR) + except Exception as e: + logger.error(e.message) + logger.error(traceback.format_exc()) + return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + def call_vnfm(resource, method, vnfm_info, data=""): ret = restcall.call_req( base_url=ignorcase_get(vnfm_info, "url"), @@ -493,3 +527,13 @@ def do_queryvnf(data, vnfm_id, vnfInstanceId): logger.error("Status code is %s, detail is %s.", ret[2], ret[1]) raise GvnfmDriverException('Failed to query vnf.') return json.JSONDecoder().decode(ret[1]) + + +def do_subscription(data): + logger.debug("[%s] request.data=%s", fun_name(), data) + ret = req_by_msb("api/vnflcm/v1/subscriptions", "POST", json.JSONEncoder().encode(data)) + logger.debug("[%s] call_req ret=%s", fun_name(), ret) + if ret[0] != 0: + logger.error("Status code is %s, detail is %s.", ret[2], ret[1]) + raise GvnfmDriverException('Failed to subscribe.') + return json.JSONDecoder().decode(ret[1]) -- 2.16.6