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/json','Accept': 'application/json'}
258 "name": symptom_params
['symptom_name'],
259 "adapterKindKey": symptom_params
['adapter_kind_key'],
260 "resourceKindKey": symptom_params
['resource_kind_key'],
261 "waitCycles": symptom_params
['wait_cycles'],
262 "cancelCycles": symptom_params
['cancel_cycles'],
264 "severity": symptom_params
['severity'],
266 "type": "CONDITION_HT",
267 "key": symptom_params
['metric_key'],
268 "operator": symptom_params
['operation'],
269 "value": symptom_params
['threshold_value'],
270 "valueType": "NUMERIC",
272 "thresholdType": "STATIC"
277 resp
= requests
.post(self
.vrops_site
+ api_url
,
278 auth
=(self
.vrops_user
, self
.vrops_password
),
281 data
=json
.dumps(data
))
283 if resp
.status_code
!= 201:
284 self
.logger
.warn("Failed to create Symptom definition: {}, response {}"\
285 .format(symptom_params
['symptom_name'], resp
.content
))
288 resp_data
= json
.loads(resp
.content
)
289 if resp_data
.get('id') is not None:
290 symptom_id
= resp_data
['id']
294 except Exception as exp
:
295 self
.logger
.warn("Error creating symptom definition : {}\n{}"\
296 .format(exp
, traceback
.format_exc()))
299 def create_alarm_definition(self
, alarm_params
):
301 Create an alarm definition in vROPs
304 'description':Alarm description,
305 'adapterKindKey': Adapter type in vROPs "VMWARE",
306 'resourceKindKey':Resource type in vROPs "VirtualMachine",
307 'waitCycles': No of wait cycles,
308 'cancelCycles': No of cancel cycles,
310 'subType': Alarm subtype,
311 'severity': Severity in vROPs "CRITICAL",
312 'symptomDefinitionId':symptom Definition uuid,
313 'impact': impact 'risk'
315 'alarm_uuid': returns alarm uuid
321 api_url
= '/suite-api/api/alertdefinitions'
322 headers
= {'Content-Type': 'application/json', 'Accept': 'application/json'}
324 "name": alarm_params
['name'],
325 "description": alarm_params
['description'],
326 "adapterKindKey": alarm_params
['adapterKindKey'],
327 "resourceKindKey": alarm_params
['resourceKindKey'],
330 "type": alarm_params
['type'],
331 "subType": alarm_params
['subType'],
334 "severity": alarm_params
['severity'],
337 "type": "SYMPTOM_SET",
339 "aggregation": "ALL",
340 "symptomSetOperator": "AND",
341 "symptomDefinitionIds": [alarm_params
['symptomDefinitionId']]
344 "impactType": "BADGE",
345 "detail": alarm_params
['impact']
351 resp
= requests
.post(self
.vrops_site
+ api_url
,
352 auth
=(self
.vrops_user
, self
.vrops_password
),
355 data
=json
.dumps(data
))
357 if resp
.status_code
!= 201:
358 self
.logger
.warn("Failed to create Alarm definition: {}, response {}"\
359 .format(alarm_params
['name'], resp
.content
))
362 resp_data
= json
.loads(resp
.content
)
363 if resp_data
.get('id') is not None:
364 alarm_uuid
= resp_data
['id']
368 except Exception as exp
:
369 self
.logger
.warn("Error creating alarm definition : {}\n{}".format(exp
, traceback
.format_exc()))
372 def configure_rest_plugin(self
):
374 Creates REST Plug-in for vROPs outbound alerts
379 plugin_name
= 'MON_module_REST_Plugin'
380 plugin_id
= self
.check_if_plugin_configured(plugin_name
)
382 #If REST plugin not configured, configure it
383 if plugin_id
is not None:
387 cert_file_string
= open(SSL_CERTIFICATE_FILE_PATH
, "rb").read()
388 except IOError as exp
:
389 msg
= ("Could not read SSL certificate file: {}".format(SSL_CERTIFICATE_FILE_PATH
))
390 self
.logger
.error(msg
)
392 cert
= load_certificate(FILETYPE_PEM
, cert_file_string
)
393 certificate
= cert
.digest("sha1")
394 api_url
= '/suite-api/api/alertplugins'
395 headers
= {'Content-Type': 'application/json', 'Accept': 'application/json'}
397 "pluginTypeId": "RestPlugin",
405 "name": "Content-type",
406 "value": "application/json"
409 "name": "Certificate",
413 "name": "ConnectionCount",
419 resp
= requests
.post(self
.vrops_site
+ api_url
,
420 auth
=(self
.vrops_user
, self
.vrops_password
),
423 data
=json
.dumps(data
))
425 if resp
.status_code
is not 201:
426 self
.logger
.warn("Failed to create REST Plugin: {} for url: {}, \nresponse code: {},"\
427 "\nresponse content: {}".format(plugin_name
, webhook_url
,\
428 resp
.status_code
, resp
.content
))
431 resp_data
= json
.loads(resp
.content
)
432 if resp_data
.get('pluginId') is not None:
433 plugin_id
= resp_data
['pluginId']
435 if plugin_id
is None:
436 self
.logger
.warn("Failed to get REST Plugin ID for {}, url: {}".format(plugin_name
, webhook_url
))
439 self
.logger
.info("Created REST Plugin: {} with ID : {} for url: {}".format(plugin_name
, plugin_id
, webhook_url
))
440 status
= self
.enable_rest_plugin(plugin_id
, plugin_name
)
442 self
.logger
.warn("Failed to enable created REST Plugin: {} for url: {}".format(plugin_name
, webhook_url
))
445 self
.logger
.info("Enabled REST Plugin: {} for url: {}".format(plugin_name
, webhook_url
))
448 def check_if_plugin_configured(self
, plugin_name
):
449 """Check if the REST plugin is already created
450 Returns: plugin_id: if already created, None: if needs to be created
453 #Find the REST Plugin id details for - MON_module_REST_Plugin
454 api_url
= '/suite-api/api/alertplugins'
455 headers
= {'Accept': 'application/json'}
457 resp
= requests
.get(self
.vrops_site
+ api_url
,
458 auth
=(self
.vrops_user
, self
.vrops_password
),
459 verify
= False, headers
= headers
)
461 if resp
.status_code
is not 200:
462 self
.logger
.warn("Failed to REST GET Alarm plugin details \nResponse code: {}\nResponse content: {}"\
463 .format(resp
.status_code
, resp
.content
))
466 # Look for specific plugin & parse pluginId for 'MON_module_REST_Plugin'
467 plugins_list
= json
.loads(resp
.content
)
468 if plugins_list
.get('notificationPluginInstances') is not None:
469 for notify_plugin
in plugins_list
['notificationPluginInstances']:
470 if notify_plugin
.get('name') is not None and notify_plugin
['name'] == plugin_name
:
471 plugin_id
= notify_plugin
.get('pluginId')
473 if plugin_id
is None:
474 self
.logger
.warn("REST plugin {} not found".format(plugin_name
))
477 self
.logger
.info("Found REST Plugin: {}".format(plugin_name
))
481 def enable_rest_plugin(self
, plugin_id
, plugin_name
):
483 Enable the REST plugin using plugin_id
484 Params: plugin_id: plugin ID string that is to be enabled
485 Returns: status (Boolean) - True for success, False for failure
488 if plugin_id
is None or plugin_name
is None:
489 self
.logger
.debug("enable_rest_plugin() : Plugin ID or plugin_name not provided for {} plugin"\
490 .format(plugin_name
))
494 api_url
= "/suite-api/api/alertplugins/{}/enable/True".format(plugin_id
)
496 resp
= requests
.put(self
.vrops_site
+ api_url
,
497 auth
=(self
.vrops_user
, self
.vrops_password
),
500 if resp
.status_code
is not 204:
501 self
.logger
.warn("Failed to enable REST plugin {}. \nResponse code {}\nResponse Content: {}"\
502 .format(plugin_name
, resp
.status_code
, resp
.content
))
505 self
.logger
.info("Enabled REST plugin {}.".format(plugin_name
))
508 except Exception as exp
:
509 self
.logger
.warn("Error enabling REST plugin for {} plugin: Exception: {}\n{}"\
510 .format(plugin_name
, exp
, traceback
.format_exc()))
512 def create_alarm_notification_rule(self
, alarm_name
, alarm_id
, resource_id
):
514 Create notification rule for each alarm
521 notification_id: notification_id or None
523 notification_name
= 'notify_' + alarm_name
524 notification_id
= None
525 plugin_name
= 'MON_module_REST_Plugin'
527 #1) Find the REST Plugin id details for - MON_module_REST_Plugin
528 plugin_id
= self
.check_if_plugin_configured(plugin_name
)
529 if plugin_id
is None:
530 self
.logger
.warn("Failed to get REST plugin_id for : {}".format('MON_module_REST_Plugin'))
533 #2) Create Alarm notification rule
534 api_url
= '/suite-api/api/notifications/rules'
535 headers
= {'Content-Type': 'application/json', 'Accept': 'application/json'}
537 "name" : notification_name
,
538 "pluginId" : plugin_id
,
540 "matchResourceIdOnly": True,
541 "resourceId": resource_id
543 "alertDefinitionIdFilters" : {
544 "values" : [ alarm_id
]
548 resp
= requests
.post(self
.vrops_site
+ api_url
,
549 auth
=(self
.vrops_user
, self
.vrops_password
),
552 data
=json
.dumps(data
))
554 if resp
.status_code
is not 201:
555 self
.logger
.warn("Failed to create Alarm notification rule {} for {} alarm."\
556 "\nResponse code: {}\nResponse content: {}"\
557 .format(notification_name
, alarm_name
, resp
.status_code
, resp
.content
))
560 #parse notification id from response
561 resp_data
= json
.loads(resp
.content
)
562 if resp_data
.get('id') is not None:
563 notification_id
= resp_data
['id']
565 self
.logger
.info("Created Alarm notification rule {} for {} alarm.".format(notification_name
, alarm_name
))
566 return notification_id
568 def get_vm_moref_id(self
, vapp_uuid
):
570 Get the moref_id of given VM
574 vm_details
= self
.get_vapp_details_rest(vapp_uuid
)
575 if vm_details
and "vm_vcenter_info" in vm_details
:
576 vm_moref_id
= vm_details
["vm_vcenter_info"].get("vm_moref_id", None)
578 self
.logger
.info("Found vm_moref_id: {} for vApp UUID: {}".format(vm_moref_id
, vapp_uuid
))
581 except Exception as exp
:
582 self
.logger
.warn("Error occurred while getting VM moref ID for VM : {}\n{}"\
583 .format(exp
, traceback
.format_exc()))
586 def get_vapp_details_rest(self
, vapp_uuid
=None):
588 Method retrieve vapp detail from vCloud director
591 vapp_uuid - is vapp identifier.
594 Returns VM MOref ID or return None
600 vca
= self
.connect_as_admin()
603 self
.logger
.warn("connect() to vCD is failed")
604 if vapp_uuid
is None:
607 url_list
= [vca
.host
, '/api/vApp/vapp-', vapp_uuid
]
608 get_vapp_restcall
= ''.join(url_list
)
610 if vca
.vcloud_session
and vca
.vcloud_session
.organization
:
611 response
= requests
.get(get_vapp_restcall
,
612 headers
=vca
.vcloud_session
.get_vcloud_headers(),
615 if response
.status_code
!= 200:
616 self
.logger
.warn("REST API call {} failed. Return status code {}"\
617 .format(get_vapp_restcall
, response
.content
))
618 return parsed_respond
621 xmlroot_respond
= XmlElementTree
.fromstring(response
.content
)
623 namespaces
= {'vm': 'http://www.vmware.com/vcloud/v1.5',
624 "vmext":"http://www.vmware.com/vcloud/extension/v1.5",
625 "xmlns":"http://www.vmware.com/vcloud/v1.5"
628 # parse children section for other attrib
629 children_section
= xmlroot_respond
.find('vm:Children/', namespaces
)
630 if children_section
is not None:
631 vCloud_extension_section
= children_section
.find('xmlns:VCloudExtension', namespaces
)
632 if vCloud_extension_section
is not None:
634 vim_info
= vCloud_extension_section
.find('vmext:VmVimInfo', namespaces
)
635 vmext
= vim_info
.find('vmext:VmVimObjectRef', namespaces
)
636 if vmext
is not None:
637 vm_vcenter_info
["vm_moref_id"] = vmext
.find('vmext:MoRef', namespaces
).text
638 parsed_respond
["vm_vcenter_info"]= vm_vcenter_info
640 except Exception as exp
:
641 self
.logger
.warn("Error occurred calling rest api for getting vApp details: {}\n{}"\
642 .format(exp
, traceback
.format_exc()))
644 return parsed_respond
647 def connect_as_admin(self
):
648 """ Method connect as pvdc admin user to vCloud director.
649 There are certain action that can be done only by provider vdc admin user.
650 Organization creation / provider network creation etc.
653 The return vca object that letter can be used to connect to vcloud direct as admin for provider vdc
656 self
.logger
.info("Logging in to a VCD org as admin.")
658 vca_admin
= VCA(host
=self
.vcloud_site
,
659 username
=self
.admin_username
,
660 service_type
='standalone',
664 result
= vca_admin
.login(password
=self
.admin_password
, org
='System')
666 self
.logger
.warn("Can't connect to a vCloud director as: {}".format(self
.admin_username
))
667 result
= vca_admin
.login(token
=vca_admin
.token
, org
='System', org_url
=vca_admin
.vcloud_session
.org_url
)
669 self
.logger
.info("Successfully logged to a vcloud direct org: {} as user: {}"\
670 .format('System', self
.admin_username
))
675 def get_vm_resource_id(self
, vm_moref_id
):
676 """ Find resource ID in vROPs using vm_moref_id
678 if vm_moref_id
is None:
681 api_url
= '/suite-api/api/resources?resourceKind=VirtualMachine'
682 headers
= {'Accept': 'application/json'}
684 resp
= requests
.get(self
.vrops_site
+ api_url
,
685 auth
=(self
.vrops_user
, self
.vrops_password
),
686 verify
= False, headers
= headers
)
688 if resp
.status_code
is not 200:
689 self
.logger
.warn("Failed to get resource details from vROPs for {}"\
690 "\nResponse code:{}\nResponse Content: {}"\
691 .format(vm_moref_id
, resp
.status_code
, resp
.content
))
694 vm_resource_id
= None
696 resp_data
= json
.loads(resp
.content
)
697 if resp_data
.get('resourceList') is not None:
698 resource_list
= resp_data
.get('resourceList')
699 for resource
in resource_list
:
700 if resource
.get('resourceKey') is not None:
701 resource_details
= resource
['resourceKey']
702 if resource_details
.get('resourceIdentifiers') is not None:
703 resource_identifiers
= resource_details
['resourceIdentifiers']
704 for resource_identifier
in resource_identifiers
:
705 if resource_identifier
['identifierType']['name']=='VMEntityObjectID':
706 if resource_identifier
.get('value') is not None and \
707 resource_identifier
['value']==vm_moref_id
:
708 vm_resource_id
= resource
['identifier']
709 self
.logger
.info("Found VM resource ID: {} for vm_moref_id: {}"\
710 .format(vm_resource_id
, vm_moref_id
))
712 except Exception as exp
:
713 self
.logger
.warn("get_vm_resource_id: Error in parsing {}\n{}"\
714 .format(exp
, traceback
.format_exc()))
716 return vm_resource_id
719 def get_metrics_data(self
, metric
={}):
720 """Get an individual metric's data of a resource.
722 'metric_name': Normalized name of metric (string)
723 'resource_uuid': Resource UUID (string)
724 'period': Time period in Period Unit for which metrics data to be collected from
725 Monitoring tool from now.
726 'period_unit': Period measurement unit can be one of 'HR', 'DAY', 'MONTH', 'YEAR'
728 Return a dict that contains:
729 'metric_name': Normalized name of metric (string)
730 'resource_uuid': Resource UUID (string)
731 'tenant_id': tenent id name in which the resource is present in string format
732 'metrics_data': Dictionary containing time_series & metrics_series data.
733 'time_series': List of individual time stamp values in msec
734 'metrics_series': List of individual metrics data values
735 Raises an exception upon error or when network is not found
738 return_data
['schema_version'] = "1.0"
739 return_data
['schema_type'] = 'read_metric_data_response'
740 return_data
['metric_name'] = metric
['metric_name']
741 #To do - No metric_uuid in vROPs, thus returning '0'
742 return_data
['metric_uuid'] = '0'
743 return_data
['correlation_id'] = metric
['correlation_id']
744 return_data
['resource_uuid'] = metric
['resource_uuid']
745 return_data
['metrics_data'] = {'time_series':[], 'metrics_series':[]}
746 #To do - Need confirmation about uuid & id
747 if 'tenant_uuid' in metric
and metric
['tenant_uuid'] is not None:
748 return_data
['tenant_uuid'] = metric
['tenant_uuid']
750 return_data
['tenant_uuid'] = None
751 return_data
['unit'] = None
752 #return_data['tenant_id'] = self.tenant_id
753 #self.logger.warn("return_data: {}".format(return_data))
755 #1) Get metric details from plugin specific file & format it into vROPs metrics
756 metric_key_params
= self
.get_default_Params(metric
['metric_name'])
758 if not metric_key_params
:
759 self
.logger
.warn("Metric not supported: {}".format(metric
['metric_name']))
760 #To Do: Return message
763 return_data
['unit'] = metric_key_params
['unit']
765 #2) Find the resource id in vROPs based on OSM resource_uuid
766 #2.a) Find vm_moref_id from vApp uuid in vCD
767 vm_moref_id
= self
.get_vm_moref_id(metric
['resource_uuid'])
768 if vm_moref_id
is None:
769 self
.logger
.warn("Failed to find vm morefid for vApp in vCD: {}".format(metric
['resource_uuid']))
771 #2.b) Based on vm_moref_id, find VM's corresponding resource_id in vROPs to set notification
772 resource_id
= self
.get_vm_resource_id(vm_moref_id
)
773 if resource_id
is None:
774 self
.logger
.warn("Failed to find resource in vROPs: {}".format(metric
['resource_uuid']))
777 #3) Calculate begin & end time for period & period unit
778 end_time
= int(round(time
.time() * 1000))
779 if metric
['collection_unit'] == 'YR':
780 time_diff
= PERIOD_MSEC
[metric
['collection_unit']]
782 time_diff
= metric
['collection_period']* PERIOD_MSEC
[metric
['collection_unit']]
783 begin_time
= end_time
- time_diff
785 #4) Get the metrics data
786 self
.logger
.info("metric_key_params['metric_key'] = {}".format(metric_key_params
['metric_key']))
787 self
.logger
.info("end_time: {}, begin_time: {}".format(end_time
, begin_time
))
789 url_list
= ['/suite-api/api/resources/', resource_id
, '/stats?statKey=',\
790 metric_key_params
['metric_key'], '&begin=', str(begin_time
),'&end=',str(end_time
)]
791 api_url
= ''.join(url_list
)
792 headers
= {'Accept': 'application/json'}
794 resp
= requests
.get(self
.vrops_site
+ api_url
,
795 auth
=(self
.vrops_user
, self
.vrops_password
),
796 verify
= False, headers
= headers
)
798 if resp
.status_code
is not 200:
799 self
.logger
.warn("Failed to retrive Metric data from vROPs for {}\nResponse code:{}\nResponse Content: {}"\
800 .format(metric
['metric_name'], resp
.status_code
, resp
.content
))
803 #5) Convert to required format
805 json_data
= json
.loads(resp
.content
)
806 for resp_key
,resp_val
in json_data
.iteritems():
807 if resp_key
== 'values':
808 data
= json_data
['values'][0]
809 for data_k
,data_v
in data
.iteritems():
810 if data_k
== 'stat-list':
812 for stat_list_k
,stat_list_v
in stat_list
.iteritems():
813 for stat_keys
,stat_vals
in stat_list_v
[0].iteritems():
814 if stat_keys
== 'timestamps':
815 metrics_data
['time_series'] = stat_list_v
[0]['timestamps']
816 if stat_keys
== 'data':
817 metrics_data
['metrics_series'] = stat_list_v
[0]['data']
819 return_data
['metrics_data'] = metrics_data
823 def update_alarm_configuration(self
, new_alarm_config
):
824 """Update alarm configuration (i.e. Symptom & alarm) as per request
826 if new_alarm_config
.get('alarm_uuid') is None:
827 self
.logger
.warn("alarm_uuid is required to update an Alarm")
829 #1) Get Alarm details from it's uuid & find the symptom defination
830 alarm_details_json
, alarm_details
= self
.get_alarm_defination_details(new_alarm_config
['alarm_uuid'])
831 if alarm_details_json
is None:
835 #2) Update the symptom defination
836 if alarm_details
['alarm_id'] is not None and alarm_details
['symptom_definition_id'] is not None:
837 symptom_defination_id
= alarm_details
['symptom_definition_id']
839 self
.logger
.info("Symptom Defination ID not found for {}".format(new_alarm_config
['alarm_uuid']))
842 symptom_uuid
= self
.update_symptom_defination(symptom_defination_id
, new_alarm_config
)
844 #3) Update the alarm defination & Return UUID if successful update
845 if symptom_uuid
is None:
846 self
.logger
.info("Symptom Defination details not found for {}"\
847 .format(new_alarm_config
['alarm_uuid']))
850 alarm_uuid
= self
.reconfigure_alarm(alarm_details_json
, new_alarm_config
)
851 if alarm_uuid
is None:
856 self
.logger
.error("Exception while updating alarm: {}".format(traceback
.format_exc()))
858 def get_alarm_defination_details(self
, alarm_uuid
):
859 """Get alarm details based on alarm UUID
861 if alarm_uuid
is None:
862 self
.logger
.warn("get_alarm_defination_details: Alarm UUID not provided")
867 api_url
= '/suite-api/api/alertdefinitions/AlertDefinition-'
868 headers
= {'Accept': 'application/json'}
870 resp
= requests
.get(self
.vrops_site
+ api_url
+ alarm_uuid
,
871 auth
=(self
.vrops_user
, self
.vrops_password
),
872 verify
= False, headers
= headers
)
874 if resp
.status_code
is not 200:
875 self
.logger
.warn("Alarm to be updated not found: {}\nResponse code:{}\nResponse Content: {}"\
876 .format(alarm_uuid
, resp
.status_code
, resp
.content
))
880 json_data
= json
.loads(resp
.content
)
881 if json_data
['id'] is not None:
882 alarm_details
['alarm_id'] = json_data
['id']
883 alarm_details
['alarm_name'] = json_data
['name']
884 alarm_details
['adapter_kind'] = json_data
['adapterKindKey']
885 alarm_details
['resource_kind'] = json_data
['resourceKindKey']
886 alarm_details
['type'] = json_data
['type']
887 alarm_details
['sub_type'] = json_data
['subType']
888 alarm_details
['symptom_definition_id'] = json_data
['states'][0]['base-symptom-set']['symptomDefinitionIds'][0]
889 except Exception as exp
:
890 self
.logger
.warn("Exception while retriving alarm defination details: {}".format(exp
))
893 return json_data
, alarm_details
896 def get_alarm_defination_by_name(self
, alarm_name
):
897 """Get alarm details based on alarm name
900 alert_match_list
= []
902 if alarm_name
is None:
903 self
.logger
.warn("get_alarm_defination_by_name: Alarm name not provided")
904 return alert_match_list
907 api_url
= '/suite-api/api/alertdefinitions'
908 headers
= {'Accept': 'application/json'}
910 resp
= requests
.get(self
.vrops_site
+ api_url
,
911 auth
=(self
.vrops_user
, self
.vrops_password
),
912 verify
= False, headers
= headers
)
914 if resp
.status_code
is not 200:
915 self
.logger
.warn("get_alarm_defination_by_name: Error in response: {}\nResponse code:{}"\
916 "\nResponse Content: {}".format(alarm_name
, resp
.status_code
, resp
.content
))
917 return alert_match_list
920 json_data
= json
.loads(resp
.content
)
921 if json_data
['alertDefinitions'] is not None:
922 alerts_list
= json_data
['alertDefinitions']
923 alert_match_list
= filter(lambda alert
: alert
['name'] == alarm_name
, alerts_list
)
924 status
= False if not alert_match_list
else True
925 #self.logger.debug("Found alert_match_list: {}for larm_name: {},\nstatus: {}".format(alert_match_list, alarm_name,status))
927 return alert_match_list
929 except Exception as exp
:
930 self
.logger
.warn("Exception while searching alarm defination: {}".format(exp
))
931 return alert_match_list
934 def update_symptom_defination(self
, symptom_uuid
, new_alarm_config
):
935 """Update symptom defination based on new alarm input configuration
937 #1) Get symptom defination details
938 symptom_details
= self
.get_symptom_defination_details(symptom_uuid
)
939 #print "\n\nsymptom_details: {}".format(symptom_details)
940 if symptom_details
is None:
943 if new_alarm_config
.has_key('severity') and new_alarm_config
['severity'] is not None:
944 symptom_details
['state']['severity'] = severity_mano2vrops
[new_alarm_config
['severity']]
945 if new_alarm_config
.has_key('operation') and new_alarm_config
['operation'] is not None:
946 symptom_details
['state']['condition']['operator'] = OPERATION_MAPPING
[new_alarm_config
['operation']]
947 if new_alarm_config
.has_key('threshold_value') and new_alarm_config
['threshold_value'] is not None:
948 symptom_details
['state']['condition']['value'] = new_alarm_config
['threshold_value']
949 #Find vrops metric key from metric_name, if required
951 if new_alarm_config.has_key('metric_name') and new_alarm_config['metric_name'] is not None:
952 metric_key_params = self.get_default_Params(new_alarm_config['metric_name'])
953 if not metric_key_params:
954 self.logger.warn("Metric not supported: {}".format(config_dict['metric_name']))
956 symptom_details['state']['condition']['key'] = metric_key_params['metric_key']
958 self
.logger
.info("Fetched Symptom details : {}".format(symptom_details
))
960 api_url
= '/suite-api/api/symptomdefinitions'
961 headers
= {'Content-Type': 'application/json', 'Accept':'application/json'}
962 data
= json
.dumps(symptom_details
)
963 resp
= requests
.put(self
.vrops_site
+ api_url
,
964 auth
=(self
.vrops_user
, self
.vrops_password
),
969 if resp
.status_code
!= 200:
970 self
.logger
.warn("Failed to update Symptom definition: {}, response {}"\
971 .format(symptom_uuid
, resp
.content
))
975 if symptom_uuid
is not None:
976 self
.logger
.info("Symptom defination updated {} for alarm: {}"\
977 .format(symptom_uuid
, new_alarm_config
['alarm_uuid']))
980 self
.logger
.warn("Failed to update Symptom Defination {} for : {}"\
981 .format(symptom_uuid
, new_alarm_config
['alarm_uuid']))
985 def get_symptom_defination_details(self
, symptom_uuid
):
986 """Get symptom defination details
989 if symptom_uuid
is None:
990 self
.logger
.warn("get_symptom_defination_details: Symptom UUID not provided")
993 api_url
= '/suite-api/api/symptomdefinitions/'
994 headers
= {'Accept': 'application/json'}
996 resp
= requests
.get(self
.vrops_site
+ api_url
+ symptom_uuid
,
997 auth
=(self
.vrops_user
, self
.vrops_password
),
998 verify
= False, headers
= headers
)
1000 if resp
.status_code
is not 200:
1001 self
.logger
.warn("Symptom defination not found {} \nResponse code:{}\nResponse Content: {}"\
1002 .format(symptom_uuid
, resp
.status_code
, resp
.content
))
1005 symptom_details
= json
.loads(resp
.content
)
1006 #print "New symptom Details: {}".format(symptom_details)
1007 return symptom_details
1010 def reconfigure_alarm(self
, alarm_details_json
, new_alarm_config
):
1011 """Reconfigure alarm defination as per input
1013 if new_alarm_config
.has_key('severity') and new_alarm_config
['severity'] is not None:
1014 alarm_details_json
['states'][0]['severity'] = new_alarm_config
['severity']
1015 if new_alarm_config
.has_key('description') and new_alarm_config
['description'] is not None:
1016 alarm_details_json
['description'] = new_alarm_config
['description']
1018 api_url
= '/suite-api/api/alertdefinitions'
1019 headers
= {'Content-Type': 'application/json', 'Accept':'application/json'}
1020 data
= json
.dumps(alarm_details_json
)
1021 resp
= requests
.put(self
.vrops_site
+ api_url
,
1022 auth
=(self
.vrops_user
, self
.vrops_password
),
1027 if resp
.status_code
!= 200:
1028 self
.logger
.warn("Failed to update Alarm definition: {}, response code {}, response content: {}"\
1029 .format(alarm_details_json
['id'], resp
.status_code
, resp
.content
))
1032 parsed_alarm_details
= json
.loads(resp
.content
)
1033 alarm_def_uuid
= parsed_alarm_details
['id'].split('-', 1)[1]
1034 self
.logger
.info("Successfully updated Alarm definition: {}".format(alarm_def_uuid
))
1035 return alarm_def_uuid
1037 def delete_alarm_configuration(self
, delete_alarm_req_dict
):
1038 """Delete complete alarm configuration
1040 if delete_alarm_req_dict
['alarm_uuid'] is None:
1041 self
.logger
.info("delete_alarm_configuration: Alarm UUID not provided")
1043 #1)Get alarm & symptom definition details
1044 alarm_details_json
, alarm_details
= self
.get_alarm_defination_details(delete_alarm_req_dict
['alarm_uuid'])
1045 if alarm_details
is None or alarm_details_json
is None:
1048 #2) Delete alarm notification
1049 rule_id
= self
.delete_notification_rule(alarm_details
['alarm_name'])
1053 #3) Delete alarm configuration
1054 alarm_id
= self
.delete_alarm_defination(alarm_details
['alarm_id'])
1055 if alarm_id
is None:
1058 #4) Delete alarm symptom
1059 symptom_id
= self
.delete_symptom_definition(alarm_details
['symptom_definition_id'])
1060 if symptom_id
is None:
1063 self
.logger
.info("Completed deleting alarm configuration: {}"\
1064 .format(delete_alarm_req_dict
['alarm_uuid']))
1065 return delete_alarm_req_dict
['alarm_uuid']
1067 def delete_notification_rule(self
, alarm_name
):
1068 """Deleted notification rule defined for a particular alarm
1070 rule_id
= self
.get_notification_rule_id_by_alarm_name(alarm_name
)
1074 api_url
= '/suite-api/api/notifications/rules/'
1075 headers
= {'Accept':'application/json'}
1076 resp
= requests
.delete(self
.vrops_site
+ api_url
+ rule_id
,
1077 auth
=(self
.vrops_user
, self
.vrops_password
),
1078 verify
= False, headers
= headers
)
1079 if resp
.status_code
is not 204:
1080 self
.logger
.warn("Failed to delete notification rules for {}".format(alarm_name
))
1083 self
.logger
.info("Deleted notification rules for {}".format(alarm_name
))
1086 def get_notification_rule_id_by_alarm_name(self
, alarm_name
):
1087 """Find created Alarm notification rule id by alarm name
1089 alarm_notify_id
= 'notify_' + alarm_name
1090 api_url
= '/suite-api/api/notifications/rules'
1091 headers
= {'Content-Type': 'application/json', 'Accept':'application/json'}
1092 resp
= requests
.get(self
.vrops_site
+ api_url
,
1093 auth
=(self
.vrops_user
, self
.vrops_password
),
1094 verify
= False, headers
= headers
)
1096 if resp
.status_code
is not 200:
1097 self
.logger
.warn("Failed to get notification rules details for {}"\
1098 .format(alarm_name
))
1101 notifications
= json
.loads(resp
.content
)
1102 if notifications
is not None and notifications
.has_key('notification-rule'):
1103 notifications_list
= notifications
['notification-rule']
1104 for dict in notifications_list
:
1105 if dict['name'] is not None and dict['name'] == alarm_notify_id
:
1106 notification_id
= dict['id']
1107 self
.logger
.info("Found Notification id to be deleted: {} for {}"\
1108 .format(notification_id
, alarm_name
))
1109 return notification_id
1111 self
.logger
.warn("Notification id to be deleted not found for {}"\
1112 .format(notification_id
, alarm_name
))
1115 def delete_alarm_defination(self
, alarm_id
):
1116 """Delete created Alarm defination
1118 api_url
= '/suite-api/api/alertdefinitions/'
1119 headers
= {'Accept':'application/json'}
1120 resp
= requests
.delete(self
.vrops_site
+ api_url
+ alarm_id
,
1121 auth
=(self
.vrops_user
, self
.vrops_password
),
1122 verify
= False, headers
= headers
)
1123 if resp
.status_code
is not 204:
1124 self
.logger
.warn("Failed to delete alarm definition {}".format(alarm_id
))
1127 self
.logger
.info("Deleted alarm definition {}".format(alarm_id
))
1130 def delete_symptom_definition(self
, symptom_id
):
1131 """Delete symptom defination
1133 api_url
= '/suite-api/api/symptomdefinitions/'
1134 headers
= {'Accept':'application/json'}
1135 resp
= requests
.delete(self
.vrops_site
+ api_url
+ symptom_id
,
1136 auth
=(self
.vrops_user
, self
.vrops_password
),
1137 verify
= False, headers
= headers
)
1138 if resp
.status_code
is not 204:
1139 self
.logger
.warn("Failed to delete symptom definition {}".format(symptom_id
))
1142 self
.logger
.info("Deleted symptom definition {}".format(symptom_id
))
1146 def verify_metric_support(self
, metric_info
):
1147 """Verify, if Metric is supported by vROPs plugin, verify metric unit & return status
1149 status: True if supported, False if not supported
1152 if 'metric_name' not in metric_info
:
1153 self
.logger
.debug("Metric name not provided: {}".format(metric_info
))
1155 metric_key_params
= self
.get_default_Params(metric_info
['metric_name'])
1156 if not metric_key_params
:
1157 self
.logger
.warn("Metric not supported: {}".format(metric_info
['metric_name']))
1160 #If Metric is supported, verify optional metric unit & return status
1161 if 'metric_unit' in metric_info
:
1162 if metric_key_params
.get('unit') == metric_info
['metric_unit']:
1163 self
.logger
.info("Metric is supported with unit: {}".format(metric_info
['metric_name']))
1166 self
.logger
.debug("Metric supported but there is unit mismatch for: {}."\
1167 "Supported unit: {}"\
1168 .format(metric_info
['metric_name'],metric_key_params
['unit']))
1172 def get_triggered_alarms_list(self
, list_alarm_input
):
1173 """Get list of triggered alarms on a resource based on alarm input request.
1175 #TO Do - Need to add filtering of alarms based on Severity & alarm name
1177 triggered_alarms_list
= []
1178 if list_alarm_input
.get('resource_uuid') is None:
1179 self
.logger
.warn("Resource UUID is required to get triggered alarms list")
1180 return triggered_alarms_list
1182 #1)Find vROPs resource ID using RO resource UUID
1183 vrops_resource_id
= self
.get_vrops_resourceid_from_ro_uuid(list_alarm_input
['resource_uuid'])
1184 if vrops_resource_id
is None:
1185 return triggered_alarms_list
1187 #2)Get triggered alarms on particular resource
1188 triggered_alarms_list
= self
.get_triggered_alarms_on_resource(list_alarm_input
['resource_uuid'], vrops_resource_id
)
1189 return triggered_alarms_list
1191 def get_vrops_resourceid_from_ro_uuid(self
, ro_resource_uuid
):
1192 """Fetch vROPs resource ID using resource UUID from RO/SO
1194 #1) Find vm_moref_id from vApp uuid in vCD
1195 vm_moref_id
= self
.get_vm_moref_id(ro_resource_uuid
)
1196 if vm_moref_id
is None:
1197 self
.logger
.warn("Failed to find vm morefid for vApp in vCD: {}".format(ro_resource_uuid
))
1200 #2) Based on vm_moref_id, find VM's corresponding resource_id in vROPs to set notification
1201 vrops_resource_id
= self
.get_vm_resource_id(vm_moref_id
)
1202 if vrops_resource_id
is None:
1203 self
.logger
.warn("Failed to find resource in vROPs: {}".format(ro_resource_uuid
))
1205 return vrops_resource_id
1208 def get_triggered_alarms_on_resource(self
, ro_resource_uuid
, vrops_resource_id
):
1209 """Get triggered alarms on particular resource & return list of dictionary of alarms
1211 resource_alarms
= []
1212 api_url
= '/suite-api/api/alerts?resourceId='
1213 headers
= {'Accept':'application/json'}
1214 resp
= requests
.get(self
.vrops_site
+ api_url
+ vrops_resource_id
,
1215 auth
=(self
.vrops_user
, self
.vrops_password
),
1216 verify
= False, headers
= headers
)
1218 if resp
.status_code
is not 200:
1219 self
.logger
.warn("Failed to get triggered alarms for {}"\
1220 .format(ro_resource_uuid
))
1223 all_alerts
= json
.loads(resp
.content
)
1224 if all_alerts
.has_key('alerts'):
1225 if not all_alerts
['alerts']:
1226 self
.logger
.info("No alarms present on resource {}".format(ro_resource_uuid
))
1227 return resource_alarms
1228 all_alerts_list
= all_alerts
['alerts']
1229 for alarm
in all_alerts_list
:
1230 #self.logger.info("Triggered Alarm {}".format(alarm))
1231 if alarm
['alertDefinitionName'] is not None and\
1232 len(alarm
['alertDefinitionName'].split('-', 1)) == 2:
1233 if alarm
['alertDefinitionName'].split('-', 1)[1] == ro_resource_uuid
:
1235 alarm_instance
['alarm_uuid'] = alarm
['alertDefinitionId'].split('-', 1)[1]
1236 alarm_instance
['resource_uuid'] = ro_resource_uuid
1237 alarm_instance
['alarm_instance_uuid'] = alarm
['alertId']
1238 alarm_instance
['vim_type'] = 'VMware'
1239 #find severity of alarm
1241 for key
,value
in severity_mano2vrops
.iteritems():
1242 if value
== alarm
['alertLevel']:
1244 if severity
is None:
1245 severity
= 'INDETERMINATE'
1246 alarm_instance
['severity'] = severity
1247 alarm_instance
['status'] = alarm
['status']
1248 alarm_instance
['start_date'] = self
.convert_date_time(alarm
['startTimeUTC'])
1249 alarm_instance
['update_date'] = self
.convert_date_time(alarm
['updateTimeUTC'])
1250 alarm_instance
['cancel_date'] = self
.convert_date_time(alarm
['cancelTimeUTC'])
1251 self
.logger
.info("Triggered Alarm on resource {}".format(alarm_instance
))
1252 resource_alarms
.append(alarm_instance
)
1253 if not resource_alarms
:
1254 self
.logger
.info("No alarms present on resource {}".format(ro_resource_uuid
))
1255 return resource_alarms
1257 def convert_date_time(self
, date_time
):
1258 """Convert the input UTC time in msec to OSM date time format
1260 date_time_formatted
= '0000-00-00T00:00:00'
1262 complete_datetime
= datetime
.datetime
.fromtimestamp(date_time
/1000.0).isoformat('T')
1263 date_time_formatted
= complete_datetime
.split('.',1)[0]
1264 return date_time_formatted