| OLD | NEW |
| 1 # Copyright (c) 2010 Reza Lotun http://reza.lotun.name | 1 # Copyright (c) 2010 Reza Lotun http://reza.lotun.name |
| 2 # | 2 # |
| 3 # Permission is hereby granted, free of charge, to any person obtaining a | 3 # Permission is hereby granted, free of charge, to any person obtaining a |
| 4 # copy of this software and associated documentation files (the | 4 # copy of this software and associated documentation files (the |
| 5 # "Software"), to deal in the Software without restriction, including | 5 # "Software"), to deal in the Software without restriction, including |
| 6 # without limitation the rights to use, copy, modify, merge, publish, dis- | 6 # without limitation the rights to use, copy, modify, merge, publish, dis- |
| 7 # tribute, sublicense, and/or sell copies of the Software, and to permit | 7 # tribute, sublicense, and/or sell copies of the Software, and to permit |
| 8 # persons to whom the Software is furnished to do so, subject to the fol- | 8 # persons to whom the Software is furnished to do so, subject to the fol- |
| 9 # lowing conditions: | 9 # lowing conditions: |
| 10 # | 10 # |
| 11 # The above copyright notice and this permission notice shall be included | 11 # The above copyright notice and this permission notice shall be included |
| 12 # in all copies or substantial portions of the Software. | 12 # in all copies or substantial portions of the Software. |
| 13 # | 13 # |
| 14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | 14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| 15 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- | 15 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- |
| 16 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT | 16 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT |
| 17 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | 17 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| 18 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | 18 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | 19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| 20 # IN THE SOFTWARE. | 20 # IN THE SOFTWARE. |
| 21 # | 21 # |
| 22 | 22 |
| 23 from datetime import datetime | 23 from datetime import datetime |
| 24 import json | 24 from boto.resultset import ResultSet |
| 25 | 25 from boto.ec2.cloudwatch.listelement import ListElement |
| 26 try: |
| 27 import simplejson as json |
| 28 except ImportError: |
| 29 import json |
| 26 | 30 |
| 27 class MetricAlarm(object): | 31 class MetricAlarm(object): |
| 28 | 32 |
| 29 OK = 'OK' | 33 OK = 'OK' |
| 30 ALARM = 'ALARM' | 34 ALARM = 'ALARM' |
| 31 INSUFFICIENT_DATA = 'INSUFFICIENT_DATA' | 35 INSUFFICIENT_DATA = 'INSUFFICIENT_DATA' |
| 32 | 36 |
| 33 _cmp_map = { | 37 _cmp_map = { |
| 34 '>=' : 'GreaterThanOrEqualToThreshold', | 38 '>=' : 'GreaterThanOrEqualToThreshold', |
| 35 '>' : 'GreaterThanThreshold', | 39 '>' : 'GreaterThanThreshold', |
| 36 '<' : 'LessThanThreshold', | 40 '<' : 'LessThanThreshold', |
| 37 '<=' : 'LessThanOrEqualToThreshold', | 41 '<=' : 'LessThanOrEqualToThreshold', |
| 38 } | 42 } |
| 39 _rev_cmp_map = dict((v, k) for (k, v) in _cmp_map.iteritems()) | 43 _rev_cmp_map = dict((v, k) for (k, v) in _cmp_map.iteritems()) |
| 40 | 44 |
| 41 def __init__(self, connection=None, name=None, metric=None, | 45 def __init__(self, connection=None, name=None, metric=None, |
| 42 namespace=None, statistic=None, comparison=None, threshold=None
, | 46 namespace=None, statistic=None, comparison=None, |
| 43 period=None, evaluation_periods=None): | 47 threshold=None, period=None, evaluation_periods=None, |
| 48 unit=None, description='', dimensions=None, |
| 49 alarm_actions=None, insufficient_data_actions=None, |
| 50 ok_actions=None): |
| 44 """ | 51 """ |
| 45 Creates a new Alarm. | 52 Creates a new Alarm. |
| 46 | 53 |
| 47 :type name: str | 54 :type name: str |
| 48 :param name: Name of alarm. | 55 :param name: Name of alarm. |
| 49 | 56 |
| 50 :type metric: str | 57 :type metric: str |
| 51 :param metric: Name of alarm's associated metric. | 58 :param metric: Name of alarm's associated metric. |
| 52 | 59 |
| 53 :type namespace: str | 60 :type namespace: str |
| 54 :param namespace: The namespace for the alarm's metric. | 61 :param namespace: The namespace for the alarm's metric. |
| 55 | 62 |
| 56 :type statistic: str | 63 :type statistic: str |
| 57 :param statistic: The statistic to apply to the alarm's associated metri
c. Can | 64 :param statistic: The statistic to apply to the alarm's associated |
| 58 be one of 'SampleCount', 'Average', 'Sum', 'Minimum',
'Maximum' | 65 metric. |
| 66 Valid values: SampleCount|Average|Sum|Minimum|Maximum |
| 59 | 67 |
| 60 :type comparison: str | 68 :type comparison: str |
| 61 :param comparison: Comparison used to compare statistic with threshold.
Can be | 69 :param comparison: Comparison used to compare statistic with threshold. |
| 62 one of '>=', '>', '<', '<=' | 70 Valid values: >= | > | < | <= |
| 63 | 71 |
| 64 :type threshold: float | 72 :type threshold: float |
| 65 :param threshold: The value against which the specified statistic is com
pared. | 73 :param threshold: The value against which the specified statistic |
| 74 is compared. |
| 66 | 75 |
| 67 :type period: int | 76 :type period: int |
| 68 :param period: The period in seconds over which teh specified statistic
is applied. | 77 :param period: The period in seconds over which teh specified |
| 78 statistic is applied. |
| 69 | 79 |
| 70 :type evaluation_periods: int | 80 :type evaluation_periods: int |
| 71 :param evaluation_period: The number of periods over which data is compa
red to | 81 :param evaluation_period: The number of periods over which data is |
| 72 the specified threshold | 82 compared to the specified threshold. |
| 83 |
| 84 :type unit: str |
| 85 :param unit: Allowed Values are: |
| 86 Seconds|Microseconds|Milliseconds, |
| 87 Bytes|Kilobytes|Megabytes|Gigabytes|Terabytes, |
| 88 Bits|Kilobits|Megabits|Gigabits|Terabits, |
| 89 Percent|Count| |
| 90 Bytes/Second|Kilobytes/Second|Megabytes/Second| |
| 91 Gigabytes/Second|Terabytes/Second, |
| 92 Bits/Second|Kilobits/Second|Megabits/Second, |
| 93 Gigabits/Second|Terabits/Second|Count/Second|None |
| 94 |
| 95 :type description: str |
| 96 :param description: Description of MetricAlarm |
| 97 |
| 98 :type dimensions: list of dicts |
| 99 :param description: Dimensions of alarm, such as: |
| 100 [{'InstanceId':['i-0123456,i-0123457']}] |
| 101 |
| 102 :type alarm_actions: list of strs |
| 103 :param alarm_actions: A list of the ARNs of the actions to take in |
| 104 ALARM state |
| 105 |
| 106 :type insufficient_data_actions: list of strs |
| 107 :param insufficient_data_actions: A list of the ARNs of the actions to |
| 108 take in INSUFFICIENT_DATA state |
| 109 |
| 110 :type ok_actions: list of strs |
| 111 :param ok_actions: A list of the ARNs of the actions to take in OK state |
| 73 """ | 112 """ |
| 74 self.name = name | 113 self.name = name |
| 75 self.connection = connection | 114 self.connection = connection |
| 76 self.metric = metric | 115 self.metric = metric |
| 77 self.namespace = namespace | 116 self.namespace = namespace |
| 78 self.statistic = statistic | 117 self.statistic = statistic |
| 79 self.threshold = float(threshold) if threshold is not None else None | 118 if threshold is not None: |
| 119 self.threshold = float(threshold) |
| 120 else: |
| 121 self.threshold = None |
| 80 self.comparison = self._cmp_map.get(comparison) | 122 self.comparison = self._cmp_map.get(comparison) |
| 81 self.period = int(period) if period is not None else None | 123 if period is not None: |
| 82 self.evaluation_periods = int(evaluation_periods) if evaluation_periods
is not None else None | 124 self.period = int(period) |
| 125 else: |
| 126 self.period = None |
| 127 if evaluation_periods is not None: |
| 128 self.evaluation_periods = int(evaluation_periods) |
| 129 else: |
| 130 self.evaluation_periods = None |
| 83 self.actions_enabled = None | 131 self.actions_enabled = None |
| 84 self.alarm_actions = [] | |
| 85 self.alarm_arn = None | 132 self.alarm_arn = None |
| 86 self.last_updated = None | 133 self.last_updated = None |
| 87 self.description = '' | 134 self.description = description |
| 88 self.dimensions = [] | 135 self.dimensions = dimensions |
| 89 self.insufficient_data_actions = [] | |
| 90 self.ok_actions = [] | |
| 91 self.state_reason = None | 136 self.state_reason = None |
| 92 self.state_value = None | 137 self.state_value = None |
| 93 self.unit = None | 138 self.unit = unit |
| 139 self.alarm_actions = alarm_actions |
| 140 self.insufficient_data_actions = insufficient_data_actions |
| 141 self.ok_actions = ok_actions |
| 94 | 142 |
| 95 def __repr__(self): | 143 def __repr__(self): |
| 96 return 'MetricAlarm:%s[%s(%s) %s %s]' % (self.name, self.metric, self.st
atistic, self.comparison, self.threshold) | 144 return 'MetricAlarm:%s[%s(%s) %s %s]' % (self.name, self.metric, |
| 145 self.statistic, |
| 146 self.comparison, |
| 147 self.threshold) |
| 97 | 148 |
| 98 def startElement(self, name, attrs, connection): | 149 def startElement(self, name, attrs, connection): |
| 99 return | 150 if name == 'AlarmActions': |
| 151 self.alarm_actions = ListElement() |
| 152 return self.alarm_actions |
| 153 elif name == 'InsufficientDataActions': |
| 154 self.insufficient_data_actions = ListElement() |
| 155 return self.insufficient_data_actions |
| 156 elif name == 'OKActions': |
| 157 self.ok_actions = ListElement() |
| 158 return self.ok_actions |
| 159 else: |
| 160 pass |
| 100 | 161 |
| 101 def endElement(self, name, value, connection): | 162 def endElement(self, name, value, connection): |
| 102 if name == 'ActionsEnabled': | 163 if name == 'ActionsEnabled': |
| 103 self.actions_enabled = value | 164 self.actions_enabled = value |
| 104 elif name == 'AlarmArn': | 165 elif name == 'AlarmArn': |
| 105 self.alarm_arn = value | 166 self.alarm_arn = value |
| 106 elif name == 'AlarmConfigurationUpdatedTimestamp': | 167 elif name == 'AlarmConfigurationUpdatedTimestamp': |
| 107 self.last_updated = value | 168 self.last_updated = value |
| 108 elif name == 'AlarmDescription': | 169 elif name == 'AlarmDescription': |
| 109 self.description = value | 170 self.description = value |
| 110 elif name == 'AlarmName': | 171 elif name == 'AlarmName': |
| 111 self.name = value | 172 self.name = value |
| 112 elif name == 'ComparisonOperator': | 173 elif name == 'ComparisonOperator': |
| 113 setattr(self, 'comparison', self._rev_cmp_map[value]) | 174 setattr(self, 'comparison', self._rev_cmp_map[value]) |
| 114 elif name == 'EvaluationPeriods': | 175 elif name == 'EvaluationPeriods': |
| 115 self.evaluation_periods = int(value) | 176 self.evaluation_periods = int(value) |
| 116 elif name == 'MetricName': | 177 elif name == 'MetricName': |
| 117 self.metric = value | 178 self.metric = value |
| 118 elif name == 'Namespace': | 179 elif name == 'Namespace': |
| 119 self.namespace = value | 180 self.namespace = value |
| 120 elif name == 'Period': | 181 elif name == 'Period': |
| 121 self.period = int(value) | 182 self.period = int(value) |
| 122 elif name == 'StateReason': | 183 elif name == 'StateReason': |
| 123 self.state_reason = value | 184 self.state_reason = value |
| 124 elif name == 'StateValue': | 185 elif name == 'StateValue': |
| 125 self.state_value = None | 186 self.state_value = value |
| 126 elif name == 'Statistic': | 187 elif name == 'Statistic': |
| 127 self.statistic = value | 188 self.statistic = value |
| 128 elif name == 'Threshold': | 189 elif name == 'Threshold': |
| 129 self.threshold = float(value) | 190 self.threshold = float(value) |
| 130 elif name == 'Unit': | 191 elif name == 'Unit': |
| 131 self.unit = value | 192 self.unit = value |
| 132 else: | 193 else: |
| 133 setattr(self, name, value) | 194 setattr(self, name, value) |
| 134 | 195 |
| 135 def set_state(self, value, reason, data=None): | 196 def set_state(self, value, reason, data=None): |
| (...skipping 12 matching lines...) Expand all Loading... |
| 148 | 209 |
| 149 def update(self): | 210 def update(self): |
| 150 return self.connection.update_alarm(self) | 211 return self.connection.update_alarm(self) |
| 151 | 212 |
| 152 def enable_actions(self): | 213 def enable_actions(self): |
| 153 return self.connection.enable_alarm_actions([self.name]) | 214 return self.connection.enable_alarm_actions([self.name]) |
| 154 | 215 |
| 155 def disable_actions(self): | 216 def disable_actions(self): |
| 156 return self.connection.disable_alarm_actions([self.name]) | 217 return self.connection.disable_alarm_actions([self.name]) |
| 157 | 218 |
| 158 def describe_history(self, start_date=None, end_date=None, max_records=None,
history_item_type=None, next_token=None): | 219 def describe_history(self, start_date=None, end_date=None, max_records=None, |
| 159 return self.connection.describe_alarm_history(self.name, start_date, end
_date, | 220 history_item_type=None, next_token=None): |
| 160 max_records, history_item_
type, next_token) | 221 return self.connection.describe_alarm_history(self.name, start_date, |
| 222 end_date, max_records, |
| 223 history_item_type, |
| 224 next_token) |
| 225 |
| 226 def add_alarm_action(self, action_arn=None): |
| 227 """ |
| 228 Adds an alarm action, represented as an SNS topic, to this alarm. |
| 229 What do do when alarm is triggered. |
| 230 |
| 231 :type action_arn: str |
| 232 :param action_arn: SNS topics to which notification should be |
| 233 sent if the alarm goes to state ALARM. |
| 234 """ |
| 235 if not action_arn: |
| 236 return # Raise exception instead? |
| 237 self.actions_enabled = 'true' |
| 238 self.alarm_actions.append(action_arn) |
| 239 |
| 240 def add_insufficient_data_action(self, action_arn=None): |
| 241 """ |
| 242 Adds an insufficient_data action, represented as an SNS topic, to |
| 243 this alarm. What to do when the insufficient_data state is reached. |
| 244 |
| 245 :type action_arn: str |
| 246 :param action_arn: SNS topics to which notification should be |
| 247 sent if the alarm goes to state INSUFFICIENT_DATA. |
| 248 """ |
| 249 if not action_arn: |
| 250 return |
| 251 self.actions_enabled = 'true' |
| 252 self.insufficient_data_actions.append(action_arn) |
| 253 |
| 254 def add_ok_action(self, action_arn=None): |
| 255 """ |
| 256 Adds an ok action, represented as an SNS topic, to this alarm. What |
| 257 to do when the ok state is reached. |
| 258 |
| 259 :type action_arn: str |
| 260 :param action_arn: SNS topics to which notification should be |
| 261 sent if the alarm goes to state INSUFFICIENT_DATA. |
| 262 """ |
| 263 if not action_arn: |
| 264 return |
| 265 self.actions_enabled = 'true' |
| 266 self.ok_actions.append(action_arn) |
| 267 |
| 268 def delete(self): |
| 269 self.connection.delete_alarms([self]) |
| 161 | 270 |
| 162 class AlarmHistoryItem(object): | 271 class AlarmHistoryItem(object): |
| 163 def __init__(self, connection=None): | 272 def __init__(self, connection=None): |
| 164 self.connection = connection | 273 self.connection = connection |
| 165 | 274 |
| 166 def __repr__(self): | 275 def __repr__(self): |
| 167 return 'AlarmHistory:%s[%s at %s]' % (self.name, self.summary, self.time
stamp) | 276 return 'AlarmHistory:%s[%s at %s]' % (self.name, self.summary, self.time
stamp) |
| 168 | 277 |
| 169 def startElement(self, name, attrs, connection): | 278 def startElement(self, name, attrs, connection): |
| 170 pass | 279 pass |
| 171 | 280 |
| 172 def endElement(self, name, value, connection): | 281 def endElement(self, name, value, connection): |
| 173 if name == 'AlarmName': | 282 if name == 'AlarmName': |
| 174 self.name = value | 283 self.name = value |
| 175 elif name == 'HistoryData': | 284 elif name == 'HistoryData': |
| 176 self.data = json.loads(value) | 285 self.data = json.loads(value) |
| 177 elif name == 'HistoryItemType': | 286 elif name == 'HistoryItemType': |
| 178 self.tem_type = value | 287 self.tem_type = value |
| 179 elif name == 'HistorySummary': | 288 elif name == 'HistorySummary': |
| 180 self.summary = value | 289 self.summary = value |
| 181 elif name == 'Timestamp': | 290 elif name == 'Timestamp': |
| 182 self.timestamp = datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%fZ') | 291 self.timestamp = datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%fZ') |
| 183 | 292 |
| OLD | NEW |