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