CloudFormation support.

This commit is contained in:
James Martin
2013-02-22 15:52:23 -05:00
parent 9d594d7494
commit fa63a9b5f4
3 changed files with 687 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
---
# This playbook demonstrates how to use the ansible cloudformation module to launch an AWS CloudFormation stack.
#
# This module requires that the boto python library is installed, and that you have your AWS credentials
# in $HOME/.boto
#The thought here is to bring up a bare infrastructure with CloudFormation, but use ansible to configure it.
#I generally do this in 2 different playbook runs as to allow the ec2.py inventory to be updated.
#This module also uses "complex arguments" which were introduced in ansible 1.1 allowing you to specify the
#Cloudformation template parameters
#This example launches a 3 node AutoScale group, with a security group, and an InstanceProfile with root permissions.
#If a stack does not exist, it will be created. If it does exist and the template file has changed, the stack will be updated.
#If the parameters are different, the stack will also be updated.
#CloudFormation stacks can take awhile to provision, if you are curious about its status, use the AWS
#web console or one of the CloudFormation CLI's.
#Example update -- try first launching the stack with 3 as the ClusterSize. After it is launched, change it to 4
#and run the playbook again.
- name: provision stack
hosts: localhost
connection: local
gather_facts: false
# Launch the cloudformation-example.json template. Register the output.
tasks:
- name: launch ansible cloudformation example
cloudformation: >
stack_name="ansible-cloudformation" state=present
region=us-east-1 disable_rollback=true
template=files/cloudformation-example.json
args:
template_parameters:
KeyName: jmartin
DiskType: ephemeral
InstanceType: m1.small
ClusterSize: 3
register: stack
- name: show stack outputs
debug: msg="My stack outputs are ${stack.stack_outputs}"

View File

@@ -0,0 +1,399 @@
{
"Outputs" : {
"ClusterSecGroup" : {
"Description" : "Name of RegionalManagerSecGroup",
"Value" : {
"Ref" : "InstanceSecurityGroup"
}
}
},
"AWSTemplateFormatVersion" : "2010-09-09",
"Description" : "Launches an example cluster",
"Mappings" : {
"ebs" : {
"ap-northeast-1" : {
"AMI" : "ami-4e6cd34f"
},
"ap-southeast-1" : {
"AMI" : "ami-a6a7e7f4"
},
"eu-west-1" : {
"AMI" : "ami-c37474b7"
},
"sa-east-1" : {
"AMI" : "ami-1e08d103"
},
"us-east-1" : {
"AMI" : "ami-1624987f"
},
"us-west-1" : {
"AMI" : "ami-1bf9de5e"
},
"us-west-2" : {
"AMI" : "ami-2a31bf1a"
}
},
"ephemeral" : {
"ap-northeast-1" : {
"AMI" : "ami-5a6cd35b"
},
"ap-southeast-1" : {
"AMI" : "ami-a8a7e7fa"
},
"eu-west-1" : {
"AMI" : "ami-b57474c1"
},
"sa-east-1" : {
"AMI" : "ami-1608d10b"
},
"us-east-1" : {
"AMI" : "ami-e8249881"
},
"us-west-1" : {
"AMI" : "ami-21f9de64"
},
"us-west-2" : {
"AMI" : "ami-2e31bf1e"
}
}
},
"Parameters" : {
"ClusterSize" : {
"Description" : "Number of nodes in the cluster",
"Type" : "String"
},
"DiskType" : {
"AllowedValues" : [
"ephemeral",
"ebs"
],
"Default" : "ephemeral",
"Description" : "Type of Disk to use ( ephemeral/ebs )",
"Type" : "String"
},
"InstanceType" : {
"AllowedValues" : [
"t1.micro",
"m1.small",
"m1.medium",
"m1.large",
"m1.xlarge",
"m2.xlarge",
"m2.2xlarge",
"m2.4xlarge",
"c1.medium",
"c1.xlarge",
"cc1.4xlarge"
],
"ConstraintDescription" : "must be valid instance type. ",
"Default" : "m1.large",
"Description" : "Type of EC2 instance for cluster",
"Type" : "String"
},
"KeyName" : {
"Description" : "Name of an existing EC2 KeyPair to enable SSH access to the cluster",
"Type" : "String"
}
},
"Resources" : {
"ApplicationWaitCondition" : {
"DependsOn" : "ClusterServerGroup",
"Properties" : {
"Handle" : {
"Ref" : "ApplicationWaitHandle"
},
"Timeout" : "4500"
},
"Type" : "AWS::CloudFormation::WaitCondition"
},
"ApplicationWaitHandle" : {
"Type" : "AWS::CloudFormation::WaitConditionHandle"
},
"CFNInitUser" : {
"Properties" : {
"Path" : "/",
"Policies" : [
{
"PolicyDocument" : {
"Statement" : [
{
"Action" : [
"cloudformation:DescribeStackResource",
"s3:GetObject"
],
"Effect" : "Allow",
"Resource" : "*"
}
]
},
"PolicyName" : "AccessForCFNInit"
}
]
},
"Type" : "AWS::IAM::User"
},
"CFNKeys" : {
"Properties" : {
"UserName" : {
"Ref" : "CFNInitUser"
}
},
"Type" : "AWS::IAM::AccessKey"
},
"ClusterCommunication1" : {
"Properties" : {
"FromPort" : "-1",
"GroupName" : {
"Ref" : "InstanceSecurityGroup"
},
"IpProtocol" : "icmp",
"SourceSecurityGroupName" : {
"Ref" : "InstanceSecurityGroup"
},
"ToPort" : "-1"
},
"Type" : "AWS::EC2::SecurityGroupIngress"
},
"ClusterCommunication2" : {
"Properties" : {
"FromPort" : "1",
"GroupName" : {
"Ref" : "InstanceSecurityGroup"
},
"IpProtocol" : "tcp",
"SourceSecurityGroupName" : {
"Ref" : "InstanceSecurityGroup"
},
"ToPort" : "65356"
},
"Type" : "AWS::EC2::SecurityGroupIngress"
},
"ClusterCommunication3" : {
"Properties" : {
"FromPort" : "1",
"GroupName" : {
"Ref" : "InstanceSecurityGroup"
},
"IpProtocol" : "udp",
"SourceSecurityGroupName" : {
"Ref" : "InstanceSecurityGroup"
},
"ToPort" : "65356"
},
"Type" : "AWS::EC2::SecurityGroupIngress"
},
"InstanceSecurityGroup" : {
"Properties" : {
"GroupDescription" : "Enable SSH access via port 22",
"SecurityGroupIngress" : [
{
"CidrIp" : "0.0.0.0/0",
"FromPort" : "22",
"IpProtocol" : "tcp",
"ToPort" : "22"
}
]
},
"Type" : "AWS::EC2::SecurityGroup"
},
"LaunchConfig" : {
"Properties" : {
"IamInstanceProfile" : {
"Ref" : "RootInstanceProfile"
},
"ImageId" : {
"Fn::FindInMap" : [
{
"Ref" : "DiskType"
},
{
"Ref" : "AWS::Region"
},
"AMI"
]
},
"InstanceType" : {
"Ref" : "InstanceType"
},
"KeyName" : {
"Ref" : "KeyName"
},
"SecurityGroups" : [
{
"Ref" : "InstanceSecurityGroup"
}
],
"UserData" : {
"Fn::Base64" : {
"Fn::Join" : [
"\n",
[
"#!/bin/bash -v",
"exec > >(tee /var/log/cfn-data.log|logger -t user-data -s 2>/dev/console) 2>&1",
"",
"sleep 10",
"",
"function retry {",
" nTrys=0",
" maxTrys=5",
" status=256",
" until [ $status == 0 ] ; do",
" $1",
" status=$?",
" nTrys=$(($nTrys + 1))",
" if [ $nTrys -gt $maxTrys ] ; then",
" echo \"Number of re-trys exceeded. Exit code: $status\"",
" exit $status",
" fi",
" if [ $status != 0 ] ; then",
" echo \"Failed (exit code $status)... retry $nTrys\"",
" sleep 10",
" fi",
" done",
"}",
"",
"yum update -y aws-cfn-bootstrap",
"",
"#for all the stuff that complains about sudo and tty",
"sed -i 's,Defaults requiretty,#Defaults requiretty,g' /etc/sudoers",
"",
"function error_exit",
"{",
{
"Fn::Join" : [
"",
[
" /opt/aws/bin/cfn-signal -e 1 -r \"$1\" '",
{
"Ref" : "ApplicationWaitHandle"
},
"'"
]
]
},
"}",
"yum update -y aws-cfn-bootstrap",
"#this runs the first stage of cfinit",
{
"Fn::Join" : [
"",
[
"#/opt/aws/bin/cfn-init -c ascending -v --region ",
{
"Ref" : "AWS::Region"
},
" -s ",
{
"Ref" : "AWS::StackName"
},
" -r ",
"LaunchConfig",
" --access-key ",
{
"Ref" : "CFNKeys"
},
" --secret-key ",
{
"Fn::GetAtt" : [
"CFNKeys",
"SecretAccessKey"
]
},
" || error_exit 'Failed to initialize client using cfn-init'"
]
]
},
"",
"",
"",
"result_code=$?",
{
"Fn::Join" : [
"",
[
"/opt/aws/bin/cfn-signal -e $result_code '",
{
"Ref" : "ApplicationWaitHandle"
},
"'"
]
]
}
]
]
}
}
},
"Type" : "AWS::AutoScaling::LaunchConfiguration"
},
"ClusterServerGroup" : {
"Properties" : {
"AvailabilityZones" : {
"Fn::GetAZs" : ""
},
"LaunchConfigurationName" : {
"Ref" : "LaunchConfig"
},
"MaxSize" : {
"Ref" : "ClusterSize"
},
"MinSize" : {
"Ref" : "ClusterSize"
}
},
"Type" : "AWS::AutoScaling::AutoScalingGroup"
},
"RolePolicies" : {
"Properties" : {
"PolicyDocument" : {
"Statement" : [
{
"Action" : "*",
"Effect" : "Allow",
"Resource" : "*"
}
]
},
"PolicyName" : "root",
"Roles" : [
{
"Ref" : "RootRole"
}
]
},
"Type" : "AWS::IAM::Policy"
},
"RootInstanceProfile" : {
"Properties" : {
"Path" : "/",
"Roles" : [
{
"Ref" : "RootRole"
}
]
},
"Type" : "AWS::IAM::InstanceProfile"
},
"RootRole" : {
"Properties" : {
"AssumeRolePolicyDocument" : {
"Statement" : [
{
"Action" : [
"sts:AssumeRole"
],
"Effect" : "Allow",
"Principal" : {
"Service" : [
"ec2.amazonaws.com"
]
}
}
]
},
"Path" : "/"
},
"Type" : "AWS::IAM::Role"
}
}
}