moto/tests/test_ssm/test_ssm_boto3.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

2328 lines
77 KiB
Python
Raw Normal View History

import datetime
import re
import string
import uuid
import boto3
import botocore.exceptions
import pytest
from botocore.exceptions import ClientError
2024-01-07 12:03:33 +00:00
from moto import mock_aws
2022-08-13 09:49:43 +00:00
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
from moto.ssm.models import PARAMETER_HISTORY_MAX_RESULTS, PARAMETER_VERSION_LIMIT
from tests import EXAMPLE_AMI_ID
2024-01-07 12:03:33 +00:00
@mock_aws
def test_delete_parameter():
client = boto3.client("ssm", region_name="us-east-1")
client.put_parameter(
Name="test", Description="A test parameter", Value="value", Type="String"
)
response = client.get_parameters(Names=["test"])
assert len(response["Parameters"]) == 1
client.delete_parameter(Name="test")
response = client.get_parameters(Names=["test"])
assert len(response["Parameters"]) == 0
2017-09-18 20:46:07 +00:00
2024-01-07 12:03:33 +00:00
@mock_aws
def test_delete_nonexistent_parameter():
client = boto3.client("ssm", region_name="us-east-1")
2020-10-06 06:04:09 +00:00
with pytest.raises(ClientError) as ex:
client.delete_parameter(Name="test_noexist")
assert ex.value.response["Error"]["Code"] == "ParameterNotFound"
assert ex.value.response["Error"]["Message"] == "Parameter test_noexist not found."
2024-01-07 12:03:33 +00:00
@mock_aws
def test_delete_parameters():
client = boto3.client("ssm", region_name="us-east-1")
client.put_parameter(
Name="test", Description="A test parameter", Value="value", Type="String"
)
response = client.get_parameters(Names=["test"])
assert len(response["Parameters"]) == 1
result = client.delete_parameters(Names=["test", "invalid"])
assert len(result["DeletedParameters"]) == 1
assert len(result["InvalidParameters"]) == 1
response = client.get_parameters(Names=["test"])
assert len(response["Parameters"]) == 0
2017-09-18 20:46:07 +00:00
2024-01-07 12:03:33 +00:00
@mock_aws
def test_get_parameters_by_path():
client = boto3.client("ssm", region_name="us-east-1")
2022-12-10 22:36:09 +00:00
client.put_parameter(Name="/foo/name1", Value="value1", Type="String")
2022-12-10 22:36:09 +00:00
client.put_parameter(Name="/foo/name2", Value="value2", Type="String")
2022-12-10 22:36:09 +00:00
client.put_parameter(Name="/bar/name3", Value="value3", Type="String")
client.put_parameter(
Name="/bar/name3/name4",
Value="value4",
Type="String",
)
client.put_parameter(
Name="/baz/name1",
Description="A test parameter (list)",
Value="value1,value2,value3",
Type="StringList",
)
2022-12-10 22:36:09 +00:00
client.put_parameter(Name="/baz/name2", Value="value1", Type="String")
client.put_parameter(
Name="/baz/pwd",
Description="A secure test parameter",
Value="my_secret",
Type="SecureString",
KeyId="alias/aws/ssm",
)
2022-12-10 22:36:09 +00:00
client.put_parameter(Name="foo", Value="bar", Type="String")
2022-12-10 22:36:09 +00:00
client.put_parameter(Name="baz", Value="qux", Type="String")
response = client.get_parameters_by_path(Path="/", Recursive=False)
assert len(response["Parameters"]) == 2
assert {p["Value"] for p in response["Parameters"]} == set(["bar", "qux"])
assert {p["ARN"] for p in response["Parameters"]} == set(
[
f"arn:aws:ssm:us-east-1:{ACCOUNT_ID}:parameter/foo",
f"arn:aws:ssm:us-east-1:{ACCOUNT_ID}:parameter/baz",
]
)
for p in response["Parameters"]:
assert isinstance(p["LastModifiedDate"], datetime.datetime)
response = client.get_parameters_by_path(Path="/", Recursive=True)
assert len(response["Parameters"]) == 9
response = client.get_parameters_by_path(Path="/foo")
assert len(response["Parameters"]) == 2
assert {p["Value"] for p in response["Parameters"]} == set(["value1", "value2"])
response = client.get_parameters_by_path(Path="/bar", Recursive=False)
assert len(response["Parameters"]) == 1
assert response["Parameters"][0]["Value"] == "value3"
response = client.get_parameters_by_path(Path="/bar", Recursive=True)
assert len(response["Parameters"]) == 2
assert {p["Value"] for p in response["Parameters"]} == set(["value3", "value4"])
response = client.get_parameters_by_path(Path="/baz")
assert len(response["Parameters"]) == 3
2019-10-31 15:44:26 +00:00
filters = [{"Key": "Type", "Option": "Equals", "Values": ["StringList"]}]
response = client.get_parameters_by_path(Path="/baz", ParameterFilters=filters)
assert len(response["Parameters"]) == 1
assert {p["Name"] for p in response["Parameters"]} == set(["/baz/name1"])
# note: 'Option' is optional (default: 'Equals')
filters = [{"Key": "Type", "Values": ["StringList"]}]
response = client.get_parameters_by_path(Path="/baz", ParameterFilters=filters)
assert len(response["Parameters"]) == 1
assert {p["Name"] for p in response["Parameters"]} == set(["/baz/name1"])
2019-10-31 15:44:26 +00:00
filters = [{"Key": "Type", "Option": "Equals", "Values": ["String"]}]
response = client.get_parameters_by_path(Path="/baz", ParameterFilters=filters)
assert len(response["Parameters"]) == 1
assert {p["Name"] for p in response["Parameters"]} == set(["/baz/name2"])
2019-10-31 15:44:26 +00:00
filters = [
{"Key": "Type", "Option": "Equals", "Values": ["String", "SecureString"]}
]
response = client.get_parameters_by_path(Path="/baz", ParameterFilters=filters)
assert len(response["Parameters"]) == 2
assert {p["Name"] for p in response["Parameters"]} == set(
["/baz/name2", "/baz/pwd"]
)
2019-10-31 15:44:26 +00:00
filters = [{"Key": "Type", "Option": "BeginsWith", "Values": ["String"]}]
response = client.get_parameters_by_path(Path="/baz", ParameterFilters=filters)
assert len(response["Parameters"]) == 2
assert {p["Name"] for p in response["Parameters"]} == set(
["/baz/name1", "/baz/name2"]
)
filters = [{"Key": "KeyId", "Option": "Equals", "Values": ["alias/aws/ssm"]}]
response = client.get_parameters_by_path(Path="/baz", ParameterFilters=filters)
assert len(response["Parameters"]) == 1
assert {p["Name"] for p in response["Parameters"]} == set(["/baz/pwd"])
2019-10-31 15:44:26 +00:00
response = client.get_parameters_by_path(Path="/", Recursive=True, MaxResults=4)
assert len(response["Parameters"]) == 4
assert response["NextToken"] == "4"
response = client.get_parameters_by_path(
Path="/", Recursive=True, MaxResults=4, NextToken=response["NextToken"]
)
assert len(response["Parameters"]) == 4
assert response["NextToken"] == "8"
response = client.get_parameters_by_path(
Path="/", Recursive=True, MaxResults=4, NextToken=response["NextToken"]
)
assert len(response["Parameters"]) == 1
assert "NextToken" not in response
filters = [{"Key": "Name", "Values": ["error"]}]
with pytest.raises(ClientError) as client_err:
client.get_parameters_by_path(Path="/baz", ParameterFilters=filters)
assert client_err.value.response["Error"]["Message"] == (
"The following filter key is not valid: Name. "
"Valid filter keys include: [Type, KeyId]."
)
filters = [{"Key": "Path", "Values": ["/error"]}]
with pytest.raises(ClientError) as client_err:
client.get_parameters_by_path(Path="/baz", ParameterFilters=filters)
assert client_err.value.response["Error"]["Message"] == (
"The following filter key is not valid: Path. "
"Valid filter keys include: [Type, KeyId]."
)
filters = [{"Key": "Tier", "Values": ["Standard"]}]
with pytest.raises(ClientError) as client_err:
client.get_parameters_by_path(Path="/baz", ParameterFilters=filters)
assert client_err.value.response["Error"]["Message"] == (
"The following filter key is not valid: Tier. "
"Valid filter keys include: [Type, KeyId]."
)
# Label filter in get_parameters_by_path
client.label_parameter_version(Name="/foo/name2", Labels=["Label1"])
filters = [{"Key": "Label", "Values": ["Label1"]}]
response = client.get_parameters_by_path(Path="/foo", ParameterFilters=filters)
assert len(response["Parameters"]) == 1
assert {p["Name"] for p in response["Parameters"]} == set(["/foo/name2"])
@pytest.mark.parametrize("name", ["test", "my-cool-parameter"])
2024-01-07 12:03:33 +00:00
@mock_aws
def test_put_parameter(name):
client = boto3.client("ssm", region_name="us-east-1")
response = client.put_parameter(
Name=name, Description="A test parameter", Value="value", Type="String"
)
assert response["Version"] == 1
response = client.get_parameters(Names=[name], WithDecryption=False)
assert len(response["Parameters"]) == 1
assert response["Parameters"][0]["Name"] == name
assert response["Parameters"][0]["Value"] == "value"
assert response["Parameters"][0]["Type"] == "String"
assert response["Parameters"][0]["Version"] == 1
assert response["Parameters"][0]["DataType"] == "text"
assert isinstance(response["Parameters"][0]["LastModifiedDate"], datetime.datetime)
assert response["Parameters"][0]["ARN"] == (
f"arn:aws:ssm:us-east-1:{ACCOUNT_ID}:parameter/{name}"
)
initial_modification_date = response["Parameters"][0]["LastModifiedDate"]
try:
client.put_parameter(
Name=name, Description="desc 2", Value="value 2", Type="String"
)
raise RuntimeError("Should fail")
except botocore.exceptions.ClientError as err:
assert err.operation_name == "PutParameter"
assert err.response["Error"]["Message"] == (
"The parameter already exists. To overwrite this value, set the "
"overwrite option in the request to true."
)
response = client.get_parameters(Names=[name], WithDecryption=False)
# without overwrite nothing change
assert len(response["Parameters"]) == 1
assert response["Parameters"][0]["Name"] == name
assert response["Parameters"][0]["Value"] == "value"
assert response["Parameters"][0]["Type"] == "String"
assert response["Parameters"][0]["Version"] == 1
assert response["Parameters"][0]["DataType"] == "text"
assert response["Parameters"][0]["LastModifiedDate"] == initial_modification_date
assert response["Parameters"][0]["ARN"] == (
f"arn:aws:ssm:us-east-1:{ACCOUNT_ID}:parameter/{name}"
)
new_data_type = "aws:ec2:image"
# Cannot have tags and overwrite at the same time
with pytest.raises(ClientError) as ex:
response = client.put_parameter(
Name=name,
Description="desc 3",
Value="value 3",
Type="String",
Overwrite=True,
Tags=[{"Key": "foo", "Value": "bar"}],
DataType=new_data_type,
)
assert ex.value.response["Error"]["Code"] == "ValidationException"
response = client.put_parameter(
Name=name,
Description="desc 3",
Value="value 3",
Type="String",
Overwrite=True,
DataType=new_data_type,
)
assert response["Version"] == 2
response = client.get_parameters(Names=[name], WithDecryption=False)
# without overwrite nothing change
assert len(response["Parameters"]) == 1
assert response["Parameters"][0]["Name"] == name
assert response["Parameters"][0]["Value"] == "value 3"
assert response["Parameters"][0]["Type"] == "String"
assert response["Parameters"][0]["Version"] == 2
assert response["Parameters"][0]["DataType"] != "text"
assert response["Parameters"][0]["DataType"] == new_data_type
assert response["Parameters"][0]["LastModifiedDate"] != initial_modification_date
assert response["Parameters"][0]["ARN"] == (
f"arn:aws:ssm:us-east-1:{ACCOUNT_ID}:parameter/{name}"
)
2019-10-31 15:44:26 +00:00
2017-09-18 13:13:02 +00:00
@pytest.mark.parametrize("name", ["test", "my-cool-parameter"])
2024-01-07 12:03:33 +00:00
@mock_aws
def test_put_parameter_overwrite_preserves_metadata(name):
test_tag_key = "TestKey"
test_tag_value = "TestValue"
test_description = "A test parameter"
test_pattern = ".*"
test_key_id = "someKeyId"
client = boto3.client("ssm", region_name="us-east-1")
response = client.put_parameter(
Name=name,
Description=test_description,
Value="value",
Type="String",
Tags=[{"Key": test_tag_key, "Value": test_tag_value}],
AllowedPattern=test_pattern,
KeyId=test_key_id,
Tier="Standard",
Policies='["Expiration"]',
)
assert response["Version"] == 1
response = client.get_parameters(Names=[name], WithDecryption=False)
assert len(response["Parameters"]) == 1
assert response["Parameters"][0]["Name"] == name
assert response["Parameters"][0]["Value"] == "value"
assert response["Parameters"][0]["Type"] == "String"
assert response["Parameters"][0]["Version"] == 1
assert response["Parameters"][0]["DataType"] == "text"
assert isinstance(response["Parameters"][0]["LastModifiedDate"], datetime.datetime)
assert response["Parameters"][0]["ARN"] == (
f"arn:aws:ssm:us-east-1:{ACCOUNT_ID}:parameter/{name}"
)
initial_modification_date = response["Parameters"][0]["LastModifiedDate"]
# Verify that the tag got set
response = client.list_tags_for_resource(ResourceType="Parameter", ResourceId=name)
assert len(response["TagList"]) == 1
assert response["TagList"][0]["Key"] == test_tag_key
assert response["TagList"][0]["Value"] == test_tag_value
# Verify description is set
response = client.describe_parameters(
ParameterFilters=[
{
"Key": "Name",
"Option": "Equals",
"Values": [name],
},
]
)
assert len(response["Parameters"]) == 1
assert response["Parameters"][0]["Description"] == test_description
assert response["Parameters"][0]["AllowedPattern"] == test_pattern
assert response["Parameters"][0]["KeyId"] == test_key_id
# Overwrite just the value
response = client.put_parameter(Name=name, Value="value 2", Overwrite=True)
assert response["Version"] == 2
response = client.get_parameters(Names=[name], WithDecryption=False)
assert len(response["Parameters"]) == 1
assert response["Parameters"][0]["Name"] == name
assert response["Parameters"][0]["Value"] == "value 2"
assert response["Parameters"][0]["Type"] == "String"
assert response["Parameters"][0]["Version"] == 2
assert response["Parameters"][0]["DataType"] == "text"
assert response["Parameters"][0]["LastModifiedDate"] != initial_modification_date
assert response["Parameters"][0]["ARN"] == (
f"arn:aws:ssm:us-east-1:{ACCOUNT_ID}:parameter/{name}"
)
# Verify that tags are unchanged
response = client.list_tags_for_resource(ResourceType="Parameter", ResourceId=name)
assert len(response["TagList"]) == 1
assert response["TagList"][0]["Key"] == test_tag_key
assert response["TagList"][0]["Value"] == test_tag_value
# Verify description/tier/policies is unchanged
response = client.describe_parameters(
ParameterFilters=[{"Key": "Name", "Option": "Equals", "Values": [name]}]
)
assert len(response["Parameters"]) == 1
assert response["Parameters"][0]["Description"] == test_description
assert response["Parameters"][0]["AllowedPattern"] == test_pattern
assert response["Parameters"][0]["KeyId"] == test_key_id
assert response["Parameters"][0]["Tier"] == "Standard"
assert response["Parameters"][0]["Policies"] == [
{
"PolicyStatus": "Finished",
"PolicyText": "Expiration",
"PolicyType": "Expiration",
}
]
2024-01-07 12:03:33 +00:00
@mock_aws
def test_put_parameter_with_invalid_policy():
name = "some_param"
test_description = "A test parameter"
client = boto3.client("ssm", region_name="us-east-1")
client.put_parameter(
Name=name,
Description=test_description,
Value="value",
Type="String",
Policies="invalid json",
)
# Verify that an invalid policy does not break anything
param = client.describe_parameters(
ParameterFilters=[{"Key": "Name", "Option": "Equals", "Values": [name]}]
)["Parameters"][0]
assert "Policies" not in param
2024-01-07 12:03:33 +00:00
@mock_aws
def test_put_parameter_empty_string_value():
client = boto3.client("ssm", region_name="us-east-1")
with pytest.raises(ClientError) as e:
client.put_parameter(Name="test_name", Value="", Type="String")
ex = e.value
assert ex.operation_name == "PutParameter"
assert ex.response["ResponseMetadata"]["HTTPStatusCode"] == 400
assert "ValidationException" in ex.response["Error"]["Code"]
assert ex.response["Error"]["Message"] == (
"1 validation error detected: "
"Value '' at 'value' failed to satisfy constraint: "
"Member must have length greater than or equal to 1."
)
2024-01-07 12:03:33 +00:00
@mock_aws
def test_put_parameter_invalid_names():
client = boto3.client("ssm", region_name="us-east-1")
invalid_prefix_err = (
'Parameter name: can\'t be prefixed with "aws" or "ssm" (case-insensitive).'
)
with pytest.raises(ClientError) as client_err:
client.put_parameter(Name="ssm_test", Value="value", Type="String")
assert client_err.value.response["Error"]["Message"] == invalid_prefix_err
with pytest.raises(ClientError) as client_err:
client.put_parameter(Name="SSM_TEST", Value="value", Type="String")
assert client_err.value.response["Error"]["Message"] == invalid_prefix_err
with pytest.raises(ClientError) as client_err:
client.put_parameter(Name="aws_test", Value="value", Type="String")
assert client_err.value.response["Error"]["Message"] == invalid_prefix_err
with pytest.raises(ClientError) as client_err:
client.put_parameter(Name="AWS_TEST", Value="value", Type="String")
assert client_err.value.response["Error"]["Message"] == invalid_prefix_err
ssm_path = "/ssm_test/path/to/var"
with pytest.raises(ClientError) as client_err:
client.put_parameter(Name=ssm_path, Value="value", Type="String")
assert client_err.value.response["Error"]["Message"] == (
'Parameter name: can\'t be prefixed with "ssm" (case-insensitive). '
"If formed as a path, it can consist of sub-paths divided by slash "
"symbol; each sub-path can be formed as a mix of letters, numbers "
"and the following 3 symbols .-_"
)
ssm_path = "/SSM/PATH/TO/VAR"
with pytest.raises(ClientError) as client_err:
client.put_parameter(Name=ssm_path, Value="value", Type="String")
assert client_err.value.response["Error"]["Message"] == (
'Parameter name: can\'t be prefixed with "ssm" (case-insensitive). '
"If formed as a path, it can consist of sub-paths divided by slash "
"symbol; each sub-path can be formed as a mix of letters, numbers "
"and the following 3 symbols .-_"
)
aws_path = "/aws_test/path/to/var"
with pytest.raises(ClientError) as client_err:
client.put_parameter(Name=aws_path, Value="value", Type="String")
assert client_err.value.response["Error"]["Message"] == (
f"No access to reserved parameter name: {aws_path}."
)
aws_path = "/AWS/PATH/TO/VAR"
with pytest.raises(ClientError) as client_err:
client.put_parameter(Name=aws_path, Value="value", Type="String")
assert client_err.value.response["Error"]["Message"] == (
f"No access to reserved parameter name: {aws_path}."
)
2024-01-07 12:03:33 +00:00
@mock_aws
def test_put_parameter_china():
client = boto3.client("ssm", region_name="cn-north-1")
response = client.put_parameter(
Name="test", Description="A test parameter", Value="value", Type="String"
)
assert response["Version"] == 1
2017-09-18 13:13:02 +00:00
2024-01-07 12:03:33 +00:00
@mock_aws
@pytest.mark.parametrize("bad_data_type", ["not_text", "not_ec2", "something weird"])
def test_put_parameter_invalid_data_type(bad_data_type):
client = boto3.client("ssm", region_name="us-east-1")
with pytest.raises(ClientError) as e:
client.put_parameter(
Name="test_name", Value="some_value", Type="String", DataType=bad_data_type
)
ex = e.value
assert ex.operation_name == "PutParameter"
assert ex.response["ResponseMetadata"]["HTTPStatusCode"] == 400
assert "ValidationException" in ex.response["Error"]["Code"]
assert ex.response["Error"]["Message"] == (
f"The following data type is not supported: {bad_data_type}"
" (Data type names are all lowercase.)"
)
2024-01-07 12:03:33 +00:00
@mock_aws
2023-01-12 12:06:40 +00:00
def test_put_parameter_invalid_type():
client = boto3.client("ssm", region_name="us-east-1")
bad_type = "str" # correct value is String
with pytest.raises(ClientError) as e:
client.put_parameter(
Name="test_name", Value="some_value", Type=bad_type, DataType="text"
)
ex = e.value
assert ex.operation_name == "PutParameter"
assert ex.response["ResponseMetadata"]["HTTPStatusCode"] == 400
assert "ValidationException" in ex.response["Error"]["Code"]
assert ex.response["Error"]["Message"] == (
f"1 validation error detected: Value '{bad_type}' at 'type' "
"failed to satisfy constraint: Member must satisfy enum value set: "
"[SecureString, StringList, String]"
2023-01-12 12:06:40 +00:00
)
2024-01-07 12:03:33 +00:00
@mock_aws
def test_put_parameter_no_type():
client = boto3.client("ssm", "us-east-1")
with pytest.raises(ClientError) as e:
client.put_parameter(
Name="test_name",
Value="some_value",
)
ex = e.value
assert ex.operation_name == "PutParameter"
assert ex.response["ResponseMetadata"]["HTTPStatusCode"] == 400
assert ex.response["Error"]["Code"] == "ValidationException"
assert (
ex.response["Error"]["Message"]
== "A parameter type is required when you create a parameter."
)
# Ensure backend state is consistent
assert client.describe_parameters()
2024-01-07 12:03:33 +00:00
@mock_aws
def test_update_parameter():
# Setup
client = boto3.client("ssm", "us-east-1")
param_name = "test_param"
param_type = "String"
updated_value = "UpdatedValue"
client.put_parameter(
Description="Description",
Name=param_name,
Type=param_type,
Value="Value",
)
# Execute
response = client.put_parameter(
Name=param_name,
Overwrite=True,
Value=updated_value,
)
new_param = client.get_parameter(Name=param_name)
# Verify
assert response["ResponseMetadata"]["HTTPStatusCode"] == 200
assert new_param["Parameter"]["Type"] == param_type
assert new_param["Parameter"]["Value"] == updated_value
2024-01-07 12:03:33 +00:00
@mock_aws
def test_update_parameter_already_exists_error():
# Setup
client = boto3.client("ssm", "us-east-1")
client.put_parameter(
Description="Description",
Name="Name",
Type="String",
Value="Value",
)
# Execute
with pytest.raises(ClientError) as exc:
client.put_parameter(
Name="Name",
Value="UpdatedValue",
)
# Verify
ex = exc.value
assert ex.operation_name == "PutParameter"
assert ex.response["ResponseMetadata"]["HTTPStatusCode"] == 400
assert ex.response["Error"]["Code"] == "ParameterAlreadyExists"
assert ex.response["Error"]["Message"] == (
"The parameter already exists. To overwrite this value, set the "
"overwrite option in the request to true."
)
2024-01-07 12:03:33 +00:00
@mock_aws
2017-09-18 13:13:02 +00:00
def test_get_parameter():
client = boto3.client("ssm", region_name="us-east-1")
client.put_parameter(
Name="test", Description="A test parameter", Value="value", Type="String"
2017-09-18 13:13:02 +00:00
)
response = client.get_parameter(Name="test", WithDecryption=False)
assert response["Parameter"]["Name"] == "test"
assert response["Parameter"]["Value"] == "value"
assert response["Parameter"]["Type"] == "String"
assert response["Parameter"]["DataType"] == "text"
assert isinstance(response["Parameter"]["LastModifiedDate"], datetime.datetime)
assert response["Parameter"]["ARN"] == (
f"arn:aws:ssm:us-east-1:{ACCOUNT_ID}:parameter/test"
)
2024-01-07 12:03:33 +00:00
@mock_aws
def test_get_parameter_with_version_and_labels():
client = boto3.client("ssm", region_name="us-east-1")
client.put_parameter(
Name="test-1", Description="A test parameter", Value="value", Type="String"
)
client.put_parameter(
Name="test-2", Description="A test parameter", Value="value", Type="String"
)
client.label_parameter_version(
Name="test-2", ParameterVersion=1, Labels=["test-label"]
)
response = client.get_parameter(Name="test-1:1", WithDecryption=False)
assert response["Parameter"]["Name"] == "test-1"
assert response["Parameter"]["Value"] == "value"
assert response["Parameter"]["Type"] == "String"
assert response["Parameter"]["DataType"] == "text"
assert isinstance(response["Parameter"]["LastModifiedDate"], datetime.datetime)
assert response["Parameter"]["ARN"] == (
f"arn:aws:ssm:us-east-1:{ACCOUNT_ID}:parameter/test-1"
)
response = client.get_parameter(Name="test-2:1", WithDecryption=False)
assert response["Parameter"]["Name"] == "test-2"
assert response["Parameter"]["Value"] == "value"
assert response["Parameter"]["Type"] == "String"
assert response["Parameter"]["DataType"] == "text"
assert isinstance(response["Parameter"]["LastModifiedDate"], datetime.datetime)
assert response["Parameter"]["ARN"] == (
f"arn:aws:ssm:us-east-1:{ACCOUNT_ID}:parameter/test-2"
)
response = client.get_parameter(Name="test-2:test-label", WithDecryption=False)
assert response["Parameter"]["Name"] == "test-2"
assert response["Parameter"]["Value"] == "value"
assert response["Parameter"]["Type"] == "String"
assert response["Parameter"]["DataType"] == "text"
assert isinstance(response["Parameter"]["LastModifiedDate"], datetime.datetime)
assert response["Parameter"]["ARN"] == (
f"arn:aws:ssm:us-east-1:{ACCOUNT_ID}:parameter/test-2"
)
2020-10-06 06:04:09 +00:00
with pytest.raises(ClientError) as ex:
client.get_parameter(Name="test-2:2:3", WithDecryption=False)
assert ex.value.response["Error"]["Code"] == "ParameterNotFound"
assert ex.value.response["Error"]["Message"] == ("Parameter test-2:2:3 not found.")
2020-10-06 06:04:09 +00:00
with pytest.raises(ClientError) as ex:
client.get_parameter(Name="test-2:2", WithDecryption=False)
assert ex.value.response["Error"]["Code"] == "ParameterVersionNotFound"
assert ex.value.response["Error"]["Message"] == (
"Systems Manager could not find version 2 of test-2. Verify the version and try again."
)
with pytest.raises(ClientError) as ex:
client.get_parameter(Name="test-3:2", WithDecryption=False)
assert ex.value.response["Error"]["Code"] == "ParameterNotFound"
assert ex.value.response["Error"]["Message"] == "Parameter test-3:2 not found."
2024-01-07 12:03:33 +00:00
@mock_aws
def test_get_parameters_errors():
client = boto3.client("ssm", region_name="us-east-1")
ssm_parameters = {name: "value" for name in string.ascii_lowercase[:11]}
for name, value in ssm_parameters.items():
client.put_parameter(Name=name, Value=value, Type="String")
2020-10-06 06:04:09 +00:00
with pytest.raises(ClientError) as e:
client.get_parameters(Names=list(ssm_parameters.keys()))
2020-10-06 06:04:09 +00:00
ex = e.value
assert ex.operation_name == "GetParameters"
assert ex.response["ResponseMetadata"]["HTTPStatusCode"] == 400
assert "ValidationException" in ex.response["Error"]["Code"]
all_keys = ", ".join(ssm_parameters.keys())
assert ex.response["Error"]["Message"] == (
"1 validation error detected: "
f"Value '[{all_keys}]' at 'names' failed to satisfy constraint: "
"Member must have length less than or equal to 10."
)
2024-01-07 12:03:33 +00:00
@mock_aws
def test_get_nonexistant_parameter():
client = boto3.client("ssm", region_name="us-east-1")
try:
client.get_parameter(Name="test_noexist", WithDecryption=False)
raise RuntimeError("Should have failed")
except botocore.exceptions.ClientError as err:
assert err.operation_name == "GetParameter"
assert err.response["Error"]["Message"] == "Parameter test_noexist not found."
2024-01-07 12:03:33 +00:00
@mock_aws
2017-06-20 18:47:53 +00:00
def test_describe_parameters():
client = boto3.client("ssm", region_name="us-east-1")
client.put_parameter(
Name="test",
Description="A test parameter",
Value="value",
Type="String",
AllowedPattern=r".*",
)
2017-06-20 18:47:53 +00:00
response = client.describe_parameters()
parameters = response["Parameters"]
assert len(parameters) == 1
assert parameters[0]["Name"] == "test"
assert parameters[0]["Type"] == "String"
assert parameters[0]["DataType"] == "text"
assert parameters[0]["AllowedPattern"] == r".*"
2017-06-20 18:47:53 +00:00
2024-01-07 12:03:33 +00:00
@mock_aws
2017-06-20 18:47:53 +00:00
def test_describe_parameters_paging():
client = boto3.client("ssm", region_name="us-east-1")
for i in range(50):
client.put_parameter(Name=f"param-{i}", Value=f"value-{i}", Type="String")
2017-06-20 18:47:53 +00:00
response = client.describe_parameters()
assert len(response["Parameters"]) == 10
assert response["NextToken"] == "10"
2017-06-20 18:47:53 +00:00
response = client.describe_parameters(NextToken=response["NextToken"])
assert len(response["Parameters"]) == 10
assert response["NextToken"] == "20"
2017-06-20 18:47:53 +00:00
response = client.describe_parameters(NextToken=response["NextToken"])
assert len(response["Parameters"]) == 10
assert response["NextToken"] == "30"
2017-06-20 18:47:53 +00:00
response = client.describe_parameters(NextToken=response["NextToken"])
assert len(response["Parameters"]) == 10
assert response["NextToken"] == "40"
2017-06-20 18:47:53 +00:00
response = client.describe_parameters(NextToken=response["NextToken"])
assert len(response["Parameters"]) == 10
assert response["NextToken"] == "50"
2017-06-20 18:47:53 +00:00
response = client.describe_parameters(NextToken=response["NextToken"])
assert len(response["Parameters"]) == 0
assert "NextToken" not in response
2017-06-20 18:47:53 +00:00
2017-06-26 18:20:56 +00:00
2024-01-07 12:03:33 +00:00
@mock_aws
2017-06-20 18:47:53 +00:00
def test_describe_parameters_filter_names():
client = boto3.client("ssm", region_name="us-east-1")
for i in range(50):
p = {"Name": f"param-{i}", "Value": f"value-{i}", "Type": "String"}
2017-06-20 18:47:53 +00:00
if i % 5 == 0:
p["Type"] = "SecureString"
p["KeyId"] = "a key"
client.put_parameter(**p)
response = client.describe_parameters(
2017-06-26 18:17:36 +00:00
Filters=[{"Key": "Name", "Values": ["param-22"]}]
2017-06-20 18:47:53 +00:00
)
parameters = response["Parameters"]
assert len(parameters) == 1
assert parameters[0]["Name"] == "param-22"
assert parameters[0]["Type"] == "String"
assert "NextToken" not in response
2017-06-20 18:47:53 +00:00
2017-06-26 18:20:56 +00:00
2024-01-07 12:03:33 +00:00
@mock_aws
2017-06-20 18:47:53 +00:00
def test_describe_parameters_filter_type():
client = boto3.client("ssm", region_name="us-east-1")
for i in range(50):
p = {"Name": f"param-{i}", "Value": f"value-{i}", "Type": "String"}
2017-06-20 18:47:53 +00:00
if i % 5 == 0:
p["Type"] = "SecureString"
p["KeyId"] = "a key"
client.put_parameter(**p)
response = client.describe_parameters(
Filters=[{"Key": "Type", "Values": ["SecureString"]}]
)
parameters = response["Parameters"]
assert len(parameters) == 10
assert parameters[0]["Type"] == "SecureString"
assert response["NextToken"] == "10"
2017-06-20 18:47:53 +00:00
2017-06-26 18:20:56 +00:00
2024-01-07 12:03:33 +00:00
@mock_aws
2017-06-20 18:47:53 +00:00
def test_describe_parameters_filter_keyid():
client = boto3.client("ssm", region_name="us-east-1")
for i in range(50):
p = {"Name": f"param-{i}", "Value": f"value-{i}", "Type": "String"}
2017-06-20 18:47:53 +00:00
if i % 5 == 0:
p["Type"] = "SecureString"
p["KeyId"] = f"key:{i}"
2017-06-20 18:47:53 +00:00
client.put_parameter(**p)
response = client.describe_parameters(
2017-06-26 18:17:36 +00:00
Filters=[{"Key": "KeyId", "Values": ["key:10"]}]
2017-06-20 18:47:53 +00:00
)
parameters = response["Parameters"]
assert len(parameters) == 1
assert parameters[0]["Name"] == "param-10"
assert parameters[0]["Type"] == "SecureString"
assert "NextToken" not in response
2024-01-07 12:03:33 +00:00
@mock_aws
def test_describe_parameters_with_parameter_filters_keyid():
client = boto3.client("ssm", region_name="us-east-1")
client.put_parameter(Name="secure-param", Value="secure-value", Type="SecureString")
client.put_parameter(
Name="custom-secure-param",
Value="custom-secure-value",
Type="SecureString",
KeyId="alias/custom",
)
client.put_parameter(Name="param", Value="value", Type="String")
response = client.describe_parameters(
ParameterFilters=[{"Key": "KeyId", "Values": ["alias/aws/ssm"]}]
)
parameters = response["Parameters"]
assert len(parameters) == 1
assert parameters[0]["Name"] == "secure-param"
assert parameters[0]["Type"] == "SecureString"
assert "NextToken" not in response
response = client.describe_parameters(
ParameterFilters=[{"Key": "KeyId", "Values": ["alias/custom"]}]
)
parameters = response["Parameters"]
assert len(parameters) == 1
assert parameters[0]["Name"] == "custom-secure-param"
assert parameters[0]["Type"] == "SecureString"
assert "NextToken" not in response
response = client.describe_parameters(
ParameterFilters=[{"Key": "KeyId", "Option": "BeginsWith", "Values": ["alias"]}]
)
parameters = response["Parameters"]
assert len(parameters) == 2
assert "NextToken" not in response
2024-01-07 12:03:33 +00:00
@mock_aws
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"]}]
)
parameters = response["Parameters"]
assert len(parameters) == 1
assert parameters[0]["Name"] == "param"
assert parameters[0]["Type"] == "String"
assert "NextToken" not in response
response = client.describe_parameters(
ParameterFilters=[{"Key": "Name", "Values": ["/param"]}]
)
parameters = response["Parameters"]
assert len(parameters) == 1
assert parameters[0]["Name"] == "param"
assert parameters[0]["Type"] == "String"
assert "NextToken" not in response
response = client.describe_parameters(
ParameterFilters=[{"Key": "Name", "Values": ["param-2"]}]
)
parameters = response["Parameters"]
assert len(parameters) == 1
assert parameters[0]["Name"] == "/param-2"
assert parameters[0]["Type"] == "String"
assert "NextToken" not in response
response = client.describe_parameters(
ParameterFilters=[{"Key": "Name", "Option": "BeginsWith", "Values": ["param"]}]
)
parameters = response["Parameters"]
assert len(parameters) == 2
assert "NextToken" not in response
response = client.describe_parameters(
ParameterFilters=[{"Key": "Name", "Option": "Contains", "Values": ["ram"]}]
)
parameters = response["Parameters"]
assert len(parameters) == 3
assert "NextToken" not in response
response = client.describe_parameters(
ParameterFilters=[{"Key": "Name", "Option": "Contains", "Values": ["/tan"]}]
)
parameters = response["Parameters"]
assert len(parameters) == 2
assert "NextToken" not in response
2024-01-07 12:03:33 +00:00
@mock_aws
def test_describe_parameters_with_parameter_filters_path():
client = boto3.client("ssm", region_name="us-east-1")
client.put_parameter(Name="/foo/name1", Value="value1", Type="String")
client.put_parameter(Name="/foo/name2", Value="value2", Type="String")
client.put_parameter(Name="/bar/name3", Value="value3", Type="String")
client.put_parameter(Name="/bar/name3/name4", Value="value4", Type="String")
client.put_parameter(Name="foo", Value="bar", Type="String")
response = client.describe_parameters(
ParameterFilters=[{"Key": "Path", "Values": ["/fo"]}]
)
parameters = response["Parameters"]
assert len(parameters) == 0
assert "NextToken" not in response
response = client.describe_parameters(
ParameterFilters=[{"Key": "Path", "Values": ["/"]}]
)
parameters = response["Parameters"]
assert len(parameters) == 1
assert parameters[0]["Name"] == "foo"
assert parameters[0]["Type"] == "String"
assert "NextToken" not in response
response = client.describe_parameters(
ParameterFilters=[{"Key": "Path", "Values": ["/", "/foo"]}]
)
parameters = response["Parameters"]
assert len(parameters) == 3
assert {parameter["Name"] for parameter in response["Parameters"]} == {
"/foo/name1",
"/foo/name2",
"foo",
}
assert "NextToken" not in response
response = client.describe_parameters(
ParameterFilters=[{"Key": "Path", "Values": ["/foo/"]}]
)
parameters = response["Parameters"]
assert len(parameters) == 2
assert {parameter["Name"] for parameter in response["Parameters"]} == {
"/foo/name1",
"/foo/name2",
}
assert "NextToken" not in response
response = client.describe_parameters(
ParameterFilters=[
{"Key": "Path", "Option": "OneLevel", "Values": ["/bar/name3"]}
]
)
parameters = response["Parameters"]
assert len(parameters) == 1
assert parameters[0]["Name"] == "/bar/name3/name4"
assert parameters[0]["Type"] == "String"
assert "NextToken" not in response
response = client.describe_parameters(
ParameterFilters=[{"Key": "Path", "Option": "Recursive", "Values": ["/fo"]}]
)
parameters = response["Parameters"]
assert len(parameters) == 0
assert "NextToken" not in response
response = client.describe_parameters(
ParameterFilters=[{"Key": "Path", "Option": "Recursive", "Values": ["/"]}]
)
parameters = response["Parameters"]
assert len(parameters) == 5
assert "NextToken" not in response
response = client.describe_parameters(
ParameterFilters=[
{"Key": "Path", "Option": "Recursive", "Values": ["/foo", "/bar"]}
]
)
parameters = response["Parameters"]
assert len(parameters) == 4
assert {parameter["Name"] for parameter in response["Parameters"]} == {
"/foo/name1",
"/foo/name2",
"/bar/name3",
"/bar/name3/name4",
}
assert "NextToken" not in response
response = client.describe_parameters(
ParameterFilters=[{"Key": "Path", "Option": "Recursive", "Values": ["/foo/"]}]
)
parameters = response["Parameters"]
assert len(parameters) == 2
assert {parameter["Name"] for parameter in response["Parameters"]} == {
"/foo/name1",
"/foo/name2",
}
assert "NextToken" not in response
response = client.describe_parameters(
ParameterFilters=[
{"Key": "Path", "Option": "Recursive", "Values": ["/bar/name3"]}
]
)
parameters = response["Parameters"]
assert len(parameters) == 1
assert parameters[0]["Name"] == "/bar/name3/name4"
assert parameters[0]["Type"] == "String"
assert "NextToken" not in response
2024-01-07 12:03:33 +00:00
@mock_aws
def test_describe_parameters_needs_param():
client = boto3.client("ssm", region_name="us-east-1")
with pytest.raises(ClientError) as client_err:
client.describe_parameters(
Filters=[{"Key": "Name", "Values": ["test"]}],
ParameterFilters=[{"Key": "Name", "Values": ["test"]}],
)
assert client_err.value.response["Error"]["Message"] == (
"You can use either Filters or ParameterFilters in a single request."
)
@pytest.mark.parametrize(
"filters,error_msg",
[
(
[{"Key": "key"}],
(
"Member must satisfy regular expression pattern: "
"tag:.+|Name|Type|KeyId|Path|Label|Tier"
),
2019-10-31 15:44:26 +00:00
),
(
[{"Key": "tag:" + "t" * 129}],
"Member must have length less than or equal to 132",
),
(
[{"Key": "Name", "Option": "over 10 chars"}],
"Member must have length less than or equal to 10",
),
(
[{"Key": "Name", "Values": ["test"] * 51}],
"Member must have length less than or equal to 50",
),
(
[{"Key": "Name", "Values": ["t" * 1025]}],
(
"Member must have length less than or equal to 1024, "
"Member must have length greater than or equal to 1"
),
),
(
[{"Key": "Name", "Option": "over 10 chars"}, {"Key": "key"}],
"2 validation errors detected:",
),
(
[{"Key": "Label"}],
(
"The following filter key is not valid: Label. Valid "
"filter keys include: [Path, Name, Type, KeyId, Tier]"
),
),
(
[{"Key": "Name"}],
"The following filter values are missing : null for filter key Name",
),
(
[
{"Key": "Name", "Values": ["test"]},
{"Key": "Name", "Values": ["test test"]},
],
(
"The following filter is duplicated in the request: Name. "
"A request can contain only one occurrence of a specific filter."
),
),
(
[{"Key": "Path", "Values": ["/aws", "/ssm"]}],
(
"Filters for common parameters can't be prefixed with "
'"aws" or "ssm" (case-insensitive).'
),
),
(
[{"Key": "Path", "Option": "Equals", "Values": ["test"]}],
(
"The following filter option is not valid: Equals. "
"Valid options include: [Recursive, OneLevel]"
),
),
(
[{"Key": "Tier", "Values": ["test"]}],
(
"The following filter value is not valid: test. Valid "
"values include: [Standard, Advanced, Intelligent-Tiering]"
),
),
(
[{"Key": "Type", "Values": ["test"]}],
(
"The following filter value is not valid: test. Valid "
"values include: [String, StringList, SecureString]"
),
),
(
[{"Key": "Name", "Option": "option", "Values": ["test"]}],
(
"The following filter option is not valid: option. Valid "
"options include: [BeginsWith, Equals]."
),
),
],
)
2024-01-07 12:03:33 +00:00
@mock_aws
def test_describe_parameters_invalid_parameter_filters(filters, error_msg):
client = boto3.client("ssm", region_name="us-east-1")
with pytest.raises(ClientError) as e:
client.describe_parameters(ParameterFilters=filters)
assert error_msg in e.value.response["Error"]["Message"]
@pytest.mark.parametrize("value", ["/###", "//", "test"])
2024-01-07 12:03:33 +00:00
@mock_aws
def test_describe_parameters_invalid_path(value):
client = boto3.client("ssm", region_name="us-east-1")
with pytest.raises(ClientError) as e:
client.describe_parameters(
ParameterFilters=[{"Key": "Path", "Values": [value]}]
)
msg = e.value.response["Error"]["Message"]
assert "The parameter doesn't meet the parameter name requirements" in msg
assert 'The parameter name must begin with a forward slash "/".' in msg
assert 'It can\'t be prefixed with "aws" or "ssm" (case-insensitive).' in msg
assert (
"It must use only letters, numbers, or the following symbols: . "
"(period), - (hyphen), _ (underscore)."
) in msg
assert (
"Special characters are not allowed. All sub-paths, if specified, "
'must use the forward slash symbol "/".'
) in msg
assert "Valid example: /get/parameters2-/by1./path0_." in msg
2024-01-07 12:03:33 +00:00
@mock_aws
def test_describe_parameters_attributes():
client = boto3.client("ssm", region_name="us-east-1")
client.put_parameter(
Name="aa", Value="11", Type="String", Description="my description"
)
client.put_parameter(Name="bb", Value="22", Type="String")
response = client.describe_parameters()
parameters = response["Parameters"]
assert len(parameters) == 2
assert parameters[0]["Description"] == "my description"
assert parameters[0]["Version"] == 1
assert isinstance(parameters[0]["LastModifiedDate"], datetime.date)
assert parameters[0]["LastModifiedUser"] == "N/A"
assert "Description" not in parameters[1]
assert parameters[1]["Version"] == 1
2017-06-26 18:20:56 +00:00
2024-01-07 12:03:33 +00:00
@mock_aws
2021-03-02 09:00:26 +00:00
def test_describe_parameters_tags():
client = boto3.client("ssm", region_name="us-east-1")
client.put_parameter(Name="/foo/bar", Value="spam", Type="String")
client.put_parameter(
Name="/spam/eggs",
Value="eggs",
Type="String",
Tags=[{"Key": "spam", "Value": "eggs"}],
)
parameters = client.describe_parameters(
2021-03-02 09:00:26 +00:00
ParameterFilters=[{"Key": "tag:spam", "Values": ["eggs"]}]
)["Parameters"]
assert len(parameters) == 1
assert parameters[0]["Name"] == "/spam/eggs"
# Verify we can filter by the existence of a tag
filters = [{"Key": "tag:spam"}]
response = client.describe_parameters(ParameterFilters=filters)
assert len(response["Parameters"]) == 1
assert {p["Name"] for p in response["Parameters"]} == set(["/spam/eggs"])
2021-03-02 09:00:26 +00:00
2024-01-07 12:03:33 +00:00
@mock_aws
2022-12-10 22:36:09 +00:00
def test_describe_parameters__multiple_tags():
client = boto3.client("ssm", region_name="us-east-1")
for x in "ab":
client.put_parameter(
Name=f"test_my_param_01_{x}",
Value=f"Contents of param {x}",
Type="String",
Tags=[{"Key": "hello", "Value": "world"}, {"Key": "x", "Value": x}],
)
response = client.describe_parameters(
ParameterFilters=[
{"Key": "tag:x", "Option": "Equals", "Values": ["b"]},
{"Key": "tag:hello", "Option": "Equals", "Values": ["world"]},
]
)
assert len(response["Parameters"]) == 1
2022-12-10 22:36:09 +00:00
# Both params contains hello:world - ensure we also check the second tag, x=b
response = client.describe_parameters(
ParameterFilters=[
{"Key": "tag:hello", "Option": "Equals", "Values": ["world"]},
{"Key": "tag:x", "Option": "Equals", "Values": ["b"]},
]
)
assert len(response["Parameters"]) == 1
2022-12-10 22:36:09 +00:00
# tag begins_with should also work
assert (
len(
client.describe_parameters(
ParameterFilters=[
{"Key": "tag:hello", "Option": "BeginsWith", "Values": ["w"]},
]
)["Parameters"]
)
== 2
)
assert (
len(
client.describe_parameters(
ParameterFilters=[
{"Key": "tag:x", "Option": "BeginsWith", "Values": ["a"]},
]
)["Parameters"]
)
== 1
)
2022-12-10 22:36:09 +00:00
2024-01-07 12:03:33 +00:00
@mock_aws
def test_tags_in_list_tags_from_resource_parameter():
client = boto3.client("ssm", region_name="us-east-1")
client.put_parameter(
Name="/spam/eggs",
Value="eggs",
Type="String",
Tags=[{"Key": "spam", "Value": "eggs"}],
)
tags = client.list_tags_for_resource(
ResourceId="/spam/eggs", ResourceType="Parameter"
)
assert tags.get("TagList") == [{"Key": "spam", "Value": "eggs"}]
client.delete_parameter(Name="/spam/eggs")
with pytest.raises(ClientError) as ex:
client.list_tags_for_resource(ResourceType="Parameter", ResourceId="/spam/eggs")
assert ex.value.response["Error"]["Code"] == "InvalidResourceId"
2024-01-07 12:03:33 +00:00
@mock_aws
def test_tags_invalid_resource_id():
client = boto3.client("ssm", region_name="us-east-1")
with pytest.raises(ClientError) as ex:
client.list_tags_for_resource(ResourceType="Parameter", ResourceId="bar")
assert ex.value.response["Error"]["Code"] == "InvalidResourceId"
2024-01-07 12:03:33 +00:00
@mock_aws
def test_tags_invalid_resource_type():
client = boto3.client("ssm", region_name="us-east-1")
with pytest.raises(ClientError) as ex:
client.list_tags_for_resource(ResourceType="foo", ResourceId="bar")
assert ex.value.response["Error"]["Code"] == "InvalidResourceType"
2024-01-07 12:03:33 +00:00
@mock_aws
def test_get_parameter_invalid():
client = client = boto3.client("ssm", region_name="us-east-1")
response = client.get_parameters(Names=["invalid"], WithDecryption=False)
assert len(response["Parameters"]) == 0
assert len(response["InvalidParameters"]) == 1
assert response["InvalidParameters"][0] == "invalid"
2024-01-07 12:03:33 +00:00
@mock_aws
def test_put_parameter_secure_default_kms():
client = boto3.client("ssm", region_name="us-east-1")
client.put_parameter(
Name="test", Description="A test parameter", Value="value", Type="SecureString"
)
response = client.get_parameters(Names=["test"], WithDecryption=False)
assert len(response["Parameters"]) == 1
assert response["Parameters"][0]["Name"] == "test"
assert response["Parameters"][0]["Value"] == "kms:alias/aws/ssm:value"
assert response["Parameters"][0]["Type"] == "SecureString"
2019-10-31 15:44:26 +00:00
response = client.get_parameters(Names=["test"], WithDecryption=True)
assert len(response["Parameters"]) == 1
assert response["Parameters"][0]["Name"] == "test"
assert response["Parameters"][0]["Value"] == "value"
assert response["Parameters"][0]["Type"] == "SecureString"
2024-01-07 12:03:33 +00:00
@mock_aws
def test_put_parameter_secure_custom_kms():
client = boto3.client("ssm", region_name="us-east-1")
client.put_parameter(
Name="test",
Description="A test parameter",
Value="value",
Type="SecureString",
KeyId="foo",
)
response = client.get_parameters(Names=["test"], WithDecryption=False)
assert len(response["Parameters"]) == 1
assert response["Parameters"][0]["Name"] == "test"
assert response["Parameters"][0]["Value"] == "kms:foo:value"
assert response["Parameters"][0]["Type"] == "SecureString"
response = client.get_parameters(Names=["test"], WithDecryption=True)
2019-10-31 15:44:26 +00:00
assert len(response["Parameters"]) == 1
assert response["Parameters"][0]["Name"] == "test"
assert response["Parameters"][0]["Value"] == "value"
assert response["Parameters"][0]["Type"] == "SecureString"
2019-11-04 18:04:10 +00:00
2024-01-07 12:03:33 +00:00
@mock_aws
def test_get_parameter_history():
client = boto3.client("ssm", region_name="us-east-1")
test_parameter_name = "test"
for i in range(3):
client.put_parameter(
2019-11-04 18:04:10 +00:00
Name=test_parameter_name,
Description=f"A test parameter version {i}",
Value=f"value-{i}",
2019-11-04 18:04:10 +00:00
Type="String",
Overwrite=True,
)
response = client.get_parameter_history(Name=test_parameter_name)
2019-11-04 18:04:10 +00:00
parameters_response = response["Parameters"]
for index, param in enumerate(parameters_response):
assert param["Name"] == test_parameter_name
assert param["Type"] == "String"
assert param["Value"] == f"value-{index}"
assert param["Version"] == index + 1
assert param["Description"] == f"A test parameter version {index}"
assert param["Labels"] == []
assert len(parameters_response) == 3
2019-11-04 18:04:10 +00:00
2024-01-07 12:03:33 +00:00
@mock_aws
def test_get_parameter_history_with_secure_string():
client = boto3.client("ssm", region_name="us-east-1")
test_parameter_name = "test"
for i in range(3):
client.put_parameter(
2019-11-04 18:04:10 +00:00
Name=test_parameter_name,
Description=f"A test parameter version {i}",
Value=f"value-{i}",
2019-11-04 18:04:10 +00:00
Type="SecureString",
Overwrite=True,
)
for with_decryption in [True, False]:
2019-11-04 18:04:10 +00:00
response = client.get_parameter_history(
Name=test_parameter_name, WithDecryption=with_decryption
)
parameters_response = response["Parameters"]
for index, param in enumerate(parameters_response):
assert param["Name"] == test_parameter_name
assert param["Type"] == "SecureString"
expected_plaintext_value = f"value-{index}"
if with_decryption:
assert param["Value"] == expected_plaintext_value
else:
assert param["Value"] == (
f"kms:alias/aws/ssm:{expected_plaintext_value}"
2019-11-04 18:04:10 +00:00
)
assert param["Version"] == index + 1
assert param["Description"] == f"A test parameter version {index}"
assert len(parameters_response) == 3
2024-01-07 12:03:33 +00:00
@mock_aws
def test_label_parameter_version():
client = boto3.client("ssm", region_name="us-east-1")
test_parameter_name = "test"
client.put_parameter(
Name=test_parameter_name,
Description="A test parameter",
Value="value",
Type="String",
)
response = client.label_parameter_version(
Name=test_parameter_name, Labels=["test-label"]
)
assert response["InvalidLabels"] == []
assert response["ParameterVersion"] == 1
2024-01-07 12:03:33 +00:00
@mock_aws
def test_label_parameter_version_with_specific_version():
client = boto3.client("ssm", region_name="us-east-1")
test_parameter_name = "test"
client.put_parameter(
Name=test_parameter_name,
Description="A test parameter",
Value="value",
Type="String",
)
response = client.label_parameter_version(
Name=test_parameter_name, ParameterVersion=1, Labels=["test-label"]
)
assert response["InvalidLabels"] == []
assert response["ParameterVersion"] == 1
2024-01-07 12:03:33 +00:00
@mock_aws
def test_label_parameter_version_twice():
client = boto3.client("ssm", region_name="us-east-1")
test_parameter_name = "test"
test_labels = ["test-label"]
client.put_parameter(
Name=test_parameter_name,
Description="A test parameter",
Value="value",
Type="String",
)
response = client.label_parameter_version(
Name=test_parameter_name, ParameterVersion=1, Labels=test_labels
)
assert response["InvalidLabels"] == []
assert response["ParameterVersion"] == 1
response = client.label_parameter_version(
Name=test_parameter_name, ParameterVersion=1, Labels=test_labels
)
assert response["InvalidLabels"] == []
assert response["ParameterVersion"] == 1
response = client.get_parameter_history(Name=test_parameter_name)
assert len(response["Parameters"]) == 1
assert response["Parameters"][0]["Labels"] == test_labels
2024-01-07 12:03:33 +00:00
@mock_aws
def test_label_parameter_moving_versions():
client = boto3.client("ssm", region_name="us-east-1")
test_parameter_name = "test"
test_labels = ["test-label"]
for i in range(3):
client.put_parameter(
Name=test_parameter_name,
Description=f"A test parameter version {i}",
Value=f"value-{i}",
Type="String",
Overwrite=True,
)
response = client.label_parameter_version(
Name=test_parameter_name, ParameterVersion=1, Labels=test_labels
)
assert response["InvalidLabels"] == []
assert response["ParameterVersion"] == 1
response = client.label_parameter_version(
Name=test_parameter_name, ParameterVersion=2, Labels=test_labels
)
assert response["InvalidLabels"] == []
assert response["ParameterVersion"] == 2
response = client.get_parameter_history(Name=test_parameter_name)
parameters_response = response["Parameters"]
for index, param in enumerate(parameters_response):
assert param["Name"] == test_parameter_name
assert param["Type"] == "String"
assert param["Value"] == f"value-{index}"
assert param["Version"] == index + 1
assert param["Description"] == f"A test parameter version {index}"
labels = test_labels if param["Version"] == 2 else []
assert param["Labels"] == labels
assert len(parameters_response) == 3
2024-01-07 12:03:33 +00:00
@mock_aws
def test_label_parameter_moving_versions_complex():
client = boto3.client("ssm", region_name="us-east-1")
test_parameter_name = "test"
for i in range(3):
client.put_parameter(
Name=test_parameter_name,
Description=f"A test parameter version {i}",
Value=f"value-{i}",
Type="String",
Overwrite=True,
)
response = client.label_parameter_version(
Name=test_parameter_name,
ParameterVersion=1,
Labels=["test-label1", "test-label2", "test-label3"],
)
assert response["InvalidLabels"] == []
assert response["ParameterVersion"] == 1
response = client.label_parameter_version(
Name=test_parameter_name,
ParameterVersion=2,
Labels=["test-label2", "test-label3"],
)
assert response["InvalidLabels"] == []
assert response["ParameterVersion"] == 2
response = client.get_parameter_history(Name=test_parameter_name)
parameters_response = response["Parameters"]
for index, param in enumerate(parameters_response):
assert param["Name"] == test_parameter_name
assert param["Type"] == "String"
assert param["Value"] == f"value-{index}"
assert param["Version"] == index + 1
assert param["Description"] == f"A test parameter version {index}"
labels = (
["test-label2", "test-label3"]
if param["Version"] == 2
else (["test-label1"] if param["Version"] == 1 else [])
)
assert param["Labels"] == labels
assert len(parameters_response) == 3
2024-01-07 12:03:33 +00:00
@mock_aws
def test_label_parameter_version_exception_ten_labels_at_once():
client = boto3.client("ssm", region_name="us-east-1")
test_parameter_name = "test"
test_labels = [
"test-label1",
"test-label2",
"test-label3",
"test-label4",
"test-label5",
"test-label6",
"test-label7",
"test-label8",
"test-label9",
"test-label10",
"test-label11",
]
client.put_parameter(
Name=test_parameter_name,
Description="A test parameter",
Value="value",
Type="String",
)
with pytest.raises(ClientError) as client_err:
client.label_parameter_version(
Name="test", ParameterVersion=1, Labels=test_labels
)
assert client_err.value.response["Error"]["Message"] == (
"An error occurred (ParameterVersionLabelLimitExceeded) when "
"calling the LabelParameterVersion operation: "
"A parameter version can have maximum 10 labels."
"Move one or more labels to another version and try again."
)
2024-01-07 12:03:33 +00:00
@mock_aws
def test_label_parameter_version_exception_ten_labels_over_multiple_calls():
client = boto3.client("ssm", region_name="us-east-1")
test_parameter_name = "test"
client.put_parameter(
Name=test_parameter_name,
Description="A test parameter",
Value="value",
Type="String",
)
client.label_parameter_version(
Name=test_parameter_name,
ParameterVersion=1,
Labels=[
"test-label1",
"test-label2",
"test-label3",
"test-label4",
"test-label5",
],
)
with pytest.raises(ClientError) as client_err:
client.label_parameter_version(
Name="test",
ParameterVersion=1,
Labels=[
"test-label6",
"test-label7",
"test-label8",
"test-label9",
"test-label10",
"test-label11",
],
)
assert client_err.value.response["Error"]["Message"] == (
"An error occurred (ParameterVersionLabelLimitExceeded) when "
"calling the LabelParameterVersion operation: "
"A parameter version can have maximum 10 labels."
"Move one or more labels to another version and try again."
)
2024-01-07 12:03:33 +00:00
@mock_aws
def test_label_parameter_version_invalid_name():
client = boto3.client("ssm", region_name="us-east-1")
test_parameter_name = "test"
with pytest.raises(ClientError) as client_err:
client.label_parameter_version(Name=test_parameter_name, Labels=["test-label"])
assert client_err.value.response["Error"]["Message"] == "Parameter test not found."
2024-01-07 12:03:33 +00:00
@mock_aws
def test_label_parameter_version_invalid_parameter_version():
client = boto3.client("ssm", region_name="us-east-1")
test_parameter_name = "test"
client.put_parameter(
Name=test_parameter_name,
Description="A test parameter",
Value="value",
Type="String",
)
with pytest.raises(ClientError) as client_err:
client.label_parameter_version(
Name=test_parameter_name, Labels=["test-label"], ParameterVersion=5
)
assert client_err.value.response["Error"]["Message"] == (
"Systems Manager could not find version 5 of test. "
"Verify the version and try again."
)
2024-01-07 12:03:33 +00:00
@mock_aws
def test_label_parameter_version_invalid_label():
client = boto3.client("ssm", region_name="us-east-1")
test_parameter_name = "test"
client.put_parameter(
Name=test_parameter_name,
Description="A test parameter",
Value="value",
Type="String",
)
response = client.label_parameter_version(
Name=test_parameter_name, ParameterVersion=1, Labels=["awsabc"]
)
assert response["InvalidLabels"] == ["awsabc"]
response = client.label_parameter_version(
Name=test_parameter_name, ParameterVersion=1, Labels=["ssmabc"]
)
assert response["InvalidLabels"] == ["ssmabc"]
response = client.label_parameter_version(
Name=test_parameter_name, ParameterVersion=1, Labels=["9abc"]
)
assert response["InvalidLabels"] == ["9abc"]
response = client.label_parameter_version(
Name=test_parameter_name, ParameterVersion=1, Labels=["abc/123"]
)
assert response["InvalidLabels"] == ["abc/123"]
long_name = "a" * 101
with pytest.raises(ClientError) as client_err:
client.label_parameter_version(
Name=test_parameter_name, ParameterVersion=1, Labels=[long_name]
)
assert client_err.value.response["Error"]["Message"] == (
"1 validation error detected: "
f"Value '[{long_name}]' at 'labels' failed to satisfy constraint: "
"Member must satisfy constraint: "
"[Member must have length less than or equal to 100, Member must "
"have length greater than or equal to 1]"
)
2024-01-07 12:03:33 +00:00
@mock_aws
def test_get_parameter_history_with_label():
client = boto3.client("ssm", region_name="us-east-1")
test_parameter_name = "test"
test_labels = ["test-label"]
for i in range(3):
client.put_parameter(
Name=test_parameter_name,
Description=f"A test parameter version {i}",
Value=f"value-{i}",
Type="String",
Overwrite=True,
)
client.label_parameter_version(
Name=test_parameter_name, ParameterVersion=1, Labels=test_labels
)
response = client.get_parameter_history(Name=test_parameter_name)
parameters_response = response["Parameters"]
for index, param in enumerate(parameters_response):
assert param["Name"] == test_parameter_name
assert param["Type"] == "String"
assert param["Value"] == f"value-{index}"
assert param["Version"] == index + 1
assert param["Description"] == f"A test parameter version {index}"
labels = test_labels if param["Version"] == 1 else []
assert param["Labels"] == labels
assert len(parameters_response) == 3
2024-01-07 12:03:33 +00:00
@mock_aws
def test_get_parameter_history_with_label_non_latest():
client = boto3.client("ssm", region_name="us-east-1")
test_parameter_name = "test"
test_labels = ["test-label"]
for i in range(3):
client.put_parameter(
Name=test_parameter_name,
Description=f"A test parameter version {i}",
Value=f"value-{i}",
Type="String",
Overwrite=True,
)
client.label_parameter_version(
Name=test_parameter_name, ParameterVersion=2, Labels=test_labels
)
response = client.get_parameter_history(Name=test_parameter_name)
parameters_response = response["Parameters"]
for index, param in enumerate(parameters_response):
assert param["Name"] == test_parameter_name
assert param["Type"] == "String"
assert param["Value"] == f"value-{index}"
assert param["Version"] == index + 1
assert param["Description"] == f"A test parameter version {index}"
labels = test_labels if param["Version"] == 2 else []
assert param["Labels"] == labels
assert len(parameters_response) == 3
2024-01-07 12:03:33 +00:00
@mock_aws
def test_get_parameter_history_with_label_latest_assumed():
client = boto3.client("ssm", region_name="us-east-1")
test_parameter_name = "test"
test_labels = ["test-label"]
for i in range(3):
client.put_parameter(
Name=test_parameter_name,
Description=f"A test parameter version {i}",
Value=f"value-{i}",
Type="String",
Overwrite=True,
)
client.label_parameter_version(Name=test_parameter_name, Labels=test_labels)
response = client.get_parameter_history(Name=test_parameter_name)
parameters_response = response["Parameters"]
for index, param in enumerate(parameters_response):
assert param["Name"] == test_parameter_name
assert param["Type"] == "String"
assert param["Value"] == f"value-{index}"
assert param["Version"] == index + 1
assert param["Description"] == f"A test parameter version {index}"
labels = test_labels if param["Version"] == 3 else []
assert param["Labels"] == labels
assert len(parameters_response) == 3
2024-01-07 12:03:33 +00:00
@mock_aws
def test_get_parameter_history_missing_parameter():
client = boto3.client("ssm", region_name="us-east-1")
try:
client.get_parameter_history(Name="test_noexist")
raise RuntimeError("Should have failed")
except botocore.exceptions.ClientError as err:
assert err.operation_name == "GetParameterHistory"
assert err.response["Error"]["Message"] == "Parameter test_noexist not found."
2024-01-07 12:03:33 +00:00
@mock_aws
def test_add_remove_list_tags_for_resource():
client = boto3.client("ssm", region_name="us-east-1")
with pytest.raises(ClientError) as ce:
client.add_tags_to_resource(
ResourceId="test",
ResourceType="Parameter",
Tags=[{"Key": "test-key", "Value": "test-value"}],
)
assert ce.value.response["Error"]["Code"] == "InvalidResourceId"
client.put_parameter(Name="test", Value="value", Type="String")
client.add_tags_to_resource(
ResourceId="test",
ResourceType="Parameter",
Tags=[{"Key": "test-key", "Value": "test-value"}],
)
response = client.list_tags_for_resource(
ResourceId="test", ResourceType="Parameter"
)
assert len(response["TagList"]) == 1
assert response["TagList"][0]["Key"] == "test-key"
assert response["TagList"][0]["Value"] == "test-value"
client.remove_tags_from_resource(
ResourceId="test", ResourceType="Parameter", TagKeys=["test-key"]
)
response = client.list_tags_for_resource(
ResourceId="test", ResourceType="Parameter"
)
assert len(response["TagList"]) == 0
2018-02-19 15:10:52 +00:00
2024-01-07 12:03:33 +00:00
@mock_aws
2018-02-19 15:10:52 +00:00
def test_send_command():
ssm_document = "AWS-RunShellScript"
2018-02-19 15:58:46 +00:00
params = {"commands": ["#!/bin/bash\necho 'hello world'"]}
2018-02-19 15:10:52 +00:00
client = boto3.client("ssm", region_name="us-east-1")
2018-02-19 15:59:52 +00:00
# note the timeout is determined server side, so this is a simpler check.
2018-02-19 15:58:46 +00:00
before = datetime.datetime.now()
2018-02-19 15:59:52 +00:00
2018-02-19 15:10:52 +00:00
response = client.send_command(
2023-04-24 10:26:25 +00:00
Comment="some comment",
2018-02-19 15:10:52 +00:00
InstanceIds=["i-123456"],
DocumentName=ssm_document,
2023-04-24 10:26:25 +00:00
TimeoutSeconds=42,
MaxConcurrency="360",
MaxErrors="2",
2018-02-19 15:58:46 +00:00
Parameters=params,
OutputS3Region="us-east-2",
OutputS3BucketName="the-bucket",
OutputS3KeyPrefix="pref",
2018-02-19 15:10:52 +00:00
)
2018-02-19 15:58:46 +00:00
cmd = response["Command"]
2018-02-19 15:10:52 +00:00
assert cmd["CommandId"] is not None
2023-04-24 10:26:25 +00:00
assert cmd["Comment"] == "some comment"
assert cmd["DocumentName"] == ssm_document
assert cmd["Parameters"] == params
2018-02-19 15:58:46 +00:00
assert cmd["OutputS3Region"] == "us-east-2"
assert cmd["OutputS3BucketName"] == "the-bucket"
assert cmd["OutputS3KeyPrefix"] == "pref"
2018-02-19 15:58:46 +00:00
assert cmd["ExpiresAfter"] > before
assert cmd["DeliveryTimedOutCount"] == 0
2023-04-24 10:26:25 +00:00
assert cmd["TimeoutSeconds"] == 42
assert cmd["MaxConcurrency"] == "360"
assert cmd["MaxErrors"] == "2"
# test sending a command without any optional parameters
response = client.send_command(DocumentName=ssm_document)
cmd = response["Command"]
assert cmd["CommandId"] is not None
assert cmd["DocumentName"] == ssm_document
2024-01-07 12:03:33 +00:00
@mock_aws
def test_list_commands():
client = boto3.client("ssm", region_name="us-east-1")
ssm_document = "AWS-RunShellScript"
params = {"commands": ["#!/bin/bash\necho 'hello world'"]}
response = client.send_command(
InstanceIds=["i-123456"],
DocumentName=ssm_document,
Parameters=params,
OutputS3Region="us-east-2",
OutputS3BucketName="the-bucket",
OutputS3KeyPrefix="pref",
)
cmd = response["Command"]
cmd_id = cmd["CommandId"]
# get the command by id
response = client.list_commands(CommandId=cmd_id)
cmds = response["Commands"]
assert len(cmds) == 1
assert cmds[0]["CommandId"] == cmd_id
# add another command with the same instance id to test listing by
# instance id
client.send_command(InstanceIds=["i-123456"], DocumentName=ssm_document)
response = client.list_commands(InstanceId="i-123456")
cmds = response["Commands"]
assert len(cmds) == 2
for cmd in cmds:
assert "i-123456" in cmd["InstanceIds"]
assert cmd["DeliveryTimedOutCount"] == 0
# test the error case for an invalid command id
with pytest.raises(ClientError):
response = client.list_commands(CommandId=str(uuid.uuid4()))
2019-10-31 15:44:26 +00:00
2024-01-07 12:03:33 +00:00
@mock_aws
def test_get_command_invocation():
client = boto3.client("ssm", region_name="us-east-1")
ssm_document = "AWS-RunShellScript"
params = {"commands": ["#!/bin/bash\necho 'hello world'"]}
response = client.send_command(
InstanceIds=["i-123456", "i-234567", "i-345678"],
DocumentName=ssm_document,
Parameters=params,
OutputS3Region="us-east-2",
OutputS3BucketName="the-bucket",
OutputS3KeyPrefix="pref",
)
cmd = response["Command"]
cmd_id = cmd["CommandId"]
instance_id = "i-345678"
invocation_response = client.get_command_invocation(
CommandId=cmd_id, InstanceId=instance_id, PluginName="aws:runShellScript"
)
assert invocation_response["CommandId"] == cmd_id
assert invocation_response["InstanceId"] == instance_id
# test the error case for an invalid instance id
with pytest.raises(ClientError):
invocation_response = client.get_command_invocation(
CommandId=cmd_id, InstanceId="i-FAKE"
)
# test the error case for an invalid plugin name
with pytest.raises(ClientError):
invocation_response = client.get_command_invocation(
CommandId=cmd_id, InstanceId=instance_id, PluginName="FAKE"
)
2024-01-07 12:03:33 +00:00
@mock_aws
def test_get_command_invocations_by_instance_tag():
ec2 = boto3.client("ec2", region_name="us-east-1")
ssm = boto3.client("ssm", region_name="us-east-1")
tag_specifications = [
{"ResourceType": "instance", "Tags": [{"Key": "Name", "Value": "test-tag"}]}
]
num_instances = 3
resp = ec2.run_instances(
ImageId=EXAMPLE_AMI_ID,
MaxCount=num_instances,
MinCount=num_instances,
TagSpecifications=tag_specifications,
)
instance_ids = []
for instance in resp["Instances"]:
instance_ids.append(instance["InstanceId"])
assert len(instance_ids) == num_instances
command_id = ssm.send_command(
DocumentName="AWS-RunShellScript",
Targets=[{"Key": "tag:Name", "Values": ["test-tag"]}],
)["Command"]["CommandId"]
resp = ssm.list_commands(CommandId=command_id)
assert resp["Commands"][0]["TargetCount"] == num_instances
for instance_id in instance_ids:
resp = ssm.get_command_invocation(CommandId=command_id, InstanceId=instance_id)
assert resp["Status"] == "Success"
2024-01-07 12:03:33 +00:00
@mock_aws
def test_parameter_version_limit():
client = boto3.client("ssm", region_name="us-east-1")
parameter_name = "test-param"
for i in range(PARAMETER_VERSION_LIMIT + 1):
client.put_parameter(
Name=parameter_name,
Value=f"value-{(i+1)}",
Type="String",
Overwrite=True,
)
paginator = client.get_paginator("get_parameter_history")
page_iterator = paginator.paginate(Name=parameter_name)
parameter_history = list(
item for page in page_iterator for item in page["Parameters"]
)
assert len(parameter_history) == PARAMETER_VERSION_LIMIT
assert parameter_history[0]["Value"] == "value-2"
latest_version_index = PARAMETER_VERSION_LIMIT - 1
latest_version_value = f"value-{PARAMETER_VERSION_LIMIT + 1}"
assert parameter_history[latest_version_index]["Value"] == latest_version_value
2024-01-07 12:03:33 +00:00
@mock_aws
def test_parameter_overwrite_fails_when_limit_reached_and_oldest_version_has_label():
client = boto3.client("ssm", region_name="us-east-1")
parameter_name = "test-param"
for i in range(PARAMETER_VERSION_LIMIT):
client.put_parameter(
Name=parameter_name,
Value=f"value-{(i+1)}",
Type="String",
Overwrite=True,
)
client.label_parameter_version(
Name=parameter_name, ParameterVersion=1, Labels=["test-label"]
)
with pytest.raises(ClientError) as ex:
client.put_parameter(
Name=parameter_name, Value="new-value", Type="String", Overwrite=True
)
error = ex.value.response["Error"]
assert error["Code"] == "ParameterMaxVersionLimitExceeded"
assert parameter_name in error["Message"]
assert "Version 1" in error["Message"]
assert re.search(
(
r"the oldest version, can't be deleted because it has a label "
"associated with it. Move the label to another version of the "
"parameter, and try again."
),
error["Message"],
)
2024-01-07 12:03:33 +00:00
@mock_aws
def test_get_parameters_includes_invalid_parameter_when_requesting_invalid_version():
client = boto3.client("ssm", region_name="us-east-1")
parameter_name = "test-param"
versions_to_create = 5
for i in range(versions_to_create):
client.put_parameter(
Name=parameter_name,
Value=f"value-{(i+1)}",
Type="String",
Overwrite=True,
)
response = client.get_parameters(
Names=[
f"test-param:{versions_to_create + 1}",
f"test-param:{versions_to_create - 1}",
]
)
assert len(response["InvalidParameters"]) == 1
assert response["InvalidParameters"][0] == f"test-param:{versions_to_create + 1}"
assert len(response["Parameters"]) == 1
assert response["Parameters"][0]["Name"] == "test-param"
assert response["Parameters"][0]["Value"] == "value-4"
assert response["Parameters"][0]["Type"] == "String"
2024-01-07 12:03:33 +00:00
@mock_aws
def test_get_parameters_includes_invalid_parameter_when_requesting_invalid_label():
client = boto3.client("ssm", region_name="us-east-1")
parameter_name = "test-param"
versions_to_create = 5
for i in range(versions_to_create):
client.put_parameter(
Name=parameter_name,
Value=f"value-{(i+1)}",
Type="String",
Overwrite=True,
)
client.label_parameter_version(
Name=parameter_name, ParameterVersion=1, Labels=["test-label"]
)
response = client.get_parameters(
Names=[
"test-param:test-label",
"test-param:invalid-label",
"test-param",
"test-param:2",
]
)
assert len(response["InvalidParameters"]) == 1
assert response["InvalidParameters"][0] == "test-param:invalid-label"
assert len(response["Parameters"]) == 3
2024-01-07 12:03:33 +00:00
@mock_aws
def test_get_parameters_should_only_return_unique_requests():
client = boto3.client("ssm", region_name="us-east-1")
parameter_name = "test-param"
client.put_parameter(Name=parameter_name, Value="value", Type="String")
response = client.get_parameters(Names=["test-param", "test-param"])
assert len(response["Parameters"]) == 1
2024-01-07 12:03:33 +00:00
@mock_aws
def test_get_parameter_history_should_throw_exception_when_MaxResults_is_too_large():
client = boto3.client("ssm", region_name="us-east-1")
parameter_name = "test-param"
for _ in range(100):
client.put_parameter(
Name=parameter_name, Value="value", Type="String", Overwrite=True
)
with pytest.raises(ClientError) as ex:
client.get_parameter_history(
Name=parameter_name, MaxResults=PARAMETER_HISTORY_MAX_RESULTS + 1
)
error = ex.value.response["Error"]
assert error["Code"] == "ValidationException"
assert error["Message"] == (
"1 validation error detected: "
f"Value '{PARAMETER_HISTORY_MAX_RESULTS + 1}' at 'maxResults' "
"failed to satisfy constraint: "
"Member must have value less than or equal to 50."
)
2024-01-07 12:03:33 +00:00
@mock_aws
def test_get_parameter_history_NextTokenImplementation():
client = boto3.client("ssm", region_name="us-east-1")
parameter_name = "test-param"
for _ in range(100):
client.put_parameter(
Name=parameter_name, Value="value", Type="String", Overwrite=True
)
response = client.get_parameter_history(
Name=parameter_name, MaxResults=PARAMETER_HISTORY_MAX_RESULTS
) # fetch first 50
param_history = response["Parameters"]
next_token = response.get("NextToken", None)
while next_token is not None:
response = client.get_parameter_history(
Name=parameter_name, MaxResults=7, NextToken=next_token
) # fetch small amounts to test MaxResults can change
param_history.extend(response["Parameters"])
next_token = response.get("NextToken", None)
assert len(param_history) == 100
2024-01-07 12:03:33 +00:00
@mock_aws
def test_get_parameter_history_exception_when_requesting_invalid_parameter():
client = boto3.client("ssm", region_name="us-east-1")
with pytest.raises(ClientError) as ex:
client.get_parameter_history(Name="invalid_parameter_name")
error = ex.value.response["Error"]
assert error["Code"] == "ParameterNotFound"
assert error["Message"] == "Parameter invalid_parameter_name not found."