---
Parameters:
  EnvironmentName:
    Type: String
    Description: Environment name that joins all the stacks

  AppMeshMeshName:
    Type: String
    Description: Name of mesh

  ECSServicesDomain:
    Type: String
    Description: DNS namespace used by services e.g. default.svc.cluster.local

  EnvoyImage:
    Type: String
    Description: The image to use for the Envoy container

  ColorGatewayImageName:
    Description: The name for the gateway image
    Type: String

  ColorTellerImageName:
    Description: The name for the color teller image
    Type: String

  LoadBalancerPath:
    Type: String
    Default: "*"
    Description: A path on the public load balancer that this service
                 should be connected to. Use * to send all load balancer
                 traffic to this service.

Resources:


  ### colorteller.default.svc.cluster.local
  ColorTellerWhiteServiceDiscoveryRecord:
    Type: 'AWS::ServiceDiscovery::Service'
    Properties:
      Name: "colorteller"
      DnsConfig:
        NamespaceId:
          'Fn::ImportValue': !Sub "${EnvironmentName}:ECSServiceDiscoveryNamespace"
        DnsRecords:
          - Type: A
            TTL: 300
      HealthCheckCustomConfig:
        FailureThreshold: 1

  ColorTellerWhiteTaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      RequiresCompatibilities:
        - 'FARGATE'
      Family: 'white'
      NetworkMode: 'awsvpc'
      Cpu: 256
      Memory: 512
      TaskRoleArn:
        'Fn::ImportValue': !Sub "${EnvironmentName}:TaskIamRoleArn"
      ExecutionRoleArn:
        'Fn::ImportValue': !Sub "${EnvironmentName}:TaskExecutionIamRoleArn"
      ProxyConfiguration:
        Type: 'APPMESH'
        ContainerName: 'envoy'
        ProxyConfigurationProperties:
          - Name: 'IgnoredUID'
            Value: '1337'
          - Name: 'ProxyIngressPort'
            Value: '15000'
          - Name: 'ProxyEgressPort'
            Value: '15001'
          - Name: 'AppPorts'
            Value: '80'
          - Name: 'EgressIgnoredIPs'
            Value: '169.254.170.2,169.254.169.254'
      ContainerDefinitions:
        - Name: 'app'
          Image: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ColorTellerImageName}'
          Essential: true
          DependsOn:
            - ContainerName: 'envoy'
              Condition: 'HEALTHY'
          LogConfiguration:
            LogDriver: 'awslogs'
            Options:
              awslogs-group:
                Fn::ImportValue: !Sub "${EnvironmentName}:ECSServiceLogGroup"
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: 'white'
          PortMappings:
            - ContainerPort: 80
              Protocol: 'http'
          Environment:
            - Name: 'SERVER_PORT'
              Value: 80
            - Name: 'COLOR'
              Value: 'white'
        - 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:
                Fn::ImportValue: !Sub "${EnvironmentName}:ECSServiceLogGroup"
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: 'white-envoy'
          Environment:
            - Name: 'APPMESH_RESOURCE_ARN'
              Value: !Sub 'mesh/${AppMeshMeshName}/virtualNode/ColorTellerWhite'
            - Name: 'APPMESH_PREVIEW'
              Value: '1'
            - Name: 'ENVOY_LOG_LEVEL'
              Value: 'debug'  


  ColorTellerWhiteService:
    Type: 'AWS::ECS::Service'
    Properties:
      Cluster:
        'Fn::ImportValue': !Sub "${EnvironmentName}:ECSCluster"
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 100
      DesiredCount: 1
      LaunchType: FARGATE
      ServiceRegistries:
        - RegistryArn:
            'Fn::GetAtt': ColorTellerWhiteServiceDiscoveryRecord.Arn
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: DISABLED
          SecurityGroups:
            - 'Fn::ImportValue': !Sub "${EnvironmentName}:ECSServiceSecurityGroup"
          Subnets: 
            - 'Fn::ImportValue': !Sub "${EnvironmentName}:PrivateSubnet1"
            - 'Fn::ImportValue': !Sub "${EnvironmentName}:PrivateSubnet2"
      TaskDefinition: { Ref: ColorTellerWhiteTaskDefinition }

  ### colorteller-red.default.svc.cluster.local
  ColorTellerRedServiceDiscoveryRecord:
    Type: 'AWS::ServiceDiscovery::Service'
    Properties:
      Name: "colorteller-red"
      DnsConfig:
        NamespaceId:
          'Fn::ImportValue': !Sub "${EnvironmentName}:ECSServiceDiscoveryNamespace"
        DnsRecords:
          - Type: A
            TTL: 300
      HealthCheckCustomConfig:
        FailureThreshold: 1

  ColorTellerRedTaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      RequiresCompatibilities:
        - 'FARGATE'
      Family: 'red'
      NetworkMode: 'awsvpc'
      Cpu: 256
      Memory: 512
      TaskRoleArn:
        'Fn::ImportValue': !Sub "${EnvironmentName}:TaskIamRoleArn"
      ExecutionRoleArn:
        'Fn::ImportValue': !Sub "${EnvironmentName}:TaskExecutionIamRoleArn"
      ProxyConfiguration:
        Type: 'APPMESH'
        ContainerName: 'envoy'
        ProxyConfigurationProperties:
          - Name: 'IgnoredUID'
            Value: '1337'
          - Name: 'ProxyIngressPort'
            Value: '15000'
          - Name: 'ProxyEgressPort'
            Value: '15001'
          - Name: 'AppPorts'
            Value: '80'
          - Name: 'EgressIgnoredIPs'
            Value: '169.254.170.2,169.254.169.254'
      ContainerDefinitions:
        - Name: 'app'
          Image: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ColorTellerImageName}'
          Essential: true
          DependsOn:
            - ContainerName: 'envoy'
              Condition: 'HEALTHY'
          LogConfiguration:
            LogDriver: 'awslogs'
            Options:
              awslogs-group:
                Fn::ImportValue: !Sub "${EnvironmentName}:ECSServiceLogGroup"
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: 'red'
          PortMappings:
            - ContainerPort: 80
              Protocol: 'http'
          Environment:
            - Name: 'SERVER_PORT'
              Value: 80
            - Name: 'COLOR'
              Value: 'red'
        - 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:
                Fn::ImportValue: !Sub "${EnvironmentName}:ECSServiceLogGroup"
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: 'red-envoy'
          Environment:
            - Name: 'APPMESH_RESOURCE_ARN'
              Value: !Sub 'mesh/${AppMeshMeshName}/virtualNode/ColorTellerRed'
            - Name: 'APPMESH_PREVIEW'
              Value: '1'
            - Name: 'ENVOY_LOG_LEVEL'
              Value: 'debug'  

  ColorTellerRedService:
    Type: 'AWS::ECS::Service'
    Properties:
      Cluster:
        'Fn::ImportValue': !Sub "${EnvironmentName}:ECSCluster"
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 100
      DesiredCount: 1
      LaunchType: FARGATE
      ServiceRegistries:
        - RegistryArn:
            'Fn::GetAtt': ColorTellerRedServiceDiscoveryRecord.Arn
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: DISABLED
          SecurityGroups:
            - 'Fn::ImportValue': !Sub "${EnvironmentName}:ECSServiceSecurityGroup"
          Subnets: 
            - 'Fn::ImportValue': !Sub "${EnvironmentName}:PrivateSubnet1"
            - 'Fn::ImportValue': !Sub "${EnvironmentName}:PrivateSubnet2"
      TaskDefinition: { Ref: ColorTellerRedTaskDefinition }

  ### colorgateway.default.svc.cluster.local
  ColorGatewayServiceDiscoveryRecord:
    Type: 'AWS::ServiceDiscovery::Service'
    Properties:
      Name: "colorgateway"
      DnsConfig:
        NamespaceId:
          'Fn::ImportValue': !Sub "${EnvironmentName}:ECSServiceDiscoveryNamespace"
        DnsRecords:
          - Type: A
            TTL: 300
      HealthCheckCustomConfig:
        FailureThreshold: 1

  ColorGatewayTaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      RequiresCompatibilities:
        - 'FARGATE'
      Family: 'gateway'
      NetworkMode: 'awsvpc'
      Cpu: 256
      Memory: 512
      TaskRoleArn:
        'Fn::ImportValue': !Sub "${EnvironmentName}:TaskIamRoleArn"
      ExecutionRoleArn:
        'Fn::ImportValue': !Sub "${EnvironmentName}:TaskExecutionIamRoleArn"
      ProxyConfiguration:
        Type: 'APPMESH'
        ContainerName: 'envoy'
        ProxyConfigurationProperties:
          - Name: 'IgnoredUID'
            Value: '1337'
          - Name: 'ProxyIngressPort'
            Value: '15000'
          - Name: 'ProxyEgressPort'
            Value: '15001'
          - Name: 'AppPorts'
            Value: '80'
          - Name: 'EgressIgnoredIPs'
            Value: '169.254.170.2,169.254.169.254'
      ContainerDefinitions:
        - Name: 'app'
          Image: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${ColorGatewayImageName}'
          Essential: true
          DependsOn:
            - ContainerName: 'envoy'
              Condition: 'HEALTHY'
          LogConfiguration:
            LogDriver: 'awslogs'
            Options:
              awslogs-group:
                Fn::ImportValue: !Sub "${EnvironmentName}:ECSServiceLogGroup"
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: 'gateway'
          PortMappings:
            - ContainerPort: 80
              Protocol: 'http'
          Environment:
            - Name: SERVER_PORT
              Value: 80
            - Name: COLOR_TELLER_ENDPOINT
              Value: !Sub 'colorteller.${ECSServicesDomain}'
            - Name: TCP_ECHO_ENDPOINT
              Value: unused
        - 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:
                Fn::ImportValue: !Sub "${EnvironmentName}:ECSServiceLogGroup"
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: 'gateway-envoy'
          Environment:
            - Name: 'APPMESH_RESOURCE_ARN'
              Value: !Sub 'mesh/${AppMeshMeshName}/virtualNode/ColorGateway'
            - Name: 'APPMESH_PREVIEW'
              Value: '1'
            - Name: 'ENVOY_LOG_LEVEL'
              Value: 'debug'  

  ColorGatewayService:
    Type: 'AWS::ECS::Service'
    DependsOn:
      - WebLoadBalancerRule
    Properties:
      Cluster:
        'Fn::ImportValue': !Sub "${EnvironmentName}:ECSCluster"
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 100
      DesiredCount: 1
      LaunchType: FARGATE
      ServiceRegistries:
        - RegistryArn:
            'Fn::GetAtt': ColorGatewayServiceDiscoveryRecord.Arn
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: DISABLED
          SecurityGroups:
            - 'Fn::ImportValue': !Sub "${EnvironmentName}:ECSServiceSecurityGroup"
          Subnets: 
            - 'Fn::ImportValue': !Sub "${EnvironmentName}:PrivateSubnet1"
            - 'Fn::ImportValue': !Sub "${EnvironmentName}:PrivateSubnet2"
      TaskDefinition: { Ref: ColorGatewayTaskDefinition }
      LoadBalancers:
          - ContainerName: app
            ContainerPort: 80
            TargetGroupArn: !Ref WebTargetGroup

  ### publicgateway.default.svc.cluster.local
  PublicGatewayServiceDiscoveryRecord:
    Type: 'AWS::ServiceDiscovery::Service'
    Properties:
      Name: "publicgateway"
      DnsConfig:
        NamespaceId:
          'Fn::ImportValue': !Sub "${EnvironmentName}:ECSServiceDiscoveryNamespace"
        DnsRecords:
          - Type: A
            TTL: 300
      HealthCheckCustomConfig:
        FailureThreshold: 1

  PublicGatewayTaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      RequiresCompatibilities:
        - 'FARGATE'
      Family: 'publicgateway'
      NetworkMode: 'awsvpc'
      Cpu: 256
      Memory: 512
      TaskRoleArn:
        'Fn::ImportValue': !Sub "${EnvironmentName}:TaskIamRoleArn"
      ExecutionRoleArn:
        'Fn::ImportValue': !Sub "${EnvironmentName}:TaskExecutionIamRoleArn"
      ContainerDefinitions:
        - Name: 'app'
          Image: !Ref EnvoyImage
          Essential: true
          Ulimits:
            - Name: "nofile"
              HardLimit: 15000
              SoftLimit: 15000
          PortMappings:
            - ContainerPort: 9901
              Protocol: 'tcp'
            - ContainerPort: 80
              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:
                Fn::ImportValue: !Sub "${EnvironmentName}:ECSServiceLogGroup"
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: 'publicgateway-envoy'
          Environment:
            - Name: 'APPMESH_RESOURCE_ARN'
              Value: !Sub 'mesh/${AppMeshMeshName}/virtualGateway/publicgateway-vg'
            - Name: 'APPMESH_PREVIEW'
              Value: '1'
            - Name: 'ENVOY_LOG_LEVEL'
              Value: 'debug'  

  PublicGatewayService:
    Type: 'AWS::ECS::Service'
    DependsOn:
      - WebLoadBalancerRule
    Properties:
      Cluster:
        'Fn::ImportValue': !Sub "${EnvironmentName}:ECSCluster"
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 100
      DesiredCount: 1
      LaunchType: FARGATE
      ServiceRegistries:
        - RegistryArn:
            'Fn::GetAtt': PublicGatewayServiceDiscoveryRecord.Arn
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: DISABLED
          SecurityGroups:
            - 'Fn::ImportValue': !Sub "${EnvironmentName}:ECSServiceSecurityGroup"
          Subnets: 
            - 'Fn::ImportValue': !Sub "${EnvironmentName}:PrivateSubnet1"
            - 'Fn::ImportValue': !Sub "${EnvironmentName}:PrivateSubnet2"
      TaskDefinition: { Ref: PublicGatewayTaskDefinition }
      LoadBalancers:
        - ContainerName: app
          ContainerPort: 80
          TargetGroupArn: !Ref WebTargetGroup2


  PublicLoadBalancerSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Access to the public facing load balancer
      VpcId:
        'Fn::ImportValue': !Sub "${EnvironmentName}:VPC"
      SecurityGroupIngress:
          - CidrIp: 0.0.0.0/0
            IpProtocol: tcp
            FromPort: 80
            ToPort: 80

  # public ALB for color gateway
  PublicLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Scheme: internet-facing
      LoadBalancerAttributes:
        - Key: idle_timeout.timeout_seconds
          Value: '30'
      Subnets:
        - { 'Fn::ImportValue': !Sub "${EnvironmentName}:PublicSubnet1" }  
        - { 'Fn::ImportValue': !Sub "${EnvironmentName}:PublicSubnet2" }  
      SecurityGroups: [!Ref 'PublicLoadBalancerSG']

  WebTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 30
      HealthCheckPath: /server_info
      HealthCheckPort: 9901
      HealthCheckProtocol: HTTP
      HealthCheckTimeoutSeconds: 6
      HealthyThresholdCount: 3
      TargetType: ip
      Name: !Sub "${EnvironmentName}-web"
      Port: 80
      Protocol: HTTP
      UnhealthyThresholdCount: 2
      TargetGroupAttributes:
        - Key: deregistration_delay.timeout_seconds
          Value: 120
      VpcId:
        'Fn::ImportValue': !Sub "${EnvironmentName}:VPC"

  WebTargetGroup2:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 30
      HealthCheckPath: /server_info
      HealthCheckPort: 9901
      HealthCheckProtocol: HTTP
      HealthCheckTimeoutSeconds: 6
      HealthyThresholdCount: 3
      TargetType: ip
      Name: !Sub "${EnvironmentName}-vg"
      Port: 80
      Protocol: HTTP
      UnhealthyThresholdCount: 2
      TargetGroupAttributes:
        - Key: deregistration_delay.timeout_seconds
          Value: 120
      VpcId:
        'Fn::ImportValue': !Sub "${EnvironmentName}:VPC"
  
  PublicLoadBalancerListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    DependsOn:
      - PublicLoadBalancer
    Properties:
      DefaultActions:
        - TargetGroupArn: !Ref WebTargetGroup
          Type: 'forward'
      LoadBalancerArn: !Ref 'PublicLoadBalancer'
      Port: 80
      Protocol: HTTP

  WebLoadBalancerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Actions:
        - TargetGroupArn: !Ref WebTargetGroup
          Type: 'forward'
      Conditions:
        - Field: path-pattern
          Values: [!Ref 'LoadBalancerPath']
      ListenerArn: !Ref PublicLoadBalancerListener
      Priority: 2

  WebLoadBalancerRule2:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Actions:
        - TargetGroupArn: !Ref WebTargetGroup2
          Type: 'forward'
      Conditions:
        - Field: http-header
          HttpHeaderConfig:
            HttpHeaderName: Gateway
            Values:
              - Virtual
      ListenerArn: !Ref PublicLoadBalancerListener
      Priority: 1

Outputs: 

  ColorAppEndpoint:
    Description: Public endpoint for Color App service
    Value: !Join ['', ['http://', !GetAtt 'PublicLoadBalancer.DNSName']]

