1 # Copyright (C) 2018 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 requests.auth import HTTPBasicAuth
21 from rest_framework import status
23 from lcm.nf import const
24 from lcm.pub.database.models import SubscriptionModel
25 from lcm.pub.database.models import VmInstModel
26 from lcm.pub.database.models import NetworkInstModel
27 from lcm.pub.database.models import PortInstModel
28 from lcm.pub.database.models import StorageInstModel
29 from lcm.pub.database.models import VNFCInstModel
30 from lcm.pub.utils.timeutil import now_time
31 from lcm.pub.utils.enumutil import enum
33 logger = logging.getLogger(__name__)
36 lCM_OP_OCC="VnfLcmOperationOccurrenceNotification",
37 CREATION="VnfIdentifierCreationNotification",
38 DELETION="VnfIdentifierDeletionNotification"
42 class NotificationsUtil(object):
43 def send_notification(self, notification):
44 logger.info("Send Notifications to the callbackUri")
46 "operationState": "operation_states",
47 "operation": "operation_types"
49 subscriptions_filter = {v + "__contains": notification[k] for k, v in list(filters.items())}
51 subscriptions = SubscriptionModel.objects.filter(**subscriptions_filter)
52 if not subscriptions.exists():
53 logger.info("No subscriptions created for the filters %s" % notification)
55 logger.info("Start sending notifications")
56 for subscription in subscriptions:
58 notification["subscriptionId"] = subscription.subscription_id
59 notification['_links']['subscription'] = {
60 'href': '/api/vnflcm/v1/subscriptions/%s' % subscription.subscription_id
62 callbackUri = subscription.callback_uri
63 auth_info = json.loads(subscription.auth_info)
64 if auth_info["authType"] != const.OAUTH2_CLIENT_CREDENTIALS:
66 self.post_notification(callbackUri, auth_info, notification)
67 except Exception as e:
68 logger.error("Failed to post notification: %s", e.args[0])
70 def post_notification(self, callbackUri, auth_info, notification):
71 params = auth_info.get("paramsBasic", {})
72 username = params.get("userName")
73 password = params.get("password")
74 logger.info("Sending notification to %s", callbackUri)
78 auth=HTTPBasicAuth(username, password)
80 if resp.status_code != status.HTTP_204_NO_CONTENT:
81 logger.error("Notify %s failed: %s", callbackUri, resp.text)
84 def set_affected_vnfcs(affected_vnfcs, nfinstid, changetype):
85 vnfcs = VNFCInstModel.objects.filter(instid=nfinstid)
89 vm = VmInstModel.objects.filter(vmid=vnfc.vmid)
92 'vimConnectionId': vm[0].vimid,
93 'resourceId': vm[0].resourceid,
94 'resourceProviderId': vm[0].vmname, # TODO: is resourceName mapped to resourceProviderId?
95 'vimLevelResourceType': 'vm'
97 affected_vnfcs.append({
98 'id': vnfc.vnfcinstanceid,
100 'changeType': changetype,
101 'computeResource': vm_resource
103 logger.debug("affected_vnfcs=%s", affected_vnfcs)
104 return affected_vnfcs
107 def set_affected_vls(affected_vls, nfinstid, changetype):
108 networks = NetworkInstModel.objects.filter(instid=nfinstid)
109 for network in networks:
111 'vimConnectionId': network.vimid,
112 'resourceId': network.resourceid,
113 'resourceProviderId': network.name, # TODO: is resourceName mapped to resourceProviderId?
114 'vimLevelResourceType': 'network'
116 affected_vls.append({
117 'id': network.networkid,
118 'virtualLinkDescId': network.nodeId,
119 'changeType': changetype,
120 'networkResource': network_resource
122 logger.debug("affected_vls=%s", affected_vls)
125 def set_ext_connectivity(ext_connectivity, nfinstid):
126 ext_connectivity_map = {}
127 ports = PortInstModel.objects.filter(instid=nfinstid)
129 if port.networkid not in ext_connectivity_map:
130 ext_connectivity_map[port.networkid] = []
131 ext_connectivity_map[port.networkid].append({
132 'id': port.portid, # TODO: port.portid or port.nodeid?
134 'vimConnectionId': port.vimid,
135 'resourceId': port.resourceid,
136 'resourceProviderId': port.name, # TODO: is resourceName mapped to resourceProviderId?
137 'vimLevelResourceType': 'port'
139 'cpInstanceId': port.portid # TODO: port.cpinstanceid is not initiated when create port resource.
141 for network_id, ext_link_ports in list(ext_connectivity_map.items()):
142 networks = NetworkInstModel.objects.filter(networkid=network_id)
143 net_name = networks[0].name if networks else network_id
145 'vimConnectionId': ext_link_ports[0]['resourceHandle']['vimConnectionId'],
146 'resourceId': network_id,
147 'resourceProviderId': net_name, # TODO: is resourceName mapped to resourceProviderId?
148 'vimLevelResourceType': 'network'
150 ext_connectivity.append({
152 'resourceHandle': network_resource,
153 'extLinkPorts': ext_link_ports
155 logger.debug("ext_connectivity=%s", ext_connectivity)
158 def set_affected_vss(affected_vss, nfinstid, changetype):
159 vss = StorageInstModel.objects.filter(instid=nfinstid)
161 affected_vss.append({
163 'virtualStorageDescId': vs.nodeId,
164 'changeType': changetype,
166 'vimConnectionId': vs.vimid,
167 'resourceId': vs.resourceid,
168 'resourceProviderId': vs.name, # TODO: is resourceName mapped to resourceProviderId?
169 'vimLevelResourceType': 'volume'
172 logger.debug("affected_vss=%s", affected_vss)
175 def get_notification_status(operation_state):
176 if operation_state == const.OPERATION_STATE_TYPE.STARTING:
177 return const.LCM_NOTIFICATION_STATUS.START
178 return const.LCM_NOTIFICATION_STATUS.RESULT
181 def prepare_notification(nfinstid, jobid, operation, operation_state):
182 logger.info('Start to prepare notification')
183 notification_content = {
184 'id': str(uuid.uuid4()), # shall be the same if sent multiple times due to multiple subscriptions.
185 'notificationType': NOTIFY_TYPE.lCM_OP_OCC,
186 # set 'subscriptionId' after filtering for subscribers
187 'timeStamp': now_time(),
188 'notificationStatus': get_notification_status(operation_state),
189 'operationState': operation_state,
190 'vnfInstanceId': nfinstid,
191 'operation': operation,
192 'isAutomaticInvocation': False,
193 'vnfLcmOpOccId': jobid,
195 'affectedVirtualLinks': [],
196 'affectedVirtualStorages': [],
197 'changedExtConnectivity': [],
201 'href': '%s/vnf_instances/%s' % (const.URL_PREFIX, nfinstid)
204 'href': '%s/vnf_lcm_op_occs/%s' % (const.URL_PREFIX, jobid)
208 return notification_content
211 def prepare_notification_data(nfinstid, jobid, changetype, operation):
212 data = prepare_notification(
216 operation_state=const.OPERATION_STATE_TYPE.COMPLETED
219 set_affected_vnfcs(data['affectedVnfcs'], nfinstid, changetype)
220 set_affected_vls(data['affectedVirtualLinks'], nfinstid, changetype)
221 set_affected_vss(data['affectedVirtualStorages'], nfinstid, changetype)
222 set_ext_connectivity(data['changedExtConnectivity'], nfinstid)
224 logger.debug('Notification content: %s' % data)
228 def prepare_vnf_identifier_notification(notify_type, nfinstid):
230 "id": str(uuid.uuid4()), # shall be the same if sent multiple times due to multiple subscriptions.
231 "notificationType": notify_type,
232 "timeStamp": now_time(),
233 "vnfInstanceId": nfinstid,
236 'href': '%s/vnf_instances/%s' % (const.URL_PREFIX, nfinstid)
241 logger.debug('Vnf Identifier Notification: %s' % data)