Fix: nextToken
value in logs:DescribeLogGroups response (#3398)
The pagination for this endpoint has been modified to more closely model the real AWS behavior: * Log Groups are now sorted alphabetically by `logGroupName`. * `nextToken` is now a string containing the last `logGroupName` in the current response. * Specifying an invalid `nextToken` does not generate an error, but does return an empty group list. * `nextToken` is not included in the response if there are no additional items to return. Fixes #3395
This commit is contained in:
parent
fcc85a9645
commit
9eb58eea41
@ -485,20 +485,39 @@ class LogsBackend(BaseBackend):
|
|||||||
def describe_log_groups(self, limit, log_group_name_prefix, next_token):
|
def describe_log_groups(self, limit, log_group_name_prefix, next_token):
|
||||||
if log_group_name_prefix is None:
|
if log_group_name_prefix is None:
|
||||||
log_group_name_prefix = ""
|
log_group_name_prefix = ""
|
||||||
if next_token is None:
|
|
||||||
next_token = 0
|
|
||||||
|
|
||||||
groups = [
|
groups = [
|
||||||
group.to_describe_dict()
|
group.to_describe_dict()
|
||||||
for name, group in self.groups.items()
|
for name, group in self.groups.items()
|
||||||
if name.startswith(log_group_name_prefix)
|
if name.startswith(log_group_name_prefix)
|
||||||
]
|
]
|
||||||
groups = sorted(groups, key=lambda x: x["creationTime"], reverse=True)
|
groups = sorted(groups, key=lambda x: x["logGroupName"])
|
||||||
groups_page = groups[next_token : next_token + limit]
|
|
||||||
|
|
||||||
next_token += limit
|
index_start = 0
|
||||||
if next_token >= len(groups):
|
if next_token:
|
||||||
next_token = None
|
try:
|
||||||
|
index_start = (
|
||||||
|
next(
|
||||||
|
index
|
||||||
|
for (index, d) in enumerate(groups)
|
||||||
|
if d["logGroupName"] == next_token
|
||||||
|
)
|
||||||
|
+ 1
|
||||||
|
)
|
||||||
|
except StopIteration:
|
||||||
|
index_start = 0
|
||||||
|
# AWS returns an empty list if it receives an invalid token.
|
||||||
|
groups = []
|
||||||
|
|
||||||
|
index_end = index_start + limit
|
||||||
|
if index_end > len(groups):
|
||||||
|
index_end = len(groups)
|
||||||
|
|
||||||
|
groups_page = groups[index_start:index_end]
|
||||||
|
|
||||||
|
next_token = None
|
||||||
|
if groups_page and index_end < len(groups):
|
||||||
|
next_token = groups_page[-1]["logGroupName"]
|
||||||
|
|
||||||
return groups_page, next_token
|
return groups_page, next_token
|
||||||
|
|
||||||
|
@ -42,7 +42,10 @@ class LogsResponse(BaseResponse):
|
|||||||
groups, next_token = self.logs_backend.describe_log_groups(
|
groups, next_token = self.logs_backend.describe_log_groups(
|
||||||
limit, log_group_name_prefix, next_token
|
limit, log_group_name_prefix, next_token
|
||||||
)
|
)
|
||||||
return json.dumps({"logGroups": groups, "nextToken": next_token})
|
result = {"logGroups": groups}
|
||||||
|
if next_token:
|
||||||
|
result["nextToken"] = next_token
|
||||||
|
return json.dumps(result)
|
||||||
|
|
||||||
def create_log_stream(self):
|
def create_log_stream(self):
|
||||||
log_group_name = self._get_param("logGroupName")
|
log_group_name = self._get_param("logGroupName")
|
||||||
|
@ -458,3 +458,39 @@ def test_describe_subscription_filters_errors():
|
|||||||
ex.response["Error"]["Message"].should.equal(
|
ex.response["Error"]["Message"].should.equal(
|
||||||
"The specified log group does not exist"
|
"The specified log group does not exist"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_logs
|
||||||
|
def test_describe_log_groups_paging():
|
||||||
|
client = boto3.client("logs", "us-east-1")
|
||||||
|
|
||||||
|
group_names = [
|
||||||
|
"/aws/lambda/lowercase-dev",
|
||||||
|
"/aws/lambda/FileMonitoring",
|
||||||
|
"/aws/events/GetMetricData",
|
||||||
|
"/aws/lambda/fileAvailable",
|
||||||
|
]
|
||||||
|
|
||||||
|
for name in group_names:
|
||||||
|
client.create_log_group(logGroupName=name)
|
||||||
|
|
||||||
|
resp = client.describe_log_groups()
|
||||||
|
resp["logGroups"].should.have.length_of(4)
|
||||||
|
resp.should_not.have.key("nextToken")
|
||||||
|
|
||||||
|
resp = client.describe_log_groups(limit=2)
|
||||||
|
resp["logGroups"].should.have.length_of(2)
|
||||||
|
resp["nextToken"].should.equal("/aws/lambda/FileMonitoring")
|
||||||
|
|
||||||
|
resp = client.describe_log_groups(nextToken=resp["nextToken"], limit=1)
|
||||||
|
resp["logGroups"].should.have.length_of(1)
|
||||||
|
resp["nextToken"].should.equal("/aws/lambda/fileAvailable")
|
||||||
|
|
||||||
|
resp = client.describe_log_groups(nextToken=resp["nextToken"])
|
||||||
|
resp["logGroups"].should.have.length_of(1)
|
||||||
|
resp["logGroups"][0]["logGroupName"].should.equal("/aws/lambda/lowercase-dev")
|
||||||
|
resp.should_not.have.key("nextToken")
|
||||||
|
|
||||||
|
resp = client.describe_log_groups(nextToken="invalid-token")
|
||||||
|
resp["logGroups"].should.have.length_of(0)
|
||||||
|
resp.should_not.have.key("nextToken")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user