1 # -*- coding: utf-8 -*-
4 # Copyright 2016-2017 VMware Inc.
5 # This file is part of ETSI OSM
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
12 # http://www.apache.org/licenses/LICENSE-2.0
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
20 # For those usages not covered by the Apache License, Version 2.0 please
21 # contact: osslegalrouting@vmware.com
25 Montoring metrics & creating Alarm definations in vROPs
30 from pyvcloud
.vcloudair
import VCA
31 from xml
.etree
import ElementTree
as XmlElementTree
35 from OpenSSL
.crypto
import load_certificate
, FILETYPE_PEM
38 from socket
import getfqdn
40 from requests
.packages
.urllib3
.exceptions
import InsecureRequestWarning
41 requests
.packages
.urllib3
.disable_warnings(InsecureRequestWarning
)
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}
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
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
)
61 """MON Plugin class for vROPs telemetry plugin
64 """Constructor of MON plugin
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':<>}
77 Returns: Raise an exception if some needed parameter is missing, but it must not do any connectivity
80 self
.logger
= logging
.getLogger('PluginReceiver.MonPlugin')
81 self
.logger
.setLevel(logging
.DEBUG
)
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")
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
))
102 def configure_alarm(self
, config_dict
= {}):
103 """Configures or creates a new alarm using the input parameters in config_dict
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
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}
122 Returns the UUID of created alarm or None
125 #1) get alarm & metrics parameters from plugin specific file
126 def_a_params
= self
.get_default_Params(config_dict
['alarm_name'])
128 self
.logger
.warn("Alarm not supported: {}".format(config_dict
['alarm_name']))
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']))
135 #1.2) Check if alarm definition already exists
136 vrops_alarm_name
= def_a_params
['vrops_alarm']+ '-' + config_dict
['resource_uuid']
137 alert_def_list
= self
.get_alarm_defination_by_name(vrops_alarm_name
)
139 self
.logger
.warn("Alarm already exists: {}. Try updating by update_alarm_request"\
140 .format(vrops_alarm_name
))
143 #2) create symptom definition
144 symptom_params
={'cancel_cycles': (def_a_params
['cancel_period']/300)*def_a_params
['cancel_cycles'],
145 'wait_cycles': (def_a_params
['period']/300)*def_a_params
['evaluation'],
146 'resource_kind_key': def_a_params
['resource_kind'],
147 'adapter_kind_key': def_a_params
['adapter_kind'],
148 'symptom_name':vrops_alarm_name
,
149 'severity': severity_mano2vrops
[config_dict
['severity']],
150 'metric_key':metric_key_params
['metric_key'],
151 'operation':OPERATION_MAPPING
[config_dict
['operation']],
152 'threshold_value':config_dict
['threshold_value']}
153 symptom_uuid
= self
.create_symptom(symptom_params
)
154 if symptom_uuid
is not None:
155 self
.logger
.info("Symptom defined: {} with ID: {}".format(symptom_params
['symptom_name'],symptom_uuid
))
157 self
.logger
.warn("Failed to create Symptom: {}".format(symptom_params
['symptom_name']))
159 #3) create alert definition
160 #To Do - Get type & subtypes for all 5 alarms
161 alarm_params
= {'name':vrops_alarm_name
,
162 'description':config_dict
['description']\
163 if config_dict
.has_key('description') and config_dict
['description'] is not None else config_dict
['alarm_name'],
164 'adapterKindKey':def_a_params
['adapter_kind'],
165 'resourceKindKey':def_a_params
['resource_kind'],
166 'waitCycles':1, 'cancelCycles':1,
167 'type':def_a_params
['alarm_type'], 'subType':def_a_params
['alarm_subType'],
168 'severity':severity_mano2vrops
[config_dict
['severity']],
169 'symptomDefinitionId':symptom_uuid
,
170 'impact':def_a_params
['impact']}
172 alarm_def
= self
.create_alarm_definition(alarm_params
)
173 if alarm_def
is None:
174 self
.logger
.warn("Failed to create Alert: {}".format(alarm_params
['name']))
177 self
.logger
.info("Alarm defined: {} with ID: {}".format(alarm_params
['name'],alarm_def
))
179 #4) Find vm_moref_id from vApp uuid in vCD
180 vm_moref_id
= self
.get_vm_moref_id(config_dict
['resource_uuid'])
181 if vm_moref_id
is None:
182 self
.logger
.warn("Failed to find vm morefid for vApp in vCD: {}".format(config_dict
['resource_uuid']))
185 #5) Based on vm_moref_id, find VM's corresponding resource_id in vROPs to set notification
186 resource_id
= self
.get_vm_resource_id(vm_moref_id
)
187 if resource_id
is None:
188 self
.logger
.warn("Failed to find resource in vROPs: {}".format(config_dict
['resource_uuid']))
191 #6) Configure alarm notification for a particular VM using it's resource_id
192 notification_id
= self
.create_alarm_notification_rule(vrops_alarm_name
, alarm_def
, resource_id
)
193 if notification_id
is None:
196 alarm_def_uuid
= alarm_def
.split('-', 1)[1]
197 self
.logger
.info("Alarm defination created with notification: {} with ID: {}"\
198 .format(alarm_params
['name'],alarm_def_uuid
))
199 #Return alarm defination UUID by removing 'AlertDefinition' from UUID
200 return (alarm_def_uuid
)
202 def get_default_Params(self
, metric_alarm_name
):
204 Read the default config parameters from plugin specific file stored with plugin file.
206 metric_alarm_name: Name of the alarm, whose congif params to be read from the config file.
210 source
= open(CONFIG_FILE_PATH
, 'r')
211 except IOError as exp
:
212 msg
= ("Could not read Config file: {}, \nException: {}"\
213 .format(CONFIG_FILE_PATH
, exp
))
214 self
.logger
.error(msg
)
217 tree
= XmlElementTree
.parse(source
)
218 alarms
= tree
.getroot()
220 if alarm
.tag
== metric_alarm_name
:
222 if param
.tag
in ("period", "evaluation", "cancel_period", "alarm_type",\
223 "cancel_cycles", "alarm_subType"):
224 a_params
[param
.tag
] = int(param
.text
)
225 elif param
.tag
in ("enabled", "repeat"):
226 if(param
.text
.lower() == "true"):
227 a_params
[param
.tag
] = True
229 a_params
[param
.tag
] = False
231 a_params
[param
.tag
] = param
.text
236 def create_symptom(self
, symptom_params
):
237 """Create Symptom definition for an alarm
239 symptom_params: Dict of parameters required for defining a symptom as follows
242 resource_kind_key = "VirtualMachine"
243 adapter_kind_key = "VMWARE"
244 symptom_name = Test_Memory_Usage_TooHigh
249 Returns the uuid of Symptom definition
254 api_url
= '/suite-api/api/symptomdefinitions'
255 headers
= {'Content-Type': 'application/xml'}
256 data
= """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
257 <ops:symptom-definition cancelCycles="{0:s}" waitCycles="{1:s}"
258 resourceKindKey="{2:s}" adapterKindKey="{3:s}"
259 xmlns:xs="http://www.w3.org/2001/XMLSchema"
260 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
261 xmlns:ops="http://webservice.vmware.com/vRealizeOpsMgr/1.0/">
262 <ops:name>{4:s}</ops:name>
263 <ops:state severity="{5:s}">
264 <ops:condition xsi:type="ops:htCondition">
265 <ops:key>{6:s}</ops:key>
266 <ops:operator>{7:s}</ops:operator>
267 <ops:value>{8:s}</ops:value>
268 <ops:valueType>NUMERIC</ops:valueType>
269 <ops:instanced>false</ops:instanced>
270 <ops:thresholdType>STATIC</ops:thresholdType>
273 </ops:symptom-definition>"""\
274 .format(str(symptom_params
['cancel_cycles']),str(symptom_params
['wait_cycles']),
275 symptom_params
['resource_kind_key'], symptom_params
['adapter_kind_key'],
276 symptom_params
['symptom_name'],symptom_params
['severity'],
277 symptom_params
['metric_key'],symptom_params
['operation'],
278 str(symptom_params
['threshold_value']))
280 resp
= requests
.post(self
.vrops_site
+ api_url
,
281 auth
=(self
.vrops_user
, self
.vrops_password
),
286 if resp
.status_code
!= 201:
287 self
.logger
.warn("Failed to create Symptom definition: {}, response {}"\
288 .format(symptom_params
['symptom_name'], resp
.content
))
291 symptom_xmlroot
= XmlElementTree
.fromstring(resp
.content
)
292 if symptom_xmlroot
is not None and 'id' in symptom_xmlroot
.attrib
:
293 symptom_id
= symptom_xmlroot
.attrib
['id']
297 except Exception as exp
:
298 self
.logger
.warn("Error creating symptom definition : {}\n{}"\
299 .format(exp
, traceback
.format_exc()))
302 def create_alarm_definition(self
, alarm_params
):
304 Create an alarm definition in vROPs
307 'description':Alarm description,
308 'adapterKindKey': Adapter type in vROPs "VMWARE",
309 'resourceKindKey':Resource type in vROPs "VirtualMachine",
310 'waitCycles': No of wait cycles,
311 'cancelCycles': No of cancel cycles,
313 'subType': Alarm subtype,
314 'severity': Severity in vROPs "CRITICAL",
315 'symptomDefinitionId':symptom Definition uuid,
316 'impact': impact 'risk'
318 'alarm_uuid': returns alarm uuid
324 api_url
= '/suite-api/api/alertdefinitions'
325 headers
= {'Content-Type': 'application/xml'}
326 data
= """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
327 <ops:alert-definition xmlns:xs="http://www.w3.org/2001/XMLSchema"
328 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
329 xmlns:ops="http://webservice.vmware.com/vRealizeOpsMgr/1.0/">
330 <ops:name>{0:s}</ops:name>
331 <ops:description>{1:s}</ops:description>
332 <ops:adapterKindKey>{2:s}</ops:adapterKindKey>
333 <ops:resourceKindKey>{3:s}</ops:resourceKindKey>
334 <ops:waitCycles>1</ops:waitCycles>
335 <ops:cancelCycles>1</ops:cancelCycles>
336 <ops:type>{4:s}</ops:type>
337 <ops:subType>{5:s}</ops:subType>
339 <ops:state severity="{6:s}">
341 <ops:symptomDefinitionIds>
342 <ops:symptomDefinitionId>{7:s}</ops:symptomDefinitionId>
343 </ops:symptomDefinitionIds>
344 <ops:relation>SELF</ops:relation>
345 <ops:aggregation>ALL</ops:aggregation>
346 <ops:symptomSetOperator>AND</ops:symptomSetOperator>
349 <ops:impactType>BADGE</ops:impactType>
350 <ops:detail>{8:s}</ops:detail>
354 </ops:alert-definition>"""\
355 .format(alarm_params
['name'],alarm_params
['description'],
356 alarm_params
['adapterKindKey'],alarm_params
['resourceKindKey'],
357 str(alarm_params
['type']),str(alarm_params
['subType']),
358 alarm_params
['severity'],alarm_params
['symptomDefinitionId'],
359 alarm_params
['impact'])
361 resp
= requests
.post(self
.vrops_site
+ api_url
,
362 auth
=(self
.vrops_user
, self
.vrops_password
),
367 if resp
.status_code
!= 201:
368 self
.logger
.warn("Failed to create Alarm definition: {}, response {}"\
369 .format(alarm_params
['name'], resp
.content
))
372 alarm_xmlroot
= XmlElementTree
.fromstring(resp
.content
)
373 for child
in alarm_xmlroot
:
374 if child
.tag
.split("}")[1] == 'id':
375 alarm_uuid
= child
.text
379 except Exception as exp
:
380 self
.logger
.warn("Error creating alarm definition : {}\n{}".format(exp
, traceback
.format_exc()))
383 def configure_rest_plugin(self
):
385 Creates REST Plug-in for vROPs outbound alerts
390 plugin_name
= 'MON_module_REST_Plugin'
391 plugin_id
= self
.check_if_plugin_configured(plugin_name
)
393 #If REST plugin not configured, configure it
394 if plugin_id
is not None:
398 cert_file_string
= open(SSL_CERTIFICATE_FILE_PATH
, "rb").read()
399 except IOError as exp
:
400 msg
= ("Could not read SSL certificate file: {}".format(SSL_CERTIFICATE_FILE_PATH
))
401 self
.logger
.error(msg
)
403 cert
= load_certificate(FILETYPE_PEM
, cert_file_string
)
404 certificate
= cert
.digest("sha1")
405 api_url
= '/suite-api/api/alertplugins'
406 headers
= {'Content-Type': 'application/xml'}
407 data
= """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
408 <ops:notification-plugin version="0" xmlns:xs="http://www.w3.org/2001/XMLSchema"
409 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
410 xmlns:ops="http://webservice.vmware.com/vRealizeOpsMgr/1.0/">
411 <ops:pluginTypeId>RestPlugin</ops:pluginTypeId>
412 <ops:name>{0:s}</ops:name>
414 <ops:configValue name="Url">{1:s}</ops:configValue>
415 <ops:configValue name="Content-type">application/json</ops:configValue>
416 <ops:configValue name="Certificate">{2:s}</ops:configValue>
417 <ops:configValue name="ConnectionCount">20</ops:configValue>
419 </ops:notification-plugin>""".format(plugin_name
, webhook_url
, certificate
)
421 resp
= requests
.post(self
.vrops_site
+ api_url
,
422 auth
=(self
.vrops_user
, self
.vrops_password
),
427 if resp
.status_code
is not 201:
428 self
.logger
.warn("Failed to create REST Plugin: {} for url: {}, \nresponse code: {},"\
429 "\nresponse content: {}".format(plugin_name
, webhook_url
,\
430 resp
.status_code
, resp
.content
))
433 plugin_xmlroot
= XmlElementTree
.fromstring(resp
.content
)
434 if plugin_xmlroot
is not None:
435 for child
in plugin_xmlroot
:
436 if child
.tag
.split("}")[1] == 'pluginId':
437 plugin_id
= plugin_xmlroot
.find('{http://webservice.vmware.com/vRealizeOpsMgr/1.0/}pluginId').text
439 if plugin_id
is None:
440 self
.logger
.warn("Failed to get REST Plugin ID for {}, url: {}".format(plugin_name
, webhook_url
))
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
)
446 self
.logger
.warn("Failed to enable created REST Plugin: {} for url: {}".format(plugin_name
, webhook_url
))
449 self
.logger
.info("Enabled REST Plugin: {} for url: {}".format(plugin_name
, webhook_url
))
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
457 #Find the REST Plugin id details for - MON_module_REST_Plugin
458 api_url
= '/suite-api/api/alertplugins'
459 headers
= {'Accept': 'application/xml'}
460 namespace
= {'params':"http://webservice.vmware.com/vRealizeOpsMgr/1.0/"}
462 resp
= requests
.get(self
.vrops_site
+ api_url
,
463 auth
=(self
.vrops_user
, self
.vrops_password
),
464 verify
= False, headers
= headers
)
466 if resp
.status_code
is not 200:
467 self
.logger
.warn("Failed to REST GET Alarm plugin details \nResponse code: {}\nResponse content: {}"\
468 .format(resp
.status_code
, resp
.content
))
471 # Look for specific plugin & parse pluginId for 'MON_module_REST_Plugin'
472 xmlroot_resp
= XmlElementTree
.fromstring(resp
.content
)
473 for notify_plugin
in xmlroot_resp
.findall('params:notification-plugin',namespace
):
474 if notify_plugin
.find('params:name',namespace
) is not None and\
475 notify_plugin
.find('params:pluginId',namespace
) is not None:
476 if notify_plugin
.find('params:name',namespace
).text
== plugin_name
:
477 plugin_id
= notify_plugin
.find('params:pluginId',namespace
).text
479 if plugin_id
is None:
480 self
.logger
.warn("REST plugin {} not found".format('MON_module_REST_Plugin'))
483 self
.logger
.info("Found REST Plugin: {}".format(plugin_name
))
487 def enable_rest_plugin(self
, plugin_id
, plugin_name
):
489 Enable the REST plugin using plugin_id
490 Params: plugin_id: plugin ID string that is to be enabled
491 Returns: status (Boolean) - True for success, False for failure
494 if plugin_id
is None or plugin_name
is None:
495 self
.logger
.debug("enable_rest_plugin() : Plugin ID or plugin_name not provided for {} plugin"\
496 .format(plugin_name
))
500 api_url
= "/suite-api/api/alertplugins/{}/enable/True".format(plugin_id
)
502 resp
= requests
.put(self
.vrops_site
+ api_url
,
503 auth
=(self
.vrops_user
, self
.vrops_password
),
506 if resp
.status_code
is not 204:
507 self
.logger
.warn("Failed to enable REST plugin {}. \nResponse code {}\nResponse Content: {}"\
508 .format(plugin_name
, resp
.status_code
, resp
.content
))
511 self
.logger
.info("Enabled REST plugin {}.".format(plugin_name
))
514 except Exception as exp
:
515 self
.logger
.warn("Error enabling REST plugin for {} plugin: Exception: {}\n{}"\
516 .format(plugin_name
, exp
, traceback
.format_exc()))
518 def create_alarm_notification_rule(self
, alarm_name
, alarm_id
, resource_id
):
520 Create notification rule for each alarm
527 notification_id: notification_id or None
529 notification_name
= 'notify_' + alarm_name
530 notification_id
= None
531 plugin_name
= 'MON_module_REST_Plugin'
533 #1) Find the REST Plugin id details for - MON_module_REST_Plugin
534 plugin_id
= self
.check_if_plugin_configured(plugin_name
)
535 if plugin_id
is None:
536 self
.logger
.warn("Failed to get REST plugin_id for : {}".format('MON_module_REST_Plugin'))
539 #2) Create Alarm notification rule
540 api_url
= '/suite-api/api/notifications/rules'
541 headers
= {'Content-Type': 'application/xml'}
542 data
= """<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
543 <ops:notification-rule xmlns:xs="http://www.w3.org/2001/XMLSchema"
544 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
545 xmlns:ops="http://webservice.vmware.com/vRealizeOpsMgr/1.0/">
546 <ops:name>{0:s}</ops:name>
547 <ops:pluginId>{1:s}</ops:pluginId>
548 <ops:resourceFilter resourceId="{2:s}">
549 <ops:matchResourceIdOnly>true</ops:matchResourceIdOnly>
550 </ops:resourceFilter>
551 <ops:alertDefinitionIdFilters>
552 <ops:values>{3:s}</ops:values>
553 </ops:alertDefinitionIdFilters>
554 </ops:notification-rule>"""\
555 .format(notification_name
, plugin_id
, resource_id
, alarm_id
)
557 resp
= requests
.post(self
.vrops_site
+ api_url
,
558 auth
=(self
.vrops_user
, self
.vrops_password
),
563 if resp
.status_code
is not 201:
564 self
.logger
.warn("Failed to create Alarm notification rule {} for {} alarm."\
565 "\nResponse code: {}\nResponse content: {}"\
566 .format(notification_name
, alarm_name
, resp
.status_code
, resp
.content
))
569 #parse notification id from response
570 xmlroot_resp
= XmlElementTree
.fromstring(resp
.content
)
571 if xmlroot_resp
is not None and 'id' in xmlroot_resp
.attrib
:
572 notification_id
= xmlroot_resp
.attrib
.get('id')
574 self
.logger
.info("Created Alarm notification rule {} for {} alarm.".format(notification_name
, alarm_name
))
575 return notification_id
577 def get_vm_moref_id(self
, vapp_uuid
):
579 Get the moref_id of given VM
583 vm_details
= self
.get_vapp_details_rest(vapp_uuid
)
584 if vm_details
and "vm_vcenter_info" in vm_details
:
585 vm_moref_id
= vm_details
["vm_vcenter_info"].get("vm_moref_id", None)
587 self
.logger
.info("Found vm_moref_id: {} for vApp UUID: {}".format(vm_moref_id
, vapp_uuid
))
590 except Exception as exp
:
591 self
.logger
.warn("Error occurred while getting VM moref ID for VM : {}\n{}"\
592 .format(exp
, traceback
.format_exc()))
595 def get_vapp_details_rest(self
, vapp_uuid
=None):
597 Method retrieve vapp detail from vCloud director
600 vapp_uuid - is vapp identifier.
603 Returns VM MOref ID or return None
609 vca
= self
.connect_as_admin()
612 self
.logger
.warn("connect() to vCD is failed")
613 if vapp_uuid
is None:
616 url_list
= [vca
.host
, '/api/vApp/vapp-', vapp_uuid
]
617 get_vapp_restcall
= ''.join(url_list
)
619 if vca
.vcloud_session
and vca
.vcloud_session
.organization
:
620 response
= requests
.get(get_vapp_restcall
,
621 headers
=vca
.vcloud_session
.get_vcloud_headers(),
624 if response
.status_code
!= 200:
625 self
.logger
.warn("REST API call {} failed. Return status code {}"\
626 .format(get_vapp_restcall
, response
.content
))
627 return parsed_respond
630 xmlroot_respond
= XmlElementTree
.fromstring(response
.content
)
632 namespaces
= {'vm': 'http://www.vmware.com/vcloud/v1.5',
633 "vmext":"http://www.vmware.com/vcloud/extension/v1.5",
634 "xmlns":"http://www.vmware.com/vcloud/v1.5"
637 # parse children section for other attrib
638 children_section
= xmlroot_respond
.find('vm:Children/', namespaces
)
639 if children_section
is not None:
640 vCloud_extension_section
= children_section
.find('xmlns:VCloudExtension', namespaces
)
641 if vCloud_extension_section
is not None:
643 vim_info
= vCloud_extension_section
.find('vmext:VmVimInfo', namespaces
)
644 vmext
= vim_info
.find('vmext:VmVimObjectRef', namespaces
)
645 if vmext
is not None:
646 vm_vcenter_info
["vm_moref_id"] = vmext
.find('vmext:MoRef', namespaces
).text
647 parsed_respond
["vm_vcenter_info"]= vm_vcenter_info
649 except Exception as exp
:
650 self
.logger
.warn("Error occurred calling rest api for getting vApp details: {}\n{}"\
651 .format(exp
, traceback
.format_exc()))
653 return parsed_respond
656 def connect_as_admin(self
):
657 """ Method connect as pvdc admin user to vCloud director.
658 There are certain action that can be done only by provider vdc admin user.
659 Organization creation / provider network creation etc.
662 The return vca object that letter can be used to connect to vcloud direct as admin for provider vdc
665 self
.logger
.info("Logging in to a VCD org as admin.")
667 vca_admin
= VCA(host
=self
.vcloud_site
,
668 username
=self
.admin_username
,
669 service_type
='standalone',
673 result
= vca_admin
.login(password
=self
.admin_password
, org
='System')
675 self
.logger
.warn("Can't connect to a vCloud director as: {}".format(self
.admin_username
))
676 result
= vca_admin
.login(token
=vca_admin
.token
, org
='System', org_url
=vca_admin
.vcloud_session
.org_url
)
678 self
.logger
.info("Successfully logged to a vcloud direct org: {} as user: {}"\
679 .format('System', self
.admin_username
))
684 def get_vm_resource_id(self
, vm_moref_id
):
685 """ Find resource ID in vROPs using vm_moref_id
687 if vm_moref_id
is None:
690 api_url
= '/suite-api/api/resources'
691 headers
= {'Accept': 'application/xml'}
692 namespace
= {'params':"http://webservice.vmware.com/vRealizeOpsMgr/1.0/"}
694 resp
= requests
.get(self
.vrops_site
+ api_url
,
695 auth
=(self
.vrops_user
, self
.vrops_password
),
696 verify
= False, headers
= headers
)
698 if resp
.status_code
is not 200:
699 self
.logger
.warn("Failed to get resource details from vROPs for {}\nResponse code:{}\nResponse Content: {}"\
700 .format(vm_moref_id
, resp
.status_code
, resp
.content
))
704 xmlroot_respond
= XmlElementTree
.fromstring(resp
.content
)
705 for resource
in xmlroot_respond
.findall('params:resource',namespace
):
706 if resource
is not None:
707 resource_key
= resource
.find('params:resourceKey',namespace
)
708 if resource_key
is not None:
709 if resource_key
.find('params:adapterKindKey',namespace
).text
== 'VMWARE' and \
710 resource_key
.find('params:resourceKindKey',namespace
).text
== 'VirtualMachine':
711 for child
in resource_key
:
712 if child
.tag
.split('}')[1]=='resourceIdentifiers':
713 resourceIdentifiers
= child
714 for r_id
in resourceIdentifiers
:
715 if r_id
.find('params:value',namespace
).text
== vm_moref_id
:
716 self
.logger
.info("Found Resource ID : {} in vROPs for {}"\
717 .format(resource
.attrib
['identifier'], vm_moref_id
))
718 return resource
.attrib
['identifier']
719 except Exception as exp
:
720 self
.logger
.warn("Error in parsing {}\n{}".format(exp
, traceback
.format_exc()))
723 def get_metrics_data(self
, metric
={}):
724 """Get an individual metric's data of a resource.
726 'metric_name': Normalized name of metric (string)
727 'resource_uuid': Resource UUID (string)
728 'period': Time period in Period Unit for which metrics data to be collected from
729 Monitoring tool from now.
730 'period_unit': Period measurement unit can be one of 'HR', 'DAY', 'MONTH', 'YEAR'
732 Return a dict that contains:
733 'metric_name': Normalized name of metric (string)
734 'resource_uuid': Resource UUID (string)
735 'tenant_id': tenent id name in which the resource is present in string format
736 'metrics_data': Dictionary containing time_series & metrics_series data.
737 'time_series': List of individual time stamp values in msec
738 'metrics_series': List of individual metrics data values
739 Raises an exception upon error or when network is not found
742 return_data
['schema_version'] = "1.0"
743 return_data
['schema_type'] = 'read_metric_data_response'
744 return_data
['metric_name'] = metric
['metric_name']
745 #To do - No metric_uuid in vROPs, thus returning '0'
746 return_data
['metric_uuid'] = '0'
747 return_data
['correlation_id'] = metric
['correlation_id']
748 return_data
['resource_uuid'] = metric
['resource_uuid']
749 return_data
['metrics_data'] = {'time_series':[], 'metrics_series':[]}
750 #To do - Need confirmation about uuid & id
751 if 'tenant_uuid' in metric
and metric
['tenant_uuid'] is not None:
752 return_data
['tenant_uuid'] = metric
['tenant_uuid']
754 return_data
['tenant_uuid'] = None
755 return_data
['unit'] = None
756 #return_data['tenant_id'] = self.tenant_id
757 #self.logger.warn("return_data: {}".format(return_data))
759 #1) Get metric details from plugin specific file & format it into vROPs metrics
760 metric_key_params
= self
.get_default_Params(metric
['metric_name'])
762 if not metric_key_params
:
763 self
.logger
.warn("Metric not supported: {}".format(metric
['metric_name']))
764 #To Do: Return message
767 return_data
['unit'] = metric_key_params
['unit']
769 #2) Find the resource id in vROPs based on OSM resource_uuid
770 #2.a) Find vm_moref_id from vApp uuid in vCD
771 vm_moref_id
= self
.get_vm_moref_id(metric
['resource_uuid'])
772 if vm_moref_id
is None:
773 self
.logger
.warn("Failed to find vm morefid for vApp in vCD: {}".format(config_dict
['resource_uuid']))
775 #2.b) Based on vm_moref_id, find VM's corresponding resource_id in vROPs to set notification
776 resource_id
= self
.get_vm_resource_id(vm_moref_id
)
777 if resource_id
is None:
778 self
.logger
.warn("Failed to find resource in vROPs: {}".format(config_dict
['resource_uuid']))
781 #3) Calculate begin & end time for period & period unit
782 end_time
= int(round(time
.time() * 1000))
783 if metric
['collection_unit'] == 'YR':
784 time_diff
= PERIOD_MSEC
[metric
['collection_unit']]
786 time_diff
= metric
['collection_period']* PERIOD_MSEC
[metric
['collection_unit']]
787 begin_time
= end_time
- time_diff
789 #4) Get the metrics data
790 self
.logger
.info("metric_key_params['metric_key'] = {}".format(metric_key_params
['metric_key']))
791 self
.logger
.info("end_time: {}, begin_time: {}".format(end_time
, begin_time
))
793 url_list
= ['/suite-api/api/resources/', resource_id
, '/stats?statKey=',\
794 metric_key_params
['metric_key'], '&begin=', str(begin_time
),'&end=',str(end_time
)]
795 api_url
= ''.join(url_list
)
796 headers
= {'Accept': 'application/json'}
798 resp
= requests
.get(self
.vrops_site
+ api_url
,
799 auth
=(self
.vrops_user
, self
.vrops_password
),
800 verify
= False, headers
= headers
)
802 if resp
.status_code
is not 200:
803 self
.logger
.warn("Failed to retrive Metric data from vROPs for {}\nResponse code:{}\nResponse Content: {}"\
804 .format(metric
['metric_name'], resp
.status_code
, resp
.content
))
807 #5) Convert to required format
809 json_data
= json
.loads(resp
.content
)
810 for resp_key
,resp_val
in json_data
.iteritems():
811 if resp_key
== 'values':
812 data
= json_data
['values'][0]
813 for data_k
,data_v
in data
.iteritems():
814 if data_k
== 'stat-list':
816 for stat_list_k
,stat_list_v
in stat_list
.iteritems():
817 for stat_keys
,stat_vals
in stat_list_v
[0].iteritems():
818 if stat_keys
== 'timestamps':
819 metrics_data
['time_series'] = stat_list_v
[0]['timestamps']
820 if stat_keys
== 'data':
821 metrics_data
['metrics_series'] = stat_list_v
[0]['data']
823 return_data
['metrics_data'] = metrics_data
827 def update_alarm_configuration(self
, new_alarm_config
):
828 """Update alarm configuration (i.e. Symptom & alarm) as per request
830 if new_alarm_config
.get('alarm_uuid') is None:
831 self
.logger
.warn("alarm_uuid is required to update an Alarm")
833 #1) Get Alarm details from it's uuid & find the symptom defination
834 alarm_details_json
, alarm_details
= self
.get_alarm_defination_details(new_alarm_config
['alarm_uuid'])
835 if alarm_details_json
is None:
839 #2) Update the symptom defination
840 if alarm_details
['alarm_id'] is not None and alarm_details
['symptom_definition_id'] is not None:
841 symptom_defination_id
= alarm_details
['symptom_definition_id']
843 self
.logger
.info("Symptom Defination ID not found for {}".format(new_alarm_config
['alarm_uuid']))
846 symptom_uuid
= self
.update_symptom_defination(symptom_defination_id
, new_alarm_config
)
848 #3) Update the alarm defination & Return UUID if successful update
849 if symptom_uuid
is None:
850 self
.logger
.info("Symptom Defination details not found for {}"\
851 .format(new_alarm_config
['alarm_uuid']))
854 alarm_uuid
= self
.reconfigure_alarm(alarm_details_json
, new_alarm_config
)
855 if alarm_uuid
is None:
860 self
.logger
.error("Exception while updating alarm: {}".format(traceback
.format_exc()))
862 def get_alarm_defination_details(self
, alarm_uuid
):
863 """Get alarm details based on alarm UUID
865 if alarm_uuid
is None:
866 self
.logger
.warn("get_alarm_defination_details: Alarm UUID not provided")
871 api_url
= '/suite-api/api/alertdefinitions/AlertDefinition-'
872 headers
= {'Accept': 'application/json'}
874 resp
= requests
.get(self
.vrops_site
+ api_url
+ alarm_uuid
,
875 auth
=(self
.vrops_user
, self
.vrops_password
),
876 verify
= False, headers
= headers
)
878 if resp
.status_code
is not 200:
879 self
.logger
.warn("Alarm to be updated not found: {}\nResponse code:{}\nResponse Content: {}"\
880 .format(alarm_uuid
, resp
.status_code
, resp
.content
))
884 json_data
= json
.loads(resp
.content
)
885 if json_data
['id'] is not None:
886 alarm_details
['alarm_id'] = json_data
['id']
887 alarm_details
['alarm_name'] = json_data
['name']
888 alarm_details
['adapter_kind'] = json_data
['adapterKindKey']
889 alarm_details
['resource_kind'] = json_data
['resourceKindKey']
890 alarm_details
['type'] = json_data
['type']
891 alarm_details
['sub_type'] = json_data
['subType']
892 alarm_details
['symptom_definition_id'] = json_data
['states'][0]['base-symptom-set']['symptomDefinitionIds'][0]
893 except Exception as exp
:
894 self
.logger
.warn("Exception while retriving alarm defination details: {}".format(exp
))
897 return json_data
, alarm_details
900 def get_alarm_defination_by_name(self
, alarm_name
):
901 """Get alarm details based on alarm name
904 alert_match_list
= []
906 if alarm_name
is None:
907 self
.logger
.warn("get_alarm_defination_by_name: Alarm name not provided")
908 return alert_match_list
911 api_url
= '/suite-api/api/alertdefinitions'
912 headers
= {'Accept': 'application/json'}
914 resp
= requests
.get(self
.vrops_site
+ api_url
,
915 auth
=(self
.vrops_user
, self
.vrops_password
),
916 verify
= False, headers
= headers
)
918 if resp
.status_code
is not 200:
919 self
.logger
.warn("get_alarm_defination_by_name: Error in response: {}\nResponse code:{}"\
920 "\nResponse Content: {}".format(alarm_name
, resp
.status_code
, resp
.content
))
921 return alert_match_list
924 json_data
= json
.loads(resp
.content
)
925 if json_data
['alertDefinitions'] is not None:
926 alerts_list
= json_data
['alertDefinitions']
927 alert_match_list
= filter(lambda alert
: alert
['name'] == alarm_name
, alerts_list
)
928 status
= False if not alert_match_list
else True
929 #self.logger.debug("Found alert_match_list: {}for larm_name: {},\nstatus: {}".format(alert_match_list, alarm_name,status))
931 return alert_match_list
933 except Exception as exp
:
934 self
.logger
.warn("Exception while searching alarm defination: {}".format(exp
))
935 return alert_match_list
938 def update_symptom_defination(self
, symptom_uuid
, new_alarm_config
):
939 """Update symptom defination based on new alarm input configuration
941 #1) Get symptom defination details
942 symptom_details
= self
.get_symptom_defination_details(symptom_uuid
)
943 #print "\n\nsymptom_details: {}".format(symptom_details)
944 if symptom_details
is None:
947 if new_alarm_config
.has_key('severity') and new_alarm_config
['severity'] is not None:
948 symptom_details
['state']['severity'] = severity_mano2vrops
[new_alarm_config
['severity']]
949 if new_alarm_config
.has_key('operation') and new_alarm_config
['operation'] is not None:
950 symptom_details
['state']['condition']['operator'] = OPERATION_MAPPING
[new_alarm_config
['operation']]
951 if new_alarm_config
.has_key('threshold_value') and new_alarm_config
['threshold_value'] is not None:
952 symptom_details
['state']['condition']['value'] = new_alarm_config
['threshold_value']
953 #Find vrops metric key from metric_name, if required
955 if new_alarm_config.has_key('metric_name') and new_alarm_config['metric_name'] is not None:
956 metric_key_params = self.get_default_Params(new_alarm_config['metric_name'])
957 if not metric_key_params:
958 self.logger.warn("Metric not supported: {}".format(config_dict['metric_name']))
960 symptom_details['state']['condition']['key'] = metric_key_params['metric_key']
962 self
.logger
.info("Fetched Symptom details : {}".format(symptom_details
))
964 api_url
= '/suite-api/api/symptomdefinitions'
965 headers
= {'Content-Type': 'application/json', 'Accept':'application/json'}
966 data
= json
.dumps(symptom_details
)
967 resp
= requests
.put(self
.vrops_site
+ api_url
,
968 auth
=(self
.vrops_user
, self
.vrops_password
),
973 if resp
.status_code
!= 200:
974 self
.logger
.warn("Failed to update Symptom definition: {}, response {}"\
975 .format(symptom_uuid
, resp
.content
))
979 if symptom_uuid
is not None:
980 self
.logger
.info("Symptom defination updated {} for alarm: {}"\
981 .format(symptom_uuid
, new_alarm_config
['alarm_uuid']))
984 self
.logger
.warn("Failed to update Symptom Defination {} for : {}"\
985 .format(symptom_uuid
, new_alarm_config
['alarm_uuid']))
989 def get_symptom_defination_details(self
, symptom_uuid
):
990 """Get symptom defination details
993 if symptom_uuid
is None:
994 self
.logger
.warn("get_symptom_defination_details: Symptom UUID not provided")
997 api_url
= '/suite-api/api/symptomdefinitions/'
998 headers
= {'Accept': 'application/json'}
1000 resp
= requests
.get(self
.vrops_site
+ api_url
+ symptom_uuid
,
1001 auth
=(self
.vrops_user
, self
.vrops_password
),
1002 verify
= False, headers
= headers
)
1004 if resp
.status_code
is not 200:
1005 self
.logger
.warn("Symptom defination not found {} \nResponse code:{}\nResponse Content: {}"\
1006 .format(symptom_uuid
, resp
.status_code
, resp
.content
))
1009 symptom_details
= json
.loads(resp
.content
)
1010 #print "New symptom Details: {}".format(symptom_details)
1011 return symptom_details
1014 def reconfigure_alarm(self
, alarm_details_json
, new_alarm_config
):
1015 """Reconfigure alarm defination as per input
1017 if new_alarm_config
.has_key('severity') and new_alarm_config
['severity'] is not None:
1018 alarm_details_json
['states'][0]['severity'] = new_alarm_config
['severity']
1019 if new_alarm_config
.has_key('description') and new_alarm_config
['description'] is not None:
1020 alarm_details_json
['description'] = new_alarm_config
['description']
1022 api_url
= '/suite-api/api/alertdefinitions'
1023 headers
= {'Content-Type': 'application/json', 'Accept':'application/json'}
1024 data
= json
.dumps(alarm_details_json
)
1025 resp
= requests
.put(self
.vrops_site
+ api_url
,
1026 auth
=(self
.vrops_user
, self
.vrops_password
),
1031 if resp
.status_code
!= 200:
1032 self
.logger
.warn("Failed to create Symptom definition: {}, response code {}, response content: {}"\
1033 .format(symptom_uuid
, resp
.status_code
, resp
.content
))
1036 parsed_alarm_details
= json
.loads(resp
.content
)
1037 alarm_def_uuid
= parsed_alarm_details
['id'].split('-', 1)[1]
1038 self
.logger
.info("Successfully updated Alarm defination: {}".format(alarm_def_uuid
))
1039 return alarm_def_uuid
1041 def delete_alarm_configuration(self
, delete_alarm_req_dict
):
1042 """Delete complete alarm configuration
1044 if delete_alarm_req_dict
['alarm_uuid'] is None:
1045 self
.logger
.info("delete_alarm_configuration: Alarm UUID not provided")
1047 #1)Get alarm & symptom defination details
1048 alarm_details_json
, alarm_details
= self
.get_alarm_defination_details(delete_alarm_req_dict
['alarm_uuid'])
1049 if alarm_details
is None or alarm_details_json
is None:
1052 #2) Delete alarm notfication
1053 rule_id
= self
.delete_notification_rule(alarm_details
['alarm_name'])
1057 #3) Delete alarm configuraion
1058 alarm_id
= self
.delete_alarm_defination(alarm_details
['alarm_id'])
1059 if alarm_id
is None:
1062 #4) Delete alarm symptom
1063 symptom_id
= self
.delete_symptom_definition(alarm_details
['symptom_definition_id'])
1064 if symptom_id
is None:
1067 self
.logger
.info("Completed deleting alarm configuration: {}"\
1068 .format(delete_alarm_req_dict
['alarm_uuid']))
1069 return delete_alarm_req_dict
['alarm_uuid']
1071 def delete_notification_rule(self
, alarm_name
):
1072 """Deleted notification rule defined for a particular alarm
1074 rule_id
= self
.get_notification_rule_id_by_alarm_name(alarm_name
)
1078 api_url
= '/suite-api/api/notifications/rules/'
1079 headers
= {'Accept':'application/json'}
1080 resp
= requests
.delete(self
.vrops_site
+ api_url
+ rule_id
,
1081 auth
=(self
.vrops_user
, self
.vrops_password
),
1082 verify
= False, headers
= headers
)
1083 if resp
.status_code
is not 204:
1084 self
.logger
.warn("Failed to delete notification rules for {}".format(alarm_name
))
1087 self
.logger
.info("Deleted notification rules for {}".format(alarm_name
))
1090 def get_notification_rule_id_by_alarm_name(self
, alarm_name
):
1091 """Find created Alarm notification rule id by alarm name
1093 alarm_notify_id
= 'notify_' + alarm_name
1094 api_url
= '/suite-api/api/notifications/rules'
1095 headers
= {'Content-Type': 'application/json', 'Accept':'application/json'}
1096 resp
= requests
.get(self
.vrops_site
+ api_url
,
1097 auth
=(self
.vrops_user
, self
.vrops_password
),
1098 verify
= False, headers
= headers
)
1100 if resp
.status_code
is not 200:
1101 self
.logger
.warn("Failed to get notification rules details for {}"\
1102 .format(delete_alarm_req_dict
['alarm_name']))
1105 notifications
= json
.loads(resp
.content
)
1106 if notifications
is not None and notifications
.has_key('notification-rule'):
1107 notifications_list
= notifications
['notification-rule']
1108 for dict in notifications_list
:
1109 if dict['name'] is not None and dict['name'] == alarm_notify_id
:
1110 notification_id
= dict['id']
1111 self
.logger
.info("Found Notification id to be deleted: {} for {}"\
1112 .format(notification_id
, alarm_name
))
1113 return notification_id
1115 self
.logger
.warn("Notification id to be deleted not found for {}"\
1116 .format(notification_id
, alarm_name
))
1119 def delete_alarm_defination(self
, alarm_id
):
1120 """Delete created Alarm defination
1122 api_url
= '/suite-api/api/alertdefinitions/'
1123 headers
= {'Accept':'application/json'}
1124 resp
= requests
.delete(self
.vrops_site
+ api_url
+ alarm_id
,
1125 auth
=(self
.vrops_user
, self
.vrops_password
),
1126 verify
= False, headers
= headers
)
1127 if resp
.status_code
is not 204:
1128 self
.logger
.warn("Failed to delete alarm definition {}".format(alarm_id
))
1131 self
.logger
.info("Deleted alarm definition {}".format(alarm_id
))
1134 def delete_symptom_definition(self
, symptom_id
):
1135 """Delete symptom defination
1137 api_url
= '/suite-api/api/symptomdefinitions/'
1138 headers
= {'Accept':'application/json'}
1139 resp
= requests
.delete(self
.vrops_site
+ api_url
+ symptom_id
,
1140 auth
=(self
.vrops_user
, self
.vrops_password
),
1141 verify
= False, headers
= headers
)
1142 if resp
.status_code
is not 204:
1143 self
.logger
.warn("Failed to delete symptom definition {}".format(symptom_id
))
1146 self
.logger
.info("Deleted symptom definition {}".format(symptom_id
))
1150 def verify_metric_support(self
, metric_info
):
1151 """Verify, if Metric is supported by vROPs plugin, verify metric unit & return status
1153 status: True if supported, False if not supported
1156 if 'metric_name' not in metric_info
:
1157 self
.logger
.debug("Metric name not provided: {}".format(metric_info
))
1159 metric_key_params
= self
.get_default_Params(metric_info
['metric_name'])
1160 if not metric_key_params
:
1161 self
.logger
.warn("Metric not supported: {}".format(metric_info
['metric_name']))
1164 #If Metric is supported, verify optional metric unit & return status
1165 if 'metric_unit' in metric_info
:
1166 if metric_key_params
.get('unit') == metric_info
['metric_unit']:
1167 self
.logger
.info("Metric is supported with unit: {}".format(metric_info
['metric_name']))
1170 self
.logger
.debug("Metric supported but there is unit mismatch for: {}."\
1171 "Supported unit: {}"\
1172 .format(metric_info
['metric_name'],metric_key_params
['unit']))
1176 def get_triggered_alarms_list(self
, list_alarm_input
):
1177 """Get list of triggered alarms on a resource based on alarm input request.
1179 #TO Do - Need to add filtering of alarms based on Severity & alarm name
1181 triggered_alarms_list
= []
1182 if list_alarm_input
.get('resource_uuid') is None:
1183 self
.logger
.warn("Resource UUID is required to get triggered alarms list")
1184 return triggered_alarms_list
1186 #1)Find vROPs resource ID using RO resource UUID
1187 vrops_resource_id
= self
.get_vrops_resourceid_from_ro_uuid(list_alarm_input
['resource_uuid'])
1188 if vrops_resource_id
is None:
1189 return triggered_alarms_list
1191 #2)Get triggered alarms on particular resource
1192 triggered_alarms_list
= self
.get_triggered_alarms_on_resource(list_alarm_input
['resource_uuid'], vrops_resource_id
)
1193 return triggered_alarms_list
1195 def get_vrops_resourceid_from_ro_uuid(self
, ro_resource_uuid
):
1196 """Fetch vROPs resource ID using resource UUID from RO/SO
1198 #1) Find vm_moref_id from vApp uuid in vCD
1199 vm_moref_id
= self
.get_vm_moref_id(ro_resource_uuid
)
1200 if vm_moref_id
is None:
1201 self
.logger
.warn("Failed to find vm morefid for vApp in vCD: {}".format(ro_resource_uuid
))
1204 #2) Based on vm_moref_id, find VM's corresponding resource_id in vROPs to set notification
1205 vrops_resource_id
= self
.get_vm_resource_id(vm_moref_id
)
1206 if vrops_resource_id
is None:
1207 self
.logger
.warn("Failed to find resource in vROPs: {}".format(ro_resource_uuid
))
1209 return vrops_resource_id
1212 def get_triggered_alarms_on_resource(self
, ro_resource_uuid
, vrops_resource_id
):
1213 """Get triggered alarms on particular resource & return list of dictionary of alarms
1215 resource_alarms
= []
1216 api_url
= '/suite-api/api/alerts?resourceId='
1217 headers
= {'Accept':'application/json'}
1218 resp
= requests
.get(self
.vrops_site
+ api_url
+ vrops_resource_id
,
1219 auth
=(self
.vrops_user
, self
.vrops_password
),
1220 verify
= False, headers
= headers
)
1222 if resp
.status_code
is not 200:
1223 self
.logger
.warn("Failed to get notification rules details for {}"\
1224 .format(delete_alarm_req_dict
['alarm_name']))
1227 all_alerts
= json
.loads(resp
.content
)
1228 if all_alerts
.has_key('alerts'):
1229 if not all_alerts
['alerts']:
1230 self
.logger
.info("No alarms present on resource {}".format(ro_resource_uuid
))
1231 return resource_alarms
1232 all_alerts_list
= all_alerts
['alerts']
1233 for alarm
in all_alerts_list
:
1234 #self.logger.info("Triggered Alarm {}".format(alarm))
1235 if alarm
['alertDefinitionName'] is not None and\
1236 len(alarm
['alertDefinitionName'].split('-', 1)) == 2:
1237 if alarm
['alertDefinitionName'].split('-', 1)[1] == ro_resource_uuid
:
1239 alarm_instance
['alarm_uuid'] = alarm
['alertDefinitionId'].split('-', 1)[1]
1240 alarm_instance
['resource_uuid'] = ro_resource_uuid
1241 alarm_instance
['alarm_instance_uuid'] = alarm
['alertId']
1242 alarm_instance
['vim_type'] = 'VMware'
1243 #find severity of alarm
1245 for key
,value
in severity_mano2vrops
.iteritems():
1246 if value
== alarm
['alertLevel']:
1248 if severity
is None:
1249 severity
= 'INDETERMINATE'
1250 alarm_instance
['severity'] = severity
1251 alarm_instance
['status'] = alarm
['status']
1252 alarm_instance
['start_date'] = self
.convert_date_time(alarm
['startTimeUTC'])
1253 alarm_instance
['update_date'] = self
.convert_date_time(alarm
['updateTimeUTC'])
1254 alarm_instance
['cancel_date'] = self
.convert_date_time(alarm
['cancelTimeUTC'])
1255 self
.logger
.info("Triggered Alarm on resource {}".format(alarm_instance
))
1256 resource_alarms
.append(alarm_instance
)
1257 if not resource_alarms
:
1258 self
.logger
.info("No alarms present on resource {}".format(ro_resource_uuid
))
1259 return resource_alarms
1261 def convert_date_time(self
, date_time
):
1262 """Convert the input UTC time in msec to OSM date time format
1264 date_time_formatted
= '0000-00-00T00:00:00'
1266 complete_datetime
= datetime
.datetime
.fromtimestamp(date_time
/1000.0).isoformat('T')
1267 date_time_formatted
= complete_datetime
.split('.',1)[0]
1268 return date_time_formatted