Add missing changes when creating a change set (#3039)
* Display changes when creating a change set * add change set id and description when describing stack * fix lint with flake8 and black
This commit is contained in:
parent
cb600377b4
commit
90e200f0f6
@ -219,7 +219,12 @@ class FakeStack(BaseModel):
|
|||||||
self.stack_id = stack_id
|
self.stack_id = stack_id
|
||||||
self.name = name
|
self.name = name
|
||||||
self.template = template
|
self.template = template
|
||||||
|
if template != {}:
|
||||||
self._parse_template()
|
self._parse_template()
|
||||||
|
self.description = self.template_dict.get("Description")
|
||||||
|
else:
|
||||||
|
self.template_dict = {}
|
||||||
|
self.description = None
|
||||||
self.parameters = parameters
|
self.parameters = parameters
|
||||||
self.region_name = region_name
|
self.region_name = region_name
|
||||||
self.notification_arns = notification_arns if notification_arns else []
|
self.notification_arns = notification_arns if notification_arns else []
|
||||||
@ -235,7 +240,6 @@ class FakeStack(BaseModel):
|
|||||||
"CREATE_IN_PROGRESS", resource_status_reason="User Initiated"
|
"CREATE_IN_PROGRESS", resource_status_reason="User Initiated"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.description = self.template_dict.get("Description")
|
|
||||||
self.cross_stack_resources = cross_stack_resources or {}
|
self.cross_stack_resources = cross_stack_resources or {}
|
||||||
self.resource_map = self._create_resource_map()
|
self.resource_map = self._create_resource_map()
|
||||||
self.output_map = self._create_output_map()
|
self.output_map = self._create_output_map()
|
||||||
@ -331,7 +335,9 @@ class FakeStack(BaseModel):
|
|||||||
return self.output_map.exports
|
return self.output_map.exports
|
||||||
|
|
||||||
def create_resources(self):
|
def create_resources(self):
|
||||||
self.resource_map.create()
|
self.resource_map.create(self.template_dict)
|
||||||
|
# Set the description of the stack
|
||||||
|
self.description = self.template_dict.get("Description")
|
||||||
self.status = "CREATE_COMPLETE"
|
self.status = "CREATE_COMPLETE"
|
||||||
|
|
||||||
def update(self, template, role_arn=None, parameters=None, tags=None):
|
def update(self, template, role_arn=None, parameters=None, tags=None):
|
||||||
@ -398,6 +404,8 @@ class FakeChangeSet(FakeStack):
|
|||||||
self.change_set_id = change_set_id
|
self.change_set_id = change_set_id
|
||||||
self.change_set_name = change_set_name
|
self.change_set_name = change_set_name
|
||||||
self.changes = self.diff(template=template, parameters=parameters)
|
self.changes = self.diff(template=template, parameters=parameters)
|
||||||
|
if self.description is None:
|
||||||
|
self.description = self.template_dict.get("Description")
|
||||||
self.creation_time = datetime.utcnow()
|
self.creation_time = datetime.utcnow()
|
||||||
|
|
||||||
def diff(self, template, parameters=None):
|
def diff(self, template, parameters=None):
|
||||||
@ -590,7 +598,7 @@ class CloudFormationBackend(BaseBackend):
|
|||||||
raise ValidationError(stack_name)
|
raise ValidationError(stack_name)
|
||||||
else:
|
else:
|
||||||
stack_id = generate_stack_id(stack_name, region_name)
|
stack_id = generate_stack_id(stack_name, region_name)
|
||||||
stack_template = template
|
stack_template = {}
|
||||||
|
|
||||||
change_set_id = generate_changeset_id(change_set_name, region_name)
|
change_set_id = generate_changeset_id(change_set_name, region_name)
|
||||||
new_change_set = FakeChangeSet(
|
new_change_set = FakeChangeSet(
|
||||||
@ -645,6 +653,9 @@ class CloudFormationBackend(BaseBackend):
|
|||||||
if stack is None:
|
if stack is None:
|
||||||
raise ValidationError(stack_name)
|
raise ValidationError(stack_name)
|
||||||
if stack.events[-1].resource_status == "REVIEW_IN_PROGRESS":
|
if stack.events[-1].resource_status == "REVIEW_IN_PROGRESS":
|
||||||
|
stack._add_stack_event(
|
||||||
|
"CREATE_IN_PROGRESS", resource_status_reason="User Initiated"
|
||||||
|
)
|
||||||
stack._add_stack_event("CREATE_COMPLETE")
|
stack._add_stack_event("CREATE_COMPLETE")
|
||||||
else:
|
else:
|
||||||
stack._add_stack_event("UPDATE_IN_PROGRESS")
|
stack._add_stack_event("UPDATE_IN_PROGRESS")
|
||||||
|
@ -456,7 +456,7 @@ class ResourceMap(collections_abc.Mapping):
|
|||||||
cross_stack_resources,
|
cross_stack_resources,
|
||||||
):
|
):
|
||||||
self._template = template
|
self._template = template
|
||||||
self._resource_json_map = template["Resources"]
|
self._resource_json_map = template["Resources"] if template != {} else {}
|
||||||
self._region_name = region_name
|
self._region_name = region_name
|
||||||
self.input_parameters = parameters
|
self.input_parameters = parameters
|
||||||
self.tags = copy.deepcopy(tags)
|
self.tags = copy.deepcopy(tags)
|
||||||
@ -592,10 +592,12 @@ class ResourceMap(collections_abc.Mapping):
|
|||||||
self.load_parameters()
|
self.load_parameters()
|
||||||
self.load_conditions()
|
self.load_conditions()
|
||||||
|
|
||||||
def create(self):
|
def create(self, template):
|
||||||
# Since this is a lazy map, to create every object we just need to
|
# Since this is a lazy map, to create every object we just need to
|
||||||
# iterate through self.
|
# iterate through self.
|
||||||
# Assumes that self.load() has been called before
|
# Assumes that self.load() has been called before
|
||||||
|
self._template = template
|
||||||
|
self._resource_json_map = template["Resources"]
|
||||||
self.tags.update(
|
self.tags.update(
|
||||||
{
|
{
|
||||||
"aws:cloudformation:stack-name": self.get("AWS::StackName"),
|
"aws:cloudformation:stack-name": self.get("AWS::StackName"),
|
||||||
|
@ -662,6 +662,10 @@ DESCRIBE_STACKS_TEMPLATE = """<DescribeStacksResponse>
|
|||||||
<member>
|
<member>
|
||||||
<StackName>{{ stack.name }}</StackName>
|
<StackName>{{ stack.name }}</StackName>
|
||||||
<StackId>{{ stack.stack_id }}</StackId>
|
<StackId>{{ stack.stack_id }}</StackId>
|
||||||
|
{% if stack.change_set_id %}
|
||||||
|
<ChangeSetId>{{ stack.change_set_id }}</ChangeSetId>
|
||||||
|
{% endif %}
|
||||||
|
<Description>{{ stack.description }}</Description>
|
||||||
<CreationTime>{{ stack.creation_time_iso_8601 }}</CreationTime>
|
<CreationTime>{{ stack.creation_time_iso_8601 }}</CreationTime>
|
||||||
<StackStatus>{{ stack.status }}</StackStatus>
|
<StackStatus>{{ stack.status }}</StackStatus>
|
||||||
{% if stack.notification_arns %}
|
{% if stack.notification_arns %}
|
||||||
|
@ -573,9 +573,9 @@ def test_boto3_create_stack_set_with_yaml():
|
|||||||
def test_create_stack_set_from_s3_url():
|
def test_create_stack_set_from_s3_url():
|
||||||
s3 = boto3.client("s3")
|
s3 = boto3.client("s3")
|
||||||
s3_conn = boto3.resource("s3", region_name="us-east-1")
|
s3_conn = boto3.resource("s3", region_name="us-east-1")
|
||||||
bucket = s3_conn.create_bucket(Bucket="foobar")
|
s3_conn.create_bucket(Bucket="foobar")
|
||||||
|
|
||||||
key = s3_conn.Object("foobar", "template-key").put(Body=dummy_template_json)
|
s3_conn.Object("foobar", "template-key").put(Body=dummy_template_json)
|
||||||
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"}
|
||||||
)
|
)
|
||||||
@ -716,9 +716,9 @@ def test_create_stack_with_role_arn():
|
|||||||
def test_create_stack_from_s3_url():
|
def test_create_stack_from_s3_url():
|
||||||
s3 = boto3.client("s3")
|
s3 = boto3.client("s3")
|
||||||
s3_conn = boto3.resource("s3", region_name="us-east-1")
|
s3_conn = boto3.resource("s3", region_name="us-east-1")
|
||||||
bucket = s3_conn.create_bucket(Bucket="foobar")
|
s3_conn.create_bucket(Bucket="foobar")
|
||||||
|
|
||||||
key = s3_conn.Object("foobar", "template-key").put(Body=dummy_template_json)
|
s3_conn.Object("foobar", "template-key").put(Body=dummy_template_json)
|
||||||
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"}
|
||||||
)
|
)
|
||||||
@ -800,9 +800,9 @@ def test_update_stack_from_s3_url():
|
|||||||
def test_create_change_set_from_s3_url():
|
def test_create_change_set_from_s3_url():
|
||||||
s3 = boto3.client("s3")
|
s3 = boto3.client("s3")
|
||||||
s3_conn = boto3.resource("s3", region_name="us-east-1")
|
s3_conn = boto3.resource("s3", region_name="us-east-1")
|
||||||
bucket = s3_conn.create_bucket(Bucket="foobar")
|
s3_conn.create_bucket(Bucket="foobar")
|
||||||
|
|
||||||
key = s3_conn.Object("foobar", "template-key").put(Body=dummy_template_json)
|
s3_conn.Object("foobar", "template-key").put(Body=dummy_template_json)
|
||||||
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"}
|
||||||
)
|
)
|
||||||
@ -844,6 +844,25 @@ def test_describe_change_set():
|
|||||||
assert (
|
assert (
|
||||||
two_secs_ago < stack["CreationTime"] < datetime.now(tz=pytz.UTC)
|
two_secs_ago < stack["CreationTime"] < datetime.now(tz=pytz.UTC)
|
||||||
), "Change set should have been created recently"
|
), "Change set should have been created recently"
|
||||||
|
stack["Changes"].should.have.length_of(1)
|
||||||
|
stack["Changes"][0].should.equal(
|
||||||
|
dict(
|
||||||
|
{
|
||||||
|
"Type": "Resource",
|
||||||
|
"ResourceChange": {
|
||||||
|
"Action": "Add",
|
||||||
|
"LogicalResourceId": "EC2Instance1",
|
||||||
|
"ResourceType": "AWS::EC2::Instance",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Execute change set
|
||||||
|
cf_conn.execute_change_set(ChangeSetName="NewChangeSet")
|
||||||
|
# Verify that the changes have been applied
|
||||||
|
stack = cf_conn.describe_change_set(ChangeSetName="NewChangeSet")
|
||||||
|
stack["Changes"].should.have.length_of(1)
|
||||||
|
|
||||||
cf_conn.create_change_set(
|
cf_conn.create_change_set(
|
||||||
StackName="NewStack",
|
StackName="NewStack",
|
||||||
@ -887,7 +906,7 @@ def test_execute_change_set_w_arn():
|
|||||||
@mock_cloudformation
|
@mock_cloudformation
|
||||||
def test_execute_change_set_w_name():
|
def test_execute_change_set_w_name():
|
||||||
cf_conn = boto3.client("cloudformation", region_name="us-east-1")
|
cf_conn = boto3.client("cloudformation", region_name="us-east-1")
|
||||||
change_set = cf_conn.create_change_set(
|
cf_conn.create_change_set(
|
||||||
StackName="NewStack",
|
StackName="NewStack",
|
||||||
TemplateBody=dummy_template_json,
|
TemplateBody=dummy_template_json,
|
||||||
ChangeSetName="NewChangeSet",
|
ChangeSetName="NewChangeSet",
|
||||||
@ -1221,9 +1240,7 @@ def test_delete_stack_with_export():
|
|||||||
@mock_cloudformation
|
@mock_cloudformation
|
||||||
def test_export_names_must_be_unique():
|
def test_export_names_must_be_unique():
|
||||||
cf = boto3.resource("cloudformation", region_name="us-east-1")
|
cf = boto3.resource("cloudformation", region_name="us-east-1")
|
||||||
first_stack = cf.create_stack(
|
cf.create_stack(StackName="test_stack", TemplateBody=dummy_output_template_json)
|
||||||
StackName="test_stack", TemplateBody=dummy_output_template_json
|
|
||||||
)
|
|
||||||
with assert_raises(ClientError):
|
with assert_raises(ClientError):
|
||||||
cf.create_stack(StackName="test_stack", TemplateBody=dummy_output_template_json)
|
cf.create_stack(StackName="test_stack", TemplateBody=dummy_output_template_json)
|
||||||
|
|
||||||
@ -1237,9 +1254,7 @@ def test_stack_with_imports():
|
|||||||
output_stack = cf.create_stack(
|
output_stack = cf.create_stack(
|
||||||
StackName="test_stack1", TemplateBody=dummy_output_template_json
|
StackName="test_stack1", TemplateBody=dummy_output_template_json
|
||||||
)
|
)
|
||||||
import_stack = cf.create_stack(
|
cf.create_stack(StackName="test_stack2", TemplateBody=dummy_import_template_json)
|
||||||
StackName="test_stack2", TemplateBody=dummy_import_template_json
|
|
||||||
)
|
|
||||||
|
|
||||||
output_stack.outputs.should.have.length_of(1)
|
output_stack.outputs.should.have.length_of(1)
|
||||||
output = output_stack.outputs[0]["OutputValue"]
|
output = output_stack.outputs[0]["OutputValue"]
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import json
|
import json
|
||||||
|
|
||||||
import base64
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
import boto
|
import boto
|
||||||
@ -28,7 +27,6 @@ from moto import (
|
|||||||
mock_dynamodb2,
|
mock_dynamodb2,
|
||||||
mock_ec2,
|
mock_ec2,
|
||||||
mock_ec2_deprecated,
|
mock_ec2_deprecated,
|
||||||
mock_elb,
|
|
||||||
mock_elb_deprecated,
|
mock_elb_deprecated,
|
||||||
mock_events,
|
mock_events,
|
||||||
mock_iam_deprecated,
|
mock_iam_deprecated,
|
||||||
@ -37,18 +35,14 @@ from moto import (
|
|||||||
mock_logs,
|
mock_logs,
|
||||||
mock_rds_deprecated,
|
mock_rds_deprecated,
|
||||||
mock_rds2,
|
mock_rds2,
|
||||||
mock_rds2_deprecated,
|
|
||||||
mock_redshift,
|
|
||||||
mock_redshift_deprecated,
|
mock_redshift_deprecated,
|
||||||
mock_route53_deprecated,
|
mock_route53_deprecated,
|
||||||
mock_s3,
|
mock_s3,
|
||||||
mock_sns_deprecated,
|
mock_sns_deprecated,
|
||||||
mock_sqs,
|
|
||||||
mock_sqs_deprecated,
|
mock_sqs_deprecated,
|
||||||
mock_elbv2,
|
mock_elbv2,
|
||||||
)
|
)
|
||||||
from moto.core import ACCOUNT_ID
|
from moto.core import ACCOUNT_ID
|
||||||
from moto.dynamodb2.models import Table
|
|
||||||
|
|
||||||
from tests.test_cloudformation.fixtures import (
|
from tests.test_cloudformation.fixtures import (
|
||||||
ec2_classic_eip,
|
ec2_classic_eip,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user