---
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

  ColorGatewayTaskDefinition:
    Type: String
    Description: Task definition for ColorGateway Service

  ColorTellerWhiteTaskDefinition:
    Type: String
    Description: Task definition for ColorTeller White Service

  ColorTellerRedTaskDefinition:
    Type: String
    Description: Task definition for ColorTeller Red Service

  ColorTellerBlueTaskDefinition:
    Type: String
    Description: Task definition for ColorTeller Blue Service

  ColorTellerBlackTaskDefinition:
    Type: String
    Description: Task definition for ColorTeller Black Service

  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.

  DeployTester:
    Type: String
    Default: false
    AllowedValues:
      - true
      - false
    Description: Set to "true" to include the TesterService (to generate color history)

Conditions:
  ShouldDeployTester:
    !Equals [true, !Ref DeployTester]

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

  ColorTellerWhiteService:
    Type: 'AWS::ECS::Service'
    Properties:
      Cluster:
        'Fn::ImportValue': !Sub "${EnvironmentName}:ECSCluster"
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 100
      DesiredCount: 1
      LaunchType: EC2
      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-blue.default.svc.cluster.local
  ColorTellerBlueServiceDiscoveryRecord:
    Type: 'AWS::ServiceDiscovery::Service'
    Properties:
      Name: "colorteller-blue"
      DnsConfig:
        NamespaceId:
          'Fn::ImportValue': !Sub "${EnvironmentName}:ECSServiceDiscoveryNamespace"
        DnsRecords:
          - Type: A
            TTL: 300
      HealthCheckCustomConfig:
        FailureThreshold: 1

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

  ### 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

  ColorTellerRedService:
    Type: 'AWS::ECS::Service'
    Properties:
      Cluster:
        'Fn::ImportValue': !Sub "${EnvironmentName}:ECSCluster"
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 100
      DesiredCount: 1
      LaunchType: EC2
      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 }

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

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

  ### 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

  ColorGatewayService:
    Type: 'AWS::ECS::Service'
    DependsOn:
      - WebLoadBalancerRule
    Properties:
      Cluster:
        'Fn::ImportValue': !Sub "${EnvironmentName}:ECSCluster"
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 100
      DesiredCount: 1
      LaunchType: EC2
      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: 9080
          TargetGroupArn: !Ref WebTargetGroup

  ### tester
  TesterService:
    Type: 'AWS::ECS::Service'
    Condition: ShouldDeployTester
    Properties:
      Cluster:
        'Fn::ImportValue': !Sub "${EnvironmentName}:ECSCluster"
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 100
      DesiredCount: 1
      LaunchType: EC2
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: DISABLED
          SecurityGroups:
            - 'Fn::ImportValue': !Sub "${EnvironmentName}:ECSServiceSecurityGroup"
          Subnets: 
            - 'Fn::ImportValue': !Sub "${EnvironmentName}:PrivateSubnet1"
            - 'Fn::ImportValue': !Sub "${EnvironmentName}:PrivateSubnet2"
      TaskDefinition: { Ref: TesterTaskDefinition }

  TesterTaskDefinition:
    Type: 'AWS::ECS::TaskDefinition'
    Condition: ShouldDeployTester
    Properties:
      ContainerDefinitions:
        - Name: "app"
          Image: "tstrohmeier/alpine-infinite-curl"
          Essential: true
          Command:
            - !Sub "-h http://colorgateway.${ECSServicesDomain}:9080/color"
          LogConfiguration:
            LogDriver: "awslogs"
            Options:
              awslogs-group:
                'Fn::ImportValue': !Sub "${EnvironmentName}:ECSServiceLogGroup"
              awslogs-region: { Ref: "AWS::Region" }
              awslogs-stream-prefix: "tester-app"
      ExecutionRoleArn:
        'Fn::ImportValue': !Sub "${EnvironmentName}:TaskExecutionIamRoleArn"
      TaskRoleArn:
        'Fn::ImportValue': !Sub "${EnvironmentName}:TaskIamRoleArn"
      NetworkMode: "awsvpc"
      Memory: 256

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

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

  TcpEchoTaskDefinition:
    Type: 'AWS::ECS::TaskDefinition'
    Properties:
      ContainerDefinitions:
        - Name: "app"
          Image: "cjimti/go-echo"
          Essential: true
          LogConfiguration:
            LogDriver: "awslogs"
            Options:
              awslogs-group:
                'Fn::ImportValue': !Sub "${EnvironmentName}:ECSServiceLogGroup"
              awslogs-region: { Ref: "AWS::Region" }
              awslogs-stream-prefix: "tcpecho-app"
          PortMappings:
            - ContainerPort: 2701
              HostPort: 2701
              Protocol: "tcp"
          Environment:
            - Name: "TCP_PORT"
              Value: "2701"
            - Name: "NODE_NAME"
              Value: !Sub "mesh/${AppMeshMeshName}/virtualNode/tcpecho-vn"
      ExecutionRoleArn:
        'Fn::ImportValue': !Sub "${EnvironmentName}:TaskExecutionIamRoleArn"
      TaskRoleArn:
        'Fn::ImportValue': !Sub "${EnvironmentName}:TaskIamRoleArn"
      NetworkMode: "awsvpc"
      Memory: 256

  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: 6
      HealthCheckPath: /ping
      HealthCheckProtocol: HTTP
      HealthCheckTimeoutSeconds: 5
      HealthyThresholdCount: 2
      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"
  
  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: 1

Outputs: 

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