How do I use AWSUtility::CloudFormation::CommandRunner to run a command before or after a resource in my AWS CloudFormation stack?

Last updated: 2020-12-17

I want to use AWSUtility::CloudFormation::CommandRunner to run a command before or after a resource in my AWS CloudFormation stack.

Resolution

Note: If you receive errors when running AWS Command Line Interface (AWS CLI) commands, make sure that you’re using the most recent AWS CLI version.

To run a command before or after a resource in your AWS CloudFormation stack, define the AWSUtility::CloudFormation::CommandRunner resource in your AWS CloudFormation template.

For example:

Resources:
    CommandRunner:
        Type: AWSUtility::CloudFormation::CommandRunner
        Properties: 
            Command: 'aws ssm get-parameter --name BucketName --region us-east-1 --query Parameter.Value --output text > /command-output.txt'
            Role: EC2-Role
            LogGroup: my-cloudwatch-log-group

Important: If you haven't already registered the AWSUtility::CloudFormation::CommandRunner resource, then run the following commands.

git clone https://github.com/aws-cloudformation/aws-cloudformation-resource-providers-awsutilities-commandrunner.git
cd aws-cloudformation-resource-providers-awsutilities-commandrunner
curl -LO https://github.com/aws-cloudformation/aws-cloudformation-resource-providers-awsutilities-commandrunner/releases/latest/download/awsutility-cloudformation-commandrunner.zip
./scripts/register.sh --set-default

Important: The property Role requires a trust relationship with the Amazon Elastic Compute Cloud (Amazon EC2) service (ec2.amazonaws.com). The property Role is assumed by the AWSUtility::CloudFormation::CommandRunner resource to run your command. The optional property LogGroup, if specified, writes the logs from your command's execution to the Amazon CloudWatch log group.

You must Include the --region option in your AWS CLI commands, and write the command's output to a reserved file called /command-output.txt, as in the preceding code example.

You can reference the output of the command using Fn::GetAtt. For example:

S3Bucket: 
    Type: AWS::S3::Bucket
    Properties: 
        BucketName: !GetAtt CommandRunner.Output

To run the command after a resource with the logical name Instance, specify DependsOn: Instance in the AWSUtility::CloudFormation::CommandRunner resource's definition.

For example:

Resources:
   CommandRunner:
      DependsOn: Instance
      Type: AWSUtility::CloudFormation::CommandRunner
      Properties:
         Command: aws s3 ls | sed -n 1p | cut -d " " -f3 > /command-output.txt
         LogGroup: my-cloudwatch-log-group
         Role: EC2-Role
   Instance:
      Type: AWS::EC2::Instance
      Properties:
         Image: ami-abcd1234

To run the command before a resource, set DependsOn to the logical name of the AWSUtility::CloudFormation::CommandRunner resource in that resource's definition.

For example:

Resources:
   CommandRunner:
      Type: AWSUtility::CloudFormation::CommandRunner
      Properties:
         Command: aws s3 ls | sed -n 1p | cut -d " " -f3 > /command-output.txt
         LogGroup: my-cloudwatch-log-group
         Role: EC2-Role
   Instance:
      DependsOn: CommandRunner
      Type: AWS::EC2::Instance
      Properties:
         Image: ami-abcd1234

Note: In the preceding examples, sed -n 1p prints only the first line from the response returned by aws s3 ls. To get the bucket name, sed -n 1p pipes the response to cut -d " " -f3, which picks the third element in the array created after splitting the line delimited by a space.