AWSTemplateFormatVersion: '2010-09-09'
Description: >-
  Account-neutral EG334S internet-facing Application Load Balancer for the
  eu-west-1 hub service. Creates the required second-AZ public subnet. The live
  hub EC2 instance and the separate Auto Scaling group provide one normally
  running application target in each Availability Zone.

Parameters:
  VpcId:
    Type: AWS::EC2::VPC::Id
    Description: Existing EG334S Ireland hub VPC.
  PublicSubnetA:
    Type: AWS::EC2::Subnet::Id
    Description: Existing public subnet in the first Availability Zone.
  HubRouteTableId:
    Type: String
    Description: Existing Ireland public route table associated with both ALB subnets.
  SecondarySubnetCidr:
    Type: String
    Default: 10.1.2.0/24
    AllowedPattern: '^10\.1\.[0-9]{1,3}\.0/24$'
    Description: Non-overlapping public subnet created in the second Ireland Availability Zone.
  PrimaryInstanceId:
    Type: AWS::EC2::Instance::Id
    Description: Existing live EG334S Ireland hub EC2 instance.
  HubSecurityGroupId:
    Type: AWS::EC2::SecurityGroup::Id
    Description: Existing security group attached to the live and recovery hub instances.
  EnvironmentLabel:
    Type: String
    Default: SCHOOL-DEMO
    AllowedPattern: '[A-Za-z0-9 -]+'

Resources:
  SecondaryPublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VpcId
      CidrBlock: !Ref SecondarySubnetCidr
      AvailabilityZone: !Select [1, !GetAZs '']
      MapPublicIpOnLaunch: true
      Tags:
        - { Key: Name, Value: EG334S-hub-secondary-public-subnet }
        - { Key: Project, Value: EG334S }
        - { Key: Purpose, Value: ALB-and-Hub-Recovery }

  SecondarySubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref SecondaryPublicSubnet
      RouteTableId: !Ref HubRouteTableId

  AlbSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      # Keep the deployed description unchanged because EC2 treats it as immutable.
      GroupDescription: Public HTTP access to the EG334S demonstration ALB
      VpcId: !Ref VpcId
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
          Description: Public hub-service HTTP
      SecurityGroupEgress:
        - IpProtocol: -1
          CidrIp: 0.0.0.0/0
      Tags:
        - Key: Name
          Value: EG334S-hub-alb-sg
        - Key: Project
          Value: EG334S

  HubHttpFromAlb:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: !Ref HubSecurityGroupId
      IpProtocol: tcp
      FromPort: 80
      ToPort: 80
      SourceSecurityGroupId: !Ref AlbSecurityGroup
      Description: ALB health checks and hub application traffic

  TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      VpcId: !Ref VpcId
      Protocol: HTTP
      Port: 80
      TargetType: instance
      HealthCheckEnabled: true
      HealthCheckPath: /
      HealthCheckProtocol: HTTP
      HealthyThresholdCount: 2
      UnhealthyThresholdCount: 2
      HealthCheckIntervalSeconds: 15
      HealthCheckTimeoutSeconds: 5
      Matcher:
        HttpCode: '200'
      Targets:
        - Id: !Ref PrimaryInstanceId
          Port: 80
      Tags:
        - Key: Project
          Value: EG334S

  LoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: !Sub '${AWS::StackName}-alb'
      Type: application
      Scheme: internet-facing
      IpAddressType: ipv4
      SecurityGroups:
        - !Ref AlbSecurityGroup
      Subnets:
        - !Ref PublicSubnetA
        - !Ref SecondaryPublicSubnet
      LoadBalancerAttributes:
        - Key: deletion_protection.enabled
          Value: 'false'
        - Key: routing.http.drop_invalid_header_fields.enabled
          Value: 'true'
      Tags:
        - Key: Project
          Value: EG334S
        - Key: Environment
          Value: !Ref EnvironmentLabel

  Listener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      LoadBalancerArn: !Ref LoadBalancer
      Protocol: HTTP
      Port: 80
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref TargetGroup

  UnhealthyHostAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmDescription: One or more EG334S ALB targets are unhealthy
      Namespace: AWS/ApplicationELB
      MetricName: UnHealthyHostCount
      Dimensions:
        - Name: LoadBalancer
          Value: !GetAtt LoadBalancer.LoadBalancerFullName
        - Name: TargetGroup
          Value: !GetAtt TargetGroup.TargetGroupFullName
      Statistic: Maximum
      Period: 60
      EvaluationPeriods: 2
      DatapointsToAlarm: 2
      Threshold: 0
      ComparisonOperator: GreaterThanThreshold
      TreatMissingData: breaching

Outputs:
  SiteUrl:
    Description: Public URL for the existing EG334S Ireland hub service
    Value: !Sub 'http://${LoadBalancer.DNSName}'
  LoadBalancerDnsName:
    Value: !GetAtt LoadBalancer.DNSName
  PrimaryTargetInstanceId:
    Value: !Ref PrimaryInstanceId
  TargetGroupArn:
    Value: !Ref TargetGroup
  SecondaryPublicSubnetId:
    Description: Pass to hub-recovery-eu-west-1.yaml.
    Value: !Ref SecondaryPublicSubnet
