spec/kumogata_convert_spec.rb in kumogata-0.4.17 vs spec/kumogata_convert_spec.rb in kumogata-0.4.18
- old
+ new
@@ -124,10 +124,109 @@
end
end
EOS
end
+ it 'convert Ruby template to JavaScript template' do
+ template = <<-EOS
+Resources do
+ myEC2Instance do
+ Type "AWS::EC2::Instance"
+ Properties do
+ ImageId "ami-XXXXXXXX"
+ InstanceType "t1.micro"
+ end
+ end
+end
+
+Outputs do
+ AZ do
+ Value do
+ Fn__GetAtt "myEC2Instance", "AvailabilityZone"
+ end
+ end
+end
+ EOS
+
+ js_template = run_client(:convert, :template => template, :options => {:output_format => :js})
+
+ expect(js_template).to eq <<-EOS.strip
+({
+ "Resources": {
+ "myEC2Instance": {
+ "Type": "AWS::EC2::Instance",
+ "Properties": {
+ "ImageId": "ami-XXXXXXXX",
+ "InstanceType": "t1.micro"
+ }
+ }
+ },
+ "Outputs": {
+ "AZ": {
+ "Value": {
+ "Fn::GetAtt": [
+ "myEC2Instance",
+ "AvailabilityZone"
+ ]
+ }
+ }
+ }
+})
+ EOS
+ end
+
+ it 'convert JavaScript template to Ruby template' do
+ template = <<-EOS
+function fetch_ami() {
+ return "ami-XXXXXXXX";
+}
+
+({
+ Resources: { /* comment */
+ myEC2Instance: {
+ Type: "AWS::EC2::Instance",
+ Properties: {
+ ImageId: fetch_ami(),
+ InstanceType: "t1.micro"
+ }
+ }
+ },
+ Outputs: {
+ AZ: { /* comment */
+ Value: {
+ "Fn::GetAtt": [
+ "myEC2Instance",
+ "AvailabilityZone"
+ ]
+ }
+ }
+ }
+})
+ EOS
+
+ ruby_template = run_client(:convert, :template => template, :template_ext => '.js', :options => {:output_format => :ruby})
+
+ expect(ruby_template).to eq((<<-EOS).chomp)
+Resources do
+ myEC2Instance do
+ Type "AWS::EC2::Instance"
+ Properties do
+ ImageId "ami-XXXXXXXX"
+ InstanceType "t1.micro"
+ end
+ end
+end
+Outputs do
+ AZ do
+ Value do
+ Fn__GetAtt "myEC2Instance", "AvailabilityZone"
+ end
+ end
+end
+ EOS
+ end
+
it 'convert YAML template to JSON template' do
template = <<-EOS
---
Resources:
myEC2Instance:
@@ -860,7 +959,1301 @@
json_template = JSON.parse(drupal_single_instance_template)
ruby_template = run_client(:convert, :template => drupal_single_instance_template_rb)
ruby_template = JSON.parse(ruby_template)
expect(ruby_template).to eq(json_template)
+ end
+
+ let(:vpc_knowhow_2014_04_template) do
+ path = File.expand_path('../vpc-knowhow-2014-04.template', __FILE__)
+ open(path) {|f| f.read }
+ end
+
+ it 'convert JSON template to Ruby template (include yum key)' do
+ ruby_template = run_client(:convert, :template => vpc_knowhow_2014_04_template, :template_ext => '.template')
+
+ expect(ruby_template).to eq <<-'EOS'.strip
+AWSTemplateFormatVersion "2010-09-09"
+Description "VPC knowhow template"
+Parameters do
+ KeyName do
+ Description "Name of an existing EC2 KeyPair to enable SSH access to the instances"
+ Type "String"
+ MinLength 1
+ MaxLength 64
+ AllowedPattern "[-_ a-zA-Z0-9]*"
+ ConstraintDescription "can contain only alphanumeric characters, spaces, dashes and underscores."
+ end
+ SSHFrom do
+ Description "Lockdown SSH access to the bastion host (default can be accessed from anywhere)"
+ 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 CIDR range of the form x.x.x.x/x."
+ end
+ DBInstanceType do
+ Description "EC2 instance type for the Blue environment"
+ Default "db.t1.micro"
+ Type "String"
+ end
+ DBSnapshotName do
+ Default ""
+ Description "The name of a DB snapshot (optional)"
+ Type "String"
+ end
+ DBAllocatedStorage do
+ Default 5
+ Description "DB instance disk size"
+ Type "Number"
+ end
+ DBUsername do
+ Default "admin"
+ Description "The database master 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
+ Description "Password of RDS master password"
+ Type "String"
+ NoEcho "true"
+ MinLength 4
+ end
+ DBName do
+ Default ""
+ Description "The name of a DB01 database"
+ Type "String"
+ end
+ WebInstanceType do
+ Description "EC2 instance type for the web server"
+ Default "t1.micro"
+ Type "String"
+ end
+ WebFleetSize do
+ Description "Number of EC2 instances to launch for the web server"
+ Default 2
+ Type "Number"
+ MaxValue 100
+ MinValue 1
+ end
+ HostedZone do
+ Description "The DNS name of an existing Amazon Route 53 hosted zone"
+ Type "String"
+ end
+end
+Conditions do
+ UseDBSnapshot do
+ Fn__Not [
+ _{
+ Fn__Equals [
+ _{
+ Ref "DBSnapshotName"
+ },
+ ""
+ ]
+ }
+ ]
+ end
+end
+Mappings do
+ AWSAmazonLinuxAMI(
+ {"us-east-1"=>
+ {"name"=>"Virginia",
+ "201303"=>"ami-3275ee5b",
+ "201309"=>"ami-35792c5c",
+ "201403"=>"ami-2f726546"},
+ "us-west-2"=>
+ {"name"=>"Oregon",
+ "201303"=>"ami-ecbe2adc",
+ "201309"=>"ami-d03ea1e0",
+ "201403"=>"ami-b8f69f88"},
+ "us-west-1"=>
+ {"name"=>"California",
+ "201303"=>"ami-66d1fc23",
+ "201309"=>"ami-687b4f2d",
+ "201403"=>"ami-84f1cfc1"},
+ "eu-west-1"=>
+ {"name"=>"Ireland",
+ "201303"=>"ami-44939930",
+ "201309"=>"ami-149f7863",
+ "201403"=>"ami-a921dfde"},
+ "ap-southeast-1"=>
+ {"name"=>"Singapole",
+ "201303"=>"ami-aa9ed2f8",
+ "201309"=>"ami-14f2b946",
+ "201403"=>"ami-787c2c2a"},
+ "ap-southeast-2"=>
+ {"name"=>"Sydney",
+ "201303"=>"ami-363eaf0c",
+ "201309"=>"ami-a148d59b",
+ "201403"=>"ami-0bc85031"},
+ "ap-northeast-1"=>
+ {"name"=>"Tokyo",
+ "201303"=>"ami-173fbf16",
+ "201309"=>"ami-3561fe34",
+ "201403"=>"ami-a1bec3a0"},
+ "sa-east-1"=>
+ {"name"=>"SaoPaulo",
+ "201303"=>"ami-dd6bb0c0",
+ "201309"=>"ami-9f6ec982",
+ "201403"=>"ami-89de7c94"}})
+ ELBLogger(
+ {"us-east-1"=>{"AccountID"=>"127311923021"},
+ "us-west-2"=>{"AccountID"=>"797873946194"},
+ "us-west-1"=>{"AccountID"=>"027434742980"},
+ "eu-west-1"=>{"AccountID"=>"156460612806"},
+ "ap-southeast-1"=>{"AccountID"=>"114774131450"},
+ "ap-southeast-2"=>{"AccountID"=>"783225319266"},
+ "ap-northeast-1"=>{"AccountID"=>"582318560864"},
+ "sa-east-1"=>{"AccountID"=>"507241528517"},
+ "us-gov-west-1"=>{"AccountID"=>"048591011584"}})
+ StackConfig do
+ VPC do
+ CIDR "10.0.0.0/16"
+ end
+ FrontendSubnet1 do
+ CIDR "10.0.0.0/24"
+ end
+ FrontendSubnet2 do
+ CIDR "10.0.1.0/24"
+ end
+ ApplicationSubnet1 do
+ CIDR "10.0.100.0/24"
+ end
+ ApplicationSubnet2 do
+ CIDR "10.0.101.0/24"
+ end
+ DatastoreSubnet1 do
+ CIDR "10.0.200.0/24"
+ end
+ DatastoreSubnet2 do
+ CIDR "10.0.201.0/24"
+ end
+ BastionServer do
+ InstanceType "t1.micro"
+ end
+ end
+end
+Resources do
+ PowerUserRole do
+ Type "AWS::IAM::Role"
+ Properties do
+ AssumeRolePolicyDocument do
+ Statement [
+ _{
+ Effect "Allow"
+ Principal do
+ Service ["ec2.amazonaws.com"]
+ end
+ Action ["sts:AssumeRole"]
+ }
+ ]
+ end
+ Path "/"
+ Policies [
+ _{
+ PolicyName "PowerUserPolicy"
+ PolicyDocument do
+ Statement [
+ _{
+ Sid "PowerUserStmt"
+ Effect "Allow"
+ NotAction "iam:*"
+ Resource "*"
+ }
+ ]
+ end
+ }
+ ]
+ end
+ end
+ PowerUserProfile do
+ Type "AWS::IAM::InstanceProfile"
+ Properties do
+ Path "/"
+ Roles [
+ _{
+ Ref "PowerUserRole"
+ }
+ ]
+ end
+ end
+ LogBucket do
+ Type "AWS::S3::Bucket"
+ DeletionPolicy "Retain"
+ end
+ LogBucketPolicy do
+ Type "AWS::S3::BucketPolicy"
+ Properties do
+ Bucket do
+ Ref "LogBucket"
+ end
+ PolicyDocument do
+ Id "LogBucketPolicy"
+ Statement [
+ _{
+ Sid "WriteAccess"
+ Action ["s3:PutObject"]
+ Effect "Allow"
+ Resource do
+ Fn__Join [
+ "",
+ [
+ "arn:aws:s3:::",
+ _{
+ Ref "LogBucket"
+ },
+ "/AWSLogs/",
+ _{
+ Ref "AWS::AccountId"
+ },
+ "/*"
+ ]
+ ]
+ end
+ Principal do
+ AWS do
+ Fn__FindInMap [
+ "ELBLogger",
+ _{
+ Ref "AWS::Region"
+ },
+ "AccountID"
+ ]
+ end
+ end
+ }
+ ]
+ end
+ end
+ end
+ VPC do
+ Type "AWS::EC2::VPC"
+ Properties do
+ CidrBlock do
+ Fn__FindInMap "StackConfig", "VPC", "CIDR"
+ end
+ EnableDnsSupport "true"
+ EnableDnsHostnames "true"
+ InstanceTenancy "default"
+ Tags [
+ _{
+ Key "Application"
+ Value do
+ Ref "AWS::StackId"
+ end
+ },
+ _{
+ Key "Network"
+ Value "Public"
+ }
+ ]
+ end
+ end
+ InternetGateway do
+ Type "AWS::EC2::InternetGateway"
+ Properties do
+ Tags [
+ _{
+ Key "Application"
+ Value do
+ Ref "AWS::StackId"
+ end
+ },
+ _{
+ Key "Network"
+ Value "Public"
+ }
+ ]
+ end
+ end
+ AttachGateway do
+ Type "AWS::EC2::VPCGatewayAttachment"
+ Properties do
+ VpcId do
+ Ref "VPC"
+ end
+ InternetGatewayId do
+ Ref "InternetGateway"
+ end
+ end
+ end
+ PublicRouteTable do
+ Type "AWS::EC2::RouteTable"
+ DependsOn "AttachGateway"
+ Properties do
+ VpcId do
+ Ref "VPC"
+ end
+ Tags [
+ _{
+ Key "Application"
+ Value do
+ Ref "AWS::StackId"
+ end
+ },
+ _{
+ Key "Network"
+ Value "Public"
+ }
+ ]
+ end
+ end
+ PrivateRouteTable do
+ Type "AWS::EC2::RouteTable"
+ DependsOn "AttachGateway"
+ Properties do
+ VpcId do
+ Ref "VPC"
+ end
+ Tags [
+ _{
+ Key "Application"
+ Value do
+ Ref "AWS::StackId"
+ end
+ },
+ _{
+ Key "Network"
+ Value "Private"
+ }
+ ]
+ end
+ end
+ PublicRoute do
+ Type "AWS::EC2::Route"
+ DependsOn "AttachGateway"
+ Properties do
+ RouteTableId do
+ Ref "PublicRouteTable"
+ end
+ DestinationCidrBlock "0.0.0.0/0"
+ GatewayId do
+ Ref "InternetGateway"
+ end
+ end
+ end
+ FrontendSubnet1 do
+ Type "AWS::EC2::Subnet"
+ DependsOn "AttachGateway"
+ Properties do
+ VpcId do
+ Ref "VPC"
+ end
+ AvailabilityZone do
+ Fn__Select [
+ "0",
+ _{
+ Fn__GetAZs do
+ Ref "AWS::Region"
+ end
+ }
+ ]
+ end
+ CidrBlock do
+ Fn__FindInMap "StackConfig", "FrontendSubnet1", "CIDR"
+ end
+ Tags [
+ _{
+ Key "Application"
+ Value do
+ Ref "AWS::StackId"
+ end
+ },
+ _{
+ Key "Network"
+ Value "Public"
+ }
+ ]
+ end
+ end
+ FrontendSubnet2 do
+ Type "AWS::EC2::Subnet"
+ DependsOn "AttachGateway"
+ Properties do
+ VpcId do
+ Ref "VPC"
+ end
+ AvailabilityZone do
+ Fn__Select [
+ "1",
+ _{
+ Fn__GetAZs do
+ Ref "AWS::Region"
+ end
+ }
+ ]
+ end
+ CidrBlock do
+ Fn__FindInMap "StackConfig", "FrontendSubnet2", "CIDR"
+ end
+ Tags [
+ _{
+ Key "Application"
+ Value do
+ Ref "AWS::StackId"
+ end
+ },
+ _{
+ Key "Network"
+ Value "Public"
+ }
+ ]
+ end
+ end
+ ApplicationSubnet1 do
+ Type "AWS::EC2::Subnet"
+ DependsOn "AttachGateway"
+ Properties do
+ VpcId do
+ Ref "VPC"
+ end
+ CidrBlock do
+ Fn__FindInMap "StackConfig", "ApplicationSubnet1", "CIDR"
+ end
+ AvailabilityZone do
+ Fn__Select [
+ "0",
+ _{
+ Fn__GetAZs do
+ Ref "AWS::Region"
+ end
+ }
+ ]
+ end
+ Tags [
+ _{
+ Key "Application"
+ Value do
+ Ref "AWS::StackId"
+ end
+ },
+ _{
+ Key "Network"
+ Value "Public"
+ }
+ ]
+ end
+ end
+ ApplicationSubnet2 do
+ Type "AWS::EC2::Subnet"
+ DependsOn "AttachGateway"
+ Properties do
+ VpcId do
+ Ref "VPC"
+ end
+ CidrBlock do
+ Fn__FindInMap "StackConfig", "ApplicationSubnet2", "CIDR"
+ end
+ AvailabilityZone do
+ Fn__Select [
+ "1",
+ _{
+ Fn__GetAZs do
+ Ref "AWS::Region"
+ end
+ }
+ ]
+ end
+ Tags [
+ _{
+ Key "Application"
+ Value do
+ Ref "AWS::StackId"
+ end
+ },
+ _{
+ Key "Network"
+ Value "Public"
+ }
+ ]
+ end
+ end
+ DatastoreSubnet1 do
+ Type "AWS::EC2::Subnet"
+ DependsOn "AttachGateway"
+ Properties do
+ VpcId do
+ Ref "VPC"
+ end
+ CidrBlock do
+ Fn__FindInMap "StackConfig", "DatastoreSubnet1", "CIDR"
+ end
+ AvailabilityZone do
+ Fn__Select [
+ "0",
+ _{
+ Fn__GetAZs do
+ Ref "AWS::Region"
+ end
+ }
+ ]
+ end
+ Tags [
+ _{
+ Key "Application"
+ Value do
+ Ref "AWS::StackId"
+ end
+ },
+ _{
+ Key "Network"
+ Value "Private"
+ }
+ ]
+ end
+ end
+ DatastoreSubnet2 do
+ Type "AWS::EC2::Subnet"
+ DependsOn "AttachGateway"
+ Properties do
+ VpcId do
+ Ref "VPC"
+ end
+ CidrBlock do
+ Fn__FindInMap "StackConfig", "DatastoreSubnet2", "CIDR"
+ end
+ AvailabilityZone do
+ Fn__Select [
+ "1",
+ _{
+ Fn__GetAZs do
+ Ref "AWS::Region"
+ end
+ }
+ ]
+ end
+ Tags [
+ _{
+ Key "Application"
+ Value do
+ Ref "AWS::StackId"
+ end
+ },
+ _{
+ Key "Network"
+ Value "Private"
+ }
+ ]
+ end
+ end
+ FrontendSubnet1RouteTableAssociation do
+ Type "AWS::EC2::SubnetRouteTableAssociation"
+ Properties do
+ SubnetId do
+ Ref "FrontendSubnet1"
+ end
+ RouteTableId do
+ Ref "PublicRouteTable"
+ end
+ end
+ end
+ FrontendSubnet2RouteTableAssociation do
+ Type "AWS::EC2::SubnetRouteTableAssociation"
+ Properties do
+ SubnetId do
+ Ref "FrontendSubnet2"
+ end
+ RouteTableId do
+ Ref "PublicRouteTable"
+ end
+ end
+ end
+ ApplicationSubnet1RouteTableAssociation do
+ Type "AWS::EC2::SubnetRouteTableAssociation"
+ Properties do
+ SubnetId do
+ Ref "ApplicationSubnet1"
+ end
+ RouteTableId do
+ Ref "PublicRouteTable"
+ end
+ end
+ end
+ ApplicationSubnet2RouteTableAssociation do
+ Type "AWS::EC2::SubnetRouteTableAssociation"
+ Properties do
+ SubnetId do
+ Ref "ApplicationSubnet2"
+ end
+ RouteTableId do
+ Ref "PublicRouteTable"
+ end
+ end
+ end
+ DatastoreSubnet1RouteTableAssociation do
+ Type "AWS::EC2::SubnetRouteTableAssociation"
+ Properties do
+ SubnetId do
+ Ref "DatastoreSubnet1"
+ end
+ RouteTableId do
+ Ref "PrivateRouteTable"
+ end
+ end
+ end
+ DatastoreSubnet2RouteTableAssociation do
+ Type "AWS::EC2::SubnetRouteTableAssociation"
+ Properties do
+ SubnetId do
+ Ref "DatastoreSubnet2"
+ end
+ RouteTableId do
+ Ref "PrivateRouteTable"
+ end
+ end
+ end
+ VPCDefaultSecurityGroup do
+ Type "AWS::EC2::SecurityGroup"
+ Properties do
+ VpcId do
+ Ref "VPC"
+ end
+ GroupDescription "Allow all communications in VPC"
+ SecurityGroupIngress [
+ _{
+ IpProtocol "tcp"
+ FromPort 0
+ ToPort 65535
+ CidrIp do
+ Fn__FindInMap "StackConfig", "VPC", "CIDR"
+ end
+ },
+ _{
+ IpProtocol "udp"
+ FromPort 0
+ ToPort 65535
+ CidrIp do
+ Fn__FindInMap "StackConfig", "VPC", "CIDR"
+ end
+ },
+ _{
+ IpProtocol "icmp"
+ FromPort "-1"
+ ToPort "-1"
+ CidrIp do
+ Fn__FindInMap "StackConfig", "VPC", "CIDR"
+ end
+ }
+ ]
+ end
+ end
+ SSHSecurityGroup do
+ Type "AWS::EC2::SecurityGroup"
+ Properties do
+ VpcId do
+ Ref "VPC"
+ end
+ GroupDescription "Enable SSH access via port 22"
+ SecurityGroupIngress [
+ _{
+ IpProtocol "tcp"
+ FromPort 22
+ ToPort 22
+ CidrIp do
+ Ref "SSHFrom"
+ end
+ }
+ ]
+ end
+ end
+ PublicWebSecurityGroup do
+ Type "AWS::EC2::SecurityGroup"
+ Properties do
+ VpcId do
+ Ref "VPC"
+ end
+ GroupDescription "Public Security Group with HTTP access on port 443 from the internet"
+ SecurityGroupIngress [
+ _{
+ IpProtocol "tcp"
+ FromPort 80
+ ToPort 80
+ CidrIp "0.0.0.0/0"
+ },
+ _{
+ IpProtocol "tcp"
+ FromPort 443
+ ToPort 443
+ CidrIp "0.0.0.0/0"
+ }
+ ]
+ end
+ end
+ ApplicationSecurityGroup do
+ Type "AWS::EC2::SecurityGroup"
+ Properties do
+ VpcId do
+ Ref "VPC"
+ end
+ GroupDescription "Marker security group for Application server."
+ end
+ end
+ MySQLSecurityGroup do
+ Type "AWS::EC2::SecurityGroup"
+ Properties do
+ VpcId do
+ Ref "VPC"
+ end
+ GroupDescription "Marker security group for MySQL server."
+ end
+ end
+ BastionWaitHandle do
+ Type "AWS::CloudFormation::WaitConditionHandle"
+ end
+ BastionWaitCondition do
+ Type "AWS::CloudFormation::WaitCondition"
+ DependsOn "BastionInstance"
+ Properties do
+ Handle do
+ Ref "BastionWaitHandle"
+ end
+ Timeout 900
+ end
+ end
+ BastionInstance do
+ Type "AWS::EC2::Instance"
+ Properties do
+ InstanceType do
+ Fn__FindInMap "StackConfig", "BastionServer", "InstanceType"
+ end
+ KeyName do
+ Ref "KeyName"
+ end
+ SubnetId do
+ Ref "FrontendSubnet1"
+ end
+ ImageId do
+ Fn__FindInMap [
+ "AWSAmazonLinuxAMI",
+ _{
+ Ref "AWS::Region"
+ },
+ "201403"
+ ]
+ end
+ IamInstanceProfile do
+ Ref "PowerUserProfile"
+ end
+ SecurityGroupIds [
+ _{
+ Ref "SSHSecurityGroup"
+ },
+ _{
+ Ref "VPCDefaultSecurityGroup"
+ }
+ ]
+ Tags [
+ _{
+ Key "Name"
+ Value "Bastion"
+ }
+ ]
+ UserData do
+ Fn__Base64 do
+ Fn__Join [
+ "",
+ [
+ "#! /bin/bash -v\n",
+ "yum update -y\n",
+ "# Helper function\n",
+ "function error_exit\n",
+ "{\n",
+ " /opt/aws/bin/cfn-signal -e 1 -r \"$1\" '",
+ _{
+ Ref "BastionWaitHandle"
+ },
+ "'\n",
+ " exit 1\n",
+ "}\n",
+ "# Install packages\n",
+ "/opt/aws/bin/cfn-init -s ",
+ _{
+ Ref "AWS::StackId"
+ },
+ " -r BastionInstance ",
+ " --region ",
+ _{
+ Ref "AWS::Region"
+ },
+ " || error_exit 'Failed to run cfn-init'\n",
+ "# All is well so signal success\n",
+ "/opt/aws/bin/cfn-signal -e $? -r \"BastionInstance setup complete\" '",
+ _{
+ Ref "BastionWaitHandle"
+ },
+ "'\n"
+ ]
+ ]
+ end
+ end
+ end
+ Metadata do
+ AWS__CloudFormation__Init do
+ config do
+ packages do
+ yum(
+ {"mysql55"=>[], "jq"=>[], "python-magic"=>[]})
+ end
+ end
+ end
+ end
+ end
+ BastionInstanceEIP do
+ Type "AWS::EC2::EIP"
+ DependsOn "AttachGateway"
+ Properties do
+ Domain "vpc"
+ InstanceId do
+ Ref "BastionInstance"
+ end
+ end
+ end
+ BastionDNSRecord do
+ Type "AWS::Route53::RecordSet"
+ Properties do
+ HostedZoneName do
+ Fn__Join [
+ "",
+ [
+ _{
+ Ref "HostedZone"
+ },
+ "."
+ ]
+ ]
+ end
+ Comment "A record for the Bastion instance."
+ Name do
+ Fn__Join [
+ "",
+ [
+ "bastion.",
+ _{
+ Ref "HostedZone"
+ },
+ "."
+ ]
+ ]
+ end
+ Type "A"
+ TTL 300
+ ResourceRecords [
+ _{
+ Ref "BastionInstanceEIP"
+ }
+ ]
+ end
+ end
+ BastionLocalDNSRecord do
+ Type "AWS::Route53::RecordSet"
+ Properties do
+ HostedZoneName do
+ Fn__Join [
+ "",
+ [
+ _{
+ Ref "HostedZone"
+ },
+ "."
+ ]
+ ]
+ end
+ Comment "A record for the private IP address of Bastion instance."
+ Name do
+ Fn__Join [
+ "",
+ [
+ "bastion.local.",
+ _{
+ Ref "HostedZone"
+ },
+ "."
+ ]
+ ]
+ end
+ Type "A"
+ TTL 300
+ ResourceRecords [
+ _{
+ Fn__GetAtt "BastionInstance", "PrivateIp"
+ }
+ ]
+ end
+ end
+ DBParamGroup do
+ Type "AWS::RDS::DBParameterGroup"
+ Properties do
+ Description "Default parameter group for Portnoy"
+ Family "MySQL5.6"
+ Parameters(
+ {"character_set_database"=>"utf8mb4",
+ "character_set_client"=>"utf8mb4",
+ "character_set_connection"=>"utf8mb4",
+ "character_set_results"=>"utf8mb4",
+ "character_set_server"=>"utf8mb4",
+ "skip-character-set-client-handshake"=>"TRUE"})
+ end
+ end
+ DBSubnetGroup do
+ Type "AWS::RDS::DBSubnetGroup"
+ Properties do
+ DBSubnetGroupDescription "Database subnets for RDS"
+ SubnetIds [
+ _{
+ Ref "DatastoreSubnet1"
+ },
+ _{
+ Ref "DatastoreSubnet2"
+ }
+ ]
+ end
+ end
+ DBInstance do
+ Type "AWS::RDS::DBInstance"
+ DeletionPolicy "Snapshot"
+ Properties do
+ DBInstanceClass do
+ Ref "DBInstanceType"
+ end
+ AllocatedStorage do
+ Ref "DBAllocatedStorage"
+ end
+ Engine "MySQL"
+ MultiAZ "true"
+ EngineVersion "5.6.13"
+ MasterUsername do
+ Ref "DBUsername"
+ end
+ MasterUserPassword do
+ Ref "DBPassword"
+ end
+ BackupRetentionPeriod 35
+ DBParameterGroupName do
+ Ref "DBParamGroup"
+ end
+ DBSubnetGroupName do
+ Ref "DBSubnetGroup"
+ end
+ DBSnapshotIdentifier do
+ Fn__If [
+ "UseDBSnapshot",
+ _{
+ Ref "DBSnapshotName"
+ },
+ _{
+ Ref "AWS::NoValue"
+ }
+ ]
+ end
+ PreferredBackupWindow "19:00-19:30"
+ PreferredMaintenanceWindow "sat:20:00-sat:20:30"
+ VPCSecurityGroups [
+ _{
+ Ref "VPCDefaultSecurityGroup"
+ },
+ _{
+ Ref "MySQLSecurityGroup"
+ }
+ ]
+ end
+ end
+ DatabaseDNSRecord do
+ Type "AWS::Route53::RecordSet"
+ Properties do
+ HostedZoneName do
+ Fn__Join [
+ "",
+ [
+ _{
+ Ref "HostedZone"
+ },
+ "."
+ ]
+ ]
+ end
+ Comment "CNAME for the database."
+ Name do
+ Fn__Join [
+ "",
+ [
+ "db.local.",
+ _{
+ Ref "HostedZone"
+ },
+ "."
+ ]
+ ]
+ end
+ Type "CNAME"
+ TTL 300
+ ResourceRecords [
+ _{
+ Fn__GetAtt "DBInstance", "Endpoint.Address"
+ }
+ ]
+ end
+ end
+ ApplicationFleet do
+ Type "AWS::AutoScaling::AutoScalingGroup"
+ UpdatePolicy do
+ AutoScalingRollingUpdate do
+ MaxBatchSize 1
+ MinInstancesInService 1
+ PauseTime "PT2M30S"
+ end
+ end
+ Properties do
+ AvailabilityZones [
+ _{
+ Fn__GetAtt "ApplicationSubnet1", "AvailabilityZone"
+ },
+ _{
+ Fn__GetAtt "ApplicationSubnet2", "AvailabilityZone"
+ }
+ ]
+ VPCZoneIdentifier [
+ _{
+ Ref "ApplicationSubnet1"
+ },
+ _{
+ Ref "ApplicationSubnet2"
+ }
+ ]
+ LaunchConfigurationName do
+ Ref "ApplicationServerLaunchConfig"
+ end
+ MinSize do
+ Ref "WebFleetSize"
+ end
+ MaxSize do
+ Ref "WebFleetSize"
+ end
+ DesiredCapacity do
+ Ref "WebFleetSize"
+ end
+ LoadBalancerNames [
+ _{
+ Ref "ElasticLoadBalancer"
+ }
+ ]
+ Tags [
+ _{
+ Key "Name"
+ Value "Application"
+ PropagateAtLaunch "true"
+ }
+ ]
+ end
+ end
+ ApplicationServerLaunchConfig do
+ Type "AWS::AutoScaling::LaunchConfiguration"
+ Properties do
+ InstanceType do
+ Ref "WebInstanceType"
+ end
+ KeyName do
+ Ref "KeyName"
+ end
+ ImageId do
+ Fn__FindInMap [
+ "AWSAmazonLinuxAMI",
+ _{
+ Ref "AWS::Region"
+ },
+ "201403"
+ ]
+ end
+ SecurityGroups [
+ _{
+ Ref "VPCDefaultSecurityGroup"
+ },
+ _{
+ Ref "ApplicationSecurityGroup"
+ }
+ ]
+ AssociatePublicIpAddress "true"
+ IamInstanceProfile do
+ Ref "PowerUserProfile"
+ end
+ InstanceMonitoring "false"
+ UserData do
+ Fn__Base64 do
+ Fn__Join [
+ "",
+ [
+ "#! /bin/bash -v\n",
+ "yum update -y\n",
+ "# Install packages\n",
+ "/opt/aws/bin/cfn-init -s ",
+ _{
+ Ref "AWS::StackId"
+ },
+ " -r ApplicationServerLaunchConfig ",
+ " --region ",
+ _{
+ Ref "AWS::Region"
+ },
+ " || error_exit 'Failed to run cfn-init'\n"
+ ]
+ ]
+ end
+ end
+ end
+ Metadata do
+ AWS__CloudFormation__Init do
+ config do
+ packages do
+ yum(
+ {"httpd"=>[], "mysql55"=>[]})
+ end
+ files do
+ _path("/var/www/html/index.html") do
+ content "<html><head><title>Hello</title></head><body>Hello, world!</body></html>"
+ mode "000644"
+ owner "apache"
+ group "apache"
+ end
+ end
+ services do
+ sysvinit do
+ httpd do
+ enabled "true"
+ ensureRunning "true"
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ ElasticLoadBalancer do
+ Type "AWS::ElasticLoadBalancing::LoadBalancer"
+ DependsOn "AttachGateway"
+ Properties do
+ Subnets [
+ _{
+ Ref "FrontendSubnet1"
+ },
+ _{
+ Ref "FrontendSubnet2"
+ }
+ ]
+ Listeners [
+ _{
+ LoadBalancerPort 80
+ InstancePort 80
+ Protocol "HTTP"
+ }
+ ]
+ HealthCheck do
+ Target "HTTP:80/index.html"
+ HealthyThreshold 2
+ UnhealthyThreshold 2
+ Interval 6
+ Timeout 5
+ end
+ SecurityGroups [
+ _{
+ Ref "PublicWebSecurityGroup"
+ }
+ ]
+ end
+ end
+ LoadBalancerDNSRecord do
+ Type "AWS::Route53::RecordSetGroup"
+ Properties do
+ HostedZoneName do
+ Fn__Join [
+ "",
+ [
+ _{
+ Ref "HostedZone"
+ },
+ "."
+ ]
+ ]
+ end
+ Comment "Zone apex alias targeted to LoadBalancer."
+ RecordSets [
+ _{
+ Name do
+ Fn__Join [
+ "",
+ [
+ _{
+ Ref "HostedZone"
+ },
+ "."
+ ]
+ ]
+ end
+ Type "A"
+ AliasTarget do
+ HostedZoneId do
+ Fn__GetAtt "ElasticLoadBalancer", "CanonicalHostedZoneNameID"
+ end
+ DNSName do
+ Fn__GetAtt "ElasticLoadBalancer", "CanonicalHostedZoneName"
+ end
+ end
+ }
+ ]
+ end
+ end
+end
+Outputs do
+ JdbcConnectionString do
+ Value do
+ Fn__Join [
+ "",
+ [
+ "jdbc:mysql://",
+ _{
+ Ref "DatabaseDNSRecord"
+ },
+ ":",
+ _{
+ Fn__GetAtt "DBInstance", "Endpoint.Port"
+ },
+ "/",
+ _{
+ Ref "DBName"
+ }
+ ]
+ ]
+ end
+ Description "-"
+ end
+ SSHToBackendServer do
+ Value do
+ Fn__Join [
+ "",
+ [
+ "ssh -i /path/to/",
+ _{
+ Ref "KeyName"
+ },
+ ".pem",
+ " -oProxyCommand='ssh -i /path/to/",
+ _{
+ Ref "KeyName"
+ },
+ ".pem -W %h:%p ec2-user@",
+ _{
+ Ref "BastionDNSRecord"
+ },
+ "'",
+ " ec2-user@<private-ip>"
+ ]
+ ]
+ end
+ Description "SSH command to connect to the backend servers"
+ end
+end
+ EOS
end
end