AWSTemplateFormatVersion: '2010-09-09'
Description: The network stack for the ECS cluster.
Parameters:
  EnvironmentName:
    Type: String
    Default: production
    Description: "A friendly environment name that will be used for namespacing all cluster resources. Example: staging, qa, or production"

Mappings:
  # Hard values for the subnet masks. These masks define
  # the range of internal IP addresses that can be assigned.
  # The VPC can have all IP's from 10.0.0.0 to 10.0.255.255
  # There are four subnets which cover the ranges:
  #
  # 10.0.0.0 - 10.0.0.255
  # 10.0.1.0 - 10.0.1.255
  # 10.0.2.0 - 10.0.2.255
  # 10.0.3.0 - 10.0.3.255
  #
  # If you need more IP addresses (perhaps you have so many
  # instances that you run out) then you can customize these
  # ranges to add more
  SubnetConfig:
    VPC:
      CIDR: '10.0.0.0/16'
    PublicOne:
      CIDR: '10.0.0.0/24'
    PublicTwo:
      CIDR: '10.0.1.0/24'
    PrivateOne:
      CIDR: '10.0.2.0/24'
    PrivateTwo:
      CIDR: '10.0.3.0/24'

Resources:
  # VPC in which containers will be networked.
  # It has two public subnets, and two private subnets.
  # We distribute the subnets across the first two available subnets
  # for the region, for high availability.
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      EnableDnsSupport: true
      EnableDnsHostnames: true
      CidrBlock: !FindInMap ['SubnetConfig', 'VPC', 'CIDR']

  # Two public subnets, where containers can have public IP addresses
  PublicSubnetOne:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone:
         Fn::Select:
         - 0
         - Fn::GetAZs: {Ref: 'AWS::Region'}
      VpcId: !Ref 'VPC'
      CidrBlock: !FindInMap ['SubnetConfig', 'PublicOne', 'CIDR']
      MapPublicIpOnLaunch: true
  PublicSubnetTwo:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone:
         Fn::Select:
         - 1
         - Fn::GetAZs: {Ref: 'AWS::Region'}
      VpcId: !Ref 'VPC'
      CidrBlock: !FindInMap ['SubnetConfig', 'PublicTwo', 'CIDR']
      MapPublicIpOnLaunch: true

  # Two private subnets where containers will only have private
  # IP addresses, and will only be reachable by other members of the
  # VPC
  PrivateSubnetOne:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone:
         Fn::Select:
         - 0
         - Fn::GetAZs: {Ref: 'AWS::Region'}
      VpcId: !Ref 'VPC'
      CidrBlock: !FindInMap ['SubnetConfig', 'PrivateOne', 'CIDR']
  PrivateSubnetTwo:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone:
         Fn::Select:
         - 1
         - Fn::GetAZs: {Ref: 'AWS::Region'}
      VpcId: !Ref 'VPC'
      CidrBlock: !FindInMap ['SubnetConfig', 'PrivateTwo', 'CIDR']

  # Setup networking resources for the public subnets. Containers
  # in the public subnets have public IP addresses and the routing table
  # sends network traffic via the internet gateway.
  InternetGateway:
    Type: AWS::EC2::InternetGateway
  GatewayAttachement:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref 'VPC'
      InternetGatewayId: !Ref 'InternetGateway'
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref 'VPC'
  PublicRoute:
    Type: AWS::EC2::Route
    DependsOn: GatewayAttachement
    Properties:
      RouteTableId: !Ref 'PublicRouteTable'
      DestinationCidrBlock: '0.0.0.0/0'
      GatewayId: !Ref 'InternetGateway'
  PublicSubnetOneRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnetOne
      RouteTableId: !Ref PublicRouteTable
  PublicSubnetTwoRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnetTwo
      RouteTableId: !Ref PublicRouteTable

  # Setup networking resources for the private subnets. Containers
  # in these subnets have only private IP addresses, and must use a NAT
  # gateway to talk to the internet. We launch two NAT gateways, one for
  # each private subnet.
  # NatGatewayOneAttachment:
  #   Type: AWS::EC2::EIP
  #   DependsOn: GatewayAttachement
  #   Properties:
  #       Domain: vpc
  # NatGatewayTwoAttachment:
  #   Type: AWS::EC2::EIP
  #   DependsOn: GatewayAttachement
  #   Properties:
  #       Domain: vpc
  # NatGatewayOne:
  #   Type: AWS::EC2::NatGateway
  #   Properties:
  #     AllocationId: !GetAtt NatGatewayOneAttachment.AllocationId
  #     SubnetId: !Ref PublicSubnetOne
  # NatGatewayTwo:
  #   Type: AWS::EC2::NatGateway
  #   Properties:
  #     AllocationId: !GetAtt NatGatewayTwoAttachment.AllocationId
  #     SubnetId: !Ref PublicSubnetTwo
  PrivateRouteTableOne:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref 'VPC'
  # PrivateRouteOne:
  #   Type: AWS::EC2::Route
  #   Properties:
  #     RouteTableId: !Ref PrivateRouteTableOne
  #     DestinationCidrBlock: 0.0.0.0/0
  #     NatGatewayId: !Ref NatGatewayOne
  PrivateRouteTableOneAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PrivateRouteTableOne
      SubnetId: !Ref PrivateSubnetOne
  PrivateRouteTableTwo:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref 'VPC'
  # PrivateRouteTwo:
  #   Type: AWS::EC2::Route
  #   Properties:
  #     RouteTableId: !Ref PrivateRouteTableTwo
  #     DestinationCidrBlock: 0.0.0.0/0
  #     NatGatewayId: !Ref NatGatewayTwo
  PrivateRouteTableTwoAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref PrivateRouteTableTwo
      SubnetId: !Ref PrivateSubnetTwo

  # A security group for either the EC2 hosts that will run the containers
  # or the containers we will run in Fargate. Rules are added based on
  # what ingress you choose to add to the cluster.
  ContainerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Access to the ECS hosts that run containers
      VpcId: !Ref 'VPC'

# These are the values output by the CloudFormation template. Be careful
# about changing any of them, because of them are exported with specific
# names so that the other task related CF templates can use them.
Outputs:
  VpcId:
    Description: The ID of the VPC that this stack is deployed in
    Value: !Ref 'VPC'
    Export:
      Name: !Sub ${EnvironmentName}:VpcId
  PublicSubnetOne:
    Description: Public subnet one
    Value: !Ref 'PublicSubnetOne'
    Export:
      Name: !Sub ${EnvironmentName}:PublicSubnetOne
  PublicSubnetTwo:
    Description: Public subnet two
    Value: !Ref 'PublicSubnetTwo'
    Export:
      Name: !Sub ${EnvironmentName}:PublicSubnetTwo
  PrivateSubnetOne:
    Description: Private subnet one
    Value: !Ref 'PrivateSubnetOne'
    Export:
      Name: !Sub ${EnvironmentName}:PrivateSubnetOne
  PrivateSubnetTwo:
    Description: Private subnet two
    Value: !Ref 'PrivateSubnetTwo'
    Export:
      Name: !Sub ${EnvironmentName}:PrivateSubnetTwo
  ContainerSecurityGroup:
    Description: A security group used to allow containers to receive traffic
    Value: !Ref 'ContainerSecurityGroup'
    Export:
      Name: !Sub ${EnvironmentName}:ContainerSecurityGroup
