19

I am tagging my resources using Tags in my cfn script:

"Tags" : [ { "Key" : "Owner", "Value" : "my name" }, { "Key" : "Name", "Value" : "instance name" } { "Key" : "DateCreated", "Value" : <something goes here> } ], 

I would like to create a tag with the current date as per the example above. Is it possible?

1

2 Answers 2

15

You can use a "custom resource" to generate a timestamp (or any other value).

Custom resources are a newish feature in CloudFormation (introduced around 2014) and allow you to basically call a lambda function to "create", "update" or "delete" a resource for which CloudFormation does not provide language support (can even be resources outside AWS).

I use custom resource a lot just to compute some values for use in other parts of the stack, for example to create "variables" that hold computed values (e.g. using !Join and similar functions) that I need to use often and would like to compute once.

You can easily use a custom resource to just generate a time stamp. Here is some example code that is very close to what I actually use in production:

Create the "resource" implementation

Resources: ValueFunc: Type: AWS::Lambda::Function Properties: Code: ZipFile: > var r = require('cfn-response'); exports.handler = function(ev, ctx) { ev.ResourceProperties.Time = new Date().toISOString(); r.send(ev, ctx, r.SUCCESS, ev.ResourceProperties); }; Handler: index.handler Runtime: nodejs6.10 Timeout: 30 Role: !GetAtt ValueFunctionExecutionRole.Arn ValueFunctionExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: { Service: [ lambda.amazonaws.com ] } Action: sts:AssumeRole Policies: - PolicyName: Fn::Sub: "value-custom-res-${AWS::StackName}-${AWS::Region}" PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: "arn:aws:logs:*:*:*" - Effect: Allow Action: cloudformation:DescribeStacks Resource: "arn:aws:cloudformation:*:*:*" 

Then wherever you want to generate a time stamp, you do something like this (Scheduled action example taken from here):

Create a custom resource that calculates its creation time

GetTimeThisTime: Type: Custom::Value Properties: ServiceToken: !GetAtt ValueFunc.Arn 

Read the created timestamp using the Time attribute

ScheduledActionUp: Type: AWS::AutoScaling::ScheduledAction Properties: AutoScalingGroupName: !Ref WebServerGroup DesiredCapacity: 2 StartTime: !GetAtt GetTimeThisTime.Time Recurrence: "0 7 * * *" 

You can generate multiple time stamps at different times of the stack creation by simply creating a new "custom value" that depends on the logical entity whose creation you want to time.

Sign up to request clarification or add additional context in comments.

3 Comments

It seems like this would work for only the initial stack creation but not subsequent stack updates
That is true. If you know what change you want to cause the time stamp custom value to change (I'm assuming you don't want to do that for every little change), then you can add another property to the custom value that you'll manually (or with another tool) change as needed. For example, Serial: !Ref Serial and then have a parameter Serial that you update as needed. See this question and its answers for some discussion on that: stackoverflow.com/q/46824171/53538
As far as I can see, the permission "cloudformation:DescribeStacks" is not required.
13

The advice by @Guy is correct, you can access the creation timestamp of the stack from the stack properties.

If you still need to specify tags as parameters then you can do it the following way. Currently the JSON syntax supports an extremely limited set of functions. Because of this the possibilities for dynamically modifying your templates are very tiny. The only way I see to introduce this the tag you want is by adding another parameter to the template itself. Depending on the way you initialize the stack, you can script the parameter to be specified dynamically or provide it in the web console.

For example, if you have this in your template:

 "Parameters" : { "CreationDate" : { "Description" : "Date", "Type" : "String", "Default" : "2013-03-20 21:15:00", "AllowedPattern" : "^\\d{4}(-\\d{2}){2} (\\d{2}:){2}\\d{2}$", "ConstraintDescription" : "Date and time of creation" } }, 

You can later reference it using the Ref keyword in the tags like this:

 "Tags" : [ { "Key" : "Owner", "Value" : "my name" }, { "Key" : "Name", "Value" : "instance name" }, { "Key" : "DateCreated", "Value" : { "Ref" : "CreationDate" } } ], 

It is not trivial to automatically assign the current time if you create the stack from the AWS console, but if you use the CLI tools you can call cfn-create-stack like this:

 cfn-create-stack MyStack --template-file My.template --parameters "CreationDate=$(date +'%F %T')" 

Hope this helps!

2 Comments

It's not just instances - this approach will also work for volumes, AMIs, anything else that you can tag - thanks.
the equivalent using aws cli cloudformation would be aws cloudformation create-stack \ --stack-name yourname \ --template-body file://template.yaml \ --parameters \ ParameterKey=CreationDate,ParameterValue="$(date +'%F %T')"

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.