CF - detect changesets without changes (#5058)

This commit is contained in:
Bert Blommers 2022-04-24 21:37:14 +00:00 committed by GitHub
parent 96996b6b46
commit be52b4d7a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 100 additions and 2 deletions

View File

@ -251,6 +251,17 @@ class FakeStack(BaseModel):
self.creation_time = datetime.utcnow()
self.status = "CREATE_PENDING"
def has_template(self, other_template):
our_template = (
self.template
if isinstance(self.template, dict)
else json.loads(self.template)
)
return our_template == json.loads(other_template)
def has_parameters(self, other_parameters):
return self.parameters == other_parameters
def _create_resource_map(self):
resource_map = ResourceMap(
self.stack_id,
@ -732,8 +743,18 @@ class CloudFormationBackend(BaseBackend):
tags=tags,
role_arn=role_arn,
)
new_change_set.status = "CREATE_COMPLETE"
new_change_set.execution_status = "AVAILABLE"
if (
change_set_type == "UPDATE"
and stack.has_template(template)
and stack.has_parameters(parameters)
):
# Nothing has changed - mark it as such
new_change_set.status = "FAILED"
new_change_set.execution_status = "UNAVAILABLE"
new_change_set.status_reason = "The submitted information didn't contain changes. Submit different information to create a change set."
else:
new_change_set.status = "CREATE_COMPLETE"
new_change_set.execution_status = "AVAILABLE"
self.change_sets[change_set_id] = new_change_set
return change_set_id, stack.stack_id

View File

@ -1641,6 +1641,83 @@ def test_delete_change_set():
cf_conn.list_change_sets(StackName="NewStack")["Summaries"].should.have.length_of(0)
@mock_cloudformation
@mock_ec2
def test_create_change_set_twice__no_changes():
cf_client = boto3.client("cloudformation", region_name="us-east-1")
# Execute once
change_set_id = cf_client.create_change_set(
StackName="NewStack",
TemplateBody=dummy_template_json,
ChangeSetName="NewChangeSet",
ChangeSetType="CREATE",
)["Id"]
cf_client.execute_change_set(ChangeSetName=change_set_id, DisableRollback=False)
# Execute twice
change_set_id = cf_client.create_change_set(
StackName="NewStack",
TemplateBody=dummy_template_json,
ChangeSetName="NewChangeSet",
ChangeSetType="UPDATE",
)["Id"]
execution = cf_client.describe_change_set(ChangeSetName=change_set_id)
# Assert
execution["ExecutionStatus"].should.equal("UNAVAILABLE")
execution["Status"].should.equal("FAILED")
execution["StatusReason"].should.equal(
"The submitted information didn't contain changes. Submit different information to create a change set."
)
@mock_cloudformation
@mock_ec2
@mock_s3
def test_create_change_set_twice__using_s3__no_changes():
cf_client = boto3.client("cloudformation", 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.create_bucket(Bucket="foobar")
s3_conn.Object("foobar", "template-key").put(Body=dummy_template_json)
key_url_1 = s3.generate_presigned_url(
ClientMethod="get_object", Params={"Bucket": "foobar", "Key": "template-key"}
)
s3_conn.Object("foobar", "template-key-unchanged").put(Body=dummy_template_json)
key_url_2 = s3.generate_presigned_url(
ClientMethod="get_object",
Params={"Bucket": "foobar", "Key": "template-key-unchanged"},
)
# Execute once
change_set_id = cf_client.create_change_set(
StackName="NewStack",
TemplateURL=key_url_1,
ChangeSetName="NewChangeSet",
ChangeSetType="CREATE",
)["Id"]
cf_client.execute_change_set(ChangeSetName=change_set_id, DisableRollback=False)
# Execute twice
change_set_id = cf_client.create_change_set(
StackName="NewStack",
TemplateURL=key_url_2,
ChangeSetName="NewChangeSet",
ChangeSetType="UPDATE",
)["Id"]
execution = cf_client.describe_change_set(ChangeSetName=change_set_id)
# Assert
execution["ExecutionStatus"].should.equal("UNAVAILABLE")
execution["Status"].should.equal("FAILED")
execution["StatusReason"].should.equal(
"The submitted information didn't contain changes. Submit different information to create a change set."
)
@mock_cloudformation
@mock_ec2
def test_delete_stack_by_name():