CloudWatch: add support for put-metric-data with values list (#5658)

This commit is contained in:
steffyP 2022-11-14 12:41:42 +01:00 committed by GitHub
parent 9eccce8af3
commit 6b50b8020f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 162 additions and 9 deletions

View File

@ -473,22 +473,66 @@ class CloudWatchBackend(BaseBackend):
raise InvalidParameterValue( raise InvalidParameterValue(
f"The value NaN for parameter MetricData.member.{i + 1}.Value is invalid." f"The value NaN for parameter MetricData.member.{i + 1}.Value is invalid."
) )
if metric.get("Values.member"):
if "Value" in metric:
raise InvalidParameterValue(
f"The parameters MetricData.member.{i+1}.Value and MetricData.member.{i+1}.Values are mutually exclusive and you have specified both."
)
if metric.get("Counts.member"):
if len(metric["Counts.member"]) != len(metric["Values.member"]):
raise InvalidParameterValue(
f"The parameters MetricData.member.{i+1}.Values and MetricData.member.{i+1}.Counts must be of the same size."
)
for value in metric["Values.member"]:
if value.lower() == "nan":
raise InvalidParameterValue(
f"The value {value} for parameter MetricData.member.{i + 1}.Values is invalid."
)
for metric_member in metric_data: for metric_member in metric_data:
# Preserve "datetime" for get_metric_statistics comparisons # Preserve "datetime" for get_metric_statistics comparisons
timestamp = metric_member.get("Timestamp") timestamp = metric_member.get("Timestamp")
if timestamp is not None and type(timestamp) != datetime: if timestamp is not None and type(timestamp) != datetime:
timestamp = parser.parse(timestamp) timestamp = parser.parse(timestamp)
self.metric_data.append( metric_name = metric_member["MetricName"]
MetricDatum( dimension = metric_member.get("Dimensions.member", _EMPTY_LIST)
namespace, unit = metric_member.get("Unit")
metric_member["MetricName"],
float(metric_member.get("Value", 0)), # put_metric_data can include "value" as single value or "values" as a list
metric_member.get("Dimensions.member", _EMPTY_LIST), if metric_member.get("Values.member"):
timestamp, values = metric_member["Values.member"]
metric_member.get("Unit"), # value[i] should be added count[i] times (with default count 1)
counts = metric_member.get("Counts.member") or ["1"] * len(values)
for i in range(0, len(values)):
value = values[i]
timestamp = metric_member.get("Timestamp")
if timestamp is not None and type(timestamp) != datetime:
timestamp = parser.parse(timestamp)
# add the value count[i] times
for _ in range(0, int(float(counts[i]))):
self.metric_data.append(
MetricDatum(
namespace,
metric_name,
float(value),
dimension,
timestamp,
unit,
)
)
else:
# there is only a single value
self.metric_data.append(
MetricDatum(
namespace,
metric_name,
float(metric_member.get("Value", 0)),
dimension,
timestamp,
unit,
)
) )
)
def get_metric_data( def get_metric_data(
self, self,

View File

@ -52,6 +52,115 @@ def test_put_metric_data_can_not_have_nan():
) )
@mock_cloudwatch
def test_put_metric_data_can_not_have_value_and_values():
client = boto3.client("cloudwatch", region_name="us-west-2")
utc_now = datetime.now(tz=pytz.utc)
with pytest.raises(ClientError) as exc:
client.put_metric_data(
Namespace="mynamespace",
MetricData=[
{
"MetricName": "mymetric",
"Timestamp": utc_now,
"Value": 1.5,
"Values": [1.0, 10.0],
"Unit": "Count",
}
],
)
err = exc.value.response["Error"]
err["Code"].should.equal("InvalidParameterValue")
err["Message"].should.equal(
"The parameters MetricData.member.1.Value and MetricData.member.1.Values are mutually exclusive and you have specified both."
)
@mock_cloudwatch
def test_put_metric_data_can_not_have_and_values_mismatched_counts():
client = boto3.client("cloudwatch", region_name="us-west-2")
utc_now = datetime.now(tz=pytz.utc)
with pytest.raises(ClientError) as exc:
client.put_metric_data(
Namespace="mynamespace",
MetricData=[
{
"MetricName": "mymetric",
"Timestamp": utc_now,
"Values": [1.0, 10.0],
"Counts": [2, 4, 1],
"Unit": "Count",
}
],
)
err = exc.value.response["Error"]
err["Code"].should.equal("InvalidParameterValue")
err["Message"].should.equal(
"The parameters MetricData.member.1.Values and MetricData.member.1.Counts must be of the same size."
)
@mock_cloudwatch
def test_put_metric_data_values_and_counts():
client = boto3.client("cloudwatch", region_name="us-west-2")
utc_now = datetime.now(tz=pytz.utc)
namespace = "values"
metric = "mymetric"
client.put_metric_data(
Namespace=namespace,
MetricData=[
{
"MetricName": metric,
"Timestamp": utc_now,
"Values": [1.0, 10.0],
"Counts": [2, 4],
}
],
)
stats = client.get_metric_statistics(
Namespace=namespace,
MetricName=metric,
StartTime=utc_now - timedelta(seconds=60),
EndTime=utc_now + timedelta(seconds=60),
Period=60,
Statistics=["SampleCount", "Sum", "Maximum"],
)
datapoint = stats["Datapoints"][0]
datapoint["SampleCount"].should.equal(6.0)
datapoint["Sum"].should.equal(42.0)
datapoint["Maximum"].should.equal(10.0)
@mock_cloudwatch
def test_put_metric_data_values_without_counts():
client = boto3.client("cloudwatch", region_name="us-west-2")
utc_now = datetime.now(tz=pytz.utc)
namespace = "values"
metric = "mymetric"
client.put_metric_data(
Namespace=namespace,
MetricData=[
{
"MetricName": metric,
"Timestamp": utc_now,
"Values": [1.0, 10.0, 23.45],
}
],
)
stats = client.get_metric_statistics(
Namespace=namespace,
MetricName=metric,
StartTime=utc_now - timedelta(seconds=60),
EndTime=utc_now + timedelta(seconds=60),
Period=60,
Statistics=["SampleCount", "Sum", "Maximum"],
)
datapoint = stats["Datapoints"][0]
datapoint["SampleCount"].should.equal(3.0)
datapoint["Sum"].should.equal(34.45)
datapoint["Maximum"].should.equal(23.45)
@mock_cloudwatch @mock_cloudwatch
def test_put_metric_data_with_statistics(): def test_put_metric_data_with_statistics():
conn = boto3.client("cloudwatch", region_name="us-east-1") conn = boto3.client("cloudwatch", region_name="us-east-1")