moto/tests/test_ec2/test_ec2_cloudformation.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

958 lines
34 KiB
Python
Raw Normal View History

import json
2021-10-05 17:11:07 +00:00
from uuid import uuid4
import boto3
import pytest
from botocore.exceptions import ClientError
2024-01-07 12:03:33 +00:00
from moto import mock_aws
from tests import EXAMPLE_AMI_ID
from tests.test_cloudformation.fixtures import (
ec2_classic_eip,
single_instance_with_ebs_volume,
vpc_eip,
vpc_eni,
vpc_single_instance_in_subnet,
)
template_vpc = {
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Create VPC",
"Resources": {
"VPC": {"Properties": {"CidrBlock": "192.168.0.0/16"}, "Type": "AWS::EC2::VPC"}
},
}
template_subnet = {
"AWSTemplateFormatVersion": "2010-09-09",
"Description": "Create VPC",
"Resources": {
"VPC": {"Properties": {"CidrBlock": "192.168.0.0/16"}, "Type": "AWS::EC2::VPC"},
"Subnet": {
"Properties": {"VpcId": {"Ref": "VPC"}, "CidrBlock": "192.168.0.0/18"},
"Type": "AWS::EC2::Subnet",
},
},
}
2024-01-07 12:03:33 +00:00
@mock_aws
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")
2021-10-05 17:11:07 +00:00
stack_name = str(uuid4())[0:6]
cf.create_stack(
2021-10-05 17:11:07 +00:00
StackName=stack_name,
TemplateBody=template_json,
Parameters=[{"ParameterKey": "KeyName", "ParameterValue": "my_key"}],
)
ec2 = boto3.client("ec2", region_name="us-west-1")
2021-10-05 17:11:07 +00:00
stack = cf.describe_stacks(StackName=stack_name)["Stacks"][0]
2021-10-05 17:11:07 +00:00
resources = cf.list_stack_resources(StackName=stack_name)["StackResourceSummaries"]
vpc_id = [
resource
for resource in resources
if resource["ResourceType"] == "AWS::EC2::VPC"
][0]["PhysicalResourceId"]
2021-10-05 17:11:07 +00:00
vpc = ec2.describe_vpcs(VpcIds=[vpc_id])["Vpcs"][0]
assert vpc["CidrBlock"] == "10.0.0.0/16"
assert {"Key": "Application", "Value": stack["StackId"]} in vpc["Tags"]
security_group = ec2.describe_security_groups(
Filters=[{"Name": "vpc-id", "Values": [vpc["VpcId"]]}]
)["SecurityGroups"][0]
assert security_group["VpcId"] == vpc["VpcId"]
2021-10-05 17:11:07 +00:00
subnet_id = [
resource
for resource in resources
2021-10-05 17:11:07 +00:00
if resource["ResourceType"] == "AWS::EC2::Subnet"
][0]["PhysicalResourceId"]
subnet = ec2.describe_subnets(SubnetIds=[subnet_id])["Subnets"][0]
assert subnet["VpcId"] == vpc["VpcId"]
2021-10-05 17:11:07 +00:00
instance_id = [
resource
for resource in resources
2021-10-05 17:11:07 +00:00
if resource["ResourceType"] == "AWS::EC2::Instance"
][0]["PhysicalResourceId"]
res = ec2.describe_instances(InstanceIds=[instance_id])["Reservations"][0]
instance = res["Instances"][0]
assert {"Key": "Foo", "Value": "Bar"} in instance["Tags"]
2021-10-05 17:11:07 +00:00
eip_id = [
resource
for resource in resources
if resource["ResourceType"] == "AWS::EC2::EIP"
2021-10-05 17:11:07 +00:00
][0]["PhysicalResourceId"]
eip = ec2.describe_addresses(PublicIps=[eip_id])["Addresses"][0]
assert eip["Domain"] == "vpc"
assert eip["InstanceId"] == instance["InstanceId"]
2024-01-07 12:03:33 +00:00
@mock_aws
def test_delete_stack_with_vpc():
cf = boto3.client("cloudformation", region_name="us-east-1")
ec2 = boto3.client("ec2", region_name="us-east-1")
2021-10-05 17:11:07 +00:00
name = str(uuid4())[0:6]
cf.create_stack(StackName=name, TemplateBody=json.dumps(template_vpc))
2021-10-05 17:11:07 +00:00
resources = cf.list_stack_resources(StackName=name)["StackResourceSummaries"]
vpc_id = resources[0]["PhysicalResourceId"]
assert len(ec2.describe_vpcs(VpcIds=[vpc_id])["Vpcs"]) == 1
cf.delete_stack(StackName=name)
with pytest.raises(ec2.exceptions.ClientError):
ec2.describe_vpcs(VpcIds=[vpc_id])
2024-01-07 12:03:33 +00:00
@mock_aws
def test_delete_stack_with_subnet():
cf = boto3.client("cloudformation", region_name="us-east-1")
ec2 = boto3.client("ec2", region_name="us-east-1")
name = str(uuid4())[0:6]
cf.create_stack(StackName=name, TemplateBody=json.dumps(template_subnet))
subnet_ids = [
resource["PhysicalResourceId"]
for resource in cf.list_stack_resources(StackName=name)[
"StackResourceSummaries"
]
if resource["ResourceType"] == "AWS::EC2::Subnet"
]
assert len(ec2.describe_subnets(SubnetIds=subnet_ids)["Subnets"]) == 1
cf.delete_stack(StackName=name)
with pytest.raises(ec2.exceptions.ClientError):
ec2.describe_subnets(SubnetIds=subnet_ids)
2024-01-07 12:03:33 +00:00
@mock_aws
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")
2021-10-05 17:11:07 +00:00
stack_name = str(uuid4())[0:6]
cf.create_stack(StackName=stack_name, TemplateBody=template_json)
ec2 = boto3.client("ec2", region_name="us-west-1")
2021-10-05 17:11:07 +00:00
all_enis = ec2.describe_network_interfaces()["NetworkInterfaces"]
all_eni_ids = [eni["NetworkInterfaceId"] for eni in all_enis]
all_ips = [eni["PrivateIpAddresses"][0]["PrivateIpAddress"] for eni in all_enis]
2021-10-05 17:11:07 +00:00
resources = cf.list_stack_resources(StackName=stack_name)["StackResourceSummaries"]
cfn_eni = [
resource
for resource in resources
if resource["ResourceType"] == "AWS::EC2::NetworkInterface"
][0]
assert cfn_eni["PhysicalResourceId"] in all_eni_ids
2021-10-05 17:11:07 +00:00
outputs = cf.describe_stacks(StackName=stack_name)["Stacks"][0]["Outputs"]
received_ip = [
o["OutputValue"] for o in outputs if o["OutputKey"] == "ENIIpAddress"
][0]
assert received_ip in all_ips
2024-01-07 12:03:33 +00:00
@mock_aws
def test_volume_size_through_cloudformation():
ec2 = boto3.client("ec2", region_name="us-east-1")
cf = boto3.client("cloudformation", region_name="us-east-1")
2021-10-05 17:11:07 +00:00
tag_value = str(uuid4())
volume_template = {
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"testInstance": {
"Type": "AWS::EC2::Instance",
"Properties": {
"ImageId": EXAMPLE_AMI_ID,
"KeyName": "dummy",
"InstanceType": "t2.micro",
"BlockDeviceMappings": [
{"DeviceName": "/dev/sda2", "Ebs": {"VolumeSize": "50"}}
],
"Tags": [
{"Key": "foo", "Value": "bar"},
2021-10-05 17:11:07 +00:00
{"Key": "blah", "Value": tag_value},
],
},
}
},
}
template_json = json.dumps(volume_template)
2021-10-05 17:11:07 +00:00
stack_name = str(uuid4())[0:6]
cf.create_stack(StackName=stack_name, TemplateBody=template_json)
resource = cf.list_stack_resources(StackName=stack_name)["StackResourceSummaries"][
0
]
assert resource["LogicalResourceId"] == "testInstance"
assert resource["PhysicalResourceId"] is not None
assert resource["ResourceType"] == "AWS::EC2::Instance"
instances = ec2.describe_instances(InstanceIds=[resource["PhysicalResourceId"]])
2021-10-05 17:11:07 +00:00
volume = instances["Reservations"][0]["Instances"][0]["BlockDeviceMappings"][0][
"Ebs"
]
volumes = ec2.describe_volumes(VolumeIds=[volume["VolumeId"]])
assert volumes["Volumes"][0]["Size"] == 50
2024-01-07 12:03:33 +00:00
@mock_aws
def test_attach_internet_gateway():
ec2 = boto3.client("ec2", region_name="us-east-1")
cf = boto3.client("cloudformation", region_name="us-east-1")
volume_template = {
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"DEVLAB1": {
"Type": "AWS::EC2::VPC",
"Properties": {"CidrBlock": "10.0.0.0/16"},
},
"internetgateway": {"Type": "AWS::EC2::InternetGateway"},
"DEVLAB1VPGAttaching": {
"Type": "AWS::EC2::VPCGatewayAttachment",
"Properties": {
"VpcId": {"Ref": "DEVLAB1"},
"InternetGatewayId": {"Ref": "internetgateway"},
},
},
},
}
template_json = json.dumps(volume_template)
stack_name = str(uuid4())[0:6]
cf.create_stack(StackName=stack_name, TemplateBody=template_json)
stack_resources = cf.list_stack_resources(StackName=stack_name)[
"StackResourceSummaries"
]
# Verify VPC is created
vpc = [r for r in stack_resources if r["ResourceType"] == "AWS::EC2::VPC"][0]
assert vpc["LogicalResourceId"] == "DEVLAB1"
vpc_id = vpc["PhysicalResourceId"]
# Verify Internet Gateway is created
gateway_id = get_resource_id("AWS::EC2::InternetGateway", stack_resources)
gateway = ec2.describe_internet_gateways(InternetGatewayIds=[gateway_id])[
"InternetGateways"
][0]
assert {"State": "available", "VpcId": vpc_id} in gateway["Attachments"]
assert {
"Key": "aws:cloudformation:logical-id",
"Value": "internetgateway",
} in gateway["Tags"]
2024-01-07 12:03:33 +00:00
@mock_aws
def test_attach_vpn_gateway():
ec2 = boto3.client("ec2", region_name="us-east-1")
cf = boto3.client("cloudformation", region_name="us-east-1")
vpn_gateway_template = {
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"DEVLAB1": {
"Type": "AWS::EC2::VPC",
"Properties": {"CidrBlock": "10.0.0.0/16"},
},
"DEVLAB1DCGateway": {
"Type": "AWS::EC2::VPNGateway",
"Properties": {"Type": "ipsec.1"},
},
"DEVLAB1VPGAttaching": {
"Type": "AWS::EC2::VPCGatewayAttachment",
"Properties": {
"VpcId": {"Ref": "DEVLAB1"},
"VpnGatewayId": {"Ref": "DEVLAB1DCGateway"},
},
"DependsOn": ["DEVLAB1DCGateway"],
},
},
}
template_json = json.dumps(vpn_gateway_template)
stack_name = str(uuid4())[0:6]
cf.create_stack(StackName=stack_name, TemplateBody=template_json)
stack_resources = cf.list_stack_resources(StackName=stack_name)[
"StackResourceSummaries"
]
gateway_id = get_resource_id("AWS::EC2::VPNGateway", stack_resources)
vpc_id = get_resource_id("AWS::EC2::VPC", stack_resources)
gateway = ec2.describe_vpn_gateways(VpnGatewayIds=[gateway_id])["VpnGateways"][0]
assert {"State": "attached", "VpcId": vpc_id} in gateway["VpcAttachments"]
def get_resource_id(resource_type, stack_resources):
r = [r for r in stack_resources if r["ResourceType"] == resource_type][0]
return r["PhysicalResourceId"]
2024-01-07 12:03:33 +00:00
@mock_aws
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")
2021-10-05 17:11:07 +00:00
stack_name = str(uuid4())[0:6]
cf.create_stack(StackName=stack_name, TemplateBody=template_json)
resources = cf.list_stack_resources(StackName=stack_name)["StackResourceSummaries"]
subnet_id = resources[0]["PhysicalResourceId"]
2021-10-05 17:11:07 +00:00
subnet = ec2.describe_subnets(SubnetIds=[subnet_id])["Subnets"][0]
assert subnet["CidrBlock"] == "10.0.0.0/24"
assert {"Key": "foo", "Value": "bar"} in subnet["Tags"]
assert {"Key": "blah", "Value": "baz"} in subnet["Tags"]
2024-01-07 12:03:33 +00:00
@mock_aws
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")
2021-10-05 17:11:07 +00:00
stack_name = str(uuid4())[0:6]
cf.create_stack(
2021-10-05 17:11:07 +00:00
StackName=stack_name,
TemplateBody=template_json,
Parameters=[{"ParameterKey": "KeyName", "ParameterValue": "key_name"}],
)
2021-10-05 17:11:07 +00:00
resources = cf.list_stack_resources(StackName=stack_name)["StackResourceSummaries"]
instance_id = [
r["PhysicalResourceId"]
for r in resources
if r["ResourceType"] == "AWS::EC2::Instance"
][0]
volume_id = [
r["PhysicalResourceId"]
for r in resources
if r["ResourceType"] == "AWS::EC2::Volume"
][0]
ec2 = boto3.client("ec2", region_name="us-west-1")
2021-10-05 17:11:07 +00:00
ec2_instance = ec2.describe_instances(InstanceIds=[instance_id])["Reservations"][0][
"Instances"
][0]
2021-10-05 17:11:07 +00:00
volumes = ec2.describe_volumes(VolumeIds=[volume_id])["Volumes"]
# Grab the mounted drive
volume = [
volume for volume in volumes if volume["Attachments"][0]["Device"] == "/dev/sdh"
][0]
assert volume["State"] == "in-use"
assert volume["Attachments"][0]["InstanceId"] == ec2_instance["InstanceId"]
2024-01-07 12:03:33 +00:00
@mock_aws
def test_classic_eip():
template_json = json.dumps(ec2_classic_eip.template)
cf = boto3.client("cloudformation", region_name="us-west-1")
2021-10-05 17:11:07 +00:00
stack_name = str(uuid4())[0:6]
cf.create_stack(StackName=stack_name, TemplateBody=template_json)
ec2 = boto3.client("ec2", region_name="us-west-1")
2021-10-05 17:11:07 +00:00
all_ips = [eip["PublicIp"] for eip in ec2.describe_addresses()["Addresses"]]
2021-10-05 17:11:07 +00:00
resources = cf.list_stack_resources(StackName=stack_name)["StackResourceSummaries"]
cfn_eip = [
resource
for resource in resources
if resource["ResourceType"] == "AWS::EC2::EIP"
][0]
assert cfn_eip["PhysicalResourceId"] in all_ips
2024-01-07 12:03:33 +00:00
@mock_aws
def test_vpc_eip():
template_json = json.dumps(vpc_eip.template)
cf = boto3.client("cloudformation", region_name="us-west-1")
2021-10-05 17:11:07 +00:00
stack_name = str(uuid4())[0:6]
cf.create_stack(StackName=stack_name, TemplateBody=template_json)
ec2 = boto3.client("ec2", region_name="us-west-1")
2021-10-05 17:11:07 +00:00
all_ips = [eip["PublicIp"] for eip in ec2.describe_addresses()["Addresses"]]
2021-10-05 17:11:07 +00:00
resources = cf.list_stack_resources(StackName=stack_name)["StackResourceSummaries"]
cfn_eip = [
resource
for resource in resources
if resource["ResourceType"] == "AWS::EC2::EIP"
][0]
assert cfn_eip["PhysicalResourceId"] in all_ips
2024-01-07 12:03:33 +00:00
@mock_aws
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")
2021-10-05 17:11:07 +00:00
stack_name = str(uuid4())[0:6]
cf.create_stack(StackName=stack_name, TemplateBody=template_json)
resources = cf.list_stack_resources(StackName=stack_name)["StackResourceSummaries"]
vpc_id = resources[1]["PhysicalResourceId"]
ec2 = boto3.client("ec2", region_name="us-west-1")
2021-10-05 17:11:07 +00:00
vpc = ec2.describe_vpcs(VpcIds=[vpc_id])["Vpcs"][0]
assert vpc["CidrBlock"] == "10.0.0.0/16"
igws = ec2.describe_internet_gateways(
Filters=[{"Name": "attachment.vpc-id", "Values": [vpc["VpcId"]]}]
)["InternetGateways"]
assert len(igws) == 1
2024-01-07 12:03:33 +00:00
@mock_aws
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")
2021-10-05 17:11:07 +00:00
stack_name = str(uuid4())[0:6]
cf.create_stack(StackName=stack_name, TemplateBody=template_json)
resources = cf.list_stack_resources(StackName=stack_name)["StackResourceSummaries"]
our_vpx_id = resources[0]["PhysicalResourceId"]
peering_connections = ec2_client.describe_vpc_peering_connections(
VpcPeeringConnectionIds=[our_vpx_id]
)["VpcPeeringConnections"]
assert len(peering_connections) == 1
2024-01-07 12:03:33 +00:00
@mock_aws
def test_multiple_security_group_ingress_separate_from_security_group_by_id():
2021-10-05 17:11:07 +00:00
sg1 = str(uuid4())[0:6]
sg2 = str(uuid4())[0:6]
template = {
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"test-security-group1": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "test security group",
2021-10-05 17:11:07 +00:00
"Tags": [{"Key": "sg-name", "Value": sg1}],
},
},
"test-security-group2": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "test security group",
2021-10-05 17:11:07 +00:00
"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")
2021-10-05 17:11:07 +00:00
cf.create_stack(StackName=str(uuid4())[0:6], TemplateBody=template_json)
ec2 = boto3.client("ec2", region_name="us-west-1")
2021-10-05 17:11:07 +00:00
security_group1 = get_secgroup_by_tag(ec2, sg1)
security_group2 = get_secgroup_by_tag(ec2, sg2)
assert len(security_group1["IpPermissions"]) == 1
assert len(security_group1["IpPermissions"][0]["UserIdGroupPairs"]) == 1
assert (
security_group1["IpPermissions"][0]["UserIdGroupPairs"][0]["GroupId"]
== security_group2["GroupId"]
)
assert security_group1["IpPermissions"][0]["IpProtocol"] == "tcp"
assert security_group1["IpPermissions"][0]["FromPort"] == 80
assert security_group1["IpPermissions"][0]["ToPort"] == 8080
2024-01-07 12:03:33 +00:00
@mock_aws
def test_security_group_ingress_separate_from_security_group_by_id():
ec2 = boto3.client("ec2", region_name="us-west-1")
2021-10-05 17:11:07 +00:00
sg_name = str(uuid4())
ec2.create_security_group(GroupName=sg_name, Description="test security group")
2021-10-05 17:11:07 +00:00
sg_2 = str(uuid4())[0:6]
template = {
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"test-security-group2": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "test security group",
2021-10-05 17:11:07 +00:00
"Tags": [{"Key": "sg-name", "Value": sg_2}],
},
},
"test-sg-ingress": {
"Type": "AWS::EC2::SecurityGroupIngress",
"Properties": {
2021-10-05 17:11:07 +00:00
"GroupName": sg_name,
"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")
2021-10-05 17:11:07 +00:00
cf.create_stack(StackName=str(uuid4())[0:6], TemplateBody=template_json)
security_group1 = ec2.describe_security_groups(GroupNames=[sg_name])[
"SecurityGroups"
][0]
2021-10-05 17:11:07 +00:00
security_group2 = get_secgroup_by_tag(ec2, sg_2)
assert len(security_group1["IpPermissions"]) == 1
assert len(security_group1["IpPermissions"][0]["UserIdGroupPairs"]) == 1
assert (
security_group1["IpPermissions"][0]["UserIdGroupPairs"][0]["GroupId"]
== security_group2["GroupId"]
)
assert security_group1["IpPermissions"][0]["IpProtocol"] == "tcp"
assert security_group1["IpPermissions"][0]["FromPort"] == 80
assert security_group1["IpPermissions"][0]["ToPort"] == 8080
2024-01-07 12:03:33 +00:00
@mock_aws
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")
2021-10-05 17:11:07 +00:00
cf.create_stack(StackName=str(uuid4())[0:6], TemplateBody=template_json)
security_group1 = get_secgroup_by_tag(ec2_client, "sg1")
security_group2 = get_secgroup_by_tag(ec2_client, "sg2")
assert len(security_group1["IpPermissions"]) == 1
assert len(security_group1["IpPermissions"][0]["UserIdGroupPairs"]) == 1
assert (
security_group1["IpPermissions"][0]["UserIdGroupPairs"][0]["GroupId"]
== security_group2["GroupId"]
)
assert security_group1["IpPermissions"][0]["IpProtocol"] == "tcp"
assert security_group1["IpPermissions"][0]["FromPort"] == 80
assert security_group1["IpPermissions"][0]["ToPort"] == 8080
2024-01-07 12:03:33 +00:00
@mock_aws
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")
2021-10-05 17:11:07 +00:00
sg = str(uuid4())[0:6]
template = {
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
"test-security-group": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupDescription": "test security group",
"VpcId": vpc1.id,
2021-10-05 17:11:07 +00:00
"Tags": [{"Key": "sg-name", "Value": sg}],
},
}
},
}
template_json = json.dumps(template)
cf = boto3.client("cloudformation", region_name="us-west-1")
2021-10-05 17:11:07 +00:00
stack_name = str(uuid4())[0:6]
cf.create_stack(StackName=stack_name, TemplateBody=template_json)
security_group = get_secgroup_by_tag(ec2_client, sg)
assert security_group["VpcId"] == vpc1.id
template["Resources"]["test-security-group"]["Properties"]["VpcId"] = vpc2.id
template_json = json.dumps(template)
2021-10-05 17:11:07 +00:00
cf.update_stack(StackName=stack_name, TemplateBody=template_json)
security_group = get_secgroup_by_tag(ec2_client, sg)
assert security_group["VpcId"] == vpc2.id
2024-01-07 12:03:33 +00:00
@mock_aws
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)
2021-10-05 17:11:07 +00:00
stack_name = str(uuid4())[0:6]
cf.create_stack(StackName=stack_name, TemplateBody=template_json)
resources = cf.list_stack_resources(StackName=stack_name)["StackResourceSummaries"]
subnet_id = resources[0]["PhysicalResourceId"]
subnet = ec2_client.describe_subnets(SubnetIds=[subnet_id])["Subnets"][0]
assert subnet["CidrBlock"] == "10.0.0.0/24"
assert subnet["AvailabilityZone"] == "us-west-1b"
def get_secgroup_by_tag(ec2, sg_):
return ec2.describe_security_groups(
Filters=[{"Name": "tag:sg-name", "Values": [sg_]}]
)["SecurityGroups"][0]
2022-03-03 22:43:25 +00:00
2024-01-07 12:03:33 +00:00
@mock_aws
2022-03-03 22:43:25 +00:00
def test_vpc_endpoint_creation():
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")
subnet1 = ec2.create_subnet(
VpcId=vpc.id, CidrBlock="10.0.0.0/24", AvailabilityZone="us-west-1a"
2022-03-03 22:43:25 +00:00
)
subnet_template = {
"AWSTemplateFormatVersion": "2010-09-09",
"Parameters": {
"EndpointSubnetId": {"Type": "String"},
"EndpointVpcId": {"Type": "String"},
"EndpointServiceName": {"Type": "String"},
},
"Resources": {
"GwlbVpcEndpoint": {
"Type": "AWS::EC2::VPCEndpoint",
"Properties": {
"ServiceName": {"Ref": "EndpointServiceName"},
"SubnetIds": [{"Ref": "EndpointSubnetId"}],
"VpcEndpointType": "GatewayLoadBalancer",
"VpcId": {"Ref": "EndpointVpcId"},
},
}
},
"Outputs": {
"EndpointId": {
"Description": "Id of the endpoint created",
"Value": {"Ref": "GwlbVpcEndpoint"},
},
},
}
cf = boto3.client("cloudformation", region_name="us-west-1")
template_json = json.dumps(subnet_template)
stack_name = str(uuid4())[0:6]
cf.create_stack(
StackName=stack_name,
TemplateBody=template_json,
Parameters=[
{"ParameterKey": "EndpointSubnetId", "ParameterValue": subnet1.id},
{"ParameterKey": "EndpointVpcId", "ParameterValue": vpc.id},
{"ParameterKey": "EndpointServiceName", "ParameterValue": "serv_name"},
],
)
resources = cf.list_stack_resources(StackName=stack_name)["StackResourceSummaries"]
assert len(resources) == 1
assert resources[0]["LogicalResourceId"] == "GwlbVpcEndpoint"
2022-03-03 22:43:25 +00:00
vpc_endpoint_id = resources[0]["PhysicalResourceId"]
outputs = cf.describe_stacks(StackName=stack_name)["Stacks"][0]["Outputs"]
assert len(outputs) == 1
assert outputs[0] == {
"OutputKey": "EndpointId",
"OutputValue": vpc_endpoint_id,
"Description": "Id of the endpoint created",
}
2022-03-03 22:43:25 +00:00
endpoint = ec2_client.describe_vpc_endpoints(VpcEndpointIds=[vpc_endpoint_id])[
"VpcEndpoints"
][0]
assert endpoint["VpcId"] == vpc.id
assert endpoint["ServiceName"] == "serv_name"
assert endpoint["State"] == "available"
assert endpoint["SubnetIds"] == [subnet1.id]
assert endpoint["VpcEndpointType"] == "GatewayLoadBalancer"
2024-01-07 12:03:33 +00:00
@mock_aws
def test_launch_template_create():
cf = boto3.client("cloudformation", region_name="us-west-1")
ec2 = boto3.client("ec2", region_name="us-west-1")
launch_template_name = str(uuid4())[0:6]
logical_id = str(uuid4())[0:6]
stack_name = str(uuid4())[0:6]
lt_tags = [{"Key": "lt-tag-key", "Value": "lt-tag-value"}]
template_json = json.dumps(
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
logical_id: {
"Type": "AWS::EC2::LaunchTemplate",
"Properties": {
"LaunchTemplateName": launch_template_name,
"VersionDescription": "some template",
"LaunchTemplateData": {
"TagSpecifications": [
{
"ResourceType": "instance",
"Tags": [
{"Key": "i-tag-key", "Value": "i-tag-value"}
],
}
]
},
"TagSpecifications": [
{
"ResourceType": "launch-template",
"Tags": lt_tags,
}
],
},
}
},
"Outputs": {
"LaunchTemplateId": {
"Description": "The ID of the created launch template",
"Value": {"Ref": logical_id},
},
},
}
)
cf.create_stack(StackName=stack_name, TemplateBody=template_json)
resources = cf.list_stack_resources(StackName=stack_name)["StackResourceSummaries"]
assert len(resources) == 1
assert resources[0]["LogicalResourceId"] == logical_id
launch_template_id = resources[0]["PhysicalResourceId"]
outputs = cf.describe_stacks(StackName=stack_name)["Stacks"][0]["Outputs"]
assert len(outputs) == 1
assert outputs[0] == {
"OutputKey": "LaunchTemplateId",
"OutputValue": launch_template_id,
"Description": "The ID of the created launch template",
}
launch_template = ec2.describe_launch_templates(
LaunchTemplateNames=[launch_template_name]
)["LaunchTemplates"][0]
assert launch_template["LaunchTemplateName"] == launch_template_name
assert launch_template["LaunchTemplateId"] == launch_template_id
assert launch_template["Tags"] == lt_tags
launch_template_version = ec2.describe_launch_template_versions(
LaunchTemplateName=launch_template_name
)["LaunchTemplateVersions"][0]
assert launch_template_version["LaunchTemplateName"] == launch_template_name
assert launch_template_version["LaunchTemplateId"] == launch_template_id
assert (
launch_template_version["LaunchTemplateData"]["TagSpecifications"][0][
"ResourceType"
]
== "instance"
)
2024-01-07 12:03:33 +00:00
@mock_aws
def test_launch_template_update():
cf = boto3.client("cloudformation", region_name="us-west-1")
ec2 = boto3.client("ec2", region_name="us-west-1")
launch_template_name = str(uuid4())[0:6]
logical_id = str(uuid4())[0:6]
stack_name = str(uuid4())[0:6]
template_json = json.dumps(
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
logical_id: {
"Type": "AWS::EC2::LaunchTemplate",
"Properties": {
"LaunchTemplateName": launch_template_name,
"VersionDescription": "some template",
"LaunchTemplateData": {"UserData": ""},
},
}
},
}
)
cf.create_stack(StackName=stack_name, TemplateBody=template_json)
template_json = json.dumps(
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
logical_id: {
"Type": "AWS::EC2::LaunchTemplate",
"Properties": {
"LaunchTemplateName": launch_template_name,
"VersionDescription": "a better template",
"LaunchTemplateData": {"UserData": ""},
},
}
},
}
)
cf.update_stack(StackName=stack_name, TemplateBody=template_json)
resources = cf.list_stack_resources(StackName=stack_name)["StackResourceSummaries"]
assert len(resources) == 1
launch_template_versions = ec2.describe_launch_template_versions(
LaunchTemplateName=launch_template_name
)["LaunchTemplateVersions"]
assert len(launch_template_versions) == 2
assert launch_template_versions[0]["VersionDescription"] == "some template"
assert launch_template_versions[1]["VersionDescription"] == "a better template"
2024-01-07 12:03:33 +00:00
@mock_aws
def test_launch_template_delete():
cf = boto3.client("cloudformation", region_name="us-west-1")
ec2 = boto3.client("ec2", region_name="us-west-1")
launch_template_name = str(uuid4())[0:6]
logical_id = str(uuid4())[0:6]
stack_name = str(uuid4())[0:6]
template_json = json.dumps(
{
"AWSTemplateFormatVersion": "2010-09-09",
"Resources": {
logical_id: {
"Type": "AWS::EC2::LaunchTemplate",
"Properties": {
"LaunchTemplateName": launch_template_name,
"VersionDescription": "some template",
"LaunchTemplateData": {"UserData": ""},
},
}
},
}
)
cf.create_stack(StackName=stack_name, TemplateBody=template_json)
cf.delete_stack(StackName=stack_name)
with pytest.raises(ClientError) as exc:
ec2.describe_launch_templates(LaunchTemplateNames=[launch_template_name])
err = exc.value.response["Error"]
assert err["Code"] == "InvalidLaunchTemplateName.NotFoundException"
assert (
err["Message"]
== "At least one of the launch templates specified in the request does not exist."
)