AwsAsCode
This gem is built upon a great cfndsl CloudFormation DSL language in order to automate routine tasks related to CF stack updates:
- compilation of multiple associated templates;
- a sensible convention around the way compiled templates are uploaded and stored on S3;
- a simple wrapper around AWS SDK allowing you to apply stack changes immediately after they have been compiled and uploaded to S3.
This gem provides a command-line utility; normally you don't need to use it as a library.
Installation
Add this line to your application's Gemfile:
gem 'aws_as_code'
And then execute:
$ bundle
Or install it yourself as:
$ gem install aws_as_code
Usage
bundle exec aws-as-code [command] [option...]
Commands
create
Processes (compiles and uploads) CF templates and attempts to create a new stack using them.
bundle exec aws-as-code create \
--bucket=projectname-prod-cloudformation \
--version="$VERSION" \
--stack-params=ApiKey:KEY ApiSecret:SECRET
update
Processes (compiles and uploads) CF templates and applies changes to an existing stack (keeping all existing stack parameters which are not explicitly overridden in the command line)
bundle exec aws-as-code update \
--bucket=projectname-prod-cloudformation \
--version="$VERSION" \
--stack-params=ApiSecret:NEWSECRET
compile
Compiles CF templates from ruby-dir
using configuration from
config-dir
and stores them locally in json-dir
bundle exec aws-as-code compile \
--bucket=projectname-prod-cloudformation \
--version="$VERSION"
Mainly used for debugging purposes.
upload
Uploads CF templates from json-dir
to bucket
on S3.
bundle exec aws-as-code upload \
--bucket=projectname-prod-cloudformation \
--version="$VERSION"
Mainly used for debugging purposes
do-update
Applies changes to the existing stack using currently uploaded templates.
bundle exec aws-as-code do-update \
--bucket=projectname-prod-cloudformation \
--version="$VERSION"
Mainly used for debugging purposes
do-create
Creates a new stack using templates already uploaded to S3
bundle exec aws-as-code do-create \
--bucket=projectname-prod-cloudformation \
--version="$VERSION"
Mainly used for debugging purposes
Options
--config-dir
Directory with configuration files.
Default value: cfn
--ruby-dir
Directory with CloudFormation templates written in Ruby DSL
Default value: cfn
--json-dir
Directory to put compiled JSON CF templates to
Default value: cfn-compiled
--bucket
S3 bucket used to store compiled templates.
Required
--template
Filename of the stack root template.
Default value: environment
--stack
Name of the stack to create or update (also used as a part of the uploaded template name to help distinguish stack templates compiled from the same source but using different configurations)
Default value: master
--stack-params
A list of stack parameters in the key-value form.
--stack-params=ApiKey:KEY ApiSecret:SECRET
Optional. If not provided for update
task, all parameters will be
kept as-is. If not provided for create
task, no parameters will be
passed to the stack (if stack requires any parameters, then stack
creation will fail).
--version
Stack definition version. If you're using a version system, it's highly recommended to use the latest commit hash as a version.
Required
Configuration files
aws-as-code
expects to find two configuration files in config-dir
:
- parameters.yml
- settings.yml
parameters.yml
Contains the list of stack parameters configurable through the CloudFormation AWS console.
Format:
<PARAMETER NAME>:
Type: "String" | "Number" | "CommaDelimitedList"
Default: <DEFAULT VALUE>
_ext:
env: <ENVIRONMENT VARIABLE NAME>
services: <LIST OF SERVICE NAMES THIS PARAMETER IS PASSED TO>
Example:
GoogleAnalyticsId:
Type: String
Default: UA-66947010-2
_ext:
env: GOOGLE_ANALYTICS_ID
services:
- web
MailerUrl:
Type: String
Default: test://localhost
_ext:
secure: true
env: MAILER_URL
services:
- web
- queue
Keep in mind that AWS has a
hard cap of 60 parameters
available to your stack. If a value is not sensitive and doesn't need to be
reconfigured on the fly, consider using settings.yml
instead!
From the example above, GoogleAnalyticsId
can be moved to
settings.yml
, while MailerUrl
cannot, as it contains some
sensitive information such as SMTP username and password.
settings.yml
Contains the list of non-sensitive environment-specific settings
Settings can be referenced from the tempalte definition using the
setting('<SETTING NAME>')
DSL extension
Format:
<SETTING NAME>:
<STACK NAME>: <VALUE>
<STACK NAME>: <VALUE>
_default: <DEFAULT VALUE>
Example:
es_instance_type:
master: t2.small.elasticsearch
_default: t2.small.elasticsearch
es_instance_count:
master: 2
_default: 1
web_tasks_count:
master: 4
_default: 1
DSL extensions
env_ebs_options(env = nil)
Generates a list of ElasticBeanstalk confugration options passing the list of stack parameters to the ElasticBeanstalk environment.
Example:
ElasticBeanstalk_Environment "Service" do
Description "Sample app"
ApplicationName Ref "Application"
VersionLabel Ref "CurrentVersion"
OptionSettings [
{
Namespace: "aws:elasticbeanstalk:environment",
OptionName: "EnvironmentType",
Value: "SingleInstance"
}
] + env_ebs_options("web")
SolutionStackName "SOLUTION"
end
env_passthrough(env = nil)
Generates a list of stack parameters passing the list input parameters specific
to a selected environment env
to a nested stack.
Example:
CloudFormation_Stack "Services" do
Parameters Hash[
VPC: FnGetAtt("Network", "Outputs.VPC"),
].merge(env_passthrough)
TemplateURL template_url "services"
TimeoutInMinutes 20
end
inputs(env = nil)
Generates a list of stack input declarations for the environment env
.
Example:
CloudFormation do
inputs("web")
Parameter "SubnetA" do
String()
end
...
params(env = nil)
Returns a list of parameters for environment env
setting(key)
Returns the value of the setting key
from settings.yml
Example:
Resource "Lambda" do
Type "AWS::Lambda::Function"
Property "Description", "Sample lambda"
Property "Handler", "main.handler"
Property "Code",
S3Bucket: setting("lambda_source"),
S3Key: FnJoin(
"",
[
"lambda/", ENV["VERSION"], ".zip"
]
)
Property "Runtime", "nodejs6.10"
Property "Timeout", "3"
Property "Role", setting("role")
end
template_url
Returns a full S3 URL (including dynamically generated version) of another template.
Example:
CloudFormation do
inputs
CloudFormation_Stack "Network" do
TemplateURL template_url "network"
TimeoutInMinutes 10
end
end
Examples
Deploying stack changes from CircleCI
Assuming that AWS credentials (secret, key and default region) are available in the build environment and this user has all the required permissions to perform the required stack updates.
circle.yml
deployment:
production:
branch: master
commands:
- >
bundle exec aws-as-code update \
--template=environment \
--config-dir=core \
--ruby-dir=core/cfn \
--json-dir=tmp/cfn \
--bucket=projectname-prod-cloudformation \
--stack="$CIRCLE_BRANCH" \
--version="$CIRCLE_SHA1"