spec/dslh_spec.rb in dslh-0.1.8 vs spec/dslh_spec.rb in dslh-0.1.9

- old
+ new

@@ -1,6 +1,10 @@ describe Dslh do + let(:drupal_multi_az_template) do + open(File.expand_path('../Drupal_Multi_AZ.template', __FILE__)) {|f| f.read } + end + it 'should be empty hash' do h = Dslh.eval {} expect(h).to eq({}) end @@ -495,14 +499,1192 @@ end EOS end it 'should convert json to dsl' do - url = 'https://s3.amazonaws.com/cloudformation-templates-us-east-1/Drupal_Multi_AZ.template' - template = open(url) {|f| f.read } - template = JSON.parse(template) + template = JSON.parse(drupal_multi_az_template) dsl = Dslh.deval(template) evaluated = Dslh.eval(dsl, :key_conv => proc {|i| i.to_s }) expect(evaluated).to eq(template) + end + + it 'should convert json to dsl with key_conf' do + template = JSON.parse(drupal_multi_az_template) + + key_conv = proc do |k| + k.to_s.gsub('::', '__') + end + + dsl = Dslh.deval(template, :key_conv => key_conv) + + expect(dsl).to eq(<<-'EOS') +AWSTemplateFormatVersion "2010-09-09" +Description "AWS CloudFormation Sample Template Drupal_Multi_AZ. Drupal is an open source content management platform powering millions of websites and applications. This template installs a highly-available, scalable Drupal deployment using a multi-az Amazon RDS database instance for storage. It uses the AWS CloudFormation bootstrap scripts to install packages and files at instance launch time. **WARNING** This template creates one or more Amazon EC2 instances, an Elastic Load Balancer and an Amazon RDS database. You will be billed for the AWS resources used if you create a stack from this template." +Parameters do + KeyName do + Description "Name of an existing EC2 KeyPair to enable SSH access to the instances" + Type "String" + MinLength "1" + MaxLength "255" + AllowedPattern "[\\x20-\\x7E]*" + ConstraintDescription "can contain only ASCII characters." + end + InstanceType do + Description "WebServer EC2 instance type" + Type "String" + Default "m1.small" + ConstraintDescription "must be a valid EC2 instance type." + end + SiteName do + Default "My Site" + Description "The name of the Drupal Site" + Type "String" + end + SiteEMail do + Description "EMail for site adminitrator" + Type "String" + end + SiteAdmin do + Description "The Drupal site admin account username" + Type "String" + MinLength "1" + MaxLength "16" + AllowedPattern "[a-zA-Z][a-zA-Z0-9]*" + ConstraintDescription "must begin with a letter and contain only alphanumeric characters." + end + SitePassword do + NoEcho "true" + Description "The Drupal site admin account password" + Type "String" + MinLength "1" + MaxLength "41" + AllowedPattern "[a-zA-Z0-9]*" + ConstraintDescription "must contain only alphanumeric characters." + end + DBName do + Default "drupaldb" + Description "The Drupal database name" + Type "String" + MinLength "1" + MaxLength "64" + AllowedPattern "[a-zA-Z][a-zA-Z0-9]*" + ConstraintDescription "must begin with a letter and contain only alphanumeric characters." + end + DBUsername do + Default "admin" + NoEcho "true" + Description "The Drupal database admin account username" + Type "String" + MinLength "1" + MaxLength "16" + AllowedPattern "[a-zA-Z][a-zA-Z0-9]*" + ConstraintDescription "must begin with a letter and contain only alphanumeric characters." + end + DBPassword do + Default "password" + NoEcho "true" + Description "The Drupal database admin account password" + Type "String" + MinLength "8" + MaxLength "41" + AllowedPattern "[a-zA-Z0-9]*" + ConstraintDescription "must contain only alphanumeric characters." + end + DBClass do + Default "db.m1.small" + Description "Database instance class" + Type "String" + AllowedValues "db.m1.small", "db.m1.large", "db.m1.xlarge", "db.m2.xlarge", "db.m2.2xlarge", "db.m2.4xlarge" + ConstraintDescription "must select a valid database instance type." + end + DBAllocatedStorage do + Default "5" + Description "The size of the database (Gb)" + Type "Number" + MinValue "5" + MaxValue "1024" + ConstraintDescription "must be between 5 and 1024Gb." + end + MultiAZDatabase do + Default "true" + Description "Create a multi-AZ MySQL Amazon RDS database instance" + Type "String" + AllowedValues "true", "false" + ConstraintDescription "must be either true or false." + end + WebServerCapacity do + Default "2" + Description "The initial number of WebServer instances" + Type "Number" + MinValue "1" + MaxValue "5" + ConstraintDescription "must be between 1 and 5 EC2 instances." + end + SSHLocation do + 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." + end +end +Mappings do + AWSInstanceType2Arch( + {"t1.micro"=>{"Arch"=>"64"}, + "m1.small"=>{"Arch"=>"64"}, + "m1.medium"=>{"Arch"=>"64"}, + "m1.large"=>{"Arch"=>"64"}, + "m1.xlarge"=>{"Arch"=>"64"}, + "m2.xlarge"=>{"Arch"=>"64"}, + "m2.2xlarge"=>{"Arch"=>"64"}, + "m2.4xlarge"=>{"Arch"=>"64"}, + "m3.xlarge"=>{"Arch"=>"64"}, + "m3.2xlarge"=>{"Arch"=>"64"}, + "c1.medium"=>{"Arch"=>"64"}, + "c1.xlarge"=>{"Arch"=>"64"}, + "cc1.4xlarge"=>{"Arch"=>"64HVM"}, + "cc2.8xlarge"=>{"Arch"=>"64HVM"}, + "cg1.4xlarge"=>{"Arch"=>"64HVM"}}) + AWSRegionArch2AMI( + {"us-east-1"=> + {"32"=>"ami-a0cd60c9", "64"=>"ami-aecd60c7", "64HVM"=>"ami-a8cd60c1"}, + "us-west-2"=> + {"32"=>"ami-46da5576", "64"=>"ami-48da5578", "64HVM"=>"NOT_YET_SUPPORTED"}, + "us-west-1"=> + {"32"=>"ami-7d4c6938", "64"=>"ami-734c6936", "64HVM"=>"NOT_YET_SUPPORTED"}, + "eu-west-1"=> + {"32"=>"ami-61555115", "64"=>"ami-6d555119", "64HVM"=>"ami-67555113"}, + "ap-southeast-1"=> + {"32"=>"ami-220b4a70", "64"=>"ami-3c0b4a6e", "64HVM"=>"NOT_YET_SUPPORTED"}, + "ap-southeast-2"=> + {"32"=>"ami-8f990eb5", "64"=>"ami-95990eaf", "64HVM"=>"NOT_YET_SUPPORTED"}, + "ap-northeast-1"=> + {"32"=>"ami-2a19aa2b", "64"=>"ami-2819aa29", "64HVM"=>"NOT_YET_SUPPORTED"}, + "sa-east-1"=> + {"32"=>"ami-f836e8e5", "64"=>"ami-fe36e8e3", "64HVM"=>"NOT_YET_SUPPORTED"}}) +end +Resources do + S3Bucket do + Type "AWS::S3::Bucket" + DeletionPolicy "Retain" + end + BucketPolicy do + Type "AWS::S3::BucketPolicy" + Properties do + PolicyDocument do + Version "2008-10-17" + Id "UploadPolicy" + Statement [ + _{ + Sid "EnableReadWrite" + Action "s3:GetObject", "s3:PutObject", "s3:PutObjectACL" + Effect "Allow" + Resource do + Fn__Join [ + "", + ["arn:aws:s3:::", {"Ref"=>"S3Bucket"}, "/*"] + ] + end + Principal do + AWS do + Fn__GetAtt "S3User", "Arn" + end + end + } + ] + end + Bucket do + Ref "S3Bucket" + end + end + end + S3User do + Type "AWS::IAM::User" + Properties do + Path "/" + Policies [ + _{ + PolicyName "root" + PolicyDocument do + Statement [ + _{ + Effect "Allow" + Action "s3:*" + Resource "*" + } + ] + end + } + ] + end + end + S3Keys do + Type "AWS::IAM::AccessKey" + Properties do + UserName do + Ref "S3User" + end + end + end + ElasticLoadBalancer do + Type "AWS::ElasticLoadBalancing::LoadBalancer" + Metadata do + Comment "Configure the Load Balancer with a simple health check and cookie-based stickiness" + end + Properties do + AvailabilityZones do + Fn__GetAZs "" + end + LBCookieStickinessPolicy [ + _{ + PolicyName "CookieBasedPolicy" + CookieExpirationPeriod "30" + } + ] + Listeners [ + _{ + LoadBalancerPort "80" + InstancePort "80" + Protocol "HTTP" + PolicyNames ["CookieBasedPolicy"] + } + ] + HealthCheck do + Target "HTTP:80/" + HealthyThreshold "2" + UnhealthyThreshold "5" + Interval "10" + Timeout "5" + end + end + end + WebServerGroup do + Type "AWS::AutoScaling::AutoScalingGroup" + Properties do + AvailabilityZones do + Fn__GetAZs "" + end + LaunchConfigurationName do + Ref "LaunchConfig" + end + MinSize "1" + MaxSize "5" + DesiredCapacity do + Ref "WebServerCapacity" + end + LoadBalancerNames [ + _{ + Ref "ElasticLoadBalancer" + } + ] + end + end + LaunchConfig do + Type "AWS::AutoScaling::LaunchConfiguration" + Metadata do + AWS__CloudFormation__Init do + config do + packages do + yum( + {"httpd"=>[], + "php"=>[], + "php-mysql"=>[], + "php-gd"=>[], + "php-xml"=>[], + "php-mbstring"=>[], + "mysql"=>[], + "gcc"=>[], + "make"=>[], + "libstdc++-devel"=>[], + "gcc-c++"=>[], + "fuse"=>[], + "fuse-devel"=>[], + "libcurl-devel"=>[], + "libxml2-devel"=>[], + "openssl-devel"=>[], + "mailcap"=>[]}) + end + sources( + {"/var/www/html"=>"http://ftp.drupal.org/files/projects/drupal-7.8.tar.gz", + "/home/ec2-user"=>"http://ftp.drupal.org/files/projects/drush-7.x-4.5.tar.gz", + "/home/ec2-user/s3fs"=>"http://s3fs.googlecode.com/files/s3fs-1.61.tar.gz"}) + files( + {"/etc/passwd-s3fs"=> + {"content"=> + {"Fn::Join"=> + ["", + [{"Ref"=>"S3Keys"}, + ":", + {"Fn::GetAtt"=>["S3Keys", "SecretAccessKey"]}, + "\n"]]}, + "mode"=>"000400", + "owner"=>"root", + "group"=>"root"}, + "/home/ec2-user/settings.php"=> + {"content"=> + {"Fn::Join"=> + ["", + ["<?php\n", + "\n", + "$databases = array (\n", + " 'default' =>\n", + " array (\n", + " 'default' =>\n", + " array (\n", + " 'database' => '", + {"Ref"=>"DBName"}, + "',\n", + " 'username' => '", + {"Ref"=>"DBUsername"}, + "',\n", + " 'password' => '", + {"Ref"=>"DBPassword"}, + "',\n", + " 'host' => '", + {"Fn::GetAtt"=>["DBInstance", "Endpoint.Address"]}, + "',\n", + " 'port' => '", + {"Fn::GetAtt"=>["DBInstance", "Endpoint.Port"]}, + "',\n", + " 'driver' => 'mysql',\n", + " 'prefix' => 'drupal_',\n", + " ),\n", + " ),\n", + ");\n", + "\n", + "$update_free_access = FALSE;\n", + "\n", + "$drupal_hash_salt = '0c3R8noNALe3shsioQr5hK1dMHdwRfikLoSfqn0_xpA';\n", + "\n", + "ini_set('session.gc_probability', 1);\n", + "ini_set('session.gc_divisor', 100);\n", + "ini_set('session.gc_maxlifetime', 200000);\n", + "ini_set('session.cookie_lifetime', 2000000);\n"]]}, + "mode"=>"000400", + "owner"=>"root", + "group"=>"root"}}) + services do + sysvinit do + httpd do + enabled "true" + ensureRunning "true" + end + sendmail do + enabled "false" + ensureRunning "false" + end + end + end + end + end + end + Properties do + ImageId do + Fn__FindInMap [ + "AWSRegionArch2AMI", + _{ + Ref "AWS::Region" + }, + _{ + Fn__FindInMap [ + "AWSInstanceType2Arch", + _{ + Ref "InstanceType" + }, + "Arch" + ] + } + ] + end + InstanceType do + Ref "InstanceType" + end + SecurityGroups [ + _{ + Ref "WebServerSecurityGroup" + } + ] + KeyName do + Ref "KeyName" + end + UserData do + Fn__Base64 do + Fn__Join [ + "", + ["#!/bin/bash -v\n", + "yum update -y aws-cfn-bootstrap\n", + "# Helper function\n", + "function error_exit\n", + "{\n", + " /opt/aws/bin/cfn-signal -e 1 -r \"$1\" '", + {"Ref"=>"WaitHandle"}, + "'\n", + " exit 1\n", + "}\n", + "# Install Apache Web Server, MySQL and Drupal\n", + "/opt/aws/bin/cfn-init -s ", + {"Ref"=>"AWS::StackId"}, + " -r LaunchConfig ", + " --region ", + {"Ref"=>"AWS::Region"}, + " || error_exit 'Failed to run cfn-init'\n", + "# Install s3fs\n", + "cd /home/ec2-user/s3fs/s3fs-1.61\n", + "./configure --prefix=/usr\n", + "make\n", + "make install\n", + "# Move the website files to the top level\n", + "mv /var/www/html/drupal-7.8/* /var/www/html\n", + "mv /var/www/html/drupal-7.8/.htaccess /var/www/html\n", + "rm -Rf /var/www/html/drupal-7.8\n", + "# Mount the S3 bucket\n", + "mv /var/www/html/sites/default/files /var/www/html/sites/default/files_original\n", + "mkdir -p /var/www/html/sites/default/files\n", + "s3fs -o allow_other -o use_cache=/tmp ", + {"Ref"=>"S3Bucket"}, + " /var/www/html/sites/default/files || error_exit 'Failed to mount the S3 bucket'\n", + "echo `hostname` >> /var/www/html/sites/default/files/hosts\n", + "# Make changes to Apache Web Server configuration\n", + "sed -i 's/AllowOverride None/AllowOverride All/g' /etc/httpd/conf/httpd.conf\n", + "service httpd restart\n", + "# Only execute the site install if we are the first host up - otherwise we'll end up losing all the data\n", + "read first < /var/www/html/sites/default/files/hosts\n", + "if [ `hostname` = $first ]\n", + "then\n", + " # Create the site in Drupal\n", + " cd /var/www/html\n", + " ~ec2-user/drush/drush site-install standard --yes", + " --site-name='", + {"Ref"=>"SiteName"}, + "' --site-mail=", + {"Ref"=>"SiteEMail"}, + " --account-name=", + {"Ref"=>"SiteAdmin"}, + " --account-pass=", + {"Ref"=>"SitePassword"}, + " --db-url=mysql://", + {"Ref"=>"DBUsername"}, + ":", + {"Ref"=>"DBPassword"}, + "@", + {"Fn::GetAtt"=>["DBInstance", "Endpoint.Address"]}, + ":", + {"Fn::GetAtt"=>["DBInstance", "Endpoint.Port"]}, + "/", + {"Ref"=>"DBName"}, + " --db-prefix=drupal_\n", + " # use the S3 bucket for shared file storage\n", + " cp -R sites/default/files_original/* sites/default/files\n", + " cp -R sites/default/files_original/.htaccess sites/default/files\n", + "else\n", + " # Copy settings.php file since everything else is configured\n", + " cp /home/ec2-user/settings.php /var/www/html/sites/default\n", + "fi\n", + "rm /home/ec2-user/settings.php\n", + "# All is well so signal success\n", + "/opt/aws/bin/cfn-signal -e 0 -r \"Drupal setup complete\" '", + {"Ref"=>"WaitHandle"}, + "'\n"] + ] + end + end + end + end + WaitHandle do + Type "AWS::CloudFormation::WaitConditionHandle" + end + WaitCondition do + Type "AWS::CloudFormation::WaitCondition" + DependsOn "WebServerGroup" + Properties do + Handle do + Ref "WaitHandle" + end + Timeout "600" + end + end + DBInstance do + Type "AWS::RDS::DBInstance" + Properties do + DBName do + Ref "DBName" + end + Engine "MySQL" + MultiAZ do + Ref "MultiAZDatabase" + end + MasterUsername do + Ref "DBUsername" + end + DBInstanceClass do + Ref "DBClass" + end + DBSecurityGroups [ + _{ + Ref "DBSecurityGroup" + } + ] + AllocatedStorage do + Ref "DBAllocatedStorage" + end + MasterUserPassword do + Ref "DBPassword" + end + end + end + DBSecurityGroup do + Type "AWS::RDS::DBSecurityGroup" + Properties do + DBSecurityGroupIngress do + EC2SecurityGroupName do + Ref "WebServerSecurityGroup" + end + end + GroupDescription "Frontend Access" + end + end + WebServerSecurityGroup do + Type "AWS::EC2::SecurityGroup" + Properties do + GroupDescription "Enable HTTP access via port 80, locked down to requests from the load balancer only and SSH access" + SecurityGroupIngress [ + _{ + IpProtocol "tcp" + FromPort "80" + ToPort "80" + SourceSecurityGroupOwnerId do + Fn__GetAtt "ElasticLoadBalancer", "SourceSecurityGroup.OwnerAlias" + end + SourceSecurityGroupName do + Fn__GetAtt "ElasticLoadBalancer", "SourceSecurityGroup.GroupName" + end + }, + _{ + IpProtocol "tcp" + FromPort "22" + ToPort "22" + CidrIp do + Ref "SSHLocation" + end + } + ] + end + end +end +Outputs do + WebsiteURL do + Value do + Fn__Join [ + "", + ["http://", {"Fn::GetAtt"=>["ElasticLoadBalancer", "DNSName"]}] + ] + end + Description "Drupal Website" + end +end + EOS + end + + it 'should convert json to dsl with key_conf (return Proc)' do + template = JSON.parse(drupal_multi_az_template) + + exclude_key = proc do |k| + k = k.to_s.gsub('::', '__') + k !~ /\A[_a-z]\w+\Z/i and k !~ %r|(?:/[:graph:]+)+| + end + + key_conv = proc do |k| + k = k.to_s + + if k =~ %r|(?:/[:graph:]+)+| + proc do |v, nested| + if nested + "_path(#{k.inspect}) #{v}" + else + "_path #{k.inspect}, #{v}" + end + end + else + k.gsub('::', '__') + end + end + + dsl = Dslh.deval(template, :key_conv => key_conv, :exclude_key => exclude_key) + + expect(dsl).to eq(<<-'EOS') +AWSTemplateFormatVersion "2010-09-09" +Description "AWS CloudFormation Sample Template Drupal_Multi_AZ. Drupal is an open source content management platform powering millions of websites and applications. This template installs a highly-available, scalable Drupal deployment using a multi-az Amazon RDS database instance for storage. It uses the AWS CloudFormation bootstrap scripts to install packages and files at instance launch time. **WARNING** This template creates one or more Amazon EC2 instances, an Elastic Load Balancer and an Amazon RDS database. You will be billed for the AWS resources used if you create a stack from this template." +Parameters do + KeyName do + Description "Name of an existing EC2 KeyPair to enable SSH access to the instances" + Type "String" + MinLength "1" + MaxLength "255" + AllowedPattern "[\\x20-\\x7E]*" + ConstraintDescription "can contain only ASCII characters." + end + InstanceType do + Description "WebServer EC2 instance type" + Type "String" + Default "m1.small" + ConstraintDescription "must be a valid EC2 instance type." + end + SiteName do + Default "My Site" + Description "The name of the Drupal Site" + Type "String" + end + SiteEMail do + Description "EMail for site adminitrator" + Type "String" + end + SiteAdmin do + Description "The Drupal site admin account username" + Type "String" + MinLength "1" + MaxLength "16" + AllowedPattern "[a-zA-Z][a-zA-Z0-9]*" + ConstraintDescription "must begin with a letter and contain only alphanumeric characters." + end + SitePassword do + NoEcho "true" + Description "The Drupal site admin account password" + Type "String" + MinLength "1" + MaxLength "41" + AllowedPattern "[a-zA-Z0-9]*" + ConstraintDescription "must contain only alphanumeric characters." + end + DBName do + Default "drupaldb" + Description "The Drupal database name" + Type "String" + MinLength "1" + MaxLength "64" + AllowedPattern "[a-zA-Z][a-zA-Z0-9]*" + ConstraintDescription "must begin with a letter and contain only alphanumeric characters." + end + DBUsername do + Default "admin" + NoEcho "true" + Description "The Drupal database admin account username" + Type "String" + MinLength "1" + MaxLength "16" + AllowedPattern "[a-zA-Z][a-zA-Z0-9]*" + ConstraintDescription "must begin with a letter and contain only alphanumeric characters." + end + DBPassword do + Default "password" + NoEcho "true" + Description "The Drupal database admin account password" + Type "String" + MinLength "8" + MaxLength "41" + AllowedPattern "[a-zA-Z0-9]*" + ConstraintDescription "must contain only alphanumeric characters." + end + DBClass do + Default "db.m1.small" + Description "Database instance class" + Type "String" + AllowedValues "db.m1.small", "db.m1.large", "db.m1.xlarge", "db.m2.xlarge", "db.m2.2xlarge", "db.m2.4xlarge" + ConstraintDescription "must select a valid database instance type." + end + DBAllocatedStorage do + Default "5" + Description "The size of the database (Gb)" + Type "Number" + MinValue "5" + MaxValue "1024" + ConstraintDescription "must be between 5 and 1024Gb." + end + MultiAZDatabase do + Default "true" + Description "Create a multi-AZ MySQL Amazon RDS database instance" + Type "String" + AllowedValues "true", "false" + ConstraintDescription "must be either true or false." + end + WebServerCapacity do + Default "2" + Description "The initial number of WebServer instances" + Type "Number" + MinValue "1" + MaxValue "5" + ConstraintDescription "must be between 1 and 5 EC2 instances." + end + SSHLocation do + 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." + end +end +Mappings do + AWSInstanceType2Arch( + {"t1.micro"=>{"Arch"=>"64"}, + "m1.small"=>{"Arch"=>"64"}, + "m1.medium"=>{"Arch"=>"64"}, + "m1.large"=>{"Arch"=>"64"}, + "m1.xlarge"=>{"Arch"=>"64"}, + "m2.xlarge"=>{"Arch"=>"64"}, + "m2.2xlarge"=>{"Arch"=>"64"}, + "m2.4xlarge"=>{"Arch"=>"64"}, + "m3.xlarge"=>{"Arch"=>"64"}, + "m3.2xlarge"=>{"Arch"=>"64"}, + "c1.medium"=>{"Arch"=>"64"}, + "c1.xlarge"=>{"Arch"=>"64"}, + "cc1.4xlarge"=>{"Arch"=>"64HVM"}, + "cc2.8xlarge"=>{"Arch"=>"64HVM"}, + "cg1.4xlarge"=>{"Arch"=>"64HVM"}}) + AWSRegionArch2AMI( + {"us-east-1"=> + {"32"=>"ami-a0cd60c9", "64"=>"ami-aecd60c7", "64HVM"=>"ami-a8cd60c1"}, + "us-west-2"=> + {"32"=>"ami-46da5576", "64"=>"ami-48da5578", "64HVM"=>"NOT_YET_SUPPORTED"}, + "us-west-1"=> + {"32"=>"ami-7d4c6938", "64"=>"ami-734c6936", "64HVM"=>"NOT_YET_SUPPORTED"}, + "eu-west-1"=> + {"32"=>"ami-61555115", "64"=>"ami-6d555119", "64HVM"=>"ami-67555113"}, + "ap-southeast-1"=> + {"32"=>"ami-220b4a70", "64"=>"ami-3c0b4a6e", "64HVM"=>"NOT_YET_SUPPORTED"}, + "ap-southeast-2"=> + {"32"=>"ami-8f990eb5", "64"=>"ami-95990eaf", "64HVM"=>"NOT_YET_SUPPORTED"}, + "ap-northeast-1"=> + {"32"=>"ami-2a19aa2b", "64"=>"ami-2819aa29", "64HVM"=>"NOT_YET_SUPPORTED"}, + "sa-east-1"=> + {"32"=>"ami-f836e8e5", "64"=>"ami-fe36e8e3", "64HVM"=>"NOT_YET_SUPPORTED"}}) +end +Resources do + S3Bucket do + Type "AWS::S3::Bucket" + DeletionPolicy "Retain" + end + BucketPolicy do + Type "AWS::S3::BucketPolicy" + Properties do + PolicyDocument do + Version "2008-10-17" + Id "UploadPolicy" + Statement [ + _{ + Sid "EnableReadWrite" + Action "s3:GetObject", "s3:PutObject", "s3:PutObjectACL" + Effect "Allow" + Resource do + Fn__Join [ + "", + ["arn:aws:s3:::", {"Ref"=>"S3Bucket"}, "/*"] + ] + end + Principal do + AWS do + Fn__GetAtt "S3User", "Arn" + end + end + } + ] + end + Bucket do + Ref "S3Bucket" + end + end + end + S3User do + Type "AWS::IAM::User" + Properties do + Path "/" + Policies [ + _{ + PolicyName "root" + PolicyDocument do + Statement [ + _{ + Effect "Allow" + Action "s3:*" + Resource "*" + } + ] + end + } + ] + end + end + S3Keys do + Type "AWS::IAM::AccessKey" + Properties do + UserName do + Ref "S3User" + end + end + end + ElasticLoadBalancer do + Type "AWS::ElasticLoadBalancing::LoadBalancer" + Metadata do + Comment "Configure the Load Balancer with a simple health check and cookie-based stickiness" + end + Properties do + AvailabilityZones do + Fn__GetAZs "" + end + LBCookieStickinessPolicy [ + _{ + PolicyName "CookieBasedPolicy" + CookieExpirationPeriod "30" + } + ] + Listeners [ + _{ + LoadBalancerPort "80" + InstancePort "80" + Protocol "HTTP" + PolicyNames ["CookieBasedPolicy"] + } + ] + HealthCheck do + Target "HTTP:80/" + HealthyThreshold "2" + UnhealthyThreshold "5" + Interval "10" + Timeout "5" + end + end + end + WebServerGroup do + Type "AWS::AutoScaling::AutoScalingGroup" + Properties do + AvailabilityZones do + Fn__GetAZs "" + end + LaunchConfigurationName do + Ref "LaunchConfig" + end + MinSize "1" + MaxSize "5" + DesiredCapacity do + Ref "WebServerCapacity" + end + LoadBalancerNames [ + _{ + Ref "ElasticLoadBalancer" + } + ] + end + end + LaunchConfig do + Type "AWS::AutoScaling::LaunchConfiguration" + Metadata do + AWS__CloudFormation__Init do + config do + packages do + yum( + {"httpd"=>[], + "php"=>[], + "php-mysql"=>[], + "php-gd"=>[], + "php-xml"=>[], + "php-mbstring"=>[], + "mysql"=>[], + "gcc"=>[], + "make"=>[], + "libstdc++-devel"=>[], + "gcc-c++"=>[], + "fuse"=>[], + "fuse-devel"=>[], + "libcurl-devel"=>[], + "libxml2-devel"=>[], + "openssl-devel"=>[], + "mailcap"=>[]}) + end + sources do + _path "/var/www/html", "http://ftp.drupal.org/files/projects/drupal-7.8.tar.gz" + _path "/home/ec2-user", "http://ftp.drupal.org/files/projects/drush-7.x-4.5.tar.gz" + _path "/home/ec2-user/s3fs", "http://s3fs.googlecode.com/files/s3fs-1.61.tar.gz" + end + files do + _path("/etc/passwd-s3fs") do + content do + Fn__Join [ + "", + [{"Ref"=>"S3Keys"}, ":", {"Fn::GetAtt"=>["S3Keys", "SecretAccessKey"]}, "\n"] + ] + end + mode "000400" + owner "root" + group "root" + end + _path("/home/ec2-user/settings.php") do + content do + Fn__Join [ + "", + ["<?php\n", + "\n", + "$databases = array (\n", + " 'default' =>\n", + " array (\n", + " 'default' =>\n", + " array (\n", + " 'database' => '", + {"Ref"=>"DBName"}, + "',\n", + " 'username' => '", + {"Ref"=>"DBUsername"}, + "',\n", + " 'password' => '", + {"Ref"=>"DBPassword"}, + "',\n", + " 'host' => '", + {"Fn::GetAtt"=>["DBInstance", "Endpoint.Address"]}, + "',\n", + " 'port' => '", + {"Fn::GetAtt"=>["DBInstance", "Endpoint.Port"]}, + "',\n", + " 'driver' => 'mysql',\n", + " 'prefix' => 'drupal_',\n", + " ),\n", + " ),\n", + ");\n", + "\n", + "$update_free_access = FALSE;\n", + "\n", + "$drupal_hash_salt = '0c3R8noNALe3shsioQr5hK1dMHdwRfikLoSfqn0_xpA';\n", + "\n", + "ini_set('session.gc_probability', 1);\n", + "ini_set('session.gc_divisor', 100);\n", + "ini_set('session.gc_maxlifetime', 200000);\n", + "ini_set('session.cookie_lifetime', 2000000);\n"] + ] + end + mode "000400" + owner "root" + group "root" + end + end + services do + sysvinit do + httpd do + enabled "true" + ensureRunning "true" + end + sendmail do + enabled "false" + ensureRunning "false" + end + end + end + end + end + end + Properties do + ImageId do + Fn__FindInMap [ + "AWSRegionArch2AMI", + _{ + Ref "AWS::Region" + }, + _{ + Fn__FindInMap [ + "AWSInstanceType2Arch", + _{ + Ref "InstanceType" + }, + "Arch" + ] + } + ] + end + InstanceType do + Ref "InstanceType" + end + SecurityGroups [ + _{ + Ref "WebServerSecurityGroup" + } + ] + KeyName do + Ref "KeyName" + end + UserData do + Fn__Base64 do + Fn__Join [ + "", + ["#!/bin/bash -v\n", + "yum update -y aws-cfn-bootstrap\n", + "# Helper function\n", + "function error_exit\n", + "{\n", + " /opt/aws/bin/cfn-signal -e 1 -r \"$1\" '", + {"Ref"=>"WaitHandle"}, + "'\n", + " exit 1\n", + "}\n", + "# Install Apache Web Server, MySQL and Drupal\n", + "/opt/aws/bin/cfn-init -s ", + {"Ref"=>"AWS::StackId"}, + " -r LaunchConfig ", + " --region ", + {"Ref"=>"AWS::Region"}, + " || error_exit 'Failed to run cfn-init'\n", + "# Install s3fs\n", + "cd /home/ec2-user/s3fs/s3fs-1.61\n", + "./configure --prefix=/usr\n", + "make\n", + "make install\n", + "# Move the website files to the top level\n", + "mv /var/www/html/drupal-7.8/* /var/www/html\n", + "mv /var/www/html/drupal-7.8/.htaccess /var/www/html\n", + "rm -Rf /var/www/html/drupal-7.8\n", + "# Mount the S3 bucket\n", + "mv /var/www/html/sites/default/files /var/www/html/sites/default/files_original\n", + "mkdir -p /var/www/html/sites/default/files\n", + "s3fs -o allow_other -o use_cache=/tmp ", + {"Ref"=>"S3Bucket"}, + " /var/www/html/sites/default/files || error_exit 'Failed to mount the S3 bucket'\n", + "echo `hostname` >> /var/www/html/sites/default/files/hosts\n", + "# Make changes to Apache Web Server configuration\n", + "sed -i 's/AllowOverride None/AllowOverride All/g' /etc/httpd/conf/httpd.conf\n", + "service httpd restart\n", + "# Only execute the site install if we are the first host up - otherwise we'll end up losing all the data\n", + "read first < /var/www/html/sites/default/files/hosts\n", + "if [ `hostname` = $first ]\n", + "then\n", + " # Create the site in Drupal\n", + " cd /var/www/html\n", + " ~ec2-user/drush/drush site-install standard --yes", + " --site-name='", + {"Ref"=>"SiteName"}, + "' --site-mail=", + {"Ref"=>"SiteEMail"}, + " --account-name=", + {"Ref"=>"SiteAdmin"}, + " --account-pass=", + {"Ref"=>"SitePassword"}, + " --db-url=mysql://", + {"Ref"=>"DBUsername"}, + ":", + {"Ref"=>"DBPassword"}, + "@", + {"Fn::GetAtt"=>["DBInstance", "Endpoint.Address"]}, + ":", + {"Fn::GetAtt"=>["DBInstance", "Endpoint.Port"]}, + "/", + {"Ref"=>"DBName"}, + " --db-prefix=drupal_\n", + " # use the S3 bucket for shared file storage\n", + " cp -R sites/default/files_original/* sites/default/files\n", + " cp -R sites/default/files_original/.htaccess sites/default/files\n", + "else\n", + " # Copy settings.php file since everything else is configured\n", + " cp /home/ec2-user/settings.php /var/www/html/sites/default\n", + "fi\n", + "rm /home/ec2-user/settings.php\n", + "# All is well so signal success\n", + "/opt/aws/bin/cfn-signal -e 0 -r \"Drupal setup complete\" '", + {"Ref"=>"WaitHandle"}, + "'\n"] + ] + end + end + end + end + WaitHandle do + Type "AWS::CloudFormation::WaitConditionHandle" + end + WaitCondition do + Type "AWS::CloudFormation::WaitCondition" + DependsOn "WebServerGroup" + Properties do + Handle do + Ref "WaitHandle" + end + Timeout "600" + end + end + DBInstance do + Type "AWS::RDS::DBInstance" + Properties do + DBName do + Ref "DBName" + end + Engine "MySQL" + MultiAZ do + Ref "MultiAZDatabase" + end + MasterUsername do + Ref "DBUsername" + end + DBInstanceClass do + Ref "DBClass" + end + DBSecurityGroups [ + _{ + Ref "DBSecurityGroup" + } + ] + AllocatedStorage do + Ref "DBAllocatedStorage" + end + MasterUserPassword do + Ref "DBPassword" + end + end + end + DBSecurityGroup do + Type "AWS::RDS::DBSecurityGroup" + Properties do + DBSecurityGroupIngress do + EC2SecurityGroupName do + Ref "WebServerSecurityGroup" + end + end + GroupDescription "Frontend Access" + end + end + WebServerSecurityGroup do + Type "AWS::EC2::SecurityGroup" + Properties do + GroupDescription "Enable HTTP access via port 80, locked down to requests from the load balancer only and SSH access" + SecurityGroupIngress [ + _{ + IpProtocol "tcp" + FromPort "80" + ToPort "80" + SourceSecurityGroupOwnerId do + Fn__GetAtt "ElasticLoadBalancer", "SourceSecurityGroup.OwnerAlias" + end + SourceSecurityGroupName do + Fn__GetAtt "ElasticLoadBalancer", "SourceSecurityGroup.GroupName" + end + }, + _{ + IpProtocol "tcp" + FromPort "22" + ToPort "22" + CidrIp do + Ref "SSHLocation" + end + } + ] + end + end +end +Outputs do + WebsiteURL do + Value do + Fn__Join [ + "", + ["http://", {"Fn::GetAtt"=>["ElasticLoadBalancer", "DNSName"]}] + ] + end + Description "Drupal Website" + end +end +EOS end end