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