Implement Filter: Contains functionality for describe_params (#3189)

* Implement Filter: Contains functionality for describe_params

This commit adds the Contains functionality. Tests were created
to mimic behavior in AWS/boto3, including that filters with values
in the form of `/name` will match parameters named `/name/match` but
not parameters named `match/with/other-name`. In the test example, a
Contains filter with the value `/tan` would match: `/tangent-3` and
`tangram-4` but not `standby-5`.

* Enforce parameter filter restrictions on get_parameters_by_path

According to the boto3 documentation [1], `Name`, `Path`, and `Tier` are not
allowed values for `Key` in a parameter filter for `get_parameters_by_path`.

This commit enforces this by calling `_validate_parameter_filters` from the
`get_parameters_by_path` method, and adding a check to `_validate_parameter_filters`.

I added 3 test cases to `test_get_parameters_by_path` which check for the correct
exception when calling with a parameter filter using any of these keys.

* Code formatted to match style

* Refactored logic
This commit is contained in:
Jordan Reiter 2020-07-28 05:17:35 -04:00 committed by GitHub
parent 6adee0cbaf
commit 126f5a5155
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 64 additions and 2 deletions

View File

@ -965,6 +965,13 @@ class SimpleSystemManagerBackend(BaseBackend):
"The following filter key is not valid: Label. Valid filter keys include: [Path, Name, Type, KeyId, Tier]."
)
if by_path and key in ["Name", "Path", "Tier"]:
raise InvalidFilterKey(
"The following filter key is not valid: {key}. Valid filter keys include: [Type, KeyId].".format(
key=key
)
)
if not values:
raise InvalidFilterValue(
"The following filter values are missing : null for filter key Name."
@ -1024,7 +1031,10 @@ class SimpleSystemManagerBackend(BaseBackend):
)
)
if key != "Path" and option not in ["Equals", "BeginsWith"]:
allowed_options = ["Equals", "BeginsWith"]
if key == "Name":
allowed_options += ["Contains"]
if key != "Path" and option not in allowed_options:
raise InvalidFilterOption(
"The following filter option is not valid: {option}. Valid options include: [BeginsWith, Equals].".format(
option=option
@ -1084,6 +1094,9 @@ class SimpleSystemManagerBackend(BaseBackend):
max_results=10,
):
"""Implement the get-parameters-by-path-API in the backend."""
self._validate_parameter_filters(filters, by_path=True)
result = []
# path could be with or without a trailing /. we handle this
# difference here.
@ -1134,7 +1147,8 @@ class SimpleSystemManagerBackend(BaseBackend):
what = parameter.keyid
elif key == "Name":
what = "/" + parameter.name.lstrip("/")
values = ["/" + value.lstrip("/") for value in values]
if option != "Contains":
values = ["/" + value.lstrip("/") for value in values]
elif key == "Path":
what = "/" + parameter.name.lstrip("/")
values = ["/" + value.strip("/") for value in values]
@ -1147,6 +1161,8 @@ class SimpleSystemManagerBackend(BaseBackend):
what.startswith(value) for value in values
):
return False
elif option == "Contains" and not any(value in what for value in values):
return False
elif option == "Equals" and not any(what == value for value in values):
return False
elif option == "OneLevel":

View File

@ -198,6 +198,33 @@ def test_get_parameters_by_path():
len(response["Parameters"]).should.equal(1)
response.should_not.have.key("NextToken")
filters = [{"Key": "Name", "Values": ["error"]}]
client.get_parameters_by_path.when.called_with(
Path="/baz", ParameterFilters=filters
).should.throw(
ClientError,
"The following filter key is not valid: Name. "
"Valid filter keys include: [Type, KeyId].",
)
filters = [{"Key": "Path", "Values": ["/error"]}]
client.get_parameters_by_path.when.called_with(
Path="/baz", ParameterFilters=filters
).should.throw(
ClientError,
"The following filter key is not valid: Path. "
"Valid filter keys include: [Type, KeyId].",
)
filters = [{"Key": "Tier", "Values": ["Standard"]}]
client.get_parameters_by_path.when.called_with(
Path="/baz", ParameterFilters=filters
).should.throw(
ClientError,
"The following filter key is not valid: Tier. "
"Valid filter keys include: [Type, KeyId].",
)
@mock_ssm
def test_put_parameter():
@ -504,6 +531,9 @@ def test_describe_parameters_with_parameter_filters_name():
client = boto3.client("ssm", region_name="us-east-1")
client.put_parameter(Name="param", Value="value", Type="String")
client.put_parameter(Name="/param-2", Value="value-2", Type="String")
client.put_parameter(Name="/tangent-3", Value="value-3", Type="String")
client.put_parameter(Name="tangram-4", Value="value-4", Type="String")
client.put_parameter(Name="standby-5", Value="value-5", Type="String")
response = client.describe_parameters(
ParameterFilters=[{"Key": "Name", "Values": ["param"]}]
@ -543,6 +573,22 @@ def test_describe_parameters_with_parameter_filters_name():
parameters.should.have.length_of(2)
response.should_not.have.key("NextToken")
response = client.describe_parameters(
ParameterFilters=[{"Key": "Name", "Option": "Contains", "Values": ["ram"]}]
)
parameters = response["Parameters"]
parameters.should.have.length_of(3)
response.should_not.have.key("NextToken")
response = client.describe_parameters(
ParameterFilters=[{"Key": "Name", "Option": "Contains", "Values": ["/tan"]}]
)
parameters = response["Parameters"]
parameters.should.have.length_of(2)
response.should_not.have.key("NextToken")
@mock_ssm
def test_describe_parameters_with_parameter_filters_path():