SSM: fix overwrite preserving non-indicated values (#7066)
This commit is contained in:
parent
3c10fb12f0
commit
807dca6e50
@ -2106,6 +2106,24 @@ class SimpleSystemManagerBackend(BaseBackend):
|
|||||||
self._check_for_parameter_version_limit_exception(name)
|
self._check_for_parameter_version_limit_exception(name)
|
||||||
previous_parameter_versions.pop(0)
|
previous_parameter_versions.pop(0)
|
||||||
|
|
||||||
|
# Ensure all the previous values that we didn't overwrite are preserved
|
||||||
|
value = value if value is not None else previous_parameter.value
|
||||||
|
description = (
|
||||||
|
description
|
||||||
|
if description is not None
|
||||||
|
else previous_parameter.description
|
||||||
|
)
|
||||||
|
allowed_pattern = (
|
||||||
|
allowed_pattern
|
||||||
|
if allowed_pattern is not None
|
||||||
|
else previous_parameter.allowed_pattern
|
||||||
|
)
|
||||||
|
keyid = keyid if keyid is not None else previous_parameter.keyid
|
||||||
|
tags = tags if tags is not None else previous_parameter.tags
|
||||||
|
data_type = (
|
||||||
|
data_type if data_type is not None else previous_parameter.data_type
|
||||||
|
)
|
||||||
|
|
||||||
last_modified_date = time.time()
|
last_modified_date = time.time()
|
||||||
self._parameters[name].append(
|
self._parameters[name].append(
|
||||||
Parameter(
|
Parameter(
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import json
|
import json
|
||||||
from typing import Any, Dict, Tuple, Union
|
from typing import Any, Dict, Tuple, Union
|
||||||
|
import warnings
|
||||||
|
|
||||||
from moto.core.responses import BaseResponse
|
from moto.core.responses import BaseResponse
|
||||||
from .exceptions import ValidationException, ParameterAlreadyExists
|
from .exceptions import ValidationException, ParameterAlreadyExists
|
||||||
@ -270,9 +271,21 @@ class SimpleSystemManagerResponse(BaseResponse):
|
|||||||
allowed_pattern = self._get_param("AllowedPattern")
|
allowed_pattern = self._get_param("AllowedPattern")
|
||||||
keyid = self._get_param("KeyId")
|
keyid = self._get_param("KeyId")
|
||||||
overwrite = self._get_param("Overwrite", False)
|
overwrite = self._get_param("Overwrite", False)
|
||||||
tags = self._get_param("Tags", [])
|
tags = self._get_param("Tags")
|
||||||
data_type = self._get_param("DataType", "text")
|
data_type = self._get_param("DataType", "text")
|
||||||
|
|
||||||
|
# To be implemented arguments of put_parameter
|
||||||
|
tier = self._get_param("Tier")
|
||||||
|
if tier is not None:
|
||||||
|
warnings.warn(
|
||||||
|
"Tier configuration option is not yet implemented. Discarding."
|
||||||
|
)
|
||||||
|
policies = self._get_param("Policies")
|
||||||
|
if policies is not None:
|
||||||
|
warnings.warn(
|
||||||
|
"Policies configuration option is not yet implemented. Discarding."
|
||||||
|
)
|
||||||
|
|
||||||
result = self.ssm_backend.put_parameter(
|
result = self.ssm_backend.put_parameter(
|
||||||
name,
|
name,
|
||||||
description,
|
description,
|
||||||
|
@ -2,13 +2,15 @@ import datetime
|
|||||||
import re
|
import re
|
||||||
import string
|
import string
|
||||||
import uuid
|
import uuid
|
||||||
|
from unittest.mock import patch, Mock
|
||||||
|
from unittest import SkipTest
|
||||||
|
|
||||||
import boto3
|
import boto3
|
||||||
import botocore.exceptions
|
import botocore.exceptions
|
||||||
from botocore.exceptions import ClientError
|
from botocore.exceptions import ClientError
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from moto import mock_ec2, mock_ssm
|
from moto import mock_ec2, mock_ssm, settings
|
||||||
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
|
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
|
||||||
from moto.ssm.models import PARAMETER_VERSION_LIMIT, PARAMETER_HISTORY_MAX_RESULTS
|
from moto.ssm.models import PARAMETER_VERSION_LIMIT, PARAMETER_HISTORY_MAX_RESULTS
|
||||||
from tests import EXAMPLE_AMI_ID
|
from tests import EXAMPLE_AMI_ID
|
||||||
@ -262,6 +264,7 @@ def test_put_parameter(name):
|
|||||||
)
|
)
|
||||||
new_data_type = "aws:ec2:image"
|
new_data_type = "aws:ec2:image"
|
||||||
|
|
||||||
|
# Cannot have tags and overwrite at the same time
|
||||||
with pytest.raises(ClientError) as ex:
|
with pytest.raises(ClientError) as ex:
|
||||||
response = client.put_parameter(
|
response = client.put_parameter(
|
||||||
Name=name,
|
Name=name,
|
||||||
@ -301,6 +304,157 @@ def test_put_parameter(name):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_ssm
|
||||||
|
def test_put_parameter_unimplemented_parameters():
|
||||||
|
"""
|
||||||
|
Test to ensure coverage of unimplemented parameters. Remove for appropriate tests
|
||||||
|
once implemented
|
||||||
|
"""
|
||||||
|
if settings.TEST_SERVER_MODE:
|
||||||
|
raise SkipTest("Can't test for warning logs in server mode")
|
||||||
|
|
||||||
|
mock_warn = Mock()
|
||||||
|
with patch("warnings.warn", mock_warn):
|
||||||
|
# Ensure that the ssm parameters are still working with the Mock
|
||||||
|
client = boto3.client("ssm", region_name="us-east-1")
|
||||||
|
name = "my-param"
|
||||||
|
response = client.put_parameter(
|
||||||
|
Name=name,
|
||||||
|
Description="A test parameter",
|
||||||
|
Value="value",
|
||||||
|
Type="String",
|
||||||
|
Tier="Advanced",
|
||||||
|
Policies="No way fam",
|
||||||
|
)
|
||||||
|
|
||||||
|
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}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# We got the argument warnings
|
||||||
|
mock_warn.assert_any_call(
|
||||||
|
"Tier configuration option is not yet implemented. Discarding."
|
||||||
|
)
|
||||||
|
mock_warn.assert_any_call(
|
||||||
|
"Policies configuration option is not yet implemented. Discarding."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("name", ["test", "my-cool-parameter"])
|
||||||
|
@mock_ssm
|
||||||
|
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,
|
||||||
|
# TODO: add tier and policies support
|
||||||
|
)
|
||||||
|
|
||||||
|
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}"
|
||||||
|
)
|
||||||
|
initial_modification_date = response["Parameters"][0]["LastModifiedDate"]
|
||||||
|
|
||||||
|
# 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 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
|
||||||
|
|
||||||
|
|
||||||
@mock_ssm
|
@mock_ssm
|
||||||
def test_put_parameter_empty_string_value():
|
def test_put_parameter_empty_string_value():
|
||||||
client = boto3.client("ssm", region_name="us-east-1")
|
client = boto3.client("ssm", region_name="us-east-1")
|
||||||
|
Loading…
Reference in New Issue
Block a user