stackup

Gem Version Build Status

Stackup provides a CLI and a simplified Ruby API for dealing with AWS CloudFormation stacks.

Why?

Stackup provides some advantages over using awscli or aws-sdk directly:

  • It treats stack changes as synchronous, streaming stack events until the stack reaches a stable state.

  • A Stack#up facade for create/update frees you from having to know whether your stack already exists or not.

  • Changes are (mostly) idempotent: "no-op" operations - e.g. deleting a stack that doesn't exist, or updating without a template change - are handled gracefully (i.e. without error).

Installation

$ gem install stackup

Command-line usage

The entry-point is the "stackup" command.

Most commands operate in the context of a named stack:

$ stackup STACK-NAME ...

Called with --list, it will list stacks:

$ stackup --list
foo-bar-test
zzz-production

Stack create/update

Use sub-command "up" to create or update a stack, as appropriate:

$ stackup myapp-test up -t template.json

This will:

  • update (or create) the named CloudFormation stack, using the specified template
  • monitor events until the stack update is complete

Requests will retry 3 times by default. After this limit is exceeded, ERROR: Rate exceeded failures will be logged. You can increase the limit using the --retry-limit option, or by setting the $AWS_RETRY_LIMIT environment variable.

For more details on usage, see

$ stackup STACK up --help

Specifying parameters

Stack parameters can be be read from a file, e.g.

$ stackup myapp-test up -t template.json -p parameters.json

Parameters can be specified as simple key-value pairs:

{
  "IndexDoc": "index.html"
}

but also supports the extended JSON format used by the AWS CLI:

[
  {
    "ParameterKey": "IndexDoc",
    "ParameterValue": "index.html",
    "UsePreviousValue": false
  }
]

You may specify -p multiple times; stackup will read and merge all the files:

$ stackup myapp-test up -t template.json \
  -p defaults.json \
  -p overrides.json

Or, you can specify one or more override parameters on the command-line, using -o with -p:

$ stackup myapp-test up -t template.json \
  -p defaults.json \
  -o IndexDoc=index-override.html
  -o ContentDoc=content-override.html

YAML support

stackup supports input files (template, parameters, tags) in YAML format, as well as JSON.

It also supports the abbreviated YAML syntax for Cloudformation functions, though unlike the AWS CLI, Stackup normalises YAML input to JSON before invoking CloudFormation APIs.

AWS credentials

The stackup command-line looks for AWS credentials in the standard environment variables.

You can also use the --with-role option to temporarily assume a different IAM role, for stack operations:

$ stackup myapp-test up -t template.json \
  --with-role arn:aws:iam::862905684840:role/deployment

You can use the --service-role-arn option to pass a specific IAM service role for CloudFormation to use for stack operations:

$ stackup myapp-test up -t template.json \
    --service-role-arn arn:aws:iam::862905684840:role/cloudformation-role

(for more information on CloudFormation service roles, see AWS' documentation).

Using URLs as inputs

You can use either local files, or HTTP URLs, to specify inputs; stack template, parameters, etc.

$ stackup mystack up \
  -t https://s3.amazonaws.com/mybucket/stack-template.json

Where a template URL references an object in S3, stackup leverages CloudFormation's native support for such URLs, enabling use of much larger templates.

Non-S3 URLs are also supported, though in that case stackup must fetch the content itself:

$ stackup mystack up \
  -t https://raw.githubusercontent.com/realestate-com-au/stackup/master/examples/template.yml

Stack deletion

Sub-command "delete" deletes the stack.

Stack inspection

Inspect details of a stack with:

$ stackup myapp-test status
$ stackup myapp-test resources
$ stackup myapp-test outputs

Change-set support

You can also create, list, inspect, apply and delete change sets using stackup.

$ stackup myapp-test change-sets
$ stackup myapp-test change-set create -t template.json
$ stackup myapp-test change-set inspect
$ stackup myapp-test change-set apply

The change-set name defaults to "pending", but can be overridden using --name.

Programmatic usage

Get a handle to a Stack object as follows:

stack = Stackup.stack("my-stack")

You can pass an Aws::CloudFormation::Client, or client config, to Stackup, e.g.

stack = Stackup(credentials).stack("my-stack")

See Stackup::Stack for more details.

Rake integration

Stackup integrates with Rake to generate handy tasks for managing a stack, e.g.

require "stackup/rake_tasks"

Stackup::RakeTasks.new("app") do |t|
  t.stack = "my-app"
  t.template = "app-template.json"
end

providing tasks:

rake app:diff       # Show pending changes to my-app stack
rake app:down       # Delete my-app stack
rake app:inspect    # Show my-app stack outputs and resources
rake app:up         # Update my-app stack

Parameters and tags may be specified via files, or as a Hash, e.g.

Stackup::RakeTasks.new("app") do |t|
  t.stack = "my-app"
  t.template = "app-template.json"
  t.parameters = "production-params.json"
  t.tags = { "environment" => "production" }
end

Docker image

Stackup is also published as a Docker image. Basic usage is:

docker run --rm \
    -v "`pwd`:/cwd" \
    -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN \
    -e AWS_DEFAULT_REGION \
    realestate/stackup:latest ...

If you're sensible, you'll replace "latest", with a specific version.

The default working-directory within the container is /cwd; hence the volume mount to make files available from the host system.

IAM Permissions

up

This policy grants the principal all actions required by stackup up for any cloudformation stack:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "cloudformation:CreateStack",
                "cloudformation:DeleteStack",
                "cloudformation:DescribeStackEvents",
                "cloudformation:DescribeStackResource",
                "cloudformation:DescribeStacks",
                "cloudformation:SetStackPolicy",
                "cloudformation:UpdateStack"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

Releasing

The release process will push tags to GitHub, push the gem to rubygems and push the docker image to DockerHub.

Prerequisites:

  • logged into dockerhub via docker login. Your user must have permission to push to realestate/stackup
  • logged into rubygems via gem push. Your user must have permission to push to the stackup gem.

To release:

bundle install
auto/release