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 const.BASIC in auth_info["authType"]:
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 headers={'content-type': 'application/json'},
79 auth=HTTPBasicAuth(username, password)
81 if resp.status_code != status.HTTP_204_NO_CONTENT:
82 logger.error("Notify %s failed: %s", callbackUri, resp.text)
85 def set_affected_vnfcs(affected_vnfcs, nfinstid, changetype):
86 vnfcs = VNFCInstModel.objects.filter(instid=nfinstid)
90 vm = VmInstModel.objects.filter(vmid=vnfc.vmid)
93 'vimConnectionId': vm[0].vimid,
94 'resourceId': vm[0].resourceid,
95 'resourceProviderId': vm[0].vmname, # TODO: is resourceName mapped to resourceProviderId?
96 'vimLevelResourceType': 'vm'
98 affected_vnfcs.append({
99 'id': vnfc.vnfcinstanceid,
101 'changeType': changetype,
102 'computeResource': vm_resource
104 logger.debug("affected_vnfcs=%s", affected_vnfcs)
105 return affected_vnfcs
108 def set_affected_vls(affected_vls, nfinstid, changetype):
109 networks = NetworkInstModel.objects.filter(instid=nfinstid)
110 for network in networks:
112 'vimConnectionId': network.vimid,
113 'resourceId': network.resourceid,
114 'resourceProviderId': network.name, # TODO: is resourceName mapped to resourceProviderId?
115 'vimLevelResourceType': 'network'
117 affected_vls.append({
118 'id': network.networkid,
119 'virtualLinkDescId': network.nodeId,
120 'changeType': changetype,
121 'networkResource': network_resource
123 logger.debug("affected_vls=%s", affected_vls)
126 def set_ext_connectivity(ext_connectivity, nfinstid):
127 ext_connectivity_map = {}
128 ports = PortInstModel.objects.filter(instid=nfinstid)
130 if port.networkid not in ext_connectivity_map:
131 ext_connectivity_map[port.networkid] = []
132 ext_connectivity_map[port.networkid].append({
133 'id': port.portid, # TODO: port.portid or port.nodeid?
135 'vimConnectionId': port.vimid,
136 'resourceId': port.resourceid,
137 'resourceProviderId': port.name, # TODO: is resourceName mapped to resourceProviderId?
138 'vimLevelResourceType': 'port'
140 'cpInstanceId': port.portid # TODO: port.cpinstanceid is not initiated when create port resource.
142 for network_id, ext_link_ports in list(ext_connectivity_map.items()):
143 networks = NetworkInstModel.objects.filter(networkid=network_id)
144 net_name = networks[0].name if networks else network_id
146 'vimConnectionId': ext_link_ports[0]['resourceHandle']['vimConnectionId'],
147 'resourceId': network_id,
148 'resourceProviderId': net_name, # TODO: is resourceName mapped to resourceProviderId?
149 'vimLevelResourceType': 'network'
151 ext_connectivity.append({
153 'resourceHandle': network_resource,
154 'extLinkPorts': ext_link_ports
156 logger.debug("ext_connectivity=%s", ext_connectivity)
159 def set_affected_vss(affected_vss, nfinstid, changetype):
160 vss = StorageInstModel.objects.filter(instid=nfinstid)
162 affected_vss.append({
164 'virtualStorageDescId': vs.nodeId,
165 'changeType': changetype,
167 'vimConnectionId': vs.vimid,
168 'resourceId': vs.resourceid,
169 'resourceProviderId': vs.name, # TODO: is resourceName mapped to resourceProviderId?
170 'vimLevelResourceType': 'volume'
173 logger.debug("affected_vss=%s", affected_vss)
176 def get_notification_status(operation_state):
177 if operation_state == const.OPERATION_STATE_TYPE.STARTING:
178 return const.LCM_NOTIFICATION_STATUS.START
179 return const.LCM_NOTIFICATION_STATUS.RESULT
182 def prepare_notification(nfinstid, jobid, operation, operation_state):
183 logger.info('Start to prepare notification')
184 notification_content = {
185 'id': str(uuid.uuid4()), # shall be the same if sent multiple times due to multiple subscriptions.
186 'notificationType': NOTIFY_TYPE.lCM_OP_OCC,
187 # set 'subscriptionId' after filtering for subscribers
188 'timeStamp': now_time(),
189 'notificationStatus': get_notification_status(operation_state),
190 'operationState': operation_state,
191 'vnfInstanceId': nfinstid,
192 'operation': operation,
193 'isAutomaticInvocation': False,
194 'vnfLcmOpOccId': jobid,
196 'affectedVirtualLinks': [],
197 'affectedVirtualStorages': [],
198 'changedExtConnectivity': [],
202 'href': '%s/vnf_instances/%s' % (const.URL_PREFIX, nfinstid)
205 'href': '%s/vnf_lcm_op_occs/%s' % (const.URL_PREFIX, jobid)
209 return notification_content
212 def prepare_notification_data(nfinstid, jobid, changetype, operation):
213 data = prepare_notification(
217 operation_state=const.OPERATION_STATE_TYPE.COMPLETED
220 set_affected_vnfcs(data['affectedVnfcs'], nfinstid, changetype)
221 set_affected_vls(data['affectedVirtualLinks'], nfinstid, changetype)
222 set_affected_vss(data['affectedVirtualStorages'], nfinstid, changetype)
223 set_ext_connectivity(data['changedExtConnectivity'], nfinstid)
225 logger.debug('Notification content: %s' % data)
229 def prepare_vnf_identifier_notification(notify_type, nfinstid):
231 "id": str(uuid.uuid4()), # shall be the same if sent multiple times due to multiple subscriptions.
232 "notificationType": notify_type,
233 "timeStamp": now_time(),
234 "vnfInstanceId": nfinstid,
237 'href': '%s/vnf_instances/%s' % (const.URL_PREFIX, nfinstid)
242 logger.debug('Vnf Identifier Notification: %s' % data)