8e5b6fe85180b7683a131f02c3e4cce6e7846fdc
[osm/MON.git] / osm_mon / plugins / CloudWatch / metric_alarms.py
1 ##
2 # Copyright 2017 xFlow Research Pvt. Ltd
3 # This file is part of MON module
4 # All Rights Reserved.
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License"); you may
7 # not use this file except in compliance with the License. You may obtain
8 # a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15 # License for the specific language governing permissions and limitations
16 # under the License.
17 #
18 # For those usages not covered by the Apache License, Version 2.0 please
19 # contact with: wajeeha.hamid@xflowresearch.com
20 ##
21
22 ''' Handling of alarms requests via BOTO 2.48 '''
23
24 __author__ = "Wajeeha Hamid"
25 __date__ = "18-September-2017"
26
27 import logging
28
29 log = logging.getLogger(__name__)
30
31 try:
32 import boto
33 import boto.ec2
34 import boto.vpc
35 import boto.ec2.cloudwatch
36 import boto.ec2.connection
37 except:
38 exit("Boto not avialable. Try activating your virtualenv OR `pip install boto`")
39
40 STATISTICS = {
41 "AVERAGE": "Average",
42 "MINIMUM": "Minimum",
43 "MAXIMUM": "Maximum",
44 "COUNT" : "SampleCount",
45 "SUM" : "Sum"}
46
47 OPERATIONS = {
48 "GE" : ">=",
49 "LE" : "<=",
50 "GT" : ">",
51 "LT" : "<",
52 "EQ" : "="}
53
54 class MetricAlarm():
55 """Alarms Functionality Handler -- Carries out alarming requests and responses via BOTO.Cloudwatch """
56 def __init__(self):
57 self.alarm_resp = dict()
58 self.del_resp = dict()
59
60 def config_alarm(self,cloudwatch_conn,create_info):
61 """Configure or Create a new alarm"""
62 inner_dict = dict()
63 """ Alarm Name to ID Mapping """
64 alarm_info = create_info['alarm_create_request']
65 alarm_id = alarm_info['alarm_name'] + "_" + alarm_info['resource_uuid']
66 if self.is_present(cloudwatch_conn,alarm_id)['status'] == True:
67 alarm_id = None
68 log.debug ("Alarm already exists, Try updating the alarm using 'update_alarm_configuration()'")
69 return alarm_id
70 else:
71 try:
72 if alarm_info['statistic'] in STATISTICS:
73 if alarm_info['operation'] in OPERATIONS:
74 alarm = boto.ec2.cloudwatch.alarm.MetricAlarm(
75 connection = cloudwatch_conn,
76 name = alarm_info['alarm_name'] + "_" + alarm_info['resource_uuid'],
77 metric = alarm_info['metric_name'],
78 namespace = "AWS/EC2",
79 statistic = STATISTICS[alarm_info['statistic']],
80 comparison = OPERATIONS[alarm_info['operation']],
81 threshold = alarm_info['threshold_value'],
82 period = 60,
83 evaluation_periods = 1,
84 unit=alarm_info['unit'],
85 description = alarm_info['severity'] + ";" + alarm_id + ";" + alarm_info['description'],
86 dimensions = {'InstanceId':alarm_info['resource_uuid']},
87 alarm_actions = None,
88 ok_actions = None,
89 insufficient_data_actions = None)
90
91 """Setting Alarm Actions :
92 alarm_actions = ['arn:aws:swf:us-west-2:465479087178:action/actions/AWS_EC2.InstanceId.Stop/1.0']"""
93
94 status=cloudwatch_conn.put_metric_alarm(alarm)
95
96 log.debug ("Alarm Configured Succesfully")
97 self.alarm_resp['schema_version'] = str(create_info['schema_version'])
98 self.alarm_resp['schema_type'] = 'create_alarm_response'
99
100 inner_dict['correlation_id'] = str(alarm_info['correlation_id'])
101 inner_dict['alarm_uuid'] = str(alarm_id)
102 inner_dict['status'] = status
103
104 self.alarm_resp['alarm_create_response'] = inner_dict
105
106 if status == True:
107 return self.alarm_resp
108 else:
109 return None
110 else:
111 log.error("Operation not supported")
112 return None
113 else:
114 log.error("Statistic not supported")
115 return None
116 except Exception as e:
117 log.error("Alarm Configuration Failed: " + str(e))
118
119 #-----------------------------------------------------------------------------------------------------------------------------
120 def update_alarm(self,cloudwatch_conn,update_info):
121
122 """Update or reconfigure an alarm"""
123 inner_dict = dict()
124 alarm_info = update_info['alarm_update_request']
125
126 """Alarm Name to ID Mapping"""
127 alarm_id = alarm_info['alarm_uuid']
128 status = self.is_present(cloudwatch_conn,alarm_id)
129
130 """Verifying : Alarm exists already"""
131 if status['status'] == False:
132 alarm_id = None
133 log.debug("Alarm not found, Try creating the alarm using 'configure_alarm()'")
134 return alarm_id
135 else:
136 try:
137 if alarm_info['statistic'] in STATISTICS:
138 if alarm_info['operation'] in OPERATIONS:
139 alarm = boto.ec2.cloudwatch.alarm.MetricAlarm(
140 connection = cloudwatch_conn,
141 name = status['info'].name ,
142 metric = alarm_info['metric_name'],
143 namespace = "AWS/EC2",
144 statistic = STATISTICS[alarm_info['statistic']],
145 comparison = OPERATIONS[alarm_info['operation']],
146 threshold = alarm_info['threshold_value'],
147 period = 60,
148 evaluation_periods = 1,
149 unit=alarm_info['unit'],
150 description = alarm_info['severity'] + ";" + alarm_id + ";" + alarm_info['description'],
151 dimensions = {'InstanceId':str(status['info'].dimensions['InstanceId']).split("'")[1]},
152 alarm_actions = None,
153 ok_actions = None,
154 insufficient_data_actions = None)
155
156 """Setting Alarm Actions :
157 alarm_actions = ['arn:aws:swf:us-west-2:465479087178:action/actions/AWS_EC2.InstanceId.Stop/1.0']"""
158
159 status=cloudwatch_conn.put_metric_alarm(alarm)
160 log.debug("Alarm %s Updated ",alarm.name)
161 self.alarm_resp['schema_version'] = str(update_info['schema_version'])
162 self.alarm_resp['schema_type'] = 'update_alarm_response'
163
164 inner_dict['correlation_id'] = str(alarm_info['correlation_id'])
165 inner_dict['alarm_uuid'] = str(alarm_id)
166 inner_dict['status'] = status
167
168 self.alarm_resp['alarm_update_response'] = inner_dict
169 return self.alarm_resp
170 else:
171 log.error("Operation not supported")
172 return None
173 else:
174 log.error("Statistic not supported")
175 return None
176 except Exception as e:
177 log.error ("Error in Updating Alarm " + str(e))
178
179 #-----------------------------------------------------------------------------------------------------------------------------
180 def delete_Alarm(self,cloudwatch_conn,del_info_all):
181
182 """Deletes an Alarm with specified alarm_id"""
183 inner_dict = dict()
184 del_info = del_info_all['alarm_delete_request']
185 status = self.is_present(cloudwatch_conn,del_info['alarm_uuid'])
186 try:
187 if status['status'] == True:
188 del_status=cloudwatch_conn.delete_alarms(status['info'].name)
189 self.del_resp['schema_version'] = str(del_info_all['schema_version'])
190 self.del_resp['schema_type'] = 'delete_alarm_response'
191 inner_dict['correlation_id'] = str(del_info['correlation_id'])
192 inner_dict['alarm_id'] = str(del_info['alarm_uuid'])
193 inner_dict['status'] = del_status
194 self.del_resp['alarm_deletion_response'] = inner_dict
195 return self.del_resp
196 return None
197 except Exception as e:
198 log.error("Alarm Not Deleted: " + str(e))
199 #-----------------------------------------------------------------------------------------------------------------------------
200 def alarms_list(self,cloudwatch_conn,list_info):
201
202 """Get a list of alarms that are present on a particular VIM type"""
203 alarm_list = []
204 alarm_info = dict()
205 inner_dict = list_info['alarm_list_request']
206 try: #id vim
207 alarms = cloudwatch_conn.describe_alarms()
208 itr = 0
209 for alarm in alarms:
210 list_info['alarm_list_request']['alarm_uuid'] = str(alarm.description).split(';')[1]
211
212 #Severity = alarm_name = resource_uuid = ""
213 if inner_dict['severity'] == "" and inner_dict['alarm_name'] == "" and inner_dict['resource_uuid'] == "":
214 alarm_list.insert(itr,self.alarm_details(cloudwatch_conn,list_info))
215 itr += 1
216 #alarm_name = resource_uuid = ""
217 if inner_dict['severity'] == str(alarm.description).split(';')[0] and inner_dict['alarm_name'] == "" and inner_dict['resource_uuid'] == "":
218 alarm_list.insert(itr,self.alarm_details(cloudwatch_conn,list_info))
219 itr += 1
220 #severity = resource_uuid = ""
221 if inner_dict['severity'] == "" and inner_dict['alarm_name'] in alarm.name and inner_dict['resource_uuid'] == "":
222 alarm_list.insert(itr,self.alarm_details(cloudwatch_conn,list_info))
223 itr += 1
224 #severity = alarm_name = ""
225 if inner_dict['severity'] == "" and inner_dict['alarm_name'] == "" and inner_dict['resource_uuid'] == str(alarm.dimensions['InstanceId']).split("'")[1]:
226 alarm_list.insert(itr,self.alarm_details(cloudwatch_conn,list_info))
227 itr += 1
228 #resource_uuid = ""
229 if inner_dict['severity'] == str(alarm.description).split(';')[0] and inner_dict['alarm_name'] in alarm.name and inner_dict['resource_uuid'] == "":
230 alarm_list.insert(itr,self.alarm_details(cloudwatch_conn,list_info))
231 itr += 1
232 #alarm_name = ""
233 if inner_dict['severity'] == str(alarm.description).split(';')[0] and inner_dict['alarm_name'] == "" and inner_dict['resource_uuid'] == str(alarm.dimensions['InstanceId']).split("'")[1]:
234 alarm_list.insert(itr,self.alarm_details(cloudwatch_conn,list_info))
235 itr += 1
236 #severity = ""
237 if inner_dict['severity'] == "" and inner_dict['alarm_name'] in alarm.name and inner_dict['resource_uuid'] == str(alarm.dimensions['InstanceId']).split("'")[1]:
238 alarm_list.insert(itr,self.alarm_details(cloudwatch_conn,list_info))
239 itr += 1
240 #Everything provided
241 if inner_dict['severity'] == str(alarm.description).split(';')[0] and inner_dict['alarm_name'] in alarm.name and inner_dict['resource_uuid'] == str(alarm.dimensions['InstanceId']).split("'")[1]:
242 alarm_list.insert(itr,self.alarm_details(cloudwatch_conn,list_info))
243 itr += 1
244
245 alarm_info['schema_version'] = str(list_info['schema_version'])
246 alarm_info['schema_type'] = 'list_alarm_response'
247 alarm_info['list_alarm_response'] = alarm_list
248
249 return alarm_info
250 except Exception as e:
251 log.error("Error in Getting List : %s",str(e))
252 #-----------------------------------------------------------------------------------------------------------------------------
253 def alarm_details(self,cloudwatch_conn,ack_info):
254
255 """Get an individual alarm details specified by alarm_name"""
256 try:
257 alarms_details=cloudwatch_conn.describe_alarm_history()
258 alarm_details_all = dict()
259 alarm_details_dict = dict()
260 ack_info_all = ack_info
261
262
263 if 'ack_details' in ack_info:
264 ack_info = ack_info['ack_details']
265 elif 'alarm_list_request' in ack_info:
266 ack_info = ack_info['alarm_list_request']
267
268 is_present = self.is_present(cloudwatch_conn,ack_info['alarm_uuid'])
269
270 for itr in range (len(alarms_details)):
271 if alarms_details[itr].name == is_present['info'].name :#name, timestamp, summary
272 if 'created' in alarms_details[itr].summary:
273 alarm_details_dict['status'] = "New"
274 elif 'updated' in alarms_details[itr].summary:
275 alarm_details_dict['status'] = "Update"
276 elif 'deleted' in alarms_details[itr].summary:
277 alarm_details_dict['status'] = "Canceled"
278
279 status = alarms_details[itr].summary.split()
280 alarms = cloudwatch_conn.describe_alarms()
281 for alarm in alarms:
282 if str(alarm.description).split(';')[1] == ack_info['alarm_uuid']:
283 alarm_details_dict['alarm_uuid'] = str(ack_info['alarm_uuid'])
284 alarm_details_dict['resource_uuid'] = str(alarm.dimensions['InstanceId']).split("'")[1]
285 alarm_details_dict['description'] = str(alarm.description).split(';')[1]
286 alarm_details_dict['severity'] = str(alarm.description).split(';')[0]
287 alarm_details_dict['start_date_time'] = str(alarms_details[itr].timestamp)
288 alarm_details_dict['vim_type'] = str(ack_info_all['vim_type'])
289 #TODO : tenant id
290 if 'ack_details' in ack_info_all:
291 alarm_details_all['schema_version'] = str(ack_info_all['schema_version'])
292 alarm_details_all['schema_type'] = 'notify_alarm'
293 alarm_details_all['notify_details'] = alarm_details_dict
294 return alarm_details_all
295
296 elif 'alarm_list_request' in ack_info_all:
297 return alarm_details_dict
298
299 except Exception as e:
300 log.error("Error getting alarm details: %s",str(e))
301 #-----------------------------------------------------------------------------------------------------------------------------
302 def is_present(self,cloudwatch_conn,alarm_id):
303 """Finding alarm from already configured alarms"""
304 alarm_info = dict()
305 try:
306 alarms = cloudwatch_conn.describe_alarms()
307 for alarm in alarms:
308 if str(alarm.description).split(';')[1] == alarm_id:
309 alarm_info['status'] = True
310 alarm_info['info'] = alarm
311 return alarm_info
312 alarm_info['status'] = False
313 return alarm_info
314 except Exception as e:
315 log.error("Error Finding Alarm",str(e))
316 #-----------------------------------------------------------------------------------------------------------------------------
317