cfparams
Wrangle CloudFormation parameters.
Reads expected parameter keys from a CloudFormation template, accepts values
from command line or YAML file, emits JSON suitable for aws cloudformation *-stack --parameters="..."
commands. Supports the use of default and previous
values.
Example use-cases
CloudFormation template excerpt describing an ECS service to be provisioned
onto an existing ECS cluster.
# cfn.yaml excerpt
Parameters:
Greeting:
Type: String
Description: greeting message to send
Default: Hello
Recipient:
Description: name of the greeting recipient
Type: String
ImageRepo:
Type: String
Description: repository of Docker image to run
Default: "123.dkr.ecr.us-east-1.amazonaws.com/greeting"
ImageTag:
Type: String
Description: tag of Docker image to run
Default: latest
Cluster:
Description: ECS cluster ID to run service on
Type: String
Launching the CloudFormation stack for the first time. Accept some defaults
from the template, specify all other parameters.
params="$(
cfparams --template=cfn.yaml --accept-defaults --no-previous \
Recipient=world ImageTag=v1 Cluster=nanoservices
)"
--template
loads supported Parameters from a CloudFormation template.
--accept-defaults
omits keys that have a default in the CloudFormation
template.
--no-previous
means fail if a key has no default in the template and isn't
specified on the command line. Without this option, those keys will be
auto-filled as "UsePreviousValue": true
.
Resulting JSON:
[
{"ParameterKey": "Recipient", "ParameterValue": "world"},
{"ParameterKey": "ImageTag", "ParameterValue": "v1"},
{"ParameterKey": "Cluster", "ParameterValue": "nanoservices"}
]
aws cloudformation create-stack \
--stack-name=greeting \
--template-body=file://cfn.yaml \
--parameters="$params"
Deploying a new version of the app
Deploying a new version of the app, e.g. from CI. Only ImageTag
should
change, all other parameters use previous value.
params="$(cfparams --template=cfn.yaml ImageTag=v2)"
Resulting JSON:
[
{"ParameterKey": "Greeting", "UsePreviousValue": true},
{"ParameterKey": "Recipient", "UsePreviousValue": true},
{"ParameterKey": "ImageRepo", "UsePreviousValue": true},
{"ParameterKey": "ImageTag", "ParameterValue": "v2"},
{"ParameterKey": "Cluster", "UsePreviousValue": true}
]
Update stack:
aws cloudformation update-stack \
--stack-name=greeting \
--use-previous-template \
--parameters="$params"
Changing the stack, for example introducing a FooHost
parameter.
# cfn.yaml excerpt
Parameters:
+ FooHost:
+ Type: String
+ Description: API key to access Foo service
Greeting:
params="$(cfparams --template=cfn-foohost.yaml FooHost=foo.example.com)"
Resulting JSON:
[
{"ParameterKey": "FooHost", "ParameterValue": "foo.example.com"},
{"ParameterKey": "Greeting", "UsePreviousValue": true},
{"ParameterKey": "Recipient", "UsePreviousValue": true},
{"ParameterKey": "ImageRepo", "UsePreviousValue": true},
{"ParameterKey": "ImageTag", "UsePreviousValue": true},
{"ParameterKey": "Cluster", "UsePreviousValue": true}
]
name="greeting-update-$(date +%Y%m%d-%H%M%S)"
aws cloudformation create-change-set \
--stack-name=greeting \
--change-set-name="$name" \
--use-previous-template \
--parameters="$(cfparams --template=cfn.yaml FooHost=foo.example.com)"
# review Change Set here
aws cloudformation execute-change-set \
--stack-name=greeting \
--change-set-name="$name"
Introducing version-controlled parameters files
Now we introduce some version-controlled files to the subset of parameters that
make sense to exist in the codebase. ImageTag
is not included in this file.
# parameters-staging.yaml
FooHost: foo.local
Greeting: Howdy
Recipient: team
Cluster: staging
# parameters-production.yaml
FooHost: foo.example.com
Greeting: Hello
Recipient: world
Cluster: production
params="$(
cfparams --template=cfn-foohost.yaml --parameters=parameters-staging.yaml \
ImageTag=v3 Greeting=Bonjour
)
Resulting JSON:
[
{"ParameterKey": "FooHost", "ParameterValue": "foo.local"},
{"ParameterKey": "Greeting", "ParameterValue": "Howdy"},
{"ParameterKey": "Recipient", "ParameterValue": "team"},
{"ParameterKey": "ImageRepo", "UsePreviousValue": true},
{"ParameterKey": "ImageTag", "ParameterValue": "v3"},
{"ParameterKey": "Cluster", "ParameterValue": "staging"}
]
CloudFormation stacks can be tagged, and those tags flow into all taggable
resources the stack creates. As with --parameters
, the aws cloudformation
commands expect these in an awkward format. cfparams --tags file.yaml
helps.
aws cloudformation create-stack \
... \
--tags "$(cfparams --tags=tags-production.yaml)" \
...
# tags-production.yaml
Name: Widgets as a Service
asset: widget-api
workload: production
cfparams --tags=tags-production.yaml
[
{
"Key": "Name",
"Value": "Widgets as a Service"
},
{
"Key": "asset",
"Value": "widget-api"
},
{
"Key": "workload",
"Value": "production"
}
]