1 # Copyright (C) 2019 Verizon. All Rights Reserved
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
20 from collections import Counter
23 from requests.auth import HTTPBasicAuth
24 from rest_framework import status
26 from catalog.packages import const
27 from catalog.pub.database.models import VnfPkgSubscriptionModel
28 from catalog.pub.exceptions import VnfPkgSubscriptionException, \
29 VnfPkgDuplicateSubscriptionException, SubscriptionDoesNotExistsException
30 from catalog.pub.utils.values import ignore_case_get
32 logger = logging.getLogger(__name__)
35 "notificationTypes": "notification_types",
37 "vnfPkgId": "vnf_pkg_id",
38 "operationalState": "operation_states",
39 "usageState": "usage_states"
43 def is_filter_type_equal(new_filter, existing_filter):
44 return Counter(new_filter) == Counter(existing_filter)
47 class CreateSubscription(object):
49 Create subscription info
51 def __init__(self, data):
53 self.filter = ignore_case_get(self.data, "filter", {})
54 self.callback_uri = ignore_case_get(self.data, "callbackUri")
55 self.authentication = ignore_case_get(self.data, "authentication", {})
56 self.notification_types = ignore_case_get(self.filter, "notificationTypes", [])
57 self.operation_states = ignore_case_get(self.filter, "operationalState", [])
58 self.usage_states = ignore_case_get(self.filter, "usageState", [])
59 self.vnfd_id = ignore_case_get(self.filter, "vnfdId", [])
60 self.vnf_pkg_id = ignore_case_get(self.filter, "vnfPkgId", [])
61 self.vnf_products_from_provider = \
62 ignore_case_get(self.filter, "vnfProductsFromProviders", [])
64 def check_callbackuri_connection(self):
66 Check if the callback uri can access
69 logger.debug("SubscribeNotification-post::> Sending GET request "
70 "to %s" % self.callback_uri)
72 if self.authentication:
73 if const.BASIC in self.authentication.get("authType", ''):
74 params = self.authentication.get("paramsBasic", {})
75 username = params.get("userName")
76 password = params.get("password")
77 response = requests.get(self.callback_uri, auth=HTTPBasicAuth(username, password), timeout=2,
79 elif const.OAUTH2_CLIENT_CREDENTIALS in self.authentication.get("authType", ''):
86 response = requests.get(self.callback_uri, timeout=2, verify=False)
87 if response.status_code != status.HTTP_204_NO_CONTENT:
88 raise VnfPkgSubscriptionException(
89 "callbackUri %s returns %s status code." % (
95 raise VnfPkgSubscriptionException(
96 "callbackUri %s didn't return 204 status code." % self.callback_uri
104 self.subscription_id = str(uuid.uuid4())
105 self.check_valid_auth_info()
106 self.check_callbackuri_connection()
109 subscription = VnfPkgSubscriptionModel.objects.get(
110 subscription_id=self.subscription_id
113 return subscription.toDict()
115 def check_valid_auth_info(self):
117 Check if the Auth info is valid
120 logger.debug("SubscribeNotification--post::> Validating Auth "
121 "details if provided")
122 if self.authentication.get("paramsBasic", {}) and const.BASIC not in self.authentication.get("authType"):
123 raise VnfPkgSubscriptionException('Auth type should be ' + const.BASIC)
124 if self.authentication.get("paramsOauth2ClientCredentials", {}) \
125 and const.OAUTH2_CLIENT_CREDENTIALS not in self.authentication.get("authType"):
126 raise VnfPkgSubscriptionException('Auth type should be ' + const.OAUTH2_CLIENT_CREDENTIALS)
128 def check_filter_exists(self, sub):
129 # Check the usage states, operationStates
130 for filter_type in ["operation_states", "usage_states"]:
131 if not is_filter_type_equal(getattr(self, filter_type),
132 ast.literal_eval(getattr(sub, filter_type))):
134 # If all the above types are same then check id filter
135 for id_filter in ["vnfd_id", "vnf_pkg_id"]:
136 if not is_filter_type_equal(getattr(self, id_filter),
137 ast.literal_eval(getattr(sub, id_filter))):
141 def check_valid(self):
143 logger.debug("SubscribeNotification--post::> Checking DB if "
144 "callbackUri already exists")
145 subscriptions = VnfPkgSubscriptionModel.objects.filter(callback_uri=self.callback_uri)
146 for subscription in subscriptions:
147 if self.check_filter_exists(subscription):
148 links = json.loads(subscription.links)
149 logger.error("Subscriptions has already exists with the same callbackUri and filter:%s" % links)
150 raise VnfPkgDuplicateSubscriptionException(
151 "/%s" % (links["self"]["href"]))
157 Save the subscription info to DB
160 logger.debug("SubscribeNotification--post::> Saving the subscription "
161 "%s to the database" % self.subscription_id)
164 "href": os.path.join(const.VNFPKG_SUBSCRIPTION_ROOT_URI, self.subscription_id)
167 VnfPkgSubscriptionModel.objects.create(
168 subscription_id=self.subscription_id,
169 callback_uri=self.callback_uri,
170 notification_types=json.dumps(self.notification_types),
171 auth_info=json.dumps(self.authentication),
172 usage_states=json.dumps(self.usage_states),
173 operation_states=json.dumps(self.operation_states),
174 vnf_products_from_provider=json.dumps(self.vnf_products_from_provider),
175 vnfd_id=json.dumps(self.vnfd_id),
176 vnf_pkg_id=json.dumps(self.vnf_pkg_id),
177 links=json.dumps(links))
178 logger.debug('Create Subscription[%s] success', self.subscription_id)
181 class QuerySubscription(object):
183 The class for query subscription
185 def query_multi_subscriptions(self, params):
192 logger.debug("QuerySubscription--get--multi--subscriptions--biz::> Check "
193 "for filter in query params %s" % params)
194 for query, value in list(params.items()):
195 if query in ROOT_FILTERS:
196 query_data[ROOT_FILTERS[query] + '__icontains'] = value
197 # Query the database with filter if the request has fields in request params, else fetch all records
199 subscriptions = VnfPkgSubscriptionModel.objects.filter(**query_data)
201 subscriptions = VnfPkgSubscriptionModel.objects.all()
202 if not subscriptions.exists():
204 return [subscription.toDict() for subscription in subscriptions]
206 def query_single_subscription(self, subscription_id):
208 Query subscription by id
209 :param subscription_id:
212 logger.debug("QuerySingleSubscriptions--get--single--subscription--biz::> "
213 "ID: %s" % subscription_id)
215 subscription = VnfPkgSubscriptionModel.objects.filter(
216 subscription_id=subscription_id)
217 if not subscription.exists():
218 raise SubscriptionDoesNotExistsException("Subscription with ID: %s "
219 "does not exist" % subscription_id)
220 return subscription[0].toDict()
223 class TerminateSubscription(object):
225 The class to terminate the subscription
227 def terminate(self, subscription_id):
228 logger.debug("TerminateSubscriptions--delete--biz::> "
229 "ID: %s" % subscription_id)
231 subscription = VnfPkgSubscriptionModel.objects.filter(
232 subscription_id=subscription_id)
233 if not subscription.exists():
234 raise SubscriptionDoesNotExistsException("Subscription with ID: %s "
235 "does not exist" % subscription_id)
236 subscription[0].delete()