Source code for examples.ElastiCacheRedis

#!/usr/bin/env python
"""
Converted from ElastiCache_Redis.template located at:
http://aws.amazon.com/cloudformation/aws-cloudformation-templates/

In addition to troposphere, this script requires awacs (Amazon Web Access
Control Subsystem)
"""


import awacs
from awacs.aws import Allow, PolicyDocument, Principal, Statement
from awacs.sts import AssumeRole

import troposphere.ec2 as ec2
import troposphere.elasticache as elasticache
import troposphere.iam as iam
from troposphere import (
    Base64,
    FindInMap,
    GetAtt,
    Join,
    Output,
    Parameter,
    Ref,
    Tags,
    Template,
    cloudformation,
)
from troposphere.policies import CreationPolicy, ResourceSignal


[docs]def main(): """ Create a ElastiCache Redis Node and EC2 Instance """ template = Template() # Description template.set_description( "AWS CloudFormation Sample Template ElastiCache_Redis:" "Sample template showing how to create an Amazon" "ElastiCache Redis Cluster. **WARNING** This template" "creates an Amazon EC2 Instance and an Amazon ElastiCache" "Cluster. You will be billed for the AWS resources used" "if you create a stack from this template." ) # Mappings template.add_mapping( "AWSInstanceType2Arch", { "t1.micro": {"Arch": "PV64"}, "t2.micro": {"Arch": "HVM64"}, "t2.small": {"Arch": "HVM64"}, "t2.medium": {"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"}, "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"}, "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"}, }, ) template.add_mapping( "AWSRegionArch2AMI", { "us-east-1": { "PV64": "ami-0f4cfd64", "HVM64": "ami-0d4cfd66", "HVMG2": "ami-5b05ba30", }, "us-west-2": { "PV64": "ami-d3c5d1e3", "HVM64": "ami-d5c5d1e5", "HVMG2": "ami-a9d6c099", }, "us-west-1": { "PV64": "ami-85ea13c1", "HVM64": "ami-87ea13c3", "HVMG2": "ami-37827a73", }, "eu-west-1": { "PV64": "ami-d6d18ea1", "HVM64": "ami-e4d18e93", "HVMG2": "ami-72a9f105", }, "eu-central-1": { "PV64": "ami-a4b0b7b9", "HVM64": "ami-a6b0b7bb", "HVMG2": "ami-a6c9cfbb", }, "ap-northeast-1": { "PV64": "ami-1a1b9f1a", "HVM64": "ami-1c1b9f1c", "HVMG2": "ami-f644c4f6", }, "ap-southeast-1": { "PV64": "ami-d24b4280", "HVM64": "ami-d44b4286", "HVMG2": "ami-12b5bc40", }, "ap-southeast-2": { "PV64": "ami-ef7b39d5", "HVM64": "ami-db7b39e1", "HVMG2": "ami-b3337e89", }, "sa-east-1": { "PV64": "ami-5b098146", "HVM64": "ami-55098148", "HVMG2": "NOT_SUPPORTED", }, "cn-north-1": { "PV64": "ami-bec45887", "HVM64": "ami-bcc45885", "HVMG2": "NOT_SUPPORTED", }, }, ) template.add_mapping( "Region2Principal", { "us-east-1": { "EC2Principal": "ec2.amazonaws.com", "OpsWorksPrincipal": "opsworks.amazonaws.com", }, "us-west-2": { "EC2Principal": "ec2.amazonaws.com", "OpsWorksPrincipal": "opsworks.amazonaws.com", }, "us-west-1": { "EC2Principal": "ec2.amazonaws.com", "OpsWorksPrincipal": "opsworks.amazonaws.com", }, "eu-west-1": { "EC2Principal": "ec2.amazonaws.com", "OpsWorksPrincipal": "opsworks.amazonaws.com", }, "ap-southeast-1": { "EC2Principal": "ec2.amazonaws.com", "OpsWorksPrincipal": "opsworks.amazonaws.com", }, "ap-northeast-1": { "EC2Principal": "ec2.amazonaws.com", "OpsWorksPrincipal": "opsworks.amazonaws.com", }, "ap-southeast-2": { "EC2Principal": "ec2.amazonaws.com", "OpsWorksPrincipal": "opsworks.amazonaws.com", }, "sa-east-1": { "EC2Principal": "ec2.amazonaws.com", "OpsWorksPrincipal": "opsworks.amazonaws.com", }, "cn-north-1": { "EC2Principal": "ec2.amazonaws.com.cn", "OpsWorksPrincipal": "opsworks.amazonaws.com.cn", }, "eu-central-1": { "EC2Principal": "ec2.amazonaws.com", "OpsWorksPrincipal": "opsworks.amazonaws.com", }, }, ) # Parameters cachenodetype = template.add_parameter( Parameter( "ClusterNodeType", Description="The compute and memory capacity of the nodes in the Redis" " Cluster", Type="String", Default="cache.m1.small", AllowedValues=[ "cache.m1.small", "cache.m1.large", "cache.m1.xlarge", "cache.m2.xlarge", "cache.m2.2xlarge", "cache.m2.4xlarge", "cache.c1.xlarge", ], ConstraintDescription="must select a valid Cache Node type.", ) ) instancetype = template.add_parameter( Parameter( "InstanceType", Description="WebServer EC2 instance type", Type="String", Default="t2.micro", AllowedValues=[ "t1.micro", "t2.micro", "t2.small", "t2.medium", "m1.small", "m1.medium", "m1.large", "m1.xlarge", "m2.xlarge", "m2.2xlarge", "m2.4xlarge", "m3.medium", "m3.large", "m3.xlarge", "m3.2xlarge", "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", "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.", ) ) keyname = template.add_parameter( Parameter( "KeyName", Description="Name of an existing EC2 KeyPair to enable SSH access" " to the instance", Type="AWS::EC2::KeyPair::KeyName", ConstraintDescription="must be the name of an existing EC2 KeyPair.", ) ) sshlocation = template.add_parameter( Parameter( "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.", ) ) # Resources webserverrole = template.add_resource( iam.Role( "WebServerRole", AssumeRolePolicyDocument=PolicyDocument( Statement=[ Statement( Effect=Allow, Action=[AssumeRole], Principal=Principal( "Service", [ FindInMap( "Region2Principal", Ref("AWS::Region"), "EC2Principal", ) ], ), ) ] ), Path="/", ) ) template.add_resource( iam.PolicyType( "WebServerRolePolicy", PolicyName="WebServerRole", PolicyDocument=PolicyDocument( Statement=[ awacs.aws.Statement( Action=[ awacs.aws.Action("elasticache", "DescribeCacheClusters") ], Resource=["*"], Effect=awacs.aws.Allow, ) ] ), Roles=[Ref(webserverrole)], ) ) webserverinstanceprofile = template.add_resource( iam.InstanceProfile( "WebServerInstanceProfile", Path="/", Roles=[Ref(webserverrole)], ) ) webserversg = template.add_resource( ec2.SecurityGroup( "WebServerSecurityGroup", GroupDescription="Enable HTTP and SSH access", SecurityGroupIngress=[ ec2.SecurityGroupRule( IpProtocol="tcp", FromPort="22", ToPort="22", CidrIp=Ref(sshlocation), ), ec2.SecurityGroupRule( IpProtocol="tcp", FromPort="80", ToPort="80", CidrIp="0.0.0.0/0", ), ], ) ) webserverinstance = template.add_resource( ec2.Instance( "WebServerInstance", Metadata=cloudformation.Metadata( cloudformation.Init( { "config": cloudformation.InitConfig( packages={ "yum": { "httpd": [], "php": [], "php-devel": [], "gcc": [], "make": [], } }, files=cloudformation.InitFiles( { "/var/www/html/index.php": cloudformation.InitFile( content=Join( "", [ "<?php\n", 'echo "<h1>AWS CloudFormation sample' " application for Amazon ElastiCache" ' Redis Cluster</h1>";\n', "\n", "$cluster_config = json_decode(" "file_get_contents('/tmp/cacheclusterconfig'" "), true);\n", "$endpoint = $cluster_config['CacheClusters" "'][0]['CacheNodes'][0]['Endpoint']['Add" "ress'];\n", "$port = $cluster_config['CacheClusters'][0]" "['CacheNodes'][0]['Endpoint']['Port'];" "\n", "\n", 'echo "<p>Connecting to Redis Cache Cluster ' "node '{$endpoint}' on port {$port}</p>\";" "\n", "\n", "$redis=new Redis();\n", "$redis->connect($endpoint, $port);\n", "$redis->set('testkey', 'Hello World!');" "\n", "$return = $redis->get('testkey');\n", "\n", 'echo "<p>Retrieved value: $return</p>";' "\n", "?>\n", ], ), mode="000644", owner="apache", group="apache", ), "/etc/cron.d/get_cluster_config": cloudformation.InitFile( content="*/5 * * * * root" " /usr/local/bin/get_cluster_config", mode="000644", owner="root", group="root", ), "/usr/local/bin/get_cluster_config": cloudformation.InitFile( content=Join( "", [ "#! /bin/bash\n", "aws elasticache describe-cache-clusters ", " --cache-cluster-id ", Ref("RedisCluster"), " --show-cache-node-info" " --region ", Ref("AWS::Region"), " > /tmp/cacheclusterconfig\n", ], ), mode="000755", owner="root", group="root", ), "/usr/local/bin/install_phpredis": cloudformation.InitFile( content=Join( "", [ "#! /bin/bash\n", "cd /tmp\n", "wget https://github.com/nicolasff/" "phpredis/zipball/master -O phpredis.zip" "\n", "unzip phpredis.zip\n", "cd nicolasff-phpredis-*\n", "phpize\n", "./configure\n", "make && make install\n", "touch /etc/php.d/redis.ini\n", "echo extension=redis.so > /etc/php.d/" "redis.ini\n", ], ), mode="000755", owner="root", group="root", ), "/etc/cfn/cfn-hup.conf": cloudformation.InitFile( content=Join( "", [ "[main]\n", "stack=", Ref("AWS::StackId"), "\n", "region=", Ref("AWS::Region"), "\n", ], ), mode="000400", owner="root", group="root", ), "/etc/cfn/hooks.d/cfn-auto-reloader.conf": cloudformation.InitFile( content=Join( "", [ "[cfn-auto-reloader-hook]\n", "triggers=post.update\n", "path=Resources.WebServerInstance.Metadata" ".AWS::CloudFormation::Init\n", "action=/opt/aws/bin/cfn-init -v ", " --stack ", Ref("AWS::StackName"), " --resource WebServerInstance ", " --region ", Ref("AWS::Region"), "\n", "runas=root\n", ], ), # Why doesn't the Amazon template have this? # mode='000400', # owner='root', # group='root' ), } ), commands={ "01-install_phpredis": { "command": "/usr/local/bin/install_phpredis" }, "02-get-cluster-config": { "command": "/usr/local/bin/get_cluster_config" }, }, services={ "sysvinit": cloudformation.InitServices( { "httpd": cloudformation.InitService( enabled=True, ensureRunning=True, ), "cfn-hup": cloudformation.InitService( enabled=True, ensureRunning=True, files=[ "/etc/cfn/cfn-hup.conf", "/etc/cfn/hooks.d/" "cfn-auto-reloader.conf", ], ), } ), }, ) } ) ), ImageId=FindInMap( "AWSRegionArch2AMI", Ref("AWS::Region"), FindInMap("AWSInstanceType2Arch", Ref(instancetype), "Arch"), ), InstanceType=Ref(instancetype), SecurityGroups=[Ref(webserversg)], KeyName=Ref(keyname), IamInstanceProfile=Ref(webserverinstanceprofile), UserData=Base64( Join( "", [ "#!/bin/bash -xe\n", "yum update -y aws-cfn-bootstrap\n", "# Setup the PHP sample application\n", "/opt/aws/bin/cfn-init -v ", " --stack ", Ref("AWS::StackName"), " --resource WebServerInstance ", " --region ", Ref("AWS::Region"), "\n", "# Signal the status of cfn-init\n", "/opt/aws/bin/cfn-signal -e $? ", " --stack ", Ref("AWS::StackName"), " --resource WebServerInstance ", " --region ", Ref("AWS::Region"), "\n", ], ) ), CreationPolicy=CreationPolicy( ResourceSignal=ResourceSignal(Timeout="PT15M") ), Tags=Tags( Application=Ref("AWS::StackId"), Details="Created using Troposhpere" ), ) ) redisclustersg = template.add_resource( elasticache.SecurityGroup( "RedisClusterSecurityGroup", Description="Lock the cluster down", ) ) template.add_resource( elasticache.SecurityGroupIngress( "RedisClusterSecurityGroupIngress", CacheSecurityGroupName=Ref(redisclustersg), EC2SecurityGroupName=Ref(webserversg), ) ) template.add_resource( elasticache.CacheCluster( "RedisCluster", Engine="redis", CacheNodeType=Ref(cachenodetype), NumCacheNodes="1", CacheSecurityGroupNames=[Ref(redisclustersg)], ) ) # Outputs template.add_output( [ Output( "WebsiteURL", Description="Application URL", Value=Join( "", [ "http://", GetAtt(webserverinstance, "PublicDnsName"), ], ), ) ] ) # Print CloudFormation Template print(template.to_json())
if __name__ == "__main__": main()