Adds support for vdu_name, ns_id and vnf_member_index
[osm/MON.git] / osm_mon / plugins / vRealiseOps / mon_plugin_vrops.py
1 # -*- coding: utf-8 -*-
2
3 ##
4 # Copyright 2016-2017 VMware Inc.
5 # This file is part of ETSI OSM
6 # All Rights Reserved.
7 #
8 # Licensed under the Apache License, Version 2.0 (the "License"); you may
9 # not use this file except in compliance with the License. You may obtain
10 # a copy of the License at
11 #
12 # http://www.apache.org/licenses/LICENSE-2.0
13 #
14 # Unless required by applicable law or agreed to in writing, software
15 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17 # License for the specific language governing permissions and limitations
18 # under the License.
19 #
20 # For those usages not covered by the Apache License, Version 2.0 please
21 # contact: osslegalrouting@vmware.com
22 ##
23
24 """
25 Monitoring metrics & creating Alarm definitions in vROPs
26 """
27
28 import requests
29 import logging
30
31 import six
32 from pyvcloud.vcd.client import BasicLoginCredentials
33 from pyvcloud.vcd.client import Client
34 API_VERSION = '5.9'
35
36 from xml.etree import ElementTree as XmlElementTree
37 import traceback
38 import time
39 import json
40 from OpenSSL.crypto import load_certificate, FILETYPE_PEM
41 import os
42 import datetime
43 from socket import getfqdn
44
45 import urllib3
46 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
47
48 OPERATION_MAPPING = {'GE':'GT_EQ', 'LE':'LT_EQ', 'GT':'GT', 'LT':'LT', 'EQ':'EQ'}
49 severity_mano2vrops = {'WARNING':'WARNING', 'MINOR':'WARNING', 'MAJOR':"IMMEDIATE",\
50 'CRITICAL':'CRITICAL', 'INDETERMINATE':'UNKNOWN'}
51 PERIOD_MSEC = {'HR':3600000,'DAY':86400000,'WEEK':604800000,'MONTH':2678400000,'YEAR':31536000000}
52
53 #To Do - Add actual webhook url & certificate
54 #SSL_CERTIFICATE_FILE_NAME = 'vROPs_Webservice/SSL_certificate/www.vrops_webservice.com.cert'
55 #webhook_url = "https://mano-dev-1:8080/notify/" #for testing
56 webhook_url = "https://" + getfqdn() + ":8080/notify/"
57 SSL_CERTIFICATE_FILE_NAME = ('vROPs_Webservice/SSL_certificate/' + getfqdn() + ".cert")
58 #SSL_CERTIFICATE_FILE_NAME = 'vROPs_Webservice/SSL_certificate/10.172.137.214.cert' #for testing
59
60 MODULE_DIR = os.path.dirname(__file__)
61 CONFIG_FILE_NAME = 'vrops_config.xml'
62 CONFIG_FILE_PATH = os.path.join(MODULE_DIR, CONFIG_FILE_NAME)
63 SSL_CERTIFICATE_FILE_PATH = os.path.join(MODULE_DIR, SSL_CERTIFICATE_FILE_NAME)
64
65 class MonPlugin():
66 """MON Plugin class for vROPs telemetry plugin
67 """
68 def __init__(self):
69 """Constructor of MON plugin
70 Params:
71 'access_config': dictionary with VIM access information based on VIM type.
72 This contains a consolidate version of VIM & monitoring tool config at creation and
73 particular VIM config at their attachment.
74 For VIM type: 'vmware',
75 access_config - {'vrops_site':<>, 'vrops_user':<>, 'vrops_password':<>,
76 'vcloud-site':<>,'admin_username':<>,'admin_password':<>,
77 'nsx_manager':<>,'nsx_user':<>,'nsx_password':<>,
78 'vcenter_ip':<>,'vcenter_port':<>,'vcenter_user':<>,'vcenter_password':<>,
79 'vim_tenant_name':<>,'orgname':<>}
80
81 #To Do
82 Returns: Raise an exception if some needed parameter is missing, but it must not do any connectivity
83 check against the VIM
84 """
85 self.logger = logging.getLogger('PluginReceiver.MonPlugin')
86 self.logger.setLevel(logging.DEBUG)
87
88 access_config = self.get_default_Params('Access_Config')
89 self.access_config = access_config
90 if not bool(access_config):
91 self.logger.error("Access configuration not provided in vROPs Config file")
92 raise KeyError("Access configuration not provided in vROPs Config file")
93
94 try:
95 self.vrops_site = access_config['vrops_site']
96 self.vrops_user = access_config['vrops_user']
97 self.vrops_password = access_config['vrops_password']
98 self.vcloud_site = access_config['vcloud-site']
99 self.admin_username = access_config['admin_username']
100 self.admin_password = access_config['admin_password']
101 self.tenant_id = access_config['tenant_id']
102 except KeyError as exp:
103 self.logger.error("Check Access configuration in vROPs Config file: {}".format(exp))
104 raise KeyError("Check Access configuration in vROPs Config file: {}".format(exp))
105
106
107 def configure_alarm(self, config_dict = {}):
108 """Configures or creates a new alarm using the input parameters in config_dict
109 Params:
110 "alarm_name": Alarm name in string format
111 "description": Description of alarm in string format
112 "resource_uuid": Resource UUID for which alarm needs to be configured. in string format
113 "Resource type": String resource type: 'VDU' or 'host'
114 "Severity": 'WARNING', 'MINOR', 'MAJOR', 'CRITICAL'
115 "metric_name": Metric key in string format
116 "operation": One of ('GE', 'LE', 'GT', 'LT', 'EQ')
117 "threshold_value": Defines the threshold (up to 2 fraction digits) that,
118 if crossed, will trigger the alarm.
119 "unit": Unit of measurement in string format
120 "statistic": AVERAGE, MINIMUM, MAXIMUM, COUNT, SUM
121
122 Default parameters for each alarm are read from the plugin specific config file.
123 Dict of default parameters is as follows:
124 default_params keys = {'cancel_cycles','wait_cycles','resource_kind','adapter_kind',
125 'alarm_type','alarm_subType',impact}
126
127 Returns the UUID of created alarm or None
128 """
129 alarm_def = None
130 #1) get alarm & metrics parameters from plugin specific file
131 def_a_params = self.get_default_Params(config_dict['alarm_name'])
132 if not def_a_params:
133 self.logger.warning("Alarm not supported: {}".format(config_dict['alarm_name']))
134 return None
135 metric_key_params = self.get_default_Params(config_dict['metric_name'])
136 if not metric_key_params:
137 self.logger.warning("Metric not supported: {}".format(config_dict['metric_name']))
138 return None
139
140 #1.2) Check if alarm definition already exists
141 vrops_alarm_name = def_a_params['vrops_alarm']+ '-' + config_dict['resource_uuid']
142 alert_def_list = self.get_alarm_defination_by_name(vrops_alarm_name)
143 if alert_def_list:
144 self.logger.warning("Alarm already exists: {}. Try updating by update_alarm_request"\
145 .format(vrops_alarm_name))
146 return None
147
148 #2) create symptom definition
149 symptom_params ={'cancel_cycles': (def_a_params['cancel_period']/300)*def_a_params['cancel_cycles'],
150 'wait_cycles': (def_a_params['period']/300)*def_a_params['evaluation'],
151 'resource_kind_key': def_a_params['resource_kind'],
152 'adapter_kind_key': def_a_params['adapter_kind'],
153 'symptom_name':vrops_alarm_name,
154 'severity': severity_mano2vrops[config_dict['severity']],
155 'metric_key':metric_key_params['metric_key'],
156 'operation':OPERATION_MAPPING[config_dict['operation']],
157 'threshold_value':config_dict['threshold_value']}
158 symptom_uuid = self.create_symptom(symptom_params)
159 if symptom_uuid is not None:
160 self.logger.info("Symptom defined: {} with ID: {}".format(symptom_params['symptom_name'],symptom_uuid))
161 else:
162 self.logger.warning("Failed to create Symptom: {}".format(symptom_params['symptom_name']))
163 return None
164 #3) create alert definition
165 #To Do - Get type & subtypes for all 5 alarms
166 alarm_params = {'name':vrops_alarm_name,
167 'description':config_dict['description']\
168 if 'description' in config_dict and config_dict['description'] is not None else config_dict['alarm_name'],
169 'adapterKindKey':def_a_params['adapter_kind'],
170 'resourceKindKey':def_a_params['resource_kind'],
171 'waitCycles':1, 'cancelCycles':1,
172 'type':def_a_params['alarm_type'], 'subType':def_a_params['alarm_subType'],
173 'severity':severity_mano2vrops[config_dict['severity']],
174 'symptomDefinitionId':symptom_uuid,
175 'impact':def_a_params['impact']}
176
177 alarm_def = self.create_alarm_definition(alarm_params)
178 if alarm_def is None:
179 self.logger.warning("Failed to create Alert: {}".format(alarm_params['name']))
180 return None
181
182 self.logger.info("Alarm defined: {} with ID: {}".format(alarm_params['name'],alarm_def))
183
184 #4) Find vm_moref_id from vApp uuid in vCD
185 vm_moref_id = self.get_vm_moref_id(config_dict['resource_uuid'])
186 if vm_moref_id is None:
187 self.logger.warning("Failed to find vm morefid for vApp in vCD: {}".format(config_dict['resource_uuid']))
188 return None
189
190 #5) Based on vm_moref_id, find VM's corresponding resource_id in vROPs to set notification
191 resource_id = self.get_vm_resource_id(vm_moref_id)
192 if resource_id is None:
193 self.logger.warning("Failed to find resource in vROPs: {}".format(config_dict['resource_uuid']))
194 return None
195
196 #6) Configure alarm notification for a particular VM using it's resource_id
197 notification_id = self.create_alarm_notification_rule(vrops_alarm_name, alarm_def, resource_id)
198 if notification_id is None:
199 return None
200 else:
201 alarm_def_uuid = alarm_def.split('-', 1)[1]
202 self.logger.info("Alarm defination created with notification: {} with ID: {}"\
203 .format(alarm_params['name'],alarm_def_uuid))
204 #Return alarm defination UUID by removing 'AlertDefinition' from UUID
205 return (alarm_def_uuid)
206
207 def get_default_Params(self, metric_alarm_name):
208 """
209 Read the default config parameters from plugin specific file stored with plugin file.
210 Params:
211 metric_alarm_name: Name of the alarm, whose config parameters to be read from the config file.
212 """
213 a_params = {}
214 try:
215 source = open(CONFIG_FILE_PATH, 'r')
216 except IOError as exp:
217 msg = ("Could not read Config file: {}, \nException: {}"\
218 .format(CONFIG_FILE_PATH, exp))
219 self.logger.error(msg)
220 raise IOError(msg)
221
222 tree = XmlElementTree.parse(source)
223 alarms = tree.getroot()
224 for alarm in alarms:
225 if alarm.tag == metric_alarm_name:
226 for param in alarm:
227 if param.tag in ("period", "evaluation", "cancel_period", "alarm_type",\
228 "cancel_cycles", "alarm_subType"):
229 a_params[param.tag] = int(param.text)
230 elif param.tag in ("enabled", "repeat"):
231 if(param.text.lower() == "true"):
232 a_params[param.tag] = True
233 else:
234 a_params[param.tag] = False
235 else:
236 a_params[param.tag] = param.text
237 source.close()
238 return a_params
239
240
241 def create_symptom(self, symptom_params):
242 """Create Symptom definition for an alarm
243 Params:
244 symptom_params: Dict of parameters required for defining a symptom as follows
245 cancel_cycles
246 wait_cycles
247 resource_kind_key = "VirtualMachine"
248 adapter_kind_key = "VMWARE"
249 symptom_name = Test_Memory_Usage_TooHigh
250 severity
251 metric_key
252 operation = GT_EQ
253 threshold_value = 85
254 Returns the uuid of Symptom definition
255 """
256 symptom_id = None
257
258 try:
259 api_url = '/suite-api/api/symptomdefinitions'
260 headers = {'Content-Type': 'application/json','Accept': 'application/json'}
261 data = {
262 "id": None,
263 "name": symptom_params['symptom_name'],
264 "adapterKindKey": symptom_params['adapter_kind_key'],
265 "resourceKindKey": symptom_params['resource_kind_key'],
266 "waitCycles": symptom_params['wait_cycles'],
267 "cancelCycles": symptom_params['cancel_cycles'],
268 "state": {
269 "severity": symptom_params['severity'],
270 "condition": {
271 "type": "CONDITION_HT",
272 "key": symptom_params['metric_key'],
273 "operator": symptom_params['operation'],
274 "value": symptom_params['threshold_value'],
275 "valueType": "NUMERIC",
276 "instanced": False,
277 "thresholdType": "STATIC"
278 }
279 }
280 }
281
282 resp = requests.post(self.vrops_site + api_url,
283 auth=(self.vrops_user, self.vrops_password),
284 headers=headers,
285 verify = False,
286 data=json.dumps(data))
287
288 if resp.status_code != 201:
289 self.logger.warning("Failed to create Symptom definition: {}, response {}"\
290 .format(symptom_params['symptom_name'], resp.content))
291 return None
292
293 resp_data = json.loads(resp.content)
294 if resp_data.get('id') is not None:
295 symptom_id = resp_data['id']
296
297 return symptom_id
298
299 except Exception as exp:
300 self.logger.warning("Error creating symptom definition : {}\n{}"\
301 .format(exp, traceback.format_exc()))
302
303
304 def create_alarm_definition(self, alarm_params):
305 """
306 Create an alarm definition in vROPs
307 Params:
308 'name': Alarm Name,
309 'description':Alarm description,
310 'adapterKindKey': Adapter type in vROPs "VMWARE",
311 'resourceKindKey':Resource type in vROPs "VirtualMachine",
312 'waitCycles': No of wait cycles,
313 'cancelCycles': No of cancel cycles,
314 'type': Alarm type,
315 'subType': Alarm subtype,
316 'severity': Severity in vROPs "CRITICAL",
317 'symptomDefinitionId':symptom Definition uuid,
318 'impact': impact 'risk'
319 Returns:
320 'alarm_uuid': returns alarm uuid
321 """
322
323 alarm_uuid = None
324
325 try:
326 api_url = '/suite-api/api/alertdefinitions'
327 headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
328 data = {
329 "name": alarm_params['name'],
330 "description": alarm_params['description'],
331 "adapterKindKey": alarm_params['adapterKindKey'],
332 "resourceKindKey": alarm_params['resourceKindKey'],
333 "waitCycles": 1,
334 "cancelCycles": 1,
335 "type": alarm_params['type'],
336 "subType": alarm_params['subType'],
337 "states": [
338 {
339 "severity": alarm_params['severity'],
340 "base-symptom-set":
341 {
342 "type": "SYMPTOM_SET",
343 "relation": "SELF",
344 "aggregation": "ALL",
345 "symptomSetOperator": "AND",
346 "symptomDefinitionIds": [alarm_params['symptomDefinitionId']]
347 },
348 "impact": {
349 "impactType": "BADGE",
350 "detail": alarm_params['impact']
351 }
352 }
353 ]
354 }
355
356 resp = requests.post(self.vrops_site + api_url,
357 auth=(self.vrops_user, self.vrops_password),
358 headers=headers,
359 verify = False,
360 data=json.dumps(data))
361
362 if resp.status_code != 201:
363 self.logger.warning("Failed to create Alarm definition: {}, response {}"\
364 .format(alarm_params['name'], resp.content))
365 return None
366
367 resp_data = json.loads(resp.content)
368 if resp_data.get('id') is not None:
369 alarm_uuid = resp_data['id']
370
371 return alarm_uuid
372
373 except Exception as exp:
374 self.logger.warning("Error creating alarm definition : {}\n{}".format(exp, traceback.format_exc()))
375
376
377 def configure_rest_plugin(self):
378 """
379 Creates REST Plug-in for vROPs outbound alerts
380
381 Returns Plugin ID
382 """
383 plugin_id = None
384 plugin_name = 'MON_module_REST_Plugin'
385 plugin_id = self.check_if_plugin_configured(plugin_name)
386
387 #If REST plugin not configured, configure it
388 if plugin_id is not None:
389 return plugin_id
390 else:
391 try:
392 cert_file_string = open(SSL_CERTIFICATE_FILE_PATH, "rb").read()
393 except IOError as exp:
394 msg = ("Could not read SSL certificate file: {}".format(SSL_CERTIFICATE_FILE_PATH))
395 self.logger.error(msg)
396 raise IOError(msg)
397 cert = load_certificate(FILETYPE_PEM, cert_file_string)
398 certificate = cert.digest("sha1")
399 api_url = '/suite-api/api/alertplugins'
400 headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
401 data = {
402 "pluginTypeId": "RestPlugin",
403 "name": plugin_name,
404 "configValues": [
405 {
406 "name": "Url",
407 "value": webhook_url
408 },
409 {
410 "name": "Content-type",
411 "value": "application/json"
412 },
413 {
414 "name": "Certificate",
415 "value": certificate
416 },
417 {
418 "name": "ConnectionCount",
419 "value": "20"
420 }
421 ]
422 }
423
424 resp = requests.post(self.vrops_site + api_url,
425 auth=(self.vrops_user, self.vrops_password),
426 headers=headers,
427 verify = False,
428 data=json.dumps(data))
429
430 if resp.status_code is not 201:
431 self.logger.warning("Failed to create REST Plugin: {} for url: {}, \nresponse code: {},"\
432 "\nresponse content: {}".format(plugin_name, webhook_url,\
433 resp.status_code, resp.content))
434 return None
435
436 resp_data = json.loads(resp.content)
437 if resp_data.get('pluginId') is not None:
438 plugin_id = resp_data['pluginId']
439
440 if plugin_id is None:
441 self.logger.warning("Failed to get REST Plugin ID for {}, url: {}".format(plugin_name, webhook_url))
442 return None
443 else:
444 self.logger.info("Created REST Plugin: {} with ID : {} for url: {}".format(plugin_name, plugin_id, webhook_url))
445 status = self.enable_rest_plugin(plugin_id, plugin_name)
446 if status is False:
447 self.logger.warning("Failed to enable created REST Plugin: {} for url: {}".format(plugin_name, webhook_url))
448 return None
449 else:
450 self.logger.info("Enabled REST Plugin: {} for url: {}".format(plugin_name, webhook_url))
451 return plugin_id
452
453 def check_if_plugin_configured(self, plugin_name):
454 """Check if the REST plugin is already created
455 Returns: plugin_id: if already created, None: if needs to be created
456 """
457 plugin_id = None
458 #Find the REST Plugin id details for - MON_module_REST_Plugin
459 api_url = '/suite-api/api/alertplugins'
460 headers = {'Accept': 'application/json'}
461
462 resp = requests.get(self.vrops_site + api_url,
463 auth=(self.vrops_user, self.vrops_password),
464 verify = False, headers = headers)
465
466 if resp.status_code is not 200:
467 self.logger.warning("Failed to REST GET Alarm plugin details \nResponse code: {}\nResponse content: {}"\
468 .format(resp.status_code, resp.content))
469 return None
470
471 # Look for specific plugin & parse pluginId for 'MON_module_REST_Plugin'
472 plugins_list = json.loads(resp.content)
473 if plugins_list.get('notificationPluginInstances') is not None:
474 for notify_plugin in plugins_list['notificationPluginInstances']:
475 if notify_plugin.get('name') is not None and notify_plugin['name'] == plugin_name:
476 plugin_id = notify_plugin.get('pluginId')
477
478 if plugin_id is None:
479 self.logger.warning("REST plugin {} not found".format(plugin_name))
480 return None
481 else:
482 self.logger.info("Found REST Plugin: {}".format(plugin_name))
483 return plugin_id
484
485
486 def enable_rest_plugin(self, plugin_id, plugin_name):
487 """
488 Enable the REST plugin using plugin_id
489 Params: plugin_id: plugin ID string that is to be enabled
490 Returns: status (Boolean) - True for success, False for failure
491 """
492
493 if plugin_id is None or plugin_name is None:
494 self.logger.debug("enable_rest_plugin() : Plugin ID or plugin_name not provided for {} plugin"\
495 .format(plugin_name))
496 return False
497
498 try:
499 api_url = "/suite-api/api/alertplugins/{}/enable/True".format(plugin_id)
500
501 resp = requests.put(self.vrops_site + api_url,
502 auth=(self.vrops_user, self.vrops_password),
503 verify = False)
504
505 if resp.status_code is not 204:
506 self.logger.warning("Failed to enable REST plugin {}. \nResponse code {}\nResponse Content: {}"\
507 .format(plugin_name, resp.status_code, resp.content))
508 return False
509
510 self.logger.info("Enabled REST plugin {}.".format(plugin_name))
511 return True
512
513 except Exception as exp:
514 self.logger.warning("Error enabling REST plugin for {} plugin: Exception: {}\n{}"\
515 .format(plugin_name, exp, traceback.format_exc()))
516
517 def create_alarm_notification_rule(self, alarm_name, alarm_id, resource_id):
518 """
519 Create notification rule for each alarm
520 Params:
521 alarm_name
522 alarm_id
523 resource_id
524
525 Returns:
526 notification_id: notification_id or None
527 """
528 notification_name = 'notify_' + alarm_name
529 notification_id = None
530 plugin_name = 'MON_module_REST_Plugin'
531
532 #1) Find the REST Plugin id details for - MON_module_REST_Plugin
533 plugin_id = self.check_if_plugin_configured(plugin_name)
534 if plugin_id is None:
535 self.logger.warning("Failed to get REST plugin_id for : {}".format('MON_module_REST_Plugin'))
536 return None
537
538 #2) Create Alarm notification rule
539 api_url = '/suite-api/api/notifications/rules'
540 headers = {'Content-Type': 'application/json', 'Accept': 'application/json'}
541 data = {
542 "name" : notification_name,
543 "pluginId" : plugin_id,
544 "resourceFilter": {
545 "matchResourceIdOnly": True,
546 "resourceId": resource_id
547 },
548 "alertDefinitionIdFilters" : {
549 "values" : [ alarm_id ]
550 }
551 }
552
553 resp = requests.post(self.vrops_site + api_url,
554 auth=(self.vrops_user, self.vrops_password),
555 headers=headers,
556 verify = False,
557 data=json.dumps(data))
558
559 if resp.status_code is not 201:
560 self.logger.warning("Failed to create Alarm notification rule {} for {} alarm."\
561 "\nResponse code: {}\nResponse content: {}"\
562 .format(notification_name, alarm_name, resp.status_code, resp.content))
563 return None
564
565 #parse notification id from response
566 resp_data = json.loads(resp.content)
567 if resp_data.get('id') is not None:
568 notification_id = resp_data['id']
569
570 self.logger.info("Created Alarm notification rule {} for {} alarm.".format(notification_name, alarm_name))
571 return notification_id
572
573 def get_vm_moref_id(self, vapp_uuid):
574 """
575 Get the moref_id of given VM
576 """
577 try:
578 if vapp_uuid:
579 vm_details = self.get_vapp_details_rest(vapp_uuid)
580 if vm_details and "vm_vcenter_info" in vm_details:
581 vm_moref_id = vm_details["vm_vcenter_info"].get("vm_moref_id", None)
582
583 self.logger.info("Found vm_moref_id: {} for vApp UUID: {}".format(vm_moref_id, vapp_uuid))
584 return vm_moref_id
585
586 except Exception as exp:
587 self.logger.warning("Error occurred while getting VM moref ID for VM : {}\n{}"\
588 .format(exp, traceback.format_exc()))
589
590
591 def get_vapp_details_rest(self, vapp_uuid=None):
592 """
593 Method retrieve vapp detail from vCloud director
594
595 Args:
596 vapp_uuid - is vapp identifier.
597
598 Returns:
599 Returns VM MOref ID or return None
600 """
601
602 parsed_respond = {}
603 vca = None
604
605 if vapp_uuid is None:
606 return None
607
608 vca = self.connect_as_admin()
609 if not vca:
610 self.logger.warning("Failed to connect to vCD")
611 return parsed_respond
612
613 url_list = [self.vcloud_site, '/api/vApp/vapp-', vapp_uuid]
614 get_vapp_restcall = ''.join(url_list)
615
616 if vca._session:
617 headers = {'Accept':'application/*+xml;version=' + API_VERSION,
618 'x-vcloud-authorization': vca._session.headers['x-vcloud-authorization']}
619 response = requests.get(get_vapp_restcall,
620 headers=headers,
621 verify=False)
622
623 if response.status_code != 200:
624 self.logger.warning("REST API call {} failed. Return status code {}"\
625 .format(get_vapp_restcall, response.content))
626 return parsed_respond
627
628 try:
629 xmlroot_respond = XmlElementTree.fromstring(response.content)
630
631 namespaces = {'vm': 'http://www.vmware.com/vcloud/v1.5',
632 "vmext":"http://www.vmware.com/vcloud/extension/v1.5",
633 "xmlns":"http://www.vmware.com/vcloud/v1.5"
634 }
635
636 # parse children section for other attrib
637 children_section = xmlroot_respond.find('vm:Children/', namespaces)
638 if children_section is not None:
639 vCloud_extension_section = children_section.find('xmlns:VCloudExtension', namespaces)
640 if vCloud_extension_section is not None:
641 vm_vcenter_info = {}
642 vim_info = vCloud_extension_section.find('vmext:VmVimInfo', namespaces)
643 vmext = vim_info.find('vmext:VmVimObjectRef', namespaces)
644 if vmext is not None:
645 vm_vcenter_info["vm_moref_id"] = vmext.find('vmext:MoRef', namespaces).text
646 parsed_respond["vm_vcenter_info"]= vm_vcenter_info
647
648 except Exception as exp :
649 self.logger.warning("Error occurred calling rest api for getting vApp details: {}\n{}"\
650 .format(exp, traceback.format_exc()))
651
652 return parsed_respond
653
654
655 def connect_as_admin(self):
656 """ Method connect as pvdc admin user to vCloud director.
657 There are certain action that can be done only by provider vdc admin user.
658 Organization creation / provider network creation etc.
659
660 Returns:
661 The return vca object that letter can be used to connect to vcloud direct as admin for provider vdc
662 """
663
664 self.logger.debug("Logging into vCD org as admin.")
665
666 try:
667 host = self.vcloud_site
668 org = 'System'
669 client_as_admin = Client(host, verify_ssl_certs=False)
670 client_as_admin.set_credentials(BasicLoginCredentials(self.admin_username, org,\
671 self.admin_password))
672 except Exception as e:
673 self.logger.warning("Can't connect to a vCloud director as: {} with exception {}"\
674 .format(self.admin_username, e))
675
676 return client_as_admin
677
678
679 def get_vm_resource_id(self, vm_moref_id):
680 """ Find resource ID in vROPs using vm_moref_id
681 """
682 if vm_moref_id is None:
683 return None
684
685 api_url = '/suite-api/api/resources?resourceKind=VirtualMachine'
686 headers = {'Accept': 'application/json'}
687
688 resp = requests.get(self.vrops_site + api_url,
689 auth=(self.vrops_user, self.vrops_password),
690 verify = False, headers = headers)
691
692 if resp.status_code is not 200:
693 self.logger.warning("Failed to get resource details from vROPs for {}"\
694 "\nResponse code:{}\nResponse Content: {}"\
695 .format(vm_moref_id, resp.status_code, resp.content))
696 return None
697
698 vm_resource_id = None
699 try:
700 resp_data = json.loads(resp.content)
701 if resp_data.get('resourceList') is not None:
702 resource_list = resp_data.get('resourceList')
703 for resource in resource_list:
704 if resource.get('resourceKey') is not None:
705 resource_details = resource['resourceKey']
706 if resource_details.get('resourceIdentifiers') is not None:
707 resource_identifiers = resource_details['resourceIdentifiers']
708 for resource_identifier in resource_identifiers:
709 if resource_identifier['identifierType']['name']=='VMEntityObjectID':
710 if resource_identifier.get('value') is not None and \
711 resource_identifier['value']==vm_moref_id:
712 vm_resource_id = resource['identifier']
713 self.logger.info("Found VM resource ID: {} for vm_moref_id: {}"\
714 .format(vm_resource_id, vm_moref_id))
715
716 except Exception as exp:
717 self.logger.warning("get_vm_resource_id: Error in parsing {}\n{}"\
718 .format(exp, traceback.format_exc()))
719
720 return vm_resource_id
721
722
723 def get_metrics_data(self, metric={}):
724 """Get an individual metric's data of a resource.
725 Params:
726 'metric_name': Normalized name of metric (string)
727 'resource_uuid': Resource UUID (string)
728 'period': Time period in Period Unit for which metrics data to be collected from
729 Monitoring tool from now.
730 'period_unit': Period measurement unit can be one of 'HR', 'DAY', 'MONTH', 'YEAR'
731
732 Return a dict that contains:
733 'metric_name': Normalized name of metric (string)
734 'resource_uuid': Resource UUID (string)
735 'tenant_id': tenent id name in which the resource is present in string format
736 'metrics_data': Dictionary containing time_series & metrics_series data.
737 'time_series': List of individual time stamp values in msec
738 'metrics_series': List of individual metrics data values
739 Raises an exception upon error or when network is not found
740 """
741 return_data = {}
742 return_data['schema_version'] = "1.0"
743 return_data['schema_type'] = 'read_metric_data_response'
744 return_data['metric_name'] = metric['metric_name']
745 #To do - No metric_uuid in vROPs, thus returning '0'
746 return_data['metric_uuid'] = '0'
747 return_data['correlation_id'] = metric['correlation_id']
748 return_data['resource_uuid'] = metric['resource_uuid']
749 return_data['metrics_data'] = {'time_series':[], 'metrics_series':[]}
750 #To do - Need confirmation about uuid & id
751 if 'tenant_uuid' in metric and metric['tenant_uuid'] is not None:
752 return_data['tenant_uuid'] = metric['tenant_uuid']
753 else:
754 return_data['tenant_uuid'] = None
755 return_data['unit'] = None
756 #return_data['tenant_id'] = self.tenant_id
757 #self.logger.warning("return_data: {}".format(return_data))
758
759 #1) Get metric details from plugin specific file & format it into vROPs metrics
760 metric_key_params = self.get_default_Params(metric['metric_name'])
761
762 if not metric_key_params:
763 self.logger.warning("Metric not supported: {}".format(metric['metric_name']))
764 #To Do: Return message
765 return return_data
766
767 return_data['unit'] = metric_key_params['unit']
768
769 #2) Find the resource id in vROPs based on OSM resource_uuid
770 #2.a) Find vm_moref_id from vApp uuid in vCD
771 vm_moref_id = self.get_vm_moref_id(metric['resource_uuid'])
772 if vm_moref_id is None:
773 self.logger.warning("Failed to find vm morefid for vApp in vCD: {}".format(metric['resource_uuid']))
774 return return_data
775 #2.b) Based on vm_moref_id, find VM's corresponding resource_id in vROPs to set notification
776 resource_id = self.get_vm_resource_id(vm_moref_id)
777 if resource_id is None:
778 self.logger.warning("Failed to find resource in vROPs: {}".format(metric['resource_uuid']))
779 return return_data
780
781 #3) Calculate begin & end time for period & period unit
782 end_time = int(round(time.time() * 1000))
783 if metric['collection_unit'] == 'YR':
784 time_diff = PERIOD_MSEC[metric['collection_unit']]
785 else:
786 time_diff = metric['collection_period']* PERIOD_MSEC[metric['collection_unit']]
787 begin_time = end_time - time_diff
788
789 #4) Get the metrics data
790 self.logger.info("metric_key_params['metric_key'] = {}".format(metric_key_params['metric_key']))
791 self.logger.info("end_time: {}, begin_time: {}".format(end_time, begin_time))
792
793 url_list = ['/suite-api/api/resources/', resource_id, '/stats?statKey=',\
794 metric_key_params['metric_key'], '&begin=', str(begin_time),'&end=',str(end_time)]
795 api_url = ''.join(url_list)
796 headers = {'Accept': 'application/json'}
797
798 resp = requests.get(self.vrops_site + api_url,
799 auth=(self.vrops_user, self.vrops_password),
800 verify = False, headers = headers)
801
802 if resp.status_code is not 200:
803 self.logger.warning("Failed to retrive Metric data from vROPs for {}\nResponse code:{}\nResponse Content: {}"\
804 .format(metric['metric_name'], resp.status_code, resp.content))
805 return return_data
806
807 #5) Convert to required format
808 metrics_data = {}
809 json_data = json.loads(resp.content)
810 for resp_key,resp_val in six.iteritems(json_data):
811 if resp_key == 'values':
812 data = json_data['values'][0]
813 for data_k,data_v in six.iteritems(data):
814 if data_k == 'stat-list':
815 stat_list = data_v
816 for stat_list_k,stat_list_v in six.iteritems(stat_list):
817 for stat_keys,stat_vals in six.iteritems(stat_list_v[0]):
818 if stat_keys == 'timestamps':
819 metrics_data['time_series'] = stat_list_v[0]['timestamps']
820 if stat_keys == 'data':
821 metrics_data['metrics_series'] = stat_list_v[0]['data']
822
823 return_data['metrics_data'] = metrics_data
824
825 return return_data
826
827 def update_alarm_configuration(self, new_alarm_config):
828 """Update alarm configuration (i.e. Symptom & alarm) as per request
829 """
830 if new_alarm_config.get('alarm_uuid') is None:
831 self.logger.warning("alarm_uuid is required to update an Alarm")
832 return None
833 #1) Get Alarm details from it's uuid & find the symptom defination
834 alarm_details_json, alarm_details = self.get_alarm_defination_details(new_alarm_config['alarm_uuid'])
835 if alarm_details_json is None:
836 return None
837
838 try:
839 #2) Update the symptom defination
840 if alarm_details['alarm_id'] is not None and alarm_details['symptom_definition_id'] is not None:
841 symptom_defination_id = alarm_details['symptom_definition_id']
842 else:
843 self.logger.info("Symptom Defination ID not found for {}".format(new_alarm_config['alarm_uuid']))
844 return None
845
846 symptom_uuid = self.update_symptom_defination(symptom_defination_id, new_alarm_config)
847
848 #3) Update the alarm defination & Return UUID if successful update
849 if symptom_uuid is None:
850 self.logger.info("Symptom Defination details not found for {}"\
851 .format(new_alarm_config['alarm_uuid']))
852 return None
853 else:
854 alarm_uuid = self.reconfigure_alarm(alarm_details_json, new_alarm_config)
855 if alarm_uuid is None:
856 return None
857 else:
858 return alarm_uuid
859 except:
860 self.logger.error("Exception while updating alarm: {}".format(traceback.format_exc()))
861
862 def get_alarm_defination_details(self, alarm_uuid):
863 """Get alarm details based on alarm UUID
864 """
865 if alarm_uuid is None:
866 self.logger.warning("get_alarm_defination_details: Alarm UUID not provided")
867 return None, None
868
869 alarm_details = {}
870 json_data = {}
871 api_url = '/suite-api/api/alertdefinitions/AlertDefinition-'
872 headers = {'Accept': 'application/json'}
873
874 resp = requests.get(self.vrops_site + api_url + alarm_uuid,
875 auth=(self.vrops_user, self.vrops_password),
876 verify = False, headers = headers)
877
878 if resp.status_code is not 200:
879 self.logger.warning("Alarm to be updated not found: {}\nResponse code:{}\nResponse Content: {}"\
880 .format(alarm_uuid, resp.status_code, resp.content))
881 return None, None
882
883 try:
884 json_data = json.loads(resp.content)
885 if json_data['id'] is not None:
886 alarm_details['alarm_id'] = json_data['id']
887 alarm_details['alarm_name'] = json_data['name']
888 alarm_details['adapter_kind'] = json_data['adapterKindKey']
889 alarm_details['resource_kind'] = json_data['resourceKindKey']
890 alarm_details['type'] = json_data['type']
891 alarm_details['sub_type'] = json_data['subType']
892 alarm_details['symptom_definition_id'] = json_data['states'][0]['base-symptom-set']['symptomDefinitionIds'][0]
893 except Exception as exp:
894 self.logger.warning("Exception while retriving alarm defination details: {}".format(exp))
895 return None, None
896
897 return json_data, alarm_details
898
899
900 def get_alarm_defination_by_name(self, alarm_name):
901 """Get alarm details based on alarm name
902 """
903 status = False
904 alert_match_list = []
905
906 if alarm_name is None:
907 self.logger.warning("get_alarm_defination_by_name: Alarm name not provided")
908 return alert_match_list
909
910 json_data = {}
911 api_url = '/suite-api/api/alertdefinitions'
912 headers = {'Accept': 'application/json'}
913
914 resp = requests.get(self.vrops_site + api_url,
915 auth=(self.vrops_user, self.vrops_password),
916 verify = False, headers = headers)
917
918 if resp.status_code is not 200:
919 self.logger.warning("get_alarm_defination_by_name: Error in response: {}\nResponse code:{}"\
920 "\nResponse Content: {}".format(alarm_name, resp.status_code, resp.content))
921 return alert_match_list
922
923 try:
924 json_data = json.loads(resp.content)
925 if json_data['alertDefinitions'] is not None:
926 alerts_list = json_data['alertDefinitions']
927 alert_match_list = list(filter(lambda alert: alert['name'] == alarm_name, alerts_list))
928 status = False if not alert_match_list else True
929 #self.logger.debug("Found alert_match_list: {}for larm_name: {},\nstatus: {}".format(alert_match_list, alarm_name,status))
930
931 return alert_match_list
932
933 except Exception as exp:
934 self.logger.warning("Exception while searching alarm defination: {}".format(exp))
935 return alert_match_list
936
937
938 def update_symptom_defination(self, symptom_uuid, new_alarm_config):
939 """Update symptom defination based on new alarm input configuration
940 """
941 #1) Get symptom defination details
942 symptom_details = self.get_symptom_defination_details(symptom_uuid)
943 #print "\n\nsymptom_details: {}".format(symptom_details)
944 if symptom_details is None:
945 return None
946
947 if 'severity' in new_alarm_config and new_alarm_config['severity'] is not None:
948 symptom_details['state']['severity'] = severity_mano2vrops[new_alarm_config['severity']]
949 if 'operation' in new_alarm_config and new_alarm_config['operation'] is not None:
950 symptom_details['state']['condition']['operator'] = OPERATION_MAPPING[new_alarm_config['operation']]
951 if 'threshold_value' in new_alarm_config and new_alarm_config['threshold_value'] is not None:
952 symptom_details['state']['condition']['value'] = new_alarm_config['threshold_value']
953 #Find vrops metric key from metric_name, if required
954 """
955 if 'metric_name' in new_alarm_config and new_alarm_config['metric_name'] is not None:
956 metric_key_params = self.get_default_Params(new_alarm_config['metric_name'])
957 if not metric_key_params:
958 self.logger.warning("Metric not supported: {}".format(config_dict['metric_name']))
959 return None
960 symptom_details['state']['condition']['key'] = metric_key_params['metric_key']
961 """
962 self.logger.info("Fetched Symptom details : {}".format(symptom_details))
963
964 api_url = '/suite-api/api/symptomdefinitions'
965 headers = {'Content-Type': 'application/json', 'Accept':'application/json'}
966 data = json.dumps(symptom_details)
967 resp = requests.put(self.vrops_site + api_url,
968 auth=(self.vrops_user, self.vrops_password),
969 headers=headers,
970 verify = False,
971 data=data)
972
973 if resp.status_code != 200:
974 self.logger.warning("Failed to update Symptom definition: {}, response {}"\
975 .format(symptom_uuid, resp.content))
976 return None
977
978
979 if symptom_uuid is not None:
980 self.logger.info("Symptom defination updated {} for alarm: {}"\
981 .format(symptom_uuid, new_alarm_config['alarm_uuid']))
982 return symptom_uuid
983 else:
984 self.logger.warning("Failed to update Symptom Defination {} for : {}"\
985 .format(symptom_uuid, new_alarm_config['alarm_uuid']))
986 return None
987
988
989 def get_symptom_defination_details(self, symptom_uuid):
990 """Get symptom defination details
991 """
992 symptom_details = {}
993 if symptom_uuid is None:
994 self.logger.warning("get_symptom_defination_details: Symptom UUID not provided")
995 return None
996
997 api_url = '/suite-api/api/symptomdefinitions/'
998 headers = {'Accept': 'application/json'}
999
1000 resp = requests.get(self.vrops_site + api_url + symptom_uuid,
1001 auth=(self.vrops_user, self.vrops_password),
1002 verify = False, headers = headers)
1003
1004 if resp.status_code is not 200:
1005 self.logger.warning("Symptom defination not found {} \nResponse code:{}\nResponse Content: {}"\
1006 .format(symptom_uuid, resp.status_code, resp.content))
1007 return None
1008
1009 symptom_details = json.loads(resp.content)
1010 #print "New symptom Details: {}".format(symptom_details)
1011 return symptom_details
1012
1013
1014 def reconfigure_alarm(self, alarm_details_json, new_alarm_config):
1015 """Reconfigure alarm defination as per input
1016 """
1017 if 'severity' in new_alarm_config and new_alarm_config['severity'] is not None:
1018 alarm_details_json['states'][0]['severity'] = new_alarm_config['severity']
1019 if 'description' in new_alarm_config and new_alarm_config['description'] is not None:
1020 alarm_details_json['description'] = new_alarm_config['description']
1021
1022 api_url = '/suite-api/api/alertdefinitions'
1023 headers = {'Content-Type': 'application/json', 'Accept':'application/json'}
1024 data = json.dumps(alarm_details_json)
1025 resp = requests.put(self.vrops_site + api_url,
1026 auth=(self.vrops_user, self.vrops_password),
1027 headers=headers,
1028 verify = False,
1029 data=data)
1030
1031 if resp.status_code != 200:
1032 self.logger.warning("Failed to update Alarm definition: {}, response code {}, response content: {}"\
1033 .format(alarm_details_json['id'], resp.status_code, resp.content))
1034 return None
1035 else:
1036 parsed_alarm_details = json.loads(resp.content)
1037 alarm_def_uuid = parsed_alarm_details['id'].split('-', 1)[1]
1038 self.logger.info("Successfully updated Alarm definition: {}".format(alarm_def_uuid))
1039 return alarm_def_uuid
1040
1041 def delete_alarm_configuration(self, delete_alarm_req_dict):
1042 """Delete complete alarm configuration
1043 """
1044 if delete_alarm_req_dict['alarm_uuid'] is None:
1045 self.logger.info("delete_alarm_configuration: Alarm UUID not provided")
1046 return None
1047 #1)Get alarm & symptom definition details
1048 alarm_details_json, alarm_details = self.get_alarm_defination_details(delete_alarm_req_dict['alarm_uuid'])
1049 if alarm_details is None or alarm_details_json is None:
1050 return None
1051
1052 #2) Delete alarm notification
1053 rule_id = self.delete_notification_rule(alarm_details['alarm_name'])
1054 if rule_id is None:
1055 return None
1056
1057 #3) Delete alarm configuration
1058 alarm_id = self.delete_alarm_defination(alarm_details['alarm_id'])
1059 if alarm_id is None:
1060 return None
1061
1062 #4) Delete alarm symptom
1063 symptom_id = self.delete_symptom_definition(alarm_details['symptom_definition_id'])
1064 if symptom_id is None:
1065 return None
1066 else:
1067 self.logger.info("Completed deleting alarm configuration: {}"\
1068 .format(delete_alarm_req_dict['alarm_uuid']))
1069 return delete_alarm_req_dict['alarm_uuid']
1070
1071 def delete_notification_rule(self, alarm_name):
1072 """Deleted notification rule defined for a particular alarm
1073 """
1074 rule_id = self.get_notification_rule_id_by_alarm_name(alarm_name)
1075 if rule_id is None:
1076 return None
1077 else:
1078 api_url = '/suite-api/api/notifications/rules/'
1079 headers = {'Accept':'application/json'}
1080 resp = requests.delete(self.vrops_site + api_url + rule_id,
1081 auth=(self.vrops_user, self.vrops_password),
1082 verify = False, headers = headers)
1083 if resp.status_code is not 204:
1084 self.logger.warning("Failed to delete notification rules for {}".format(alarm_name))
1085 return None
1086 else:
1087 self.logger.info("Deleted notification rules for {}".format(alarm_name))
1088 return rule_id
1089
1090 def get_notification_rule_id_by_alarm_name(self, alarm_name):
1091 """Find created Alarm notification rule id by alarm name
1092 """
1093 alarm_notify_id = 'notify_' + alarm_name
1094 api_url = '/suite-api/api/notifications/rules'
1095 headers = {'Content-Type': 'application/json', 'Accept':'application/json'}
1096 resp = requests.get(self.vrops_site + api_url,
1097 auth=(self.vrops_user, self.vrops_password),
1098 verify = False, headers = headers)
1099
1100 if resp.status_code is not 200:
1101 self.logger.warning("Failed to get notification rules details for {}"\
1102 .format(alarm_name))
1103 return None
1104
1105 notifications = json.loads(resp.content)
1106 if notifications is not None and 'notification-rule' in notifications:
1107 notifications_list = notifications['notification-rule']
1108 for dict in notifications_list:
1109 if dict['name'] is not None and dict['name'] == alarm_notify_id:
1110 notification_id = dict['id']
1111 self.logger.info("Found Notification id to be deleted: {} for {}"\
1112 .format(notification_id, alarm_name))
1113 return notification_id
1114
1115 self.logger.warning("Notification id to be deleted not found for {}"\
1116 .format(alarm_name))
1117 return None
1118
1119 def delete_alarm_defination(self, alarm_id):
1120 """Delete created Alarm defination
1121 """
1122 api_url = '/suite-api/api/alertdefinitions/'
1123 headers = {'Accept':'application/json'}
1124 resp = requests.delete(self.vrops_site + api_url + alarm_id,
1125 auth=(self.vrops_user, self.vrops_password),
1126 verify = False, headers = headers)
1127 if resp.status_code is not 204:
1128 self.logger.warning("Failed to delete alarm definition {}".format(alarm_id))
1129 return None
1130 else:
1131 self.logger.info("Deleted alarm definition {}".format(alarm_id))
1132 return alarm_id
1133
1134 def delete_symptom_definition(self, symptom_id):
1135 """Delete symptom defination
1136 """
1137 api_url = '/suite-api/api/symptomdefinitions/'
1138 headers = {'Accept':'application/json'}
1139 resp = requests.delete(self.vrops_site + api_url + symptom_id,
1140 auth=(self.vrops_user, self.vrops_password),
1141 verify = False, headers = headers)
1142 if resp.status_code is not 204:
1143 self.logger.warning("Failed to delete symptom definition {}".format(symptom_id))
1144 return None
1145 else:
1146 self.logger.info("Deleted symptom definition {}".format(symptom_id))
1147 return symptom_id
1148
1149
1150 def verify_metric_support(self, metric_info):
1151 """Verify, if Metric is supported by vROPs plugin, verify metric unit & return status
1152 Returns:
1153 status: True if supported, False if not supported
1154 """
1155 status = False
1156 if 'metric_name' not in metric_info:
1157 self.logger.debug("Metric name not provided: {}".format(metric_info))
1158 return status
1159 metric_key_params = self.get_default_Params(metric_info['metric_name'])
1160 if not metric_key_params:
1161 self.logger.warning("Metric not supported: {}".format(metric_info['metric_name']))
1162 return status
1163 else:
1164 #If Metric is supported, verify optional metric unit & return status
1165 if 'metric_unit' in metric_info:
1166 if metric_key_params.get('unit') == metric_info['metric_unit']:
1167 self.logger.info("Metric is supported with unit: {}".format(metric_info['metric_name']))
1168 status = True
1169 else:
1170 self.logger.debug("Metric supported but there is unit mismatch for: {}."\
1171 "Supported unit: {}"\
1172 .format(metric_info['metric_name'],metric_key_params['unit']))
1173 status = True
1174 return status
1175
1176 def get_triggered_alarms_list(self, list_alarm_input):
1177 """Get list of triggered alarms on a resource based on alarm input request.
1178 """
1179 #TO Do - Need to add filtering of alarms based on Severity & alarm name
1180
1181 triggered_alarms_list = []
1182 if list_alarm_input.get('resource_uuid') is None:
1183 self.logger.warning("Resource UUID is required to get triggered alarms list")
1184 return triggered_alarms_list
1185
1186 #1)Find vROPs resource ID using RO resource UUID
1187 vrops_resource_id = self.get_vrops_resourceid_from_ro_uuid(list_alarm_input['resource_uuid'])
1188 if vrops_resource_id is None:
1189 return triggered_alarms_list
1190
1191 #2)Get triggered alarms on particular resource
1192 triggered_alarms_list = self.get_triggered_alarms_on_resource(list_alarm_input['resource_uuid'], vrops_resource_id)
1193 return triggered_alarms_list
1194
1195 def get_vrops_resourceid_from_ro_uuid(self, ro_resource_uuid):
1196 """Fetch vROPs resource ID using resource UUID from RO/SO
1197 """
1198 #1) Find vm_moref_id from vApp uuid in vCD
1199 vm_moref_id = self.get_vm_moref_id(ro_resource_uuid)
1200 if vm_moref_id is None:
1201 self.logger.warning("Failed to find vm morefid for vApp in vCD: {}".format(ro_resource_uuid))
1202 return None
1203
1204 #2) Based on vm_moref_id, find VM's corresponding resource_id in vROPs to set notification
1205 vrops_resource_id = self.get_vm_resource_id(vm_moref_id)
1206 if vrops_resource_id is None:
1207 self.logger.warning("Failed to find resource in vROPs: {}".format(ro_resource_uuid))
1208 return None
1209 return vrops_resource_id
1210
1211
1212 def get_triggered_alarms_on_resource(self, ro_resource_uuid, vrops_resource_id):
1213 """Get triggered alarms on particular resource & return list of dictionary of alarms
1214 """
1215 resource_alarms = []
1216 api_url = '/suite-api/api/alerts?resourceId='
1217 headers = {'Accept':'application/json'}
1218 resp = requests.get(self.vrops_site + api_url + vrops_resource_id,
1219 auth=(self.vrops_user, self.vrops_password),
1220 verify = False, headers = headers)
1221
1222 if resp.status_code is not 200:
1223 self.logger.warning("Failed to get triggered alarms for {}"\
1224 .format(ro_resource_uuid))
1225 return None
1226
1227 all_alerts = json.loads(resp.content)
1228 if 'alerts' in all_alerts:
1229 if not all_alerts['alerts']:
1230 self.logger.info("No alarms present on resource {}".format(ro_resource_uuid))
1231 return resource_alarms
1232 all_alerts_list = all_alerts['alerts']
1233 for alarm in all_alerts_list:
1234 #self.logger.info("Triggered Alarm {}".format(alarm))
1235 if alarm['alertDefinitionName'] is not None and\
1236 len(alarm['alertDefinitionName'].split('-', 1)) == 2:
1237 if alarm['alertDefinitionName'].split('-', 1)[1] == ro_resource_uuid:
1238 alarm_instance = {}
1239 alarm_instance['alarm_uuid'] = alarm['alertDefinitionId'].split('-', 1)[1]
1240 alarm_instance['resource_uuid'] = ro_resource_uuid
1241 alarm_instance['alarm_instance_uuid'] = alarm['alertId']
1242 alarm_instance['vim_type'] = 'VMware'
1243 #find severity of alarm
1244 severity = None
1245 for key,value in six.iteritems(severity_mano2vrops):
1246 if value == alarm['alertLevel']:
1247 severity = key
1248 if severity is None:
1249 severity = 'INDETERMINATE'
1250 alarm_instance['severity'] = severity
1251 alarm_instance['status'] = alarm['status']
1252 alarm_instance['start_date'] = self.convert_date_time(alarm['startTimeUTC'])
1253 alarm_instance['update_date'] = self.convert_date_time(alarm['updateTimeUTC'])
1254 alarm_instance['cancel_date'] = self.convert_date_time(alarm['cancelTimeUTC'])
1255 self.logger.info("Triggered Alarm on resource {}".format(alarm_instance))
1256 resource_alarms.append(alarm_instance)
1257 if not resource_alarms:
1258 self.logger.info("No alarms present on resource {}".format(ro_resource_uuid))
1259 return resource_alarms
1260
1261 def convert_date_time(self, date_time):
1262 """Convert the input UTC time in msec to OSM date time format
1263 """
1264 date_time_formatted = '0000-00-00T00:00:00'
1265 if date_time != 0:
1266 complete_datetime = datetime.datetime.fromtimestamp(date_time/1000.0).isoformat('T')
1267 date_time_formatted = complete_datetime.split('.',1)[0]
1268 return date_time_formatted
1269
1270