Reference ID of resource in Userdata Cloudformation - amazon-web-services

I'm writing a cloudformation template in YAML format.
Now i'm stuck with appending the id of the ebs volume to ec2 user data.
Type: AWS::EC2::Volume
Properties:
Size: 50
AvailabilityZone: ap-southeast-1b
Tags:
- Key: Name
Value: Logstash Volume
LogStashMountPoint:
Type: AWS::EC2::VolumeAttachment
Properties:
InstanceId:
Ref: LogstashInstance
VolumeId:
Ref: LogstashVolume
Device: "/dev/xvdf"
LogstashInstance:
Type: AWS::EC2::Instance
Properties:
IamInstanceProfile:
Ref: LogstashInstanceProfile
InstanceType: t2.micro
KeyName: chuongtest
ImageId: ami-0cd31be676780afa7
UserData:
Fn::Base64:
Fn::Sub:
- |
#!/bin/bash -xe
echo ${LogstashVolume} >> /home/ec2-user/ebsid.txt
{LogstashVolume: Ref: LogstashVolume}
touch /home/ec2-user/ebscomplete.txt
curl "http://169.254.169.254/latest/meta-data/instance-id" >> /home/ec2-user/ec2id.txt
touch /home/ec2-user/ec2complete.txt
touch /home/ec2-user/complete.txt
- LogstashVolume: !Ref LogstashVolume
SecurityGroupIds:
- Ref: LogstashSecurityGroup
SubnetId: subnet-0d0e0989f57b96389
Tags:
- Key: Name
Value: Logstash Instance
UserData script with Resource Attribute CloudFormation
I'm following this link but it still doesn't work
When the new instance is launched. It has nothing in /home/ec2-user.
I looked everywhere and this is my final but it didn't work
Can anyone help me with it?

There is at least one syntax error in your UserData:
echo ${LogstashVolume}) >> /home/ec2-user/ebsid.txt
should be
echo ${LogstashVolume} >> /home/ec2-user/ebsid.txt
For further debugging of your UserData, login to the instance and check /var/log/could-init-output.log file.
p.s.
The following is also incorrect:
{LogstashVolume: Ref: LogstashVolume}
Its not a valid bash command.

Related

Error creating SpotFleet using CloudFormation

I'm creating a SpotFleet request using CloudFormation, but whenever I try to deploy it, fails with the message:
Unable to fetch parameters [ami-09bee01cc997a78a6] from parameter store for this account.
I'm using the following code (snippet):
SpotFleet:
Type: AWS::EC2::SpotFleet
Properties:
SpotFleetRequestConfigData:
ExcessCapacityTerminationPolicy: default
InstanceInterruptionBehavior: terminate
IamFleetRole: !GetAtt SpotFleetRole.Arn
TargetCapacity: !Ref ClusterSize
TerminateInstancesWithExpiration: false
LaunchSpecifications:
- IamInstanceProfile:
Arn: !Ref ECSInstanceProfile
ImageId: !Ref LatestAmiId
InstanceType: !Ref SpotFleetInstanceType
KeyName: !Ref KeyName
Monitoring:
Enabled: false
SecurityGroups:
- GroupId: !Ref ECSHostSecurityGroup
SubnetId: !Ref PublicSubnet
...
The ImageId is:
LatestAmiId:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: '/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id'
When I manually fetch the image id from the AWS CLI I get:
aws ssm get-parameters --names /aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id --region us-east-1 --output json | jq -r ."Parameters[].Value"
Output:
ami-09bee01cc997a78a6
If a manually hardcode this value into the ImageId parameter, it returns the same error (Unable to fetch parameters...)
Why it is failing if I am able to fetch the id value from the CLI?
Thanks to #Marcin's comment and this answer, I found the problem.
The problem is that I was using the wrong parameter type for the Image Id. I was using:
LatestAmiId:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: '/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id'
and I should be using this:
LatestAmiId:
Description: Linux AMI
Type: AWS::EC2::Image::Id

Im trying to get a file in cloudformation to generate in an ec2 instance and cant seem to see it on the ec2 instance

currently I try to simply spin up an ec2 instance to show myfile2.txt in the tmp folder currently the cloud formation launches. but no file. I have tried working around in the command line and check the logs but I don't see what the issue is I've been having trouble with AWS::CloudFormation::Init: for a while and was wondering if anyone had any suggestions??
This is a just simple exercise that is part of a greater project.
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
InstanceTypeParameter:
Type: String
Default: t2.micro
AllowedValues:
- t2.micro
- m1.small
- m1.large
Description: Enter t2.micro, m1.small, or m1.large. Default is t2.micro.
KeyName:
Description: key pair name
Type: AWS::EC2::KeyPair::KeyName
Resources:
WebInstance:
Type: AWS::EC2::Instance
Metadata:
AWS::CloudFormation::Init:
config:
files:
'/tmp/myfile2.txt':
content: "Hello sir"
mode: '000755'
owner: root
group: root
Properties:
InstanceType:
Ref: InstanceTypeParameter
ImageId: ami-04b762b4289fba92b
SecurityGroupIds:
- sg-0394c353eef246c71
SubnetId: subnet-476a773e
Tags:
-
Key: Name
Value: Trovo-webserver
KeyName:
Ref: KeyName
UserData:
Fn::Base64:
!Sub |
#!/bin/bash -xe
It's not clear if you're running cfn-init command or not. Ideally your userdata section would have a command cfn-init which in turn would invoke the configsets defined under Init key. Please check the sample snippet below.
UserData: !Base64
'Fn::Join':
- ''
- - |
#!/bin/bash -xe
- |
# Install the files and packages from the metadata
- '/opt/aws/bin/cfn-init -v '
- ' --stack '
- !Ref 'AWS::StackName'
- ' --resource WebServerInstance '
- ' --configsets InstallAndRun '
- ' --region '
- !Ref 'AWS::Region'
- |+

AWS CloudFormation UserData EC2 Environment Variable

I'm working on an infrastructure with CloudFormation.
That is my own infrastructure code shown below .
AWSRegionArch2AMI:
us-east-1:
HVM64: ami-0ff8a91507f77f867
HVMG2: ami-0a584ac55a7631c0c
...
..
.
Resources:
EC2Instance:
Type: AWS::EC2::Instance
Properties:
InstanceType:
Ref: InstanceType
SecurityGroups:
- Ref: InstanceSecurityGroup
KeyName:
Ref: KeyName
UserData:
Fn::Base64: !Sub |
#!/bin/bash
export MY_AMI_NAME=${ !GetAtt AWSRegionArch2AMI.us-east-1.HVM64 }
echo $MY_AMI_NAME > $HOME/user_data.txt
I want to set the variable to the user_data file but it is empty, How I can get the environment variable to inside my user data field and use it my own application side How I can do it.
Please help !
Try this:
UserData:
Fn::Base64: !Sub
- |
#!/bin/bash
MY_AMI_NAME=${image_id}
echo $MY_AMI_NAME > $HOME/user_data.txt
- image_id: !GetAtt AWSRegionArch2AMI.us-east-1.HVM64
Explanation:
Use of export in Bash is to make variables available to subshells - "environment variables". You don't need it there.
See the docs for proper use of the !Sub function.
See also this related Stack Overflow answer.

Using Conditions and Parameters in CloudFormation

I am trying to create a condition based on an optional parameter. The option is whether to run some additional installation from my userData script for an EC2 deployment.
The parameters and conditions look like this:
Parameters:
EnvType:
Description: Option to install New Relic Infrastructure.
Default: apm
Type: String
AllowedValues:
- apm
- +infra
Then my EC2 Resource with conditional startup scripts
Resources:
Ec2Instance:
Type: AWS::EC2::Instance
Properties:
InstanceType: t2.micro
ImageId: ami-9c9443e3 #Amazon Linux AMI in Tokyo
KeyName: tokyocloudformation
IamInstanceProfile: 'S3EC2'
SecurityGroupIds:
- !Ref myNewSecurityGroup
UserData:
Condition: apmOnly
Fn::Base64:
|
#!/bin/bash
installstuff
Condition: addInfrastructureAgent
Fn::Base64:
|
#!/bin/bash
installstuff
installsomeotherstuff
The error message I'm getting is:
Template validation error: Template format error: Unresolved dependencies [EnvTyp]. Cannot reference resources in the Conditions block of the template
I get what the error is saying I believe, but it doesn't seem to fit with the examples given by AWS.
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html .
This AWS example clearly uses a !Ref in the Conditions block.
EnvType:
Description: Environment type.
Default: test
Type: String
AllowedValues:
- prod
- test
ConstraintDescription: must specify prod or test.
Conditions:
CreateProdResources: !Equals [ !Ref EnvType, prod ]
Can someone provide some feedback on how to implement this conditional or why this error message is being thrown for this implementation?
According to the docs, Conditions should be used at the top level of the resource you want to conditionally create.
Putting a Condition inside the Instance UserData section isn't supported.
To use Conditions in your situation, you'd want separate Resources conditionally created based on the Parameter.
Resources:
Ec2InstanceAPMOnly:
Type: AWS::EC2::Instance
Condition: apmOnly
Properties:
InstanceType: t2.micro
ImageId: ami-9c9443e3 #Amazon Linux AMI in Tokyo
KeyName: tokyocloudformation
IamInstanceProfile: 'S3EC2'
SecurityGroupIds:
- !Ref myNewSecurityGroup
UserData:
Fn::Base64:
!Sub |
#!/bin/bash
installstuff
Ec2InstanceWithInfrastructureAgent:
Type: AWS::EC2::Instance
Condition: addInfrastructureAgent
Properties:
InstanceType: t2.micro
ImageId: ami-9c9443e3 #Amazon Linux AMI in Tokyo
KeyName: tokyocloudformation
IamInstanceProfile: 'S3EC2'
SecurityGroupIds:
- !Ref myNewSecurityGroup
UserData:
Fn::Base64:
!Sub |
#!/bin/bash
installstuff
installsomeotherstuff
You can use Conditions in userData as well. i followed this post https://www.singlestoneconsulting.com/blog/cloudformation-mapping-and-conditionals-making-your-templates-more-universal/ and it worked perfactlly

Reference Parameter Value in UserData in AWS Cloudformation

I have this under parameter section ,
Parameters:
PlatformSelect:
Description: Cockpit platform Select.
Type: String
Default: qa-1
AllowedValues: [qa-1, qa-2, staging, production]
I need to reference this value in my UserData. I’m using Mappings in between.
Mappings:
bootstrap:
ubuntu:
print: echo ${PlatformSelect} >>test.txt
Resources:
EC2Instance:
Type: AWS::EC2::Instance
Properties:
InstanceType: !Ref ‘InstanceType’
KeyName: !Ref ‘KeyName’
Tags:
- Key: Name
Value: Test
UserData:
Fn::Base64:
Fn::Join:
- ‘’
- - |
#!/bin/bash
- Fn::FindInMap:
- bootstrap
- ubuntu
- print
- |2+
This is not working. Not sure the way I refer it is wrong in first place!!
Should I use something before it like, ‘${AWS::Parameters:PlatformSelect}’ ?
Is there a reason why you are using Mapping in between?
You could easily use !Sub instead
Resources:
EC2Instance:
Type: AWS::EC2::Instance
Properties:
InstanceType: !Ref InstanceType
KeyName: !Ref KeyName
Tags:
- Key: Name
Value: Test
UserData:
Fn::Base64:
!Sub |
#!/bin/bash
${PlatformSelect}
What about a combination of Fn::Join and Ref
UserData:
Fn::Base64:
Fn::Join:
- ''
- - '#!/bin/bash\n'
- 'print: echo'
- !Ref 'PlatformSelect'
- '>>test.txt\n'