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