summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBharath Thiruveedula <bharath.thiruveedula@verizon.com>2019-03-01 18:06:39 +0530
committerSirisha Gopigiri <sirisha.gopigiri@verizon.com>2019-03-11 17:01:02 +0530
commit68f9a9e97e345f7a3d3b37cb59a923cbf4f2046d (patch)
tree9bfda9dd7f98930a17bf8f0cfb1dd88ec0af9014
parent719e0d9fa0c9fc1f5d7da336b7618adaf2616d2e (diff)
Add Create VnfPkgmSubscription API
Add SOL 005 Create VnfPkgmSubscription API Issue-ID: VFC-1221 Change-Id: Id0b7d8c454a8c77cf14b9d299b5afb3e9ab29df5 Signed-off-by: Bharath Thiruveedula <bharath.thiruveedula@verizon.com>
-rw-r--r--.gitignore4
-rwxr-xr-xcatalog/packages/biz/vnf_pkg_subscription.py138
-rwxr-xr-x[-rw-r--r--]catalog/packages/const.py10
-rw-r--r--catalog/packages/serializers/nsd_info.py3
-rw-r--r--catalog/packages/serializers/response.py28
-rwxr-xr-xcatalog/packages/serializers/subscription_auth_data.py69
-rw-r--r--catalog/packages/serializers/vnf_pkg_info.py3
-rwxr-xr-xcatalog/packages/serializers/vnf_pkg_notifications.py99
-rwxr-xr-xcatalog/packages/serializers/vnf_pkg_subscription.py87
-rw-r--r--catalog/packages/tests/test_vnf_pkg_subscription.py100
-rwxr-xr-x[-rw-r--r--]catalog/packages/urls.py5
-rwxr-xr-xcatalog/packages/views/vnf_package_subscription_views.py72
-rw-r--r--catalog/pub/database/models.py35
-rw-r--r--catalog/pub/exceptions.py8
14 files changed, 659 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index f5ecb0a5..54a7acb3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,6 @@ logs/*.log
.tox
target
htmlcov
-.coverage \ No newline at end of file
+.coverage
+static/*/*
+test-reports/*
diff --git a/catalog/packages/biz/vnf_pkg_subscription.py b/catalog/packages/biz/vnf_pkg_subscription.py
new file mode 100755
index 00000000..20bd68ed
--- /dev/null
+++ b/catalog/packages/biz/vnf_pkg_subscription.py
@@ -0,0 +1,138 @@
+# Copyright (C) 2019 Verizon. All Rights Reserved
+#
+# 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.
+
+import ast
+import json
+import logging
+import os
+import requests
+import uuid
+
+from collections import Counter
+from rest_framework import status
+
+from catalog.packages import const
+from catalog.pub.database.models import VnfPkgSubscriptionModel
+from catalog.pub.exceptions import VnfPkgSubscriptionException, VnfPkgDuplicateSubscriptionException
+from catalog.pub.utils.values import ignore_case_get
+
+
+logger = logging.getLogger(__name__)
+
+ROOT_FILTERS = {
+ "notificationTypes": "notification_types",
+ "vnfdId": "vnfd_id",
+ "vnfPkgId": "vnf_pkg_id",
+ "operationalState": "operation_states",
+ "usageState": "usage_states"
+}
+
+
+def is_filter_type_equal(new_filter, existing_filter):
+ return Counter(new_filter) == Counter(existing_filter)
+
+
+class CreateSubscription(object):
+
+ def __init__(self, data):
+ self.data = data
+ self.filter = ignore_case_get(self.data, "filters", {})
+ self.callback_uri = ignore_case_get(self.data, "callbackUri")
+ self.authentication = ignore_case_get(self.data, "authentication", {})
+ self.notification_types = ignore_case_get(self.filter, "notificationTypes", [])
+ self.operation_states = ignore_case_get(self.filter, "operationalState", [])
+ self.usage_states = ignore_case_get(self.filter, "usageState", [])
+ self.vnfd_id = ignore_case_get(self.filter, "vnfdId", [])
+ self.vnf_pkg_id = ignore_case_get(self.filter, "vnfPkgId", [])
+ self.vnf_products_from_provider = \
+ ignore_case_get(self.filter, "vnfProductsFromProviders", {})
+
+ def check_callbackuri_connection(self):
+ logger.debug("SubscribeNotification-post::> Sending GET request "
+ "to %s" % self.callback_uri)
+ try:
+ response = requests.get(self.callback_uri, timeout=2)
+ if response.status_code != status.HTTP_204_NO_CONTENT:
+ raise VnfPkgSubscriptionException("callbackUri %s returns %s status "
+ "code." % (self.callback_uri, response.status_code))
+ except Exception:
+ raise VnfPkgSubscriptionException("callbackUri %s didn't return 204 status"
+ "code." % self.callback_uri)
+
+ def do_biz(self):
+ self.subscription_id = str(uuid.uuid4())
+ self.check_callbackuri_connection()
+ self.check_valid_auth_info()
+ self.check_valid()
+ self.save_db()
+ subscription = VnfPkgSubscriptionModel.objects.get(subscription_id=self.subscription_id)
+ if subscription:
+ return subscription.toDict()
+
+ def check_valid_auth_info(self):
+ logger.debug("SubscribeNotification--post::> Validating Auth "
+ "details if provided")
+ if self.authentication.get("paramsBasic", {}) and \
+ const.BASIC not in self.authentication.get("authType"):
+ raise VnfPkgSubscriptionException('Auth type should be ' + const.BASIC)
+ if self.authentication.get("paramsOauth2ClientCredentials", {}) and \
+ const.OAUTH2_CLIENT_CREDENTIALS not in self.authentication.get("authType"):
+ raise VnfPkgSubscriptionException('Auth type should be ' + const.OAUTH2_CLIENT_CREDENTIALS)
+
+ def check_filter_exists(self, sub):
+ # Check the usage states, operationStates
+ for filter_type in ["operation_states", "usage_states"]:
+ if not is_filter_type_equal(getattr(self, filter_type),
+ ast.literal_eval(getattr(sub, filter_type))):
+ return False
+ # If all the above types are same then check id filters
+ for id_filter in ["vnfd_id", "vnf_pkg_id"]:
+ if not is_filter_type_equal(getattr(self, id_filter),
+ ast.literal_eval(getattr(sub, id_filter))):
+ return False
+ return True
+
+ def check_valid(self):
+ logger.debug("SubscribeNotification--post::> Checking DB if "
+ "callbackUri already exists")
+ subscriptions = VnfPkgSubscriptionModel.objects.filter(callback_uri=self.callback_uri)
+ if not subscriptions.exists():
+ return True
+ for subscription in subscriptions:
+ if self.check_filter_exists(subscription):
+ raise VnfPkgDuplicateSubscriptionException(
+ "Already Subscription (%s) exists with the "
+ "same callbackUri and filter" % subscription.subscription_id)
+ return True
+
+ def save_db(self):
+ logger.debug("SubscribeNotification--post::> Saving the subscription "
+ "%s to the database" % self.subscription_id)
+ links = {
+ "self": {
+ "href": os.path.join(const.VNFPKG_SUBSCRIPTION_ROOT_URI, self.subscription_id)
+ }
+ }
+ VnfPkgSubscriptionModel.objects.create(
+ subscription_id=self.subscription_id,
+ callback_uri=self.callback_uri,
+ notification_types=json.dumps(self.notification_types),
+ auth_info=json.dumps(self.authentication),
+ usage_states=json.dumps(self.usage_states),
+ operation_states=json.dumps(self.operation_states),
+ vnf_products_from_provider=json.dumps(self.vnf_products_from_provider),
+ vnfd_id=json.dumps(self.vnfd_id),
+ vnf_pkg_id=json.dumps(self.vnf_pkg_id),
+ links=json.dumps(links))
+ logger.debug('Create Subscription[%s] success', self.subscription_id)
diff --git a/catalog/packages/const.py b/catalog/packages/const.py
index 9d3f6ebd..e942ffdf 100644..100755
--- a/catalog/packages/const.py
+++ b/catalog/packages/const.py
@@ -16,3 +16,13 @@ from catalog.pub.utils.jobutil import enum
PKG_STATUS = enum(CREATED="CREATED", UPLOADING="UPLOADING", PROCESSING="PROCESSING", ONBOARDED="ONBOARDED",
IN_USE="IN_USE", NOT_IN_USE="NOT_IN_USE", ENABLED="ENABLED", DISABLED="DISABLED")
+
+AUTH_TYPES = ["BASIC", "OAUTH2_CLIENT_CREDENTIALS", "TLS_CERT"]
+
+BASIC = "BASIC"
+
+OAUTH2_CLIENT_CREDENTIALS = "OAUTH2_CLIENT_CREDENTIALS"
+
+NOTIFICATION_TYPES = ["VnfPackageOnboardingNotification", "VnfPackageChangeNotification"]
+
+VNFPKG_SUBSCRIPTION_ROOT_URI = "api/vnfpkgm/v1/subscriptions/"
diff --git a/catalog/packages/serializers/nsd_info.py b/catalog/packages/serializers/nsd_info.py
index e934a1f1..59df1b65 100644
--- a/catalog/packages/serializers/nsd_info.py
+++ b/catalog/packages/serializers/nsd_info.py
@@ -29,6 +29,9 @@ class _LinkSerializer(serializers.Serializer):
allow_null=False
)
+ class Meta:
+ ref_name = 'NSD_LinkSerializer'
+
class NsdInfoSerializer(serializers.Serializer):
id = serializers.CharField(
diff --git a/catalog/packages/serializers/response.py b/catalog/packages/serializers/response.py
new file mode 100644
index 00000000..64740780
--- /dev/null
+++ b/catalog/packages/serializers/response.py
@@ -0,0 +1,28 @@
+# Copyright (C) 2019 Verizon. All Rights Reserved.
+#
+# 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
+
+
+class ProblemDetailsSerializer(serializers.Serializer):
+ type = serializers.CharField(help_text="Type", required=False, allow_null=True)
+ title = serializers.CharField(help_text="Title", required=False, allow_null=True)
+ status = serializers.IntegerField(help_text="Status", required=True)
+ detail = serializers.CharField(help_text="Detail", required=True, allow_null=True)
+ instance = serializers.CharField(help_text="Instance", required=False, allow_null=True)
+ additional_details = serializers.ListField(
+ help_text="Any number of additional attributes, as defined in a "
+ "specification or by an implementation.",
+ required=False,
+ allow_null=True)
diff --git a/catalog/packages/serializers/subscription_auth_data.py b/catalog/packages/serializers/subscription_auth_data.py
new file mode 100755
index 00000000..5d40e4d3
--- /dev/null
+++ b/catalog/packages/serializers/subscription_auth_data.py
@@ -0,0 +1,69 @@
+# Copyright (C) 2019 Verizon. All Rights Reserved
+#
+# 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 catalog.packages import const
+
+
+class OAuthCredentialsSerializer(serializers.Serializer):
+ clientId = serializers.CharField(
+ help_text="Client identifier to be used in the access token "
+ "request of the OAuth 2.0 client credentials grant type.",
+ required=False,
+ max_length=255,
+ allow_null=False)
+ clientPassword = serializers.CharField(
+ help_text="Client password to be used in the access token "
+ "request of the OAuth 2.0 client credentials grant type.",
+ required=False,
+ max_length=255,
+ allow_null=False)
+ tokenEndpoint = serializers.CharField(
+ help_text="The token endpoint from which the access token can "
+ "be obtained.",
+ required=False,
+ max_length=255,
+ allow_null=False)
+
+
+class BasicAuthSerializer(serializers.Serializer):
+ userName = serializers.CharField(
+ help_text="Username to be used in HTTP Basic authentication.",
+ max_length=255,
+ required=False,
+ allow_null=False)
+ password = serializers.CharField(
+ help_text="Password to be used in HTTP Basic authentication.",
+ max_length=255,
+ required=False,
+ allow_null=False)
+
+
+class SubscriptionAuthenticationSerializer(serializers.Serializer):
+ authType = serializers.ListField(
+ child=serializers.ChoiceField(required=True, choices=const.AUTH_TYPES),
+ help_text="Defines the types of Authentication / Authorization "
+ "which the API consumer is willing to accept when "
+ "receiving a notification.",
+ required=True)
+ paramsBasic = BasicAuthSerializer(
+ help_text="Parameters for authentication/authorization using BASIC.",
+ required=False,
+ allow_null=False)
+ paramsOauth2ClientCredentials = OAuthCredentialsSerializer(
+ help_text="Parameters for authentication/authorization using "
+ "OAUTH2_CLIENT_CREDENTIALS.",
+ required=False,
+ allow_null=False)
diff --git a/catalog/packages/serializers/vnf_pkg_info.py b/catalog/packages/serializers/vnf_pkg_info.py
index 4c63a463..844937fb 100644
--- a/catalog/packages/serializers/vnf_pkg_info.py
+++ b/catalog/packages/serializers/vnf_pkg_info.py
@@ -33,6 +33,9 @@ class _LinkSerializer(serializers.Serializer):
required=True,
allow_null=False)
+ class Meta:
+ ref_name = 'VNF_PKGM_Link_Serializer'
+
class VnfPkgInfoSerializer(serializers.Serializer):
id = serializers.CharField(
diff --git a/catalog/packages/serializers/vnf_pkg_notifications.py b/catalog/packages/serializers/vnf_pkg_notifications.py
new file mode 100755
index 00000000..deb0ea03
--- /dev/null
+++ b/catalog/packages/serializers/vnf_pkg_notifications.py
@@ -0,0 +1,99 @@
+# Copyright (C) 2019 Verizon. All Rights Reserved
+#
+# 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 catalog.packages.const import NOTIFICATION_TYPES
+
+PackageOperationalStateType = ["ENABLED", "DISABLED"]
+PackageUsageStateType = ["IN_USE", "NOT_IN_USE"]
+
+
+class VersionSerializer(serializers.Serializer):
+ vnfSoftwareVersion = serializers.CharField(
+ help_text="VNF software version to match.",
+ max_length=255,
+ required=True,
+ allow_null=False)
+ vnfdVersions = serializers.ListField(
+ child=serializers.CharField(),
+ help_text="Match VNF packages that contain "
+ "VNF products with certain VNFD versions",
+ required=False,
+ allow_null=False)
+
+
+class vnfProductsSerializer(serializers.Serializer):
+ vnfProductName = serializers.CharField(
+ help_text="Name of the VNF product to match.",
+ max_length=255,
+ required=True,
+ allow_null=False)
+ versions = VersionSerializer(
+ help_text="match VNF packages that contain "
+ "VNF products with certain versions",
+ required=False,
+ allow_null=False
+ )
+
+
+class vnfProductsProvidersSerializer(serializers.Serializer):
+ vnfProvider = serializers.CharField(
+ help_text="Name of the VNFprovider to match.",
+ max_length=255,
+ required=True,
+ allow_null=False)
+ vnfProducts = vnfProductsSerializer(
+ help_text="match VNF packages that contain "
+ "VNF products with certain product names, "
+ "from one particular provider",
+ required=False,
+ allow_null=False
+ )
+
+
+class PkgmNotificationsFilter(serializers.Serializer):
+ notificationTypes = serializers.ListField(
+ child=serializers.ChoiceField(required=True, choices=NOTIFICATION_TYPES),
+ help_text="Match particular notification types",
+ allow_null=False,
+ required=False)
+ vnfProductsFromProviders = vnfProductsProvidersSerializer(
+ help_text="Match VNF packages that contain "
+ "VNF products from certain providers.",
+ allow_null=False,
+ required=False
+ )
+ vnfdId = serializers.ListField(
+ child=serializers.UUIDField(),
+ help_text="Match VNF packages with a VNFD identifier"
+ "listed in the attribute",
+ required=False,
+ allow_null=False)
+ vnfPkgId = serializers.ListField(
+ child=serializers.UUIDField(),
+ help_text="Match VNF packages with a VNFD identifier"
+ "listed in the attribute",
+ required=False,
+ allow_null=False)
+ operationalState = serializers.ListField(
+ child=serializers.ChoiceField(required=True, choices=PackageOperationalStateType),
+ help_text="Operational state of the VNF package.",
+ allow_null=False,
+ required=False)
+ usageState = serializers.ListField(
+ child=serializers.ChoiceField(required=True, choices=PackageUsageStateType),
+ help_text="Operational state of the VNF package.",
+ allow_null=False,
+ required=False)
diff --git a/catalog/packages/serializers/vnf_pkg_subscription.py b/catalog/packages/serializers/vnf_pkg_subscription.py
new file mode 100755
index 00000000..8cbac758
--- /dev/null
+++ b/catalog/packages/serializers/vnf_pkg_subscription.py
@@ -0,0 +1,87 @@
+# Copyright (C) 2019 Verizon. All Rights Reserved
+#
+# 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 catalog.packages.serializers import subscription_auth_data
+from catalog.packages.serializers import vnf_pkg_notifications
+
+
+class LinkSerializer(serializers.Serializer):
+ href = serializers.CharField(
+ help_text="URI of the referenced resource.",
+ required=True,
+ allow_null=False,
+ allow_blank=False)
+
+ class Meta:
+ ref_name = 'VNF_SUBSCRIPTION_LINKSERIALIZER'
+
+
+class LinkSelfSerializer(serializers.Serializer):
+ self = LinkSerializer(
+ help_text="URI of this resource.",
+ required=True,
+ allow_null=False)
+
+
+class PkgmSubscriptionRequestSerializer(serializers.Serializer):
+ filters = vnf_pkg_notifications.PkgmNotificationsFilter(
+ help_text="Filter settings for this subscription, "
+ "to define the subset of all notifications"
+ " this subscription relates to",
+ required=False,
+ allow_null=False
+ )
+ callbackUri = serializers.URLField(
+ help_text="Callback URI to send"
+ "the notification",
+ required=True,
+ allow_null=False)
+ authentication = subscription_auth_data.SubscriptionAuthenticationSerializer(
+ help_text="Authentication parameters to configure the use of "
+ "authorization when sending notifications corresponding to"
+ "this subscription",
+ required=False,
+ allow_null=False
+ )
+
+
+class PkgmSubscriptionSerializer(serializers.Serializer):
+ id = serializers.UUIDField(
+ help_text="Identifier of this subscription resource.",
+ required=True,
+ allow_null=False)
+ callbackUri = serializers.URLField(
+ help_text="The URI of the endpoint to send the notification to.",
+ required=True,
+ allow_null=False)
+
+ _links = LinkSelfSerializer(
+ help_text="Links to resources related to this resource.",
+ required=True,
+ allow_null=False)
+
+ filter = vnf_pkg_notifications.PkgmNotificationsFilter(
+ help_text="Filter settings for this subscription, "
+ "to define the subset of all notifications"
+ " this subscription relates to",
+ required=False,
+ allow_null=False
+ )
+
+
+class PkgmSubscriptionsSerializer(serializers.ListSerializer):
+ child = PkgmSubscriptionSerializer()
+ allow_empty = True
diff --git a/catalog/packages/tests/test_vnf_pkg_subscription.py b/catalog/packages/tests/test_vnf_pkg_subscription.py
new file mode 100644
index 00000000..7c8b9f13
--- /dev/null
+++ b/catalog/packages/tests/test_vnf_pkg_subscription.py
@@ -0,0 +1,100 @@
+# Copyright (C) 2019 Verizon. All Rights Reserved
+#
+# 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.
+
+import uuid
+import mock
+from rest_framework.test import APIClient
+from django.test import TestCase
+from catalog.pub.database.models import VnfPkgSubscriptionModel
+
+
+class TestNfPackageSubscription(TestCase):
+ def setUp(self):
+ self.client = APIClient()
+ VnfPkgSubscriptionModel.objects.filter().delete()
+ self.vnf_subscription_data = {
+ "filters": {
+ "notificationTypes": [
+ "VnfPackageOnboardingNotification"
+ ],
+ "vnfProductsFromProviders": {
+ "vnfProvider": "string",
+ "vnfProducts": {
+ "vnfProductName": "string",
+ "versions": {
+ "vnfSoftwareVersion": "string",
+ "vnfdVersions": [
+ "string"
+ ]
+ }
+ }
+ },
+ "vnfdId": [
+ "3fa85f64-5717-4562-b3fc-2c963f66afa6"
+ ],
+ "vnfPkgId": [
+ "3fa85f64-5717-4562-b3fc-2c963f66afa6"
+ ],
+ "operationalState": [
+ "ENABLED"
+ ],
+ "usageState": [
+ "IN_USE"
+ ]
+ },
+ "callbackUri": "http://www.vnf1.com/notification",
+ "authentication": {
+ "authType": [
+ "BASIC"
+ ],
+ "paramsBasic": {
+ "userName": "string",
+ "password": "string"
+ }
+ }
+ }
+
+ def tearDown(self):
+ pass
+
+ @mock.patch("requests.get")
+ @mock.patch.object(uuid, 'uuid4')
+ def test_create_vnf_subscription(self, mock_uuid4, mock_requests):
+ temp_uuid = "99442b18-a5c7-11e8-998c-bf1755941f13"
+ mock_requests.return_value.status_code = 204
+ mock_requests.get.status_code = 204
+ mock_uuid4.return_value = temp_uuid
+ response = self.client.post("/api/vnfpkgm/v1/subscriptions", data=self.vnf_subscription_data, format='json')
+ self.assertEqual(201, response.status_code)
+ self.assertEqual(self.vnf_subscription_data["callbackUri"], response.data["callbackUri"])
+ self.assertEqual(temp_uuid, response.data["id"])
+
+ @mock.patch("requests.get")
+ @mock.patch.object(uuid, 'uuid4')
+ def test_create_duplicate_subscriptions(self, mock_uuid4, mock_requests):
+ temp_uuid = "99442b18-a5c7-11e8-998c-bf1755941f13"
+ temp1_uuid = "00342b18-a5c7-11e8-998c-bf1755941f12"
+ mock_requests.return_value.status_code = 204
+ mock_requests.get.status_code = 204
+ mock_uuid4.side_effect = [temp_uuid, temp1_uuid]
+ response = self.client.post("/api/vnfpkgm/v1/subscriptions", data=self.vnf_subscription_data, format='json')
+ self.assertEqual(201, response.status_code)
+ self.assertEqual(self.vnf_subscription_data["callbackUri"], response.data["callbackUri"])
+ self.assertEqual(temp_uuid, response.data["id"])
+ temp_uuid = "00442b18-a5c7-11e8-998c-bf1755941f12"
+ mock_requests.return_value.status_code = 204
+ mock_requests.get.status_code = 204
+ mock_uuid4.return_value = temp_uuid
+ response = self.client.post("/api/vnfpkgm/v1/subscriptions", data=self.vnf_subscription_data, format='json')
+ self.assertEqual(303, response.status_code)
diff --git a/catalog/packages/urls.py b/catalog/packages/urls.py
index e62bc76a..1c20fc20 100644..100755
--- a/catalog/packages/urls.py
+++ b/catalog/packages/urls.py
@@ -15,6 +15,7 @@
from django.conf.urls import url
from catalog.packages.views import vnf_package_views
+from catalog.packages.views.vnf_package_subscription_views import SubscriptionsView
from catalog.packages.views import catalog_views, ns_descriptor_views, pnf_descriptor_views
@@ -48,7 +49,9 @@ urlpatterns = [
url(r'^api/vnfpkgm/v1/vnf_packages/(?P<vnfPkgId>[0-9a-zA-Z\-\_]+)$', vnf_package_views.vnf_package_rd, name='vnf_package_rd'),
url(r'^api/vnfpkgm/v1/vnf_packages/(?P<vnfPkgId>[0-9a-zA-Z\-\_]+)/package_content$', vnf_package_views.package_content_ru, name='package_content_ru'),
url(r'^api/vnfpkgm/v1/vnf_packages/(?P<vnfPkgId>[0-9a-zA-Z\-\_]+)/package_content/upload_from_uri$', vnf_package_views.upload_from_uri_c, name='upload_from_uri_c'),
+ url(r'^api/vnfpkgm/v1/subscriptions$', SubscriptionsView.as_view(), name='subscriptions_create_query'),
+ # url(r'^api/vnfpkgm/v1/subscriptions/(?P<vnfPkgId>[0-9a-zA-Z\-\_]+)$', vnf_package_subscription_views.vnf_package_subscriptions_rc, name='subscriptions_rc'),
# url(r'^api/vnfpkgm/v1/vnf_packages/(?P<vnfPkgId>[0-9a-zA-Z\-\_]+)/vnfd$', vnfd.as_view(), name='vnfd_r'),# url(r'^api/vnfpkgm/v1/vnf_packages/(?P<vnfPkgId>[0-9a-zA-Z\-\_]+)/artifacts/artifactPath$', artifacts.as_view(), name='artifacts_r'),
- # url(r'^api/vnfpkgm/v1/subscriptions', vnfpkg_subscriptions.as_view(), name='subscriptions_rc'),
+
# url(r'^api/vnfpkgm/v1/subscriptions/(?P<subscriptionId>[0-9a-zA-Z\-\_]+)$', vnfpkg_subscription.as_view(), name='subscription_rd'),
]
diff --git a/catalog/packages/views/vnf_package_subscription_views.py b/catalog/packages/views/vnf_package_subscription_views.py
new file mode 100755
index 00000000..d7449a89
--- /dev/null
+++ b/catalog/packages/views/vnf_package_subscription_views.py
@@ -0,0 +1,72 @@
+# Copyright (C) 2019 Verizon. All Rights Reserved
+#
+# 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.
+
+
+import traceback
+import logging
+
+from drf_yasg.utils import swagger_auto_schema
+from rest_framework import status
+from rest_framework.views import APIView
+from rest_framework.response import Response
+
+from catalog.packages.serializers.vnf_pkg_subscription import PkgmSubscriptionRequestSerializer, \
+ PkgmSubscriptionSerializer
+from catalog.packages.serializers.response import ProblemDetailsSerializer
+from catalog.packages.biz.vnf_pkg_subscription import CreateSubscription
+from catalog.packages.views.common import validate_data
+from catalog.pub.exceptions import VnfPkgDuplicateSubscriptionException
+
+logger = logging.getLogger(__name__)
+VALID_FILTERS = ["callbackUri", "notificationTypes", "vnfdId", "vnfPkgId", "operationalState", "usageState"]
+
+
+def get_problem_details_serializer(status_code, error_message):
+ problem_details = {
+ "status": status_code,
+ "detail": error_message
+ }
+ problem_details_serializer = ProblemDetailsSerializer(data=problem_details)
+ problem_details_serializer.is_valid()
+ return problem_details_serializer
+
+
+class SubscriptionsView(APIView):
+
+ @swagger_auto_schema(
+ request_body=PkgmSubscriptionRequestSerializer,
+ responses={
+ status.HTTP_201_CREATED: PkgmSubscriptionSerializer(),
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Internal error"
+ }
+ )
+ def post(self, request):
+ logger.debug("Create VNF package Subscription> %s" % request.data)
+ try:
+ vnf_pkg_subscription_request = validate_data(request.data, PkgmSubscriptionRequestSerializer)
+ data = CreateSubscription(vnf_pkg_subscription_request.data).do_biz()
+ subscription_info = validate_data(data, PkgmSubscriptionSerializer)
+ return Response(data=subscription_info.data, status=status.HTTP_201_CREATED)
+ except VnfPkgDuplicateSubscriptionException as e:
+ logger.error(e.message)
+ logger.error(traceback.format_exc())
+ problem_details_serializer = get_problem_details_serializer(status.HTTP_303_SEE_OTHER,
+ traceback.format_exc())
+ return Response(data=problem_details_serializer.data, status=status.HTTP_303_SEE_OTHER)
+ except Exception as e:
+ logger.error(e.message)
+ logger.error(traceback.format_exc())
+ problem_details_serializer = get_problem_details_serializer(status.HTTP_500_INTERNAL_SERVER_ERROR,
+ traceback.format_exc())
+ return Response(data=problem_details_serializer.data, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
diff --git a/catalog/pub/database/models.py b/catalog/pub/database/models.py
index 04e39c29..c1e2a8ae 100644
--- a/catalog/pub/database/models.py
+++ b/catalog/pub/database/models.py
@@ -140,3 +140,38 @@ class JobStatusModel(models.Model):
def toJSON(self):
import json
return json.dumps(dict([(attr, getattr(self, attr)) for attr in [f.name for f in self._meta.fields]]))
+
+
+class VnfPkgSubscriptionModel(models.Model):
+ subscription_id = models.CharField(max_length=255, primary_key=True, db_column='SUBSCRIPTION_ID')
+ callback_uri = models.URLField(db_column="CALLBACK_URI", max_length=255)
+ auth_info = models.TextField(db_column="AUTH_INFO")
+ usage_states = models.TextField(db_column="USAGE_STATES")
+ notification_types = models.TextField(db_column="NOTIFICATION_TYPES")
+ vnfd_id = models.TextField(db_column="VNFD_ID")
+ vnf_pkg_id = models.TextField(db_column="VNF_PKG_ID")
+ operation_states = models.TextField(db_column="OPERATION_STATES")
+ vnf_products_from_provider = \
+ models.TextField(db_column="VNF_PRODUCTS_FROM_PROVIDER")
+ links = models.TextField(db_column="LINKS")
+
+ class Meta:
+ db_table = 'VNF_PKG_SUBSCRIPTION'
+
+ def toDict(self):
+ import json
+ subscription_obj = {
+ "id": self.subscription_id,
+ "callbackUri": self.callback_uri,
+ "_links": json.loads(self.links)
+ }
+ filter_obj = {
+ "notificationTypes": json.loads(self.notification_types),
+ "vnfdId": json.loads(self.vnfd_id),
+ "vnfPkgId": json.loads(self.vnf_pkg_id),
+ "operationalState": json.loads(self.operation_states),
+ "usageState": json.loads(self.usage_states),
+ "vnfProductsFromProviders": json.loads(self.vnf_products_from_provider)
+ }
+ subscription_obj["filter"] = filter_obj
+ return subscription_obj
diff --git a/catalog/pub/exceptions.py b/catalog/pub/exceptions.py
index a86775ea..7f348d65 100644
--- a/catalog/pub/exceptions.py
+++ b/catalog/pub/exceptions.py
@@ -19,3 +19,11 @@ class CatalogException(Exception):
class ResourceNotFoundException(CatalogException):
pass
+
+
+class VnfPkgSubscriptionException(CatalogException):
+ pass
+
+
+class VnfPkgDuplicateSubscriptionException(CatalogException):
+ pass