From 12bd6af540215fce50732db59df546bda5539dc1 Mon Sep 17 00:00:00 2001 From: nom3ad <19239479+nom3ad@users.noreply.github.com> Date: Sat, 23 Oct 2021 17:10:41 +0530 Subject: [PATCH] fix(cloudformation): missing Parameters key in get_template_summary() response (#4466) --- moto/cloudformation/responses.py | 26 ++++++- tests/helpers.py | 15 +++- .../test_cloudformation_stack_crud_boto3.py | 70 ++++++++++++++++++- 3 files changed, 108 insertions(+), 3 deletions(-) diff --git a/moto/cloudformation/responses.py b/moto/cloudformation/responses.py index 2c56ef9e8..b67f2d938 100644 --- a/moto/cloudformation/responses.py +++ b/moto/cloudformation/responses.py @@ -1186,14 +1186,38 @@ LIST_STACK_SET_OPERATION_RESULTS_RESPONSE_TEMPLATE = ( """ ) +# https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_GetTemplateSummary.html +# TODO:implement fields: ResourceIdentifierSummaries, Capabilities, CapabilitiesReason GET_TEMPLATE_SUMMARY_TEMPLATE = """ {{ template_summary.Description }} {% for resource in template_summary.resourceTypes %} - {{ resource }} + {{ resource }} {% endfor %} + + {% for k,p in template_summary.get('Parameters',{}).items() %} + + {{ k }} , + {{ p.get('Description', '') }}, + {% if p.Default %} + {{ p.Default }} + {% endif %} + {{ p.get('NoEcho', False) }} + {{ p.get('Type', 'String') }} + + {% if p.AllowedValues %} + + {% for v in p.AllowedValues %} + {{ v }} + {% endfor %} + + {% endif %} + + + {% endfor %} + {{ template_summary.AWSTemplateFormatVersion }} diff --git a/tests/helpers.py b/tests/helpers.py index dc4dc9a5b..93f4db41a 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -1,6 +1,6 @@ import boto from unittest import SkipTest -from collections.abc import Iterable +from collections.abc import Iterable, Mapping from sure import assertion @@ -45,3 +45,16 @@ def containing_item_with_attributes(context, **kwargs): else: assert contains, f"{context.obj} does not contain matching item {kwargs}" return True + + +@assertion +def match_dict(context, dict_value): + assert isinstance(dict_value, Mapping), f"Invalid match target value: {dict_value}" + assert isinstance( + context.obj, Mapping + ), f"Expected dict like object, but got: {context.obj}" + + for k, v in dict_value.items(): + assert k in context.obj, f"No such key '{k}' in {context.obj}" + context.obj[k].should.equal(v) + return True diff --git a/tests/test_cloudformation/test_cloudformation_stack_crud_boto3.py b/tests/test_cloudformation/test_cloudformation_stack_crud_boto3.py index 949aa1a66..402e3acff 100644 --- a/tests/test_cloudformation/test_cloudformation_stack_crud_boto3.py +++ b/tests/test_cloudformation/test_cloudformation_stack_crud_boto3.py @@ -55,6 +55,28 @@ dummy_template3 = { }, } + +dummy_template_with_parameters = { + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "A simple CloudFormation template", + "Resources": { + "Bucket": { + "Type": "AWS::S3::Bucket", + "Properties": {"BucketName": {"Ref": "Name"}}, + } + }, + "Parameters": { + "Name": {"Type": "String", "Default": "SomeValue"}, + "Another": { + "Type": "String", + "Default": "A", + "AllowedValues": ["A", "B"], + "Description": "Chose A or B", + }, + }, +} + + dummy_template_yaml = """--- AWSTemplateFormatVersion: 2010-09-09 Description: Stack1 with yaml template @@ -70,6 +92,7 @@ Resources: Value: Test tag - Key: Name Value: Name tag for tests + Parameters: """ dummy_template_yaml_with_short_form_func = """--- @@ -867,6 +890,7 @@ def test_get_template_summary(): result["ResourceTypes"].should.equal(["AWS::EC2::VPC"]) result["Version"].should.equal("2010-09-09") result["Description"].should.equal("Stack 3") + result["Parameters"].should.equal([]) # existing stack conn.create_stack(StackName="test_stack", TemplateBody=json.dumps(dummy_template3)) @@ -874,6 +898,7 @@ def test_get_template_summary(): result["ResourceTypes"].should.equal(["AWS::EC2::VPC"]) result["Version"].should.equal("2010-09-09") result["Description"].should.equal("Stack 3") + result["Parameters"].should.equal([]) # json template from s3 s3_conn.create_bucket(Bucket="foobar") @@ -896,7 +921,7 @@ def test_get_template_summary(): @mock_cloudformation -def test_get_template_summary_for_stack_createed_by_changeset_execution(): +def test_get_template_summary_for_stack_created_by_changeset_execution(): conn = boto3.client("cloudformation", region_name="us-east-1") conn.create_change_set( StackName="stack_from_changeset", @@ -916,6 +941,49 @@ def test_get_template_summary_for_stack_createed_by_changeset_execution(): result["Description"].should.equal("Stack 3") +@mock_s3 +@mock_cloudformation +def test_get_template_summary_for_template_containing_parameters(): + conn = boto3.client("cloudformation", region_name="us-east-1") + conn.create_stack( + StackName="test_stack", TemplateBody=json.dumps(dummy_template_with_parameters) + ) + result = conn.get_template_summary(StackName="test_stack") + result.should.match_dict( + { + "Parameters": [ + { + "ParameterKey": "Name", + "DefaultValue": "SomeValue", + "ParameterType": "String", + "NoEcho": False, + "Description": "", + "ParameterConstraints": {}, + }, + { + "ParameterKey": "Another", + "DefaultValue": "A", + "ParameterType": "String", + "NoEcho": False, + "Description": "Chose A or B", + "ParameterConstraints": {"AllowedValues": ["A", "B"]}, + }, + ], + "Description": "A simple CloudFormation template", + "ResourceTypes": ["AWS::S3::Bucket"], + "Version": "2010-09-09", + # TODO: get_template_summary should support ResourceIdentifierSummaries + # "ResourceIdentifierSummaries": [ + # { + # "ResourceType": "AWS::S3::Bucket", + # "LogicalResourceIds": ["Bucket"], + # "ResourceIdentifiers": ["BucketName"], + # } + # ], + } + ) + + @mock_cloudformation def test_boto3_create_stack_with_ref_yaml(): cf_conn = boto3.client("cloudformation", region_name="us-east-1")