Parameters:
  ProjectName:
    Type: String
    Description: Project name to link stacks

  EnvoyImage:
    Type: String
    Description: Envoy container image

  ColorServerImage:
    Type: String
    Description: Color server app container image

  ContainerPort:
    Type: Number
    Description: Port number to use for applications
    Default: 8080

Resources:
  PublicLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Type: network
      Scheme: internet-facing
      Subnets:
      - Fn::ImportValue: !Sub '${ProjectName}:PublicSubnet1'
      - Fn::ImportValue: !Sub '${ProjectName}:PublicSubnet2'

  WebTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 30
      HealthCheckPort: 8080
      HealthCheckProtocol: TCP
      HealthCheckTimeoutSeconds: 10
      HealthyThresholdCount: 3
      TargetType: ip
      Name: !Sub '${ProjectName}-wtg'
      Port: 80
      Protocol: TCP
      UnhealthyThresholdCount: 3
      TargetGroupAttributes:
      - Key: deregistration_delay.timeout_seconds
        Value: 120
      VpcId:
        Fn::ImportValue: !Sub '${ProjectName}:VPC'

  PublicLoadBalancerListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    DependsOn:
      - PublicLoadBalancer
    Properties:
      DefaultActions:
      - TargetGroupArn: !Ref WebTargetGroup
        Type: 'forward'
      LoadBalancerArn: !Ref PublicLoadBalancer
      Port: 80
      Protocol: TCP

  TaskSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "Security group for the tasks"
      VpcId:
        Fn::ImportValue: !Sub '${ProjectName}:VPC'
      SecurityGroupIngress:
      - CidrIp:
          Fn::ImportValue: !Sub '${ProjectName}:VpcCIDR'
        IpProtocol: -1

  LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub '${ProjectName}-log-group'
      RetentionInDays: 30

  TaskIamRole:
    Type: AWS::IAM::Role
    Properties:
      Path: /
      AssumeRolePolicyDocument: |
        {
            "Statement": [{
                "Effect": "Allow",
                "Principal": { "Service": [ "ecs-tasks.amazonaws.com" ]},
                "Action": [ "sts:AssumeRole" ]
            }]
        }
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/CloudWatchFullAccess
      - arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess
      - arn:aws:iam::aws:policy/AWSAppMeshEnvoyAccess

  TaskExecutionIamRole:
    Type: AWS::IAM::Role
    Properties:
      Path: /
      AssumeRolePolicyDocument: |
        {
            "Statement": [{
                "Effect": "Allow",
                "Principal": { "Service": [ "ecs-tasks.amazonaws.com" ]},
                "Action": [ "sts:AssumeRole" ]
            }]
        }
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
      - arn:aws:iam::aws:policy/CloudWatchLogsFullAccess

  SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "Security group for the instances"
      VpcId:
        Fn::ImportValue: !Sub '${ProjectName}:VPC'
      SecurityGroupIngress:
      - CidrIp:
          Fn::ImportValue: !Sub '${ProjectName}:VpcCIDR'
        IpProtocol: -1

  ColorGatewayRegistry:
    Type: AWS::ServiceDiscovery::Service
    Properties:
      Name: 'color_gateway'
      DnsConfig:
        NamespaceId:
          Fn::ImportValue: !Sub '${ProjectName}:CloudMapNamespaceId'
        DnsRecords:
        - Type: A
          TTL: 300
      HealthCheckCustomConfig:
        FailureThreshold: 1

  ColorGatewayService:
    Type: AWS::ECS::Service
    DependsOn:
    - ColorServerService
    - PublicLoadBalancerListener
    Properties:
      Cluster:
        Fn::ImportValue: !Sub '${ProjectName}:ECSCluster'
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 100
      DesiredCount: 1
      LaunchType: 'FARGATE'
      ServiceRegistries:
      - RegistryArn: !GetAtt 'ColorGatewayRegistry.Arn'
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: DISABLED
          SecurityGroups:
          - !Ref SecurityGroup
          Subnets:
          - Fn::ImportValue: !Sub '${ProjectName}:PrivateSubnet1'
          - Fn::ImportValue: !Sub '${ProjectName}:PrivateSubnet2'
      TaskDefinition: !Ref ColorGatewayTaskDef
      LoadBalancers:
      - ContainerName: app
        ContainerPort: !Ref ContainerPort
        TargetGroupArn: !Ref WebTargetGroup

  ColorGatewayTaskDef:
    Type: AWS::ECS::TaskDefinition
    Properties:
      RequiresCompatibilities:
      - 'FARGATE'
      Family: 'color_gateway'
      NetworkMode: 'awsvpc'
      Cpu: 256
      Memory: 512
      TaskRoleArn: !Ref TaskIamRole
      ExecutionRoleArn: !Ref TaskExecutionIamRole
      ContainerDefinitions:
      - Name: app
        Image: !Ref EnvoyImage
        Essential: true
        User: '1337'
        Ulimits:
        - Name: "nofile"
          HardLimit: 15000
          SoftLimit: 15000
        PortMappings:
        - ContainerPort: 9901
          Protocol: 'tcp'
        - ContainerPort: !Ref ContainerPort
          Protocol: 'tcp'   
        HealthCheck:
          Command:
          - 'CMD-SHELL'
          - 'curl -s http://localhost:9901/server_info | grep state | grep -q LIVE'
          Interval: 5
          Timeout: 2
          Retries: 3
        LogConfiguration:
          LogDriver: 'awslogs'
          Options:
            awslogs-group: !Sub '${ProjectName}-log-group'
            awslogs-region: !Ref AWS::Region
            awslogs-stream-prefix: 'color_gateway-envoy'
        Environment:
        - Name: 'APPMESH_RESOURCE_ARN'
          Value: !Sub 'mesh/${ProjectName}-mesh/virtualGateway/color_gateway'
        - Name: 'ENVOY_LOG_LEVEL'
          Value: 'debug'

  ColorServerRegistry:
    Type: AWS::ServiceDiscovery::Service
    Properties:
      Name: 'color_server'
      DnsConfig:
        NamespaceId:
          Fn::ImportValue: !Sub '${ProjectName}:CloudMapNamespaceId'
        DnsRecords:
        - Type: A
          TTL: 300
      HealthCheckCustomConfig:
        FailureThreshold: 1

  ColorServerService:
    Type: AWS::ECS::Service
    Properties:
      Cluster:
        Fn::ImportValue: !Sub '${ProjectName}:ECSCluster'
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 100
      DesiredCount: 1
      LaunchType: 'FARGATE'
      ServiceRegistries:
      - RegistryArn: !GetAtt 'ColorServerRegistry.Arn'
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: DISABLED
          SecurityGroups:
          - !Ref SecurityGroup
          Subnets:
          - Fn::ImportValue: !Sub '${ProjectName}:PrivateSubnet1'
          - Fn::ImportValue: !Sub '${ProjectName}:PrivateSubnet2'
      TaskDefinition: !Ref ColorServerTaskDef

  ColorServerTaskDef:
    Type: AWS::ECS::TaskDefinition
    Properties:
      RequiresCompatibilities:
      - 'FARGATE'
      Family: 'color_server'
      NetworkMode: 'awsvpc'
      Cpu: 256
      Memory: 512
      TaskRoleArn: !Ref TaskIamRole
      ExecutionRoleArn: !Ref TaskExecutionIamRole
      ProxyConfiguration:
        Type: 'APPMESH'
        ContainerName: 'envoy'
        ProxyConfigurationProperties:
        - Name: 'IgnoredUID'
          Value: '1337'
        - Name: 'ProxyIngressPort'
          Value: '15000'
        - Name: 'ProxyEgressPort'
          Value: '15001'
        - Name: 'AppPorts'
          Value: !Sub '${ContainerPort}'
        - Name: 'EgressIgnoredIPs'
          Value: '169.254.170.2,169.254.169.254'
      ContainerDefinitions:
      - Name: 'app'
        Image: !Ref ColorServerImage
        Essential: true
        LogConfiguration:
          LogDriver: 'awslogs'
          Options:
            awslogs-group: !Sub '${ProjectName}-log-group'
            awslogs-region: !Ref AWS::Region
            awslogs-stream-prefix: 'color_server'
        PortMappings:
        - ContainerPort: !Ref ContainerPort
          Protocol: 'tcp'
        Environment:
        - Name: 'PORT'
          Value: !Sub '${ContainerPort}'
        - Name: 'COLOR'
          Value: !Sub 'no color!'
      - Name: envoy
        Image: !Ref EnvoyImage
        Essential: true
        User: '1337'
        Ulimits:
        - Name: "nofile"
          HardLimit: 15000
          SoftLimit: 15000
        PortMappings:
        - ContainerPort: 9901
          Protocol: 'tcp'
        - ContainerPort: 15000
          Protocol: 'tcp'
        - ContainerPort: 15001
          Protocol: 'tcp'
        HealthCheck:
          Command:
          - 'CMD-SHELL'
          - 'curl -s http://localhost:9901/server_info | grep state | grep -q LIVE'
          Interval: 5
          Timeout: 2
          Retries: 3
        LogConfiguration:
          LogDriver: 'awslogs'
          Options:
            awslogs-group: !Sub '${ProjectName}-log-group'
            awslogs-region: !Ref AWS::Region
            awslogs-stream-prefix: 'color_server-envoy'
        Environment:
        - Name: 'APPMESH_RESOURCE_ARN'
          Value: !Sub 'mesh/${ProjectName}-mesh/virtualNode/color_server'
        - Name: 'ENVOY_LOG_LEVEL'
          Value: 'debug'

Outputs:
  PublicEndpoint:
    Description: 'Public endpoint for the color client service'
    Value: !Join ['', ['http://', !GetAtt 'PublicLoadBalancer.DNSName']]
    Export:
      Name: !Sub '${ProjectName}:PublicEndpoint'
