add metric filter support to cloudwatch logs (updated) (#4278)
Co-authored-by: Brady <brady.jubic@gsa.gov>
This commit is contained in:
parent
d48cd31ebb
commit
9859d66ff8
@ -7068,7 +7068,7 @@
|
|||||||
|
|
||||||
## logs
|
## logs
|
||||||
<details>
|
<details>
|
||||||
<summary>50% implemented</summary>
|
<summary>57% implemented</summary>
|
||||||
|
|
||||||
- [ ] associate_kms_key
|
- [ ] associate_kms_key
|
||||||
- [ ] cancel_export_task
|
- [ ] cancel_export_task
|
||||||
@ -7078,7 +7078,7 @@
|
|||||||
- [ ] delete_destination
|
- [ ] delete_destination
|
||||||
- [X] delete_log_group
|
- [X] delete_log_group
|
||||||
- [X] delete_log_stream
|
- [X] delete_log_stream
|
||||||
- [ ] delete_metric_filter
|
- [X] delete_metric_filter
|
||||||
- [ ] delete_query_definition
|
- [ ] delete_query_definition
|
||||||
- [X] delete_resource_policy
|
- [X] delete_resource_policy
|
||||||
- [X] delete_retention_policy
|
- [X] delete_retention_policy
|
||||||
@ -7087,7 +7087,7 @@
|
|||||||
- [ ] describe_export_tasks
|
- [ ] describe_export_tasks
|
||||||
- [X] describe_log_groups
|
- [X] describe_log_groups
|
||||||
- [X] describe_log_streams
|
- [X] describe_log_streams
|
||||||
- [ ] describe_metric_filters
|
- [X] describe_metric_filters
|
||||||
- [ ] describe_queries
|
- [ ] describe_queries
|
||||||
- [ ] describe_query_definitions
|
- [ ] describe_query_definitions
|
||||||
- [X] describe_resource_policies
|
- [X] describe_resource_policies
|
||||||
@ -7102,7 +7102,7 @@
|
|||||||
- [ ] put_destination
|
- [ ] put_destination
|
||||||
- [ ] put_destination_policy
|
- [ ] put_destination_policy
|
||||||
- [X] put_log_events
|
- [X] put_log_events
|
||||||
- [ ] put_metric_filter
|
- [X] put_metric_filter
|
||||||
- [ ] put_query_definition
|
- [ ] put_query_definition
|
||||||
- [X] put_resource_policy
|
- [X] put_resource_policy
|
||||||
- [X] put_retention_policy
|
- [X] put_retention_policy
|
||||||
|
65
moto/logs/metric_filters.py
Normal file
65
moto/logs/metric_filters.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
def find_metric_transformation_by_name(metric_transformations, metric_name):
|
||||||
|
for metric in metric_transformations:
|
||||||
|
if metric["metricName"] == metric_name:
|
||||||
|
return metric
|
||||||
|
|
||||||
|
|
||||||
|
def find_metric_transformation_by_namespace(metric_transformations, metric_namespace):
|
||||||
|
for metric in metric_transformations:
|
||||||
|
if metric["metricNamespace"] == metric_namespace:
|
||||||
|
return metric
|
||||||
|
|
||||||
|
|
||||||
|
class MetricFilters:
|
||||||
|
def __init__(self):
|
||||||
|
self.metric_filters = []
|
||||||
|
|
||||||
|
def add_filter(
|
||||||
|
self, filter_name, filter_pattern, log_group_name, metric_transformations
|
||||||
|
):
|
||||||
|
self.metric_filters.append(
|
||||||
|
{
|
||||||
|
"filterName": filter_name,
|
||||||
|
"filterPattern": filter_pattern,
|
||||||
|
"logGroupName": log_group_name,
|
||||||
|
"metricTransformations": metric_transformations,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_matching_filters(
|
||||||
|
self, prefix=None, log_group_name=None, metric_name=None, metric_namespace=None
|
||||||
|
):
|
||||||
|
result = []
|
||||||
|
for f in self.metric_filters:
|
||||||
|
prefix_matches = prefix is None or f["filterName"].startswith(prefix)
|
||||||
|
log_group_matches = (
|
||||||
|
log_group_name is None or f["logGroupName"] == log_group_name
|
||||||
|
)
|
||||||
|
metric_name_matches = (
|
||||||
|
metric_name is None
|
||||||
|
or find_metric_transformation_by_name(
|
||||||
|
f["metricTransformations"], metric_name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
namespace_matches = (
|
||||||
|
metric_namespace is None
|
||||||
|
or find_metric_transformation_by_namespace(
|
||||||
|
f["metricTransformations"], metric_namespace
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (
|
||||||
|
prefix_matches
|
||||||
|
and log_group_matches
|
||||||
|
and metric_name_matches
|
||||||
|
and namespace_matches
|
||||||
|
):
|
||||||
|
result.append(f)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def delete_filter(self, filter_name=None, log_group_name=None):
|
||||||
|
for f in self.metric_filters:
|
||||||
|
if f["filterName"] == filter_name and f["logGroupName"] == log_group_name:
|
||||||
|
self.metric_filters.remove(f)
|
||||||
|
return self.metric_filters
|
@ -5,6 +5,7 @@ from boto3 import Session
|
|||||||
from moto import core as moto_core
|
from moto import core as moto_core
|
||||||
from moto.core import BaseBackend, BaseModel
|
from moto.core import BaseBackend, BaseModel
|
||||||
from moto.core.utils import unix_time_millis
|
from moto.core.utils import unix_time_millis
|
||||||
|
from moto.logs.metric_filters import MetricFilters
|
||||||
from moto.logs.exceptions import (
|
from moto.logs.exceptions import (
|
||||||
ResourceNotFoundException,
|
ResourceNotFoundException,
|
||||||
ResourceAlreadyExistsException,
|
ResourceAlreadyExistsException,
|
||||||
@ -32,6 +33,7 @@ class LogEvent(BaseModel):
|
|||||||
self.message = log_event["message"]
|
self.message = log_event["message"]
|
||||||
self.event_id = self.__class__._event_id
|
self.event_id = self.__class__._event_id
|
||||||
self.__class__._event_id += 1
|
self.__class__._event_id += 1
|
||||||
|
""
|
||||||
|
|
||||||
def to_filter_dict(self):
|
def to_filter_dict(self):
|
||||||
return {
|
return {
|
||||||
@ -525,6 +527,7 @@ class LogsBackend(BaseBackend):
|
|||||||
def __init__(self, region_name):
|
def __init__(self, region_name):
|
||||||
self.region_name = region_name
|
self.region_name = region_name
|
||||||
self.groups = dict() # { logGroupName: LogGroup}
|
self.groups = dict() # { logGroupName: LogGroup}
|
||||||
|
self.filters = MetricFilters()
|
||||||
self.queries = dict()
|
self.queries = dict()
|
||||||
self.resource_policies = dict()
|
self.resource_policies = dict()
|
||||||
|
|
||||||
@ -796,6 +799,24 @@ class LogsBackend(BaseBackend):
|
|||||||
log_group = self.groups[log_group_name]
|
log_group = self.groups[log_group_name]
|
||||||
log_group.untag(tags)
|
log_group.untag(tags)
|
||||||
|
|
||||||
|
def put_metric_filter(
|
||||||
|
self, filter_name, filter_pattern, log_group_name, metric_transformations
|
||||||
|
):
|
||||||
|
self.filters.add_filter(
|
||||||
|
filter_name, filter_pattern, log_group_name, metric_transformations
|
||||||
|
)
|
||||||
|
|
||||||
|
def describe_metric_filters(
|
||||||
|
self, prefix=None, log_group_name=None, metric_name=None, metric_namespace=None
|
||||||
|
):
|
||||||
|
filters = self.filters.get_matching_filters(
|
||||||
|
prefix, log_group_name, metric_name, metric_namespace
|
||||||
|
)
|
||||||
|
return filters
|
||||||
|
|
||||||
|
def delete_metric_filter(self, filter_name=None, log_group_name=None):
|
||||||
|
self.filters.delete_filter(filter_name, log_group_name)
|
||||||
|
|
||||||
def describe_subscription_filters(self, log_group_name):
|
def describe_subscription_filters(self, log_group_name):
|
||||||
log_group = self.groups.get(log_group_name)
|
log_group = self.groups.get(log_group_name)
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import json
|
import json
|
||||||
|
import re
|
||||||
|
|
||||||
from .exceptions import InvalidParameterException
|
from .exceptions import InvalidParameterException
|
||||||
|
|
||||||
@ -8,6 +9,26 @@ from .models import logs_backends
|
|||||||
# See http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/Welcome.html
|
# See http://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/Welcome.html
|
||||||
|
|
||||||
|
|
||||||
|
def validate_param(
|
||||||
|
param_name, param_value, constraint, constraint_expression, pattern=None
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
assert constraint_expression(param_value)
|
||||||
|
except (AssertionError, TypeError):
|
||||||
|
raise InvalidParameterException(
|
||||||
|
constraint=constraint, parameter=param_name, value=param_value,
|
||||||
|
)
|
||||||
|
if pattern and param_value:
|
||||||
|
try:
|
||||||
|
assert re.match(pattern, param_value)
|
||||||
|
except (AssertionError, TypeError):
|
||||||
|
raise InvalidParameterException(
|
||||||
|
constraint=f"Must match pattern: {pattern}",
|
||||||
|
parameter=param_name,
|
||||||
|
value=param_value,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class LogsResponse(BaseResponse):
|
class LogsResponse(BaseResponse):
|
||||||
@property
|
@property
|
||||||
def logs_backend(self):
|
def logs_backend(self):
|
||||||
@ -23,6 +44,107 @@ class LogsResponse(BaseResponse):
|
|||||||
def _get_param(self, param, if_none=None):
|
def _get_param(self, param, if_none=None):
|
||||||
return self.request_params.get(param, if_none)
|
return self.request_params.get(param, if_none)
|
||||||
|
|
||||||
|
def _get_validated_param(
|
||||||
|
self, param, constraint, constraint_expression, pattern=None
|
||||||
|
):
|
||||||
|
param_value = self._get_param(param)
|
||||||
|
validate_param(param, param_value, constraint, constraint_expression, pattern)
|
||||||
|
return param_value
|
||||||
|
|
||||||
|
def put_metric_filter(self):
|
||||||
|
filter_name = self._get_validated_param(
|
||||||
|
"filterName",
|
||||||
|
"Minimum length of 1. Maximum length of 512.",
|
||||||
|
lambda x: 1 <= len(x) <= 512,
|
||||||
|
pattern="[^:*]*",
|
||||||
|
)
|
||||||
|
filter_pattern = self._get_validated_param(
|
||||||
|
"filterPattern",
|
||||||
|
"Minimum length of 0. Maximum length of 1024.",
|
||||||
|
lambda x: 0 <= len(x) <= 1024,
|
||||||
|
)
|
||||||
|
log_group_name = self._get_validated_param(
|
||||||
|
"logGroupName",
|
||||||
|
"Minimum length of 1. Maximum length of 512.",
|
||||||
|
lambda x: 1 <= len(x) <= 512,
|
||||||
|
pattern="[.-_/#A-Za-z0-9]+",
|
||||||
|
)
|
||||||
|
metric_transformations = self._get_validated_param(
|
||||||
|
"metricTransformations", "Fixed number of 1 item.", lambda x: len(x) == 1
|
||||||
|
)
|
||||||
|
|
||||||
|
self.logs_backend.put_metric_filter(
|
||||||
|
filter_name, filter_pattern, log_group_name, metric_transformations
|
||||||
|
)
|
||||||
|
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def describe_metric_filters(self):
|
||||||
|
filter_name_prefix = self._get_validated_param(
|
||||||
|
"filterNamePrefix",
|
||||||
|
"Minimum length of 1. Maximum length of 512.",
|
||||||
|
lambda x: x is None or 1 <= len(x) <= 512,
|
||||||
|
pattern="[^:*]*",
|
||||||
|
)
|
||||||
|
log_group_name = self._get_validated_param(
|
||||||
|
"logGroupName",
|
||||||
|
"Minimum length of 1. Maximum length of 512",
|
||||||
|
lambda x: x is None or 1 <= len(x) <= 512,
|
||||||
|
pattern="[.-_/#A-Za-z0-9]+",
|
||||||
|
)
|
||||||
|
metric_name = self._get_validated_param(
|
||||||
|
"metricName",
|
||||||
|
"Maximum length of 255.",
|
||||||
|
lambda x: x is None or len(x) <= 255,
|
||||||
|
pattern="[^:*$]*",
|
||||||
|
)
|
||||||
|
metric_namespace = self._get_validated_param(
|
||||||
|
"metricNamespace",
|
||||||
|
"Maximum length of 255.",
|
||||||
|
lambda x: x is None or len(x) <= 255,
|
||||||
|
pattern="[^:*$]*",
|
||||||
|
)
|
||||||
|
next_token = self._get_validated_param(
|
||||||
|
"nextToken", "Minimum length of 1.", lambda x: x is None or 1 <= len(x)
|
||||||
|
)
|
||||||
|
|
||||||
|
if metric_name and not metric_namespace:
|
||||||
|
raise InvalidParameterException(
|
||||||
|
constraint=f"If you include the metricName parameter in your request, "
|
||||||
|
f"you must also include the metricNamespace parameter.",
|
||||||
|
parameter="metricNamespace",
|
||||||
|
value=metric_namespace,
|
||||||
|
)
|
||||||
|
if metric_namespace and not metric_name:
|
||||||
|
raise InvalidParameterException(
|
||||||
|
constraint=f"If you include the metricNamespace parameter in your request, "
|
||||||
|
f"you must also include the metricName parameter.",
|
||||||
|
parameter="metricName",
|
||||||
|
value=metric_name,
|
||||||
|
)
|
||||||
|
|
||||||
|
filters = self.logs_backend.describe_metric_filters(
|
||||||
|
filter_name_prefix, log_group_name, metric_name, metric_namespace
|
||||||
|
)
|
||||||
|
return json.dumps({"metricFilters": filters, "nextToken": next_token})
|
||||||
|
|
||||||
|
def delete_metric_filter(self):
|
||||||
|
filter_name = self._get_validated_param(
|
||||||
|
"filterName",
|
||||||
|
"Minimum length of 1. Maximum length of 512.",
|
||||||
|
lambda x: 1 <= len(x) <= 512,
|
||||||
|
pattern="[^:*]*$",
|
||||||
|
)
|
||||||
|
log_group_name = self._get_validated_param(
|
||||||
|
"logGroupName",
|
||||||
|
"Minimum length of 1. Maximum length of 512.",
|
||||||
|
lambda x: 1 <= len(x) <= 512,
|
||||||
|
pattern="[.-_/#A-Za-z0-9]+$",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.logs_backend.delete_metric_filter(filter_name, log_group_name)
|
||||||
|
return ""
|
||||||
|
|
||||||
def create_log_group(self):
|
def create_log_group(self):
|
||||||
log_group_name = self._get_param("logGroupName")
|
log_group_name = self._get_param("logGroupName")
|
||||||
tags = self._get_param("tags")
|
tags = self._get_param("tags")
|
||||||
|
@ -37,6 +37,297 @@ def json_policy_doc():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_logs
|
||||||
|
def test_describe_metric_filters_happy_prefix():
|
||||||
|
conn = boto3.client("logs", "us-west-2")
|
||||||
|
|
||||||
|
response1 = put_metric_filter(conn, count=1)
|
||||||
|
assert response1["ResponseMetadata"]["HTTPStatusCode"] == 200
|
||||||
|
response2 = put_metric_filter(conn, count=2)
|
||||||
|
assert response2["ResponseMetadata"]["HTTPStatusCode"] == 200
|
||||||
|
|
||||||
|
response = conn.describe_metric_filters(filterNamePrefix="filter")
|
||||||
|
|
||||||
|
assert len(response["metricFilters"]) == 2
|
||||||
|
assert response["metricFilters"][0]["filterName"] == "filterName1"
|
||||||
|
assert response["metricFilters"][1]["filterName"] == "filterName2"
|
||||||
|
|
||||||
|
|
||||||
|
@mock_logs
|
||||||
|
def test_describe_metric_filters_happy_log_group_name():
|
||||||
|
conn = boto3.client("logs", "us-west-2")
|
||||||
|
|
||||||
|
response1 = put_metric_filter(conn, count=1)
|
||||||
|
assert response1["ResponseMetadata"]["HTTPStatusCode"] == 200
|
||||||
|
response2 = put_metric_filter(conn, count=2)
|
||||||
|
assert response2["ResponseMetadata"]["HTTPStatusCode"] == 200
|
||||||
|
|
||||||
|
response = conn.describe_metric_filters(logGroupName="logGroupName2")
|
||||||
|
|
||||||
|
assert len(response["metricFilters"]) == 1
|
||||||
|
assert response["metricFilters"][0]["logGroupName"] == "logGroupName2"
|
||||||
|
|
||||||
|
|
||||||
|
@mock_logs
|
||||||
|
def test_describe_metric_filters_happy_metric_name():
|
||||||
|
conn = boto3.client("logs", "us-west-2")
|
||||||
|
|
||||||
|
response1 = put_metric_filter(conn, count=1)
|
||||||
|
assert response1["ResponseMetadata"]["HTTPStatusCode"] == 200
|
||||||
|
response2 = put_metric_filter(conn, count=2)
|
||||||
|
assert response2["ResponseMetadata"]["HTTPStatusCode"] == 200
|
||||||
|
|
||||||
|
response = conn.describe_metric_filters(
|
||||||
|
metricName="metricName1", metricNamespace="metricNamespace1",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(response["metricFilters"]) == 1
|
||||||
|
metrics = response["metricFilters"][0]["metricTransformations"]
|
||||||
|
assert metrics[0]["metricName"] == "metricName1"
|
||||||
|
assert metrics[0]["metricNamespace"] == "metricNamespace1"
|
||||||
|
|
||||||
|
|
||||||
|
@mock_logs
|
||||||
|
def test_put_metric_filters_validation():
|
||||||
|
conn = boto3.client("logs", "us-west-2")
|
||||||
|
|
||||||
|
invalid_filter_name = "X" * 513
|
||||||
|
invalid_filter_pattern = "X" * 1025
|
||||||
|
invalid_metric_transformations = [
|
||||||
|
{
|
||||||
|
"defaultValue": 1,
|
||||||
|
"metricName": "metricName",
|
||||||
|
"metricNamespace": "metricNamespace",
|
||||||
|
"metricValue": "metricValue",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"defaultValue": 1,
|
||||||
|
"metricName": "metricName",
|
||||||
|
"metricNamespace": "metricNamespace",
|
||||||
|
"metricValue": "metricValue",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
test_cases = [
|
||||||
|
build_put_case(name="Invalid filter name", filter_name=invalid_filter_name,),
|
||||||
|
build_put_case(
|
||||||
|
name="Invalid filter pattern", filter_pattern=invalid_filter_pattern,
|
||||||
|
),
|
||||||
|
build_put_case(
|
||||||
|
name="Invalid filter metric transformations",
|
||||||
|
metric_transformations=invalid_metric_transformations,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
for test_case in test_cases:
|
||||||
|
with pytest.raises(ClientError) as exc:
|
||||||
|
conn.put_metric_filter(**test_case["input"])
|
||||||
|
response = exc.value.response
|
||||||
|
response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
|
||||||
|
response["Error"]["Code"].should.equal("InvalidParameterException")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_logs
|
||||||
|
def test_describe_metric_filters_validation():
|
||||||
|
conn = boto3.client("logs", "us-west-2")
|
||||||
|
|
||||||
|
length_over_512 = "X" * 513
|
||||||
|
length_over_255 = "X" * 256
|
||||||
|
|
||||||
|
test_cases = [
|
||||||
|
build_describe_case(
|
||||||
|
name="Invalid filter name prefix", filter_name_prefix=length_over_512,
|
||||||
|
),
|
||||||
|
build_describe_case(
|
||||||
|
name="Invalid log group name", log_group_name=length_over_512,
|
||||||
|
),
|
||||||
|
build_describe_case(name="Invalid metric name", metric_name=length_over_255,),
|
||||||
|
build_describe_case(
|
||||||
|
name="Invalid metric namespace", metric_namespace=length_over_255,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
for test_case in test_cases:
|
||||||
|
with pytest.raises(ClientError) as exc:
|
||||||
|
conn.describe_metric_filters(**test_case["input"])
|
||||||
|
response = exc.value.response
|
||||||
|
response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
|
||||||
|
response["Error"]["Code"].should.equal("InvalidParameterException")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_logs
|
||||||
|
def test_describe_metric_filters_multiple_happy():
|
||||||
|
conn = boto3.client("logs", "us-west-2")
|
||||||
|
|
||||||
|
response = put_metric_filter(conn, 1)
|
||||||
|
assert response["ResponseMetadata"]["HTTPStatusCode"] == 200
|
||||||
|
|
||||||
|
response = put_metric_filter(conn, 2)
|
||||||
|
assert response["ResponseMetadata"]["HTTPStatusCode"] == 200
|
||||||
|
response = conn.describe_metric_filters(
|
||||||
|
filterNamePrefix="filter", logGroupName="logGroupName1"
|
||||||
|
)
|
||||||
|
assert response["metricFilters"][0]["filterName"] == "filterName1"
|
||||||
|
|
||||||
|
response = conn.describe_metric_filters(filterNamePrefix="filter")
|
||||||
|
assert response["metricFilters"][0]["filterName"] == "filterName1"
|
||||||
|
|
||||||
|
response = conn.describe_metric_filters(logGroupName="logGroupName1")
|
||||||
|
assert response["metricFilters"][0]["filterName"] == "filterName1"
|
||||||
|
|
||||||
|
|
||||||
|
@mock_logs
|
||||||
|
def test_delete_metric_filter():
|
||||||
|
conn = boto3.client("logs", "us-west-2")
|
||||||
|
|
||||||
|
response = put_metric_filter(conn, 1)
|
||||||
|
assert response["ResponseMetadata"]["HTTPStatusCode"] == 200
|
||||||
|
|
||||||
|
response = put_metric_filter(conn, 2)
|
||||||
|
assert response["ResponseMetadata"]["HTTPStatusCode"] == 200
|
||||||
|
|
||||||
|
response = conn.delete_metric_filter(
|
||||||
|
filterName="filterName", logGroupName="logGroupName1"
|
||||||
|
)
|
||||||
|
assert response["ResponseMetadata"]["HTTPStatusCode"] == 200
|
||||||
|
|
||||||
|
response = conn.describe_metric_filters(
|
||||||
|
filterNamePrefix="filter", logGroupName="logGroupName2"
|
||||||
|
)
|
||||||
|
assert response["metricFilters"][0]["filterName"] == "filterName2"
|
||||||
|
|
||||||
|
response = conn.describe_metric_filters(logGroupName="logGroupName2")
|
||||||
|
assert response["metricFilters"][0]["filterName"] == "filterName2"
|
||||||
|
|
||||||
|
|
||||||
|
@mock_logs
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"filter_name, failing_constraint",
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"X" * 513,
|
||||||
|
"Minimum length of 1. Maximum length of 512.",
|
||||||
|
), # filterName too long
|
||||||
|
("x:x", "Must match pattern"), # invalid filterName pattern
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_delete_metric_filter_invalid_filter_name(filter_name, failing_constraint):
|
||||||
|
conn = boto3.client("logs", "us-west-2")
|
||||||
|
with pytest.raises(ClientError) as exc:
|
||||||
|
conn.delete_metric_filter(filterName=filter_name, logGroupName="valid")
|
||||||
|
response = exc.value.response
|
||||||
|
response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
|
||||||
|
response["Error"]["Code"].should.equal("InvalidParameterException")
|
||||||
|
response["Error"]["Message"].should.contain(
|
||||||
|
f"Value '{filter_name}' at 'filterName' failed to satisfy constraint"
|
||||||
|
)
|
||||||
|
response["Error"]["Message"].should.contain(failing_constraint)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_logs
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"log_group_name, failing_constraint",
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"X" * 513,
|
||||||
|
"Minimum length of 1. Maximum length of 512.",
|
||||||
|
), # logGroupName too long
|
||||||
|
("x!x", "Must match pattern"), # invalid logGroupName pattern
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_delete_metric_filter_invalid_log_group_name(
|
||||||
|
log_group_name, failing_constraint
|
||||||
|
):
|
||||||
|
conn = boto3.client("logs", "us-west-2")
|
||||||
|
with pytest.raises(ClientError) as exc:
|
||||||
|
conn.delete_metric_filter(filterName="valid", logGroupName=log_group_name)
|
||||||
|
response = exc.value.response
|
||||||
|
response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
|
||||||
|
response["Error"]["Code"].should.equal("InvalidParameterException")
|
||||||
|
response["Error"]["Message"].should.contain(
|
||||||
|
f"Value '{log_group_name}' at 'logGroupName' failed to satisfy constraint"
|
||||||
|
)
|
||||||
|
response["Error"]["Message"].should.contain(failing_constraint)
|
||||||
|
|
||||||
|
|
||||||
|
def put_metric_filter(conn, count=1):
|
||||||
|
count = str(count)
|
||||||
|
return conn.put_metric_filter(
|
||||||
|
filterName="filterName" + count,
|
||||||
|
filterPattern="filterPattern" + count,
|
||||||
|
logGroupName="logGroupName" + count,
|
||||||
|
metricTransformations=[
|
||||||
|
{
|
||||||
|
"defaultValue": int(count),
|
||||||
|
"metricName": "metricName" + count,
|
||||||
|
"metricNamespace": "metricNamespace" + count,
|
||||||
|
"metricValue": "metricValue" + count,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def build_put_case(
|
||||||
|
name,
|
||||||
|
filter_name="filterName",
|
||||||
|
filter_pattern="filterPattern",
|
||||||
|
log_group_name="logGroupName",
|
||||||
|
metric_transformations=None,
|
||||||
|
):
|
||||||
|
return {
|
||||||
|
"name": name,
|
||||||
|
"input": build_put_input(
|
||||||
|
filter_name, filter_pattern, log_group_name, metric_transformations
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def build_put_input(
|
||||||
|
filter_name, filter_pattern, log_group_name, metric_transformations
|
||||||
|
):
|
||||||
|
if metric_transformations is None:
|
||||||
|
metric_transformations = [
|
||||||
|
{
|
||||||
|
"defaultValue": 1,
|
||||||
|
"metricName": "metricName",
|
||||||
|
"metricNamespace": "metricNamespace",
|
||||||
|
"metricValue": "metricValue",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
return {
|
||||||
|
"filterName": filter_name,
|
||||||
|
"filterPattern": filter_pattern,
|
||||||
|
"logGroupName": log_group_name,
|
||||||
|
"metricTransformations": metric_transformations,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def build_describe_input(
|
||||||
|
filter_name_prefix, log_group_name, metric_name, metric_namespace
|
||||||
|
):
|
||||||
|
return {
|
||||||
|
"filterNamePrefix": filter_name_prefix,
|
||||||
|
"logGroupName": log_group_name,
|
||||||
|
"metricName": metric_name,
|
||||||
|
"metricNamespace": metric_namespace,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def build_describe_case(
|
||||||
|
name,
|
||||||
|
filter_name_prefix="filterNamePrefix",
|
||||||
|
log_group_name="logGroupName",
|
||||||
|
metric_name="metricName",
|
||||||
|
metric_namespace="metricNamespace",
|
||||||
|
):
|
||||||
|
return {
|
||||||
|
"name": name,
|
||||||
|
"input": build_describe_input(
|
||||||
|
filter_name_prefix, log_group_name, metric_name, metric_namespace
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@mock_logs
|
@mock_logs
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"kms_key_id",
|
"kms_key_id",
|
||||||
|
Loading…
Reference in New Issue
Block a user