c457bfeb1fe9f1cb3546cc7d0416ace15b328e3b
[modeling/etsicatalog.git] / catalog / packages / biz / vnf_pkg_subscription.py
1 # Copyright (C) 2019 Verizon. All Rights Reserved
2 #
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
6 #
7 #         http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
14
15 import ast
16 import json
17 import logging
18 import os
19 import requests
20 import uuid
21
22 from collections import Counter
23 from rest_framework import status
24
25 from catalog.packages import const
26 from catalog.pub.database.models import VnfPkgSubscriptionModel
27 from catalog.pub.exceptions import VnfPkgSubscriptionException, \
28     VnfPkgDuplicateSubscriptionException, SubscriptionDoesNotExistsException
29 from catalog.pub.utils.values import ignore_case_get
30
31 logger = logging.getLogger(__name__)
32
33 ROOT_FILTERS = {
34     "notificationTypes": "notification_types",
35     "vnfdId": "vnfd_id",
36     "vnfPkgId": "vnf_pkg_id",
37     "operationalState": "operation_states",
38     "usageState": "usage_states"
39 }
40
41
42 def is_filter_type_equal(new_filter, existing_filter):
43     return Counter(new_filter) == Counter(existing_filter)
44
45
46 class CreateSubscription(object):
47
48     def __init__(self, data):
49         self.data = data
50         self.filter = ignore_case_get(self.data, "filter", {})
51         self.callback_uri = ignore_case_get(self.data, "callbackUri")
52         self.authentication = ignore_case_get(self.data, "authentication", {})
53         self.notification_types = ignore_case_get(self.filter, "notificationTypes", [])
54         self.operation_states = ignore_case_get(self.filter, "operationalState", [])
55         self.usage_states = ignore_case_get(self.filter, "usageState", [])
56         self.vnfd_id = ignore_case_get(self.filter, "vnfdId", [])
57         self.vnf_pkg_id = ignore_case_get(self.filter, "vnfPkgId", [])
58         self.vnf_products_from_provider = \
59             ignore_case_get(self.filter, "vnfProductsFromProviders", [])
60
61     def check_callbackuri_connection(self):
62         logger.debug("SubscribeNotification-post::> Sending GET request "
63                      "to %s" % self.callback_uri)
64         try:
65             response = requests.get(self.callback_uri, timeout=2)
66             if response.status_code != status.HTTP_204_NO_CONTENT:
67                 raise VnfPkgSubscriptionException(
68                     "callbackUri %s returns %s status code." % (
69                         self.callback_uri,
70                         response.status_code
71                     )
72                 )
73         except Exception:
74             raise VnfPkgSubscriptionException(
75                 "callbackUri %s didn't return 204 status code." % self.callback_uri
76             )
77
78     def do_biz(self):
79         self.subscription_id = str(uuid.uuid4())
80         self.check_callbackuri_connection()
81         self.check_valid_auth_info()
82         self.check_valid()
83         self.save_db()
84         subscription = VnfPkgSubscriptionModel.objects.get(
85             subscription_id=self.subscription_id
86         )
87         if subscription:
88             return subscription.toDict()
89
90     def check_valid_auth_info(self):
91         logger.debug("SubscribeNotification--post::> Validating Auth "
92                      "details if provided")
93         if self.authentication.get("paramsBasic", {}) and \
94                 const.BASIC not in self.authentication.get("authType"):
95             raise VnfPkgSubscriptionException('Auth type should be ' + const.BASIC)
96         if self.authentication.get("paramsOauth2ClientCredentials", {}) and \
97                 const.OAUTH2_CLIENT_CREDENTIALS not in self.authentication.get("authType"):
98             raise VnfPkgSubscriptionException('Auth type should be ' + const.OAUTH2_CLIENT_CREDENTIALS)
99
100     def check_filter_exists(self, sub):
101         # Check the usage states, operationStates
102         for filter_type in ["operation_states", "usage_states"]:
103             if not is_filter_type_equal(getattr(self, filter_type),
104                                         ast.literal_eval(getattr(sub, filter_type))):
105                 return False
106         # If all the above types are same then check id filter
107         for id_filter in ["vnfd_id", "vnf_pkg_id"]:
108             if not is_filter_type_equal(getattr(self, id_filter),
109                                         ast.literal_eval(getattr(sub, id_filter))):
110                 return False
111         return True
112
113     def check_valid(self):
114         logger.debug("SubscribeNotification--post::> Checking DB if "
115                      "callbackUri already exists")
116         subscriptions = VnfPkgSubscriptionModel.objects.filter(callback_uri=self.callback_uri)
117         if not subscriptions.exists():
118             return True
119         for subscription in subscriptions:
120             if self.check_filter_exists(subscription):
121                 raise VnfPkgDuplicateSubscriptionException(
122                     "Already Subscription (%s) exists with the "
123                     "same callbackUri and filter" % subscription.subscription_id)
124         return True
125
126     def save_db(self):
127         logger.debug("SubscribeNotification--post::> Saving the subscription "
128                      "%s to the database" % self.subscription_id)
129         links = {
130             "self": {
131                 "href": os.path.join(const.VNFPKG_SUBSCRIPTION_ROOT_URI, self.subscription_id)
132             }
133         }
134         VnfPkgSubscriptionModel.objects.create(
135             subscription_id=self.subscription_id,
136             callback_uri=self.callback_uri,
137             notification_types=json.dumps(self.notification_types),
138             auth_info=json.dumps(self.authentication),
139             usage_states=json.dumps(self.usage_states),
140             operation_states=json.dumps(self.operation_states),
141             vnf_products_from_provider=json.dumps(self.vnf_products_from_provider),
142             vnfd_id=json.dumps(self.vnfd_id),
143             vnf_pkg_id=json.dumps(self.vnf_pkg_id),
144             links=json.dumps(links))
145         logger.debug('Create Subscription[%s] success', self.subscription_id)
146
147
148 class QuerySubscription(object):
149
150     def query_multi_subscriptions(self, params):
151         query_data = {}
152         logger.debug("QuerySubscription--get--multi--subscriptions--biz::> Check "
153                      "for filter in query params %s" % params)
154         for query, value in list(params.items()):
155             if query in ROOT_FILTERS:
156                 query_data[ROOT_FILTERS[query] + '__icontains'] = value
157         # Query the database with filter if the request has fields in request params, else fetch all records
158         if query_data:
159             subscriptions = VnfPkgSubscriptionModel.objects.filter(**query_data)
160         else:
161             subscriptions = VnfPkgSubscriptionModel.objects.all()
162         if not subscriptions.exists():
163             return []
164         return [subscription.toDict() for subscription in subscriptions]
165
166     def query_single_subscription(self, subscription_id):
167         logger.debug("QuerySingleSubscriptions--get--single--subscription--biz::> "
168                      "ID: %s" % subscription_id)
169
170         subscription = VnfPkgSubscriptionModel.objects.filter(
171             subscription_id=subscription_id)
172         if not subscription.exists():
173             raise SubscriptionDoesNotExistsException("Subscription with ID: %s "
174                                                      "does not exist" % subscription_id)
175         return subscription[0].toDict()
176
177
178 class TerminateSubscription(object):
179
180     def terminate(self, subscription_id):
181         logger.debug("TerminateSubscriptions--delete--biz::> "
182                      "ID: %s" % subscription_id)
183
184         subscription = VnfPkgSubscriptionModel.objects.filter(
185             subscription_id=subscription_id)
186         if not subscription.exists():
187             raise SubscriptionDoesNotExistsException("Subscription with ID: %s "
188                                                      "does not exist" % subscription_id)
189         subscription[0].delete()