Skip to content

Instantly share code, notes, and snippets.

@sebdah
Last active August 29, 2015 14:18
Show Gist options
  • Save sebdah/164a128f05f7fa4ed26b to your computer and use it in GitHub Desktop.
Save sebdah/164a128f05f7fa4ed26b to your computer and use it in GitHub Desktop.
{
"AWSTemplateFormatVersion":"2010-09-09",
"Description":"This is a sample CloudFormation template for deploying Dynamic DynamoDB. 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 and underscores."
},
"InstanceType":{
"Default":"t1.micro",
"Description":"AWS EC2 instance type",
"Type":"String"
}
},
"Mappings":{
"Region2AMI":{
"us-east-1":{
"64":"ami-fb8e9292"
},
"us-west-1":{
"64":"ami-7aba833f"
},
"us-west-2":{
"64":"ami-043a5034"
},
"eu-west-1":{
"64":"ami-2918e35e"
},
"sa-east-1":{
"64":"ami-215dff3c"
},
"ap-southeast-1":{
"64":"ami-b40d5ee6"
},
"ap-southeast-2":{
"64":"ami-3b4bd301"
},
"ap-northeast-1":{
"64":"ami-c9562fc8"
}
}
},
"Resources":{
"LaunchConfig":{
"Type":"AWS::AutoScaling::LaunchConfiguration",
"Properties":{
"ImageId":{
"Fn::FindInMap":[
"Region2AMI",
{
"Ref":"AWS::Region"
},
"64"
]
},
"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>=1.7.0,<2.0.0\">/etc/dynamic-dynamodb/requirements.txt",
"sudo 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/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":[
"ec2.amazonaws.com"
]
},
"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":[
"arn:aws:sns:*::dynamic-dynamodb"
]
}
]
}
}
]
}
},
"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"
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment