Rewrite deprecated CloudFormation tests (#3842)
This commit is contained in:
parent
c5f2a40245
commit
e9a4100324
@ -1,11 +1,8 @@
|
||||
import boto3
|
||||
import json
|
||||
import sure # noqa
|
||||
|
||||
from moto import (
|
||||
mock_autoscaling,
|
||||
mock_cloudformation,
|
||||
mock_ec2,
|
||||
)
|
||||
from moto import mock_autoscaling, mock_cloudformation, mock_ec2, mock_elb
|
||||
|
||||
from .utils import setup_networking
|
||||
from tests import EXAMPLE_AMI_ID
|
||||
@ -276,3 +273,194 @@ Outputs:
|
||||
lt["LaunchTemplateId"].should.be.equal(launch_template_id)
|
||||
lt["LaunchTemplateName"].should.be.equal("test_launch_template_new")
|
||||
lt["Version"].should.be.equal("1")
|
||||
|
||||
|
||||
@mock_autoscaling
|
||||
@mock_elb
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
def test_autoscaling_group_with_elb():
|
||||
web_setup_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"my-as-group": {
|
||||
"Type": "AWS::AutoScaling::AutoScalingGroup",
|
||||
"Properties": {
|
||||
"AvailabilityZones": ["us-east-1a"],
|
||||
"LaunchConfigurationName": {"Ref": "my-launch-config"},
|
||||
"MinSize": "2",
|
||||
"MaxSize": "2",
|
||||
"DesiredCapacity": "2",
|
||||
"LoadBalancerNames": [{"Ref": "my-elb"}],
|
||||
"Tags": [
|
||||
{
|
||||
"Key": "propagated-test-tag",
|
||||
"Value": "propagated-test-tag-value",
|
||||
"PropagateAtLaunch": True,
|
||||
},
|
||||
{
|
||||
"Key": "not-propagated-test-tag",
|
||||
"Value": "not-propagated-test-tag-value",
|
||||
"PropagateAtLaunch": False,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
"my-launch-config": {
|
||||
"Type": "AWS::AutoScaling::LaunchConfiguration",
|
||||
"Properties": {
|
||||
"ImageId": EXAMPLE_AMI_ID,
|
||||
"InstanceType": "t2.medium",
|
||||
"UserData": "some user data",
|
||||
},
|
||||
},
|
||||
"my-elb": {
|
||||
"Type": "AWS::ElasticLoadBalancing::LoadBalancer",
|
||||
"Properties": {
|
||||
"AvailabilityZones": ["us-east-1a"],
|
||||
"Listeners": [
|
||||
{
|
||||
"LoadBalancerPort": "80",
|
||||
"InstancePort": "80",
|
||||
"Protocol": "HTTP",
|
||||
}
|
||||
],
|
||||
"LoadBalancerName": "my-elb",
|
||||
"HealthCheck": {
|
||||
"Target": "HTTP:80",
|
||||
"HealthyThreshold": "3",
|
||||
"UnhealthyThreshold": "5",
|
||||
"Interval": "30",
|
||||
"Timeout": "5",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
web_setup_template_json = json.dumps(web_setup_template)
|
||||
|
||||
cf = boto3.client("cloudformation", region_name="us-east-1")
|
||||
ec2 = boto3.client("ec2", region_name="us-east-1")
|
||||
elb = boto3.client("elb", region_name="us-east-1")
|
||||
client = boto3.client("autoscaling", region_name="us-east-1")
|
||||
|
||||
cf.create_stack(StackName="web_stack", TemplateBody=web_setup_template_json)
|
||||
|
||||
autoscale_group = client.describe_auto_scaling_groups()["AutoScalingGroups"][0]
|
||||
autoscale_group["LaunchConfigurationName"].should.contain("my-launch-config")
|
||||
autoscale_group["LoadBalancerNames"].should.equal(["my-elb"])
|
||||
|
||||
# Confirm the Launch config was actually created
|
||||
client.describe_launch_configurations()[
|
||||
"LaunchConfigurations"
|
||||
].should.have.length_of(1)
|
||||
|
||||
# Confirm the ELB was actually created
|
||||
elb.describe_load_balancers()["LoadBalancerDescriptions"].should.have.length_of(1)
|
||||
|
||||
resources = cf.list_stack_resources(StackName="web_stack")["StackResourceSummaries"]
|
||||
as_group_resource = [
|
||||
resource
|
||||
for resource in resources
|
||||
if resource["ResourceType"] == "AWS::AutoScaling::AutoScalingGroup"
|
||||
][0]
|
||||
as_group_resource["PhysicalResourceId"].should.contain("my-as-group")
|
||||
|
||||
launch_config_resource = [
|
||||
resource
|
||||
for resource in resources
|
||||
if resource["ResourceType"] == "AWS::AutoScaling::LaunchConfiguration"
|
||||
][0]
|
||||
launch_config_resource["PhysicalResourceId"].should.contain("my-launch-config")
|
||||
|
||||
elb_resource = [
|
||||
resource
|
||||
for resource in resources
|
||||
if resource["ResourceType"] == "AWS::ElasticLoadBalancing::LoadBalancer"
|
||||
][0]
|
||||
elb_resource["PhysicalResourceId"].should.contain("my-elb")
|
||||
|
||||
# confirm the instances were created with the right tags
|
||||
reservations = ec2.describe_instances()["Reservations"]
|
||||
|
||||
reservations.should.have.length_of(1)
|
||||
reservations[0]["Instances"].should.have.length_of(2)
|
||||
for instance in reservations[0]["Instances"]:
|
||||
tag_keys = [t["Key"] for t in instance["Tags"]]
|
||||
tag_keys.should.contain("propagated-test-tag")
|
||||
tag_keys.should_not.contain("not-propagated-test-tag")
|
||||
|
||||
|
||||
@mock_autoscaling
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
def test_autoscaling_group_update():
|
||||
asg_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"my-as-group": {
|
||||
"Type": "AWS::AutoScaling::AutoScalingGroup",
|
||||
"Properties": {
|
||||
"AvailabilityZones": ["us-west-1a"],
|
||||
"LaunchConfigurationName": {"Ref": "my-launch-config"},
|
||||
"MinSize": "2",
|
||||
"MaxSize": "2",
|
||||
"DesiredCapacity": "2",
|
||||
},
|
||||
},
|
||||
"my-launch-config": {
|
||||
"Type": "AWS::AutoScaling::LaunchConfiguration",
|
||||
"Properties": {
|
||||
"ImageId": EXAMPLE_AMI_ID,
|
||||
"InstanceType": "t2.medium",
|
||||
"UserData": "some user data",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
asg_template_json = json.dumps(asg_template)
|
||||
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
client = boto3.client("autoscaling", region_name="us-west-1")
|
||||
cf.create_stack(StackName="asg_stack", TemplateBody=asg_template_json)
|
||||
|
||||
asg = client.describe_auto_scaling_groups()["AutoScalingGroups"][0]
|
||||
asg["MinSize"].should.equal(2)
|
||||
asg["MaxSize"].should.equal(2)
|
||||
asg["DesiredCapacity"].should.equal(2)
|
||||
|
||||
asg_template["Resources"]["my-as-group"]["Properties"]["MaxSize"] = 3
|
||||
asg_template["Resources"]["my-as-group"]["Properties"]["Tags"] = [
|
||||
{
|
||||
"Key": "propagated-test-tag",
|
||||
"Value": "propagated-test-tag-value",
|
||||
"PropagateAtLaunch": True,
|
||||
},
|
||||
{
|
||||
"Key": "not-propagated-test-tag",
|
||||
"Value": "not-propagated-test-tag-value",
|
||||
"PropagateAtLaunch": False,
|
||||
},
|
||||
]
|
||||
asg_template_json = json.dumps(asg_template)
|
||||
cf.update_stack(StackName="asg_stack", TemplateBody=asg_template_json)
|
||||
asg = client.describe_auto_scaling_groups()["AutoScalingGroups"][0]
|
||||
asg["MinSize"].should.equal(2)
|
||||
asg["MaxSize"].should.equal(3)
|
||||
asg["DesiredCapacity"].should.equal(2)
|
||||
|
||||
# confirm the instances were created with the right tags
|
||||
reservations = ec2.describe_instances()["Reservations"]
|
||||
running_instance_count = 0
|
||||
for res in reservations:
|
||||
for instance in res["Instances"]:
|
||||
if instance["State"]["Name"] == "running":
|
||||
running_instance_count += 1
|
||||
instance["Tags"].should.contain(
|
||||
{"Key": "propagated-test-tag", "Value": "propagated-test-tag-value"}
|
||||
)
|
||||
tag_keys = [t["Key"] for t in instance["Tags"]]
|
||||
tag_keys.should_not.contain("not-propagated-test-tag")
|
||||
running_instance_count.should.equal(2)
|
||||
|
@ -4,7 +4,6 @@ import os
|
||||
import json
|
||||
|
||||
import boto
|
||||
import boto3
|
||||
import boto.dynamodb2
|
||||
import boto.iam
|
||||
import boto.s3
|
||||
@ -15,7 +14,6 @@ from freezegun import freeze_time
|
||||
import sure # noqa
|
||||
|
||||
import pytest
|
||||
from moto.core import ACCOUNT_ID
|
||||
|
||||
from moto import (
|
||||
mock_cloudformation_deprecated,
|
||||
@ -79,6 +77,7 @@ dummy_template_json3 = json.dumps(dummy_template3)
|
||||
dummy_template_json4 = json.dumps(dummy_template4)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_create_stack():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -127,6 +126,7 @@ def test_create_stack_with_other_region():
|
||||
)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
@mock_route53_deprecated
|
||||
def test_create_stack_hosted_zone_by_id():
|
||||
@ -168,6 +168,7 @@ def test_create_stack_hosted_zone_by_id():
|
||||
assert stack.list_resources()
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_creating_stacks_across_regions():
|
||||
west1_conn = boto.cloudformation.connect_to_region("us-west-1")
|
||||
@ -180,6 +181,7 @@ def test_creating_stacks_across_regions():
|
||||
list(west2_conn.describe_stacks()).should.have.length_of(1)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
@mock_sns_deprecated
|
||||
@mock_sqs_deprecated
|
||||
@ -246,6 +248,7 @@ def test_create_stack_with_notification_arn():
|
||||
msg.should.have.key("UnsubscribeURL")
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
@mock_s3_deprecated
|
||||
def test_create_stack_from_s3_url():
|
||||
@ -275,6 +278,7 @@ def test_create_stack_from_s3_url():
|
||||
)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_describe_stack_by_name():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -284,6 +288,7 @@ def test_describe_stack_by_name():
|
||||
stack.stack_name.should.equal("test_stack")
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_describe_stack_by_stack_id():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -296,6 +301,7 @@ def test_describe_stack_by_stack_id():
|
||||
|
||||
|
||||
@mock_dynamodb2_deprecated
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_delete_stack_dynamo_template():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -308,6 +314,7 @@ def test_delete_stack_dynamo_template():
|
||||
db_conn.list_tables()["TableNames"].should.have.length_of(0)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_describe_deleted_stack():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -322,6 +329,7 @@ def test_describe_deleted_stack():
|
||||
stack_by_id.stack_status.should.equal("DELETE_COMPLETE")
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_get_template_by_name():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -342,6 +350,7 @@ def test_get_template_by_name():
|
||||
)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_list_stacks():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -353,6 +362,7 @@ def test_list_stacks():
|
||||
stacks[0].template_description.should.equal("Stack 1")
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_list_stacks_with_filter():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -366,6 +376,7 @@ def test_list_stacks_with_filter():
|
||||
stacks.should.have.length_of(1)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_delete_stack_by_name():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -376,6 +387,7 @@ def test_delete_stack_by_name():
|
||||
conn.describe_stacks().should.have.length_of(0)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_delete_stack_by_id():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -390,6 +402,7 @@ def test_delete_stack_by_id():
|
||||
conn.describe_stacks(stack_id).should.have.length_of(1)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_delete_stack_with_resource_missing_delete_attr():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -400,6 +413,7 @@ def test_delete_stack_with_resource_missing_delete_attr():
|
||||
conn.describe_stacks().should.have.length_of(0)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_bad_describe_stack():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -407,6 +421,7 @@ def test_bad_describe_stack():
|
||||
conn.describe_stacks("bad_stack")
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated()
|
||||
def test_cloudformation_params():
|
||||
dummy_template = {
|
||||
@ -435,6 +450,7 @@ def test_cloudformation_params():
|
||||
param.value.should.equal("testing123")
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_cloudformation_params_conditions_and_resources_are_distinct():
|
||||
dummy_template = {
|
||||
@ -471,6 +487,7 @@ def test_cloudformation_params_conditions_and_resources_are_distinct():
|
||||
]
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_stack_tags():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -484,6 +501,7 @@ def test_stack_tags():
|
||||
dict(stack.tags).should.equal({"foo": "bar", "baz": "bleh"})
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_update_stack():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -507,6 +525,7 @@ def test_update_stack():
|
||||
)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_update_stack_with_previous_template():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -529,6 +548,7 @@ def test_update_stack_with_previous_template():
|
||||
)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_update_stack_with_parameters():
|
||||
dummy_template = {
|
||||
@ -559,6 +579,7 @@ def test_update_stack_with_parameters():
|
||||
assert stack.parameters[0].value == "192.168.0.1/16"
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_update_stack_replace_tags():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -575,6 +596,7 @@ def test_update_stack_replace_tags():
|
||||
dict(stack.tags).should.equal({"foo": "baz"})
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_update_stack_when_rolled_back():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -594,6 +616,7 @@ def test_update_stack_when_rolled_back():
|
||||
ex.status.should.equal(400)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_describe_stack_events_shows_create_update_and_delete():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -647,6 +670,7 @@ def test_describe_stack_events_shows_create_update_and_delete():
|
||||
err.status.should.equal(400)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_create_stack_lambda_and_dynamodb():
|
||||
conn = boto.connect_cloudformation()
|
||||
@ -714,6 +738,7 @@ def test_create_stack_lambda_and_dynamodb():
|
||||
assert len(resources) == 4
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
def test_create_stack_kinesis():
|
||||
conn = boto.connect_cloudformation()
|
||||
|
@ -3,12 +3,14 @@ from __future__ import unicode_literals
|
||||
import json
|
||||
from collections import OrderedDict
|
||||
from datetime import datetime, timedelta
|
||||
import os
|
||||
import pytz
|
||||
|
||||
import boto3
|
||||
from botocore.exceptions import ClientError
|
||||
|
||||
import pytest
|
||||
from unittest import SkipTest
|
||||
|
||||
from moto import (
|
||||
mock_cloudformation,
|
||||
@ -17,9 +19,14 @@ from moto import (
|
||||
mock_sns,
|
||||
mock_sqs,
|
||||
mock_ec2,
|
||||
mock_iam,
|
||||
mock_lambda,
|
||||
)
|
||||
from moto import settings
|
||||
from moto.core import ACCOUNT_ID
|
||||
from moto.cloudformation import cloudformation_backends
|
||||
from .test_cloudformation_stack_crud import dummy_template_json2, dummy_template_json4
|
||||
|
||||
from tests import EXAMPLE_AMI_ID
|
||||
|
||||
dummy_template = {
|
||||
@ -223,6 +230,20 @@ dummy_redrive_template_json = json.dumps(dummy_redrive_template)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
def test_create_stack():
|
||||
cf_conn = boto3.client("cloudformation", region_name="us-east-1")
|
||||
cf_conn.create_stack(StackName="test_stack", TemplateBody=dummy_template_json)
|
||||
|
||||
stack = cf_conn.describe_stacks()["Stacks"][0]
|
||||
stack.should.have.key("StackName").equal("test_stack")
|
||||
|
||||
template = cf_conn.get_template(StackName="test_stack")["TemplateBody"]
|
||||
template.should.equal(dummy_template)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
def test_boto3_describe_stack_instances():
|
||||
cf_conn = boto3.client("cloudformation", region_name="us-east-1")
|
||||
cf_conn.create_stack_set(
|
||||
@ -1560,15 +1581,39 @@ def test_describe_updated_stack():
|
||||
stack_by_id["RoleARN"].should.equal("arn:aws:iam::{}:role/moto".format(ACCOUNT_ID))
|
||||
stack_by_id["Tags"].should.equal([{"Key": "foo", "Value": "baz"}])
|
||||
|
||||
# Verify the updated template is persisted
|
||||
template = cf_conn.get_template(StackName="test_stack")["TemplateBody"]
|
||||
template.should.equal(dummy_update_template)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
def test_update_stack_with_previous_template():
|
||||
cf_conn = boto3.client("cloudformation", region_name="us-east-1")
|
||||
cf_conn.create_stack(StackName="test_stack", TemplateBody=dummy_template_json)
|
||||
cf_conn.update_stack(StackName="test_stack", UsePreviousTemplate=True)
|
||||
|
||||
stack = cf_conn.describe_stacks(StackName="test_stack")["Stacks"][0]
|
||||
stack["StackName"].should.equal("test_stack")
|
||||
stack["StackStatus"].should.equal("UPDATE_COMPLETE")
|
||||
|
||||
# Verify the original template is persisted
|
||||
template = cf_conn.get_template(StackName="test_stack")["TemplateBody"]
|
||||
template.should.equal(dummy_template)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
def test_bad_describe_stack():
|
||||
cf_conn = boto3.client("cloudformation", region_name="us-east-1")
|
||||
with pytest.raises(ClientError):
|
||||
with pytest.raises(ClientError) as exc:
|
||||
cf_conn.describe_stacks(StackName="non_existent_stack")
|
||||
err = exc.value.response["Error"]
|
||||
err.should.have.key("Code").being.equal("ValidationError")
|
||||
err.should.have.key("Message").being.equal(
|
||||
"Stack with id non_existent_stack does not exist"
|
||||
)
|
||||
|
||||
|
||||
@mock_cloudformation()
|
||||
@mock_cloudformation
|
||||
def test_cloudformation_params():
|
||||
dummy_template_with_params = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
@ -1597,6 +1642,119 @@ def test_cloudformation_params():
|
||||
param["ParameterValue"].should.equal("testing123")
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
def test_update_stack_with_parameters():
|
||||
template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Description": "Stack",
|
||||
"Resources": {
|
||||
"VPC": {
|
||||
"Properties": {"CidrBlock": {"Ref": "Bar"}},
|
||||
"Type": "AWS::EC2::VPC",
|
||||
}
|
||||
},
|
||||
"Parameters": {"Bar": {"Type": "String"}},
|
||||
}
|
||||
template_json = json.dumps(template)
|
||||
cf = boto3.client("cloudformation", region_name="us-east-1")
|
||||
cf.create_stack(
|
||||
StackName="test_stack",
|
||||
TemplateBody=template_json,
|
||||
Parameters=[{"ParameterKey": "Bar", "ParameterValue": "192.168.0.0/16"}],
|
||||
)
|
||||
cf.update_stack(
|
||||
StackName="test_stack",
|
||||
TemplateBody=template_json,
|
||||
Parameters=[{"ParameterKey": "Bar", "ParameterValue": "192.168.0.1/16"}],
|
||||
)
|
||||
|
||||
stack = cf.describe_stacks(StackName="test_stack")["Stacks"][0]
|
||||
stack["Parameters"].should.have.length_of(1)
|
||||
stack["Parameters"][0].should.equal(
|
||||
{"ParameterKey": "Bar", "ParameterValue": "192.168.0.1/16"}
|
||||
)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
def test_update_stack_replace_tags():
|
||||
cf = boto3.client("cloudformation", region_name="us-east-1")
|
||||
cf.create_stack(
|
||||
StackName="test_stack",
|
||||
TemplateBody=dummy_template_json,
|
||||
Tags=[{"Key": "foo", "Value": "bar"}],
|
||||
)
|
||||
cf.update_stack(
|
||||
StackName="test_stack",
|
||||
TemplateBody=dummy_template_json,
|
||||
Tags=[{"Key": "foo", "Value": "baz"}],
|
||||
)
|
||||
|
||||
stack = cf.describe_stacks(StackName="test_stack")["Stacks"][0]
|
||||
stack["StackStatus"].should.equal("UPDATE_COMPLETE")
|
||||
stack["Tags"].should.equal([{"Key": "foo", "Value": "baz"}])
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
def test_update_stack_when_rolled_back():
|
||||
if settings.TEST_SERVER_MODE:
|
||||
raise SkipTest("Cant manipulate backend in server mode")
|
||||
cf = boto3.client("cloudformation", region_name="us-east-1")
|
||||
stack = cf.create_stack(StackName="test_stack", TemplateBody=dummy_template_json)
|
||||
stack_id = stack["StackId"]
|
||||
|
||||
cloudformation_backends["us-east-1"].stacks[stack_id].status = "ROLLBACK_COMPLETE"
|
||||
|
||||
with pytest.raises(ClientError) as ex:
|
||||
cf.update_stack(StackName="test_stack", TemplateBody=dummy_template_json)
|
||||
|
||||
err = ex.value.response["Error"]
|
||||
err.should.have.key("Code").being.equal("ValidationError")
|
||||
err.should.have.key("Message").match(
|
||||
r"Stack:arn:aws:cloudformation:us-east-1:123456789:stack/test_stack/[a-z0-9-]+ is in ROLLBACK_COMPLETE state and can not be updated."
|
||||
)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
def test_cloudformation_params_conditions_and_resources_are_distinct():
|
||||
template_with_conditions = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Description": "Stack 1",
|
||||
"Conditions": {
|
||||
"FooEnabled": {"Fn::Equals": [{"Ref": "FooEnabled"}, "true"]},
|
||||
"FooDisabled": {
|
||||
"Fn::Not": [{"Fn::Equals": [{"Ref": "FooEnabled"}, "true"]}]
|
||||
},
|
||||
},
|
||||
"Parameters": {
|
||||
"FooEnabled": {"Type": "String", "AllowedValues": ["true", "false"]}
|
||||
},
|
||||
"Resources": {
|
||||
"Bar": {
|
||||
"Properties": {"CidrBlock": "192.168.0.0/16"},
|
||||
"Condition": "FooDisabled",
|
||||
"Type": "AWS::EC2::VPC",
|
||||
}
|
||||
},
|
||||
}
|
||||
template_with_conditions = json.dumps(template_with_conditions)
|
||||
cf = boto3.client("cloudformation", region_name="us-east-1")
|
||||
cf.create_stack(
|
||||
StackName="test_stack1",
|
||||
TemplateBody=template_with_conditions,
|
||||
Parameters=[{"ParameterKey": "FooEnabled", "ParameterValue": "true"}],
|
||||
)
|
||||
stack = cf.describe_stacks(StackName="test_stack1")["Stacks"][0]
|
||||
resources = cf.list_stack_resources(StackName="test_stack1")[
|
||||
"StackResourceSummaries"
|
||||
]
|
||||
assert not [
|
||||
resource for resource in resources if resource["LogicalResourceId"] == "Bar"
|
||||
]
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
def test_stack_tags():
|
||||
tags = [{"Key": "foo", "Value": "bar"}, {"Key": "baz", "Value": "bleh"}]
|
||||
@ -1791,3 +1949,91 @@ def test_delete_stack_dynamo_template():
|
||||
table_desc = dynamodb_client.list_tables()
|
||||
len(table_desc.get("TableNames")).should.equal(0)
|
||||
conn.create_stack(StackName="test_stack", TemplateBody=dummy_template_json4)
|
||||
|
||||
|
||||
@mock_dynamodb2
|
||||
@mock_cloudformation
|
||||
@mock_lambda
|
||||
def test_create_stack_lambda_and_dynamodb():
|
||||
if settings.TEST_SERVER_MODE:
|
||||
raise SkipTest("Cant set environment variables in server mode")
|
||||
cf = boto3.client("cloudformation", region_name="us-east-1")
|
||||
template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Description": "Stack Lambda Test 1",
|
||||
"Parameters": {},
|
||||
"Resources": {
|
||||
"func1": {
|
||||
"Type": "AWS::Lambda::Function",
|
||||
"Properties": {
|
||||
"Code": {"S3Bucket": "bucket_123", "S3Key": "key_123"},
|
||||
"FunctionName": "func1",
|
||||
"Handler": "handler.handler",
|
||||
"Role": get_role_name(),
|
||||
"Runtime": "python2.7",
|
||||
"Description": "descr",
|
||||
"MemorySize": 12345,
|
||||
},
|
||||
},
|
||||
"func1version": {
|
||||
"Type": "AWS::Lambda::Version",
|
||||
"Properties": {"FunctionName": {"Ref": "func1"}},
|
||||
},
|
||||
"tab1": {
|
||||
"Type": "AWS::DynamoDB::Table",
|
||||
"Properties": {
|
||||
"TableName": "tab1",
|
||||
"KeySchema": [{"AttributeName": "attr1", "KeyType": "HASH"}],
|
||||
"AttributeDefinitions": [
|
||||
{"AttributeName": "attr1", "AttributeType": "string"}
|
||||
],
|
||||
"ProvisionedThroughput": {
|
||||
"ReadCapacityUnits": 10,
|
||||
"WriteCapacityUnits": 10,
|
||||
},
|
||||
"StreamSpecification": {"StreamViewType": "KEYS_ONLY"},
|
||||
},
|
||||
},
|
||||
"func1mapping": {
|
||||
"Type": "AWS::Lambda::EventSourceMapping",
|
||||
"Properties": {
|
||||
"FunctionName": {"Ref": "func1"},
|
||||
"EventSourceArn": {"Fn::GetAtt": ["tab1", "StreamArn"]},
|
||||
"StartingPosition": "0",
|
||||
"BatchSize": 100,
|
||||
"Enabled": True,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
validate_s3_before = os.environ.get("VALIDATE_LAMBDA_S3", "")
|
||||
try:
|
||||
os.environ["VALIDATE_LAMBDA_S3"] = "false"
|
||||
cf.create_stack(
|
||||
StackName="test_stack_lambda", TemplateBody=json.dumps(template),
|
||||
)
|
||||
finally:
|
||||
os.environ["VALIDATE_LAMBDA_S3"] = validate_s3_before
|
||||
|
||||
resources = cf.list_stack_resources(StackName="test_stack_lambda")[
|
||||
"StackResourceSummaries"
|
||||
]
|
||||
resources.should.have.length_of(4)
|
||||
resource_types = [r["ResourceType"] for r in resources]
|
||||
resource_types.should.contain("AWS::Lambda::Function")
|
||||
resource_types.should.contain("AWS::Lambda::Version")
|
||||
resource_types.should.contain("AWS::DynamoDB::Table")
|
||||
resource_types.should.contain("AWS::Lambda::EventSourceMapping")
|
||||
|
||||
|
||||
def get_role_name():
|
||||
with mock_iam():
|
||||
iam = boto3.client("iam", region_name="us-east-1")
|
||||
try:
|
||||
return iam.get_role(RoleName="my-role")["Role"]["Arn"]
|
||||
except ClientError:
|
||||
return iam.create_role(
|
||||
RoleName="my-role",
|
||||
AssumeRolePolicyDocument="some policy",
|
||||
Path="/my-path/",
|
||||
)["Role"]["Arn"]
|
||||
|
@ -21,6 +21,8 @@ import boto.sqs
|
||||
import boto.vpc
|
||||
import boto3
|
||||
import sure # noqa
|
||||
import pytest
|
||||
from copy import deepcopy
|
||||
from string import Template
|
||||
|
||||
from moto import (
|
||||
@ -44,6 +46,7 @@ from moto import (
|
||||
mock_route53_deprecated,
|
||||
mock_s3,
|
||||
mock_sns_deprecated,
|
||||
mock_sqs,
|
||||
mock_sqs_deprecated,
|
||||
mock_elbv2,
|
||||
)
|
||||
@ -65,6 +68,7 @@ from tests.test_cloudformation.fixtures import (
|
||||
)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated()
|
||||
def test_stack_sqs_integration():
|
||||
sqs_template = {
|
||||
@ -88,6 +92,7 @@ def test_stack_sqs_integration():
|
||||
queue.physical_resource_id.should.equal("my-queue")
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated()
|
||||
def test_stack_list_resources():
|
||||
sqs_template = {
|
||||
@ -112,6 +117,7 @@ def test_stack_list_resources():
|
||||
queue.physical_resource_id.should.equal("my-queue")
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated()
|
||||
@mock_sqs_deprecated()
|
||||
def test_update_stack():
|
||||
@ -147,6 +153,7 @@ def test_update_stack():
|
||||
)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated()
|
||||
@mock_sqs_deprecated()
|
||||
def test_update_stack_and_remove_resource():
|
||||
@ -176,6 +183,7 @@ def test_update_stack_and_remove_resource():
|
||||
queues.should.have.length_of(0)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated()
|
||||
@mock_sqs_deprecated()
|
||||
def test_update_stack_and_add_resource():
|
||||
@ -205,6 +213,7 @@ def test_update_stack_and_add_resource():
|
||||
queues.should.have.length_of(1)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_ec2_deprecated()
|
||||
@mock_cloudformation_deprecated()
|
||||
def test_stack_ec2_integration():
|
||||
@ -233,6 +242,7 @@ def test_stack_ec2_integration():
|
||||
instance.physical_resource_id.should.equal(ec2_instance.id)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_ec2_deprecated()
|
||||
@mock_elb_deprecated()
|
||||
@mock_cloudformation_deprecated()
|
||||
@ -277,6 +287,7 @@ def test_stack_elb_integration_with_attached_ec2_instances():
|
||||
list(load_balancer.availability_zones).should.equal(["us-east-1"])
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_elb_deprecated()
|
||||
@mock_cloudformation_deprecated()
|
||||
def test_stack_elb_integration_with_health_check():
|
||||
@ -322,6 +333,7 @@ def test_stack_elb_integration_with_health_check():
|
||||
health_check.unhealthy_threshold.should.equal(2)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_elb_deprecated()
|
||||
@mock_cloudformation_deprecated()
|
||||
def test_stack_elb_integration_with_update():
|
||||
@ -363,6 +375,7 @@ def test_stack_elb_integration_with_update():
|
||||
load_balancer.availability_zones[0].should.equal("us-west-1b")
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_ec2_deprecated()
|
||||
@mock_redshift_deprecated()
|
||||
@mock_cloudformation_deprecated()
|
||||
@ -409,6 +422,7 @@ def test_redshift_stack():
|
||||
group.rules[0].grants[0].cidr_ip.should.equal("10.0.0.1/16")
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_ec2_deprecated()
|
||||
@mock_cloudformation_deprecated()
|
||||
def test_stack_security_groups():
|
||||
@ -485,6 +499,7 @@ def test_stack_security_groups():
|
||||
rule2.grants[0].group_id.should.equal(other_group.id)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_autoscaling_deprecated()
|
||||
@mock_elb_deprecated()
|
||||
@mock_cloudformation_deprecated()
|
||||
@ -599,6 +614,7 @@ def test_autoscaling_group_with_elb():
|
||||
instance.tags.keys().should_not.contain("not-propagated-test-tag")
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_autoscaling_deprecated()
|
||||
@mock_cloudformation_deprecated()
|
||||
@mock_ec2_deprecated()
|
||||
@ -672,6 +688,7 @@ def test_autoscaling_group_update():
|
||||
running_instance_count.should.equal(2)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_ec2_deprecated()
|
||||
@mock_cloudformation_deprecated()
|
||||
def test_vpc_single_instance_in_subnet():
|
||||
@ -727,56 +744,7 @@ def test_vpc_single_instance_in_subnet():
|
||||
eip_resource.physical_resource_id.should.equal(eip.public_ip)
|
||||
|
||||
|
||||
@mock_cloudformation()
|
||||
@mock_ec2()
|
||||
@mock_rds2()
|
||||
def test_rds_db_parameter_groups():
|
||||
ec2_conn = boto3.client("ec2", region_name="us-west-1")
|
||||
ec2_conn.create_security_group(
|
||||
GroupName="application", Description="Our Application Group"
|
||||
)
|
||||
|
||||
template_json = json.dumps(rds_mysql_with_db_parameter_group.template)
|
||||
cf_conn = boto3.client("cloudformation", "us-west-1")
|
||||
cf_conn.create_stack(
|
||||
StackName="test_stack",
|
||||
TemplateBody=template_json,
|
||||
Parameters=[
|
||||
{"ParameterKey": key, "ParameterValue": value}
|
||||
for key, value in [
|
||||
("DBInstanceIdentifier", "master_db"),
|
||||
("DBName", "my_db"),
|
||||
("DBUser", "my_user"),
|
||||
("DBPassword", "my_password"),
|
||||
("DBAllocatedStorage", "20"),
|
||||
("DBInstanceClass", "db.m1.medium"),
|
||||
("EC2SecurityGroup", "application"),
|
||||
("MultiAZ", "true"),
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
rds_conn = boto3.client("rds", region_name="us-west-1")
|
||||
|
||||
db_parameter_groups = rds_conn.describe_db_parameter_groups()
|
||||
len(db_parameter_groups["DBParameterGroups"]).should.equal(1)
|
||||
db_parameter_group_name = db_parameter_groups["DBParameterGroups"][0][
|
||||
"DBParameterGroupName"
|
||||
]
|
||||
|
||||
found_cloudformation_set_parameter = False
|
||||
for db_parameter in rds_conn.describe_db_parameters(
|
||||
DBParameterGroupName=db_parameter_group_name
|
||||
)["Parameters"]:
|
||||
if (
|
||||
db_parameter["ParameterName"] == "BACKLOG_QUEUE_LIMIT"
|
||||
and db_parameter["ParameterValue"] == "2048"
|
||||
):
|
||||
found_cloudformation_set_parameter = True
|
||||
|
||||
found_cloudformation_set_parameter.should.equal(True)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated()
|
||||
@mock_ec2_deprecated()
|
||||
@mock_rds_deprecated()
|
||||
@ -819,6 +787,7 @@ def test_rds_mysql_with_read_replica():
|
||||
security_group.ec2_groups[0].name.should.equal("application")
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated()
|
||||
@mock_ec2_deprecated()
|
||||
@mock_rds_deprecated()
|
||||
@ -847,6 +816,7 @@ def test_rds_mysql_with_read_replica_in_vpc():
|
||||
subnet_group.description.should.equal("my db subnet group")
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_autoscaling_deprecated()
|
||||
@mock_iam_deprecated()
|
||||
@mock_cloudformation_deprecated()
|
||||
@ -1002,6 +972,7 @@ def test_iam_roles():
|
||||
{r.physical_resource_id for r in role_resources}.should.equal(set(role_names))
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_ec2_deprecated()
|
||||
@mock_cloudformation_deprecated()
|
||||
def test_single_instance_with_ebs_volume():
|
||||
@ -1033,6 +1004,7 @@ def test_single_instance_with_ebs_volume():
|
||||
ebs_volumes[0].physical_resource_id.should.equal(volume.id)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated()
|
||||
def test_create_template_without_required_param():
|
||||
template_json = json.dumps(single_instance_with_ebs_volume.template)
|
||||
@ -1042,6 +1014,18 @@ def test_create_template_without_required_param():
|
||||
).should.throw(BotoServerError)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
def test_create_template_without_required_param_boto3():
|
||||
template_json = json.dumps(single_instance_with_ebs_volume.template)
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
with pytest.raises(ClientError) as ex:
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
err = ex.value.response["Error"]
|
||||
err.should.have.key("Code").equal("Missing Parameter")
|
||||
err.should.have.key("Message").equal("Missing parameter KeyName")
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_ec2_deprecated()
|
||||
@mock_cloudformation_deprecated()
|
||||
def test_classic_eip():
|
||||
@ -1059,6 +1043,7 @@ def test_classic_eip():
|
||||
cfn_eip.physical_resource_id.should.equal(eip.public_ip)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_ec2_deprecated()
|
||||
@mock_cloudformation_deprecated()
|
||||
def test_vpc_eip():
|
||||
@ -1076,6 +1061,7 @@ def test_vpc_eip():
|
||||
cfn_eip.physical_resource_id.should.equal(eip.public_ip)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_ec2_deprecated()
|
||||
@mock_cloudformation_deprecated()
|
||||
def test_fn_join():
|
||||
@ -1090,6 +1076,21 @@ def test_fn_join():
|
||||
fn_join_output.value.should.equal("test eip:{0}".format(eip.public_ip))
|
||||
|
||||
|
||||
@mock_ec2
|
||||
@mock_cloudformation
|
||||
def test_fn_join_boto3():
|
||||
template_json = json.dumps(fn_join.template)
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
eip = ec2.describe_addresses()["Addresses"][0]
|
||||
|
||||
stack = cf.describe_stacks()["Stacks"][0]
|
||||
fn_join_output = stack["Outputs"][0]
|
||||
fn_join_output["OutputValue"].should.equal("test eip:{0}".format(eip["PublicIp"]))
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated()
|
||||
@mock_sqs_deprecated()
|
||||
def test_conditional_resources():
|
||||
@ -1128,6 +1129,43 @@ def test_conditional_resources():
|
||||
list(sqs_conn.get_all_queues()).should.have.length_of(1)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_sqs
|
||||
def test_conditional_resources_boto3():
|
||||
sqs_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Parameters": {
|
||||
"EnvType": {"Description": "Environment type.", "Type": "String"}
|
||||
},
|
||||
"Conditions": {"CreateQueue": {"Fn::Equals": [{"Ref": "EnvType"}, "prod"]}},
|
||||
"Resources": {
|
||||
"QueueGroup": {
|
||||
"Condition": "CreateQueue",
|
||||
"Type": "AWS::SQS::Queue",
|
||||
"Properties": {"QueueName": "my-queue", "VisibilityTimeout": 60},
|
||||
}
|
||||
},
|
||||
}
|
||||
sqs_template_json = json.dumps(sqs_template)
|
||||
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(
|
||||
StackName="test_stack_without_queue",
|
||||
TemplateBody=sqs_template_json,
|
||||
Parameters=[{"ParameterKey": "EnvType", "ParameterValue": "staging"}],
|
||||
)
|
||||
sqs = boto3.client("sqs", region_name="us-west-1")
|
||||
sqs.list_queues().shouldnt.have.key("QueueUrls")
|
||||
|
||||
cf.create_stack(
|
||||
StackName="test_stack_with_queue",
|
||||
TemplateBody=sqs_template_json,
|
||||
Parameters=[{"ParameterKey": "EnvType", "ParameterValue": "prod"}],
|
||||
)
|
||||
sqs.list_queues()["QueueUrls"].should.have.length_of(1)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated()
|
||||
@mock_ec2_deprecated()
|
||||
def test_conditional_if_handling():
|
||||
@ -1173,6 +1211,51 @@ def test_conditional_if_handling():
|
||||
ec2_instance.image_id.should.equal(EXAMPLE_AMI_ID)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
def test_conditional_if_handling_boto3():
|
||||
dummy_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Conditions": {"EnvEqualsPrd": {"Fn::Equals": [{"Ref": "ENV"}, "prd"]}},
|
||||
"Parameters": {
|
||||
"ENV": {
|
||||
"Default": "dev",
|
||||
"Description": "Deployment environment for the stack (dev/prd)",
|
||||
"Type": "String",
|
||||
}
|
||||
},
|
||||
"Description": "Stack 1",
|
||||
"Resources": {
|
||||
"App1": {
|
||||
"Properties": {
|
||||
"ImageId": {
|
||||
"Fn::If": ["EnvEqualsPrd", EXAMPLE_AMI_ID, EXAMPLE_AMI_ID2]
|
||||
}
|
||||
},
|
||||
"Type": "AWS::EC2::Instance",
|
||||
}
|
||||
},
|
||||
}
|
||||
dummy_template_json = json.dumps(dummy_template)
|
||||
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=dummy_template_json)
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
ec2_instance = ec2.describe_instances()["Reservations"][0]["Instances"][0]
|
||||
ec2_instance["ImageId"].should.equal(EXAMPLE_AMI_ID2)
|
||||
|
||||
cf = boto3.client("cloudformation", region_name="us-west-2")
|
||||
cf.create_stack(
|
||||
StackName="test_stack",
|
||||
TemplateBody=dummy_template_json,
|
||||
Parameters=[{"ParameterKey": "ENV", "ParameterValue": "prd"}],
|
||||
)
|
||||
ec2 = boto3.client("ec2", region_name="us-west-2")
|
||||
ec2_instance = ec2.describe_instances()["Reservations"][0]["Instances"][0]
|
||||
ec2_instance["ImageId"].should.equal(EXAMPLE_AMI_ID)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated()
|
||||
@mock_ec2_deprecated()
|
||||
def test_cloudformation_mapping():
|
||||
@ -1217,6 +1300,49 @@ def test_cloudformation_mapping():
|
||||
ec2_instance.image_id.should.equal(EXAMPLE_AMI_ID)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
def test_cloudformation_mapping_boto3():
|
||||
dummy_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Mappings": {
|
||||
"RegionMap": {
|
||||
"us-east-1": {"32": EXAMPLE_AMI_ID, "64": "n/a"},
|
||||
"us-west-1": {"32": EXAMPLE_AMI_ID2, "64": "n/a"},
|
||||
"eu-west-1": {"32": "n/a", "64": "n/a"},
|
||||
"ap-southeast-1": {"32": "n/a", "64": "n/a"},
|
||||
"ap-northeast-1": {"32": "n/a", "64": "n/a"},
|
||||
}
|
||||
},
|
||||
"Resources": {
|
||||
"WebServer": {
|
||||
"Type": "AWS::EC2::Instance",
|
||||
"Properties": {
|
||||
"ImageId": {
|
||||
"Fn::FindInMap": ["RegionMap", {"Ref": "AWS::Region"}, "32"]
|
||||
},
|
||||
"InstanceType": "m1.small",
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
dummy_template_json = json.dumps(dummy_template)
|
||||
|
||||
cf = boto3.client("cloudformation", region_name="us-east-1")
|
||||
cf.create_stack(StackName="test_stack1", TemplateBody=dummy_template_json)
|
||||
ec2 = boto3.client("ec2", region_name="us-east-1")
|
||||
ec2_instance = ec2.describe_instances()["Reservations"][0]["Instances"][0]
|
||||
ec2_instance["ImageId"].should.equal(EXAMPLE_AMI_ID)
|
||||
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack1", TemplateBody=dummy_template_json)
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
ec2_instance = ec2.describe_instances()["Reservations"][0]["Instances"][0]
|
||||
ec2_instance["ImageId"].should.equal(EXAMPLE_AMI_ID2)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated()
|
||||
@mock_route53_deprecated()
|
||||
def test_route53_roundrobin():
|
||||
@ -1259,6 +1385,7 @@ def test_route53_roundrobin():
|
||||
output.value.should.equal("arn:aws:route53:::hostedzone/{0}".format(zone_id))
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated()
|
||||
@mock_ec2_deprecated()
|
||||
@mock_route53_deprecated()
|
||||
@ -1292,6 +1419,7 @@ def test_route53_ec2_instance_with_public_ip():
|
||||
record_set1.resource_records[0].should.equal("10.0.0.25")
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated()
|
||||
@mock_route53_deprecated()
|
||||
def test_route53_associate_health_check():
|
||||
@ -1330,6 +1458,7 @@ def test_route53_associate_health_check():
|
||||
record_set.health_check.should.equal(health_check_id)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated()
|
||||
@mock_route53_deprecated()
|
||||
def test_route53_with_update():
|
||||
@ -1353,10 +1482,11 @@ def test_route53_with_update():
|
||||
record_set = rrsets[0]
|
||||
record_set.resource_records.should.equal(["my.example.com"])
|
||||
|
||||
route53_health_check.template["Resources"]["myDNSRecord"]["Properties"][
|
||||
"ResourceRecords"
|
||||
] = ["my_other.example.com"]
|
||||
template_json = json.dumps(route53_health_check.template)
|
||||
template = deepcopy(route53_health_check.template)
|
||||
template["Resources"]["myDNSRecord"]["Properties"]["ResourceRecords"] = [
|
||||
"my_other.example.com"
|
||||
]
|
||||
template_json = json.dumps(template)
|
||||
cf_conn.update_stack("test_stack", template_body=template_json)
|
||||
|
||||
zones = route53_conn.get_all_hosted_zones()["ListHostedZonesResponse"][
|
||||
@ -1374,6 +1504,7 @@ def test_route53_with_update():
|
||||
record_set.resource_records.should.equal(["my_other.example.com"])
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated()
|
||||
@mock_sns_deprecated()
|
||||
def test_sns_topic():
|
||||
@ -1424,6 +1555,7 @@ def test_sns_topic():
|
||||
topic_arn_output.value.should.equal(topic_arn)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
@mock_ec2_deprecated
|
||||
def test_vpc_gateway_attachment_creation_should_attach_itself_to_vpc():
|
||||
@ -1461,6 +1593,7 @@ def test_vpc_gateway_attachment_creation_should_attach_itself_to_vpc():
|
||||
igws.should.have.length_of(1)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
@mock_ec2_deprecated
|
||||
def test_vpc_peering_creation():
|
||||
@ -1485,6 +1618,7 @@ def test_vpc_peering_creation():
|
||||
peering_connections.should.have.length_of(1)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
@mock_ec2_deprecated
|
||||
def test_multiple_security_group_ingress_separate_from_security_group_by_id():
|
||||
@ -1538,6 +1672,7 @@ def test_multiple_security_group_ingress_separate_from_security_group_by_id():
|
||||
security_group1.rules[0].to_port.should.equal("8080")
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
@mock_ec2_deprecated
|
||||
def test_security_group_ingress_separate_from_security_group_by_id():
|
||||
@ -1585,6 +1720,7 @@ def test_security_group_ingress_separate_from_security_group_by_id():
|
||||
security_group1.rules[0].to_port.should.equal("8080")
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
@mock_ec2_deprecated
|
||||
def test_security_group_ingress_separate_from_security_group_by_id_using_vpc():
|
||||
@ -1642,6 +1778,7 @@ def test_security_group_ingress_separate_from_security_group_by_id_using_vpc():
|
||||
security_group1.rules[0].to_port.should.equal("8080")
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
@mock_ec2_deprecated
|
||||
def test_security_group_with_update():
|
||||
@ -1676,6 +1813,7 @@ def test_security_group_with_update():
|
||||
security_group.vpc_id.should.equal(vpc2.id)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
@mock_ec2_deprecated
|
||||
def test_subnets_should_be_created_with_availability_zone():
|
||||
@ -1702,6 +1840,7 @@ def test_subnets_should_be_created_with_availability_zone():
|
||||
subnet.availability_zone.should.equal("us-west-1b")
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_cloudformation_deprecated
|
||||
@mock_datapipeline_deprecated
|
||||
def test_datapipeline():
|
||||
|
70
tests/test_datapipeline/test_datapipeline_cloudformation.py
Normal file
70
tests/test_datapipeline/test_datapipeline_cloudformation.py
Normal file
@ -0,0 +1,70 @@
|
||||
import boto3
|
||||
import json
|
||||
import sure # noqa
|
||||
|
||||
|
||||
from moto import mock_cloudformation, mock_datapipeline
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_datapipeline
|
||||
def test_datapipeline():
|
||||
dp_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"dataPipeline": {
|
||||
"Properties": {
|
||||
"Activate": "true",
|
||||
"Name": "testDataPipeline",
|
||||
"PipelineObjects": [
|
||||
{
|
||||
"Fields": [
|
||||
{
|
||||
"Key": "failureAndRerunMode",
|
||||
"StringValue": "CASCADE",
|
||||
},
|
||||
{"Key": "scheduleType", "StringValue": "cron"},
|
||||
{"Key": "schedule", "RefValue": "DefaultSchedule"},
|
||||
{
|
||||
"Key": "pipelineLogUri",
|
||||
"StringValue": "s3://bucket/logs",
|
||||
},
|
||||
{"Key": "type", "StringValue": "Default"},
|
||||
],
|
||||
"Id": "Default",
|
||||
"Name": "Default",
|
||||
},
|
||||
{
|
||||
"Fields": [
|
||||
{
|
||||
"Key": "startDateTime",
|
||||
"StringValue": "1970-01-01T01:00:00",
|
||||
},
|
||||
{"Key": "period", "StringValue": "1 Day"},
|
||||
{"Key": "type", "StringValue": "Schedule"},
|
||||
],
|
||||
"Id": "DefaultSchedule",
|
||||
"Name": "RunOnce",
|
||||
},
|
||||
],
|
||||
"PipelineTags": [],
|
||||
},
|
||||
"Type": "AWS::DataPipeline::Pipeline",
|
||||
}
|
||||
},
|
||||
}
|
||||
cf = boto3.client("cloudformation", region_name="us-east-1")
|
||||
template_json = json.dumps(dp_template)
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
|
||||
dp = boto3.client("datapipeline", region_name="us-east-1")
|
||||
data_pipelines = dp.list_pipelines()["pipelineIdList"]
|
||||
|
||||
data_pipelines.should.have.length_of(1)
|
||||
data_pipelines[0]["name"].should.equal("testDataPipeline")
|
||||
|
||||
stack_resources = cf.list_stack_resources(StackName="test_stack")[
|
||||
"StackResourceSummaries"
|
||||
]
|
||||
stack_resources.should.have.length_of(1)
|
||||
stack_resources[0]["PhysicalResourceId"].should.equal(data_pipelines[0]["id"])
|
51
tests/test_dynamodb2/test_dynamodb_cloudformation.py
Normal file
51
tests/test_dynamodb2/test_dynamodb_cloudformation.py
Normal file
@ -0,0 +1,51 @@
|
||||
import boto3
|
||||
import json
|
||||
import sure # noqa
|
||||
|
||||
from moto import mock_cloudformation, mock_dynamodb2
|
||||
|
||||
|
||||
template_create_table = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"myDynamoDBTable": {
|
||||
"Type": "AWS::DynamoDB::Table",
|
||||
"Properties": {
|
||||
"AttributeDefinitions": [
|
||||
{"AttributeName": "Name", "AttributeType": "S"},
|
||||
{"AttributeName": "Age", "AttributeType": "S"},
|
||||
],
|
||||
"KeySchema": [
|
||||
{"AttributeName": "Name", "KeyType": "HASH"},
|
||||
{"AttributeName": "Age", "KeyType": "RANGE"},
|
||||
],
|
||||
"ProvisionedThroughput": {
|
||||
"ReadCapacityUnits": 5,
|
||||
"WriteCapacityUnits": 5,
|
||||
},
|
||||
"TableName": "Person",
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@mock_dynamodb2
|
||||
@mock_cloudformation
|
||||
def test_delete_stack_dynamo_template_boto3():
|
||||
conn = boto3.client("cloudformation", region_name="us-east-1")
|
||||
dynamodb_client = boto3.client("dynamodb", region_name="us-east-1")
|
||||
|
||||
conn.create_stack(
|
||||
StackName="test_stack", TemplateBody=json.dumps(template_create_table)
|
||||
)
|
||||
table_desc = dynamodb_client.list_tables()
|
||||
len(table_desc.get("TableNames")).should.equal(1)
|
||||
|
||||
conn.delete_stack(StackName="test_stack")
|
||||
table_desc = dynamodb_client.list_tables()
|
||||
len(table_desc.get("TableNames")).should.equal(0)
|
||||
|
||||
conn.create_stack(
|
||||
StackName="test_stack", TemplateBody=json.dumps(template_create_table)
|
||||
)
|
@ -1,16 +1,124 @@
|
||||
from botocore.exceptions import ClientError
|
||||
from moto import mock_cloudformation_deprecated, mock_ec2_deprecated
|
||||
from moto import mock_cloudformation, mock_ec2
|
||||
from tests import EXAMPLE_AMI_ID
|
||||
from tests.test_cloudformation.fixtures import ec2_classic_eip
|
||||
from tests.test_cloudformation.fixtures import single_instance_with_ebs_volume
|
||||
from tests.test_cloudformation.fixtures import vpc_eip
|
||||
from tests.test_cloudformation.fixtures import vpc_eni
|
||||
from tests.test_cloudformation.fixtures import vpc_single_instance_in_subnet
|
||||
import boto
|
||||
import boto.ec2
|
||||
import boto.cloudformation
|
||||
import boto.vpc
|
||||
import boto3
|
||||
import json
|
||||
import pytest
|
||||
import sure # noqa
|
||||
|
||||
|
||||
template_vpc = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Description": "Create VPC",
|
||||
"Resources": {
|
||||
"VPC": {"Properties": {"CidrBlock": "192.168.0.0/16"}, "Type": "AWS::EC2::VPC"}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@mock_ec2
|
||||
@mock_cloudformation
|
||||
def test_vpc_single_instance_in_subnet():
|
||||
template_json = json.dumps(vpc_single_instance_in_subnet.template)
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(
|
||||
StackName="test_stack",
|
||||
TemplateBody=template_json,
|
||||
Parameters=[{"ParameterKey": "KeyName", "ParameterValue": "my_key"}],
|
||||
)
|
||||
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
|
||||
vpc = ec2.describe_vpcs(Filters=[{"Name": "cidrBlock", "Values": ["10.0.0.0/16"]}])[
|
||||
"Vpcs"
|
||||
][0]
|
||||
vpc["CidrBlock"].should.equal("10.0.0.0/16")
|
||||
|
||||
ec2.describe_internet_gateways()["InternetGateways"].should.have.length_of(1)
|
||||
|
||||
subnet = ec2.describe_subnets(
|
||||
Filters=[{"Name": "vpcId", "Values": [vpc["VpcId"]]}]
|
||||
)["Subnets"][0]
|
||||
subnet["VpcId"].should.equal(vpc["VpcId"])
|
||||
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
reservation = ec2.describe_instances()["Reservations"][0]
|
||||
instance = reservation["Instances"][0]
|
||||
instance["Tags"].should.contain({"Key": "Foo", "Value": "Bar"})
|
||||
# Check that the EIP is attached the the EC2 instance
|
||||
eip = ec2.describe_addresses()["Addresses"][0]
|
||||
eip["Domain"].should.equal("vpc")
|
||||
eip["InstanceId"].should.equal(instance["InstanceId"])
|
||||
|
||||
security_group = ec2.describe_security_groups(
|
||||
Filters=[{"Name": "vpc-id", "Values": [vpc["VpcId"]]}]
|
||||
)["SecurityGroups"][0]
|
||||
security_group["VpcId"].should.equal(vpc["VpcId"])
|
||||
|
||||
stack = cf.describe_stacks(StackName="test_stack")["Stacks"][0]
|
||||
|
||||
vpc["Tags"].should.contain({"Key": "Application", "Value": stack["StackId"]})
|
||||
|
||||
resources = cf.list_stack_resources(StackName="test_stack")[
|
||||
"StackResourceSummaries"
|
||||
]
|
||||
vpc_resource = [
|
||||
resource
|
||||
for resource in resources
|
||||
if resource["ResourceType"] == "AWS::EC2::VPC"
|
||||
][0]
|
||||
vpc_resource["PhysicalResourceId"].should.equal(vpc["VpcId"])
|
||||
|
||||
subnet_resource = [
|
||||
resource
|
||||
for resource in resources
|
||||
if resource["ResourceType"] == "AWS::EC2::Subnet"
|
||||
][0]
|
||||
subnet_resource["PhysicalResourceId"].should.equal(subnet["SubnetId"])
|
||||
|
||||
eip_resource = [
|
||||
resource
|
||||
for resource in resources
|
||||
if resource["ResourceType"] == "AWS::EC2::EIP"
|
||||
][0]
|
||||
eip_resource["PhysicalResourceId"].should.equal(eip["PublicIp"])
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
def test_delete_stack_with_resource_missing_delete_attr():
|
||||
cf = boto3.client("cloudformation", region_name="us-east-1")
|
||||
ec2 = boto3.client("ec2", region_name="us-east-1")
|
||||
name = "test_stack"
|
||||
|
||||
cf.create_stack(StackName=name, TemplateBody=json.dumps(template_vpc))
|
||||
cf.describe_stacks(StackName=name)["Stacks"].should.have.length_of(1)
|
||||
ec2.describe_vpcs()["Vpcs"].should.have.length_of(2)
|
||||
|
||||
cf.delete_stack(
|
||||
StackName=name
|
||||
) # should succeed, despite the fact that the resource itself cannot be deleted
|
||||
with pytest.raises(ClientError) as exc:
|
||||
cf.describe_stacks(StackName=name)
|
||||
err = exc.value.response["Error"]
|
||||
err.should.have.key("Code").equals("ValidationError")
|
||||
err.should.have.key("Message").equals("Stack with id test_stack does not exist")
|
||||
|
||||
# We still have two VPCs, as the VPC-object does not have a delete-method yet
|
||||
ec2.describe_vpcs()["Vpcs"].should.have.length_of(2)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_ec2_deprecated
|
||||
@mock_cloudformation_deprecated
|
||||
def test_elastic_network_interfaces_cloudformation():
|
||||
@ -35,6 +143,34 @@ def test_elastic_network_interfaces_cloudformation():
|
||||
outputs["ENIIpAddress"].should.equal(eni.private_ip_addresses[0].private_ip_address)
|
||||
|
||||
|
||||
@mock_ec2
|
||||
@mock_cloudformation
|
||||
def test_elastic_network_interfaces_cloudformation_boto3():
|
||||
template = vpc_eni.template
|
||||
template_json = json.dumps(template)
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
eni = ec2.describe_network_interfaces()["NetworkInterfaces"][0]
|
||||
eni["PrivateIpAddresses"].should.have.length_of(1)
|
||||
private_ip_address = eni["PrivateIpAddresses"][0]["PrivateIpAddress"]
|
||||
|
||||
resources = cf.list_stack_resources(StackName="test_stack")[
|
||||
"StackResourceSummaries"
|
||||
]
|
||||
cfn_eni = [
|
||||
resource
|
||||
for resource in resources
|
||||
if resource["ResourceType"] == "AWS::EC2::NetworkInterface"
|
||||
][0]
|
||||
cfn_eni["PhysicalResourceId"].should.equal(eni["NetworkInterfaceId"])
|
||||
|
||||
outputs = cf.describe_stacks(StackName="test_stack")["Stacks"][0]["Outputs"]
|
||||
outputs.should.contain(
|
||||
{"OutputKey": "ENIIpAddress", "OutputValue": private_ip_address}
|
||||
)
|
||||
|
||||
|
||||
@mock_ec2
|
||||
@mock_cloudformation
|
||||
def test_volume_size_through_cloudformation():
|
||||
@ -63,7 +199,15 @@ def test_volume_size_through_cloudformation():
|
||||
}
|
||||
template_json = json.dumps(volume_template)
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
instances = ec2.describe_instances()
|
||||
|
||||
resource = cf.list_stack_resources(StackName="test_stack")[
|
||||
"StackResourceSummaries"
|
||||
][0]
|
||||
resource.should.have.key("LogicalResourceId").being.equal("testInstance")
|
||||
resource.should.have.key("PhysicalResourceId").shouldnt.be.none
|
||||
resource.should.have.key("ResourceType").being.equal("AWS::EC2::Instance")
|
||||
|
||||
instances = ec2.describe_instances(InstanceIds=[resource["PhysicalResourceId"]])
|
||||
volume = instances["Reservations"][0]["Instances"][0]["BlockDeviceMappings"][0][
|
||||
"Ebs"
|
||||
]
|
||||
@ -72,6 +216,7 @@ def test_volume_size_through_cloudformation():
|
||||
volumes["Volumes"][0]["Size"].should.equal(50)
|
||||
|
||||
|
||||
# Has boto3 equivalent
|
||||
@mock_ec2_deprecated
|
||||
@mock_cloudformation_deprecated
|
||||
def test_subnet_tags_through_cloudformation():
|
||||
@ -102,3 +247,405 @@ def test_subnet_tags_through_cloudformation():
|
||||
subnet = vpc_conn.get_all_subnets(filters={"cidrBlock": "10.0.0.0/24"})[0]
|
||||
subnet.tags["foo"].should.equal("bar")
|
||||
subnet.tags["blah"].should.equal("baz")
|
||||
|
||||
|
||||
@mock_ec2
|
||||
@mock_cloudformation
|
||||
def test_subnet_tags_through_cloudformation_boto3():
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
ec2_res = boto3.resource("ec2", region_name="us-west-1")
|
||||
vpc = ec2_res.create_vpc(CidrBlock="10.0.0.0/16")
|
||||
|
||||
subnet_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"testSubnet": {
|
||||
"Type": "AWS::EC2::Subnet",
|
||||
"Properties": {
|
||||
"VpcId": vpc.id,
|
||||
"CidrBlock": "10.0.0.0/24",
|
||||
"AvailabilityZone": "us-west-1b",
|
||||
"Tags": [
|
||||
{"Key": "foo", "Value": "bar"},
|
||||
{"Key": "blah", "Value": "baz"},
|
||||
],
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
template_json = json.dumps(subnet_template)
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
|
||||
subnet = ec2.describe_subnets(
|
||||
Filters=[{"Name": "cidrBlock", "Values": ["10.0.0.0/24"]}]
|
||||
)["Subnets"][0]
|
||||
subnet["Tags"].should.contain({"Key": "foo", "Value": "bar"})
|
||||
subnet["Tags"].should.contain({"Key": "blah", "Value": "baz"})
|
||||
|
||||
|
||||
@mock_ec2
|
||||
@mock_cloudformation
|
||||
def test_single_instance_with_ebs_volume():
|
||||
template_json = json.dumps(single_instance_with_ebs_volume.template)
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(
|
||||
StackName="test_stack",
|
||||
TemplateBody=template_json,
|
||||
Parameters=[{"ParameterKey": "KeyName", "ParameterValue": "key_name"}],
|
||||
)
|
||||
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
ec2_instance = ec2.describe_instances()["Reservations"][0]["Instances"][0]
|
||||
|
||||
volumes = ec2.describe_volumes()["Volumes"]
|
||||
# Grab the mounted drive
|
||||
volume = [
|
||||
volume for volume in volumes if volume["Attachments"][0]["Device"] == "/dev/sdh"
|
||||
][0]
|
||||
volume["State"].should.equal("in-use")
|
||||
volume["Attachments"][0]["InstanceId"].should.equal(ec2_instance["InstanceId"])
|
||||
|
||||
resources = cf.list_stack_resources(StackName="test_stack")[
|
||||
"StackResourceSummaries"
|
||||
]
|
||||
ebs_volumes = [
|
||||
resource
|
||||
for resource in resources
|
||||
if resource["ResourceType"] == "AWS::EC2::Volume"
|
||||
]
|
||||
ebs_volumes[0]["PhysicalResourceId"].should.equal(volume["VolumeId"])
|
||||
|
||||
|
||||
@mock_ec2
|
||||
@mock_cloudformation
|
||||
def test_classic_eip():
|
||||
template_json = json.dumps(ec2_classic_eip.template)
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
eip = ec2.describe_addresses()["Addresses"][0]
|
||||
|
||||
resources = cf.list_stack_resources(StackName="test_stack")[
|
||||
"StackResourceSummaries"
|
||||
]
|
||||
cfn_eip = [
|
||||
resource
|
||||
for resource in resources
|
||||
if resource["ResourceType"] == "AWS::EC2::EIP"
|
||||
][0]
|
||||
cfn_eip["PhysicalResourceId"].should.equal(eip["PublicIp"])
|
||||
|
||||
|
||||
@mock_ec2
|
||||
@mock_cloudformation
|
||||
def test_vpc_eip():
|
||||
template_json = json.dumps(vpc_eip.template)
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
eip = ec2.describe_addresses()["Addresses"][0]
|
||||
|
||||
resources = cf.list_stack_resources(StackName="test_stack")[
|
||||
"StackResourceSummaries"
|
||||
]
|
||||
cfn_eip = [
|
||||
resource
|
||||
for resource in resources
|
||||
if resource["ResourceType"] == "AWS::EC2::EIP"
|
||||
][0]
|
||||
cfn_eip["PhysicalResourceId"].should.equal(eip["PublicIp"])
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
def test_vpc_gateway_attachment_creation_should_attach_itself_to_vpc():
|
||||
template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"internetgateway": {"Type": "AWS::EC2::InternetGateway"},
|
||||
"testvpc": {
|
||||
"Type": "AWS::EC2::VPC",
|
||||
"Properties": {
|
||||
"CidrBlock": "10.0.0.0/16",
|
||||
"EnableDnsHostnames": "true",
|
||||
"EnableDnsSupport": "true",
|
||||
"InstanceTenancy": "default",
|
||||
},
|
||||
},
|
||||
"vpcgatewayattachment": {
|
||||
"Type": "AWS::EC2::VPCGatewayAttachment",
|
||||
"Properties": {
|
||||
"InternetGatewayId": {"Ref": "internetgateway"},
|
||||
"VpcId": {"Ref": "testvpc"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
template_json = json.dumps(template)
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
vpc = ec2.describe_vpcs(Filters=[{"Name": "cidrBlock", "Values": ["10.0.0.0/16"]}])[
|
||||
"Vpcs"
|
||||
][0]
|
||||
|
||||
igws = ec2.describe_internet_gateways(
|
||||
Filters=[{"Name": "attachment.vpc-id", "Values": [vpc["VpcId"]]}]
|
||||
)["InternetGateways"]
|
||||
igws.should.have.length_of(1)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
def test_vpc_peering_creation():
|
||||
ec2 = boto3.resource("ec2", region_name="us-west-1")
|
||||
ec2_client = boto3.client("ec2", region_name="us-west-1")
|
||||
vpc_source = ec2.create_vpc(CidrBlock="10.0.0.0/16")
|
||||
peer_vpc = ec2.create_vpc(CidrBlock="10.1.0.0/16")
|
||||
template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"vpcpeeringconnection": {
|
||||
"Type": "AWS::EC2::VPCPeeringConnection",
|
||||
"Properties": {"PeerVpcId": peer_vpc.id, "VpcId": vpc_source.id},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
template_json = json.dumps(template)
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
|
||||
peering_connections = ec2_client.describe_vpc_peering_connections()[
|
||||
"VpcPeeringConnections"
|
||||
]
|
||||
peering_connections.should.have.length_of(1)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
def test_multiple_security_group_ingress_separate_from_security_group_by_id():
|
||||
template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"test-security-group1": {
|
||||
"Type": "AWS::EC2::SecurityGroup",
|
||||
"Properties": {
|
||||
"GroupDescription": "test security group",
|
||||
"Tags": [{"Key": "sg-name", "Value": "sg1"}],
|
||||
},
|
||||
},
|
||||
"test-security-group2": {
|
||||
"Type": "AWS::EC2::SecurityGroup",
|
||||
"Properties": {
|
||||
"GroupDescription": "test security group",
|
||||
"Tags": [{"Key": "sg-name", "Value": "sg2"}],
|
||||
},
|
||||
},
|
||||
"test-sg-ingress": {
|
||||
"Type": "AWS::EC2::SecurityGroupIngress",
|
||||
"Properties": {
|
||||
"GroupId": {"Ref": "test-security-group1"},
|
||||
"IpProtocol": "tcp",
|
||||
"FromPort": "80",
|
||||
"ToPort": "8080",
|
||||
"SourceSecurityGroupId": {"Ref": "test-security-group2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
template_json = json.dumps(template)
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
|
||||
security_group1 = get_secgroup_by_tag(ec2, "sg1")
|
||||
security_group2 = get_secgroup_by_tag(ec2, "sg2")
|
||||
|
||||
security_group1["IpPermissions"].should.have.length_of(1)
|
||||
security_group1["IpPermissions"][0]["UserIdGroupPairs"].should.have.length_of(1)
|
||||
security_group1["IpPermissions"][0]["UserIdGroupPairs"][0]["GroupId"].should.equal(
|
||||
security_group2["GroupId"]
|
||||
)
|
||||
security_group1["IpPermissions"][0]["IpProtocol"].should.equal("tcp")
|
||||
security_group1["IpPermissions"][0]["FromPort"].should.equal(80)
|
||||
security_group1["IpPermissions"][0]["ToPort"].should.equal(8080)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
def test_security_group_ingress_separate_from_security_group_by_id():
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
ec2.create_security_group(
|
||||
GroupName="test-security-group1", Description="test security group"
|
||||
)
|
||||
|
||||
template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"test-security-group2": {
|
||||
"Type": "AWS::EC2::SecurityGroup",
|
||||
"Properties": {
|
||||
"GroupDescription": "test security group",
|
||||
"Tags": [{"Key": "sg-name", "Value": "sg2"}],
|
||||
},
|
||||
},
|
||||
"test-sg-ingress": {
|
||||
"Type": "AWS::EC2::SecurityGroupIngress",
|
||||
"Properties": {
|
||||
"GroupName": "test-security-group1",
|
||||
"IpProtocol": "tcp",
|
||||
"FromPort": "80",
|
||||
"ToPort": "8080",
|
||||
"SourceSecurityGroupId": {"Ref": "test-security-group2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
template_json = json.dumps(template)
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
security_group1 = ec2.describe_security_groups(GroupNames=["test-security-group1"])[
|
||||
"SecurityGroups"
|
||||
][0]
|
||||
security_group2 = get_secgroup_by_tag(ec2, "sg2")
|
||||
|
||||
security_group1["IpPermissions"].should.have.length_of(1)
|
||||
security_group1["IpPermissions"][0]["UserIdGroupPairs"].should.have.length_of(1)
|
||||
security_group1["IpPermissions"][0]["UserIdGroupPairs"][0]["GroupId"].should.equal(
|
||||
security_group2["GroupId"]
|
||||
)
|
||||
security_group1["IpPermissions"][0]["IpProtocol"].should.equal("tcp")
|
||||
security_group1["IpPermissions"][0]["FromPort"].should.equal(80)
|
||||
security_group1["IpPermissions"][0]["ToPort"].should.equal(8080)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
def test_security_group_ingress_separate_from_security_group_by_id_using_vpc():
|
||||
ec2 = boto3.resource("ec2", region_name="us-west-1")
|
||||
ec2_client = boto3.client("ec2", region_name="us-west-1")
|
||||
vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
|
||||
|
||||
template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"test-security-group1": {
|
||||
"Type": "AWS::EC2::SecurityGroup",
|
||||
"Properties": {
|
||||
"GroupDescription": "test security group",
|
||||
"VpcId": vpc.id,
|
||||
"Tags": [{"Key": "sg-name", "Value": "sg1"}],
|
||||
},
|
||||
},
|
||||
"test-security-group2": {
|
||||
"Type": "AWS::EC2::SecurityGroup",
|
||||
"Properties": {
|
||||
"GroupDescription": "test security group",
|
||||
"VpcId": vpc.id,
|
||||
"Tags": [{"Key": "sg-name", "Value": "sg2"}],
|
||||
},
|
||||
},
|
||||
"test-sg-ingress": {
|
||||
"Type": "AWS::EC2::SecurityGroupIngress",
|
||||
"Properties": {
|
||||
"GroupId": {"Ref": "test-security-group1"},
|
||||
"VpcId": vpc.id,
|
||||
"IpProtocol": "tcp",
|
||||
"FromPort": "80",
|
||||
"ToPort": "8080",
|
||||
"SourceSecurityGroupId": {"Ref": "test-security-group2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
template_json = json.dumps(template)
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
security_group1 = get_secgroup_by_tag(ec2_client, "sg1")
|
||||
security_group2 = get_secgroup_by_tag(ec2_client, "sg2")
|
||||
|
||||
security_group1["IpPermissions"].should.have.length_of(1)
|
||||
security_group1["IpPermissions"][0]["UserIdGroupPairs"].should.have.length_of(1)
|
||||
security_group1["IpPermissions"][0]["UserIdGroupPairs"][0]["GroupId"].should.equal(
|
||||
security_group2["GroupId"]
|
||||
)
|
||||
security_group1["IpPermissions"][0]["IpProtocol"].should.equal("tcp")
|
||||
security_group1["IpPermissions"][0]["FromPort"].should.equal(80)
|
||||
security_group1["IpPermissions"][0]["ToPort"].should.equal(8080)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
def test_security_group_with_update():
|
||||
ec2 = boto3.resource("ec2", region_name="us-west-1")
|
||||
ec2_client = boto3.client("ec2", region_name="us-west-1")
|
||||
vpc1 = ec2.create_vpc(CidrBlock="10.0.0.0/16")
|
||||
vpc2 = ec2.create_vpc(CidrBlock="10.1.0.0/16")
|
||||
|
||||
template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"test-security-group": {
|
||||
"Type": "AWS::EC2::SecurityGroup",
|
||||
"Properties": {
|
||||
"GroupDescription": "test security group",
|
||||
"VpcId": vpc1.id,
|
||||
"Tags": [{"Key": "sg-name", "Value": "sg"}],
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
template_json = json.dumps(template)
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
security_group = get_secgroup_by_tag(ec2_client, "sg")
|
||||
security_group["VpcId"].should.equal(vpc1.id)
|
||||
|
||||
template["Resources"]["test-security-group"]["Properties"]["VpcId"] = vpc2.id
|
||||
template_json = json.dumps(template)
|
||||
cf.update_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
security_group = get_secgroup_by_tag(ec2_client, "sg")
|
||||
security_group["VpcId"].should.equal(vpc2.id)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
def test_subnets_should_be_created_with_availability_zone():
|
||||
ec2 = boto3.resource("ec2", region_name="us-west-1")
|
||||
ec2_client = boto3.client("ec2", region_name="us-west-1")
|
||||
vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
|
||||
|
||||
subnet_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"testSubnet": {
|
||||
"Type": "AWS::EC2::Subnet",
|
||||
"Properties": {
|
||||
"VpcId": vpc.id,
|
||||
"CidrBlock": "10.0.0.0/24",
|
||||
"AvailabilityZone": "us-west-1b",
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
template_json = json.dumps(subnet_template)
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
subnet = ec2_client.describe_subnets(
|
||||
Filters=[{"Name": "cidrBlock", "Values": ["10.0.0.0/24"]}]
|
||||
)["Subnets"][0]
|
||||
subnet["AvailabilityZone"].should.equal("us-west-1b")
|
||||
|
||||
|
||||
def get_secgroup_by_tag(ec2, sg_):
|
||||
return ec2.describe_security_groups(
|
||||
Filters=[{"Name": "tag:sg-name", "Values": [sg_]}]
|
||||
)["SecurityGroups"][0]
|
||||
|
@ -1,6 +1,8 @@
|
||||
import boto3
|
||||
import json
|
||||
import sure # noqa
|
||||
from moto import mock_cloudformation, mock_ec2
|
||||
from tests import EXAMPLE_AMI_ID
|
||||
|
||||
|
||||
SEC_GROUP_INGRESS = """{
|
||||
@ -85,6 +87,44 @@ SEC_GROUP_INGRESS_WITHOUT_DESC = """{
|
||||
}
|
||||
"""
|
||||
|
||||
SEC_GROUP_SOURCE = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"my-security-group": {
|
||||
"Type": "AWS::EC2::SecurityGroup",
|
||||
"Properties": {"GroupDescription": "My other group"},
|
||||
},
|
||||
"Ec2Instance2": {
|
||||
"Type": "AWS::EC2::Instance",
|
||||
"Properties": {
|
||||
"SecurityGroups": [{"Ref": "InstanceSecurityGroup"}],
|
||||
"ImageId": EXAMPLE_AMI_ID,
|
||||
},
|
||||
},
|
||||
"InstanceSecurityGroup": {
|
||||
"Type": "AWS::EC2::SecurityGroup",
|
||||
"Properties": {
|
||||
"GroupDescription": "My security group",
|
||||
"Tags": [{"Key": "bar", "Value": "baz"}],
|
||||
"SecurityGroupIngress": [
|
||||
{
|
||||
"IpProtocol": "tcp",
|
||||
"FromPort": "22",
|
||||
"ToPort": "22",
|
||||
"CidrIp": "123.123.123.123/32",
|
||||
},
|
||||
{
|
||||
"IpProtocol": "tcp",
|
||||
"FromPort": "80",
|
||||
"ToPort": "8000",
|
||||
"SourceSecurityGroupId": {"Ref": "my-security-group"},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
@ -137,3 +177,46 @@ def test_security_group_ingress_without_description():
|
||||
len(group["IpPermissions"]).should.be(1)
|
||||
ingress = group["IpPermissions"][0]
|
||||
ingress["IpRanges"].should.equal([{"CidrIp": "10.0.0.0/8"}])
|
||||
|
||||
|
||||
@mock_ec2
|
||||
@mock_cloudformation
|
||||
def test_stack_security_groups():
|
||||
|
||||
template = json.dumps(SEC_GROUP_SOURCE)
|
||||
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(
|
||||
StackName="security_group_stack",
|
||||
TemplateBody=template,
|
||||
Tags=[{"Key": "foo", "Value": "bar"}],
|
||||
)
|
||||
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
instance_group = ec2.describe_security_groups(
|
||||
Filters=[{"Name": "description", "Values": ["My security group"]}]
|
||||
)["SecurityGroups"][0]
|
||||
instance_group.should.have.key("Description").equal("My security group")
|
||||
instance_group.should.have.key("Tags")
|
||||
instance_group["Tags"].should.contain({"Key": "bar", "Value": "baz"})
|
||||
instance_group["Tags"].should.contain({"Key": "foo", "Value": "bar"})
|
||||
other_group = ec2.describe_security_groups(
|
||||
Filters=[{"Name": "description", "Values": ["My other group"]}]
|
||||
)["SecurityGroups"][0]
|
||||
|
||||
ec2_instance = ec2.describe_instances()["Reservations"][0]["Instances"][0]
|
||||
|
||||
ec2_instance["NetworkInterfaces"][0]["Groups"][0]["GroupId"].should.equal(
|
||||
instance_group["GroupId"]
|
||||
)
|
||||
|
||||
rule1, rule2 = instance_group["IpPermissions"]
|
||||
int(rule1["ToPort"]).should.equal(22)
|
||||
int(rule1["FromPort"]).should.equal(22)
|
||||
rule1["IpRanges"][0]["CidrIp"].should.equal("123.123.123.123/32")
|
||||
rule1["IpProtocol"].should.equal("tcp")
|
||||
|
||||
int(rule2["ToPort"]).should.equal(8000)
|
||||
int(rule2["FromPort"]).should.equal(80)
|
||||
rule2["IpProtocol"].should.equal("tcp")
|
||||
rule2["UserIdGroupPairs"][0]["GroupId"].should.equal(other_group["GroupId"])
|
||||
|
141
tests/test_elb/test_elb_cloudformation.py
Normal file
141
tests/test_elb/test_elb_cloudformation.py
Normal file
@ -0,0 +1,141 @@
|
||||
import boto3
|
||||
import json
|
||||
import sure # noqa
|
||||
|
||||
from moto import mock_cloudformation, mock_ec2, mock_elb
|
||||
from tests import EXAMPLE_AMI_ID
|
||||
|
||||
|
||||
@mock_ec2
|
||||
@mock_elb
|
||||
@mock_cloudformation
|
||||
def test_stack_elb_integration_with_attached_ec2_instances():
|
||||
elb_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"MyELB": {
|
||||
"Type": "AWS::ElasticLoadBalancing::LoadBalancer",
|
||||
"Properties": {
|
||||
"Instances": [{"Ref": "Ec2Instance1"}],
|
||||
"LoadBalancerName": "test-elb",
|
||||
"AvailabilityZones": ["us-east-1"],
|
||||
"Listeners": [
|
||||
{
|
||||
"InstancePort": "80",
|
||||
"LoadBalancerPort": "80",
|
||||
"Protocol": "HTTP",
|
||||
}
|
||||
],
|
||||
},
|
||||
},
|
||||
"Ec2Instance1": {
|
||||
"Type": "AWS::EC2::Instance",
|
||||
"Properties": {"ImageId": EXAMPLE_AMI_ID, "UserData": "some user data"},
|
||||
},
|
||||
},
|
||||
}
|
||||
elb_template_json = json.dumps(elb_template)
|
||||
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="elb_stack", TemplateBody=elb_template_json)
|
||||
|
||||
elb = boto3.client("elb", region_name="us-west-1")
|
||||
load_balancer = elb.describe_load_balancers()["LoadBalancerDescriptions"][0]
|
||||
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
reservations = ec2.describe_instances()["Reservations"][0]
|
||||
ec2_instance = reservations["Instances"][0]
|
||||
|
||||
load_balancer["Instances"][0]["InstanceId"].should.equal(ec2_instance["InstanceId"])
|
||||
load_balancer["AvailabilityZones"].should.equal(["us-east-1"])
|
||||
|
||||
|
||||
@mock_elb
|
||||
@mock_cloudformation
|
||||
def test_stack_elb_integration_with_health_check():
|
||||
elb_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"MyELB": {
|
||||
"Type": "AWS::ElasticLoadBalancing::LoadBalancer",
|
||||
"Properties": {
|
||||
"LoadBalancerName": "test-elb",
|
||||
"AvailabilityZones": ["us-west-1"],
|
||||
"HealthCheck": {
|
||||
"HealthyThreshold": "3",
|
||||
"Interval": "5",
|
||||
"Target": "HTTP:80/healthcheck",
|
||||
"Timeout": "4",
|
||||
"UnhealthyThreshold": "2",
|
||||
},
|
||||
"Listeners": [
|
||||
{
|
||||
"InstancePort": "80",
|
||||
"LoadBalancerPort": "80",
|
||||
"Protocol": "HTTP",
|
||||
}
|
||||
],
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
elb_template_json = json.dumps(elb_template)
|
||||
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="elb_stack", TemplateBody=elb_template_json)
|
||||
|
||||
elb = boto3.client("elb", region_name="us-west-1")
|
||||
load_balancer = elb.describe_load_balancers()["LoadBalancerDescriptions"][0]
|
||||
health_check = load_balancer["HealthCheck"]
|
||||
|
||||
health_check.should.have.key("HealthyThreshold").equal(3)
|
||||
health_check.should.have.key("Interval").equal(5)
|
||||
health_check.should.have.key("Target").equal("HTTP:80/healthcheck")
|
||||
health_check.should.have.key("Timeout").equal(4)
|
||||
health_check.should.have.key("UnhealthyThreshold").equal(2)
|
||||
|
||||
|
||||
@mock_elb
|
||||
@mock_cloudformation
|
||||
def test_stack_elb_integration_with_update():
|
||||
elb_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"MyELB": {
|
||||
"Type": "AWS::ElasticLoadBalancing::LoadBalancer",
|
||||
"Properties": {
|
||||
"LoadBalancerName": "test-elb",
|
||||
"AvailabilityZones": ["us-west-1a"],
|
||||
"Listeners": [
|
||||
{
|
||||
"InstancePort": "80",
|
||||
"LoadBalancerPort": "80",
|
||||
"Protocol": "HTTP",
|
||||
}
|
||||
],
|
||||
"Policies": {"Ref": "AWS::NoValue"},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
elb_template_json = json.dumps(elb_template)
|
||||
|
||||
# when
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="elb_stack", TemplateBody=elb_template_json)
|
||||
|
||||
# then
|
||||
elb = boto3.client("elb", region_name="us-west-1")
|
||||
load_balancer = elb.describe_load_balancers()["LoadBalancerDescriptions"][0]
|
||||
load_balancer["AvailabilityZones"].should.equal(["us-west-1a"])
|
||||
|
||||
# when
|
||||
elb_template["Resources"]["MyELB"]["Properties"]["AvailabilityZones"] = [
|
||||
"us-west-1b"
|
||||
]
|
||||
elb_template_json = json.dumps(elb_template)
|
||||
cf.update_stack(StackName="elb_stack", TemplateBody=elb_template_json)
|
||||
|
||||
# then
|
||||
load_balancer = elb.describe_load_balancers()["LoadBalancerDescriptions"][0]
|
||||
load_balancer["AvailabilityZones"].should.equal(["us-west-1b"])
|
@ -1,12 +1,14 @@
|
||||
import boto3
|
||||
import json
|
||||
import yaml
|
||||
import sure # noqa
|
||||
|
||||
import pytest
|
||||
from botocore.exceptions import ClientError
|
||||
|
||||
from moto import mock_iam, mock_cloudformation, mock_s3, mock_sts
|
||||
from moto.core import ACCOUNT_ID
|
||||
from moto import mock_autoscaling, mock_iam, mock_cloudformation, mock_s3, mock_sts
|
||||
from tests import EXAMPLE_AMI_ID
|
||||
|
||||
|
||||
TEMPLATE_MINIMAL_ROLE = """
|
||||
@ -60,6 +62,7 @@ Resources:
|
||||
- !Ref RootRole
|
||||
"""
|
||||
|
||||
|
||||
# AWS::IAM::User Tests
|
||||
@mock_iam
|
||||
@mock_cloudformation
|
||||
@ -1495,3 +1498,165 @@ def test_iam_cloudformation_create_role_and_instance_profile():
|
||||
cf_client.delete_stack(StackName=stack_name)
|
||||
|
||||
iam_client.list_roles()["Roles"].should.have.length_of(0)
|
||||
|
||||
|
||||
@mock_autoscaling
|
||||
@mock_iam
|
||||
@mock_cloudformation
|
||||
def test_iam_roles():
|
||||
iam_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"my-launch-config": {
|
||||
"Properties": {
|
||||
"IamInstanceProfile": {"Ref": "my-instance-profile-with-path"},
|
||||
"ImageId": EXAMPLE_AMI_ID,
|
||||
"InstanceType": "t2.medium",
|
||||
},
|
||||
"Type": "AWS::AutoScaling::LaunchConfiguration",
|
||||
},
|
||||
"my-instance-profile-with-path": {
|
||||
"Properties": {
|
||||
"Path": "my-path",
|
||||
"Roles": [{"Ref": "my-role-with-path"}],
|
||||
},
|
||||
"Type": "AWS::IAM::InstanceProfile",
|
||||
},
|
||||
"my-instance-profile-no-path": {
|
||||
"Properties": {"Roles": [{"Ref": "my-role-no-path"}]},
|
||||
"Type": "AWS::IAM::InstanceProfile",
|
||||
},
|
||||
"my-role-with-path": {
|
||||
"Properties": {
|
||||
"AssumeRolePolicyDocument": {
|
||||
"Statement": [
|
||||
{
|
||||
"Action": ["sts:AssumeRole"],
|
||||
"Effect": "Allow",
|
||||
"Principal": {"Service": ["ec2.amazonaws.com"]},
|
||||
}
|
||||
]
|
||||
},
|
||||
"Path": "/my-path/",
|
||||
"Policies": [
|
||||
{
|
||||
"PolicyDocument": {
|
||||
"Statement": [
|
||||
{
|
||||
"Action": [
|
||||
"ec2:CreateTags",
|
||||
"ec2:DescribeInstances",
|
||||
"ec2:DescribeTags",
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": ["*"],
|
||||
}
|
||||
],
|
||||
"Version": "2012-10-17",
|
||||
},
|
||||
"PolicyName": "EC2_Tags",
|
||||
},
|
||||
{
|
||||
"PolicyDocument": {
|
||||
"Statement": [
|
||||
{
|
||||
"Action": ["sqs:*"],
|
||||
"Effect": "Allow",
|
||||
"Resource": ["*"],
|
||||
}
|
||||
],
|
||||
"Version": "2012-10-17",
|
||||
},
|
||||
"PolicyName": "SQS",
|
||||
},
|
||||
],
|
||||
},
|
||||
"Type": "AWS::IAM::Role",
|
||||
},
|
||||
"my-role-no-path": {
|
||||
"Properties": {
|
||||
"RoleName": "my-role-no-path-name",
|
||||
"AssumeRolePolicyDocument": {
|
||||
"Statement": [
|
||||
{
|
||||
"Action": ["sts:AssumeRole"],
|
||||
"Effect": "Allow",
|
||||
"Principal": {"Service": ["ec2.amazonaws.com"]},
|
||||
}
|
||||
]
|
||||
},
|
||||
},
|
||||
"Type": "AWS::IAM::Role",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
iam_template_json = json.dumps(iam_template)
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=iam_template_json)
|
||||
|
||||
iam = boto3.client("iam", region_name="us-west-1")
|
||||
|
||||
role_results = iam.list_roles()["Roles"]
|
||||
role_name_to_id = {}
|
||||
role_names = []
|
||||
for role_result in role_results:
|
||||
role = iam.get_role(RoleName=role_result["RoleName"])["Role"]
|
||||
role_names.append(role["RoleName"])
|
||||
# Role name is not specified, so randomly generated - can't check exact name
|
||||
if "with-path" in role["RoleName"]:
|
||||
role_name_to_id["with-path"] = role["RoleId"]
|
||||
role["Path"].should.equal("/my-path/")
|
||||
else:
|
||||
role_name_to_id["no-path"] = role["RoleId"]
|
||||
role["RoleName"].should.equal("my-role-no-path-name")
|
||||
role["Path"].should.equal("/")
|
||||
|
||||
instance_profile_responses = iam.list_instance_profiles()["InstanceProfiles"]
|
||||
instance_profile_responses.should.have.length_of(2)
|
||||
instance_profile_names = []
|
||||
|
||||
for instance_profile_response in instance_profile_responses:
|
||||
instance_profile = iam.get_instance_profile(
|
||||
InstanceProfileName=instance_profile_response["InstanceProfileName"]
|
||||
)["InstanceProfile"]
|
||||
instance_profile_names.append(instance_profile["InstanceProfileName"])
|
||||
instance_profile["InstanceProfileName"].should.contain("my-instance-profile")
|
||||
if "with-path" in instance_profile["InstanceProfileName"]:
|
||||
instance_profile["Path"].should.equal("my-path")
|
||||
instance_profile["Roles"][0]["RoleId"].should.equal(
|
||||
role_name_to_id["with-path"]
|
||||
)
|
||||
else:
|
||||
instance_profile["InstanceProfileName"].should.contain("no-path")
|
||||
instance_profile["Roles"][0]["RoleId"].should.equal(
|
||||
role_name_to_id["no-path"]
|
||||
)
|
||||
instance_profile["Path"].should.equal("/")
|
||||
|
||||
autoscale = boto3.client("autoscaling", region_name="us-west-1")
|
||||
launch_config = autoscale.describe_launch_configurations()["LaunchConfigurations"][
|
||||
0
|
||||
]
|
||||
launch_config.should.have.key("IamInstanceProfile").should.contain(
|
||||
"my-instance-profile-with-path"
|
||||
)
|
||||
|
||||
resources = cf.list_stack_resources(StackName="test_stack")[
|
||||
"StackResourceSummaries"
|
||||
]
|
||||
instance_profile_resources = [
|
||||
resource
|
||||
for resource in resources
|
||||
if resource["ResourceType"] == "AWS::IAM::InstanceProfile"
|
||||
]
|
||||
{ip["PhysicalResourceId"] for ip in instance_profile_resources}.should.equal(
|
||||
set(instance_profile_names)
|
||||
)
|
||||
|
||||
role_resources = [
|
||||
resource
|
||||
for resource in resources
|
||||
if resource["ResourceType"] == "AWS::IAM::Role"
|
||||
]
|
||||
{r["PhysicalResourceId"] for r in role_resources}.should.equal(set(role_names))
|
||||
|
@ -2,6 +2,8 @@ import boto3
|
||||
import json
|
||||
import sure # noqa
|
||||
from moto import mock_cloudformation, mock_ec2, mock_rds2
|
||||
from tests.test_cloudformation.fixtures import rds_mysql_with_db_parameter_group
|
||||
from tests.test_cloudformation.fixtures import rds_mysql_with_read_replica
|
||||
|
||||
|
||||
@mock_ec2
|
||||
@ -112,3 +114,137 @@ def test_create_dbsecuritygroup_via_cf():
|
||||
|
||||
created = result[0]
|
||||
created["DBSecurityGroupDescription"].should.equal("my sec group")
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
@mock_rds2
|
||||
def test_rds_db_parameter_groups():
|
||||
ec2_conn = boto3.client("ec2", region_name="us-west-1")
|
||||
ec2_conn.create_security_group(
|
||||
GroupName="application", Description="Our Application Group"
|
||||
)
|
||||
|
||||
template_json = json.dumps(rds_mysql_with_db_parameter_group.template)
|
||||
cf_conn = boto3.client("cloudformation", "us-west-1")
|
||||
cf_conn.create_stack(
|
||||
StackName="test_stack",
|
||||
TemplateBody=template_json,
|
||||
Parameters=[
|
||||
{"ParameterKey": key, "ParameterValue": value}
|
||||
for key, value in [
|
||||
("DBInstanceIdentifier", "master_db"),
|
||||
("DBName", "my_db"),
|
||||
("DBUser", "my_user"),
|
||||
("DBPassword", "my_password"),
|
||||
("DBAllocatedStorage", "20"),
|
||||
("DBInstanceClass", "db.m1.medium"),
|
||||
("EC2SecurityGroup", "application"),
|
||||
("MultiAZ", "true"),
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
rds_conn = boto3.client("rds", region_name="us-west-1")
|
||||
|
||||
db_parameter_groups = rds_conn.describe_db_parameter_groups()
|
||||
db_parameter_groups["DBParameterGroups"].should.have.length_of(1)
|
||||
db_parameter_group_name = db_parameter_groups["DBParameterGroups"][0][
|
||||
"DBParameterGroupName"
|
||||
]
|
||||
|
||||
found_cloudformation_set_parameter = False
|
||||
for db_parameter in rds_conn.describe_db_parameters(
|
||||
DBParameterGroupName=db_parameter_group_name
|
||||
)["Parameters"]:
|
||||
if (
|
||||
db_parameter["ParameterName"] == "BACKLOG_QUEUE_LIMIT"
|
||||
and db_parameter["ParameterValue"] == "2048"
|
||||
):
|
||||
found_cloudformation_set_parameter = True
|
||||
|
||||
found_cloudformation_set_parameter.should.equal(True)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
@mock_rds2
|
||||
def test_rds_mysql_with_read_replica():
|
||||
ec2_conn = boto3.client("ec2", region_name="us-west-1")
|
||||
ec2_conn.create_security_group(
|
||||
GroupName="application", Description="Our Application Group"
|
||||
)
|
||||
|
||||
template_json = json.dumps(rds_mysql_with_read_replica.template)
|
||||
cf = boto3.client("cloudformation", "us-west-1")
|
||||
cf.create_stack(
|
||||
StackName="test_stack",
|
||||
TemplateBody=template_json,
|
||||
Parameters=[
|
||||
{"ParameterKey": "DBInstanceIdentifier", "ParameterValue": "master_db"},
|
||||
{"ParameterKey": "DBName", "ParameterValue": "my_db"},
|
||||
{"ParameterKey": "DBUser", "ParameterValue": "my_user"},
|
||||
{"ParameterKey": "DBPassword", "ParameterValue": "my_password"},
|
||||
{"ParameterKey": "DBAllocatedStorage", "ParameterValue": "20"},
|
||||
{"ParameterKey": "DBInstanceClass", "ParameterValue": "db.m1.medium"},
|
||||
{"ParameterKey": "EC2SecurityGroup", "ParameterValue": "application"},
|
||||
{"ParameterKey": "MultiAZ", "ParameterValue": "true"},
|
||||
],
|
||||
)
|
||||
|
||||
rds = boto3.client("rds", region_name="us-west-1")
|
||||
|
||||
primary = rds.describe_db_instances(DBInstanceIdentifier="master_db")[
|
||||
"DBInstances"
|
||||
][0]
|
||||
primary.should.have.key("MasterUsername").equal("my_user")
|
||||
primary.should.have.key("AllocatedStorage").equal(20)
|
||||
primary.should.have.key("DBInstanceClass").equal("db.m1.medium")
|
||||
primary.should.have.key("MultiAZ").equal(True)
|
||||
primary.should.have.key("ReadReplicaDBInstanceIdentifiers").being.length_of(1)
|
||||
replica_id = primary["ReadReplicaDBInstanceIdentifiers"][0]
|
||||
|
||||
replica = rds.describe_db_instances(DBInstanceIdentifier=replica_id)["DBInstances"][
|
||||
0
|
||||
]
|
||||
replica.should.have.key("DBInstanceClass").equal("db.m1.medium")
|
||||
|
||||
security_group_name = primary["DBSecurityGroups"][0]["DBSecurityGroupName"]
|
||||
security_group = rds.describe_db_security_groups(
|
||||
DBSecurityGroupName=security_group_name
|
||||
)["DBSecurityGroups"][0]
|
||||
security_group["EC2SecurityGroups"][0]["EC2SecurityGroupName"].should.equal(
|
||||
"application"
|
||||
)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
@mock_rds2
|
||||
def test_rds_mysql_with_read_replica_in_vpc():
|
||||
template_json = json.dumps(rds_mysql_with_read_replica.template)
|
||||
cf = boto3.client("cloudformation", "eu-central-1")
|
||||
cf.create_stack(
|
||||
StackName="test_stack",
|
||||
TemplateBody=template_json,
|
||||
Parameters=[
|
||||
{"ParameterKey": "DBInstanceIdentifier", "ParameterValue": "master_db"},
|
||||
{"ParameterKey": "DBName", "ParameterValue": "my_db"},
|
||||
{"ParameterKey": "DBUser", "ParameterValue": "my_user"},
|
||||
{"ParameterKey": "DBPassword", "ParameterValue": "my_password"},
|
||||
{"ParameterKey": "DBAllocatedStorage", "ParameterValue": "20"},
|
||||
{"ParameterKey": "DBInstanceClass", "ParameterValue": "db.m1.medium"},
|
||||
{"ParameterKey": "MultiAZ", "ParameterValue": "true"},
|
||||
],
|
||||
)
|
||||
|
||||
rds = boto3.client("rds", region_name="eu-central-1")
|
||||
primary = rds.describe_db_instances(DBInstanceIdentifier="master_db")[
|
||||
"DBInstances"
|
||||
][0]
|
||||
|
||||
subnet_group_name = primary["DBSubnetGroup"]["DBSubnetGroupName"]
|
||||
subnet_group = rds.describe_db_subnet_groups(DBSubnetGroupName=subnet_group_name)[
|
||||
"DBSubnetGroups"
|
||||
][0]
|
||||
subnet_group.should.have.key("DBSubnetGroupDescription").equal("my db subnet group")
|
||||
|
52
tests/test_redshift/test_redshift_cloudformation.py
Normal file
52
tests/test_redshift/test_redshift_cloudformation.py
Normal file
@ -0,0 +1,52 @@
|
||||
import boto3
|
||||
import json
|
||||
import sure # noqa
|
||||
|
||||
from moto import mock_cloudformation, mock_ec2, mock_redshift
|
||||
from tests.test_cloudformation.fixtures import redshift
|
||||
|
||||
|
||||
@mock_ec2
|
||||
@mock_redshift
|
||||
@mock_cloudformation
|
||||
def test_redshift_stack():
|
||||
redshift_template_json = json.dumps(redshift.template)
|
||||
|
||||
ec2 = boto3.client("ec2", region_name="us-west-2")
|
||||
cf = boto3.client("cloudformation", region_name="us-west-2")
|
||||
cf.create_stack(
|
||||
StackName="redshift_stack",
|
||||
TemplateBody=redshift_template_json,
|
||||
Parameters=[
|
||||
{"ParameterKey": "DatabaseName", "ParameterValue": "mydb"},
|
||||
{"ParameterKey": "ClusterType", "ParameterValue": "multi-node"},
|
||||
{"ParameterKey": "NumberOfNodes", "ParameterValue": "2"},
|
||||
{"ParameterKey": "NodeType", "ParameterValue": "dw1.xlarge"},
|
||||
{"ParameterKey": "MasterUsername", "ParameterValue": "myuser"},
|
||||
{"ParameterKey": "MasterUserPassword", "ParameterValue": "mypass"},
|
||||
{"ParameterKey": "InboundTraffic", "ParameterValue": "10.0.0.1/16"},
|
||||
{"ParameterKey": "PortNumber", "ParameterValue": "5439"},
|
||||
],
|
||||
)
|
||||
|
||||
redshift_conn = boto3.client("redshift", region_name="us-west-2")
|
||||
|
||||
cluster_res = redshift_conn.describe_clusters()
|
||||
clusters = cluster_res["Clusters"]
|
||||
clusters.should.have.length_of(1)
|
||||
cluster = clusters[0]
|
||||
cluster["DBName"].should.equal("mydb")
|
||||
cluster["NumberOfNodes"].should.equal(2)
|
||||
cluster["NodeType"].should.equal("dw1.xlarge")
|
||||
cluster["MasterUsername"].should.equal("myuser")
|
||||
cluster["Endpoint"]["Port"].should.equal(5439)
|
||||
cluster["VpcSecurityGroups"].should.have.length_of(1)
|
||||
security_group_id = cluster["VpcSecurityGroups"][0]["VpcSecurityGroupId"]
|
||||
|
||||
groups = ec2.describe_security_groups(GroupIds=[security_group_id])[
|
||||
"SecurityGroups"
|
||||
]
|
||||
groups.should.have.length_of(1)
|
||||
group = groups[0]
|
||||
group["IpPermissions"].should.have.length_of(1)
|
||||
group["IpPermissions"][0]["IpRanges"][0]["CidrIp"].should.equal("10.0.0.1/16")
|
@ -11,6 +11,7 @@ from moto import mock_s3
|
||||
from tests import EXAMPLE_AMI_ID, EXAMPLE_AMI_ID2
|
||||
|
||||
|
||||
@mock_rds2
|
||||
@mock_ec2
|
||||
@mock_resourcegroupstaggingapi
|
||||
def test_get_resources_ec2():
|
||||
|
226
tests/test_route53/test_route53_cloudformation.py
Normal file
226
tests/test_route53/test_route53_cloudformation.py
Normal file
@ -0,0 +1,226 @@
|
||||
import boto3
|
||||
import json
|
||||
import sure # noqa
|
||||
|
||||
from copy import deepcopy
|
||||
from moto import mock_cloudformation, mock_ec2, mock_route53
|
||||
from tests.test_cloudformation.fixtures import route53_ec2_instance_with_public_ip
|
||||
from tests.test_cloudformation.fixtures import route53_health_check
|
||||
from tests.test_cloudformation.fixtures import route53_roundrobin
|
||||
|
||||
template_hosted_zone = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Description": "Stack 1",
|
||||
"Parameters": {},
|
||||
"Resources": {
|
||||
"Bar": {
|
||||
"Type": "AWS::Route53::HostedZone",
|
||||
"Properties": {"Name": "foo.bar.baz"},
|
||||
}
|
||||
},
|
||||
}
|
||||
template_record_set = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Description": "Stack 2",
|
||||
"Parameters": {"ZoneId": {"Type": "String"}},
|
||||
"Resources": {
|
||||
"Foo": {
|
||||
"Properties": {
|
||||
"HostedZoneId": {"Ref": "ZoneId"},
|
||||
"RecordSets": [
|
||||
{
|
||||
"Name": "test.vpc.internal",
|
||||
"Type": "A",
|
||||
"SetIdentifier": "test1",
|
||||
"Weight": 50,
|
||||
}
|
||||
],
|
||||
},
|
||||
"Type": "AWS::Route53::RecordSetGroup",
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_route53
|
||||
def test_create_stack_hosted_zone_by_id():
|
||||
cf_conn = boto3.client("cloudformation", region_name="us-east-1")
|
||||
conn = boto3.client("route53", region_name="us-east-1")
|
||||
|
||||
# when creating a hosted zone via CF
|
||||
cf_conn.create_stack(
|
||||
StackName="test_stack1", TemplateBody=json.dumps(template_hosted_zone)
|
||||
)
|
||||
|
||||
# then a hosted zone should exist
|
||||
zone = conn.list_hosted_zones()["HostedZones"][0]
|
||||
zone.should.have.key("Name").equal("foo.bar.baz")
|
||||
zone.should.have.key("ResourceRecordSetCount").equal(0)
|
||||
|
||||
# when adding a record set to this zone
|
||||
cf_conn.create_stack(
|
||||
StackName="test_stack2",
|
||||
TemplateBody=json.dumps(template_record_set),
|
||||
Parameters=[{"ParameterKey": "ZoneId", "ParameterValue": zone["Id"]}],
|
||||
)
|
||||
|
||||
# then the hosted zone should have a record
|
||||
updated_zone = conn.list_hosted_zones()["HostedZones"][0]
|
||||
updated_zone.should.have.key("Id").equal(zone["Id"])
|
||||
updated_zone.should.have.key("Name").equal("foo.bar.baz")
|
||||
updated_zone.should.have.key("ResourceRecordSetCount").equal(1)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_route53
|
||||
def test_route53_roundrobin():
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
route53 = boto3.client("route53", region_name="us-west-1")
|
||||
|
||||
template_json = json.dumps(route53_roundrobin.template)
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
|
||||
zones = route53.list_hosted_zones()["HostedZones"]
|
||||
zones.should.have.length_of(1)
|
||||
zone_id = zones[0]["Id"].split("/")[2]
|
||||
|
||||
rrsets = route53.list_resource_record_sets(HostedZoneId=zone_id)[
|
||||
"ResourceRecordSets"
|
||||
]
|
||||
rrsets.should.have.length_of(2)
|
||||
record_set1 = rrsets[0]
|
||||
record_set1["Name"].should.equal("test_stack.us-west-1.my_zone.")
|
||||
record_set1["SetIdentifier"].should.equal("test_stack AWS")
|
||||
record_set1["Type"].should.equal("CNAME")
|
||||
record_set1["TTL"].should.equal(900)
|
||||
record_set1["Weight"].should.equal(3)
|
||||
record_set1["ResourceRecords"][0]["Value"].should.equal("aws.amazon.com")
|
||||
|
||||
record_set2 = rrsets[1]
|
||||
record_set2["Name"].should.equal("test_stack.us-west-1.my_zone.")
|
||||
record_set2["SetIdentifier"].should.equal("test_stack Amazon")
|
||||
record_set2["Type"].should.equal("CNAME")
|
||||
record_set2["TTL"].should.equal(900)
|
||||
record_set2["Weight"].should.equal(1)
|
||||
record_set2["ResourceRecords"][0]["Value"].should.equal("www.amazon.com")
|
||||
|
||||
stack = cf.describe_stacks(StackName="test_stack")["Stacks"][0]
|
||||
output = stack["Outputs"][0]
|
||||
output["OutputKey"].should.equal("DomainName")
|
||||
output["OutputValue"].should.equal(
|
||||
"arn:aws:route53:::hostedzone/{0}".format(zone_id)
|
||||
)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_ec2
|
||||
@mock_route53
|
||||
def test_route53_ec2_instance_with_public_ip():
|
||||
route53 = boto3.client("route53", region_name="us-west-1")
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
|
||||
template_json = json.dumps(route53_ec2_instance_with_public_ip.template)
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
|
||||
instance_id = ec2.describe_instances()["Reservations"][0]["Instances"][0][
|
||||
"InstanceId"
|
||||
]
|
||||
|
||||
zones = route53.list_hosted_zones()["HostedZones"]
|
||||
zones.should.have.length_of(1)
|
||||
zone_id = zones[0]["Id"].split("/")[2]
|
||||
|
||||
rrsets = route53.list_resource_record_sets(HostedZoneId=zone_id)[
|
||||
"ResourceRecordSets"
|
||||
]
|
||||
rrsets.should.have.length_of(1)
|
||||
|
||||
record_set = rrsets[0]
|
||||
record_set["Name"].should.equal("{0}.us-west-1.my_zone.".format(instance_id))
|
||||
record_set.shouldnt.have.key("SetIdentifier")
|
||||
record_set["Type"].should.equal("A")
|
||||
record_set["TTL"].should.equal(900)
|
||||
record_set.shouldnt.have.key("Weight")
|
||||
record_set["ResourceRecords"][0]["Value"].should.equal("10.0.0.25")
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_route53
|
||||
def test_route53_associate_health_check():
|
||||
route53 = boto3.client("route53", region_name="us-west-1")
|
||||
|
||||
template_json = json.dumps(route53_health_check.template)
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
|
||||
checks = route53.list_health_checks()["HealthChecks"]
|
||||
checks.should.have.length_of(1)
|
||||
check = checks[0]
|
||||
health_check_id = check["Id"]
|
||||
config = check["HealthCheckConfig"]
|
||||
config["FailureThreshold"].should.equal(3)
|
||||
config["IPAddress"].should.equal("10.0.0.4")
|
||||
config["Port"].should.equal(80)
|
||||
config["RequestInterval"].should.equal(10)
|
||||
config["ResourcePath"].should.equal("/")
|
||||
config["Type"].should.equal("HTTP")
|
||||
|
||||
zones = route53.list_hosted_zones()["HostedZones"]
|
||||
zones.should.have.length_of(1)
|
||||
zone_id = zones[0]["Id"].split("/")[2]
|
||||
|
||||
rrsets = route53.list_resource_record_sets(HostedZoneId=zone_id)[
|
||||
"ResourceRecordSets"
|
||||
]
|
||||
rrsets.should.have.length_of(1)
|
||||
record_set = rrsets[0]
|
||||
record_set["HealthCheckId"].should.equal(health_check_id)
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_route53
|
||||
def test_route53_with_update():
|
||||
route53 = boto3.client("route53", region_name="us-west-1")
|
||||
|
||||
template_json = json.dumps(route53_health_check.template)
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
|
||||
zones = route53.list_hosted_zones()["HostedZones"]
|
||||
zones.should.have.length_of(1)
|
||||
zone_id = zones[0]["Id"]
|
||||
zone_id = zone_id.split("/")
|
||||
zone_id = zone_id[2]
|
||||
|
||||
rrsets = route53.list_resource_record_sets(HostedZoneId=zone_id)[
|
||||
"ResourceRecordSets"
|
||||
]
|
||||
rrsets.should.have.length_of(1)
|
||||
|
||||
record_set = rrsets[0]
|
||||
record_set["ResourceRecords"][0]["Value"].should.equal("my.example.com")
|
||||
|
||||
# given
|
||||
template = deepcopy(route53_health_check.template)
|
||||
template["Resources"]["myDNSRecord"]["Properties"]["ResourceRecords"] = [
|
||||
"my_other.example.com"
|
||||
]
|
||||
template_json = json.dumps(template)
|
||||
|
||||
# when
|
||||
cf.update_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
|
||||
# then
|
||||
zones = route53.list_hosted_zones()["HostedZones"]
|
||||
zones.should.have.length_of(1)
|
||||
zone_id = zones[0]["Id"].split("/")[2]
|
||||
|
||||
rrsets = route53.list_resource_record_sets(HostedZoneId=zone_id)[
|
||||
"ResourceRecordSets"
|
||||
]
|
||||
rrsets.should.have.length_of(1)
|
||||
|
||||
record_set = rrsets[0]
|
||||
record_set["ResourceRecords"][0]["Value"].should.equal("my_other.example.com")
|
53
tests/test_sns/test_sns_cloudformation.py
Normal file
53
tests/test_sns/test_sns_cloudformation.py
Normal file
@ -0,0 +1,53 @@
|
||||
import boto3
|
||||
import json
|
||||
import sure # noqa
|
||||
|
||||
from moto import mock_cloudformation, mock_sns
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_sns
|
||||
def test_sns_topic():
|
||||
dummy_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"MySNSTopic": {
|
||||
"Type": "AWS::SNS::Topic",
|
||||
"Properties": {
|
||||
"Subscription": [
|
||||
{"Endpoint": "https://example.com", "Protocol": "https"}
|
||||
],
|
||||
"TopicName": "my_topics",
|
||||
},
|
||||
}
|
||||
},
|
||||
"Outputs": {
|
||||
"topic_name": {"Value": {"Fn::GetAtt": ["MySNSTopic", "TopicName"]}},
|
||||
"topic_arn": {"Value": {"Ref": "MySNSTopic"}},
|
||||
},
|
||||
}
|
||||
template_json = json.dumps(dummy_template)
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=template_json)
|
||||
|
||||
sns = boto3.client("sns", region_name="us-west-1")
|
||||
topics = sns.list_topics()["Topics"]
|
||||
topics.should.have.length_of(1)
|
||||
topic_arn = topics[0]["TopicArn"]
|
||||
topic_arn.should.contain("my_topics")
|
||||
|
||||
subscriptions = sns.list_subscriptions()["Subscriptions"]
|
||||
subscriptions.should.have.length_of(1)
|
||||
subscription = subscriptions[0]
|
||||
subscription["TopicArn"].should.equal(topic_arn)
|
||||
subscription["Protocol"].should.equal("https")
|
||||
subscription["SubscriptionArn"].should.contain(topic_arn)
|
||||
subscription["Endpoint"].should.equal("https://example.com")
|
||||
|
||||
stack = cf.describe_stacks(StackName="test_stack")["Stacks"][0]
|
||||
topic_name_output = [x for x in stack["Outputs"] if x["OutputKey"] == "topic_name"][
|
||||
0
|
||||
]
|
||||
topic_name_output["OutputValue"].should.equal("my_topics")
|
||||
topic_arn_output = [x for x in stack["Outputs"] if x["OutputKey"] == "topic_arn"][0]
|
||||
topic_arn_output["OutputValue"].should.equal(topic_arn)
|
@ -1,6 +1,21 @@
|
||||
import boto3
|
||||
from moto import mock_sqs, mock_cloudformation
|
||||
import json
|
||||
import sure # noqa
|
||||
|
||||
from moto import mock_sqs, mock_cloudformation
|
||||
from moto.core import ACCOUNT_ID
|
||||
|
||||
|
||||
simple_queue = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"QueueGroup": {
|
||||
"Type": "AWS::SQS::Queue",
|
||||
"Properties": {"QueueName": "my-queue", "VisibilityTimeout": 60},
|
||||
}
|
||||
},
|
||||
}
|
||||
simple_queue_json = json.dumps(simple_queue)
|
||||
sqs_template_with_tags = """
|
||||
{
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
@ -24,6 +39,43 @@ sqs_template_with_tags = """
|
||||
}"""
|
||||
|
||||
|
||||
@mock_sqs
|
||||
@mock_cloudformation
|
||||
def test_describe_stack_subresources():
|
||||
res = boto3.resource("cloudformation", region_name="us-east-1")
|
||||
cf = boto3.client("cloudformation", region_name="us-east-1")
|
||||
client = boto3.client("sqs", region_name="us-east-1")
|
||||
|
||||
cf.create_stack(StackName="test_sqs", TemplateBody=simple_queue_json)
|
||||
|
||||
queue_url = client.list_queues()["QueueUrls"][0]
|
||||
queue_url.should.contain("{}/{}".format(ACCOUNT_ID, "my-queue"))
|
||||
|
||||
stack = res.Stack("test_sqs")
|
||||
for s in stack.resource_summaries.all():
|
||||
s.resource_type.should.equal("AWS::SQS::Queue")
|
||||
s.logical_id.should.equal("QueueGroup")
|
||||
s.physical_resource_id.should.equal("my-queue")
|
||||
|
||||
|
||||
@mock_sqs
|
||||
@mock_cloudformation
|
||||
def test_list_stack_resources():
|
||||
cf = boto3.client("cloudformation", region_name="us-east-1")
|
||||
client = boto3.client("sqs", region_name="us-east-1")
|
||||
|
||||
cf.create_stack(StackName="test_sqs", TemplateBody=simple_queue_json)
|
||||
|
||||
queue_url = client.list_queues()["QueueUrls"][0]
|
||||
queue_url.should.contain("{}/{}".format(ACCOUNT_ID, "my-queue"))
|
||||
|
||||
queue = cf.list_stack_resources(StackName="test_sqs")["StackResourceSummaries"][0]
|
||||
|
||||
queue.should.have.key("ResourceType").equal("AWS::SQS::Queue")
|
||||
queue.should.have.key("LogicalResourceId").should.equal("QueueGroup")
|
||||
queue.should.have.key("PhysicalResourceId").should.equal("my-queue")
|
||||
|
||||
|
||||
@mock_sqs
|
||||
@mock_cloudformation
|
||||
def test_create_from_cloudformation_json_with_tags():
|
||||
@ -36,3 +88,98 @@ def test_create_from_cloudformation_json_with_tags():
|
||||
|
||||
queue_tags = client.list_queue_tags(QueueUrl=queue_url)["Tags"]
|
||||
queue_tags.should.equal({"keyname1": "value1", "keyname2": "value2"})
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_sqs
|
||||
def test_update_stack():
|
||||
sqs_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"QueueGroup": {
|
||||
"Type": "AWS::SQS::Queue",
|
||||
"Properties": {"QueueName": "my-queue", "VisibilityTimeout": 60},
|
||||
}
|
||||
},
|
||||
}
|
||||
sqs_template_json = json.dumps(sqs_template)
|
||||
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=sqs_template_json)
|
||||
|
||||
client = boto3.client("sqs", region_name="us-west-1")
|
||||
queues = client.list_queues()["QueueUrls"]
|
||||
queues.should.have.length_of(1)
|
||||
attrs = client.get_queue_attributes(QueueUrl=queues[0], AttributeNames=["All"])[
|
||||
"Attributes"
|
||||
]
|
||||
attrs["VisibilityTimeout"].should.equal("60")
|
||||
|
||||
# when updating
|
||||
sqs_template["Resources"]["QueueGroup"]["Properties"]["VisibilityTimeout"] = 100
|
||||
sqs_template_json = json.dumps(sqs_template)
|
||||
cf.update_stack(StackName="test_stack", TemplateBody=sqs_template_json)
|
||||
|
||||
# then the attribute should be updated
|
||||
queues = client.list_queues()["QueueUrls"]
|
||||
queues.should.have.length_of(1)
|
||||
attrs = client.get_queue_attributes(QueueUrl=queues[0], AttributeNames=["All"])[
|
||||
"Attributes"
|
||||
]
|
||||
attrs["VisibilityTimeout"].should.equal("100")
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_sqs
|
||||
def test_update_stack_and_remove_resource():
|
||||
sqs_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"QueueGroup": {
|
||||
"Type": "AWS::SQS::Queue",
|
||||
"Properties": {"QueueName": "my-queue", "VisibilityTimeout": 60},
|
||||
}
|
||||
},
|
||||
}
|
||||
sqs_template_json = json.dumps(sqs_template)
|
||||
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=sqs_template_json)
|
||||
|
||||
client = boto3.client("sqs", region_name="us-west-1")
|
||||
client.list_queues()["QueueUrls"].should.have.length_of(1)
|
||||
|
||||
sqs_template["Resources"].pop("QueueGroup")
|
||||
sqs_template_json = json.dumps(sqs_template)
|
||||
cf.update_stack(StackName="test_stack", TemplateBody=sqs_template_json)
|
||||
|
||||
client.list_queues().shouldnt.have.key(
|
||||
"QueueUrls"
|
||||
) # No queues exist, so the key is not passed through
|
||||
|
||||
|
||||
@mock_cloudformation
|
||||
@mock_sqs
|
||||
def test_update_stack_and_add_resource():
|
||||
sqs_template = {"AWSTemplateFormatVersion": "2010-09-09", "Resources": {}}
|
||||
sqs_template_json = json.dumps(sqs_template)
|
||||
|
||||
cf = boto3.client("cloudformation", region_name="us-west-1")
|
||||
cf.create_stack(StackName="test_stack", TemplateBody=sqs_template_json)
|
||||
|
||||
client = boto3.client("sqs", region_name="us-west-1")
|
||||
client.list_queues().shouldnt.have.key("QueueUrls")
|
||||
|
||||
sqs_template = {
|
||||
"AWSTemplateFormatVersion": "2010-09-09",
|
||||
"Resources": {
|
||||
"QueueGroup": {
|
||||
"Type": "AWS::SQS::Queue",
|
||||
"Properties": {"QueueName": "my-queue", "VisibilityTimeout": 60},
|
||||
}
|
||||
},
|
||||
}
|
||||
sqs_template_json = json.dumps(sqs_template)
|
||||
cf.update_stack(StackName="test_stack", TemplateBody=sqs_template_json)
|
||||
|
||||
client.list_queues()["QueueUrls"].should.have.length_of(1)
|
||||
|
Loading…
Reference in New Issue
Block a user