Source code for troposphere_mate.canned.vpc

# -*- coding: utf-8 -*-

try:
    from typing import List
except:
    pass

from troposphere_mate import Ref, Select, GetAtt, GetAZs, Join, Tags, Export

from .. import ec2
from ..core.canned import MultiEnvBasicConfig, Constant, Derivable, helper_fn_sub
from ..core.mate import Template, Parameter, Output


class AZPropertyValues:
    the_01_th = Select(0, GetAZs())
    the_02_th = Select(1, GetAZs())
    the_03_th = Select(2, GetAZs())
    the_04_th = Select(3, GetAZs())
    the_05_th = Select(4, GetAZs())
    the_06_th = Select(5, GetAZs())
    the_07_th = Select(6, GetAZs())
    the_08_th = Select(7, GetAZs())
    the_09_th = Select(8, GetAZs())
    the_10_th = Select(9, GetAZs())

    @classmethod
    def get_nth_az(cls, nth):
        return Select(nth - 1, GetAZs())


[docs]class VPCTier(MultiEnvBasicConfig): VPC_CIDR_ID = Constant() # an Integer between 0 - 255 N_PUBLIC_SUBNET = Constant() # an Integer between 1-3 N_PRIVATE_SUBNET = Constant() # an Integer between 1-3 USE_NAT_GW_PER_PRIVATE_SUBNET_FLAG = Constant() # bool, True or False SSH_ALLOWWED_IP_ADDRESSES = Constant(default="") # string, delimited by comma VPC_CIDR = Derivable() @VPC_CIDR.getter def get_VPC_CIDR(self): return "10.{}.0.0/16".format(self.VPC_CIDR_ID.get_value()) def get_nth_public_subnet_cidr(self, nth): return "10.{}.{}.0/24".format( self.VPC_CIDR_ID.get_value(), (nth - 1) * 2, ) def get_nth_private_subnet_cidr(self, nth): return "10.{}.{}.0/24".format( self.VPC_CIDR_ID.get_value(), (nth - 1) * 2 + 1, ) PUBLIC_SUBNET_CIDR_LIST = Derivable() @PUBLIC_SUBNET_CIDR_LIST.getter def get_PUBLIC_SUBNET_CIDR_LIST(self): return [ self.get_nth_public_subnet_cidr(nth) for nth in range(1, 1 + self.N_PUBLIC_SUBNET.get_value()) ] PRIVATE_SUBNET_CIDR_LIST = Derivable() @PRIVATE_SUBNET_CIDR_LIST.getter def get_PUBLIC_SUBNET_CIDR_LIST(self): return [ self.get_nth_private_subnet_cidr(nth) for nth in range(1, 1 + self.N_PUBLIC_SUBNET.get_value()) ] @USE_NAT_GW_PER_PRIVATE_SUBNET_FLAG.validator def check_use_nat_gw_per_private_subnet_flag(self, value): if value is True: if self.N_PUBLIC_SUBNET.get_value() < self.N_PRIVATE_SUBNET.get_value(): raise ValueError("If you want to use 1 independent Nat GW " "Per Private Subnet, then the number of " "public subnet has to be greater than " "private subnet.") NUMBER_OF_NAT_GW = Derivable() @NUMBER_OF_NAT_GW.getter def get_number_of_nat_gw(self): if self.USE_NAT_GW_PER_PRIVATE_SUBNET_FLAG.get_value(): return self.N_PUBLIC_SUBNET.get_value() else: return 1 vpc = None # type: ec2.VPC public_subnet_list = None # type: List[ec2.Subnet] private_subnet_list = None # type: List[ec2.Subnet] subnet_list = None # type: List[ec2.Subnet] igw = None # type: ec2.InternetGateway eip_list = None # type: List[ec2.EIP] ngw_list = None # type: List[ec2.NatGateway] public_route_table = None # type: ec2.RouteTable sg_for_ssh_from_anywhere = None # type: ec2.SecurityGroup def do_create_template(self): template = Template() self.template = template param_env_name = Parameter( "EnvironmentName", Type="String", Default=self.ENVIRONMENT_NAME.get_value(), ) param_stage = Parameter( "Stage", Type="String", Default=self.STAGE.get_value(), ) template.add_parameter(param_stage) template.add_parameter(param_env_name) output_list = list() vpc = ec2.VPC( "VPC", template=template, CidrBlock=self.VPC_CIDR.get_value(), EnableDnsHostnames=True, ) self.vpc = vpc public_subnet_list = list() for ind, cidr in enumerate(self.PUBLIC_SUBNET_CIDR_LIST.get_value()): subnet = ec2.Subnet( "PublicSubnet{}".format(ind + 1), template=template, CidrBlock=cidr, VpcId=Ref(vpc), AvailabilityZone=AZPropertyValues.get_nth_az(ind + 1), MapPublicIpOnLaunch=True, Tags=Tags( Name=helper_fn_sub( "{}/subnet/public%s" % (ind + 1,), param_env_name ) ), DependsOn=[vpc, ], ) public_subnet_list.append(subnet) self.public_subnet_list = public_subnet_list private_subnet_list = list() for ind, cidr in enumerate(self.PRIVATE_SUBNET_CIDR_LIST.get_value()): subnet = ec2.Subnet( "PrivateSubnet{}".format(ind + 1), template=template, CidrBlock=cidr, VpcId=Ref(vpc), AvailabilityZone=AZPropertyValues.get_nth_az(ind + 1), MapPublicIpOnLaunch=False, Tags=Tags( Name=helper_fn_sub( "{}/subnet/priavte%s" % (ind + 1,), param_env_name ) ), DependsOn=[vpc, ], ) private_subnet_list.append(subnet) self.private_subnet_list = private_subnet_list subnet_list = public_subnet_list + private_subnet_list self.subnet_list = subnet_list # igw for public subnet # internet gateway is a component that allow VPC to visit public internet igw = ec2.InternetGateway( "IGW", template=template, ) igw_attach_vpc = ec2.VPCGatewayAttachment( "IGWAttachVPC", template=template, VpcId=Ref(vpc), InternetGatewayId=Ref(igw), DependsOn=[ vpc, igw, ] ) self.igw = igw # eip + ngw is on public subnet but for private subnet traffic out eip_list = list() ngw_list = list() for ind in range(1, 1 + self.NUMBER_OF_NAT_GW.get_value()): eip = ec2.EIP( "EIP{}".format(ind), template=template, Domain="vpc", DependsOn=[ igw_attach_vpc, ] ) eip_list.append(eip) ngw = ec2.NatGateway( "NGW{}".format(ind), template=template, AllocationId=GetAtt(eip, "AllocationId"), SubnetId=Ref(public_subnet_list[ind - 1]), Tags=Tags( Name=helper_fn_sub( "{}/ngw/public%s" % ind, param_env_name ) ), DependsOn=eip_list, ) ngw_list.append(ngw) self.eip_list = eip_list self.ngw_list = ngw_list # public route public_route_table = ec2.RouteTable( "PublicRouteTable", template=template, VpcId=Ref(vpc), Tags=Tags( Name=helper_fn_sub("{}/public-routes", param_env_name) ) ) self.public_route_table = public_route_table public_route_default = ec2.Route( "PublicRouteDefault", template=template, RouteTableId=Ref(public_route_table), DestinationCidrBlock="0.0.0.0/0", GatewayId=Ref(igw), DependsOn=[public_route_table, igw], ) for ind, subnet in enumerate(public_subnet_list): route_table_association = ec2.SubnetRouteTableAssociation( "PublicSubnet{}RouteTableAssociation".format(ind + 1), template=template, RouteTableId=Ref(public_route_table), SubnetId=Ref(subnet), DependsOn=[public_route_table, subnet], ) # private route if self.USE_NAT_GW_PER_PRIVATE_SUBNET_FLAG.get_value() is True: for ind, subnet in enumerate(private_subnet_list): private_route_table = ec2.RouteTable( "PrivateRouteTable{}".format(ind + 1), template=template, VpcId=Ref(vpc), Tags=Tags( Name=helper_fn_sub( "{}/private-routes%s" % (ind + 1,), param_env_name ) ), DependsOn=[vpc, ] ) # Route anything to nat gateway private_route_default = ec2.Route( "PrivateRoute{}Default".format(ind + 1), template=template, RouteTableId=Ref(private_route_table), DestinationCidrBlock="0.0.0.0/0", NatGatewayId=Ref(ngw_list[ind]), DependsOn=[private_route_table, ngw_list[ind]], ) route_table_association = ec2.SubnetRouteTableAssociation( "PrivateSubnet{}RouteTableAssociation".format(ind + 1), template=template, RouteTableId=Ref(private_route_table), SubnetId=Ref(subnet), DependsOn=[private_route_table, subnet], ) else: private_route_table = ec2.RouteTable( "PrivateRouteTable", template=template, VpcId=Ref(vpc), Tags=Tags( Name=helper_fn_sub("{}/private-routes", param_env_name) ), DependsOn=[vpc, ], ) private_route_default = ec2.Route( "PrivateRouteDefault", template=template, RouteTableId=Ref(private_route_table), DestinationCidrBlock="0.0.0.0/0", NatGatewayId=Ref(ngw_list[0]), DependsOn=[private_route_table, ngw_list[0]], ) for ind, subnet in enumerate(private_subnet_list): route_table_association = ec2.SubnetRouteTableAssociation( "PrivateSubnet{}RouteTableAssociation".format(ind + 1), template=template, RouteTableId=Ref(private_route_table), SubnetId=Ref(subnet), DependsOn=[private_route_table, subnet], ) group_name = "{}/sg/allow-ssh-from-anywhere".format( self.ENVIRONMENT_NAME.get_value()) sg_for_ssh_from_anywhere = ec2.SecurityGroup( "SGForSSHFromAnywhere", template=template, GroupDescription="Allow SSH In", GroupName=group_name, VpcId=Ref(vpc), SecurityGroupIngress=[ { "IpProtocol": "tcp", "FromPort": 22, "ToPort": 22, "CidrIp": "0.0.0.0/0" } ], Tags=Tags(Name=group_name), ) self.sg_for_ssh_from_anywhere = sg_for_ssh_from_anywhere output_list.extend([ Output( vpc.title + "Id", Description="VPC ID", Value=Ref(vpc), Export=Export(helper_fn_sub("{}-vpc-id", param_env_name)), DependsOn=vpc, ), Output( "PublicSubnetIds", Description="comma delimited public subnet Ids", Value=Join( ",", [ Ref(subnet) for subnet in self.public_subnet_list ] ), Export=Export(helper_fn_sub("{}-public-subnet-ids", param_env_name)), DependsOn=self.public_subnet_list, ), Output( "PrivateSubnetIds", Description="comma delimited private subnet Ids", Value=Join(",", [ Ref(subnet) for subnet in self.private_subnet_list ] ), Export=Export(helper_fn_sub("{}-private-subnet-ids", param_env_name)), DependsOn=self.private_subnet_list, ), Output( sg_for_ssh_from_anywhere.title + "Id", Description="Security Group ID", Value=Ref(sg_for_ssh_from_anywhere), Export=Export(helper_fn_sub("{}-sg-id-allow-ssh-from-anywhere", param_env_name)) ) ]) for subnet in subnet_list: output = Output( subnet.title + "Id", Description="{} ID".format(subnet.title), Value=Ref(subnet), DependsOn=subnet, ) output_list.append(output) for output in output_list: template.add_output(output) common_tags = dict( Name=self.ENVIRONMENT_NAME.get_value(), Project=self.PROJECT_NAME_SLUG.get_value(), Stage=self.STAGE.get_value(), EnvName=self.ENVIRONMENT_NAME.get_value(), ) template.update_tags(common_tags, overwrite=False) return template def get_nth_public_subnet(self, nth): return self.public_subnet_list[nth - 1] def get_nth_private_subnet(self, nth): return self.private_subnet_list[nth - 1]