1 # Copyright 2019 ZTE Corporation.
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.
21 from django.db.models import Q
22 from requests.auth import HTTPBasicAuth
23 from rest_framework import status
25 import catalog.pub.utils.timeutil
26 from catalog.packages import const
27 from catalog.packages.serializers.vnf_pkg_notifications import PkgChangeNotificationSerializer, \
28 PkgOnboardingNotificationSerializer
29 from catalog.pub.database.models import VnfPackageModel, VnfPkgSubscriptionModel, NsdmSubscriptionModel
30 from catalog.pub.utils.values import remove_none_key
32 logger = logging.getLogger(__name__)
35 class NotificationsUtil(object):
37 Util for notifications
40 def __init__(self, notification_type):
41 self.notification_type = notification_type
42 self.notifyserializer = None
44 def prepare_notification(self, **kwargs):
47 def send_notification(self):
52 notification = self.prepare_notification()
54 subscriptions_filter = {v + "__contains": notification[k] for k, v in self.filter.items()}
55 subscriptions_filter = remove_none_key(subscriptions_filter)
56 logger.debug('send_notification subscriptions_filter = %s' % subscriptions_filter)
59 for k, v in subscriptions_filter.items():
60 q1.children.append((k, v))
62 subscriptions = self.SubscriptionModel.objects.filter(q1)
63 if not subscriptions.exists():
64 logger.info("No subscriptions created for the filter %s" % notification)
66 logger.info("Start sending notifications")
67 for sub in subscriptions:
69 notification["subscriptionId"] = sub.get_subscription_id()
70 notification['_links']['subscription'] = {
71 'href': '/%s%s' % (self.subscription_root_uri, notification["subscriptionId"])
73 callbackuri = sub.callback_uri
75 auth_info = json.loads(sub.auth_info)
76 if auth_info["authType"] == const.OAUTH2_CLIENT_CREDENTIALS:
79 if self.notifyserializer:
80 serialized_data = self.notifyserializer(data=notification)
81 if not serialized_data.is_valid():
82 logger.error('Notification Data is invalid:%s.' % serialized_data.errors)
85 self.post_notification(callbackuri, notification, auth_info=json.loads(sub.auth_info))
87 self.post_notification(callbackuri, notification)
89 def post_notification(self, callbackuri, notification, auth_info=None):
99 if const.BASIC in auth_info.get("authType", ''):
100 params = auth_info.get("paramsBasic", {})
101 username = params.get("userName")
102 password = params.get("password")
103 resp = requests.post(callbackuri,
104 data=json.dumps(notification),
105 headers={'Connection': 'close',
106 'content-type': 'application/json',
107 'accept': 'application/json'},
108 auth=HTTPBasicAuth(username, password),
110 elif const.OAUTH2_CLIENT_CREDENTIALS in auth_info.get("authType", ''):
117 resp = requests.post(callbackuri,
118 data=json.dumps(notification),
119 headers={'Connection': 'close',
120 'content-type': 'application/json',
121 'accept': 'application/json'},
124 if resp.status_code == status.HTTP_204_NO_CONTENT:
125 logger.info("Sending notification to %s successfully.", callbackuri)
127 logger.error("Sending notification to %s failed: %s" % (callbackuri, resp))
129 logger.error("Post notification failed.")
130 logger.error(traceback.format_exc())
133 class PkgNotifications(NotificationsUtil):
135 Notification Utils for VNF pckages
138 def __init__(self, notification_type, vnf_pkg_id, change_type=None, operational_state=None):
139 super(PkgNotifications, self).__init__(notification_type)
142 'vnfPkgId': 'vnf_pkg_id'
144 self.vnf_pkg_id = vnf_pkg_id
145 self.change_type = change_type
146 self.operational_state = operational_state
147 self.SubscriptionModel = VnfPkgSubscriptionModel
148 self.subscription_root_uri = const.VNFPKG_SUBSCRIPTION_ROOT_URI
149 if self.notification_type == "VnfPackageChangeNotification":
150 self.notifyserializer = PkgChangeNotificationSerializer
152 self.notifyserializer = PkgOnboardingNotificationSerializer
154 def prepare_notification(self):
159 logger.info('Start to prepare Pkgnotification')
161 vnf_pkg = VnfPackageModel.objects.filter(vnfPackageId=self.vnf_pkg_id)
164 vnfd_id = vnf_pkg[0].vnfdId
165 notification_content = {
166 'id': str(uuid.uuid4()), # shall be the same if sent multiple times due to multiple subscriptions.
167 'notificationType': self.notification_type,
168 # set 'subscriptionId' after filtering for subscribers
169 'timeStamp': catalog.pub.utils.timeutil.now_time(),
170 'vnfPkgId': self.vnf_pkg_id,
174 'href': '/%s/vnf_packages/%s' % (const.PKG_URL_PREFIX, self.vnf_pkg_id)
179 if self.notification_type == "VnfPackageChangeNotification":
180 notification_content['changeType'] = self.change_type
181 notification_content['operationalState'] = self.operational_state
183 return notification_content
186 class NsdNotifications(NotificationsUtil):
188 Notification Util for NS packages
191 def __init__(self, notification_type, nsd_info_id, nsd_id, failure_details=None, operational_state=None):
192 super(NsdNotifications, self).__init__(notification_type)
194 'nsdInfoId': 'nsdInfoId',
197 self.SubscriptionModel = NsdmSubscriptionModel
198 self.subscription_root_uri = const.NSDM_SUBSCRIPTION_ROOT_URI
199 self.nsd_info_id = nsd_info_id
201 self.failure_details = failure_details
202 self.operational_state = operational_state
204 # if self.notification_type == "VnfPackageChangeNotification":
205 # self.notifyserializer = PkgChangeNotificationSerializer
207 # self.notifyserializer = PkgOnboardingNotificationSerializer
209 def prepare_notification(self):
214 logger.info('Start to prepare Nsdnotification')
216 notification_content = {
217 'id': str(uuid.uuid4()), # shall be the same if sent multiple times due to multiple subscriptions.
218 'notificationType': self.notification_type,
219 # set 'subscriptionId' after filtering for subscribers
220 'timeStamp': catalog.pub.utils.timeutil.now_time(),
221 'nsdInfoId': self.nsd_info_id,
222 'nsdId': self.nsd_id,
225 'href': '/%s/ns_descriptors/%s' % (
226 const.NSD_URL_PREFIX, self.nsd_info_id)
230 if self.notification_type == "NsdOnboardingFailureNotification":
231 notification_content['onboardingFailureDetails'] = self.failure_details
232 if self.notification_type == "NsdChangeNotification":
233 notification_content['nsdOperationalState'] = self.operational_state
234 return notification_content
237 class PnfNotifications(NotificationsUtil):
239 Notification util for PNF package
241 def __init__(self, notification_type, pnfd_info_id, pnfd_id, failure_details=None):
242 super(PnfNotifications, self).__init__(notification_type)
245 'pnfdInfoIds': 'pnfdInfoIds',
247 self.SubscriptionModel = NsdmSubscriptionModel
248 self.subscription_root_uri = const.NSDM_SUBSCRIPTION_ROOT_URI
249 self.pnfd_info_id = pnfd_info_id
250 self.pnfd_id = pnfd_id
251 self.failure_details = failure_details
253 # if self.notification_type == "VnfPackageChangeNotification":
254 # self.notifyserializer = PkgChangeNotificationSerializer
256 # self.notifyserializer = PkgOnboardingNotificationSerializer
258 def prepare_notification(self, *args, **kwargs):
265 logger.info('Start to prepare Pnfnotification')
266 notification_content = {
267 'id': str(uuid.uuid4()), # shall be the same if sent multiple times due to multiple subscriptions.
268 'notificationType': self.notification_type,
269 # set 'subscriptionId' after filtering for subscribers
270 'timeStamp': catalog.pub.utils.timeutil.now_time(),
271 'pnfdInfoIds': self.pnfd_info_id,
272 'pnfdId': self.pnfd_id,
275 'href': '/%s/pnf_descriptors/%s' % (const.NSD_URL_PREFIX,
280 if self.notification_type == "PnfdOnboardingFailureNotification":
281 notification_content['onboardingFailureDetails'] = self.failure_details
282 return notification_content