Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get current date in a CloudFormation script?

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?

like image 216
chris Avatar asked Mar 26 '13 13:03

chris


2 Answers

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.

like image 80
Guss Avatar answered Sep 20 '22 14:09

Guss


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!

like image 41
zorlem Avatar answered Sep 18 '22 14:09

zorlem