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