Add a subscription api on gvnfmdriver. 49/66349/2
authorlaili <lai.li@zte.com.cn>
Thu, 13 Sep 2018 12:13:29 +0000 (20:13 +0800)
committerFu Jinhua <fu.jinhua@zte.com.cn>
Fri, 14 Sep 2018 00:30:07 +0000 (00:30 +0000)
Add serializers, view, and tests supscription.

Change-Id: I64cf560520038d9396c810307ac022d303f9ddfe
Issue-ID: VFC-1118
Signed-off-by: laili <lai.li@zte.com.cn>
gvnfmadapter/driver/interfaces/serializers/lccn_subscription.py [new file with mode: 0644]
gvnfmadapter/driver/interfaces/serializers/lccn_subscription_request.py [new file with mode: 0644]
gvnfmadapter/driver/interfaces/tests.py
gvnfmadapter/driver/interfaces/urls.py
gvnfmadapter/driver/interfaces/views.py

diff --git a/gvnfmadapter/driver/interfaces/serializers/lccn_subscription.py b/gvnfmadapter/driver/interfaces/serializers/lccn_subscription.py
new file mode 100644 (file)
index 0000000..829c927
--- /dev/null
@@ -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 (file)
index 0000000..88797bc
--- /dev/null
@@ -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)
index 9c50466..4d58137 100644 (file)
@@ -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)
index 6adb6f9..40b8f3b 100644 (file)
 
 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<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/(?P<vnfmid>[0-9a-zA-Z\-\_]+)/vnfs$', VnfInstInfo.as_view()),
-    url(r'^api/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/(?P<vnfmid>[0-9a-zA-Z\-\_]+)/vnfs/(?P<vnfInstanceId>'
-        r'[0-9a-zA-Z\-\_]+)/terminate$', VnfTermInfo.as_view()),
-    url(r'^api/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/(?P<vnfmid>[0-9a-zA-Z\-\_]+)/vnfs/(?P<vnfInstanceId>'
-        r'[0-9a-zA-Z\-\_]+)$', VnfQueryInfo.as_view()),
-    url(r'^api/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/(?P<vnfmid>[0-9a-zA-Z\-\_]+)/jobs/(?P<jobid>[0-9a-zA-Z\-\_]+)$',
-        VnfOperInfo.as_view()),
+    url(r'^api/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/(?P<vnfmid>[0-9a-zA-Z\-\_]+)/vnfs/(?P<vnfInstanceId>[0-9a-zA-Z\-\_]+)/terminate$', VnfTermInfo.as_view()),
+    url(r'^api/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/(?P<vnfmid>[0-9a-zA-Z\-\_]+)/vnfs/(?P<vnfInstanceId>[0-9a-zA-Z\-\_]+)$', VnfQueryInfo.as_view()),
+    url(r'^api/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/(?P<vnfmid>[0-9a-zA-Z\-\_]+)/jobs/(?P<jobid>[0-9a-zA-Z\-\_]+)$', VnfOperInfo.as_view()),
+    url(r'^api/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/subscriptions$', Subscription.as_view()),
+
+
     url(r'^api/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/vnfpackages$', VnfPkgsInfo.as_view()),
     url(r'^api/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/resource/grant$', VnfGrantInfo.as_view()),
-    url(r'^api/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/vnfs/lifecyclechangesnotification$',
-        VnfNotifyInfo.as_view()),
-    url(r'^api/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/(?P<vnfmid>[0-9a-zA-Z\-\_]+)/vnf_lcm_op_occs/(?P<lcmopoccid>[0-9a-zA-Z_-]+)$',
-        QuerySingleVnfLcmOpOcc.as_view()),
+    url(r'^api/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/vnfs/lifecyclechangesnotification$', VnfNotifyInfo.as_view()),
+    url(r'^api/(?P<vnfmtype>[0-9a-zA-Z\-\_]+)/v1/(?P<vnfmid>[0-9a-zA-Z\-\_]+)/vnf_lcm_op_occs/(?P<lcmopoccid>[0-9a-zA-Z_-]+)$', QuerySingleVnfLcmOpOcc.as_view()),
 ]
index 362fe12..1cf6fa2 100644 (file)
@@ -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])