bd76c81847b020beefa4c175f48391688bd2baf5
[osm/MON.git] / 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 sys
28 import os
29 import re
30 import datetime
31 import random
32 import json
33 import logging as log
34 from random import randint
35 from operator import itemgetter
36 from connection import Connection
37
38
39 try:
40 import boto
41 import boto.ec2
42 import boto.vpc
43 import boto.ec2.cloudwatch
44 import boto.ec2.connection
45 except:
46 exit("Boto not avialable. Try activating your virtualenv OR `pip install boto`")
47
48
49 class MetricAlarm():
50 """Alarms Functionality Handler -- Carries out alarming requests and responses via BOTO.Cloudwatch """
51 def __init__(self):
52 self.alarm_resp = dict()
53 self.del_resp = dict()
54
55 def config_alarm(self,cloudwatch_conn,create_info):
56 """Configure or Create a new alarm"""
57 inner_dict = dict()
58 """ Alarm Name to ID Mapping """
59 alarm_info = create_info['alarm_create_request']
60 alarm_id = alarm_info['alarm_name'] + "_" + alarm_info['resource_uuid']
61 if self.is_present(cloudwatch_conn,alarm_id)['status'] == True:
62 alarm_id = None
63 log.debug ("Alarm already exists, Try updating the alarm using 'update_alarm_configuration()'")
64 else:
65 try:
66 alarm = boto.ec2.cloudwatch.alarm.MetricAlarm(
67 connection = cloudwatch_conn,
68 name = alarm_info['alarm_name'] + "_" + alarm_info['resource_uuid'],
69 metric = alarm_info['metric_name'],
70 namespace = "AWS/EC2",
71 statistic = alarm_info['statistic'],
72 comparison = alarm_info['operation'],
73 threshold = alarm_info['threshold_value'],
74 period = 60,
75 evaluation_periods = 1,
76 unit=alarm_info['unit'],
77 description = alarm_info['severity'] + ";" + alarm_id + ";" + alarm_info['description'],
78 dimensions = {'InstanceId':alarm_info['resource_uuid']},
79 alarm_actions = None,
80 ok_actions = None,
81 insufficient_data_actions = None)
82
83 """Setting Alarm Actions :
84 alarm_actions = ['arn:aws:swf:us-west-2:465479087178:action/actions/AWS_EC2.InstanceId.Stop/1.0']"""
85
86 status=cloudwatch_conn.put_metric_alarm(alarm)
87
88 log.debug ("Alarm Configured Succesfully")
89 self.alarm_resp['schema_version'] = str(create_info['schema_version'])
90 self.alarm_resp['schema_type'] = 'create_alarm_response'
91
92 inner_dict['correlation_id'] = str(alarm_info['correlation_id'])
93 inner_dict['alarm_uuid'] = str(alarm_id)
94 inner_dict['status'] = status
95
96 self.alarm_resp['alarm_create_response'] = inner_dict
97 if status == True:
98 return self.alarm_resp
99 else:
100 return None
101
102 except Exception as e:
103 log.error("Alarm Configuration Failed: " + str(e))
104
105 #-----------------------------------------------------------------------------------------------------------------------------
106 def update_alarm(self,cloudwatch_conn,update_info):
107
108 """Update or reconfigure an alarm"""
109 inner_dict = dict()
110 alarm_info = update_info['alarm_update_request']
111
112 """Alarm Name to ID Mapping"""
113 alarm_id = alarm_info['alarm_uuid']
114 status = self.is_present(cloudwatch_conn,alarm_id)
115
116 """Verifying : Alarm exists already"""
117 if status['status'] == False:
118 alarm_id = None
119 log.debug("Alarm not found, Try creating the alarm using 'configure_alarm()'")
120 return alarm_id
121 else:
122 try:
123 alarm = boto.ec2.cloudwatch.alarm.MetricAlarm(
124 connection = cloudwatch_conn,
125 name = status['info'].name ,
126 metric = alarm_info['metric_name'],
127 namespace = "AWS/EC2",
128 statistic = alarm_info['statistic'],
129 comparison = alarm_info['operation'],
130 threshold = alarm_info['threshold_value'],
131 period = 60,
132 evaluation_periods = 1,
133 unit=alarm_info['unit'],
134 description = alarm_info['severity'] + ";" + alarm_id + ";" + alarm_info['description'],
135 dimensions = {'InstanceId':str(status['info'].dimensions['InstanceId']).split("'")[1]},
136 alarm_actions = None,
137 ok_actions = None,
138 insufficient_data_actions = None)
139
140 """Setting Alarm Actions :
141 alarm_actions = ['arn:aws:swf:us-west-2:465479087178:action/actions/AWS_EC2.InstanceId.Stop/1.0']"""
142
143 status=cloudwatch_conn.put_metric_alarm(alarm)
144 log.debug("Alarm %s Updated ",alarm.name)
145 self.alarm_resp['schema_version'] = str(update_info['schema_version'])
146 self.alarm_resp['schema_type'] = 'update_alarm_response'
147
148 inner_dict['correlation_id'] = str(alarm_info['correlation_id'])
149 inner_dict['alarm_uuid'] = str(alarm_id)
150 inner_dict['status'] = status
151
152 self.alarm_resp['alarm_update_response'] = inner_dict
153 return self.alarm_resp
154 except Exception as e:
155 log.error ("Error in Updating Alarm " + str(e))
156
157 #-----------------------------------------------------------------------------------------------------------------------------
158 def delete_Alarm(self,cloudwatch_conn,del_info_all):
159
160 """Deletes an Alarm with specified alarm_id"""
161 inner_dict = dict()
162 del_info = del_info_all['alarm_delete_request']
163 status = self.is_present(cloudwatch_conn,del_info['alarm_uuid'])
164 try:
165 if status['status'] == True:
166 del_status=cloudwatch_conn.delete_alarms(status['info'].name)
167 self.del_resp['schema_version'] = str(del_info_all['schema_version'])
168 self.del_resp['schema_type'] = 'delete_alarm_response'
169 inner_dict['correlation_id'] = str(del_info['correlation_id'])
170 inner_dict['alarm_id'] = str(del_info['alarm_uuid'])
171 inner_dict['status'] = del_status
172 self.del_resp['alarm_deletion_response'] = inner_dict
173 return self.del_resp
174 return None
175 except Exception as e:
176 log.error("Alarm Not Deleted: " + str(e))
177 #-----------------------------------------------------------------------------------------------------------------------------
178 def alarms_list(self,cloudwatch_conn,list_info):
179
180 """Get a list of alarms that are present on a particular VIM type"""
181 alarm_list = []
182 alarm_info = dict()
183 try: #id vim
184 alarms = cloudwatch_conn.describe_alarms()
185 itr = 0
186 for alarm in alarms:
187 list_info['alarm_list_request']['alarm_uuid'] = str(alarm.description).split(';')[1]
188 alarm_list.insert(itr,self.alarm_details(cloudwatch_conn,list_info))
189 itr += 1
190
191 alarm_info['schema_version'] = str(list_info['schema_version'])
192 alarm_info['schema_type'] = 'list_alarm_response'
193 alarm_info['list_alarm_resp'] = json.dumps(alarm_list)
194
195 return alarm_info
196 except Exception as e:
197 log.error("Error in Getting List : %s",str(e))
198 #-----------------------------------------------------------------------------------------------------------------------------
199 def alarm_details(self,cloudwatch_conn,ack_info):
200
201 """Get an individual alarm details specified by alarm_name"""
202 try:
203 alarms_details=cloudwatch_conn.describe_alarm_history()
204 alarm_details_all = dict()
205 alarm_details_dict = dict()
206 ack_info_all = ack_info
207
208
209 if 'ack_details' in ack_info:
210 ack_info = ack_info['ack_details']
211 elif 'alarm_list_request' in ack_info:
212 ack_info = ack_info['alarm_list_request']
213
214 is_present = self.is_present(cloudwatch_conn,ack_info['alarm_uuid'])
215
216 for itr in range (len(alarms_details)):
217 if alarms_details[itr].name == is_present['info'].name :#name, timestamp, summary
218 if 'created' in alarms_details[itr].summary:
219 alarm_details_dict['status'] = "New"
220 elif 'updated' in alarms_details[itr].summary:
221 alarm_details_dict['status'] = "Update"
222 elif 'deleted' in alarms_details[itr].summary:
223 alarm_details_dict['status'] = "Canceled"
224
225 status = alarms_details[itr].summary.split()
226 alarms = cloudwatch_conn.describe_alarms()
227 for alarm in alarms:
228 if str(alarm.description).split(';')[1] == ack_info['alarm_uuid']:
229 alarm_details_dict['alarm_uuid'] = str(ack_info['alarm_uuid'])
230 alarm_details_dict['resource_uuid'] = str(alarm.dimensions['InstanceId']).split("'")[1]
231 alarm_details_dict['description'] = str(alarm.description).split(';')[1]
232 alarm_details_dict['severity'] = str(alarm.description).split(';')[0]
233 alarm_details_dict['start_date_time'] = str(alarms_details[itr].timestamp)
234 alarm_details_dict['vim_type'] = str(ack_info_all['vim_type'])
235 #TODO : tenant id
236 if 'ack_details' in ack_info_all:
237 alarm_details_all['schema_version'] = str(ack_info_all['schema_version'])
238 alarm_details_all['schema_type'] = 'notify_alarm'
239 alarm_details_all['notify_details'] = alarm_details_dict
240 return alarm_details_all
241
242 elif 'alarm_list_request' in ack_info_all:
243 return alarm_details_dict
244
245 except Exception as e:
246 log.error("Error getting alarm details: %s",str(e))
247 #-----------------------------------------------------------------------------------------------------------------------------
248 def is_present(self,cloudwatch_conn,alarm_id):
249 """Finding alarm from already configured alarms"""
250 alarm_info = dict()
251 try:
252 alarms = cloudwatch_conn.describe_alarms()
253 for alarm in alarms:
254 if str(alarm.description).split(';')[1] == alarm_id:
255 alarm_info['status'] = True
256 alarm_info['info'] = alarm
257 return alarm_info
258 alarm_info['status'] = False
259 return alarm_info
260 except Exception as e:
261 log.error("Error Finding Alarm",str(e))
262 #-----------------------------------------------------------------------------------------------------------------------------
263