# For testing/development purposes only!
AWSTemplateFormatVersion: '2010-09-09'
Description: Deploy an ECS service with a Consul Connect sidecar
Parameters:
  EnvironmentName:
    Type: String
    Default: test
    Description: The name of the environment to add this service to
  ServiceName:
    Type: String
    Default: greeting
    Description: A name for the service
  ImageUrl:
    Type: String
    #Default: nathanpeck/greeting
    Description: The url of a docker image that contains the application process that
                 will handle the traffic for this service
  InitImageUrl:
    Type: String
    Description: The custom build image which will create the config files

  ContainerPort:
    Type: Number
    Default: 3000
    Description: What port number the application inside the docker container is binding to
  ContainerCpu:
    Type: Number
    Default: 256
    Description: How much CPU to give the container. 1024 is 1 CPU
  ContainerMemory:
    Type: Number
    Default: 512
    Description: How much memory in megabytes to give the container
  DesiredCount:
    Type: Number
    Default: 2
    Description: How many copies of the service task to run

Resources:
  # A log group for storing the stdout logs from this service's containers
  LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub ${EnvironmentName}-service-${ServiceName}

  # Consul agent role. This role authorizes the Consul daemon to query the list of EC2 instances
  # by tag in order to locate the Consul server.
  ConsulAgentRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Effect: Allow
          Principal:
            Service: "ecs-tasks.amazonaws.com"
          Action: ['sts:AssumeRole']
      Path: /
      Policies:
      - PolicyName: query-ec2-instances
        PolicyDocument:
          Statement:
          - Effect: Allow
            Action:
              - 'ec2:DescribeInstances'
            Resource: '*'

  # Task execution role. This role authorizes the ECS agent to pull images from ECR 
  # and post to CloudWatch logs.
  TaskExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Effect: Allow
          Principal:
            Service: "ecs-tasks.amazonaws.com"
          Action: ['sts:AssumeRole']
      Path: /
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy

  # The task definition. This is a simple metadata description of what
  # container to run, and what resource requirements it has.
  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: !Ref 'ServiceName'
      NetworkMode: awsvpc
      Cpu: 512
      Memory: 1024
      ExecutionRoleArn: !GetAtt 'TaskExecutionRole.Arn'
      TaskRoleArn: !GetAtt 'ConsulAgentRole.Arn'
      RequiresCompatibilities:
        - FARGATE
      Volumes:
        - Name: consul-data
        - Name: consul-config
      ContainerDefinitions:

        # The actual service container. Should only accept inbound traffic from Consul 
        # Connect and to other services via a localhost Consul proxy pipe
        - Name: !Ref 'ServiceName'
          Cpu: !Ref 'ContainerCpu'
          Memory: !Ref 'ContainerMemory'
          Image: !Ref 'ImageUrl'
          Environment:
            - Name: PORT
              Value: !Ref 'ContainerPort'
          Essential: true
          LogConfiguration:
            LogDriver: 'awslogs'
            Options:
              awslogs-group: !Sub ${EnvironmentName}-service-${ServiceName}
              awslogs-region: !Ref 'AWS::Region'
              awslogs-stream-prefix: !Ref 'ServiceName'

        # the agent which should join the mesh & register the service
        - Name: !Sub ${ServiceName}-agent
          Image: !Ref 'InitImageUrl'
          PortMappings:
            - ContainerPort: 8301
              Protocol: tcp
            - ContainerPort: 8301
              Protocol: udp
            - ContainerPort: 8400
              Protocol: tcp
            - ContainerPort: 8500
              Protocol: tcp
            - ContainerPort: 53
              Protocol: udp
          MountPoints:
              - ContainerPath: /consul/data
                SourceVolume: consul-data
                ReadOnly: false
              - ContainerPath: /consul/config
                SourceVolume: consul-config
                ReadOnly: false
          LogConfiguration:
            LogDriver: 'awslogs'
            Options:
              awslogs-group: !Sub ${EnvironmentName}-service-${ServiceName}
              awslogs-region: !Ref 'AWS::Region'
              awslogs-stream-prefix: !Sub ${ServiceName}-agent

        # the Consul Connect sidecar proxy
        - Name: !Sub ${ServiceName}-proxy
          Image: 'public.ecr.aws/hashicorp/consul:1.9.1'
          DependsOn:
            - ContainerName: !Sub ${ServiceName}-agent
              Condition: START
          EntryPoint:
            - '/bin/sh'
            - '-c'
          Command:
            - !Sub >
              exec consul connect proxy -sidecar-for ${ServiceName}
          PortMappings:
            - ContainerPort: 8080
          LogConfiguration:
            LogDriver: 'awslogs'
            Options:
              awslogs-group: !Sub ${EnvironmentName}-service-${ServiceName}
              awslogs-region: !Ref 'AWS::Region'
              awslogs-stream-prefix: !Sub ${ServiceName}-proxy

  # The ECS service to run the containers
  Service:
    Type: AWS::ECS::Service
    Properties:
      ServiceName: !Ref 'ServiceName'
      LaunchType: 'FARGATE'
      Cluster:
        Fn::ImportValue: !Sub ${EnvironmentName}:ClusterName
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 75
      DesiredCount: !Ref 'DesiredCount'
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED
          SecurityGroups:
            - Fn::ImportValue: !Sub ${EnvironmentName}:ServiceSecurityGroup
          Subnets:
            - Fn::ImportValue: !Sub ${EnvironmentName}:PublicSubnetOne
            - Fn::ImportValue: !Sub ${EnvironmentName}:PublicSubnetTwo
      TaskDefinition: !Ref 'TaskDefinition'