cfn-signal in aws cloudformation with launchConfiguration and AutoScalingGroup - amazon-web-services

I have the following configuration in my AWS Cloudformation template.
The template creates one EC2 instance based on instance1. I am using the reference to same instance in my LaunchConfiguration to create the instances of same type.
The problem I am facing is by including the CreationPolicy element in my AutoScalingGroup template. I get the following error when ASG launches an instance and waits for the cfn-signal.
+ /opt/aws/bin/cfn-signal -e 0 --stack ss07 --resource Instance1 --region us-west-2
ValidationError: Resource Instance1 is in CREATE_COMPLETE state and cannot be signaled
It seems like somehow the reference is made to an already existing instance1 and not to the instance being created by LaunchConfig. I saw examples which had the LaunchConfig embedded within, but I want to keep the instance details at one place instead of two places.
"instance1": {
"Type": "AWS::EC2::Instance",
"Metadata": {
"AWS::CloudFormation::Init": {
"configSets": {
"install": ["yum_packages","install_cfn"]
},
"yum_packages": {
"packages" : {
"yum" : {
"awslogs" : [],
"ruby" : [],
"wget" : [],
"httpd" : []
}
}
},
"install_cfn": {
"files": {
"/etc/cfn/cfn-hup.conf": {
"content": {
"Fn::Join": [
"",
[
"[main]\n",
"stack=",
{
"Ref": "AWS::StackId"
},
"\n",
"region=",
{
"Ref": "AWS::Region"
},
"\n"
]
]
},
"mode": "000400",
"owner": "root",
"group": "root"
},
"/etc/cfn/hooks.d/cfn-auto-reloader.conf": {
"content": {
"Fn::Join": [
"",
[
"[cfn-auto-reloader-hook]\n",
"triggers=post.update\n",
"path=Resources.WebServer.Metadata.AWS::CloudFormation::Init\n",
"action=/opt/aws/bin/cfn-init -v ",
" --stack ",
{
"Ref": "AWS::StackName"
},
" --resource splitsweetInstance ",
" --configsets install ",
" --region ",
{
"Ref": "AWS::Region"
},
"\n"
]
]
},
"mode": "000400",
"owner": "root",
"group": "root"
}
},
"services": {
"sysvinit": {
"cfn-hup": { "enabled": "true", "ensureRunning": "true", "files": [
"/etc/cfn/cfn-hup.conf",
"/etc/cfn/hooks.d/cfn-auto-reloader.conf"
]
}
}
}
}
}
},
"CreationPolicy": {
"ResourceSignal": {
"Timeout": "PT10M"
}
},
"Properties": {
"ImageId": {
"Fn::FindInMap": [
"AWSRegionArch2AMI", {
"Ref": "AWS::Region"
}, {
"Fn::FindInMap": [
"AWSInstanceType2Arch", {
"Ref": "instanceType1"
},
"Arch"
]
}
]
},
"InstanceType": {"Ref": "instanceType1"},
"KeyName": {"Ref": "KeyName"},
"Monitoring": "false",
"UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
"#!/bin/bash -xe\n",
"yum install -y aws-cfn-bootstrap\n",
"# Install the files and packages from the metadata\n",
"/opt/aws/bin/cfn-init -v ",
" --stack ", { "Ref" : "AWS::StackName" },
" --resource splitsweetInstance ",
" --configsets install ",
" --region ", { "Ref" : "AWS::Region" }, "\n",
"wget ", { "Fn::FindInMap": [ "Region2CodeDeployAgent", { "Ref": "AWS::Region"}, "url"] }, "\n",
"chmod +x ./install\n",
"./install auto\n",
"# Signal the status from cfn-init\n",
"/opt/aws/bin/cfn-signal -e $? ",
" --stack ", { "Ref" : "AWS::StackName" },
" --resource splitsweetInstance ",
" --region ", { "Ref" : "AWS::Region" }, "\n"
]]}},
"Tags": [
{
"Key": "Name",
"Value": "inst1"
}
],
"SecurityGroupIds": [
{ "Fn::GetAtt" : [ "instance1Sg", "GroupId" ] }
]
}
}
My Launch Config is as follows -
"LaunchConfig1": {
"Type" : "AWS::AutoScaling::LaunchConfiguration",
"Properties" : {
"ImageId": {
"Fn::FindInMap": [
"AWSRegionArch2AMI", {
"Ref": "AWS::Region"
}, {
"Fn::FindInMap": [
"AWSInstanceType2Arch", {
"Ref": "instanceType1"
},
"Arch"
]
}
]
},
"InstanceId" : { "Ref":"instance1"},
"InstanceMonitoring" : "false",
"InstanceType" : { "Ref": "instanceType1"},
"KeyName" : { "Ref" : "KeyName" },
"SecurityGroups" : [ { "Fn::GetAtt" : [ "instance1Sg", "GroupId" ] } ]
}
}
This is my AutoScalingGroup template -
"AutoScalingGroup1": {
"Type" : "AWS::AutoScaling::AutoScalingGroup",
"Properties" : {
"AvailabilityZones" : { "Fn::GetAZs": { "Ref": "AWS::Region" } },
"Cooldown" : "60",
....
"LaunchConfigurationName" : {"Ref":"LaunchConfig1"},
"MaxSize" : "3",
"MinSize" : "1",
"TargetGroupARNs" : [ {"Ref":"TargetGroup1"} ],
"VPCZoneIdentifier" : [ { "Ref": "subnetCache1" }, { "Ref": "subnetCache2" }, { "Ref": "subnetCache3" } ]
},
"CreationPolicy" : {
"ResourceSignal" : {
"Timeout" : "PT6M",
"Count" : "1"
}
}
}

The problem is that by specifying the InstanceId property in your LaunchConfiguration resource, it is reusing the same UserData that was used to launch the initial EC2 instance, including the hard-coded reference to the Logical Resource signaled by the cfn-signal command. According to the documentation,
When you use an instance to create a launch configuration, all properties are derived from the instance with the exception of BlockDeviceMapping and AssociatePublicIpAddress. You can override any properties from the instance by specifying them in the launch configuration.
To have cfn-signal signal the correct Resource, you will need to override the UserData in your LaunchConfiguration resource to contain a User-Data script that references the Launch Configuration rather than the original EC2 instance. Unfortunately, this will require either duplicating the User-Data script, or rewriting the script to dynamically figure out the Logical Resource associated with the instance the script is currently running on, so the same exact User-Data can be used in both the original EC2 instance and the auto scaling group.

I agree with wjordan that part of the problem you are having is with the InstanceId property in LaunchConfiguration. Also looking at your code sample I could not figure out where splitsweetInstance was referenced.
However my CloudFormation AutoScalingGroup was not set up this way and I still got the same error CREATE_COMPLETE state and cannot be signaled.
The solution for me was setting the DesiredCapacity on the AutoScalingGroup (hopefully this helps others as well) was found here:
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-group.html#cfn-as-group-desiredcapacity
As per the docs:
CloudFormation will not mark the Auto Scaling group as successful (by setting its status to CREATE_COMPLETE) until the desired capacity is reached.
This is what that portion of my CloudFormation template looks like:
"WebServerGroup" : {
"Type" : "AWS::AutoScaling::AutoScalingGroup",
"Properties" : {
"VPCZoneIdentifier" : { "Ref" : "Subnets" },
"LaunchConfigurationName" : { "Ref" : "LaunchConfig" },
"MinSize" : "2",
"MaxSize" : "4",
"DesiredCapacity" : "2",
"TargetGroupARNs" : [ { "Ref" : "ALBTargetGroup" } ]
}
Below is the "signal" portion of UserData section:
"# Signal the status from cfn-init\n",
"/opt/aws/bin/cfn-signal -e $? ",
" --stack ", { "Ref" : "AWS::StackName" },
" --resource WebServerGroup ",
" --region ", { "Ref" : "AWS::Region" }, "\n",

To solve this problem I ensured that I added both CreationPolicy & UpdatePolicy in Autoscaling group before using cfn-signal in UserData section of the LaunchTemplate
CreationPolicy:
AutoScalingCreationPolicy:
MinSuccessfulInstancesPercent: somepercent
ResourceSignal:
Count: somenumber
Timeout: someminutes
UpdatePolicy:
AutoScalingScheduledAction:
IgnoreUnmodifiedGroupSizeProperties: 'true'
AutoScalingRollingUpdate:
MinInstancesInService: 'somenumber'
MaxBatchSize: 'somenumber'
PauseTime: someminutes
WaitOnResourceSignals: 'true'

Related

Cloudformation - Using parameters in EC2 server

Below is my cloudformation template. Basically I want to use a parameter called "User" in a command in EC2 ubuntu server.
I have tried many solutions, but the mkdir command is not fails, rest of the template is working.
In the below example I have tried to set the "User" value as a tag as well as a property. Both failed. Suggest if you have seen any such examples.
{
"AWSTemplateFormatVersion": "2010-09-09",
"Parameters": {
"UserName": {
"Type": "String",
"Description": "Enter the username",
"AllowedPattern": "[a-zA-Z0-9_\\-]+",
"ConstraintDescription": "It should be a combination of characters from [A-Z],[a-z],[0-9],- and _."
},
"KeyName": {
"Description" : "Name of an existing EC2 KeyPair to enable SSH access to the instances",
"Type": "AWS::EC2::KeyPair::KeyName",
"ConstraintDescription" : "must be the name of an existing EC2 KeyPair."
}
},
"Resources": {
"EC2Ansiblemaster2743": {
"Type": "AWS::EC2::Instance",
"Metadata": {
"User" : { "Ref": "UserName" },
"AWS::CloudFormation::Init" : {
"configSets" : {
"CreateFile" : [
"create_file"
]
},
"create_file" : {
"files" : {
"/home/ubuntu/healthy.txt": {
"content": "Hello"
}
},
"commands" : {
"mkdir" : {
"command" : "sudo mkdir /home/$User"
}
}
}}
},
"Properties": {
"AvailabilityZone": "us-east-2a",
"ImageId": "ami-05c1fa8df71875112",
"InstanceType": "t2.micro",
"SourceDestCheck": false,
"KeyName" : { "Ref" : "KeyName" },
"Tags" : [
{
"Key" : "User",
"Value" : { "Ref": "UserName" }
}],
"UserData": {
"Fn::Base64": {
"Fn::Join": [
"",
[
"#!/bin/bash -xe\n",
"sudo apt-get update\n",
"sudo apt-get -y install python-pip\n",
"sudo pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz\n",
"# Install the files and packages from the metadata\n",
"sudo /usr/local/bin/cfn-init ",
" --stack ",
{
"Ref": "AWS::StackName"
},
" --resource EC2Ansiblemaster2743 ",
" --configsets CreateFile ",
" --region ",
{
"Ref": "AWS::Region"
},
"\n",
"# Signal the status from cfn-init\n",
"sudo /usr/local/bin/cfn-signal -e $? ",
" --stack ",
{
"Ref": "AWS::StackName"
},
" --resource EC2Ansiblemaster2743 ",
" --region ",
{
"Ref": "AWS::Region"
},
"\n"
]
]
}
},
"SecurityGroupIds": [
{
"Ref": "EC2SG2AnsM0012743"
}
]
}
},
"EC2SG2AnsM0012743": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"GroupName": "SGAnsibleMas2743",
"GroupDescription": "First",
"SecurityGroupIngress": [
{
"CidrIp": "0.0.0.0/0",
"FromPort": "0",
"ToPort": "65535",
"IpProtocol": "tcp",
"Description": "From Anywhere"
},
{
"CidrIp": "0.0.0.0/0",
"FromPort": "22",
"ToPort": "22",
"IpProtocol": "tcp",
"Description": "SSH from anywhere , from and to port will be same - 22"
}
]
},
}
}
}
I used the Fn:Sub to get the parameter to Userdata.
{
"Fn::Sub":
[
"UserName=${variable}\n",
{
"variable": {
"Ref": "UserName"
}
}]
Later I curl 169.254.169.254/latest/user-data to extract the Username string.
Please let me know if any easier solution is there for this issue.
Use the join intrinsic function to properly form the command string by referencing the username in the template.
"command" : "Fn::Join": [ "", "mkdir /home/", { "Ref": "UserName" }]
The issue is that your mkdir command does not resolve as you have it. There is no linkage between the username parameter and the command in the init section. By using the Join function I am forming the command with the correct parameter value.

how to wait for cfn-signal before adding a booting EC2 to the ELB

my question is about achieving to wait for cfn-signal before adding a booting EC2 to the ELB (if possible, using cloudformation).
For now, the ELB start using the instance without waiting it to be ready, worst, if I do start the apache service only at the end of the "boot", it do not wait for the grace period and remove the instance before it has finish to be initialized.
here is my AutoScalingGroup conf :
"webServerASG": {
"Type": "AWS::AutoScaling::AutoScalingGroup",
"CreationPolicy": {
"ResourceSignal": {
"Timeout": "PT10M",
"Count": { "Ref": "WebServerDesiredCapacity" }
}
},
"UpdatePolicy" : {
"AutoScalingReplacingUpdate" : {
"WillReplace" : true
},
"AutoScalingRollingUpdate" : {
"MaxBatchSize" : 1,
"MinInstancesInService" : 1,
"MinSuccessfulInstancesPercent" : 75,
"SuspendProcesses" : [ "AlarmNotification", "ScheduledActions", "AZRebalance", "ReplaceUnhealthy", "HealthCheck", "Launch" ],
"WaitOnResourceSignals": true,
"PauseTime" : "PT10M"
}
},
"Properties": {
"AvailabilityZones": [...],
"Cooldown": "60",
"HealthCheckGracePeriod": "560",
"HealthCheckType": "ELB",
"MaxSize": { "Ref": "WebServerMaxCapacity" },
"MinSize": "1",
"DesiredCapacity": { "Ref": "WebServerDesiredCapacity" },
"VPCZoneIdentifier": [...],
"NotificationConfigurations": [...],
"LaunchConfigurationName": { "Ref": "webServer01LC" },
"LoadBalancerNames": [ { "Ref": "webServerLoadBalancerELB" } ],
"MetricsCollection": [...],
"TerminationPolicies": [
"Default"
]
}
},
with this conf for the LoadBalancer :
"webServerLoadBalancerELB": {
"Type": "AWS::ElasticLoadBalancing::LoadBalancer",
"Properties": {
"Subnets": [...],
"HealthCheck": {
"HealthyThreshold": "10",
"Interval": "30",
"Target": "HTTP:80/aws/healthcheck.php",
"Timeout": "5",
"UnhealthyThreshold": "2"
},
"ConnectionDrainingPolicy": {
"Enabled": "true",
"Timeout": "300"
},
"ConnectionSettings": {
"IdleTimeout": "60"
},
"CrossZone": "true",
"SecurityGroups": [...],
"Listeners": [
{
"LoadBalancerPort": "80",
"Protocol": "HTTP",
"InstancePort": "80",
"InstanceProtocol": "HTTP"
}
]
}
}
and for the LaunchConfiguration :
"webServer01LC": {
"Type": "AWS::AutoScaling::LaunchConfiguration",
"Properties": {
"AssociatePublicIpAddress": false,
"ImageId": {...},
"InstanceType": "t2.small",
"KeyName": {...},
"IamInstanceProfile": "EC2WebServerRole",
"SecurityGroups": [...],
"BlockDeviceMappings": [...],
"UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
"#!/bin/bash\n",
"echo '\n### pip install cloud-init : ' | tee --append /var/log//userData.log \n",
"pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-latest.tar.gz 2>> /var/log//userData.log\n",
"ln -s /usr/local/init/ubuntu/cfn-hup /etc/init.d/cfn-hup >> /var/log//userData.log>&1\n",
"echo '\n### execute the AWS::CloudFormation::Init defined in the Metadata' | tee --append /var/log//userData.log \n",
"cfn-init -v",
" --region ", { "Ref" : "AWS::Region" },
" --stack ", { "Ref" : "AWS::StackName" },
" --resource lciTophubWebServer01LC ",
" \n",
"cfn-signal --exit-code $? --region ", { "Ref" : "AWS::Region" }, " --stack ", { "Ref" : "AWS::StackName" }, " --resource asgiTophubWebServerASG \n",
"echo '\n### end of the script!' | tee --append /var/log//userData.log \n"
]]}}
},
"Metadata": {...}
}
I found out my problem :
ELB status checks are run without pause, so during the grace period, the tests are running.
once the grace period is finished, the autoscaling group immediately look at the current ELB status checks.
In my case, I had "HealthyThreshold": "10" and "Interval": "30" so it took ELB 10*30=300 sec. to change its minds (even 329.99 if I'm not lucky) and it is way too long compared to the HealthCheckGracePeriod which is only 560 (560 - 329.99 = 230.01 sec. left to have finished starting).
I shortened this "become healthy again" delay by passing HealthyThreshold at 2 :
560 - 99.99 = 460.01 sec. left to start.

CloudFormation template failing to create "files" under MetaData Section

Could somebody help me point what wrong am I doing here. I am failing to understand how the meta data part uses the authentication resource, In the AWS::CloudFormation::Authentication part I've mentioned the role same as the one attached to the instance, Yet I'm unable to create the file "some.txt"
{
"Parameters": {
"SecurityGroupId": {
"Description": "Security group for instance",
"Type": "AWS::EC2::SecurityGroup::Id"
}
},
"Resources": {
"MyInstance": {
"Type": "AWS::EC2::Instance",
"Metadata": {
"AWS::CloudFormation::Init": {
"configsets": {
"InstallIt": ["config1"]
},
"config1": {
"files": {
"/home/ec2-user/some.txt": {
"content": "This is my name ",
"encoding": "base64",
"mode": "000644",
"owner": "root",
"group": "root"
}
}
}
},
"AWS::CloudFormation::Authentication": {
"HelpMe": {
"type": "S3",
"buckets": "poc-bucket",
"roleName": "EC2andS3"
}
}
},
"Properties": {
"KeyName": "GoldenImage-NV-Anant",
"DisableApiTermination": "false",
"ImageId": "ami-0b33d91d",
"InstanceType": "t2.micro",
"Monitoring": "false",
"SubnetId": "subnet-73487a59",
"SecurityGroupIds": [{
"Ref": "SecurityGroupId"
}],
"IamInstanceProfile": {
"Ref": "MyInstanceProfile"
},
"Tags": [{
"Key": "Name",
"Value": "GeicoUserDataPocInstance"
}],
"UserData": {
"Fn::Base64": {
"Fn::Join": [
"", [
"#!/bin/bash -ex \n",
"echo \"hello dudes\" > /home/ec2-user/hello.txt \n",
"yum update -y aws-cfn-bootstrap\n",
"/opt/aws/bin/cfn-init -v",
" --stack ", {
"Ref": "AWS::StackId"
},
" --resource MyInstance ",
" --configsets InstallIt ",
" --region ", {
"Ref": "AWS::Region"
}, "\n",
"echo \"bye dudes\" > /home/ec2-user/bye.txt", "\n",
"/opt/aws/bin/cfn-signal -e $? ",
" --stack ", {
"Ref": "AWS::StackId"
},
" --resource MyInstance ",
" --region ", {
"Ref": "AWS::Region"
}, "\n"
]
]
}
}
},
"CreationPolicy": {
"ResourceSignal": {
"Timeout": "PT90M",
"Count": "1"
}
}
},
"MyInstanceProfile": {
"Description": "Instance profile for the instance",
"Type": "AWS::IAM::InstanceProfile",
"Properties": {
"Path": "/",
"Roles": ["EC2andS3"]
}
}
}
}
configsets should be configSets with capital S:
"configSets": {
"InstallIt": ["config1"]
},
buckets property needs to be a list of strings (this might not be necessary, the documentation is a bit unclear):
"buckets": ["poc-bucket"]
AWS::CloudFormation::Authentication resource shouldn't be necessary unless the source of your file is an S3 bucket. Even then, it still shouldn't be necessary when using an attached instance profile, since it will use the instance profile for authentication by default.

AWS - cfn-init not creating a file

I am new to cloudformation.
I am using cfn-init to create a file. But doesnt create a file nor my stack fails. Stack successfully gets created with required resources like EC2 instance. Also it installs AWS CLI as mentioned in User data.
But it just does not create file i wish to create.
I tried using Advanced options of not allowing rollback of stack. But the /var/log/cfn-init.log does not get created.
See the template below? Am I doing anything wrong in this?
{
"Parameters" : {
"KeyName" : {
"Description" : "The EC2 Key Pair to allow SSH access to the instance",
"Type" : "AWS::EC2::KeyPair::KeyName"
}
},
"Resources" : {
"Ec2Instance" : {
"Type" : "AWS::EC2::Instance",
"Metadata" : {
"Comment" : "Install a simple application",
"AWS::CloudFormation::Init" : {
"config" : {
"files" : {
"/tmp/setup.mysql" : {
"content" : { "Fn::Join" : ["", ["[default]\n","region=",{"Ref": "AWS::Region"}]]},
"mode" : "000775",
"owner" : "ec2-user",
"group" : "ec2-user"
}
}
}
} },
"Properties" : {
"SecurityGroups" : [ {
"Ref" : "InstanceSecurityGroup" }
],
"IamInstanceProfile" : {"Ref" : "RootInstanceProfile"} ,
"KeyName" : { "Ref" : "KeyName"},
"InstanceType" : "t2.micro",
"ImageId" : "ami-58277d3d",
"UserData": {
"Fn::Base64": {
"Fn::Join": [
"",
[
"curl https://s3.amazonaws.com/aws-cli/awscli-bundle.zip -o awscli-bundle.zip\n",
"unzip awscli-bundle.zip\n",
"sudo ./awscli-bundle/install -i /usr/local/aws -b /usr/local/bin/aws\n",
"/opt/aws/bin/cfn-init -v ",
" --stack ", { "Ref" : "AWS::StackName" },
" --resource Ec2Instance ",
" --region ", { "Ref" : "AWS::Region" }, "\n",
"cfn-signal -e 0",
" --stack ",
{
"Ref": "AWS::StackName"
},
" --region ",
{
"Ref": "AWS::Region"
},
" --resource ",
"Ec2Instance",
"\n"
]
]
}
}
}
},
"RootRole": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Version" : "2012-10-17",
"Statement": [ {
"Effect": "Allow",
"Principal": {
"Service": [ "ec2.amazonaws.com" ]
},
"Action": [ "sts:AssumeRole" ]
} ]
},
"Path": "/",
"Policies": [ {
"PolicyName": "root",
"PolicyDocument": {
"Version" : "2012-10-17",
"Statement": [ {
"Effect": "Allow",
"Action": ["cloudwatch:PutMetricData"],
"Resource": "*"
} ]
}
} ]
}
},
"RootInstanceProfile": {
"Type": "AWS::IAM::InstanceProfile",
"Properties": {
"Path": "/",
"Roles": [ {
"Ref": "RootRole"
} ]
}
},
"InstanceSecurityGroup" : {
"Type" : "AWS::EC2::SecurityGroup",
"Properties" : {
"GroupDescription" : "Enable SSH access via port 22",
"Tags" : [{ "Key" : "Name", "Value" : "SecurityGr_EC2WithParam" }],
"SecurityGroupIngress" : [ {
"IpProtocol" : "tcp",
"FromPort" : "22",
"ToPort" : "22",
"CidrIp" : "0.0.0.0/0"
} ]
}
}
}
}
As discovered in your comment, the UserData property on your AWS::EC2::Instance Resource requires the first line to be #!/bin/bash\n.
This is necessary in order for the user-data processed by cloud-init to be interpreted as a User-Data Script, as noted in the AWS EC2 documentation section, Running Commands on Your Linux Instance at Launch:
User data shell scripts must start with the #! characters and the path to the interpreter you want to read the script (commonly /bin/bash).
Note also that sudo is not necessary in your user-data script, as also noted in the documentation:
Scripts entered as user data are executed as the root user, so do not use the sudo command in the script.
Finally, note that the AWS CLI comes pre-installed on the Amazon Linux AMI instances by default, which is why you noticed the AWS CLI was still installed on your instance despite your user-data script not running correctly.

How to create a LaunchConfiguration using CloudFormation template which creates a config file?

I want to write a LaunchConfiguration for my AWS stack using CloudFormation template.
I have written it like below.
"LaunchConfiguration": {
"Type": "AWS::AutoScaling::LaunchConfiguration",
"Metadata" : {
"AWS::CloudFormation::Init" : {
"files": {
"/etc/test.conf": {
"content": { "Fn::Join": [ "", [
"user: root\n",
"password: password\n"
]]},
"mode": "000400",
"user": "root",
"group": "root"
}
}
}
},
"Properties": {
"ImageId": "ami-*****",
"InstanceType": "*****",
"KeyName": "*****",
"IamInstanceProfile": "*****",
"InstanceMonitoring": "****",
"SecurityGroups": [
{
"Ref": "SecurityGroup"
}
]
}
},
The file is not being created in the EC2 instances created. Can anyone help me on this?
You're missing a couple things. First, you need invoke the cfn-init script from the LaunchConfiguration UserData.
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-helper-scripts-reference.html
"UserData" : { "Fn::Base64" : { "Fn::Join" : [ "", [
"#!/bin/bash -ve\n",
"# Run cfn-init\n",
"/opt/aws/bin/cfn-init -v ",
" --stack ", { "Ref": "AWS::StackName" },
" --resource LaunchConfiguration ",
" --region ", { "Ref" : "AWS::Region" }, "\n",
"# Signal success\n",
"/opt/aws/bin/cfn-signal -e $? ",
" --stack ", { "Ref" : "AWS::StackName" },
" --resource AutoScalingGroup ",
" --region ", { "Ref" : "AWS::Region" }, "\n"
]]}}
This example also uses cfn-signal to signal success which notifies the Auto Scaling group that the instance bootstrapping was successful. To use this feature, you will also need to add the CreationPolicy to your AutoScalingGroup resource.
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-creationpolicy.html
"CreationPolicy" : {
"ResourceSignal" : {
"Timeout" : "PT10M",
"Count" : "1"
}
}
Lastly, you are missing the default config wrapper around your Metadata.
"Metadata" : {
"AWS::CloudFormation::Init" : {
"config" : {
"files": {
"/etc/test.conf" : {
"content" : { "Fn::Join": [ "", [
"user: root\n",
"password: password\n"
]]},
"mode" : "000400",
"user" : "root",
"group" : "root"
}
}
}
}
}
You can use something other than config, but you then need to define the configSets attribute.
http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-init.html#aws-resource-init-configsets
"AWS::CloudFormation::Init" : {
"configSets" : {
"default" : [
"db-config",
"app-config"
]
},
"db-config": {
"files": {
...
}
},
"app-config": {
...
}
}
For more information, this is a detailed overview of bootstrapping instances using CloudFormation.
https://s3.amazonaws.com/cloudformation-examples/BoostrappingApplicationsWithAWSCloudFormation.pdf
Put "files" to "upload" section as
"Metadata" : {
"AWS::CloudFormation::Init" : {
"upload": {
"files": {
"/etc/test.conf": {
"content": { "Fn::Join": [ "", [
"user: root\n",
"password: password\n"
]]},
"mode": "000400",
"user": "root",
"group": "root"
}
}
}
}
},