{
  "AWSTemplateFormatVersion": "2010-09-09",

  "Description": "This is a sample CloudFormation template for deploying Dynamic DynamoDB version 2.x. This package will be installed from the Python Package Index repository. For more information, see http://dynamic-dynamodb.readthedocs.org.",

  "Parameters": {
    "S3Bucket": {
      "Type": "String",
      "Default": "s3://bucket-name/folder-path-if-applicable/",
      "Description": "Remove this default value and enter your pre-created S3 Bucket url upto folder name. (Please include the trailing /. Example: https://s3.amazonaws.com/my-bucket/ should be input as s3://my-bucket/). It will be used for storing a copy of Dynamic DynamoDB configuration file."
    },

    "S3BucketRegion": {
      "Type": "String",
      "Default": "us-east-1",
      "Description": "Region the S3 bucket is located in. This is needed due to a limitation in the AWS CLI (https://github.com/aws/aws-cli/issues/564)"
    },

    "KeyPair": {
      "Default": "key-pair-name",
      "Description": "Remove this default value and enter the name of your EC2 keypair to use for SSH access",
      "Type": "String",
      "MinLength": "1",
      "MaxLength": "64",
      "AllowedPattern": "[-_ a-zA-Z0-9\\.]*",
      "ConstraintDescription": "can contain only alphanumeric characters, spaces, dashes, underscores and dots."
    },

    "InstanceType" : {
      "Default" : "t2.micro",
      "Description" : "AWS EC2 instance type",
      "Type" : "String"
    }
  },

  "Mappings": {
    "RegionMap": {
      "us-east-1": {
        "AMI": "ami-467ca739",
        "IamRoleServiceHost": "ec2.amazonaws.com",
        "IamRolePolicySnsResource": "arn:aws:sns:*::dynamic-dynamodb"
      },
      "us-west-1": {
        "AMI": "ami-46e1f226",
        "IamRoleServiceHost": "ec2.amazonaws.com",
        "IamRolePolicySnsResource": "arn:aws:sns:*::dynamic-dynamodb"
      },
      "us-west-2": {
        "AMI": "ami-6b8cef13",
        "IamRoleServiceHost": "ec2.amazonaws.com",
        "IamRolePolicySnsResource": "arn:aws:sns:*::dynamic-dynamodb"
      },
      "eu-west-1": {
        "AMI": "ami-9cbe9be5",
        "IamRoleServiceHost": "ec2.amazonaws.com",
        "IamRolePolicySnsResource": "arn:aws:sns:*::dynamic-dynamodb"
      },
      "sa-east-1": {
        "AMI": "ami-f09dcc9c",
        "IamRoleServiceHost": "ec2.amazonaws.com",
        "IamRolePolicySnsResource": "arn:aws:sns:*::dynamic-dynamodb"
      },
      "ap-southeast-1": {
        "AMI": "ami-64260718",
        "IamRoleServiceHost": "ec2.amazonaws.com",
        "IamRolePolicySnsResource": "arn:aws:sns:*::dynamic-dynamodb"
      },
      "ap-southeast-2": {
        "AMI": "ami-60a26a02",
        "IamRoleServiceHost": "ec2.amazonaws.com",
        "IamRolePolicySnsResource": "arn:aws:sns:*::dynamic-dynamodb"
      },
      "ap-northeast-1": {
        "AMI": "ami-28ddc154",
        "IamRoleServiceHost": "ec2.amazonaws.com",
        "IamRolePolicySnsResource": "arn:aws:sns:*::dynamic-dynamodb"
      },
      "cn-north-1": {
        "AMI": "ami-3d3ee150",
        "IamRoleServiceHost": "ec2.amazonaws.com.cn",
        "IamRolePolicySnsResource": "arn:aws-cn:sns:*::dynamic-dynamodb"
      }
    }
  },

  "Resources": {
    "LaunchConfig": {
      "Type": "AWS::AutoScaling::LaunchConfiguration",
      "Properties": {
        "ImageId": { "Fn::FindInMap": [ "RegionMap", { "Ref": "AWS::Region" }, "AMI" ] },
        "InstanceType": { "Ref" : "InstanceType" },
        "KeyName": { "Ref": "KeyPair" },
        "SecurityGroups": [ { "Ref": "SecurityGroup" } ],
        "IamInstanceProfile"  : { "Ref" : "IamInstanceProfile" },
        "UserData": {
          "Fn::Base64": {
            "Fn::Join": [ "\n", [
              "#!/usr/bin/env bash",
              "# Helper function",
              "log(){",
              "    timenow=`date +%Y-%m-%dT%H:%M:%S.%N`",
              "    echo \"$timenow: $1\" >> $INSTALLER_LOG_FILE_LOCATION",
              "}",
              "",
              "backup_file_locally(){",
              "  FILE=$1",
              "  BACKUP_FILE_NAME=$FILE.`date +\"%Y.%m.%d.%H.%M.%S.%N\".backup`",
              "  mv $FILE \"$FILE.`date +\"%Y.%m.%d.%H.%M.%S.%N\".backup`\"",
              "  log \"Backed up $FILE to $BACKUP_FILE_NAME\"",
              "}",
              "error_exit(){",
              "  log \"$1\"",
              {
                "Fn::Join": [ "", [
                    "/opt/aws/bin/cfn-signal ",
                    " -e 1 ",
                    " -r \"$1\"",
                    " '", { "Ref" : "WaitHandle" }, "'\n"
                  ]
                ]
              },
              "  exit 1",
              "}",
              "INSTALLER_LOG_FILE_LOCATION=/etc/dynamic-dynamodb/logs/installer.log",
              "mkdir -p /etc/dynamic-dynamodb/{scripts,logs} || error_exit 'Failed to create /etc/dynamic-dynamodb'",
              {
                "Fn::Join": [ " ", [
                    "/opt/aws/bin/cfn-init ",
                    "  --stack ", { "Ref": "AWS::StackId" },
                    "  --resource LaunchConfig ",
                    "  --region ", { "Ref": "AWS::Region" },
                    " || error_exit 'Failed in AWS::CloudFormation::Init. Check logs at /var/log/cfn-init.log'"
                  ]
                ]
              },
              "",
              "if [[ -f $INSTALLER_LOG_FILE_LOCATION ]]; then",
              "  backup_file_locally $INSTALLER_LOG_FILE_LOCATION",
              "fi",
              "easy_install pip || error_exit 'Failed to install pip'",
              "log \"Installed pip\"",
              "echo \"dynamic-dynamodb>=2.0.0,<3.0.0\">/etc/dynamic-dynamodb/requirements.txt",
              "/usr/local/bin/pip install -U -r /etc/dynamic-dynamodb/requirements.txt || error_exit 'Failed to install dynamic-dynamodb package from pip repository'",
              "log \"Installed dynamic-dynamodb\"",
              "",
              "",
              "mkdir -p ~/.aws || error_exit 'Failed to create /home/root/.aws'",
              "cp /home/ec2-user/.aws/config ~/.aws/config",
              {
                "Fn::Join": [ "", [
                  "echo \"aws s3 cp /etc/dynamic-dynamodb/dynamic-dynamodb.conf ", { "Ref": "S3Bucket" }, "dynamic-dynamodb.conf --region ", { "Ref" : "S3BucketRegion" },
                  " || (echo 'Failed to upload /etc/dynamic-dynamodb/dynamic-dynamodb.conf to ",
                  { "Ref": "S3Bucket" }, "' ; exit 1)\">/etc/dynamic-dynamodb/scripts/upload-config-to-s3.sh",
                  " || error_exit 'Failed to create /etc/dynamic-dynamodb/scripts/upload-config-to-s3.sh'"
                ]]
              },
              {
                "Fn::Join": [ " ", [
                  "sh /etc/dynamic-dynamodb/scripts/init_config_file.sh /etc/dynamic-dynamodb/dynamic-dynamodb.conf",
                  { "Ref": "S3Bucket" },
                  " $INSTALLER_LOG_FILE_LOCATION",
                  " || error_exit 'Failed to initialize config file'"
                ]]
              },
              "service dynamic-dynamodb start || error_exit 'Failed to start dynamic-dynamodb service. Check /etc/dynamic-dynamodb/logs/service.log'",
              "log \"Dynamic dynamodb service started\"",
              {
                "Fn::Join": [ "", [
                  "# All is well so signal success\n",
                  "/opt/aws/bin/cfn-signal -e 0 -r \"Dynamic DynamoDB instance setup complete\" '", { "Ref": "WaitHandle" }, "'\n"
                ]]
              }
            ]]
          }
        }
      },
      "Metadata": {
        "AWS::CloudFormation::Init": {
          "config": {
            "files": {
              "/home/ec2-user/.aws/config": {
                "content" : { "Fn::Join" : ["", [
                  "[default]\n",
                  "region=", { "Ref": "AWS::Region" }, "\n"
                ]]},
                "mode": "000755",
                "owner": "root",
                "group": "root"
              },
              "/etc/init.d/dynamic-dynamodb": {
                "content": {
                  "Fn::Join": [
                    "\n",
                    [
                      "#!/usr/bin/env bash",
                      "### BEGIN INIT INFO",
                      "# Provides:        dynamic-dynamodb",
                      "# Required-Start:  $remote_fs $syslog",
                      "# Required-Stop:   $remote_fs $syslog",
                      "# Default-Start:   2 3 4 5",
                      "# Default-Stop:    0 1 6",
                      "# Short-Description: Automatic scaling for AWS DynamoDB",
                      "# Description:     Dynamic DynamoDB provides automatic scaling for AWS DynamoDB",
                      "### END INIT INFO",
                      "",
                      "NAME=dynamicdynamodb",
                      "DAEMON=/usr/local/bin/dynamic-dynamodb",
                      "DRY_RUN=$2",
                      "DAEMON_START_ARGS=\"--config /etc/dynamic-dynamodb/dynamic-dynamodb.conf --daemon start\"",
                      "DAEMON_STOP_ARGS=\"--config /etc/dynamic-dynamodb/dynamic-dynamodb.conf --daemon stop\"",
                      "SCRIPTNAME=/etc/init.d/$NAME",
                      "SERVICE_LOG_FILE=/etc/dynamic-dynamodb/logs/service.log",
                      "",
                      "if [ \"$DRY_RUN\" == \"--dry-run\" ]; then",
                      "   DAEMON_START_ARGS=\"--config /etc/dynamic-dynamodb/dynamic-dynamodb.conf --dry-run --daemon start\"",
                      "   DAEMON_STOP_ARGS=\"--config /etc/dynamic-dynamodb/dynamic-dynamodb.conf --dry-run --daemon stop\"",
                      "elif [ \"$2\" != \"\" ]; then",
                      "   echo \"$2\"",
                      "   echo \"Second parameter has to be --dry-run and is used only when running start/restart/force-reload commands\"",
                      "   exit 1",
                      "fi",
                      "",
                      "# Exit if the package is not installed",
                      "[ -x \"$DAEMON\" ] || exit 1",
                      "",
                      ". /etc/rc.d/init.d/functions",
                      "",
                      "log(){",
                      "    timenow=`date +%Y-%m-%dT%H:%M:%S.%N`",
                      "    echo \"$timenow: $1\"",
                      "    echo \"$timenow: $1\" >> $SERVICE_LOG_FILE",
                      "}",
                      "",
                      "error_exit(){",
                      "  log \"$1\"",
                      "  exit 1",
                      "}",
                      "",
                      "",
                      "do_start()",
                      "{",
                      "   if [ \"$DRY_RUN\" == \"--dry-run\" ]; then",
                      "      log \"do_start:Dry run mode, not uploading latest config file to S3\"",
                      "   else",
                      "      log \"do_start:Firstly, uploading latest config file to S3\"",
                      "      sh /etc/dynamic-dynamodb/scripts/upload-config-to-s3.sh  || error_exit \"Failed in uploading config file to s3 bucket\"",
                      "   fi",
                      "   log \"do_start:Starting $NAME\"",
                      "   daemon $DAEMON $DAEMON_START_ARGS  || error_exit \"Failed in starting $NAME service\"",
                      "}",
                      "",
                      "do_stop()",
                      "{",
                      "   log \"do_stop:Stopping $NAME\"",
                      "   daemon $DAEMON $DAEMON_STOP_ARGS || error_exit \"Failed in stopping $NAME service\"",
                      "}",
                      "",
                      "",
                      "case \"$1\" in",
                      "  start)",
                      "  do_start",
                      "  ;;",
                      "  stop)",
                      "  do_stop",
                      "  ;;",
                      "  status)",
                      "  status \"$DAEMON\" \"$NAME\" && exit 0 || exit $?",
                      "  ;;",
                      "  restart|force-reload)",
                      "  do_stop",
                      "  do_start",
                      "    #*)",
                      "  ;;",
                      "  *)",
                      "  echo \"Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}\" >&2",
                      "  exit 3",
                      "  ;;",
                      "esac",
                      "",
                      ":"

                    ]
                  ]
                },
                "mode": "000755",
                "owner": "root",
                "group": "root"
              },
              "/etc/dynamic-dynamodb/scripts/init_config_file.sh": {
                "content": {
                  "Fn::Join": [
                    "",
                    [
                      "#!/usr/bin/env bash\n",
                      "CONFIG_FILE_LOCAL_LOCATION=$1\n",
                      "S3_BUCKET=$2\n",
                      "INSTALLER_LOG_FILE_LOCATION=$3\n",
                      "CONFIG_FILE_S3_LOCATION=\"$S3_BUCKET\"dynamic-dynamodb.conf\n",
                      "DOES_CONFIG_FILE_EXIST_ON_S3=0\n",
                      "DOES_CONFIG_FILE_EXIST_ON_LOCALLY=0\n\n",

                      "log(){\n",
                      "    timenow=`date +%Y-%m-%dT%H:%M:%S.%N`\n",
                      "    echo \"$timenow: $1\" >> $INSTALLER_LOG_FILE_LOCATION\n",
                      "}\n\n",

                      "error_exit(){\n",
                      "  log \"$1\"\n",
                      "  exit 1\n",
                      "}\n\n",

                      "backup_file_locally(){\n",
                      "  FILE=$1\n",
                      "  BACKUP_FILE_NAME=$FILE.`date +\\\"%Y.%m.%d.%H.%M.%S.%N\\\".backup`\n",
                      "  mv $FILE \"$FILE.`date +\\\"%Y.%m.%d.%H.%M.%S.%N\\\".backup`\" || error_exit \"Failed in creating backup file $BACKUP_FILE_NAME\"\n",
                      "  log \"Backed up $FILE to $BACKUP_FILE_NAME\"\n",
                      "}\n\n",

                      "generate_new_config_file(){\n",
                      "   log \"Loading an example config file to $CONFIG_FILE_LOCAL_LOCATION\"\n",
                      "   cp /etc/dynamic-dynamodb/example-dynamic-dynamodb.conf $CONFIG_FILE_LOCAL_LOCATION\n",
                      "   sed -i 's/region:\\ us-east-1/region:\\ ", { "Ref" : "AWS::Region" },"/g' /etc/dynamic-dynamodb/example-dynamic-dynamodb.conf\n",
                      "   log \"Loaded example configuration to $CONFIG_FILE_LOCAL_LOCATION\"\n",
                      "}\n\n",

                      "download_from_s3(){\n",
                      "  aws s3 cp $CONFIG_FILE_S3_LOCATION $CONFIG_FILE_LOCAL_LOCATION --region ", { "Ref" : "S3BucketRegion" } ," || error_exit \"Failed to download config file from $CONFIG_FILE_S3_LOCATION to $CONFIG_FILE_S3_LOCATION  even though it existed on S3\"\n",
                      "  log \"Downloaded config file from $CONFIG_FILE_S3_LOCATION to $CONFIG_FILE_LOCAL_LOCATION\"\n",
                      "}\n\n",

                      "aws s3 cp $CONFIG_FILE_S3_LOCATION . --region ", { "Ref" : "S3BucketRegion" } ," >/dev/null 2>&1\n",
                      "if [[ \"$?\" -eq 0 ]]; then\n",
                      "   DOES_CONFIG_FILE_EXIST_ON_S3=1\n",
                      "fi\n\n",

                      "if [[ -f $CONFIG_FILE_LOCAL_LOCATION ]]; then\n",
                      "   DOES_CONFIG_FILE_EXIST_ON_LOCALLY=1\n",
                      "fi\n\n",

                      "if [ $DOES_CONFIG_FILE_EXIST_ON_S3 -eq 0 ] && [ $DOES_CONFIG_FILE_EXIST_ON_LOCALLY -eq 0 ]; then\n",
                      "  generate_new_config_file\n",
                      "elif [ $DOES_CONFIG_FILE_EXIST_ON_S3 -eq 0 ] && [ $DOES_CONFIG_FILE_EXIST_ON_LOCALLY -eq 1 ]; then\n",
                      "  log \"Config file exists locally and not on $CONFIG_FILE_S3_LOCATION, continuing to use the file\";\n",
                      "elif [ $DOES_CONFIG_FILE_EXIST_ON_S3 -eq 1 ] && [ $DOES_CONFIG_FILE_EXIST_ON_LOCALLY -eq 0 ]; then\n",
                      "  download_from_s3\n",
                      "elif [ $DOES_CONFIG_FILE_EXIST_ON_S3 -eq 1 ] && [ $DOES_CONFIG_FILE_EXIST_ON_LOCALLY -eq 1 ]; then\n",
                      "  backup_file_locally $CONFIG_FILE_LOCAL_LOCATION\n",
                      "  download_from_s3\n",
                      "fi\n"
                    ]
                  ]
                },
                "mode": "000755",
                "owner": "root",
                "group": "root"
              },
              "/etc/dynamic-dynamodb/example-dynamic-dynamodb.conf": {
                "source": "https://raw.github.com/sebdah/dynamic-dynamodb/master/example-dynamic-dynamodb.conf",
                "mode": "000644",
                "owner": "root",
                "group": "root"
              }
            }
          }
        }
      }
    },

    "AutoScalingGroup": {
      "Type": "AWS::AutoScaling::AutoScalingGroup",
      "Properties": {
        "AvailabilityZones": { "Fn::GetAZs": "" },
        "Cooldown": 300,
        "LaunchConfigurationName": { "Ref": "LaunchConfig" },
        "MaxSize": 1,
        "MinSize": 1,
        "Tags" : [
          {
            "Key"   : "Name",
            "Value" : "dynamic-dynamodb",
            "PropagateAtLaunch" : "true"
          }
        ]
      }
    },

    "IamRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Version" : "2012-10-17",
          "Statement": [ {
            "Effect": "Allow",
            "Principal": {
              "Service": [ { "Fn::FindInMap": [ "RegionMap", { "Ref": "AWS::Region" }, "IamRoleServiceHost" ] } ]
            },
            "Action": [ "sts:AssumeRole" ]
          }]
        },
        "Path": "/",
        "Policies": [ {
          "PolicyName": "root",
          "PolicyDocument": {
            "Version": "2012-10-17",
            "Statement": [
              {
                "Effect": "Allow",
                "Action": [
                  "dynamodb:DescribeTable",
                  "dynamodb:ListTables",
                  "dynamodb:UpdateTable",
                  "cloudwatch:GetMetricStatistics",
                  "s3:PutObject",
                  "s3:GetObject"
                ],
                "Resource": ["*"]
              },
              {
                "Effect": "Allow",
                "Action": [
                  "sns:Publish"
                ],
                "Resource": [
                  { "Fn::FindInMap": [ "RegionMap", { "Ref": "AWS::Region" }, "IamRolePolicySnsResource" ] }
                ]
              }
            ]
          }
        }]
      }
    },

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

    "SecurityGroup": {
      "Type": "AWS::EC2::SecurityGroup",
      "Properties": {
        "GroupDescription": "Allow access to MyInstance",
        "SecurityGroupIngress": [
          {
            "IpProtocol": "tcp",
            "FromPort": 22,
            "ToPort": 22,
            "CidrIp": "0.0.0.0/0"
          }
        ]
      }
    },

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

    "WaitCondition" : {
      "Type": "AWS::CloudFormation::WaitCondition",
      "DependsOn": "AutoScalingGroup",
      "Properties": {
        "Handle": { "Ref" : "WaitHandle" },
        "Timeout": "600"
      }
    }
  },
  "Outputs": {
    "URL": {
      "Description": "EC2 instance",
      "Value": "You can find your EC2 instance at https://console.aws.amazon.com/ec2/v2/home?#Instances:search=dynamic-dynamodb"
    }
  }
}