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