AWSTemplateFormatVersion: '2010-09-09'
Metadata:
  License: Apache-2.0
Description: 'AWS CloudFormation Sample Template AutoScalingMultiAZWithNotifications:
  Create a multi-az, load balanced and Auto Scaled sample web site running on an Apache
  Web Server. The application is configured to span all Availability Zones in the
  region and is Auto-Scaled based on the CPU utilization of the web servers. Notifications
  will be sent to the operator email address on scaling events. The instances are
  load balanced with a simple health check against the default web page. **WARNING**
  This template creates one or more Amazon EC2 instances and an Elastic Load Balancer.
  You will be billed for the AWS resources used if you create a stack from this template.'
Parameters:
  InstanceType:
    Description: WebServer EC2 instance type
    Type: String
    Default: t2.small
    AllowedValues: [t1.micro, t2.nano, t2.micro, t2.small, t2.medium, t2.large, m1.small,
      m1.medium, m1.large, m1.xlarge, m2.xlarge, m2.2xlarge, m2.4xlarge, m3.medium,
      m3.large, m3.xlarge, m3.2xlarge, m4.large, m4.xlarge, m4.2xlarge, m4.4xlarge,
      m4.10xlarge, c1.medium, c1.xlarge, c3.large, c3.xlarge, c3.2xlarge, c3.4xlarge,
      c3.8xlarge, c4.large, c4.xlarge, c4.2xlarge, c4.4xlarge, c4.8xlarge, g2.2xlarge,
      g2.8xlarge, r3.large, r3.xlarge, r3.2xlarge, r3.4xlarge, r3.8xlarge, i2.xlarge,
      i2.2xlarge, i2.4xlarge, i2.8xlarge, d2.xlarge, d2.2xlarge, d2.4xlarge, d2.8xlarge,
      hi1.4xlarge, hs1.8xlarge, cr1.8xlarge, cc2.8xlarge, cg1.4xlarge]
    ConstraintDescription: must be a valid EC2 instance type.
  OperatorEMail:
    Description: EMail address to notify if there are any scaling operations
    Type: String
    AllowedPattern: ([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)
    ConstraintDescription: must be a valid email address.
  KeyName:
    Description: The EC2 Key Pair to allow SSH access to the instances
    Type: AWS::EC2::KeyPair::KeyName
    ConstraintDescription: must be the name of an existing EC2 KeyPair.
  SSHLocation:
    Description: The IP address range that can be used to SSH to the EC2 instances
    Type: String
    MinLength: 9
    MaxLength: 18
    Default: 0.0.0.0/0
    AllowedPattern: (\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
Mappings:
  Region2Examples:
    us-east-1:
      Examples: https://s3.amazonaws.com/cloudformation-examples-us-east-1
    us-west-2:
      Examples: https://s3-us-west-2.amazonaws.com/cloudformation-examples-us-west-2
    us-west-1:
      Examples: https://s3-us-west-1.amazonaws.com/cloudformation-examples-us-west-1
    eu-west-1:
      Examples: https://s3-eu-west-1.amazonaws.com/cloudformation-examples-eu-west-1
    eu-central-1:
      Examples: https://s3-eu-central-1.amazonaws.com/cloudformation-examples-eu-central-1
    ap-southeast-1:
      Examples: https://s3-ap-southeast-1.amazonaws.com/cloudformation-examples-ap-southeast-1
    ap-northeast-1:
      Examples: https://s3-ap-northeast-1.amazonaws.com/cloudformation-examples-ap-northeast-1
    ap-northeast-2:
      Examples: https://s3-ap-northeast-2.amazonaws.com/cloudformation-examples-ap-northeast-2
    ap-southeast-2:
      Examples: https://s3-ap-southeast-2.amazonaws.com/cloudformation-examples-ap-southeast-2
    ap-south-1:
      Examples: https://s3-ap-south-1.amazonaws.com/cloudformation-examples-ap-south-1
    us-east-2:
      Examples: https://s3-us-east-2.amazonaws.com/cloudformation-examples-us-east-2
    sa-east-1:
      Examples: https://s3-sa-east-1.amazonaws.com/cloudformation-examples-sa-east-1
    cn-north-1:
      Examples: https://s3.cn-north-1.amazonaws.com.cn/cloudformation-examples-cn-north-1
  AWSInstanceType2Arch:
    t1.micro:
      Arch: PV64
    t2.nano:
      Arch: HVM64
    t2.micro:
      Arch: HVM64
    t2.small:
      Arch: HVM64
    t2.medium:
      Arch: HVM64
    t2.large:
      Arch: HVM64
    m1.small:
      Arch: PV64
    m1.medium:
      Arch: PV64
    m1.large:
      Arch: PV64
    m1.xlarge:
      Arch: PV64
    m2.xlarge:
      Arch: PV64
    m2.2xlarge:
      Arch: PV64
    m2.4xlarge:
      Arch: PV64
    m3.medium:
      Arch: HVM64
    m3.large:
      Arch: HVM64
    m3.xlarge:
      Arch: HVM64
    m3.2xlarge:
      Arch: HVM64
    m4.large:
      Arch: HVM64
    m4.xlarge:
      Arch: HVM64
    m4.2xlarge:
      Arch: HVM64
    m4.4xlarge:
      Arch: HVM64
    m4.10xlarge:
      Arch: HVM64
    c1.medium:
      Arch: PV64
    c1.xlarge:
      Arch: PV64
    c3.large:
      Arch: HVM64
    c3.xlarge:
      Arch: HVM64
    c3.2xlarge:
      Arch: HVM64
    c3.4xlarge:
      Arch: HVM64
    c3.8xlarge:
      Arch: HVM64
    c4.large:
      Arch: HVM64
    c4.xlarge:
      Arch: HVM64
    c4.2xlarge:
      Arch: HVM64
    c4.4xlarge:
      Arch: HVM64
    c4.8xlarge:
      Arch: HVM64
    g2.2xlarge:
      Arch: HVMG2
    g2.8xlarge:
      Arch: HVMG2
    r3.large:
      Arch: HVM64
    r3.xlarge:
      Arch: HVM64
    r3.2xlarge:
      Arch: HVM64
    r3.4xlarge:
      Arch: HVM64
    r3.8xlarge:
      Arch: HVM64
    i2.xlarge:
      Arch: HVM64
    i2.2xlarge:
      Arch: HVM64
    i2.4xlarge:
      Arch: HVM64
    i2.8xlarge:
      Arch: HVM64
    d2.xlarge:
      Arch: HVM64
    d2.2xlarge:
      Arch: HVM64
    d2.4xlarge:
      Arch: HVM64
    d2.8xlarge:
      Arch: HVM64
    hi1.4xlarge:
      Arch: HVM64
    hs1.8xlarge:
      Arch: HVM64
    cr1.8xlarge:
      Arch: HVM64
    cc2.8xlarge:
      Arch: HVM64
  AWSInstanceType2NATArch:
    t1.micro:
      Arch: NATPV64
    t2.nano:
      Arch: NATHVM64
    t2.micro:
      Arch: NATHVM64
    t2.small:
      Arch: NATHVM64
    t2.medium:
      Arch: NATHVM64
    t2.large:
      Arch: NATHVM64
    m1.small:
      Arch: NATPV64
    m1.medium:
      Arch: NATPV64
    m1.large:
      Arch: NATPV64
    m1.xlarge:
      Arch: NATPV64
    m2.xlarge:
      Arch: NATPV64
    m2.2xlarge:
      Arch: NATPV64
    m2.4xlarge:
      Arch: NATPV64
    m3.medium:
      Arch: NATHVM64
    m3.large:
      Arch: NATHVM64
    m3.xlarge:
      Arch: NATHVM64
    m3.2xlarge:
      Arch: NATHVM64
    m4.large:
      Arch: NATHVM64
    m4.xlarge:
      Arch: NATHVM64
    m4.2xlarge:
      Arch: NATHVM64
    m4.4xlarge:
      Arch: NATHVM64
    m4.10xlarge:
      Arch: NATHVM64
    c1.medium:
      Arch: NATPV64
    c1.xlarge:
      Arch: NATPV64
    c3.large:
      Arch: NATHVM64
    c3.xlarge:
      Arch: NATHVM64
    c3.2xlarge:
      Arch: NATHVM64
    c3.4xlarge:
      Arch: NATHVM64
    c3.8xlarge:
      Arch: NATHVM64
    c4.large:
      Arch: NATHVM64
    c4.xlarge:
      Arch: NATHVM64
    c4.2xlarge:
      Arch: NATHVM64
    c4.4xlarge:
      Arch: NATHVM64
    c4.8xlarge:
      Arch: NATHVM64
    g2.2xlarge:
      Arch: NATHVMG2
    g2.8xlarge:
      Arch: NATHVMG2
    r3.large:
      Arch: NATHVM64
    r3.xlarge:
      Arch: NATHVM64
    r3.2xlarge:
      Arch: NATHVM64
    r3.4xlarge:
      Arch: NATHVM64
    r3.8xlarge:
      Arch: NATHVM64
    i2.xlarge:
      Arch: NATHVM64
    i2.2xlarge:
      Arch: NATHVM64
    i2.4xlarge:
      Arch: NATHVM64
    i2.8xlarge:
      Arch: NATHVM64
    d2.xlarge:
      Arch: NATHVM64
    d2.2xlarge:
      Arch: NATHVM64
    d2.4xlarge:
      Arch: NATHVM64
    d2.8xlarge:
      Arch: NATHVM64
    hi1.4xlarge:
      Arch: NATHVM64
    hs1.8xlarge:
      Arch: NATHVM64
    cr1.8xlarge:
      Arch: NATHVM64
    cc2.8xlarge:
      Arch: NATHVM64
  AWSRegionArch2AMI:
    us-east-1:
      PV64: ami-2a69aa47
      HVM64: ami-6869aa05
      HVMG2: ami-50b4f047
    us-west-2:
      PV64: ami-7f77b31f
      HVM64: ami-7172b611
      HVMG2: ami-002bf460
    us-west-1:
      PV64: ami-a2490dc2
      HVM64: ami-31490d51
      HVMG2: ami-699ad409
    eu-west-1:
      PV64: ami-4cdd453f
      HVM64: ami-f9dd458a
      HVMG2: ami-f0e0a483
    eu-central-1:
      PV64: ami-6527cf0a
      HVM64: ami-ea26ce85
      HVMG2: ami-d9d62ab6
    ap-northeast-1:
      PV64: ami-3e42b65f
      HVM64: ami-374db956
      HVMG2: ami-78ba6619
    ap-northeast-2:
      PV64: NOT_SUPPORTED
      HVM64: ami-2b408b45
      HVMG2: NOT_SUPPORTED
    ap-southeast-1:
      PV64: ami-df9e4cbc
      HVM64: ami-a59b49c6
      HVMG2: ami-56e84c35
    ap-southeast-2:
      PV64: ami-63351d00
      HVM64: ami-dc361ebf
      HVMG2: ami-2589b946
    ap-south-1:
      PV64: NOT_SUPPORTED
      HVM64: ami-ffbdd790
      HVMG2: ami-f7354198
    us-east-2:
      PV64: NOT_SUPPORTED
      HVM64: ami-f6035893
      HVMG2: NOT_SUPPORTED
    sa-east-1:
      PV64: ami-1ad34676
      HVM64: ami-6dd04501
      HVMG2: NOT_SUPPORTED
    cn-north-1:
      PV64: ami-77559f1a
      HVM64: ami-8e6aa0e3
      HVMG2: NOT_SUPPORTED
Resources:
  NotificationTopic:
    Type: AWS::SNS::Topic
    Properties:
      Subscription:
      - Endpoint: !Ref 'OperatorEMail'
        Protocol: email
  WebServerGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      AvailabilityZones: !GetAZs ''
      LaunchConfigurationName: !Ref 'LaunchConfig'
      MinSize: '1'
      MaxSize: '3'
      LoadBalancerNames: [!Ref 'ElasticLoadBalancer']
      NotificationConfigurations:
        - TopicARN: !Ref 'NotificationTopic'
          NotificationTypes: ['autoscaling:EC2_INSTANCE_LAUNCH', 'autoscaling:EC2_INSTANCE_LAUNCH_ERROR',
            'autoscaling:EC2_INSTANCE_TERMINATE', 'autoscaling:EC2_INSTANCE_TERMINATE_ERROR']
    CreationPolicy:
      ResourceSignal:
        Timeout: PT15M
        Count: 1
    UpdatePolicy:
      AutoScalingRollingUpdate:
        MinInstancesInService: 1
        MaxBatchSize: 1
        PauseTime: PT15M
        WaitOnResourceSignals: true
  LaunchConfig:
    Type: AWS::AutoScaling::LaunchConfiguration
    Metadata:
      Comment: Install a simple application
      AWS::CloudFormation::Init:
        config:
          packages:
            yum:
              httpd: []
          files:
            /var/www/html/index.html:
              content: !Join ['

                  ', [<img src=", !FindInMap [Region2Examples, !Ref 'AWS::Region',
                    Examples], /cloudformation_graphic.png" alt="AWS CloudFormation
                    Logo"/>, '<h1>Congratulations, you have successfully launched
                    the AWS CloudFormation sample.</h1>']]
              mode: '000644'
              owner: root
              group: root
            /etc/cfn/cfn-hup.conf:
              content: !Join ['', ['[main]

                    ', stack=, !Ref 'AWS::StackId', '

                    ', region=, !Ref 'AWS::Region', '

                    ']]
              mode: '000400'
              owner: root
              group: root
            /etc/cfn/hooks.d/cfn-auto-reloader.conf:
              content: !Join ['', ['[cfn-auto-reloader-hook]

                    ', 'triggers=post.update

                    ', 'path=Resources.LaunchConfig.Metadata.AWS::CloudFormation::Init

                    ', 'action=/opt/aws/bin/cfn-init -v ', '         --stack ', !Ref 'AWS::StackName',
                  '         --resource LaunchConfig ', '         --region ', !Ref 'AWS::Region',
                  '

                    ', 'runas=root

                    ']]
          services:
            sysvinit:
              httpd:
                enabled: true
                ensureRunning: true
              cfn-hup:
                enabled: true
                ensureRunning: true
                files: [/etc/cfn/cfn-hup.conf, /etc/cfn/hooks.d/cfn-auto-reloader.conf]
    Properties:
      KeyName: !Ref 'KeyName'
      ImageId: !FindInMap [AWSRegionArch2AMI, !Ref 'AWS::Region', !FindInMap [AWSInstanceType2Arch,
          !Ref 'InstanceType', Arch]]
      SecurityGroups: [!Ref 'InstanceSecurityGroup']
      InstanceType: !Ref 'InstanceType'
      UserData: !Base64
        Fn::Join:
        - ''
        - ['#!/bin/bash -xe

            ', 'yum update -y aws-cfn-bootstrap

            ', '/opt/aws/bin/cfn-init -v ', '         --stack ', !Ref 'AWS::StackName',
          '         --resource LaunchConfig ', '         --region ', !Ref 'AWS::Region',
          '

            ', '/opt/aws/bin/cfn-signal -e $? ', '         --stack ', !Ref 'AWS::StackName',
          '         --resource WebServerGroup ', '         --region ', !Ref 'AWS::Region',
          '

            ']
  WebServerScaleUpPolicy:
    Type: AWS::AutoScaling::ScalingPolicy
    Properties:
      AdjustmentType: ChangeInCapacity
      AutoScalingGroupName: !Ref 'WebServerGroup'
      Cooldown: '60'
      ScalingAdjustment: 1
  WebServerScaleDownPolicy:
    Type: AWS::AutoScaling::ScalingPolicy
    Properties:
      AdjustmentType: ChangeInCapacity
      AutoScalingGroupName: !Ref 'WebServerGroup'
      Cooldown: '60'
      ScalingAdjustment: -1
  CPUAlarmHigh:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmDescription: Scale-up if CPU > 90% for 10 minutes
      MetricName: CPUUtilization
      Namespace: AWS/EC2
      Statistic: Average
      Period: 300
      EvaluationPeriods: 2
      Threshold: 90
      AlarmActions: [!Ref 'WebServerScaleUpPolicy']
      Dimensions:
      - Name: AutoScalingGroupName
        Value: !Ref 'WebServerGroup'
      ComparisonOperator: GreaterThanThreshold
  CPUAlarmLow:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmDescription: Scale-down if CPU < 70% for 10 minutes
      MetricName: CPUUtilization
      Namespace: AWS/EC2
      Statistic: Average
      Period: 300
      EvaluationPeriods: 2
      Threshold: 70
      AlarmActions: [!Ref 'WebServerScaleDownPolicy']
      Dimensions:
      - Name: AutoScalingGroupName
        Value: !Ref 'WebServerGroup'
      ComparisonOperator: LessThanThreshold
  ElasticLoadBalancer:
    Type: AWS::ElasticLoadBalancing::LoadBalancer
    Properties:
      AvailabilityZones: !GetAZs ''
      CrossZone: true
      Listeners:
      - LoadBalancerPort: '80'
        InstancePort: '80'
        Protocol: HTTP
      HealthCheck:
        Target: HTTP:80/
        HealthyThreshold: '3'
        UnhealthyThreshold: '5'
        Interval: '30'
        Timeout: '5'
  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable SSH access and HTTP from the load balancer only
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 22
        ToPort: 22
        CidrIp: !Ref 'SSHLocation'
      - IpProtocol: tcp
        FromPort: 80
        ToPort: 80
        SourceSecurityGroupOwnerId: !GetAtt [ElasticLoadBalancer, SourceSecurityGroup.OwnerAlias]
        SourceSecurityGroupName: !GetAtt [ElasticLoadBalancer, SourceSecurityGroup.GroupName]
Outputs:
  URL:
    Description: The URL of the website
    Value: !Join ['', ['http://', !GetAtt [ElasticLoadBalancer, DNSName]]]