Merge pull request #235 from joekiller/enhance/cloudformation_getatt_tags_and_resource_naming

Enhance/cloudformation getatt tags and resource naming
This commit is contained in:
Steve Pulec 2014-10-21 22:37:01 -04:00
commit c02ed667d5
16 changed files with 486 additions and 36 deletions

View file

@ -0,0 +1,9 @@
from __future__ import unicode_literals
template = {
"Resources": {
"EC2EIP": {
"Type": "AWS::EC2::EIP"
}
}
}

View file

@ -0,0 +1,23 @@
from __future__ import unicode_literals
template = {
"Resources": {
"EC2EIP": {
"Type": "AWS::EC2::EIP"
}
},
"Outputs": {
"EIP": {
"Description": "EIP for joining",
"Value": {
"Fn::Join": [
":",
[
"test eip",
{"Ref": "EC2EIP"}
]
]
}
}
}
}

View file

@ -0,0 +1,12 @@
from __future__ import unicode_literals
template = {
"Resources": {
"VPCEIP": {
"Type": "AWS::EC2::EIP",
"Properties": {
"Domain": "vpc"
}
}
}
}

View file

@ -12,7 +12,13 @@ from moto import (
mock_iam,
)
from .fixtures import single_instance_with_ebs_volume, vpc_single_instance_in_subnet
from .fixtures import (
single_instance_with_ebs_volume,
vpc_single_instance_in_subnet,
ec2_classic_eip,
vpc_eip,
fn_join
)
@mock_cloudformation()
@ -75,7 +81,7 @@ def test_stack_ec2_integration():
stack = conn.describe_stacks()[0]
instance = stack.describe_resources()[0]
instance.resource_type.should.equal('AWS::EC2::Instance')
instance.logical_resource_id.should.equal("WebServerGroup")
instance.logical_resource_id.should.contain("WebServerGroup")
instance.physical_resource_id.should.equal(ec2_instance.id)
@ -186,7 +192,7 @@ def test_stack_security_groups():
ec2_conn = boto.connect_ec2()
security_groups = ec2_conn.get_all_security_groups()
for group in security_groups:
if group.name == "InstanceSecurityGroup":
if "InstanceSecurityGroup" in group.name:
instance_group = group
else:
other_group = group
@ -245,6 +251,7 @@ def test_autoscaling_group_with_elb():
"InstancePort": "80",
"Protocol": "HTTP"
}],
"LoadBalancerName": "my-elb",
"HealthCheck": {
"Target": "80",
"HealthyThreshold": "3",
@ -267,7 +274,7 @@ def test_autoscaling_group_with_elb():
autoscale_conn = boto.connect_autoscale()
autoscale_group = autoscale_conn.get_all_groups()[0]
autoscale_group.launch_config_name.should.equal("my-launch-config")
autoscale_group.launch_config_name.should.contain("my-launch-config")
autoscale_group.load_balancers[0].should.equal('my-elb')
# Confirm the Launch config was actually created
@ -280,13 +287,13 @@ def test_autoscaling_group_with_elb():
stack = conn.describe_stacks()[0]
resources = stack.describe_resources()
as_group_resource = [resource for resource in resources if resource.resource_type == 'AWS::AutoScaling::AutoScalingGroup'][0]
as_group_resource.physical_resource_id.should.equal("my-as-group")
as_group_resource.physical_resource_id.should.contain("my-as-group")
launch_config_resource = [resource for resource in resources if resource.resource_type == 'AWS::AutoScaling::LaunchConfiguration'][0]
launch_config_resource.physical_resource_id.should.equal("my-launch-config")
launch_config_resource.physical_resource_id.should.contain("my-launch-config")
elb_resource = [resource for resource in resources if resource.resource_type == 'AWS::ElasticLoadBalancing::LoadBalancer'][0]
elb_resource.physical_resource_id.should.equal("my-elb")
elb_resource.physical_resource_id.should.contain("my-elb")
@mock_ec2()
@ -427,18 +434,21 @@ def test_iam_roles():
iam_conn = boto.connect_iam()
role = iam_conn.get_role("my-role")
role.role_name.should.equal("my-role")
role_result = iam_conn.list_roles()['list_roles_response']['list_roles_result']['roles'][0]
role = iam_conn.get_role(role_result.role_name)
role.role_name.should.contain("my-role")
role.path.should.equal("my-path")
instance_profile = iam_conn.get_instance_profile("my-instance-profile")
instance_profile.instance_profile_name.should.equal("my-instance-profile")
instance_profile_response = iam_conn.list_instance_profiles()['list_instance_profiles_response']
cfn_instance_profile = instance_profile_response['list_instance_profiles_result']['instance_profiles'][0]
instance_profile = iam_conn.get_instance_profile(cfn_instance_profile.instance_profile_name)
instance_profile.instance_profile_name.should.contain("my-instance-profile")
instance_profile.path.should.equal("my-path")
instance_profile.role_id.should.equal(role.role_id)
autoscale_conn = boto.connect_autoscale()
launch_config = autoscale_conn.get_all_launch_configurations()[0]
launch_config.instance_profile_name.should.equal("my-instance-profile")
launch_config.instance_profile_name.should.contain("my-instance-profile")
stack = conn.describe_stacks()[0]
resources = stack.describe_resources()
@ -472,3 +482,59 @@ def test_single_instance_with_ebs_volume():
resources = stack.describe_resources()
ebs_volume = [resource for resource in resources if resource.resource_type == 'AWS::EC2::Volume'][0]
ebs_volume.physical_resource_id.should.equal(volume.id)
@mock_ec2()
@mock_cloudformation()
def test_classic_eip():
template_json = json.dumps(ec2_classic_eip.template)
conn = boto.connect_cloudformation()
conn.create_stack(
"test_stack",
template_body=template_json,
)
ec2_conn = boto.connect_ec2()
eip = ec2_conn.get_all_addresses()[0]
stack = conn.describe_stacks()[0]
resources = stack.describe_resources()
cfn_eip = [resource for resource in resources if resource.resource_type == 'AWS::EC2::EIP'][0]
cfn_eip.physical_resource_id.should.equal(eip.public_ip)
@mock_ec2()
@mock_cloudformation()
def test_vpc_eip():
template_json = json.dumps(vpc_eip.template)
conn = boto.connect_cloudformation()
conn.create_stack(
"test_stack",
template_body=template_json,
)
ec2_conn = boto.connect_ec2()
eip = ec2_conn.get_all_addresses()[0]
stack = conn.describe_stacks()[0]
resources = stack.describe_resources()
cfn_eip = [resource for resource in resources if resource.resource_type == 'AWS::EC2::EIP'][0]
cfn_eip.physical_resource_id.should.equal(eip.allocation_id)
@mock_ec2()
@mock_cloudformation()
def test_fn_join():
template_json = json.dumps(fn_join.template)
conn = boto.connect_cloudformation()
conn.create_stack(
"test_stack",
template_body=template_json,
)
ec2_conn = boto.connect_ec2()
eip = ec2_conn.get_all_addresses()[0]
stack = conn.describe_stacks()[0]
fn_join_output = stack.outputs[0]
fn_join_output.value.should.equal('test eip:{0}'.format(eip.public_ip))

View file

@ -7,6 +7,8 @@ import sure # noqa
from moto.cloudformation.models import FakeStack
from moto.cloudformation.parsing import resource_class_from_type
from moto.sqs.models import Queue
from boto.cloudformation.stack import Output
from boto.exception import BotoServerError
dummy_template = {
"AWSTemplateFormatVersion": "2010-09-09",
@ -14,8 +16,7 @@ dummy_template = {
"Description": "Create a multi-az, load balanced, Auto Scaled sample web site. The Auto Scaling trigger is based on the CPU utilization of the web servers. The AMI is chosen based on the region in which the stack is run. This example creates a web service running across all availability zones in a region. The instances are load balanced with a simple health check. The web site is available on port 80, however, the instances can be configured to listen on any port (8888 by default). **WARNING** This template creates one or more Amazon EC2 instances. You will be billed for the AWS resources used if you create a stack from this template.",
"Resources": {
"WebServerGroup": {
"Queue": {
"Type": "AWS::SQS::Queue",
"Properties": {
"QueueName": "my-queue",
@ -25,7 +26,55 @@ dummy_template = {
},
}
name_type_template = {
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Create a multi-az, load balanced, Auto Scaled sample web site. The Auto Scaling trigger is based on the CPU utilization of the web servers. The AMI is chosen based on the region in which the stack is run. This example creates a web service running across all availability zones in a region. The instances are load balanced with a simple health check. The web site is available on port 80, however, the instances can be configured to listen on any port (8888 by default). **WARNING** This template creates one or more Amazon EC2 instances. You will be billed for the AWS resources used if you create a stack from this template.",
"Resources": {
"Queue": {
"Type": "AWS::SQS::Queue",
"Properties": {
"VisibilityTimeout": 60,
}
},
},
}
output_dict = {
"Outputs": {
"Output1": {
"Value": {"Ref": "Queue"},
"Description": "This is a description."
}
}
}
bad_output = {
"Outputs": {
"Output1": {
"Value": {"Fn::GetAtt": ["Queue", "InvalidAttribute"]}
}
}
}
get_attribute_output = {
"Outputs": {
"Output1": {
"Value": {"Fn::GetAtt": ["Queue", "QueueName"]}
}
}
}
outputs_template = dict(list(dummy_template.items()) + list(output_dict.items()))
bad_outputs_template = dict(list(dummy_template.items()) + list(bad_output.items()))
get_attribute_outputs_template = dict(list(dummy_template.items()) + list(get_attribute_output.items()))
dummy_template_json = json.dumps(dummy_template)
name_type_template_json = json.dumps(name_type_template)
output_type_template_json = json.dumps(outputs_template)
bad_output_template_json = json.dumps(bad_outputs_template)
get_attribute_outputs_template_json = json.dumps(get_attribute_outputs_template)
def test_parse_stack_resources():
@ -36,7 +85,7 @@ def test_parse_stack_resources():
)
stack.resource_map.should.have.length_of(1)
list(stack.resource_map.keys())[0].should.equal('WebServerGroup')
list(stack.resource_map.keys())[0].should.equal('Queue')
queue = list(stack.resource_map.values())[0]
queue.should.be.a(Queue)
queue.name.should.equal("my-queue")
@ -46,3 +95,46 @@ def test_parse_stack_resources():
def test_missing_resource_logs(logger):
resource_class_from_type("foobar")
logger.warning.assert_called_with('No Moto CloudFormation support for %s', 'foobar')
def test_parse_stack_with_name_type_resource():
stack = FakeStack(
stack_id="test_id",
name="test_stack",
template=name_type_template_json)
stack.resource_map.should.have.length_of(1)
list(stack.resource_map.keys())[0].should.equal('Queue')
queue = list(stack.resource_map.values())[0]
queue.should.be.a(Queue)
def test_parse_stack_with_outputs():
stack = FakeStack(
stack_id="test_id",
name="test_stack",
template=output_type_template_json)
stack.output_map.should.have.length_of(1)
list(stack.output_map.keys())[0].should.equal('Output1')
output = list(stack.output_map.values())[0]
output.should.be.a(Output)
output.description.should.equal("This is a description.")
def test_parse_stack_with_get_attribute_outputs():
stack = FakeStack(
stack_id="test_id",
name="test_stack",
template=get_attribute_outputs_template_json)
stack.output_map.should.have.length_of(1)
list(stack.output_map.keys())[0].should.equal('Output1')
output = list(stack.output_map.values())[0]
output.should.be.a(Output)
output.value.should.equal("my-queue")
def test_parse_stack_with_bad_get_attribute_outputs():
FakeStack.when.called_with(
"test_id", "test_stack", bad_output_template_json).should.throw(BotoServerError)