{
    "AWSTemplateFormatVersion" : "2010-09-09",
    "Description" : "This template creates an Autoscaling Group and Launch Configuration that deploys Linux instances with Watchmaker, which applies the DISA STIG.",
    "Parameters" :
    {
        "AmiId" :
        {
            "Description" : "ID of the AMI to launch",
            "Type" : "String",
            "AllowedPattern" : "^ami-[0-9a-z]{8}$|^ami-[0-9a-z]{17}$"
        },
        "AmiDistro" :
        {
            "Description" : "Linux distro of the AMI",
            "Type" : "String",
            "AllowedValues" :
            [
                "AmazonLinux",
                "CentOS",
                "RedHat"
            ]
        },
        "AppScriptParams" :
        {
            "Description" : "Parameter string to pass to the application script. Ignored if \"AppScriptUrl\" is blank",
            "Type" : "String"
        },
        "AppScriptShell" :
        {
            "Description" : "Shell with which to execute the application script. Ignored if \"AppScriptUrl\" is blank",
            "Type" : "String",
            "Default" : "bash",
            "AllowedValues" :
            [
                "bash",
                "python"
            ]
        },
        "AppScriptUrl" :
        {
            "Description" : "(Optional) URL to the application script. Leave blank to launch without an application script",
            "Type" : "String",
            "Default" : "",
            "AllowedPattern" : "^$|^http[s]?://.*$"
        },
        "AppVolumeDevice" :
        {
            "Description" : "(Optional) Device to mount an extra EBS volume. Leave blank to launch without an extra application volume",
            "Type" : "String",
            "Default" : "",
            "AllowedValues" :
            [
                "",
                "/dev/xvdf",
                "/dev/xvdg",
                "/dev/xvdh",
                "/dev/xvdi",
                "/dev/xvdj"
            ]
        },
        "AppVolumeMountPath" :
        {
            "Description" : "Filesystem path to mount the extra app volume. Ignored if \"AppVolumeDevice\" is blank",
            "Type" : "String",
            "Default" : "/opt/data",
            "AllowedPattern" : "/.*"
        },
        "AppVolumeType" :
        {
            "Description" : "Type of EBS volume to create. Ignored if \"AppVolumeDevice\" is blank",
            "Type" : "String",
            "Default" : "gp2",
            "AllowedValues" :
            [
                "gp2",
                "io1",
                "sc1",
                "st1",
                "standard"
            ]
        },
        "AppVolumeSize" :
        {
            "Description" : "Size in GB of the EBS volume to create. Ignored if \"AppVolumeDevice\" is blank",
            "Type" : "Number",
            "Default" : "1",
            "MinValue": "1",
            "MaxValue": "16384",
            "ConstraintDescription" : "Must be between 1GB and 16384GB."
        },
        "KeyPairName" :
        {
            "Description" : "Public/private key pairs allow you to securely connect to your instance after it launches",
            "Type" : "AWS::EC2::KeyPair::KeyName"
        },
        "InstanceType" :
        {
            "Description" : "Amazon EC2 instance type",
            "Type" : "String",
            "Default" : "t2.micro",
            "AllowedValues" :
            [
                "t2.micro",
                "t2.small",
                "t2.medium",
                "t2.large",
                "c4.large",
                "c4.xlarge",
                "m4.large",
                "m4.xlarge"
            ]
        },
        "InstanceRole" :
        {
            "Description" : "(Optional) IAM instance role to apply to the instance(s)",
            "Type" : "String",
            "Default" : ""
        },
        "MinCapacity" :
        {
            "Description" : "Minimum number of instances in the Autoscaling Group",
            "Type" : "Number",
            "Default" : "1"
        },
        "MaxCapacity" :
        {
            "Description" : "Maximum number of instances in the Autoscaling Group",
            "Type" : "Number",
            "Default" : "2"
        },
        "DesiredCapacity" :
        {
            "Description" : "Desired number of instances in the Autoscaling Group",
            "Type" : "Number",
            "Default" : "1"
        },
        "NoPublicIp" :
        {
            "Description" : "Controls whether to assign the instance a public IP. Recommended to leave at \"true\" _unless_ launching in a public subnet",
            "Type" : "String",
            "Default" : "true",
            "AllowedValues" :
            [
                "false",
                "true"
            ]
        },
        "NoReboot" :
        {
            "Description" : "Controls whether to reboot the instance as the last step of cfn-init execution",
            "Type" : "String",
            "Default" : "false",
            "AllowedValues" :
            [
                "false",
                "true"
            ]
        },
        "NoUpdates" :
        {
            "Description" : "Controls whether to run yum update during a stack update (on the initial instance launch, Watchmaker _always_ installs updates)",
            "Type" : "String",
            "Default" : "false",
            "AllowedValues" :
            [
                "false",
                "true"
            ]
        },
        "SecurityGroupIds" :
        {
            "Description" : "List of security groups to apply to the instance(s)",
            "Type" : "List<AWS::EC2::SecurityGroup::Id>"
        },
        "SubnetIds" :
        {
            "Type" : "List<AWS::EC2::Subnet::Id>",
            "Description" : "List of subnets to associate to the Autoscaling Group"
        },
        "PypiIndexUrl" :
        {
            "Description" : "URL to the PyPi Index",
            "Type" : "String",
            "Default" : "https://pypi.org/simple",
            "AllowedPattern" : "^http[s]?://.*$"
        },
        "WatchmakerConfig" :
        {
            "Description" : "(Optional) URL to a Watchmaker config file",
            "Type" : "String",
            "Default" : "",
            "AllowedPattern" : "^$|^http[s]?://.*$"
        },
        "WatchmakerEnvironment" :
        {
            "Description" : "Environment in which the instance is being deployed",
            "Type" : "String",
            "Default" : "",
            "AllowedValues" :
            [
                "",
                "dev",
                "test",
                "prod"
            ]
        },
        "WatchmakerOuPath" :
        {
            "Description" : "(Optional) DN of the OU to place the instance when joining a domain. If blank and \"WatchmakerEnvironment\" enforces a domain join, the instance will be placed in a default container. Leave blank if not joining a domain, or if \"WatchmakerEnvironment\" is \"false\"",
            "Type" : "String",
            "Default" : "",
            "AllowedPattern" : "^$|^(OU=.+,)+(DC=.+)+$"
        },
        "WatchmakerAdminGroups" :
        {
            "Description" : "(Optional) Colon-separated list of domain groups that should have admin permissions on the EC2 instance",
            "Type" : "String",
            "Default" : ""
        },
        "CfnEndpointUrl" :
        {
            "Description" : "(Optional) URL to the CloudFormation Endpoint. e.g. https://cloudformation.us-east-1.amazonaws.com",
            "Type" : "String",
            "Default" : "https://cloudformation.us-east-1.amazonaws.com",
            "AllowedPattern" : "^$|^http[s]?://.*$"
        },
        "CfnGetPipUrl" :
        {
            "Description" : "URL to get-pip.py",
            "Type" : "String",
            "Default" : "https://bootstrap.pypa.io/get-pip.py",
            "AllowedPattern" : "^http[s]?://.*\\.py$"
        },
        "CfnBootstrapUtilsUrl" :
        {
            "Description" : "URL to aws-cfn-bootstrap-latest.tar.gz",
            "Type" : "String",
            "Default" : "https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz",
            "AllowedPattern" : "^http[s]?://.*\\.tar\\.gz$"
        },
        "ToggleCfnInitUpdate" :
        {
            "Description" : "A/B toggle that forces a change to instance metadata, triggering the cfn-init update sequence",
            "Type" : "String",
            "Default" : "A",
            "AllowedValues" :
            [
                "A",
                "B"
            ]
        },
        "ToggleNewInstances" :
        {
            "Description" : "A/B toggle that forces a change to instance userdata, triggering new instances via the Autoscale update policy",
            "Type" : "String",
            "Default" : "A",
            "AllowedValues" :
            [
                "A",
                "B"
            ]
        }
    },
    "Conditions" :
    {
        "ExecuteAppScript" :
        {
            "Fn::Not" : [ { "Fn::Equals" : [ { "Ref" : "AppScriptUrl" }, "" ] } ]
        },
        "CreateAppVolume" :
        {
            "Fn::Not" : [ { "Fn::Equals" : [ { "Ref" : "AppVolumeDevice" }, "" ] } ]
        },
        "UseWamConfig" :
        {
            "Fn::Not" : [ { "Fn::Equals" : [ { "Ref" : "WatchmakerConfig" }, "" ] } ]
        },
        "UseOuPath" :
        {
            "Fn::Not" : [ { "Fn::Equals" : [ { "Ref" : "WatchmakerOuPath" }, "" ] } ]
        },
        "UseAdminGroups" :
        {
            "Fn::Not" : [ { "Fn::Equals" : [ { "Ref" : "WatchmakerAdminGroups" }, "" ] } ]
        },
        "UseEnvironment" :
        {
            "Fn::Not" : [ { "Fn::Equals" : [ { "Ref" : "WatchmakerEnvironment" }, "" ] } ]
        },
        "UseCfnUrl" :
        {
            "Fn::Not" : [ { "Fn::Equals" : [ { "Ref" : "CfnEndpointUrl" }, "" ] } ]
        },
        "InstallUpdates" :
        {
            "Fn::Not" : [ { "Fn::Equals" : [ { "Ref" : "NoUpdates" }, "true" ] } ]
        },
        "Reboot" :
        {
            "Fn::Not" : [ { "Fn::Equals" : [ { "Ref" : "NoReboot" }, "true" ] } ]
        },
        "AssignInstanceRole" :
        {
            "Fn::Not" : [ { "Fn::Equals" : [ { "Ref" : "InstanceRole" }, "" ] } ]
        },
        "AssignPublicIp" :
        {
            "Fn::Not" : [ { "Fn::Equals" : [ { "Ref" : "NoPublicIp" }, "true" ] } ]
        }
    },
    "Mappings" :
    {
        "Distro2RootDevice" :
        {
            "AmazonLinux" : { "DeviceName" : "xvda" },
            "RedHat" : { "DeviceName" : "sda1" },
            "CentOS" : { "DeviceName" : "sda1" }
        }
    },
    "Metadata" :
    {
        "AWS::CloudFormation::Interface" :
        {
            "ParameterGroups" :
            [
                {
                    "Label" :
                    {
                      "default" : "EC2 Instance Configuration"
                    },
                    "Parameters" :
                    [
                        "AmiId",
                        "AmiDistro",
                        "InstanceType",
                        "InstanceRole",
                        "KeyPairName",
                        "NoPublicIp",
                        "NoReboot",
                        "NoUpdates",
                        "SecurityGroupIds"
                    ]
                },
                {
                    "Label" :
                    {
                      "default" : "EC2 Watchmaker Configuration"
                    },
                    "Parameters" :
                    [
                        "PypiIndexUrl",
                        "WatchmakerConfig",
                        "WatchmakerEnvironment",
                        "WatchmakerOuPath",
                        "WatchmakerAdminGroups"
                    ]
                },
                {
                    "Label" :
                    {
                        "default" : "EC2 Application Configuration"
                    },
                    "Parameters" :
                    [
                        "AppScriptUrl",
                        "AppScriptParams",
                        "AppScriptShell"
                    ]
                },
                {
                    "Label" :
                    {
                        "default" : "EC2 Application EBS Volume"
                    },
                    "Parameters" :
                    [
                        "AppVolumeDevice",
                        "AppVolumeMountPath",
                        "AppVolumeSize",
                        "AppVolumeType"
                    ]
                },
                {
                    "Label" :
                    {
                        "default" : "AutoScale Configuration"
                    },
                    "Parameters" :
                    [
                        "DesiredCapacity",
                        "MinCapacity",
                        "MaxCapacity"
                    ]
                },
                {
                    "Label" :
                    {
                        "default" : "Network Configuration"
                    },
                    "Parameters" :
                    [
                        "SubnetIds"
                    ]
                },
                {
                    "Label" :
                    {
                        "default" : "CloudFormation Configuration"
                    },
                    "Parameters" :
                    [
                        "CfnEndpointUrl",
                        "CfnGetPipUrl",
                        "CfnBootstrapUtilsUrl",
                        "ToggleCfnInitUpdate",
                        "ToggleNewInstances"
                    ]
                }
            ],
            "ParameterLabels" :
            {
                "ToggleCfnInitUpdate" :
                {
                    "default" : "Force Cfn Init Update"
                },
                "ToggleNewInstances" :
                {
                    "default" : "Force New Instances"
                }
            }
        }
    },
    "Resources" :
    {
        "WatchmakerAutoScalingGroup" :
        {
            "Type" : "AWS::AutoScaling::AutoScalingGroup",
            "UpdatePolicy" : {
                "AutoScalingRollingUpdate" : {
                    "MinInstancesInService" : "1",
                    "MaxBatchSize" : "2",
                    "WaitOnResourceSignals" : "true",
                    "PauseTime" : "PT30M"
                }
            },
            "CreationPolicy" :
            {
                "ResourceSignal" :
                {
                    "Count" : { "Ref" : "DesiredCapacity" },
                    "Timeout" : "PT30M"
                }
            },
            "Properties" :
            {
                "VPCZoneIdentifier" : { "Ref" : "SubnetIds" },
                "LaunchConfigurationName" : { "Ref" : "WatchmakerLaunchConfig" },
                "MinSize" : { "Ref" : "MinCapacity" },
                "MaxSize" : { "Ref" : "MaxCapacity" },
                "DesiredCapacity" : { "Ref" : "DesiredCapacity" },
                "Tags" :
                [
                    {
                        "Key" : "Name",
                        "Value" :
                        { "Fn::Join" : [ "", [
                            { "Ref" : "AWS::StackName" }
                        ] ] },
                        "PropagateAtLaunch" : "true"
                    }
                ]
            }
        },
        "WatchmakerLaunchConfig" :
        {
            "Type" : "AWS::AutoScaling::LaunchConfiguration",
            "Metadata" : {
                "ToggleCfnInitUpdate" : { "Ref" : "ToggleCfnInitUpdate" },
                "AWS::CloudFormation::Init" :
                {
                    "configSets" :
                    {
                        "launch" :
                        [
                            "setup",
                            "watchmaker-install",
                            "watchmaker-launch",
                            {
                                "Fn::If" :
                                [
                                    "ExecuteAppScript",
                                    "make-app",
                                    { "Ref" : "AWS::NoValue" }
                                ]
                            },
                            "finalize",
                            {
                                "Fn::If" :
                                [
                                    "Reboot",
                                    "reboot",
                                    { "Ref" : "AWS::NoValue" }
                                ]
                            }
                        ],
                        "update" :
                        [
                            "setup",
                            {
                                "Fn::If" :
                                [
                                    "InstallUpdates",
                                    "install-updates",
                                    { "Ref" : "AWS::NoValue" }
                                ]
                            },
                            "watchmaker-install",
                            "watchmaker-update",
                            {
                                "Fn::If" :
                                [
                                    "ExecuteAppScript",
                                    "make-app",
                                    { "Ref" : "AWS::NoValue" }
                                ]
                            },
                            "finalize",
                            {
                                "Fn::If" :
                                [
                                    "Reboot",
                                    "reboot",
                                    { "Ref" : "AWS::NoValue" }
                                ]
                            }
                        ]
                    },
                    "setup" :
                    {
                        "files" :
                        {
                            "/etc/cfn/cfn-hup.conf" :
                            {
                                "content" :
                                { "Fn::Join" : ["", [
                                    "[main]\n",
                                    "stack=", { "Ref" : "AWS::StackId" }, "\n",
                                    "region=", { "Ref" : "AWS::Region" }, "\n",
                                    {
                                        "Fn::If" :
                                        [
                                            "AssignInstanceRole",
                                            { "Fn::Join" : [ "", [
                                                "role=",
                                                { "Ref" : "InstanceRole" },
                                                "\n"
                                            ] ] },
                                            ""
                                        ]
                                    },
                                    {
                                        "Fn::If" :
                                        [
                                            "UseCfnUrl",
                                            { "Fn::Join" : [ "", [
                                                "url=",
                                                { "Ref" : "CfnEndpointUrl" },
                                                "\n"
                                            ] ] },
                                            ""
                                        ]
                                    },
                                    "interval=1", "\n",
                                    "verbose=true", "\n"
                                ]]},
                                "mode"    : "000400",
                                "owner"   : "root",
                                "group"   : "root"
                            },
                            "/etc/cfn/hooks.d/cfn-auto-reloader.conf" :
                            {
                                "content" :
                                { "Fn::Join" : ["", [
                                    "[cfn-auto-reloader-hook]\n",
                                    "triggers=post.update\n",
                                    "path=Resources.WatchmakerLaunchConfig.Metadata\n",
                                    "action=/opt/aws/bin/cfn-init -v -c update",
                                    " --stack ", { "Ref" : "AWS::StackName" },
                                    " --resource WatchmakerLaunchConfig",
                                    {
                                        "Fn::If" :
                                        [
                                            "AssignInstanceRole",
                                            { "Fn::Join" : [ "", [
                                                " --role ",
                                                { "Ref" : "InstanceRole" }
                                            ] ] },
                                            ""
                                        ]
                                    },
                                    {
                                        "Fn::If" :
                                        [
                                            "UseCfnUrl",
                                            { "Fn::Join" : [ "", [
                                                " --url ",
                                                { "Ref" : "CfnEndpointUrl" }
                                            ] ] },
                                            ""
                                        ]
                                    },
                                    " --region ", { "Ref" : "AWS::Region" }, "\n",
                                    "runas=root\n"
                                ]]},
                                "mode" : "000400",
                                "owner" : "root",
                                "group" : "root"
                            },
                            "/etc/cfn/scripts/watchmaker-install.sh" :
                            {
                                "content" :
                                { "Fn::Join" : [ "", [
                                  "#!/bin/bash\n\n",

                                  "PYPI_URL=", { "Ref" : "PypiIndexUrl" }, "\n",
                                  "PYPI_HOST=$(echo $PYPI_URL |sed -e \"s/[^/]*\\/\\/\\([^@]*@\\)\\?\\([^:/]*\\).*/\\2/\")\n",

                                  "pip install",
                                  " --index-url=\"$PYPI_URL\"",
                                  " --trusted-host=\"$PYPI_HOST\"",
                                  " --allow-all-external",
                                  " --upgrade pip setuptools watchmaker\n\n",
                                ]]},
                                "mode" : "000700",
                                "owner" : "root",
                                "group" : "root"
                            }
                        },
                        "services" :
                        {
                            "sysvinit" :
                            {
                                "cfn-hup" :
                                {
                                    "enabled" : "true",
                                    "ensureRunning" : "true",
                                    "files" :
                                    [
                                        "/etc/cfn/cfn-hup.conf",
                                        "/etc/cfn/hooks.d/cfn-auto-reloader.conf"
                                    ]
                                }
                            }
                        }
                    },
                    "install-updates" :
                    {
                        "commands" :
                        {
                            "10-install-updates" :
                            {
                                "command" : "yum -y update"
                            }
                        }
                    },
                    "watchmaker-install" :
                    {
                        "commands" :
                        {
                            "10-watchmaker-install" :
                            {
                                "command" : "bash -xe /etc/cfn/scripts/watchmaker-install.sh"
                            }
                        }
                    },
                    "watchmaker-launch" :
                    {
                        "commands" :
                        {
                            "10-watchmaker-launch" :
                            {
                                "command" :
                                { "Fn::Join" : [ "", [
                                    "watchmaker -vv",
                                    " --log-dir /var/log/watchmaker",
                                    " --noreboot",
                                    {
                                        "Fn::If" :
                                        [
                                            "UseWamConfig",
                                            { "Fn::Join" : [ "", [
                                                " --config \"",
                                                { "Ref" : "WatchmakerConfig" },
                                                "\""
                                            ]]},
                                            ""
                                        ]
                                    },
                                    {
                                        "Fn::If" :
                                        [
                                            "UseEnvironment",
                                            { "Fn::Join" : [ "", [
                                                " --environment \"",
                                                { "Ref" : "WatchmakerEnvironment" },
                                                "\""
                                            ]]},
                                            ""
                                        ]
                                    },
                                    {
                                        "Fn::If" :
                                        [
                                            "UseOuPath",
                                            { "Fn::Join" : [ "", [
                                                " --ou-path \"",
                                                { "Ref" : "WatchmakerOuPath" },
                                                "\""
                                            ]]},
                                            ""
                                        ]
                                    },
                                    {
                                        "Fn::If" :
                                        [
                                            "UseAdminGroups",
                                            { "Fn::Join" : [ "", [
                                                " --admin-groups \"",
                                                { "Ref" : "WatchmakerAdminGroups" },
                                                "\""
                                            ]]},
                                            ""
                                        ]
                                    }
                                ]]}
                            }
                        }
                    },
                    "watchmaker-update" :
                    {
                        "commands" :
                        {
                            "10-watchmaker-update" :
                            {
                                "command" :
                                { "Fn::Join" : [ "", [
                                    "watchmaker -vv",
                                    " --log-dir /var/log/watchmaker",
                                    " --saltstates None",
                                    " --noreboot",
                                    {
                                        "Fn::If" :
                                        [
                                            "UseWamConfig",
                                            { "Fn::Join" : [ "", [
                                                " --config \"",
                                                { "Ref" : "WatchmakerConfig" },
                                                "\""
                                            ]]},
                                            ""
                                        ]
                                    },
                                    {
                                        "Fn::If" :
                                        [
                                            "UseEnvironment",
                                            { "Fn::Join" : [ "", [
                                                " --environment \"",
                                                { "Ref" : "WatchmakerEnvironment" },
                                                "\""
                                            ]]},
                                            ""
                                        ]
                                    },
                                    {
                                        "Fn::If" :
                                        [
                                            "UseOuPath",
                                            { "Fn::Join" : [ "", [
                                                " --oupath \"",
                                                { "Ref" : "WatchmakerOuPath" },
                                                "\""
                                            ]]},
                                            ""
                                        ]
                                    },
                                    {
                                        "Fn::If" :
                                        [
                                            "UseAdminGroups",
                                            { "Fn::Join" : [ "", [
                                                " --admingroups \"",
                                                { "Ref" : "WatchmakerAdminGroups" },
                                                "\""
                                            ]]},
                                            ""
                                        ]
                                    }
                                ]]}
                            }
                        }
                    },
                    "make-app" :
                    {
                        "files" :
                        {
                            "/etc/cfn/scripts/make-app" :
                            {
                                "source" : { "Ref" : "AppScriptUrl" },
                                "mode" : "000700",
                                "owner" : "root",
                                "group" : "root"
                            }
                        },
                        "commands" :
                        {
                            "10-make-app" :
                            {
                                "command" :
                                { "Fn::Join" : [ "", [
                                    { "Ref" : "AppScriptShell" },
                                    " /etc/cfn/scripts/make-app ",
                                    { "Ref" : "AppScriptParams" }
                                ]]}
                            }
                        }
                    },
                    "finalize" :
                    {
                        "commands" :
                        {
                            "10-signal-success" :
                            {
                                "command" :
                                { "Fn::Join" : [ "", [
                                    "/opt/aws/bin/cfn-signal -e 0",
                                    " --stack ", { "Ref" : "AWS::StackName" },
                                    " --resource WatchmakerAutoScalingGroup",
                                    {
                                        "Fn::If" :
                                        [
                                            "AssignInstanceRole",
                                            { "Fn::Join" : [ "", [
                                                " --role ",
                                                { "Ref" : "InstanceRole" }
                                            ] ] },
                                            ""
                                        ]
                                    },
                                    {
                                        "Fn::If" :
                                        [
                                            "UseCfnUrl",
                                            { "Fn::Join" : [ "", [
                                                " --url ",
                                                { "Ref" : "CfnEndpointUrl" }
                                            ] ] },
                                            ""
                                        ]
                                    },
                                    " --region ", { "Ref" : "AWS::Region"}, "\n"
                                ]]},
                                "ignoreErrors" : "true"
                            }
                        }
                    },
                    "reboot" :
                    {
                        "commands" :
                        {
                            "10-reboot" :
                            {
                                "command" : "shutdown -r +1 &"
                            }
                        }
                    }
                }
            },
            "Properties" :
            {
                "ImageId" : { "Ref" : "AmiId" },
                "InstanceType" : { "Ref" : "InstanceType" },
                "IamInstanceProfile" :
                {
                    "Fn::If" :
                    [
                        "AssignInstanceRole",
                        { "Ref" : "InstanceRole" },
                        { "Ref" : "AWS::NoValue" }
                    ]
                },
                "AssociatePublicIpAddress" :
                {
                    "Fn::If" :
                    [
                        "AssignPublicIp",
                        "true",
                        "false"
                    ]
                },
                "BlockDeviceMappings" :
                [
                    {
                        "DeviceName" :
                        { "Fn::Join" : [ "", [
                            "/dev/",
                            { "Fn::FindInMap" :
                                [
                                    "Distro2RootDevice",
                                    { "Ref" : "AmiDistro" },
                                    "DeviceName"
                                ]
                            }
                        ]]},
                        "Ebs" :
                        {
                            "VolumeType" : "gp2",
                            "DeleteOnTermination" : "true"
                        }
                      },
                      {
                          "Fn::If" :
                          [
                              "CreateAppVolume",
                              {
                                  "DeviceName" : { "Ref" : "AppVolumeDevice" },
                                  "Ebs" :
                                  {
                                      "VolumeSize" : { "Ref" : "AppVolumeSize" },
                                      "VolumeType" : { "Ref" : "AppVolumeType" },
                                      "DeleteOnTermination" : "true"
                                  }
                              },
                              { "Ref" : "AWS::NoValue" }
                          ]
                      }
                ],
                "KeyName" :
                {
                    "Ref" : "KeyPairName"
                },
                "SecurityGroups" :
                {
                    "Ref" : "SecurityGroupIds"
                },
                "UserData" :
                {
                    "Fn::Base64" :
                    { "Fn::Join" : [ "", [
                        "Content-Type: multipart/mixed; boundary=\"===============3585321300151562773==\"\n",
                        "MIME-Version: 1.0\n",
                        "\n",

                        "--===============3585321300151562773==\n",
                        "Content-Type: text/cloud-config; charset=\"us-ascii\"\n",
                        "MIME-Version: 1.0\n",
                        "Content-Transfer-Encoding: 7bit\n",
                        "Content-Disposition: attachment; filename=\"cloud.cfg\"\n",
                        "\n",

                        "#cloud-config\n",
                        {
                            "Fn::If" :
                            [
                                "CreateAppVolume",
                                { "Fn::Join" : [ "", [
                                    "bootcmd:\n",
                                    "- cloud-init-per instance mkfs-appvolume mkfs -t ext4 ",
                                    { "Ref" : "AppVolumeDevice" },
                                    "\n",
                                    "mounts:\n",
                                    "- [ ",
                                    { "Ref" : "AppVolumeDevice" }, ", ",
                                    { "Ref" : "AppVolumeMountPath" },
                                    " ]\n"
                                ]]},
                                { "Ref" : "AWS::NoValue" }
                            ]
                        },

                        "\n",

                        "--===============3585321300151562773==\n",
                        "Content-Type: text/x-shellscript; charset=\"us-ascii\"\n",
                        "MIME-Version: 1.0\n",
                        "Content-Transfer-Encoding: 7bit\n",
                        "Content-Disposition: attachment; filename=\"script.sh\"\n",
                        "\n",

                        "#!/bin/bash -xe\n\n",

                        "# CFN LaunchConfig Update Toggle: ",
                        { "Ref" : "ToggleNewInstances" },
                        "\n\n",

                        "# Export cert bundle ENVs\n",
                        "export AWS_CA_BUNDLE=/etc/pki/tls/certs/ca-bundle.crt\n",
                        "export REQUESTS_CA_BUNDLE=/etc/pki/tls/certs/ca-bundle.crt\n\n",

                        "# Get pip\n",
                        "curl --silent --show-error --retry 5 -L ",
                        { "Ref" : "CfnGetPipUrl" },
                        " | python", "\n\n",

                        "# Add pip to path\n",
                        "hash pip 2> /dev/null || ",
                        "PATH=\"${PATH}:/usr/local/bin\"", "\n\n",

                        "# Upgrade pip and setuptools\n",
                        "PYPI_URL=", { "Ref" : "PypiIndexUrl" }, "\n",
                        "PYPI_HOST=$(echo $PYPI_URL |sed -e \"s/[^/]*\\/\\/\\([^@]*@\\)\\?\\([^:/]*\\).*/\\2/\")\n",
                        "pip install",
                        " --index-url=\"$PYPI_URL\"",
                        " --trusted-host=\"$PYPI_HOST\"",
                        " --allow-all-external",
                        " --upgrade pip setuptools\n\n",

                        "# Fix python urllib3 warnings\n",
                        "yum -y install gcc python-devel libffi-devel openssl-devel\n",
                        "pip install",
                        " --index-url=\"$PYPI_URL\"",
                        " --trusted-host=\"$PYPI_HOST\"",
                        " --allow-all-external",
                        " --upgrade pyopenssl ndg-httpsclient pyasn1\n\n",

                        "# Get cfn utils\n",
                        "pip install",
                        " --index-url=\"$PYPI_URL\"",
                        " --trusted-host=\"$PYPI_HOST\"",
                        " --allow-all-external",
                        " --upgrade ",
                        { "Ref" : "CfnBootstrapUtilsUrl" },
                        "\n\n",

                        "# Remove gcc now that it is no longer needed\n",
                        "yum -y remove gcc --setopt=clean_requirements_on_remove=1\n\n",

                        "# Fixup cfn utils\n",
                        "INITDIR=$(find -L /opt/aws/apitools/cfn-init/init -name redhat ",
                        "2> /dev/null || echo /usr/init/redhat)\n",
                        "chmod 775 ${INITDIR}/cfn-hup\n",
                        "ln -f -s ${INITDIR}/cfn-hup /etc/rc.d/init.d/cfn-hup\n",
                        "chkconfig --add cfn-hup\n",
                        "chkconfig cfn-hup on\n",
                        "mkdir -p /opt/aws/bin\n",
                        "BINDIR=$(find -L /opt/aws/apitools/cfn-init -name bin ",
                        "2> /dev/null || echo /usr/bin)\n",
                        "for SCRIPT in cfn-elect-cmd-leader cfn-get-metadata cfn-hup ",
                        "cfn-init cfn-send-cmd-event cfn-send-cmd-result cfn-signal\n",
                        "do\n",
                        "    ln -s ${BINDIR}/${SCRIPT} /opt/aws/bin/${SCRIPT} 2> /dev/null || ",
                        "    echo Skipped symbolic link, /opt/aws/bin/${SCRIPT} already exists\n",
                        "done\n\n",

                        "# Add cfn-signal to path\n",
                        "hash cfn-signal 2> /dev/null || ",
                        "PATH=\"${PATH}:/usr/local/bin:/opt/aws/bin\"",
                        "\n\n",

                        "# Execute cfn-init\n",
                        "/opt/aws/bin/cfn-init -v -c launch",
                        " --stack ", { "Ref" : "AWS::StackName" },
                        " --resource WatchmakerLaunchConfig",
                        {
                            "Fn::If" :
                            [
                                "AssignInstanceRole",
                                { "Fn::Join" : [ "", [
                                    " --role ", { "Ref" : "InstanceRole" }
                                ] ] },
                                ""
                            ]
                        },
                        {
                            "Fn::If" :
                            [
                                "UseCfnUrl",
                                { "Fn::Join" : [ "", [
                                    " --url ", { "Ref" : "CfnEndpointUrl" }
                                ] ] },
                                ""
                            ]
                        },
                        " --region ", { "Ref" : "AWS::Region" }, " ||",
                        " ( echo 'ERROR: cfn-init failed! Aborting!';",
                        " /opt/aws/bin/cfn-signal -e 1",
                        "  --stack ", { "Ref" : "AWS::StackName" },
                        "  --resource WatchmakerAutoScalingGroup",
                        {
                            "Fn::If" :
                            [
                                "AssignInstanceRole",
                                { "Fn::Join" : [ "", [
                                    " --role ", { "Ref" : "InstanceRole" }
                                ] ] },
                                ""
                            ]
                        },
                        {
                            "Fn::If" :
                            [
                                "UseCfnUrl",
                                { "Fn::Join" : [ "", [
                                    " --url ", { "Ref" : "CfnEndpointUrl" }
                                ] ] },
                                ""
                            ]
                        },
                        "  --region ", { "Ref" : "AWS::Region"}, ";",
                        " exit 1",
                        " )\n\n",
                        "--===============3585321300151562773==--"
                    ] ] }
                }
            }
        }
    }
}
