-
-
Save gene1wood/a00d0b9d029f40e866df to your computer and use it in GitHub Desktop.
AWSTemplateFormatVersion: 2010-09-09 | |
Description: > | |
An example free tier (12 month) CentOS 7 EC2 instance with a security group | |
allowing SSH, a simple IAM Role, and output conveyed from the launch back out | |
to the CloudFormation stack outputs | |
Parameters: | |
SSHKeyName: | |
Description: SSH Key Name | |
Type: String | |
Mappings: | |
# This list of AMI IDs was produced with this code | |
# https://gist.github.com/gene1wood/56e42097e0f0ac1aace14cbc41ee3e11#file-create_centos7_cloudformation_ami_mapping-py | |
RegionMap: | |
ap-northeast-1: | |
CentOS7x8664EBSHVM: ami-045f38c93733dd48d | |
ap-northeast-2: | |
CentOS7x8664EBSHVM: ami-06cf2a72dadf92410 | |
ap-south-1: | |
CentOS7x8664EBSHVM: ami-02e60be79e78fef21 | |
ap-southeast-1: | |
CentOS7x8664EBSHVM: ami-0b4dd9d65556cac22 | |
ap-southeast-2: | |
CentOS7x8664EBSHVM: ami-08bd00d7713a39e7d | |
ca-central-1: | |
CentOS7x8664EBSHVM: ami-033e6106180a626d0 | |
eu-central-1: | |
CentOS7x8664EBSHVM: ami-04cf43aca3e6f3de3 | |
eu-north-1: | |
CentOS7x8664EBSHVM: ami-5ee66f20 | |
eu-west-1: | |
CentOS7x8664EBSHVM: ami-0ff760d16d9497662 | |
eu-west-2: | |
CentOS7x8664EBSHVM: ami-0eab3a90fc693af19 | |
eu-west-3: | |
CentOS7x8664EBSHVM: ami-0e1ab783dc9489f34 | |
sa-east-1: | |
CentOS7x8664EBSHVM: ami-0b8d86d4bf91850af | |
us-east-1: | |
CentOS7x8664EBSHVM: ami-02eac2c0129f6376b | |
us-east-2: | |
CentOS7x8664EBSHVM: ami-0f2b4fc905b0bd1f1 | |
us-west-1: | |
CentOS7x8664EBSHVM: ami-074e2d6769f445be5 | |
us-west-2: | |
CentOS7x8664EBSHVM: ami-01ed306a12b7d1c96 | |
Resources: | |
SecurityGroup: | |
Type: AWS::EC2::SecurityGroup | |
Properties: | |
GroupDescription: Security Group | |
SecurityGroupIngress: | |
- FromPort: 22 | |
ToPort: 22 | |
IpProtocol: tcp | |
CidrIp: '0.0.0.0/0' | |
Instance: | |
Type: AWS::EC2::Instance | |
Metadata: | |
UserDataComment1: The cloud-config script is delivered directly in user_data | |
because the CentOS 7 base AMIs run cloud-init automatically, looking for a | |
cloud-init config in user_data | |
UserDataComment2: In this example the 'dmidecode' command is run and the output | |
is sent back to the WaitConditionHandle which is then passed out through the | |
CloudFormation outputs | |
Properties: | |
ImageId: !FindInMap [ RegionMap, !Ref 'AWS::Region', CentOS7x8664EBSHVM ] | |
InstanceType: t2.micro # Instance size of the free tier for 12 months | |
BlockDeviceMappings: | |
- DeviceName: /dev/sda1 | |
Ebs: | |
VolumeType: gp2 | |
DeleteOnTermination: false | |
VolumeSize: 30 # Free tier provides 30GiB of gp2 or standard EBS | |
KeyName: !Ref SSHKeyName | |
SecurityGroups: | |
- !Ref SecurityGroup | |
IamInstanceProfile: !Ref InstanceProfile | |
UserData: | |
Fn::Base64: !Sub | | |
#cloud-config | |
packages: | |
- awscli | |
runcmd: | |
- > | |
for i in {1..3}; do /usr/bin/easy_install | |
https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz | |
2>&1 >> /var/log/initial_user-data.log && break || sleep 10; done | |
- aws --region us-west-2 ec2 describe-regions --output text >> /tmp/custom-output.txt | |
- CFNSTATUS=$? | |
- > | |
/usr/bin/cfn-signal | |
--exit-code $CFNSTATUS | |
--data "$( < /tmp/custom-output.txt )" | |
"${WaitConditionHandle}" 2>&1 >> /var/log/initial_user-data.log | |
Role: | |
Type: AWS::IAM::Role | |
Properties: | |
AssumeRolePolicyDocument: | |
Version: 2012-10-17 | |
Statement: | |
- Effect: Allow | |
Principal: | |
Service: ec2.amazonaws.com | |
Action: sts:AssumeRole | |
Policies: | |
- PolicyName: DescribeRegions | |
PolicyDocument: | |
Version: 2012-10-17 | |
Statement: | |
- Sid: AllowEC2DescribeRegions | |
Effect: Allow | |
Action: | |
- ec2:DescribeRegions | |
Resource: '*' | |
InstanceProfile: | |
Type: AWS::IAM::InstanceProfile | |
Properties: | |
Roles: | |
- !Ref Role | |
WaitConditionHandle: | |
Type: AWS::CloudFormation::WaitConditionHandle | |
WaitCondition: | |
Type: AWS::CloudFormation::WaitCondition | |
DependsOn: Instance | |
Properties: | |
Handle: !Ref WaitConditionHandle | |
Timeout: '300' | |
Outputs: | |
CloudInitOutput: | |
Description: The data returned to the WaitConditionHandle from Cloud Init | |
Value: !GetAtt WaitCondition.Data | |
EC2InstancePublicDNSName: | |
Description: The public DNS name of the instance | |
Value: !GetAtt Instance.PublicDnsName |
I found what's wrong with the above. The clue is in the line cfn-signal: error: option --exit-code: invalid integer value: '--data'
In the template, we have this:
"UserData":{
"Fn::Base64":{
"Fn::Join":[
"",
[
"#cloud-config\n",
"\n",
"runcmd:\n",
" - for i in {1..3}; do /usr/bin/easy_install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz 2>&1 >> /var/log/initial_user-data.log && break || sleep 10; done\n",
" - dmidecode 2>&1 >> /tmp/custom-output.txt",
" - CFNSTATUS=$?\n",
" - /usr/bin/cfn-signal ",
" --exit-code $CFNSTATUS ",
" --data \"$( base64 -w 0 /tmp/custom-output.txt )\" ",
"'",
{
"Ref":"WaitConditionHandle"
},
"'",
" 2>&1 >> /var/log/initial_user-data.log\n"
]
]
}
}
It looks like $CFNSTATUS is not being set to 0 (or an error), but rather is empty. I proved this by adding a line to echo $CFNSTATUS into a file in /tmp, and also to provide a 0 to the --exit-code argument in the call to /usr/bin/cfn-signal.
Once I made those changes, the server built.
Not sure why this would be so.
@edgreenberg Good catch. The reason for that bug was that the line that runs dmidecode
doesn't have a trailing \n
. So the line that looks like this
" - dmidecode 2>&1 >> /tmp/custom-output.txt",
should have looked like this
" - dmidecode 2>&1 >> /tmp/custom-output.txt\n",
I'm updating this template to yaml which will solve this problem.
@locomotif The updated template contains the regions you'd mentioned. The AMI mapping is generated with code that you can find here (so that it won't miss any regions) : https://gist.github.com/gene1wood/56e42097e0f0ac1aace14cbc41ee3e11#file-create_centos7_cloudformation_ami_mapping-py
I tried this, as written, and it times out and rolls back. I could sure use some help understanding what is failing. The log files are below.
initial_user-data.log
cloud-init.txt
cloud-init-output.txt