<commit_before># stacks/apps/the-castle.yml
# 400A
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31

Description: >-
  Creates an ECS service for The Castle (legacy), along with target group and
  listener rule for the shared ALB.

Parameters:
  kWebContainerName:
    Type: String
    Default: thecastle-web
  kWorkerContainerName:
    Type: String
    Default: thecastle-worker
  kWebApplicationPort:
    Type: Number
    Default: 3000
  kLogsVolumeName:
    Type: String
    Default: logs-fs
  #######
  RootStackName: { Type: String }
  RootStackId: { Type: String }
  EnvironmentType: { Type: String }
  EnvironmentTypeAbbreviation: { Type: String }
  RegionMode: { Type: String }
  CloudWatchAlarmTaggerServiceToken: { Type: String }
  CloudWatchLogGroupTaggerServiceToken: { Type: String }
  VpcId: { Type: AWS::EC2::VPC::Id }
  EcsClusterArn: { Type: String }
  AlbFullName: { Type: String }
  AlbHttpsListenerArn: { Type: String }
  AlbInsecureHttpListenerArn: { Type: String }
  AlbListenerRulePriorityPrefix: { Type: String }
  TheCountLogsFileSystemId: { Type: String }
  EcrImageTag: { Type: String }
  SecretsStackName: { Type: String }
  SecretsVersion: { Type: String }
  SecretsBase: { Type: String }
  NewRelicApiKeyPrxLite: { Type: String }
  SharedAuroraMysqlEndpoint: { Type: String }
  SharedAuroraMysqlPort: { Type: String }

Conditions:
  IsProduction: !Equals [!Ref EnvironmentType, Production]
  IsPrimaryRegion: !Equals [!Ref RegionMode, Primary]
  HasAuroraEndpoint: !Not [!Equals [!Ref SharedAuroraMysqlEndpoint, ""]]
  EnableWorkers: !And [!Condition HasAuroraEndpoint, !Condition IsPrimaryRegion]

Resources:
  HostHeaderListenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Actions:
        - TargetGroupArn: !Ref TargetGroup
          Type: forward
      Conditions:
        - Field: host-header
          Values:
            - thecastle.*
      ListenerArn: !Ref AlbHttpsListenerArn
      Priority: !Join ["", [!Ref AlbListenerRulePriorityPrefix, "00"]]
  InsecureHttpHostHeaderListenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Actions:
        - TargetGroupArn: !Ref TargetGroup
          Type: forward
      Conditions:
        - Field: host-header
          Values:
            - thecastle.*
      ListenerArn: !Ref AlbInsecureHttpListenerArn
      Priority: !Join ["", [!Ref AlbListenerRulePriorityPrefix, "00"]]

  TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 15
      HealthCheckPath: /login
      HealthCheckTimeoutSeconds: 5
      HealthyThresholdCount: 3
      Port: 80
      Protocol: HTTP
      TargetGroupAttributes:
        - Key: deregistration_delay.timeout_seconds
          Value: "15"
      Tags:
        - { Key: Name, Value: !Sub "${RootStackName}_the-castle" }
        - { Key: prx:meta:tagging-version, Value: "2021-04-07" }
        - { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
        - { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
        - { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
        - { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
        - { Key: prx:ops:environment, Value: !Ref EnvironmentType }
        - { Key: prx:dev:application, Value: The Castle }
      TargetType: instance
      UnhealthyThresholdCount: 3
      VpcId: !Ref VpcId
  TargetGroupHttp5xxAlarm:
    Type: AWS::CloudWatch::Alarm
    Condition: IsProduction
    Properties:
      AlarmName: !Sub ERROR [The Castle] Web server <${EnvironmentTypeAbbreviation}> RETURNING 5XX ERRORS (${RootStackName})
      AlarmDescription: !Sub >-
        ${EnvironmentType} The Castle's Rails server is returning 5XX errors
        from the ECS service to the load balancer.
      ComparisonOperator: GreaterThanThreshold
      Dimensions:
        - Name: LoadBalancer
          Value: !Ref AlbFullName
        - Name: TargetGroup
          Value: !GetAtt TargetGroup.TargetGroupFullName
      EvaluationPeriods: 1
      MetricName: HTTPCode_Target_5XX_Count
      Namespace: AWS/ApplicationELB
      Period: 60
      Statistic: Sum
      Threshold: 0
      TreatMissingData: notBreaching
  TargetGroupHttp5xxAlarmTags:
    Type: Custom::CloudWatchAlarmTags
    Condition: IsProduction
    Properties:
      ServiceToken: !Ref CloudWatchAlarmTaggerServiceToken
      AlarmArn: !GetAtt TargetGroupHttp5xxAlarm.Arn
      Tags:
        - { Key: prx:meta:tagging-version, Value: "2021-04-07" }
        - { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
        - { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
        - { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
        - { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
        - { Key: prx:ops:environment, Value: !Ref EnvironmentType }
        - { Key: prx:ops:cloudwatch-log-group-name, Value: !Ref WebTaskLogGroup }
        - { Key: prx:dev:application, Value: The Castle }

  ExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: ecs-tasks.amazonaws.com
        Version: "2012-10-17"
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
      Tags:
        - { Key: prx:meta:tagging-version, Value: "2021-04-07" }
        - { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
        - { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
        - { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
        - { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
        - { Key: prx:ops:environment, Value: !Ref EnvironmentType }
        - { Key: prx:dev:application, Value: The Castle }
  TaskRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: ecs-tasks.amazonaws.com
        Version: "2012-10-17"
      ManagedPolicyArns:
        - Fn::ImportValue: !Sub ${SecretsStackName}-SecretsInstanceDecryptPolicyArn
        - Fn::ImportValue: !Sub ${SecretsStackName}-SecretsInstanceAccessPolicyArn
      Tags:
        - { Key: prx:meta:tagging-version, Value: "2021-04-07" }
        - { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
        - { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
        - { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
        - { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
        - { Key: prx:ops:environment, Value: !Ref EnvironmentType }
        - { Key: prx:dev:application, Value: The Castle }

  WebEcsService:
    Type: AWS::ECS::Service
    Condition: HasAuroraEndpoint # See README
    Properties:
      Cluster: !Ref EcsClusterArn
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 50
      DesiredCount: !If [IsProduction, 0, 1]
      EnableECSManagedTags: true
      LoadBalancers:
        - ContainerName: !Ref kWebContainerName
          ContainerPort: !Ref kWebApplicationPort
          TargetGroupArn: !Ref TargetGroup
      PropagateTags: TASK_DEFINITION
      Tags:
        - { Key: prx:meta:tagging-version, Value: "2021-04-07" }
        - { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
        - { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
        - { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
        - { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
        - { Key: prx:ops:environment, Value: !Ref EnvironmentType }
        - { Key: prx:dev:application, Value: The Castle }
      TaskDefinition: !Ref WebTaskDefinition
  WebTaskLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      RetentionInDays: 14
  WebTaskLogGroupTags:
    Type: Custom::CloudWatchLogGroupTags
    Properties:
      ServiceToken: !Ref CloudWatchLogGroupTaggerServiceToken
      LogGroupName: !Ref WebTaskLogGroup
      Tags:
        - { Key: prx:meta:tagging-version, Value: "2021-04-07" }
        - { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
        - { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
        - { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
        - { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
        - { Key: prx:ops:environment, Value: !Ref EnvironmentType }
        - { Key: prx:dev:application, Value: The Castle }
  WebTaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      ContainerDefinitions:
        - Cpu: !If [IsProduction, 100, 64]
          Environment:
            - Name: APP_NAME
              Value: thecastle
            - Name: APP_ENV
              Value: !Ref EnvironmentTypeAbbreviation
            - Name: AWS_SECRETS_BASE
              Value: !Ref SecretsBase
            - Name: AWS_SECRETS_VERSION
              Value: !Ref SecretsVersion
            - Name: AWS_DEFAULT_REGION
              Value: !Ref AWS::Region
            - Name: NEW_RELIC_KEY
              Value: !Ref NewRelicApiKeyPrxLite
            - Name: NEW_RELIC_NAME
              Value: !If [IsProduction, The Castle Production, The Castle Staging]
            - Name: DB_PORT_3306_TCP_ADDR
              Value: !Ref SharedAuroraMysqlEndpoint
            - Name: DB_PORT_3306_TCP_PORT
              Value: !Ref SharedAuroraMysqlPort
          Essential: true
          Image: !Ref EcrImageTag
          LinuxParameters:
            InitProcessEnabled: true
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-group: !Ref WebTaskLogGroup
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: ecs
          Memory: !If [IsProduction, 400, 200]
          MountPoints:
            # This matches the default where the app expects count files
            # Override in secrets: COUNT_FILES=/app/count_files
            - ContainerPath: /app/count_files
              SourceVolume: !Ref kLogsVolumeName
          Name: !Ref kWebContainerName
          PortMappings:
            - ContainerPort: !Ref kWebApplicationPort
              HostPort: 0
      ExecutionRoleArn: !GetAtt ExecutionRole.Arn
      NetworkMode: bridge
      Tags:
        - { Key: prx:meta:tagging-version, Value: "2021-04-07" }
        - { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
        - { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
        - { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
        - { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
        - { Key: prx:ops:environment, Value: !Ref EnvironmentType }
        - { Key: prx:dev:application, Value: The Castle }
      TaskRoleArn: !GetAtt TaskRole.Arn
      Volumes:
        - EFSVolumeConfiguration:
            FilesystemId: !Ref TheCountLogsFileSystemId
          Name: !Ref kLogsVolumeName

  ### Add in the scheduled worker
  WorkerTaskLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      RetentionInDays: 14
  WorkerTaskLogGroupTags:
    Type: Custom::CloudWatchLogGroupTags
    Properties:
      ServiceToken: !Ref CloudWatchLogGroupTaggerServiceToken
      LogGroupName: !Ref WorkerTaskLogGroup
      Tags:
        - { Key: prx:meta:tagging-version, Value: "2021-04-07" }
        - { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
        - { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
        - { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
        - { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
        - { Key: prx:ops:environment, Value: !Ref EnvironmentType }
        - { Key: prx:dev:application, Value: The Castle }
  WorkerTaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      ContainerDefinitions:
        - Command:
            - worker
          Cpu: !If [IsProduction, 200, 128]
          Environment:
            - Name: APP_NAME
              Value: thecastle
            - Name: APP_ENV
              Value: !Ref EnvironmentTypeAbbreviation
            - Name: AWS_SECRETS_BASE
              Value: !Ref SecretsBase
            - Name: AWS_SECRETS_VERSION
              Value: !Ref SecretsVersion
            - Name: AWS_DEFAULT_REGION
              Value: !Ref AWS::Region
            - Name: NEW_RELIC_KEY
              Value: !Ref NewRelicApiKeyPrxLite
            - Name: NEW_RELIC_NAME
              Value: !If [IsProduction, The Castle Production, The Castle Staging]
            - Name: DB_PORT_3306_TCP_ADDR
              Value: !Ref SharedAuroraMysqlEndpoint
            - Name: DB_PORT_3306_TCP_PORT
              Value: !Ref SharedAuroraMysqlPort
          Essential: true
          Image: !Ref EcrImageTag
          LinuxParameters:
            InitProcessEnabled: true
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-group: !Ref WorkerTaskLogGroup
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: ecs
          Memory: !If [IsProduction, 2000, 1000]
          MemoryReservation: !If [IsProduction, 1000, 500]
          MountPoints:
            # This matches the default where the app expects count files
            # Override in secrets: COUNT_FILES=/app/count_files
            - ContainerPath: /app/count_files
              SourceVolume: !Ref kLogsVolumeName
          Name: !Ref kWorkerContainerName
          PortMappings:
            - ContainerPort: !Ref kWebApplicationPort
              HostPort: 0
      ExecutionRoleArn: !GetAtt ExecutionRole.Arn
      NetworkMode: bridge
      Tags:
        - { Key: prx:meta:tagging-version, Value: "2021-04-07" }
        - { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
        - { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
        - { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
        - { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
        - { Key: prx:ops:environment, Value: !Ref EnvironmentType }
        - { Key: prx:dev:application, Value: The Castle }
      TaskRoleArn: !GetAtt TaskRole.Arn
      Volumes:
        - EFSVolumeConfiguration:
            FilesystemId: !Ref TheCountLogsFileSystemId
          Name: !Ref kLogsVolumeName
  WorkerEventsRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: events.amazonaws.com
        Version: "2012-10-17"
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceEventsRole
      Tags:
        - { Key: prx:meta:tagging-version, Value: "2021-04-07" }<commit_msg>Set the correct root dir to the correct EFS path<commit_after># stacks/apps/the-castle.yml
# 400A
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31

Description: >-
  Creates an ECS service for The Castle (legacy), along with target group and
  listener rule for the shared ALB.

Parameters:
  kWebContainerName:
    Type: String
    Default: thecastle-web
  kWorkerContainerName:
    Type: String
    Default: thecastle-worker
  kWebApplicationPort:
    Type: Number
    Default: 3000
  kLogsVolumeName:
    Type: String
    Default: logs-fs
  #######
  RootStackName: { Type: String }
  RootStackId: { Type: String }
  EnvironmentType: { Type: String }
  EnvironmentTypeAbbreviation: { Type: String }
  RegionMode: { Type: String }
  CloudWatchAlarmTaggerServiceToken: { Type: String }
  CloudWatchLogGroupTaggerServiceToken: { Type: String }
  VpcId: { Type: AWS::EC2::VPC::Id }
  EcsClusterArn: { Type: String }
  AlbFullName: { Type: String }
  AlbHttpsListenerArn: { Type: String }
  AlbInsecureHttpListenerArn: { Type: String }
  AlbListenerRulePriorityPrefix: { Type: String }
  TheCountLogsFileSystemId: { Type: String }
  EcrImageTag: { Type: String }
  SecretsStackName: { Type: String }
  SecretsVersion: { Type: String }
  SecretsBase: { Type: String }
  NewRelicApiKeyPrxLite: { Type: String }
  SharedAuroraMysqlEndpoint: { Type: String }
  SharedAuroraMysqlPort: { Type: String }

Conditions:
  IsProduction: !Equals [!Ref EnvironmentType, Production]
  IsPrimaryRegion: !Equals [!Ref RegionMode, Primary]
  HasAuroraEndpoint: !Not [!Equals [!Ref SharedAuroraMysqlEndpoint, ""]]
  EnableWorkers: !And [!Condition HasAuroraEndpoint, !Condition IsPrimaryRegion]

Resources:
  HostHeaderListenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Actions:
        - TargetGroupArn: !Ref TargetGroup
          Type: forward
      Conditions:
        - Field: host-header
          Values:
            - thecastle.*
      ListenerArn: !Ref AlbHttpsListenerArn
      Priority: !Join ["", [!Ref AlbListenerRulePriorityPrefix, "00"]]
  InsecureHttpHostHeaderListenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Properties:
      Actions:
        - TargetGroupArn: !Ref TargetGroup
          Type: forward
      Conditions:
        - Field: host-header
          Values:
            - thecastle.*
      ListenerArn: !Ref AlbInsecureHttpListenerArn
      Priority: !Join ["", [!Ref AlbListenerRulePriorityPrefix, "00"]]

  TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      HealthCheckIntervalSeconds: 15
      HealthCheckPath: /login
      HealthCheckTimeoutSeconds: 5
      HealthyThresholdCount: 3
      Port: 80
      Protocol: HTTP
      TargetGroupAttributes:
        - Key: deregistration_delay.timeout_seconds
          Value: "15"
      Tags:
        - { Key: Name, Value: !Sub "${RootStackName}_the-castle" }
        - { Key: prx:meta:tagging-version, Value: "2021-04-07" }
        - { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
        - { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
        - { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
        - { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
        - { Key: prx:ops:environment, Value: !Ref EnvironmentType }
        - { Key: prx:dev:application, Value: The Castle }
      TargetType: instance
      UnhealthyThresholdCount: 3
      VpcId: !Ref VpcId
  TargetGroupHttp5xxAlarm:
    Type: AWS::CloudWatch::Alarm
    Condition: IsProduction
    Properties:
      AlarmName: !Sub ERROR [The Castle] Web server <${EnvironmentTypeAbbreviation}> RETURNING 5XX ERRORS (${RootStackName})
      AlarmDescription: !Sub >-
        ${EnvironmentType} The Castle's Rails server is returning 5XX errors
        from the ECS service to the load balancer.
      ComparisonOperator: GreaterThanThreshold
      Dimensions:
        - Name: LoadBalancer
          Value: !Ref AlbFullName
        - Name: TargetGroup
          Value: !GetAtt TargetGroup.TargetGroupFullName
      EvaluationPeriods: 1
      MetricName: HTTPCode_Target_5XX_Count
      Namespace: AWS/ApplicationELB
      Period: 60
      Statistic: Sum
      Threshold: 0
      TreatMissingData: notBreaching
  TargetGroupHttp5xxAlarmTags:
    Type: Custom::CloudWatchAlarmTags
    Condition: IsProduction
    Properties:
      ServiceToken: !Ref CloudWatchAlarmTaggerServiceToken
      AlarmArn: !GetAtt TargetGroupHttp5xxAlarm.Arn
      Tags:
        - { Key: prx:meta:tagging-version, Value: "2021-04-07" }
        - { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
        - { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
        - { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
        - { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
        - { Key: prx:ops:environment, Value: !Ref EnvironmentType }
        - { Key: prx:ops:cloudwatch-log-group-name, Value: !Ref WebTaskLogGroup }
        - { Key: prx:dev:application, Value: The Castle }

  ExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: ecs-tasks.amazonaws.com
        Version: "2012-10-17"
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
      Tags:
        - { Key: prx:meta:tagging-version, Value: "2021-04-07" }
        - { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
        - { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
        - { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
        - { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
        - { Key: prx:ops:environment, Value: !Ref EnvironmentType }
        - { Key: prx:dev:application, Value: The Castle }
  TaskRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: ecs-tasks.amazonaws.com
        Version: "2012-10-17"
      ManagedPolicyArns:
        - Fn::ImportValue: !Sub ${SecretsStackName}-SecretsInstanceDecryptPolicyArn
        - Fn::ImportValue: !Sub ${SecretsStackName}-SecretsInstanceAccessPolicyArn
      Tags:
        - { Key: prx:meta:tagging-version, Value: "2021-04-07" }
        - { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
        - { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
        - { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
        - { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
        - { Key: prx:ops:environment, Value: !Ref EnvironmentType }
        - { Key: prx:dev:application, Value: The Castle }

  WebEcsService:
    Type: AWS::ECS::Service
    Condition: HasAuroraEndpoint # See README
    Properties:
      Cluster: !Ref EcsClusterArn
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 50
      DesiredCount: !If [IsProduction, 0, 1]
      EnableECSManagedTags: true
      LoadBalancers:
        - ContainerName: !Ref kWebContainerName
          ContainerPort: !Ref kWebApplicationPort
          TargetGroupArn: !Ref TargetGroup
      PropagateTags: TASK_DEFINITION
      Tags:
        - { Key: prx:meta:tagging-version, Value: "2021-04-07" }
        - { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
        - { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
        - { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
        - { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
        - { Key: prx:ops:environment, Value: !Ref EnvironmentType }
        - { Key: prx:dev:application, Value: The Castle }
      TaskDefinition: !Ref WebTaskDefinition
  WebTaskLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      RetentionInDays: 14
  WebTaskLogGroupTags:
    Type: Custom::CloudWatchLogGroupTags
    Properties:
      ServiceToken: !Ref CloudWatchLogGroupTaggerServiceToken
      LogGroupName: !Ref WebTaskLogGroup
      Tags:
        - { Key: prx:meta:tagging-version, Value: "2021-04-07" }
        - { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
        - { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
        - { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
        - { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
        - { Key: prx:ops:environment, Value: !Ref EnvironmentType }
        - { Key: prx:dev:application, Value: The Castle }
  WebTaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      ContainerDefinitions:
        - Cpu: !If [IsProduction, 100, 64]
          Environment:
            - Name: APP_NAME
              Value: thecastle
            - Name: APP_ENV
              Value: !Ref EnvironmentTypeAbbreviation
            - Name: AWS_SECRETS_BASE
              Value: !Ref SecretsBase
            - Name: AWS_SECRETS_VERSION
              Value: !Ref SecretsVersion
            - Name: AWS_DEFAULT_REGION
              Value: !Ref AWS::Region
            - Name: NEW_RELIC_KEY
              Value: !Ref NewRelicApiKeyPrxLite
            - Name: NEW_RELIC_NAME
              Value: !If [IsProduction, The Castle Production, The Castle Staging]
            - Name: DB_PORT_3306_TCP_ADDR
              Value: !Ref SharedAuroraMysqlEndpoint
            - Name: DB_PORT_3306_TCP_PORT
              Value: !Ref SharedAuroraMysqlPort
          Essential: true
          Image: !Ref EcrImageTag
          LinuxParameters:
            InitProcessEnabled: true
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-group: !Ref WebTaskLogGroup
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: ecs
          Memory: !If [IsProduction, 400, 200]
          MountPoints:
            # This matches the default where the app expects count files
            # Override in secrets: COUNT_FILES=/app/count_files
            - ContainerPath: /app/count_files
              SourceVolume: !Ref kLogsVolumeName
          Name: !Ref kWebContainerName
          PortMappings:
            - ContainerPort: !Ref kWebApplicationPort
              HostPort: 0
      ExecutionRoleArn: !GetAtt ExecutionRole.Arn
      NetworkMode: bridge
      Tags:
        - { Key: prx:meta:tagging-version, Value: "2021-04-07" }
        - { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
        - { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
        - { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
        - { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
        - { Key: prx:ops:environment, Value: !Ref EnvironmentType }
        - { Key: prx:dev:application, Value: The Castle }
      TaskRoleArn: !GetAtt TaskRole.Arn
      Volumes:
        - EFSVolumeConfiguration:
            FilesystemId: !Ref TheCountLogsFileSystemId
            RootDirectory: "/app/count_files/"
          Name: !Ref kLogsVolumeName

  ### Add in the scheduled worker
  WorkerTaskLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      RetentionInDays: 14
  WorkerTaskLogGroupTags:
    Type: Custom::CloudWatchLogGroupTags
    Properties:
      ServiceToken: !Ref CloudWatchLogGroupTaggerServiceToken
      LogGroupName: !Ref WorkerTaskLogGroup
      Tags:
        - { Key: prx:meta:tagging-version, Value: "2021-04-07" }
        - { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
        - { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
        - { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
        - { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
        - { Key: prx:ops:environment, Value: !Ref EnvironmentType }
        - { Key: prx:dev:application, Value: The Castle }
  WorkerTaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      ContainerDefinitions:
        - Command:
            - worker
          Cpu: !If [IsProduction, 200, 128]
          Environment:
            - Name: APP_NAME
              Value: thecastle
            - Name: APP_ENV
              Value: !Ref EnvironmentTypeAbbreviation
            - Name: AWS_SECRETS_BASE
              Value: !Ref SecretsBase
            - Name: AWS_SECRETS_VERSION
              Value: !Ref SecretsVersion
            - Name: AWS_DEFAULT_REGION
              Value: !Ref AWS::Region
            - Name: NEW_RELIC_KEY
              Value: !Ref NewRelicApiKeyPrxLite
            - Name: NEW_RELIC_NAME
              Value: !If [IsProduction, The Castle Production, The Castle Staging]
            - Name: DB_PORT_3306_TCP_ADDR
              Value: !Ref SharedAuroraMysqlEndpoint
            - Name: DB_PORT_3306_TCP_PORT
              Value: !Ref SharedAuroraMysqlPort
          Essential: true
          Image: !Ref EcrImageTag
          LinuxParameters:
            InitProcessEnabled: true
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-group: !Ref WorkerTaskLogGroup
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: ecs
          Memory: !If [IsProduction, 2000, 1000]
          MemoryReservation: !If [IsProduction, 1000, 500]
          MountPoints:
            # This matches the default where the app expects count files
            # Override in secrets: COUNT_FILES=/app/count_files
            - ContainerPath: /app/count_files
              SourceVolume: !Ref kLogsVolumeName
          Name: !Ref kWorkerContainerName
          PortMappings:
            - ContainerPort: !Ref kWebApplicationPort
              HostPort: 0
      ExecutionRoleArn: !GetAtt ExecutionRole.Arn
      NetworkMode: bridge
      Tags:
        - { Key: prx:meta:tagging-version, Value: "2021-04-07" }
        - { Key: prx:cloudformation:stack-name, Value: !Ref AWS::StackName }
        - { Key: prx:cloudformation:stack-id, Value: !Ref AWS::StackId }
        - { Key: prx:cloudformation:root-stack-name, Value: !Ref RootStackName }
        - { Key: prx:cloudformation:root-stack-id, Value: !Ref RootStackId }
        - { Key: prx:ops:environment, Value: !Ref EnvironmentType }
        - { Key: prx:dev:application, Value: The Castle }
      TaskRoleArn: !GetAtt TaskRole.Arn
      Volumes:
        - EFSVolumeConfiguration:
            FilesystemId: !Ref TheCountLogsFileSystemId
            RootDirectory: "/app/count_files/"
          Name: !Ref kLogsVolumeName
  WorkerEventsRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: events.amazonaws.com
        Version: "2012-10-17"
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceEventsRole
      Tags:
        - { Key: prx:meta:tagging-version, Value: "2021-04-07" }
{'fraction_non_alphanumeric': 0.09731752963194011, 'fraction_numerical': 0.014183931444331352, 'mean_word_length': 2.5325910461609835, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6407972', 'n_tokens_mistral': 9485, 'n_tokens_neox': 8990, 'n_words': 2041}