cloudformation: fix get_template_summary() related error (#4425)

This commit is contained in:
nom3ad 2021-10-18 14:43:27 +05:30 committed by GitHub
parent 9d552c39ea
commit 080e7eba84
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 40 additions and 15 deletions

View File

@ -11,7 +11,7 @@ class UnformattedGetAttTemplateException(Exception):
class ValidationError(BadRequest): class ValidationError(BadRequest):
def __init__(self, name_or_id, message=None): def __init__(self, name_or_id=None, message=None):
if message is None: if message is None:
message = "Stack with id {0} does not exist".format(name_or_id) message = "Stack with id {0} does not exist".format(name_or_id)

View File

@ -745,24 +745,25 @@ class CloudFormationBackend(BaseBackend):
if change_set is None: if change_set is None:
raise ValidationError(stack_name) raise ValidationError(stack_name)
stack = self.stacks[change_set.stack_id]
# TODO: handle execution errors and implement rollback
if change_set.change_set_type == "CREATE": if change_set.change_set_type == "CREATE":
change_set.stack._add_stack_event( stack._add_stack_event(
"CREATE_IN_PROGRESS", resource_status_reason="User Initiated" "CREATE_IN_PROGRESS", resource_status_reason="User Initiated"
) )
change_set.apply() change_set.apply()
change_set.stack._add_stack_event("CREATE_COMPLETE") stack._add_stack_event("CREATE_COMPLETE")
else: else:
change_set.stack._add_stack_event("UPDATE_IN_PROGRESS") stack._add_stack_event("UPDATE_IN_PROGRESS")
change_set.apply() change_set.apply()
change_set.stack._add_stack_event("UPDATE_COMPLETE") stack._add_stack_event("UPDATE_COMPLETE")
# set the execution status of the changeset # set the execution status of the changeset
change_set.execution_status = "EXECUTE_COMPLETE" change_set.execution_status = "EXECUTE_COMPLETE"
# set the status of the stack # set the status of the stack
self.stacks[ stack.status = f"{change_set.change_set_type}_COMPLETE"
change_set.stack_id stack.template = change_set.template
].status = f"{change_set.change_set_type}_COMPLETE"
return True return True
def describe_stacks(self, name_or_stack_id): def describe_stacks(self, name_or_stack_id):

View File

@ -324,7 +324,12 @@ class CloudFormationResponse(BaseResponse):
stack_body = self._get_param("TemplateBody") stack_body = self._get_param("TemplateBody")
if stack_name: if stack_name:
stack_body = self.cloudformation_backend.get_stack(stack_name).template stack = self.cloudformation_backend.get_stack(stack_name)
if stack.status == "REVIEW_IN_PROGRESS":
raise ValidationError(
message="GetTemplateSummary cannot be called on REVIEW_IN_PROGRESS stacks.",
)
stack_body = stack.template
elif template_url: elif template_url:
stack_body = self._get_stack_from_s3_url(template_url) stack_body = self._get_stack_from_s3_url(template_url)

View File

@ -862,42 +862,61 @@ def test_get_template_summary():
s3 = boto3.client("s3", region_name="us-east-1") s3 = boto3.client("s3", region_name="us-east-1")
s3_conn = boto3.resource("s3", region_name="us-east-1") s3_conn = boto3.resource("s3", region_name="us-east-1")
# json template
conn = boto3.client("cloudformation", region_name="us-east-1") conn = boto3.client("cloudformation", region_name="us-east-1")
result = conn.get_template_summary(TemplateBody=json.dumps(dummy_template3)) result = conn.get_template_summary(TemplateBody=json.dumps(dummy_template3))
result["ResourceTypes"].should.equal(["AWS::EC2::VPC"]) result["ResourceTypes"].should.equal(["AWS::EC2::VPC"])
result["Version"].should.equal("2010-09-09") result["Version"].should.equal("2010-09-09")
result["Description"].should.equal("Stack 3") result["Description"].should.equal("Stack 3")
# existing stack
conn.create_stack(StackName="test_stack", TemplateBody=json.dumps(dummy_template3)) conn.create_stack(StackName="test_stack", TemplateBody=json.dumps(dummy_template3))
result = conn.get_template_summary(StackName="test_stack") result = conn.get_template_summary(StackName="test_stack")
result["ResourceTypes"].should.equal(["AWS::EC2::VPC"]) result["ResourceTypes"].should.equal(["AWS::EC2::VPC"])
result["Version"].should.equal("2010-09-09") result["Version"].should.equal("2010-09-09")
result["Description"].should.equal("Stack 3") result["Description"].should.equal("Stack 3")
# json template from s3
s3_conn.create_bucket(Bucket="foobar") s3_conn.create_bucket(Bucket="foobar")
s3_conn.Object("foobar", "template-key").put(Body=json.dumps(dummy_template3)) s3_conn.Object("foobar", "template-key").put(Body=json.dumps(dummy_template3))
key_url = s3.generate_presigned_url( key_url = s3.generate_presigned_url(
ClientMethod="get_object", Params={"Bucket": "foobar", "Key": "template-key"} ClientMethod="get_object", Params={"Bucket": "foobar", "Key": "template-key"}
) )
conn.create_stack(StackName="stack_from_url", TemplateURL=key_url) conn.create_stack(StackName="stack_from_url", TemplateURL=key_url)
result = conn.get_template_summary(TemplateURL=key_url) result = conn.get_template_summary(TemplateURL=key_url)
result["ResourceTypes"].should.equal(["AWS::EC2::VPC"]) result["ResourceTypes"].should.equal(["AWS::EC2::VPC"])
result["Version"].should.equal("2010-09-09") result["Version"].should.equal("2010-09-09")
result["Description"].should.equal("Stack 3") result["Description"].should.equal("Stack 3")
# yaml template
conn = boto3.client("cloudformation", region_name="us-east-1") conn = boto3.client("cloudformation", region_name="us-east-1")
result = conn.get_template_summary(TemplateBody=dummy_template_yaml) result = conn.get_template_summary(TemplateBody=dummy_template_yaml)
result["ResourceTypes"].should.equal(["AWS::EC2::Instance"]) result["ResourceTypes"].should.equal(["AWS::EC2::Instance"])
result["Version"].should.equal("2010-09-09") result["Version"].should.equal("2010-09-09")
result["Description"].should.equal("Stack1 with yaml template") result["Description"].should.equal("Stack1 with yaml template")
@mock_cloudformation
def test_get_template_summary_for_stack_createed_by_changeset_execution():
conn = boto3.client("cloudformation", region_name="us-east-1")
conn.create_change_set(
StackName="stack_from_changeset",
TemplateBody=json.dumps(dummy_template3),
ChangeSetName="test_changeset",
ChangeSetType="CREATE",
)
with pytest.raises(
ClientError,
match="GetTemplateSummary cannot be called on REVIEW_IN_PROGRESS stacks",
):
conn.get_template_summary(StackName="stack_from_changeset")
conn.execute_change_set(ChangeSetName="test_changeset")
result = conn.get_template_summary(StackName="stack_from_changeset")
result["ResourceTypes"].should.equal(["AWS::EC2::VPC"])
result["Version"].should.equal("2010-09-09")
result["Description"].should.equal("Stack 3")
@mock_cloudformation @mock_cloudformation
def test_boto3_create_stack_with_ref_yaml(): def test_boto3_create_stack_with_ref_yaml():
cf_conn = boto3.client("cloudformation", region_name="us-east-1") cf_conn = boto3.client("cloudformation", region_name="us-east-1")