#3548 - Logs - Transform assertions into proper exceptions (#3744)

This commit is contained in:
Bert Blommers 2021-08-28 09:36:43 +01:00 committed by GitHub
parent ec70d3cd14
commit 34c00e7dbd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 193 additions and 12 deletions

View File

@ -15,8 +15,12 @@ class ResourceNotFoundException(LogsClientError):
class InvalidParameterException(LogsClientError):
def __init__(self, msg=None):
def __init__(self, msg=None, constraint=None, parameter=None, value=None):
self.code = 400
if constraint:
msg = "1 validation error detected: Value '{}' at '{}' failed to satisfy constraint: {}".format(
value, parameter, constraint
)
super().__init__(
"InvalidParameterException", msg or "A parameter is specified incorrectly."
)

View File

@ -153,6 +153,9 @@ class LogStream(BaseModel):
next_token,
start_from_head,
):
if limit is None:
limit = 10000
def filter_func(event):
if start_time and event.timestamp < start_time:
return False
@ -382,6 +385,8 @@ class LogGroup(BaseModel):
filter_pattern,
interleaved,
):
if not limit:
limit = 10000
streams = [
stream
for name, stream in self.streams.items()
@ -531,6 +536,12 @@ class LogsBackend(BaseBackend):
def create_log_group(self, log_group_name, tags, **kwargs):
if log_group_name in self.groups:
raise ResourceAlreadyExistsException()
if len(log_group_name) > 512:
raise InvalidParameterException(
constraint="Member must have length less than or equal to 512",
parameter="logGroupName",
value=log_group_name,
)
self.groups[log_group_name] = LogGroup(
self.region_name, log_group_name, tags, **kwargs
)
@ -547,6 +558,12 @@ class LogsBackend(BaseBackend):
del self.groups[log_group_name]
def describe_log_groups(self, limit, log_group_name_prefix, next_token):
if limit > 50:
raise InvalidParameterException(
constraint="Member must have value less than or equal to 50",
parameter="limit",
value=limit,
)
if log_group_name_prefix is None:
log_group_name_prefix = ""
@ -608,6 +625,22 @@ class LogsBackend(BaseBackend):
):
if log_group_name not in self.groups:
raise ResourceNotFoundException()
if limit > 50:
raise InvalidParameterException(
constraint="Member must have value less than or equal to 50",
parameter="limit",
value=limit,
)
if order_by not in ["LogStreamName", "LastEventTime"]:
raise InvalidParameterException(
constraint="Member must satisfy enum value set: [LogStreamName, LastEventTime]",
parameter="orderBy",
value=order_by,
)
if order_by == "LastEventTime" and log_stream_name_prefix:
raise InvalidParameterException(
msg="Cannot order by LastEventTime with a logStreamNamePrefix."
)
log_group = self.groups[log_group_name]
return log_group.describe_log_streams(
descending,
@ -641,6 +674,12 @@ class LogsBackend(BaseBackend):
):
if log_group_name not in self.groups:
raise ResourceNotFoundException()
if limit and limit > 1000:
raise InvalidParameterException(
constraint="Member must have value less than or equal to 10000",
parameter="limit",
value=limit,
)
log_group = self.groups[log_group_name]
return log_group.get_log_events(
log_group_name,
@ -665,6 +704,12 @@ class LogsBackend(BaseBackend):
):
if log_group_name not in self.groups:
raise ResourceNotFoundException()
if limit and limit > 1000:
raise InvalidParameterException(
constraint="Member must have value less than or equal to 10000",
parameter="limit",
value=limit,
)
log_group = self.groups[log_group_name]
return log_group.filter_log_events(
log_group_name,

View File

@ -27,7 +27,6 @@ class LogsResponse(BaseResponse):
log_group_name = self._get_param("logGroupName")
tags = self._get_param("tags")
kms_key_id = self._get_param("kmsKeyId")
assert 1 <= len(log_group_name) <= 512 # TODO: assert pattern
self.logs_backend.create_log_group(log_group_name, tags, kmsKeyId=kms_key_id)
return ""
@ -41,7 +40,6 @@ class LogsResponse(BaseResponse):
log_group_name_prefix = self._get_param("logGroupNamePrefix")
next_token = self._get_param("nextToken")
limit = self._get_param("limit", 50)
assert limit <= 50
groups, next_token = self.logs_backend.describe_log_groups(
limit, log_group_name_prefix, next_token
)
@ -67,13 +65,8 @@ class LogsResponse(BaseResponse):
log_stream_name_prefix = self._get_param("logStreamNamePrefix", "")
descending = self._get_param("descending", False)
limit = self._get_param("limit", 50)
assert limit <= 50
next_token = self._get_param("nextToken")
order_by = self._get_param("orderBy", "LogStreamName")
assert order_by in {"LogStreamName", "LastEventTime"}
if order_by == "LastEventTime":
assert not log_stream_name_prefix
streams, next_token = self.logs_backend.describe_log_streams(
descending,
@ -101,8 +94,7 @@ class LogsResponse(BaseResponse):
log_stream_name = self._get_param("logStreamName")
start_time = self._get_param("startTime")
end_time = self._get_param("endTime")
limit = self._get_param("limit", 10000)
assert limit <= 10000
limit = self._get_param("limit")
next_token = self._get_param("nextToken")
start_from_head = self._get_param("startFromHead", False)
@ -135,8 +127,7 @@ class LogsResponse(BaseResponse):
filter_pattern = self._get_param("filterPattern")
interleaved = self._get_param("interleaved", False)
end_time = self._get_param("endTime")
limit = self._get_param("limit", 10000)
assert limit <= 10000
limit = self._get_param("limit")
next_token = self._get_param("nextToken")
events, next_token, searched_streams = self.logs_backend.filter_log_events(

View File

@ -1,6 +1,7 @@
import json
import os
import time
import sure # noqa
from unittest import SkipTest
import boto3
@ -806,3 +807,143 @@ def test_start_query():
exc_value.response["Error"]["Message"].should.equal(
"The specified log group does not exist"
)
@pytest.mark.parametrize("nr_of_events", [10001, 1000000])
@mock_logs
def test_get_too_many_log_events(nr_of_events):
client = boto3.client("logs", "us-east-1")
log_group_name = "dummy"
log_stream_name = "stream"
client.create_log_group(logGroupName=log_group_name)
client.create_log_stream(logGroupName=log_group_name, logStreamName=log_stream_name)
with pytest.raises(ClientError) as ex:
client.get_log_events(
logGroupName=log_group_name,
logStreamName=log_stream_name,
limit=nr_of_events,
)
err = ex.value.response["Error"]
err["Code"].should.equal("InvalidParameterException")
err["Message"].should.contain("1 validation error detected")
err["Message"].should.contain(
"Value '{}' at 'limit' failed to satisfy constraint".format(nr_of_events)
)
err["Message"].should.contain("Member must have value less than or equal to 10000")
@pytest.mark.parametrize("nr_of_events", [10001, 1000000])
@mock_logs
def test_filter_too_many_log_events(nr_of_events):
client = boto3.client("logs", "us-east-1")
log_group_name = "dummy"
log_stream_name = "stream"
client.create_log_group(logGroupName=log_group_name)
client.create_log_stream(logGroupName=log_group_name, logStreamName=log_stream_name)
with pytest.raises(ClientError) as ex:
client.filter_log_events(
logGroupName=log_group_name,
logStreamNames=[log_stream_name],
limit=nr_of_events,
)
err = ex.value.response["Error"]
err["Code"].should.equal("InvalidParameterException")
err["Message"].should.contain("1 validation error detected")
err["Message"].should.contain(
"Value '{}' at 'limit' failed to satisfy constraint".format(nr_of_events)
)
err["Message"].should.contain("Member must have value less than or equal to 10000")
@pytest.mark.parametrize("nr_of_groups", [51, 100])
@mock_logs
def test_describe_too_many_log_groups(nr_of_groups):
client = boto3.client("logs", "us-east-1")
with pytest.raises(ClientError) as ex:
client.describe_log_groups(limit=nr_of_groups)
err = ex.value.response["Error"]
err["Code"].should.equal("InvalidParameterException")
err["Message"].should.contain("1 validation error detected")
err["Message"].should.contain(
"Value '{}' at 'limit' failed to satisfy constraint".format(nr_of_groups)
)
err["Message"].should.contain("Member must have value less than or equal to 50")
@pytest.mark.parametrize("nr_of_streams", [51, 100])
@mock_logs
def test_describe_too_many_log_streams(nr_of_streams):
client = boto3.client("logs", "us-east-1")
log_group_name = "dummy"
client.create_log_group(logGroupName=log_group_name)
with pytest.raises(ClientError) as ex:
client.describe_log_streams(logGroupName=log_group_name, limit=nr_of_streams)
err = ex.value.response["Error"]
err["Code"].should.equal("InvalidParameterException")
err["Message"].should.contain("1 validation error detected")
err["Message"].should.contain(
"Value '{}' at 'limit' failed to satisfy constraint".format(nr_of_streams)
)
err["Message"].should.contain("Member must have value less than or equal to 50")
@pytest.mark.parametrize("length", [513, 1000])
@mock_logs
def test_create_log_group_invalid_name_length(length):
log_group_name = "a" * length
client = boto3.client("logs", "us-east-1")
with pytest.raises(ClientError) as ex:
client.create_log_group(logGroupName=log_group_name)
err = ex.value.response["Error"]
err["Code"].should.equal("InvalidParameterException")
err["Message"].should.contain("1 validation error detected")
err["Message"].should.contain(
"Value '{}' at 'logGroupName' failed to satisfy constraint".format(
log_group_name
)
)
err["Message"].should.contain("Member must have length less than or equal to 512")
@pytest.mark.parametrize("invalid_orderby", ["", "sth", "LogStreamname"])
@mock_logs
def test_describe_log_streams_invalid_order_by(invalid_orderby):
client = boto3.client("logs", "us-east-1")
log_group_name = "dummy"
client.create_log_group(logGroupName=log_group_name)
with pytest.raises(ClientError) as ex:
client.describe_log_streams(
logGroupName=log_group_name, orderBy=invalid_orderby
)
err = ex.value.response["Error"]
err["Code"].should.equal("InvalidParameterException")
err["Message"].should.contain("1 validation error detected")
err["Message"].should.contain(
"Value '{}' at 'orderBy' failed to satisfy constraint".format(invalid_orderby)
)
err["Message"].should.contain(
"Member must satisfy enum value set: [LogStreamName, LastEventTime]"
)
@mock_logs
def test_describe_log_streams_no_prefix():
"""
From the docs: If orderBy is LastEventTime , you cannot specify [logStreamNamePrefix]
"""
client = boto3.client("logs", "us-east-1")
log_group_name = "dummy"
client.create_log_group(logGroupName=log_group_name)
with pytest.raises(ClientError) as ex:
client.describe_log_streams(
logGroupName=log_group_name,
orderBy="LastEventTime",
logStreamNamePrefix="sth",
)
err = ex.value.response["Error"]
err["Code"].should.equal("InvalidParameterException")
err["Message"].should.equal(
"Cannot order by LastEventTime with a logStreamNamePrefix."
)