-
Notifications
You must be signed in to change notification settings - Fork 4.3k
/
Copy pathputmetricdata.py
158 lines (137 loc) · 6.75 KB
/
putmetricdata.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# Copyright 2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
"""
This customization adds the following scalar parameters to the
cloudwatch put-metric-data operation:
* --metric-name
* --dimensions
* --timestamp
* --value
* --statistic-values
* --unit
* --storage-resolution
"""
import decimal
from awscli.arguments import CustomArgument
from awscli.utils import split_on_commas
from awscli.customizations.utils import validate_mutually_exclusive_handler
def register_put_metric_data(event_handler):
event_handler.register(
'building-argument-table.cloudwatch.put-metric-data', _promote_args)
event_handler.register(
'operation-args-parsed.cloudwatch.put-metric-data',
validate_mutually_exclusive_handler(
['metric_data'], ['metric_name', 'timestamp', 'unit', 'value',
'dimensions', 'statistic_values']))
def _promote_args(argument_table, operation_model, **kwargs):
# We're providing top level params for metric-data. This means
# that metric-data is now longer a required arg. We do need
# to check that either metric-data or the complex args we've added
# have been provided.
argument_table['metric-data'].required = False
argument_table['metric-name'] = PutMetricArgument(
'metric-name', help_text='The name of the metric.')
argument_table['timestamp'] = PutMetricArgument(
'timestamp', help_text='The time stamp used for the metric. '
'If not specified, the default value is '
'set to the time the metric data was '
'received.')
argument_table['unit'] = PutMetricArgument(
'unit', help_text='The unit of metric.')
argument_table['value'] = PutMetricArgument(
'value', help_text='The value for the metric. Although the --value '
'parameter accepts numbers of type Double, '
'Amazon CloudWatch truncates values with very '
'large exponents. Values with base-10 exponents '
'greater than 126 (1 x 10^126) are truncated. '
'Likewise, values with base-10 exponents less '
'than -130 (1 x 10^-130) are also truncated.')
argument_table['dimensions'] = PutMetricArgument(
'dimensions', help_text=(
'The --dimensions argument further expands '
'on the identity of a metric using a Name=Value '
'pair, separated by commas, for example: '
'<code>--dimensions InstanceID=1-23456789,InstanceType=m1.small'
'</code>. Note that the <code>--dimensions</code> argument has a '
'different format when used in <code>get-metric-data</code>, '
'where for the same example you would use the format '
'<code>--dimensions Name=InstanceID,Value=i-aaba32d4 '
'Name=InstanceType,value=m1.small </code>.'
)
)
argument_table['statistic-values'] = PutMetricArgument(
'statistic-values', help_text='A set of statistical values describing '
'the metric.')
metric_data = operation_model.input_shape.members['MetricData'].member
storage_resolution = metric_data.members['StorageResolution']
argument_table['storage-resolution'] = PutMetricArgument(
'storage-resolution', help_text=storage_resolution.documentation
)
def insert_first_element(name):
def _wrap_add_to_params(func):
def _add_to_params(self, parameters, value):
if value is None:
return
if name not in parameters:
# We're taking a shortcut here and assuming that the first
# element is a struct type, hence the default value of
# a dict. If this was going to be more general we'd need
# to have this parameterized, i.e. you pass in some sort of
# factory function that creates the initial starting value.
parameters[name] = [{}]
first_element = parameters[name][0]
return func(self, first_element, value)
return _add_to_params
return _wrap_add_to_params
class PutMetricArgument(CustomArgument):
def add_to_params(self, parameters, value):
method_name = '_add_param_%s' % self.name.replace('-', '_')
return getattr(self, method_name)(parameters, value)
@insert_first_element('MetricData')
def _add_param_metric_name(self, first_element, value):
first_element['MetricName'] = value
@insert_first_element('MetricData')
def _add_param_unit(self, first_element, value):
first_element['Unit'] = value
@insert_first_element('MetricData')
def _add_param_timestamp(self, first_element, value):
first_element['Timestamp'] = value
@insert_first_element('MetricData')
def _add_param_value(self, first_element, value):
# Use a Decimal to avoid loss in precision.
first_element['Value'] = decimal.Decimal(value)
@insert_first_element('MetricData')
def _add_param_dimensions(self, first_element, value):
# Dimensions needs a little more processing. We support
# the key=value,key2=value syntax so we need to parse
# that.
dimensions = []
for pair in split_on_commas(value):
key, value = pair.split('=')
dimensions.append({'Name': key, 'Value': value})
first_element['Dimensions'] = dimensions
@insert_first_element('MetricData')
def _add_param_statistic_values(self, first_element, value):
# StatisticValues is a struct type so we are parsing
# a csv keyval list into a dict.
statistics = {}
for pair in split_on_commas(value):
key, value = pair.split('=')
# There are four supported values: Maximum, Minimum, SampleCount,
# and Sum. All of them are documented as a type double so we can
# convert these to a decimal value to preserve precision.
statistics[key] = decimal.Decimal(value)
first_element['StatisticValues'] = statistics
@insert_first_element('MetricData')
def _add_param_storage_resolution(self, first_element, value):
first_element['StorageResolution'] = int(value)