2021-05-19 07:30:25 +00:00
|
|
|
import boto3
|
2014-03-27 23:12:53 +00:00
|
|
|
import json
|
2017-05-01 18:28:35 +00:00
|
|
|
import yaml
|
2014-03-27 23:12:53 +00:00
|
|
|
|
2021-11-03 21:00:42 +00:00
|
|
|
import pytest
|
2021-10-18 19:44:29 +00:00
|
|
|
import sure # noqa # pylint: disable=unused-import
|
2021-11-03 21:00:42 +00:00
|
|
|
from botocore.exceptions import ClientError
|
2021-08-04 16:24:26 +00:00
|
|
|
from unittest.mock import patch
|
2014-03-27 23:12:53 +00:00
|
|
|
|
2017-02-24 03:28:09 +00:00
|
|
|
from moto.cloudformation.exceptions import ValidationError
|
2014-03-27 23:12:53 +00:00
|
|
|
from moto.cloudformation.models import FakeStack
|
2019-10-31 15:44:26 +00:00
|
|
|
from moto.cloudformation.parsing import (
|
|
|
|
resource_class_from_type,
|
|
|
|
parse_condition,
|
2022-01-18 15:18:57 +00:00
|
|
|
Output,
|
2019-10-31 15:44:26 +00:00
|
|
|
)
|
2021-11-03 21:00:42 +00:00
|
|
|
from moto import mock_cloudformation, mock_sqs, mock_ssm, settings
|
2022-08-13 09:49:43 +00:00
|
|
|
from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID
|
2014-03-27 23:12:53 +00:00
|
|
|
from moto.sqs.models import Queue
|
2016-08-15 18:28:07 +00:00
|
|
|
from moto.s3.models import FakeBucket
|
2017-09-07 18:28:15 +00:00
|
|
|
from moto.cloudformation.utils import yaml_tag_constructor
|
2014-03-27 23:12:53 +00:00
|
|
|
|
2017-09-07 18:28:15 +00:00
|
|
|
|
2014-03-27 23:12:53 +00:00
|
|
|
dummy_template = {
|
|
|
|
"AWSTemplateFormatVersion": "2010-09-09",
|
2021-11-03 21:00:42 +00:00
|
|
|
"Description": "sample template",
|
2014-03-27 23:12:53 +00:00
|
|
|
"Resources": {
|
2014-10-21 16:45:03 +00:00
|
|
|
"Queue": {
|
2014-03-27 23:12:53 +00:00
|
|
|
"Type": "AWS::SQS::Queue",
|
2019-10-31 15:44:26 +00:00
|
|
|
"Properties": {"QueueName": "my-queue", "VisibilityTimeout": 60},
|
2016-08-15 18:28:07 +00:00
|
|
|
},
|
2019-10-31 15:44:26 +00:00
|
|
|
"S3Bucket": {"Type": "AWS::S3::Bucket", "DeletionPolicy": "Retain"},
|
2014-03-27 23:12:53 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2014-10-20 15:45:47 +00:00
|
|
|
name_type_template = {
|
|
|
|
"AWSTemplateFormatVersion": "2010-09-09",
|
2021-11-03 21:00:42 +00:00
|
|
|
"Description": "sample template",
|
2014-10-20 15:45:47 +00:00
|
|
|
"Resources": {
|
2019-10-31 15:44:26 +00:00
|
|
|
"Queue": {"Type": "AWS::SQS::Queue", "Properties": {"VisibilityTimeout": 60}}
|
2014-10-20 15:45:47 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2020-06-18 08:50:58 +00:00
|
|
|
name_type_template_with_tabs_json = """
|
|
|
|
\t{
|
|
|
|
\t\t"AWSTemplateFormatVersion": "2010-09-09",
|
2021-11-03 21:00:42 +00:00
|
|
|
\t\t"Description": "sample template",
|
2020-06-18 08:50:58 +00:00
|
|
|
\t\t"Resources": {
|
|
|
|
\t\t\t"Queue": {"Type": "AWS::SQS::Queue", "Properties": {"VisibilityTimeout": 60}}
|
|
|
|
\t\t}
|
|
|
|
\t}
|
|
|
|
"""
|
|
|
|
|
2014-10-21 16:45:03 +00:00
|
|
|
output_dict = {
|
|
|
|
"Outputs": {
|
2019-10-31 15:44:26 +00:00
|
|
|
"Output1": {"Value": {"Ref": "Queue"}, "Description": "This is a description."}
|
2014-10-21 16:45:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-26 05:01:01 +00:00
|
|
|
null_output = {"Outputs": None}
|
|
|
|
|
2014-10-21 16:45:03 +00:00
|
|
|
bad_output = {
|
2019-10-31 15:44:26 +00:00
|
|
|
"Outputs": {"Output1": {"Value": {"Fn::GetAtt": ["Queue", "InvalidAttribute"]}}}
|
2014-10-21 16:45:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
get_attribute_output = {
|
2019-10-31 15:44:26 +00:00
|
|
|
"Outputs": {"Output1": {"Value": {"Fn::GetAtt": ["Queue", "QueueName"]}}}
|
2014-10-21 16:45:03 +00:00
|
|
|
}
|
|
|
|
|
2019-10-31 15:44:26 +00:00
|
|
|
get_availability_zones_output = {"Outputs": {"Output1": {"Value": {"Fn::GetAZs": ""}}}}
|
2018-01-11 00:57:49 +00:00
|
|
|
|
2019-05-20 23:05:02 +00:00
|
|
|
parameters = {
|
|
|
|
"Parameters": {
|
2019-10-31 15:44:26 +00:00
|
|
|
"Param": {"Type": "String"},
|
2020-07-11 07:43:45 +00:00
|
|
|
"NumberParam": {"Type": "Number"},
|
|
|
|
"NumberListParam": {"Type": "List<Number>"},
|
2019-10-31 15:44:26 +00:00
|
|
|
"NoEchoParam": {"Type": "String", "NoEcho": True},
|
2019-05-20 23:05:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-19 07:30:25 +00:00
|
|
|
ssm_parameter = {
|
|
|
|
"Parameters": {
|
|
|
|
"SingleParamCfn": {"Type": "AWS::SSM::Parameter::Value<String>"},
|
2021-06-29 17:28:52 +00:00
|
|
|
"ListParamCfn": {
|
|
|
|
"Type": "AWS::SSM::Parameter::Value<List<String>>",
|
|
|
|
"Default": "/path/to/list/param",
|
|
|
|
},
|
2021-05-19 07:30:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-08 15:38:29 +00:00
|
|
|
split_select_template = {
|
|
|
|
"AWSTemplateFormatVersion": "2010-09-09",
|
|
|
|
"Resources": {
|
|
|
|
"Queue": {
|
|
|
|
"Type": "AWS::SQS::Queue",
|
|
|
|
"Properties": {
|
2019-10-31 15:44:26 +00:00
|
|
|
"QueueName": {"Fn::Select": ["1", {"Fn::Split": ["-", "123-myqueue"]}]},
|
2017-06-08 15:38:29 +00:00
|
|
|
"VisibilityTimeout": 60,
|
2019-10-31 15:44:26 +00:00
|
|
|
},
|
2017-06-08 15:38:29 +00:00
|
|
|
}
|
2019-10-31 15:44:26 +00:00
|
|
|
},
|
2017-06-08 15:38:29 +00:00
|
|
|
}
|
|
|
|
|
2017-06-08 19:21:32 +00:00
|
|
|
sub_template = {
|
|
|
|
"AWSTemplateFormatVersion": "2010-09-09",
|
|
|
|
"Resources": {
|
|
|
|
"Queue1": {
|
|
|
|
"Type": "AWS::SQS::Queue",
|
|
|
|
"Properties": {
|
2019-10-31 15:44:26 +00:00
|
|
|
"QueueName": {"Fn::Sub": "${AWS::StackName}-queue-${!Literal}"},
|
2017-06-08 19:21:32 +00:00
|
|
|
"VisibilityTimeout": 60,
|
2019-10-31 15:44:26 +00:00
|
|
|
},
|
2017-06-08 19:21:32 +00:00
|
|
|
},
|
|
|
|
"Queue2": {
|
|
|
|
"Type": "AWS::SQS::Queue",
|
|
|
|
"Properties": {
|
2019-10-31 15:44:26 +00:00
|
|
|
"QueueName": {"Fn::Sub": "${Queue1.QueueName}"},
|
2017-06-08 19:21:32 +00:00
|
|
|
"VisibilityTimeout": 60,
|
2019-10-31 15:44:26 +00:00
|
|
|
},
|
2017-06-08 19:21:32 +00:00
|
|
|
},
|
2019-10-31 15:44:26 +00:00
|
|
|
},
|
2017-06-08 19:21:32 +00:00
|
|
|
}
|
|
|
|
|
2017-06-08 19:33:28 +00:00
|
|
|
export_value_template = {
|
|
|
|
"AWSTemplateFormatVersion": "2010-09-09",
|
|
|
|
"Resources": {
|
|
|
|
"Queue": {
|
|
|
|
"Type": "AWS::SQS::Queue",
|
|
|
|
"Properties": {
|
2019-10-31 15:44:26 +00:00
|
|
|
"QueueName": {"Fn::Sub": "${AWS::StackName}-queue"},
|
2017-06-08 19:33:28 +00:00
|
|
|
"VisibilityTimeout": 60,
|
2019-10-31 15:44:26 +00:00
|
|
|
},
|
2017-06-08 19:33:28 +00:00
|
|
|
}
|
|
|
|
},
|
2019-10-31 15:44:26 +00:00
|
|
|
"Outputs": {"Output1": {"Value": "value", "Export": {"Name": "queue-us-west-1"}}},
|
2017-06-08 19:33:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
import_value_template = {
|
|
|
|
"AWSTemplateFormatVersion": "2010-09-09",
|
|
|
|
"Resources": {
|
|
|
|
"Queue": {
|
|
|
|
"Type": "AWS::SQS::Queue",
|
|
|
|
"Properties": {
|
2019-10-31 15:44:26 +00:00
|
|
|
"QueueName": {"Fn::ImportValue": "queue-us-west-1"},
|
2017-06-08 19:33:28 +00:00
|
|
|
"VisibilityTimeout": 60,
|
2019-10-31 15:44:26 +00:00
|
|
|
},
|
2017-06-08 19:33:28 +00:00
|
|
|
}
|
2019-10-31 15:44:26 +00:00
|
|
|
},
|
2017-06-08 19:33:28 +00:00
|
|
|
}
|
|
|
|
|
2019-10-31 15:44:26 +00:00
|
|
|
outputs_template = dict(list(dummy_template.items()) + list(output_dict.items()))
|
2021-08-26 05:01:01 +00:00
|
|
|
null_outputs_template = dict(list(dummy_template.items()) + list(null_output.items()))
|
2019-10-31 15:44:26 +00:00
|
|
|
bad_outputs_template = dict(list(dummy_template.items()) + list(bad_output.items()))
|
2017-02-24 02:37:43 +00:00
|
|
|
get_attribute_outputs_template = dict(
|
2019-10-31 15:44:26 +00:00
|
|
|
list(dummy_template.items()) + list(get_attribute_output.items())
|
|
|
|
)
|
2018-01-11 00:57:49 +00:00
|
|
|
get_availability_zones_template = dict(
|
2019-10-31 15:44:26 +00:00
|
|
|
list(dummy_template.items()) + list(get_availability_zones_output.items())
|
|
|
|
)
|
2014-10-21 16:45:03 +00:00
|
|
|
|
2019-10-31 15:44:26 +00:00
|
|
|
parameters_template = dict(list(dummy_template.items()) + list(parameters.items()))
|
2021-05-19 07:30:25 +00:00
|
|
|
ssm_parameter_template = dict(
|
|
|
|
list(dummy_template.items()) + list(ssm_parameter.items())
|
|
|
|
)
|
2019-05-20 23:05:02 +00:00
|
|
|
|
2014-03-27 23:12:53 +00:00
|
|
|
dummy_template_json = json.dumps(dummy_template)
|
2014-10-20 15:45:47 +00:00
|
|
|
name_type_template_json = json.dumps(name_type_template)
|
2014-10-21 16:45:03 +00:00
|
|
|
output_type_template_json = json.dumps(outputs_template)
|
2021-08-26 05:01:01 +00:00
|
|
|
null_output_template_json = json.dumps(null_outputs_template)
|
2014-10-21 16:45:03 +00:00
|
|
|
bad_output_template_json = json.dumps(bad_outputs_template)
|
2019-10-31 15:44:26 +00:00
|
|
|
get_attribute_outputs_template_json = json.dumps(get_attribute_outputs_template)
|
|
|
|
get_availability_zones_template_json = json.dumps(get_availability_zones_template)
|
2019-05-20 23:05:02 +00:00
|
|
|
parameters_template_json = json.dumps(parameters_template)
|
2021-05-19 07:30:25 +00:00
|
|
|
ssm_parameter_template_json = json.dumps(ssm_parameter_template)
|
2017-06-08 15:38:29 +00:00
|
|
|
split_select_template_json = json.dumps(split_select_template)
|
2017-06-08 19:21:32 +00:00
|
|
|
sub_template_json = json.dumps(sub_template)
|
2017-06-08 19:33:28 +00:00
|
|
|
export_value_template_json = json.dumps(export_value_template)
|
|
|
|
import_value_template_json = json.dumps(import_value_template)
|
2014-03-27 23:12:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_parse_stack_resources():
|
|
|
|
stack = FakeStack(
|
|
|
|
stack_id="test_id",
|
|
|
|
name="test_stack",
|
|
|
|
template=dummy_template_json,
|
2014-12-31 19:21:47 +00:00
|
|
|
parameters={},
|
2022-08-13 09:49:43 +00:00
|
|
|
account_id=ACCOUNT_ID,
|
2019-10-31 15:44:26 +00:00
|
|
|
region_name="us-west-1",
|
|
|
|
)
|
2014-03-27 23:12:53 +00:00
|
|
|
|
2016-08-15 18:28:07 +00:00
|
|
|
stack.resource_map.should.have.length_of(2)
|
|
|
|
|
2019-10-31 15:44:26 +00:00
|
|
|
queue = stack.resource_map["Queue"]
|
2014-03-27 23:12:53 +00:00
|
|
|
queue.should.be.a(Queue)
|
|
|
|
queue.name.should.equal("my-queue")
|
|
|
|
|
2019-10-31 15:44:26 +00:00
|
|
|
bucket = stack.resource_map["S3Bucket"]
|
2016-08-15 18:28:07 +00:00
|
|
|
bucket.should.be.a(FakeBucket)
|
|
|
|
bucket.physical_resource_id.should.equal(bucket.name)
|
|
|
|
|
2014-03-27 23:12:53 +00:00
|
|
|
|
|
|
|
@patch("moto.cloudformation.parsing.logger")
|
|
|
|
def test_missing_resource_logs(logger):
|
|
|
|
resource_class_from_type("foobar")
|
2019-10-31 15:44:26 +00:00
|
|
|
logger.warning.assert_called_with("No Moto CloudFormation support for %s", "foobar")
|
2014-10-20 15:45:47 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_parse_stack_with_name_type_resource():
|
|
|
|
stack = FakeStack(
|
|
|
|
stack_id="test_id",
|
|
|
|
name="test_stack",
|
2014-11-15 18:34:52 +00:00
|
|
|
template=name_type_template_json,
|
2014-12-31 19:21:47 +00:00
|
|
|
parameters={},
|
2022-08-13 09:49:43 +00:00
|
|
|
account_id=ACCOUNT_ID,
|
2019-10-31 15:44:26 +00:00
|
|
|
region_name="us-west-1",
|
|
|
|
)
|
2014-10-20 15:45:47 +00:00
|
|
|
|
|
|
|
stack.resource_map.should.have.length_of(1)
|
2019-10-31 15:44:26 +00:00
|
|
|
list(stack.resource_map.keys())[0].should.equal("Queue")
|
2014-10-20 15:45:47 +00:00
|
|
|
queue = list(stack.resource_map.values())[0]
|
2020-06-18 08:50:58 +00:00
|
|
|
queue.should.be.a(Queue)
|
|
|
|
|
|
|
|
|
|
|
|
def test_parse_stack_with_tabbed_json_template():
|
|
|
|
stack = FakeStack(
|
|
|
|
stack_id="test_id",
|
|
|
|
name="test_stack",
|
|
|
|
template=name_type_template_with_tabs_json,
|
|
|
|
parameters={},
|
2022-08-13 09:49:43 +00:00
|
|
|
account_id=ACCOUNT_ID,
|
2020-06-18 08:50:58 +00:00
|
|
|
region_name="us-west-1",
|
|
|
|
)
|
|
|
|
|
|
|
|
stack.resource_map.should.have.length_of(1)
|
|
|
|
list(stack.resource_map.keys())[0].should.equal("Queue")
|
|
|
|
queue = list(stack.resource_map.values())[0]
|
2014-10-20 15:45:47 +00:00
|
|
|
queue.should.be.a(Queue)
|
2014-10-21 16:45:03 +00:00
|
|
|
|
|
|
|
|
2017-05-01 18:28:35 +00:00
|
|
|
def test_parse_stack_with_yaml_template():
|
|
|
|
stack = FakeStack(
|
|
|
|
stack_id="test_id",
|
|
|
|
name="test_stack",
|
|
|
|
template=yaml.dump(name_type_template),
|
|
|
|
parameters={},
|
2022-08-13 09:49:43 +00:00
|
|
|
account_id=ACCOUNT_ID,
|
2019-10-31 15:44:26 +00:00
|
|
|
region_name="us-west-1",
|
|
|
|
)
|
2017-05-01 18:28:35 +00:00
|
|
|
|
|
|
|
stack.resource_map.should.have.length_of(1)
|
2019-10-31 15:44:26 +00:00
|
|
|
list(stack.resource_map.keys())[0].should.equal("Queue")
|
2017-05-01 18:28:35 +00:00
|
|
|
queue = list(stack.resource_map.values())[0]
|
|
|
|
queue.should.be.a(Queue)
|
|
|
|
|
|
|
|
|
2014-10-21 16:45:03 +00:00
|
|
|
def test_parse_stack_with_outputs():
|
|
|
|
stack = FakeStack(
|
|
|
|
stack_id="test_id",
|
|
|
|
name="test_stack",
|
2014-11-15 18:34:52 +00:00
|
|
|
template=output_type_template_json,
|
2014-12-31 19:21:47 +00:00
|
|
|
parameters={},
|
2022-08-13 09:49:43 +00:00
|
|
|
account_id=ACCOUNT_ID,
|
2019-10-31 15:44:26 +00:00
|
|
|
region_name="us-west-1",
|
|
|
|
)
|
2014-10-21 16:45:03 +00:00
|
|
|
|
|
|
|
stack.output_map.should.have.length_of(1)
|
2019-10-31 15:44:26 +00:00
|
|
|
list(stack.output_map.keys())[0].should.equal("Output1")
|
2014-10-21 16:45:03 +00:00
|
|
|
output = list(stack.output_map.values())[0]
|
|
|
|
output.should.be.a(Output)
|
|
|
|
output.description.should.equal("This is a description.")
|
|
|
|
|
|
|
|
|
|
|
|
def test_parse_stack_with_get_attribute_outputs():
|
|
|
|
stack = FakeStack(
|
|
|
|
stack_id="test_id",
|
|
|
|
name="test_stack",
|
2014-11-15 18:34:52 +00:00
|
|
|
template=get_attribute_outputs_template_json,
|
2014-12-31 19:21:47 +00:00
|
|
|
parameters={},
|
2022-08-13 09:49:43 +00:00
|
|
|
account_id=ACCOUNT_ID,
|
2019-10-31 15:44:26 +00:00
|
|
|
region_name="us-west-1",
|
|
|
|
)
|
2014-10-21 16:45:03 +00:00
|
|
|
|
|
|
|
stack.output_map.should.have.length_of(1)
|
2019-10-31 15:44:26 +00:00
|
|
|
list(stack.output_map.keys())[0].should.equal("Output1")
|
2014-10-21 16:45:03 +00:00
|
|
|
output = list(stack.output_map.values())[0]
|
|
|
|
output.should.be.a(Output)
|
|
|
|
output.value.should.equal("my-queue")
|
|
|
|
|
2019-10-31 15:44:26 +00:00
|
|
|
|
2018-07-13 10:40:54 +00:00
|
|
|
def test_parse_stack_with_get_attribute_kms():
|
|
|
|
from .fixtures.kms_key import template
|
|
|
|
|
|
|
|
template_json = json.dumps(template)
|
|
|
|
stack = FakeStack(
|
|
|
|
stack_id="test_id",
|
|
|
|
name="test_stack",
|
|
|
|
template=template_json,
|
|
|
|
parameters={},
|
2022-08-13 09:49:43 +00:00
|
|
|
account_id=ACCOUNT_ID,
|
2019-10-31 15:44:26 +00:00
|
|
|
region_name="us-west-1",
|
|
|
|
)
|
2018-07-13 10:40:54 +00:00
|
|
|
|
|
|
|
stack.output_map.should.have.length_of(1)
|
2019-10-31 15:44:26 +00:00
|
|
|
list(stack.output_map.keys())[0].should.equal("KeyArn")
|
2018-07-13 10:40:54 +00:00
|
|
|
output = list(stack.output_map.values())[0]
|
|
|
|
output.should.be.a(Output)
|
2014-10-21 16:45:03 +00:00
|
|
|
|
2019-10-31 15:44:26 +00:00
|
|
|
|
2018-01-11 00:57:49 +00:00
|
|
|
def test_parse_stack_with_get_availability_zones():
|
|
|
|
stack = FakeStack(
|
|
|
|
stack_id="test_id",
|
|
|
|
name="test_stack",
|
|
|
|
template=get_availability_zones_template_json,
|
|
|
|
parameters={},
|
2022-08-13 09:49:43 +00:00
|
|
|
account_id=ACCOUNT_ID,
|
2019-10-31 15:44:26 +00:00
|
|
|
region_name="us-east-1",
|
|
|
|
)
|
2018-01-11 00:57:49 +00:00
|
|
|
|
|
|
|
stack.output_map.should.have.length_of(1)
|
2019-10-31 15:44:26 +00:00
|
|
|
list(stack.output_map.keys())[0].should.equal("Output1")
|
2018-01-11 00:57:49 +00:00
|
|
|
output = list(stack.output_map.values())[0]
|
|
|
|
output.should.be.a(Output)
|
2019-10-31 15:44:26 +00:00
|
|
|
output.value.should.equal(["us-east-1a", "us-east-1b", "us-east-1c", "us-east-1d"])
|
2018-01-11 00:57:49 +00:00
|
|
|
|
|
|
|
|
2021-11-03 21:00:42 +00:00
|
|
|
@mock_sqs
|
|
|
|
@mock_cloudformation
|
|
|
|
def test_parse_stack_with_bad_get_attribute_outputs_using_boto3():
|
|
|
|
conn = boto3.client("cloudformation", region_name="us-west-1")
|
|
|
|
with pytest.raises(ClientError) as exc:
|
|
|
|
conn.create_stack(StackName="teststack", TemplateBody=bad_output_template_json)
|
|
|
|
err = exc.value.response["Error"]
|
|
|
|
err["Code"].should.equal("ValidationError")
|
|
|
|
err["Message"].should.equal(
|
|
|
|
"Template error: resource Queue does not support attribute type InvalidAttribute in Fn::GetAtt"
|
|
|
|
)
|
2015-01-08 02:37:12 +00:00
|
|
|
|
|
|
|
|
2021-08-26 05:01:01 +00:00
|
|
|
def test_parse_stack_with_null_outputs_section():
|
2022-08-13 09:49:43 +00:00
|
|
|
with pytest.raises(ValidationError) as exc:
|
|
|
|
FakeStack(
|
|
|
|
"test_id",
|
|
|
|
"test_stack",
|
|
|
|
null_output_template_json,
|
|
|
|
{},
|
|
|
|
account_id=ACCOUNT_ID,
|
|
|
|
region_name="us-west-1",
|
|
|
|
)
|
|
|
|
err = str(exc.value)
|
|
|
|
err.should.contain("[/Outputs] 'null' values are not allowed in templates")
|
2021-08-26 05:01:01 +00:00
|
|
|
|
|
|
|
|
2019-05-20 23:05:02 +00:00
|
|
|
def test_parse_stack_with_parameters():
|
|
|
|
stack = FakeStack(
|
|
|
|
stack_id="test_id",
|
|
|
|
name="test_stack",
|
|
|
|
template=parameters_template_json,
|
2020-07-11 07:43:45 +00:00
|
|
|
parameters={
|
|
|
|
"Param": "visible value",
|
|
|
|
"NumberParam": "42",
|
|
|
|
"NumberListParam": "42,3.14159",
|
|
|
|
"NoEchoParam": "hidden value",
|
|
|
|
},
|
2022-08-13 09:49:43 +00:00
|
|
|
account_id=ACCOUNT_ID,
|
2019-10-31 15:44:26 +00:00
|
|
|
region_name="us-west-1",
|
|
|
|
)
|
2019-05-20 23:05:02 +00:00
|
|
|
|
|
|
|
stack.resource_map.no_echo_parameter_keys.should.have("NoEchoParam")
|
|
|
|
stack.resource_map.no_echo_parameter_keys.should_not.have("Param")
|
2020-07-11 07:43:45 +00:00
|
|
|
stack.resource_map.no_echo_parameter_keys.should_not.have("NumberParam")
|
|
|
|
stack.resource_map.no_echo_parameter_keys.should_not.have("NumberListParam")
|
|
|
|
stack.resource_map.resolved_parameters["NumberParam"].should.equal(42)
|
|
|
|
stack.resource_map.resolved_parameters["NumberListParam"].should.equal(
|
|
|
|
[42, 3.14159]
|
|
|
|
)
|
2019-05-20 23:05:02 +00:00
|
|
|
|
|
|
|
|
2015-01-08 02:37:12 +00:00
|
|
|
def test_parse_equals_condition():
|
|
|
|
parse_condition(
|
|
|
|
condition={"Fn::Equals": [{"Ref": "EnvType"}, "prod"]},
|
|
|
|
resources_map={"EnvType": "prod"},
|
2015-01-11 21:15:08 +00:00
|
|
|
condition_map={},
|
2015-01-08 02:37:12 +00:00
|
|
|
).should.equal(True)
|
|
|
|
|
|
|
|
parse_condition(
|
|
|
|
condition={"Fn::Equals": [{"Ref": "EnvType"}, "prod"]},
|
|
|
|
resources_map={"EnvType": "staging"},
|
2015-01-11 21:15:08 +00:00
|
|
|
condition_map={},
|
2015-01-08 02:37:12 +00:00
|
|
|
).should.equal(False)
|
|
|
|
|
|
|
|
|
|
|
|
def test_parse_not_condition():
|
|
|
|
parse_condition(
|
2019-10-31 15:44:26 +00:00
|
|
|
condition={"Fn::Not": [{"Fn::Equals": [{"Ref": "EnvType"}, "prod"]}]},
|
2015-01-08 02:37:12 +00:00
|
|
|
resources_map={"EnvType": "prod"},
|
2015-01-11 21:15:08 +00:00
|
|
|
condition_map={},
|
2015-01-08 02:37:12 +00:00
|
|
|
).should.equal(False)
|
|
|
|
|
|
|
|
parse_condition(
|
2019-10-31 15:44:26 +00:00
|
|
|
condition={"Fn::Not": [{"Fn::Equals": [{"Ref": "EnvType"}, "prod"]}]},
|
2015-01-08 02:37:12 +00:00
|
|
|
resources_map={"EnvType": "staging"},
|
2015-01-11 21:15:08 +00:00
|
|
|
condition_map={},
|
2015-01-08 02:37:12 +00:00
|
|
|
).should.equal(True)
|
|
|
|
|
|
|
|
|
|
|
|
def test_parse_and_condition():
|
|
|
|
parse_condition(
|
|
|
|
condition={
|
|
|
|
"Fn::And": [
|
|
|
|
{"Fn::Equals": [{"Ref": "EnvType"}, "prod"]},
|
|
|
|
{"Fn::Equals": [{"Ref": "EnvType"}, "staging"]},
|
|
|
|
]
|
|
|
|
},
|
|
|
|
resources_map={"EnvType": "prod"},
|
2015-01-11 21:15:08 +00:00
|
|
|
condition_map={},
|
2015-01-08 02:37:12 +00:00
|
|
|
).should.equal(False)
|
|
|
|
|
|
|
|
parse_condition(
|
|
|
|
condition={
|
|
|
|
"Fn::And": [
|
|
|
|
{"Fn::Equals": [{"Ref": "EnvType"}, "prod"]},
|
|
|
|
{"Fn::Equals": [{"Ref": "EnvType"}, "prod"]},
|
|
|
|
]
|
|
|
|
},
|
|
|
|
resources_map={"EnvType": "prod"},
|
2015-01-11 21:15:08 +00:00
|
|
|
condition_map={},
|
2015-01-08 02:37:12 +00:00
|
|
|
).should.equal(True)
|
|
|
|
|
|
|
|
|
|
|
|
def test_parse_or_condition():
|
|
|
|
parse_condition(
|
|
|
|
condition={
|
|
|
|
"Fn::Or": [
|
|
|
|
{"Fn::Equals": [{"Ref": "EnvType"}, "prod"]},
|
|
|
|
{"Fn::Equals": [{"Ref": "EnvType"}, "staging"]},
|
|
|
|
]
|
|
|
|
},
|
|
|
|
resources_map={"EnvType": "prod"},
|
2015-01-11 21:15:08 +00:00
|
|
|
condition_map={},
|
2015-01-08 02:37:12 +00:00
|
|
|
).should.equal(True)
|
|
|
|
|
|
|
|
parse_condition(
|
|
|
|
condition={
|
|
|
|
"Fn::Or": [
|
|
|
|
{"Fn::Equals": [{"Ref": "EnvType"}, "staging"]},
|
|
|
|
{"Fn::Equals": [{"Ref": "EnvType"}, "staging"]},
|
|
|
|
]
|
|
|
|
},
|
|
|
|
resources_map={"EnvType": "prod"},
|
2015-01-11 21:15:08 +00:00
|
|
|
condition_map={},
|
2015-01-08 02:37:12 +00:00
|
|
|
).should.equal(False)
|
|
|
|
|
|
|
|
|
|
|
|
def test_reference_other_conditions():
|
|
|
|
parse_condition(
|
|
|
|
condition={"Fn::Not": [{"Condition": "OtherCondition"}]},
|
2015-01-11 21:15:08 +00:00
|
|
|
resources_map={},
|
|
|
|
condition_map={"OtherCondition": True},
|
2015-01-08 02:37:12 +00:00
|
|
|
).should.equal(False)
|
2017-06-08 15:38:29 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_parse_split_and_select():
|
|
|
|
stack = FakeStack(
|
|
|
|
stack_id="test_id",
|
|
|
|
name="test_stack",
|
|
|
|
template=split_select_template_json,
|
|
|
|
parameters={},
|
2022-08-13 09:49:43 +00:00
|
|
|
account_id=ACCOUNT_ID,
|
2019-10-31 15:44:26 +00:00
|
|
|
region_name="us-west-1",
|
|
|
|
)
|
2017-06-08 15:38:29 +00:00
|
|
|
|
|
|
|
stack.resource_map.should.have.length_of(1)
|
2019-10-31 15:44:26 +00:00
|
|
|
queue = stack.resource_map["Queue"]
|
2017-06-08 15:38:29 +00:00
|
|
|
queue.name.should.equal("myqueue")
|
|
|
|
|
2017-06-08 19:21:32 +00:00
|
|
|
|
|
|
|
def test_sub():
|
|
|
|
stack = FakeStack(
|
|
|
|
stack_id="test_id",
|
|
|
|
name="test_stack",
|
|
|
|
template=sub_template_json,
|
|
|
|
parameters={},
|
2022-08-13 09:49:43 +00:00
|
|
|
account_id=ACCOUNT_ID,
|
2019-10-31 15:44:26 +00:00
|
|
|
region_name="us-west-1",
|
|
|
|
)
|
2017-06-08 19:21:32 +00:00
|
|
|
|
2019-10-31 15:44:26 +00:00
|
|
|
queue1 = stack.resource_map["Queue1"]
|
|
|
|
queue2 = stack.resource_map["Queue2"]
|
2017-06-08 19:21:32 +00:00
|
|
|
queue2.name.should.equal(queue1.name)
|
2017-06-08 19:33:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_import():
|
|
|
|
export_stack = FakeStack(
|
|
|
|
stack_id="test_id",
|
|
|
|
name="test_stack",
|
|
|
|
template=export_value_template_json,
|
|
|
|
parameters={},
|
2022-08-13 09:49:43 +00:00
|
|
|
account_id=ACCOUNT_ID,
|
2019-10-31 15:44:26 +00:00
|
|
|
region_name="us-west-1",
|
|
|
|
)
|
2017-06-08 19:33:28 +00:00
|
|
|
import_stack = FakeStack(
|
|
|
|
stack_id="test_id",
|
|
|
|
name="test_stack",
|
|
|
|
template=import_value_template_json,
|
|
|
|
parameters={},
|
2022-08-13 09:49:43 +00:00
|
|
|
account_id=ACCOUNT_ID,
|
2019-10-31 15:44:26 +00:00
|
|
|
region_name="us-west-1",
|
|
|
|
cross_stack_resources={export_stack.exports[0].value: export_stack.exports[0]},
|
|
|
|
)
|
2017-06-08 19:33:28 +00:00
|
|
|
|
2019-10-31 15:44:26 +00:00
|
|
|
queue = import_stack.resource_map["Queue"]
|
2017-06-08 19:33:28 +00:00
|
|
|
queue.name.should.equal("value")
|
2017-09-07 18:28:15 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_short_form_func_in_yaml_teamplate():
|
|
|
|
template = """---
|
|
|
|
KeyB64: !Base64 valueToEncode
|
|
|
|
KeyRef: !Ref foo
|
|
|
|
KeyAnd: !And
|
|
|
|
- A
|
|
|
|
- B
|
|
|
|
KeyEquals: !Equals [A, B]
|
|
|
|
KeyIf: !If [A, B, C]
|
|
|
|
KeyNot: !Not [A]
|
|
|
|
KeyOr: !Or [A, B]
|
|
|
|
KeyFindInMap: !FindInMap [A, B, C]
|
|
|
|
KeyGetAtt: !GetAtt A.B
|
|
|
|
KeyGetAZs: !GetAZs A
|
|
|
|
KeyImportValue: !ImportValue A
|
|
|
|
KeyJoin: !Join [ ":", [A, B, C] ]
|
|
|
|
KeySelect: !Select [A, B]
|
|
|
|
KeySplit: !Split [A, B]
|
|
|
|
KeySub: !Sub A
|
|
|
|
"""
|
2019-10-31 15:44:26 +00:00
|
|
|
yaml.add_multi_constructor("", yaml_tag_constructor, Loader=yaml.Loader)
|
2019-03-25 20:19:01 +00:00
|
|
|
template_dict = yaml.load(template, Loader=yaml.Loader)
|
2017-09-07 18:28:15 +00:00
|
|
|
key_and_expects = [
|
2019-10-31 15:44:26 +00:00
|
|
|
["KeyRef", {"Ref": "foo"}],
|
|
|
|
["KeyB64", {"Fn::Base64": "valueToEncode"}],
|
|
|
|
["KeyAnd", {"Fn::And": ["A", "B"]}],
|
|
|
|
["KeyEquals", {"Fn::Equals": ["A", "B"]}],
|
|
|
|
["KeyIf", {"Fn::If": ["A", "B", "C"]}],
|
|
|
|
["KeyNot", {"Fn::Not": ["A"]}],
|
|
|
|
["KeyOr", {"Fn::Or": ["A", "B"]}],
|
|
|
|
["KeyFindInMap", {"Fn::FindInMap": ["A", "B", "C"]}],
|
|
|
|
["KeyGetAtt", {"Fn::GetAtt": ["A", "B"]}],
|
|
|
|
["KeyGetAZs", {"Fn::GetAZs": "A"}],
|
|
|
|
["KeyImportValue", {"Fn::ImportValue": "A"}],
|
|
|
|
["KeyJoin", {"Fn::Join": [":", ["A", "B", "C"]]}],
|
|
|
|
["KeySelect", {"Fn::Select": ["A", "B"]}],
|
|
|
|
["KeySplit", {"Fn::Split": ["A", "B"]}],
|
|
|
|
["KeySub", {"Fn::Sub": "A"}],
|
2017-09-07 18:28:15 +00:00
|
|
|
]
|
|
|
|
for k, v in key_and_expects:
|
|
|
|
template_dict.should.have.key(k).which.should.be.equal(v)
|
2021-05-19 07:30:25 +00:00
|
|
|
|
|
|
|
|
|
|
|
@mock_ssm
|
|
|
|
def test_ssm_parameter_parsing():
|
|
|
|
client = boto3.client("ssm", region_name="us-west-1")
|
|
|
|
client.put_parameter(Name="/path/to/single/param", Value="string", Type="String")
|
|
|
|
client.put_parameter(
|
|
|
|
Name="/path/to/list/param", Value="comma,separated,string", Type="StringList"
|
|
|
|
)
|
|
|
|
|
|
|
|
if not settings.TEST_SERVER_MODE:
|
|
|
|
stack = FakeStack(
|
|
|
|
stack_id="test_id",
|
|
|
|
name="test_stack",
|
|
|
|
template=ssm_parameter_template_json,
|
|
|
|
parameters={
|
|
|
|
"SingleParamCfn": "/path/to/single/param",
|
|
|
|
"ListParamCfn": "/path/to/list/param",
|
|
|
|
},
|
2022-08-13 09:49:43 +00:00
|
|
|
account_id=ACCOUNT_ID,
|
2021-05-19 07:30:25 +00:00
|
|
|
region_name="us-west-1",
|
|
|
|
)
|
|
|
|
|
|
|
|
stack.resource_map.resolved_parameters["SingleParamCfn"].should.equal("string")
|
|
|
|
stack.resource_map.resolved_parameters["ListParamCfn"].should.equal(
|
|
|
|
["comma", "separated", "string"]
|
|
|
|
)
|
2021-06-29 17:28:52 +00:00
|
|
|
|
|
|
|
# Not passing in a value for ListParamCfn to test Default value
|
|
|
|
if not settings.TEST_SERVER_MODE:
|
|
|
|
stack = FakeStack(
|
|
|
|
stack_id="test_id",
|
|
|
|
name="test_stack",
|
|
|
|
template=ssm_parameter_template_json,
|
2022-03-10 14:39:59 +00:00
|
|
|
parameters={"SingleParamCfn": "/path/to/single/param"},
|
2022-08-13 09:49:43 +00:00
|
|
|
account_id=ACCOUNT_ID,
|
2021-06-29 17:28:52 +00:00
|
|
|
region_name="us-west-1",
|
|
|
|
)
|
|
|
|
|
|
|
|
stack.resource_map.resolved_parameters["SingleParamCfn"].should.equal("string")
|
|
|
|
stack.resource_map.resolved_parameters["ListParamCfn"].should.equal(
|
|
|
|
["comma", "separated", "string"]
|
|
|
|
)
|