{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Description" : "Example stack for EIP Lookup Custom Resource Backend.",

    "Parameters" : {
        "KeyName" : {
            "Description" : "Name of an existing EC2 KeyPair to enable SSH access to the instances",
            "Type" : "String"
        },
        "InstanceType" : {
            "Description" : "Custom resource runner instance type",
            "Type" : "String",
            "Default" : "t1.micro",
            "AllowedValues" : [ "t1.micro","m1.small","m1.medium","m1.large","m1.xlarge","m2.xlarge","m2.2xlarge","m2.4xlarge","m3.xlarge","m3.2xlarge","c1.medium","c1.xlarge","cc1.4xlarge","cc2.8xlarge","cg1.4xlarge"],
            "ConstraintDescription" : "must be a valid EC2 instance type."
        },
        "MinSize" : {
            "Description" : "Minimum number of custom resource runners",
            "Type" : "Number",
            "MinValue" : "1",
            "Default" : "1",
            "ConstraintDescription" : "Must have at least one runner"
        },
        "MaxSize" : {
            "Description" : "Maximum number of custom resource runners",
            "Type" : "Number",
            "MinValue" : "1",
            "Default" : "1",
            "ConstraintDescription" : "Must have at least one runner"
        },
        "SSHLocation" : {
            "Description" : "The IP address range that can be used to SSH to the custom resource runners",
            "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."
        },
        "LookupEipScriptUrl" : {
            "Description" : "The URL of the lookup-eip.py script",
            "Type" : "String",
            "Default" : "https://raw.github.com/awslabs/aws-cfn-custom-resource-examples/master/examples/eip-lookup/impl/lookup-eip.py"
        }
    },

    "Mappings" : {
        "AwsRegionToAMI" : {
            "us-east-1" : { "id" : "ami-35792c5c" },
            "us-west-2" : { "id" : "ami-d03ea1e0" },
            "us-west-1" : { "id" : "ami-687b4f2d" },
            "eu-west-1" : { "id" : "ami-149f7863" },
            "ap-southeast-1" : { "id" : "ami-14f2b946" },
            "ap-northeast-1" : { "id" : "ami-3561fe34" },
            "ap-southeast-2" : { "id" : "ami-a148d59b" },
            "sa-east-1" : { "id" : "ami-9f6ec982" }
        }
    },

    "Resources" : {
        "CustomResourcePipeline" : {
            "Type" : "AWS::CloudFormation::Stack",
            "Properties" : {
                "TemplateURL" : "https://s3.amazonaws.com/cloudformation-examples/cr-backend-substack-template.template"
            }
        },

        "EipTable" : {
            "Type" : "AWS::DynamoDB::Table",
            "Properties" : {
                "KeySchema" : {
                    "HashKeyElement": {
                        "AttributeName" : "pool",
                        "AttributeType" : "S"
                    },
                    "RangeKeyElement" : {
                        "AttributeName" : "address",
                        "AttributeType" : "S"
                    }
                },
                "ProvisionedThroughput" : {
                    "ReadCapacityUnits" : "1",
                    "WriteCapacityUnits" : "3"
                }
            }
        },

        "RunnerRole" : {
            "Type" : "AWS::IAM::Role",
            "Properties" : {
                "AssumeRolePolicyDocument" : {
                    "Version": "2008-10-17",
                    "Statement": [{
                        "Effect": "Allow",
                        "Principal": {
                            "Service": [ "ec2.amazonaws.com" ]
                        },
                        "Action": [ "sts:AssumeRole" ]
                    }]
                },
                "Path" : "/",
                "Policies" : [
                    {
                        "PolicyName" : "CustomResourceRunner",
                        "PolicyDocument" : {
                            "Statement" : [
                                {
                                    "Effect" : "Allow",
                                    "Action" : ["sqs:ChangeMessageVisibility", "sqs:DeleteMessage", "sqs:ReceiveMessage"],
                                    "Resource" : { "Fn::GetAtt" : ["CustomResourcePipeline", "Outputs.CustomResourceQueueARN"] }
                                },
                                {
                                    "Effect" : "Allow",
                                    "Action" : ["dynamodb:PutItem"],
                                    "Resource" : { "Fn::Join" : ["", ["arn:aws:dynamodb:", {"Ref" : "AWS::Region"}, ":", {"Ref" : "AWS::AccountId"}, ":table/", { "Ref" : "EipTable" }]] }
                                },
                                {
                                    "Effect" : "Allow",
                                    "Action" : ["dynamodb:Query"],
                                    "Resource" : { "Fn::Join" : ["", ["arn:aws:dynamodb:", {"Ref" : "AWS::Region"}, ":", {"Ref" : "AWS::AccountId"}, ":table/", { "Ref" : "EipTable" }]] }
                                },
                                {
                                    "Effect" : "Allow",
                                    "Action" : ["dynamodb:GetItem"],
                                    "Resource" : { "Fn::Join" : ["", ["arn:aws:dynamodb:", {"Ref" : "AWS::Region"}, ":", {"Ref" : "AWS::AccountId"}, ":table/", { "Ref" : "EipTable" }]] }
                                }
                            ]
                        }
                    }
                ]
            }
        },

        "RunnerInstanceProfile" : {
            "Type" : "AWS::IAM::InstanceProfile",
            "Properties" : {
                "Path" : "/",
                "Roles" : [ { "Ref" : "RunnerRole" } ]
            }
        },

        "RunnerLaunchConfig" : {
            "Type" : "AWS::AutoScaling::LaunchConfiguration",
            "Properties" : {
                "IamInstanceProfile" : { "Ref" : "RunnerInstanceProfile" },
                "ImageId" : { "Fn::FindInMap" : ["AwsRegionToAMI", { "Ref" : "AWS::Region" }, "id"] },
                "InstanceType" : { "Ref" : "InstanceType" },
                "KeyName" : { "Ref" : "KeyName" },
                "SecurityGroups" : [ { "Ref" : "RunnerSecurityGroup" } ],
                "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
                    "#!/bin/bash -x\n",
                    "exec &> /home/ec2-user/userdata.log\n",
                    "/opt/aws/bin/cfn-init --region ", { "Ref" : "AWS::Region" }, " -s ", { "Ref" : "AWS::StackId" }, " -r RunnerLaunchConfig -v\n",
                    "/opt/aws/bin/cfn-signal -e $? ", { "Fn::Base64" : { "Ref" : "RunnerWaitConditionHandle" }}, "\n"
                ]] } }
            },
            "Metadata" : {
                "AWS::CloudFormation::Init" : {
                    "config" : {
                        "packages" : {
                            "rpm" : {
                                "aws-cfn-resource-bridge" : "https://s3.amazonaws.com/cloudformation-examples/aws-cfn-resource-bridge-0.1-4.noarch.rpm"
                            }
                        },
                        "files" : {
                            "/etc/cfn/bridge.d/eip-lookup.conf" : {
                                "content" : { "Fn::Join" : ["", [
                                    "[eip-lookup]\n",
                                    "resource_type=Custom::EipLookup\n",
                                    "queue_url=", { "Fn::GetAtt" : ["CustomResourcePipeline", "Outputs.CustomResourceQueueURL"] }, "\n",
                                    "timeout=60\n",
                                    "default_action=/home/ec2-user/lookup-eip.py -r ", { "Ref" : "AWS::Region" }, " -t ", { "Ref" : "EipTable" }
                                ]]}
                            },
                            "/home/ec2-user/lookup-eip.py" : {
                                "source" : { "Ref" : "LookupEipScriptUrl" },
                                "mode" : "000755",
                                "owner" : "ec2-user"
                            }
                        },
                        "services" : {
                            "sysvinit" : {
                                "cfn-resource-bridge" : {
                                    "enabled" : "true",
                                    "ensureRunning" : "true",
                                    "files" : ["/etc/cfn/bridge.d/eip-lookup.conf",
                                               "/home/ec2-user/lookup-eip.py"]
                                }
                            }
                        }
                    }
                }
            }
        },

        "RunnerAutoScalingGroup" : {
            "Type" : "AWS::AutoScaling::AutoScalingGroup",
            "Properties" : {
                "AvailabilityZones" : { "Fn::GetAZs" : ""},
                "LaunchConfigurationName" : { "Ref" : "RunnerLaunchConfig" },
                "MinSize" : { "Ref" : "MinSize" },
                "MaxSize" : { "Ref" : "MaxSize" }
            }
        },

        "RunnerSecurityGroup" : {
            "Type" : "AWS::EC2::SecurityGroup",
            "Properties" : {
                "GroupDescription" : "SSH to the runner instances",
                "SecurityGroupIngress" : [
                    {
                        "CidrIp" : { "Ref" : "SSHLocation" },
                        "FromPort" : "22",
                        "ToPort" : "22",
                        "IpProtocol" : "tcp"
                    }
                ]
            }
        },

        "RunnerWaitConditionHandle" : {
            "Type" : "AWS::CloudFormation::WaitConditionHandle"
        },

        "RunnerWaitCondition" : {
            "Type" : "AWS::CloudFormation::WaitCondition",
            "DependsOn" : "RunnerAutoScalingGroup",
            "Properties" : {
                "Count" : "1",
                "Handle" : { "Ref" : "RunnerWaitConditionHandle" },
                "Timeout" : "600"
            }
        }
    },
    "Outputs" : {
        "ServiceToken" : {
            "Value" : { "Fn::GetAtt" : ["CustomResourcePipeline", "Outputs.CustomResourceTopicARN"] },
            "Description" : "Service token to use in CustomResource definitions"
        }
    }
}