Index: boto/ec2/cloudwatch/__init__.py |
diff --git a/boto/ec2/cloudwatch/__init__.py b/boto/ec2/cloudwatch/__init__.py |
index a02baa366cd34d36766a7eb5b2928a6121d18fd5..1c61736eb4346bb45635843c573ac21e75b40ded 100644 |
--- a/boto/ec2/cloudwatch/__init__.py |
+++ b/boto/ec2/cloudwatch/__init__.py |
@@ -1,4 +1,4 @@ |
-# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/ |
+# Copyright (c) 2006-2011 Mitch Garnaat http://garnaat.org/ |
# |
# Permission is hereby granted, free of charge, to any person obtaining a |
# copy of this software and associated documentation files (the |
@@ -140,6 +140,7 @@ try: |
import simplejson as json |
except ImportError: |
import json |
+ |
from boto.connection import AWSQueryConnection |
from boto.ec2.cloudwatch.metric import Metric |
from boto.ec2.cloudwatch.alarm import MetricAlarm, AlarmHistoryItem |
@@ -151,6 +152,7 @@ RegionData = { |
'us-east-1' : 'monitoring.us-east-1.amazonaws.com', |
'us-west-1' : 'monitoring.us-west-1.amazonaws.com', |
'eu-west-1' : 'monitoring.eu-west-1.amazonaws.com', |
+ 'ap-northeast-1' : 'monitoring.ap-northeast-1.amazonaws.com', |
'ap-southeast-1' : 'monitoring.ap-southeast-1.amazonaws.com'} |
def regions(): |
@@ -188,8 +190,10 @@ def connect_to_region(region_name, **kw_params): |
class CloudWatchConnection(AWSQueryConnection): |
APIVersion = boto.config.get('Boto', 'cloudwatch_version', '2010-08-01') |
- DefaultRegionName = boto.config.get('Boto', 'cloudwatch_region_name', 'us-east-1') |
- DefaultRegionEndpoint = boto.config.get('Boto', 'cloudwatch_region_endpoint', |
+ DefaultRegionName = boto.config.get('Boto', 'cloudwatch_region_name', |
+ 'us-east-1') |
+ DefaultRegionEndpoint = boto.config.get('Boto', |
+ 'cloudwatch_region_endpoint', |
'monitoring.amazonaws.com') |
@@ -218,21 +222,108 @@ class CloudWatchConnection(AWSQueryConnection): |
def _required_auth_capability(self): |
return ['ec2'] |
+ def build_dimension_param(self, dimension, params): |
+ for dim_name in dimension: |
+ dim_value = dimension[dim_name] |
+ if isinstance(dim_value, basestring): |
+ dim_value = [dim_value] |
+ for i, value in enumerate(dim_value): |
+ params['Dimensions.member.%d.Name' % (i+1)] = dim_name |
+ params['Dimensions.member.%d.Value' % (i+1)] = value |
+ |
def build_list_params(self, params, items, label): |
- if isinstance(items, str): |
+ if isinstance(items, basestring): |
items = [items] |
- for i in range(1, len(items)+1): |
- params[label % i] = items[i-1] |
+ for index, item in enumerate(items): |
+ i = index + 1 |
+ if isinstance(item, dict): |
+ for k,v in item.iteritems(): |
+ params[label % (i, 'Name')] = k |
+ if v is not None: |
+ params[label % (i, 'Value')] = v |
+ else: |
+ params[label % i] = item |
+ |
+ def build_put_params(self, params, name, value=None, timestamp=None, |
+ unit=None, dimensions=None, statistics=None): |
+ args = (name, value, unit, dimensions, statistics) |
+ length = max(map(lambda a: len(a) if isinstance(a, list) else 1, args)) |
+ |
+ def aslist(a): |
+ if isinstance(a, list): |
+ if len(a) != length: |
+ raise Exception('Must specify equal number of elements; expected %d.' % length) |
+ return a |
+ return [a] * length |
+ |
+ for index, (n, v, u, d, s) in enumerate(zip(*map(aslist, args))): |
+ metric_data = {'MetricName': n} |
+ |
+ if timestamp: |
+ metric_data['Timestamp'] = timestamp.isoformat() |
+ |
+ if unit: |
+ metric_data['Unit'] = u |
+ |
+ if dimensions: |
+ self.build_dimension_param(d, metric_data) |
+ |
+ if statistics: |
+ metric_data['StatisticValues.Maximum'] = s['maximum'] |
+ metric_data['StatisticValues.Minimum'] = s['minimum'] |
+ metric_data['StatisticValues.SampleCount'] = s['samplecount'] |
+ metric_data['StatisticValues.Sum'] = s['sum'] |
+ if value != None: |
+ msg = 'You supplied a value and statistics for a metric.' |
+ msg += 'Posting statistics and not value.' |
+ boto.log.warn(msg) |
+ elif value != None: |
+ metric_data['Value'] = v |
+ else: |
+ raise Exception('Must specify a value or statistics to put.') |
+ |
+ for key, value in metric_data.iteritems(): |
+ params['MetricData.member.%d.%s' % (index + 1, key)] = value |
def get_metric_statistics(self, period, start_time, end_time, metric_name, |
- namespace, statistics, dimensions=None, unit=None): |
+ namespace, statistics, dimensions=None, |
+ unit=None): |
""" |
Get time-series data for one or more statistics of a given metric. |
+ :type period: integer |
+ :param period: The granularity, in seconds, of the returned datapoints. |
+ Period must be at least 60 seconds and must be a multiple |
+ of 60. The default value is 60. |
+ |
+ :type start_time: datetime |
+ :param start_time: The time stamp to use for determining the first |
+ datapoint to return. The value specified is |
+ inclusive; results include datapoints with the |
+ time stamp specified. |
+ |
+ :type end_time: datetime |
+ :param end_time: The time stamp to use for determining the last |
+ datapoint to return. The value specified is |
+ exclusive; results will include datapoints up to |
+ the time stamp specified. |
+ |
:type metric_name: string |
- :param metric_name: CPUUtilization|NetworkIO-in|NetworkIO-out|DiskIO-ALL-read| |
- DiskIO-ALL-write|DiskIO-ALL-read-bytes|DiskIO-ALL-write-bytes |
+ :param metric_name: The metric name. |
+ |
+ :type namespace: string |
+ :param namespace: The metric's namespace. |
+ |
+ :type statistics: list |
+ :param statistics: A list of statistics names Valid values: |
+ Average | Sum | SampleCount | Maximum | Minimum |
+ :type dimensions: dict |
+ :param dimensions: A dictionary of dimension key/values where |
+ the key is the dimension name and the value |
+ is either a scalar value or an iterator |
+ of values to be associated with that |
+ dimension. |
:rtype: list |
""" |
params = {'Period' : period, |
@@ -242,31 +333,106 @@ class CloudWatchConnection(AWSQueryConnection): |
'EndTime' : end_time.isoformat()} |
self.build_list_params(params, statistics, 'Statistics.member.%d') |
if dimensions: |
- i = 1 |
- for name in dimensions: |
- params['Dimensions.member.%d.Name' % i] = name |
- params['Dimensions.member.%d.Value' % i] = dimensions[name] |
- i += 1 |
- return self.get_list('GetMetricStatistics', params, [('member', Datapoint)]) |
+ self.build_dimension_param(dimensions, params) |
+ return self.get_list('GetMetricStatistics', params, |
+ [('member', Datapoint)]) |
- def list_metrics(self, next_token=None): |
+ def list_metrics(self, next_token=None, dimensions=None, |
+ metric_name=None, namespace=None): |
""" |
- Returns a list of the valid metrics for which there is recorded data available. |
+ Returns a list of the valid metrics for which there is recorded |
+ data available. |
- :type next_token: string |
- :param next_token: A maximum of 500 metrics will be returned at one time. |
- If more results are available, the ResultSet returned |
- will contain a non-Null next_token attribute. Passing |
- that token as a parameter to list_metrics will retrieve |
- the next page of metrics. |
+ :type next_token: str |
+ :param next_token: A maximum of 500 metrics will be returned at one |
+ time. If more results are available, the |
+ ResultSet returned will contain a non-Null |
+ next_token attribute. Passing that token as a |
+ parameter to list_metrics will retrieve the |
+ next page of metrics. |
+ |
+ :type dimension: dict |
+ :param dimension_filters: A dictionary containing name/value pairs |
+ that will be used to filter the results. |
+ The key in the dictionary is the name of |
+ a Dimension. The value in the dictionary |
+ is either a scalar value of that Dimension |
+ name that you want to filter on, a list |
+ of values to filter on or None if |
+ you want all metrics with that Dimension name. |
+ |
+ :type metric_name: str |
+ :param metric_name: The name of the Metric to filter against. If None, |
+ all Metric names will be returned. |
+ |
+ :type namespace: str |
+ :param namespace: A Metric namespace to filter against (e.g. AWS/EC2). |
+ If None, Metrics from all namespaces will be returned. |
""" |
params = {} |
if next_token: |
params['NextToken'] = next_token |
+ if dimensions: |
+ self.build_dimension_param(dimensions, params) |
+ if metric_name: |
+ params['MetricName'] = metric_name |
+ if namespace: |
+ params['Namespace'] = namespace |
+ |
return self.get_list('ListMetrics', params, [('member', Metric)]) |
+ |
+ def put_metric_data(self, namespace, name, value=None, timestamp=None, |
+ unit=None, dimensions=None, statistics=None): |
+ """ |
+ Publishes metric data points to Amazon CloudWatch. Amazon Cloudwatch |
+ associates the data points with the specified metric. If the specified |
+ metric does not exist, Amazon CloudWatch creates the metric. If a list |
+ is specified for some, but not all, of the arguments, the remaining |
+ arguments are repeated a corresponding number of times. |
+ |
+ :type namespace: str |
+ :param namespace: The namespace of the metric. |
- def describe_alarms(self, action_prefix=None, alarm_name_prefix=None, alarm_names=None, |
- max_records=None, state_value=None, next_token=None): |
+ :type name: str or list |
+ :param name: The name of the metric. |
+ |
+ :type value: float or list |
+ :param value: The value for the metric. |
+ |
+ :type timestamp: datetime or list |
+ :param timestamp: The time stamp used for the metric. If not specified, |
+ the default value is set to the time the metric data was received. |
+ |
+ :type unit: string or list |
+ :param unit: The unit of the metric. Valid Values: Seconds | |
+ Microseconds | Milliseconds | Bytes | Kilobytes | |
+ Megabytes | Gigabytes | Terabytes | Bits | Kilobits | |
+ Megabits | Gigabits | Terabits | Percent | Count | |
+ Bytes/Second | Kilobytes/Second | Megabytes/Second | |
+ Gigabytes/Second | Terabytes/Second | Bits/Second | |
+ Kilobits/Second | Megabits/Second | Gigabits/Second | |
+ Terabits/Second | Count/Second | None |
+ |
+ :type dimensions: dict |
+ :param dimensions: Add extra name value pairs to associate |
+ with the metric, i.e.: |
+ {'name1': value1, 'name2': (value2, value3)} |
+ |
+ :type statistics: dict or list |
+ :param statistics: Use a statistic set instead of a value, for example:: |
+ |
+ {'maximum': 30, 'minimum': 1, 'samplecount': 100, 'sum': 10000} |
+ """ |
+ params = {'Namespace': namespace} |
+ self.build_put_params(params, name, value=value, timestamp=timestamp, |
+ unit=unit, dimensions=dimensions, statistics=statistics) |
+ |
+ return self.get_status('PutMetricData', params) |
+ |
+ |
+ def describe_alarms(self, action_prefix=None, alarm_name_prefix=None, |
+ alarm_names=None, max_records=None, state_value=None, |
+ next_token=None): |
""" |
Retrieves alarms with the specified names. If no name is specified, all |
alarms for the user are returned. Alarms can be retrieved by using only |
@@ -277,20 +443,22 @@ class CloudWatchConnection(AWSQueryConnection): |
:param action_name: The action name prefix. |
:type alarm_name_prefix: string |
- :param alarm_name_prefix: The alarm name prefix. AlarmNames cannot be specified |
- if this parameter is specified. |
+ :param alarm_name_prefix: The alarm name prefix. AlarmNames cannot |
+ be specified if this parameter is specified. |
:type alarm_names: list |
:param alarm_names: A list of alarm names to retrieve information for. |
:type max_records: int |
- :param max_records: The maximum number of alarm descriptions to retrieve. |
+ :param max_records: The maximum number of alarm descriptions |
+ to retrieve. |
:type state_value: string |
:param state_value: The state value to be used in matching alarms. |
:type next_token: string |
- :param next_token: The token returned by a previous call to indicate that there is more data. |
+ :param next_token: The token returned by a previous call to |
+ indicate that there is more data. |
:rtype list |
""" |
@@ -307,10 +475,13 @@ class CloudWatchConnection(AWSQueryConnection): |
params['NextToken'] = next_token |
if state_value: |
params['StateValue'] = state_value |
- return self.get_list('DescribeAlarms', params, [('member', MetricAlarm)]) |
+ return self.get_list('DescribeAlarms', params, |
+ [('member', MetricAlarm)]) |
- def describe_alarm_history(self, alarm_name=None, start_date=None, end_date=None, |
- max_records=None, history_item_type=None, next_token=None): |
+ def describe_alarm_history(self, alarm_name=None, |
+ start_date=None, end_date=None, |
+ max_records=None, history_item_type=None, |
+ next_token=None): |
""" |
Retrieves history for the specified alarm. Filter alarms by date range |
or item type. If an alarm name is not specified, Amazon CloudWatch |
@@ -330,13 +501,16 @@ class CloudWatchConnection(AWSQueryConnection): |
:param end_date: The starting date to retrieve alarm history. |
:type history_item_type: string |
- :param history_item_type: The type of alarm histories to retreive (ConfigurationUpdate | StateUpdate | Action) |
+ :param history_item_type: The type of alarm histories to retreive |
+ (ConfigurationUpdate | StateUpdate | Action) |
:type max_records: int |
- :param max_records: The maximum number of alarm descriptions to retrieve. |
+ :param max_records: The maximum number of alarm descriptions |
+ to retrieve. |
:type next_token: string |
- :param next_token: The token returned by a previous call to indicate that there is more data. |
+ :param next_token: The token returned by a previous call to indicate |
+ that there is more data. |
:rtype list |
""" |
@@ -353,9 +527,11 @@ class CloudWatchConnection(AWSQueryConnection): |
params['MaxRecords'] = max_records |
if next_token: |
params['NextToken'] = next_token |
- return self.get_list('DescribeAlarmHistory', params, [('member', AlarmHistoryItem)]) |
+ return self.get_list('DescribeAlarmHistory', params, |
+ [('member', AlarmHistoryItem)]) |
- def describe_alarms_for_metric(self, metric_name, namespace, period=None, statistic=None, dimensions=None, unit=None): |
+ def describe_alarms_for_metric(self, metric_name, namespace, period=None, |
+ statistic=None, dimensions=None, unit=None): |
""" |
Retrieves all alarms for a single metric. Specify a statistic, period, |
or unit to filter the set of alarms further. |
@@ -367,30 +543,37 @@ class CloudWatchConnection(AWSQueryConnection): |
:param namespace: The namespace of the metric. |
:type period: int |
- :param period: The period in seconds over which the statistic is applied. |
+ :param period: The period in seconds over which the statistic |
+ is applied. |
:type statistic: string |
:param statistic: The statistic for the metric. |
- :type dimensions: list |
+ :param dimension_filters: A dictionary containing name/value pairs |
+ that will be used to filter the results. |
+ The key in the dictionary is the name of |
+ a Dimension. The value in the dictionary |
+ is either a scalar value of that Dimension |
+ name that you want to filter on, a list |
+ of values to filter on or None if |
+ you want all metrics with that Dimension name. |
:type unit: string |
:rtype list |
""" |
- params = { |
- 'MetricName' : metric_name, |
- 'Namespace' : namespace, |
- } |
+ params = {'MetricName' : metric_name, |
+ 'Namespace' : namespace} |
if period: |
params['Period'] = period |
if statistic: |
params['Statistic'] = statistic |
if dimensions: |
- self.build_list_params(params, dimensions, 'Dimensions.member.%s') |
+ self.build_dimension_param(dimensions, params) |
if unit: |
params['Unit'] = unit |
- return self.get_list('DescribeAlarmsForMetric', params, [('member', MetricAlarm)]) |
+ return self.get_list('DescribeAlarmsForMetric', params, |
+ [('member', MetricAlarm)]) |
def put_metric_alarm(self, alarm): |
""" |
@@ -413,7 +596,7 @@ class CloudWatchConnection(AWSQueryConnection): |
'MetricName' : alarm.metric, |
'Namespace' : alarm.namespace, |
'Statistic' : alarm.statistic, |
- 'ComparisonOperator' : MetricAlarm._cmp_map[alarm.comparison], |
+ 'ComparisonOperator' : alarm.comparison, |
'Threshold' : alarm.threshold, |
'EvaluationPeriods' : alarm.evaluation_periods, |
'Period' : alarm.period, |
@@ -421,15 +604,18 @@ class CloudWatchConnection(AWSQueryConnection): |
if alarm.actions_enabled is not None: |
params['ActionsEnabled'] = alarm.actions_enabled |
if alarm.alarm_actions: |
- self.build_list_params(params, alarm.alarm_actions, 'AlarmActions.member.%s') |
+ self.build_list_params(params, alarm.alarm_actions, |
+ 'AlarmActions.member.%s') |
if alarm.description: |
params['AlarmDescription'] = alarm.description |
if alarm.dimensions: |
- self.build_list_params(params, alarm.dimensions, 'Dimensions.member.%s') |
+ self.build_dimension_param(alarm.dimensions, params) |
if alarm.insufficient_data_actions: |
- self.build_list_params(params, alarm.insufficient_data_actions, 'InsufficientDataActions.member.%s') |
+ self.build_list_params(params, alarm.insufficient_data_actions, |
+ 'InsufficientDataActions.member.%s') |
if alarm.ok_actions: |
- self.build_list_params(params, alarm.ok_actions, 'OKActions.member.%s') |
+ self.build_list_params(params, alarm.ok_actions, |
+ 'OKActions.member.%s') |
if alarm.unit: |
params['Unit'] = alarm.unit |
alarm.connection = self |
@@ -439,7 +625,8 @@ class CloudWatchConnection(AWSQueryConnection): |
def delete_alarms(self, alarms): |
""" |
- Deletes all specified alarms. In the event of an error, no alarms are deleted. |
+ Deletes all specified alarms. In the event of an error, no |
+ alarms are deleted. |
:type alarms: list |
:param alarms: List of alarm names. |
@@ -448,7 +635,8 @@ class CloudWatchConnection(AWSQueryConnection): |
self.build_list_params(params, alarms, 'AlarmNames.member.%s') |
return self.get_status('DeleteAlarms', params) |
- def set_alarm_state(self, alarm_name, state_reason, state_value, state_reason_data=None): |
+ def set_alarm_state(self, alarm_name, state_reason, state_value, |
+ state_reason_data=None): |
""" |
Temporarily sets the state of an alarm. When the updated StateValue |
differs from the previous value, the action configured for the |
@@ -468,11 +656,9 @@ class CloudWatchConnection(AWSQueryConnection): |
:type state_reason_data: string |
:param state_reason_data: Reason string (will be jsonified). |
""" |
- params = { |
- 'AlarmName' : alarm_name, |
- 'StateReason' : state_reason, |
- 'StateValue' : state_value, |
- } |
+ params = {'AlarmName' : alarm_name, |
+ 'StateReason' : state_reason, |
+ 'StateValue' : state_value} |
if state_reason_data: |
params['StateReasonData'] = json.dumps(state_reason_data) |