condensation
Version:
Package, reuse and share particles for CloudFormation projects
624 lines (417 loc) • 19.1 kB
Markdown
# condensation
Package, reuse and share particles for CloudFormation projects
![condensation][condensation-image]
[![NPM][npm-image]][npm-url]
[![Gitter][gitter-image]][gitter-url]
[![Build Status][travis-image]][travis-url]
[![Code Climate][codeclimate-image]][codeclimate-url]
[![Coverage Status][coveralls-image]][coveralls-url]
[![Dependency Status][daviddm-image]][daviddm-url]
## Summary
Condensation uses [gulp](http://gulpjs.com) to generate tasks that
compile, package and upload [AWS CloudFormation](http://aws.amazon.com/cloudformation/)
templates and supporting assets as distributions.
Any file with the extension `.hbs` will be compiled with
[Handlebars.js](http://handlebarsjs.com/) to support
partials, helpers and variable replacement.
## Quick Start
### With Docker
The fastest way to get started with condensation: [docker-condensation][docker-condensation-url]
```
$ alias condensation="docker run -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY -e AWS_SESSION_TOKEN -v \"$HOME\"/.aws/credentials:/home/condensation/.aws/credentials -v \`pwd\`:/particles --rm sungardas/condensation"
$ condensation create project particles-MYPROJECT
$ cd particles-MYPROJECT
$ condensation run build
```
### With a nodejs environment
Use the Yeoman
[generator](https://github.com/SungardAS/generator-condensation).
```
$ npm install -g yo
$ npm install -g generator-condensation
$ yo condensation:project particles-MYPROJECT
$ cd particles-MYPROJECT
$ npm run build
```
### Example Projects
* [condensation-examples](https://github.com/SungardAS/condensation-examples)
* [particles-vpc](https://github.com/SungardAS/particles-vpc)
* [particles-cloudsploit-scans](https://github.com/SungardAS/particles-cloudsploit-scans)
* [particles-enhanced-snapshots](https://github.com/SungardAS/particles-enhanced-snapshots)
Check out the growing list of particles on
[npm](https://www.npmjs.com/browse/keyword/condensation-particles)!
## Features
* Write reusable CloudFormation snippets, called `particles` that can be used
accross condensation projets
* Package templates and assets then upload full distributions to multiple buckets across
regions with one command.
* Reference another template within the distribution with
[AWS::CloudFormation::Stack](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-stack.html)
and the `templateS3Url` helper
* Upload scripts, configuration files and other assets alongside
CloudFormation templates and reference them with asset helpers.
## Why?
CloudFormation templates are great for creating, updating and deleting
AWS resources. Reusing parts of templates, referencing other
templates with `AWS::CloudFormation::Stack` and deploying cloud-init
scripts can be difficult to manage.
* Sections such as AMI [mappings](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/mappings-section-structure.html)
are often re-used by many templates. Particles provide a way to
write the mapping once and reuse it in other templates by reference.
* It is common to set up resources, such as a VPC, with nearly
identical attributes and structure for different applications and
services. Condensation allows that definition to become a independent
stack that can be referenced by other templates that are part of the
same distribution.
* When bootstrapping ec2 instances it is beneficial to have versioned scripts and configuration
files deployed in the same bucket and path as the CloudFormation template
they are associated with.
* When using `AWS::CloudFormation::Authentication` to download assets from
S3 buckets all resources must be in the same region. Condensation
makes it easy to deploy the same templates and assets to multiple
regions and ensure the referencing URLs are always pointing to the
right place.
For example, templates in a distribution can reference one another based on the
bucket they are deployed to.
Example:
"TemplateURL": "{{templateS3Url 'vpc.template' }}"
...
"TemplateURL": "{{templateS3Url 'subnet.template' }}"
Output:
"TemplateURL": "https://s3-us-west-1.amazonaws.com/<BUCKET>/cftemplates/vpc.template"
...
"TemplateURL": "https://s3-us-west-1.amazonaws.com/<BUCKET>/cftemplates/subnet.template"
The Handlebars helper, `templateS3Url`, creates a URL that will always reference a template deployed within the same bucket.
## Use
### Project Structure
particles-my-project
|
-- guplfile.js
|
-- README.md
|
-- CHANGELOG.md
|
--particles
|
-- assets
|
-- conditions
|
-- cftemplates
|
-- helpers
|
-- mappings
|
-- metadata
|
-- outputs
|
-- parameters
|
-- resources
|
-- sets
|
-- partials
Condensation builds templates with Handlebars helpers that
are able to load particles from the local project
or from any condensation compatible module added as a npm
dependency.
All helpers follow the same pattern:
{{<CONDENSATION-HELPER> [module:<MODULE>] '<PATH_TO_PARTICLE>' [OPTIONS...]}}
When including the particles from another project *MODULE* is the name
of the npm dependency.
**New in 0.5.0**
Use `m` instead of `module` if referencing a module that
starts with `particles-` to minimize characters used. The `m` option
will add `particles-` to the beginning of \<MODULE\> for you.
{{<CONDENSATION-HELPER> [m:<MODULE>] '<PATH_TO_PARTICLE>' [OPTIONS...]}}
Example, load a particle from `particles-core`
{{parameter "m:core" "base" logicalId="Parameter1"}}
#### Lazy Loading
Particles will only be included in the final distribution if they are
referenced in a `hbs` file.
### layout support
**New in 0.3.0**
Instead of including particles within a traditional CloudFormation
template the introduction of a layout supports capturing helper output
and adding it to the correct section. Helpers within a layout do not
have to to be in any specific order.
---
things:
-
name: subnet1
cidr: "10.0.0.0/24"
-
name subnet2
cidr: "10.0.1.0/24"
---
{{#layout templateDescription="condensation rocks!"}}
{{parameter 'my_parameter' logicalId="MyParameter"}}
{{condition 'my_condition' logicalId="MyCondition"}}
{{! helpers can occur in any order, allowing you to group related section parts together }}
{{#each things}}
{{parameter 'repeate_me' logicalId="RepeateMe" logicalIdSuffix=@index}}
{{condition 'repeate_me' logicalId="RepeateMeCond" logicalIdSuffix=@index}}
{{resource 'repeate_me' logicalId="RepeateMeResource" logicalIdSuffix=@index}}
{{output 'repeate_me' logicalId="RepeateMeOutput" logicalIdSuffix=@index}}
{{/each}}
{{/layout}}
#### assets
Files to be uploaded to S3 that are used to supplement CloudFormation
templates. Files can include bootsrap scripts, packaged install files
or configuration files.
Any file with a `.hbs` extension will be
compiled with handlebars and saved to S3. The `.hbs` extension will be
removed from the filename.
Asset URLs can be built with the `assetS3Url` helper:
{{assetS3Url 'my-asset' [protocol=https|s3]}}
{{assetS3Url 'module:<MODULE>' 'module-asset' [protocol=https|s3]}}
Parameters:
**protocol** *optional* https|s3 - Forces the protocol of the url to https:// or s3://
Example Output:
"https://s3-us-west-1.amazonaws.com/BUCKET/assets/my-asset"
"https://s3-us-west-1.amazonaws.com/BUCKET/node_modules/MODULE/particles/assets/module-asset"
Asset paths (the full key path as it will be in the s3 bucket) can be built with the `assetPath` helper:
{{assetPath 'my-asset'}}
{{assetPath 'module:<MODULE>' 'module-asset' }}
Example Output:
"/assets/my-asset"
"/node_modules/MODULE/particles/assets/module-asset"
For both assetS3Url and assetPath the particle path will match the name of the asset without the `.hbs` extension, if it exists.
To include assets that are not directly referenced from a template
use the `requireAssets` helper. It will ensure a glob of assets are
included in the distribution.
{{requireAssets '/**'}}
{{requireAssets 'module:<MODULE>' '/**'}}
`requireAssets` will not produce output, only ensure that the glob is
uploaded to S3.
#### conditions
Contents of files will be loaded as conditions that can be used in
in a traditional template or a `layout` (**recommended**)
Directory: `conditions`
Helper: `condition`
{{condition 'my-condition' logicalId="MyCond"}}
{{condition 'module:<MODULE>' 'condition-name' logicalId="TheirCond"}}
The particle path can match the base name of the file or the base name
plus any extensions.
#### cftemplates
CloudFormation templates that will be uploaded to S3.
Any file with a `.hbs` extension will be compiled with
handlebars and saved to S3 without the `.hbs` extension.
Template URLs can be built with the `assetS3Url` helper:
{{templateS3Url 'my.template'}}
{{templateS3Url 'module:<MODULE>' 'module.template'}}
The particle path should match the name of the template without the `.hbs` extension, if it exists.
Example Output:
"https://s3-us-west-1.amazonaws.com/BUCKET/cftemplates/my.template"
"https://s3-us-west-1.amazonaws.com/BUCKET/node_modules/MODULE/particles/cftemplates/module.template"
#### helpers
Node modules that export a function that is built as a
Handlebars [block helper](http://handlebarsjs.com/block_helpers.html).
Helpers are called with the `helper` helper:
{{helper 'my-helper'}}
{{helper 'module:<MODULE>' 'module-helper'}}
The particle path should match the name of the helper without the `.js` extension.
#### mappings
Contents of files will be loaded as mappings that can be used in
in a traditional template or a `layout` (**recommended**)
Directory: `mappings`
Helper: `mapping`
{{mapping 'my-mapping' logicalId="MyMapping"}}
{{mapping 'module:<MODULE>' 'mapping-name' logicalId="TheirMapping"}}
The particle path can match the base name of the file or the base name
plus any extensions.
#### metadata
Contents of files will be loaded as metadata that can be used in
in a traditional template or a `layout` (**recommended**)
Directory: `metadata`
Helper: `metadata`
{{metadata 'my-metadata' logicalId="MyMetadata"}}
{{metadata 'module:<MODULE>' 'metadata-name' logicalId="TheirMetadata"}}
The particle path can match the base name of the file or the base name
plus any extensions.
#### outputs
Contents of files will be loaded as outputs that can be used in
in a traditional template or a `layout` (**recommended**)
Directory: `outputs`
Helper: `output`
{{output 'my-output' logicalId="MyOutput"}}
{{output 'module:<MODULE>' 'output-name' logicalId="TheirOutput"}}
The particle path can match the base name of the file or the base name
plus any extensions.
#### parameters
Contents of files will be loaded as parameters that can be used in
in a traditional template or a `layout` (**recommended**)
Directory: `parameters`
Helper: `parameter`
{{parameter 'my-output' logicalId="MyParameter"}}
{{parameter 'module:<MODULE>' 'parameter-name' logicalId="TheirParameter"}}
The particle path can match the base name of the file or the base name
plus any extensions.
#### partials
Contents of files here will be loaded as partials that can be used in
`assets` and `cftemplates`.
These files will not be packaged or uploaded to S3.
Partials can be loaded with the `partial` helper:
{{partial 'my-partial'}}
{{partial 'module:<MODULE>' 'module-partial'}}
The particle path only needs to match the base name of the partial.
A path of `some_partial` would match `some_partial.json` or `some_partial.json.hbs`.
If the desired partial is not being loaded ensure precedence is given to an exact match.
#### resources
Contents of files will be loaded as resources that can be used in
in a traditional template or a `layout` (**recommended**)
Directory: `resources`
Helper: `resource`
{{resource 'my-output' logicalId="MyResource"}}
{{resource 'module:<MODULE>' 'resource-name' logicalId="TheirResource"}}
The particle path can match the base name of the file or the base name
plus any extensions.
#### sets
Intended for use with `layout`
A grouping of section definitions that will always be generated
together. Most commonly used to generate parameters with corresponding
conditions.
Directory: `sets`
Helper: `set`
{{set 'my-set' logicalId="MySet"}}
{{set 'module:<MODULE>' 'set-name' logicalId="TheirSet"}}
The particle path can match the base name of the file or the base name
plus any extensions.
##### Scoping
Sets can be repeated multiple times in a template. Sets can also be
embedded within other sets. To help with namespacing a set can be
scoped with a `logicalIdPrefix` and/or a 'logicalIdSuffix`. These
values will be apporperiately added to and logicalIds within the set.
To reference a logicalId within a scoped set use the `scopeId` and `ref`
handlebars helpers provided by condensation.
{{!-- sets/my_set.hbs --}}
{{parameter "cidr" logicalId="Cidr"}}
{{resource "subnet" logicalId="Subnet" cidr=(ref "cidr")}}
---
{{!-- cftemplates/my_template.template.json.hbs --}}
{{set "my_set" logicalIdSuffix="1"}}
{{set "my_set" logicalIdSuffix="2"}}
The definition above would produce two parameters, `Cidr1` and `Cidr2`, and
two resources, `Subnet1` and `Subnet2`. Each subnet will reference
their respective Cidr parameter.
### Tasks
Get a full list of tasks by running `gulp -T`
By default all tasks are prefixed with `condensation:`. This can be
changed with the `taskPrefix` config option.
#### Default
The `default` task is an alias for `build`. It will prepare all files
for deployment to s3. Templates and assets are written to the configured
`dist` directory.
> gulp condensation:default
#### condensation:s3:list
Will list all the configured s3 buckets and module corresponding ID.
> gulp condensation:s3:list
[10:21:47] Using gulpfile ~/condensation-example/gulpfile.js
[10:21:47] Starting 'condensation:s3:list'...
0: a.bucket.in.us-east-1
1: a.bucket.in.us-west-2
[10:21:47] Finished 'condensation:s3:list' after 153 μs
The IDs can be used to deploy to a single bucket instead of all buckets.
#### condensation:deploy
For the `deploy` task to run AWS credentials must be set as environment
variables: `AWS_SECRET_ACCESS_KEY` and `AWS_ACCESS_KEY_ID`
> AWS_SECRET_ACCESS_KEY=XXXX AWS_ACCESS_KEY_ID=XXXX gulp deploy
This will upload templates to all cofigured S3 buckets.
#### condensation:deploy:ID
Deploy templates to a specific S3 bucket.
#### condensation:deploy:LABEL
Deploy templates to all S3 buckets that contain the label, LABEL.
## Config Options
var config = {
// Array of S3 buckets to deploy to
s3: [
{
// AWS specific options
aws: {
region: 'us-east-1',
bucket: 'my.bucket.in.us-east-1',
},
// Run CloudFormation validation during the build task for this bucket
validate: true,
// Create this bucket if it does not already exist
create: true
// Prefix all objects (allows for multiple deployments to the same bucket
prefix: '',
labels: ['east']
},
],
// The prefix to add to all generated gulp tasks (default: 'condensation')
// An empty string will remove the prefix
// - condensation:deploy will become deploy
taskPrefix: '',
// Directory that contains the `particles` directory.
// Used for test scripts, should not be changed if sharing templates
root: './',
// Where the build task will put the distribution
dist: 'dist'
};
## Condensation Helpers
### ref
Build a reference to a logicalId. By default `ref` will return a
logicalId in relation to it's scope adding any logicalIdPrefix and/or
logicalIdSuffix as necessary. This can be turned off by setting `scope`
to `false`.
{{ref 'MyParameter'}}
{{ref 'MyParameter' scope=false}}
### scopeId
Return a logicalId based on it's current scope. Will add any
logicalIdPrefix and/or logicalIdSuffix that is defined.
{{scopeId 'MyParameter'}}
## Handlebars Helpers
Aside from the helpers to load particles, condensation provides the
following generic handlebars helpers.
### concat
Concatenate strings
{{concat 'one' 'two'}}
{{#parameter logicalId=(concat 'myPrefix' myStrVar)}}
## Front Matter
All `cftemplates` and `partials` are first processed with
[gray-matter](https://github.com/jonschlinkert/gray-matter) to load any
default data definitions.
## Errors
Errors due to badly formed JSON or failed CF validations will stop the
process and the offending files will be dumped to `condensation_errors`
## Experimental
### condensation.js
If a project contains `condensation.js` the file will be loaded as a
module and will attement to run the `initialize` function providing a
callback as the only parameter.
This can be used by particle project to bootstrap any necessary assets
before any template compiling begins.
Example:
[particles-cloudsploit-scans](https://github.com/SungardAS/particles-cloudsploit-scans)
## Acknowledgements
Big thank-you to [Brent Stees](https://github.com/bstees) for creating
the condensation logo!
## Sungard Availability Services | Labs
[![Sungard Availability Services | Labs][labs-logo]][labs-github-url]
This project is maintained by the Labs team at [Sungard Availability
Services](http://sungardas.com)
GitHub: [https://sungardas.github.io](https://sungardas.github.io)
Blog:
[http://blog.sungardas.com/CTOLabs/](http://blog.sungardas.com/CTOLabs/)
[codeclimate-image]: https://codeclimate.com/github/SungardAS/condensation/badges/gpa.svg
[codeclimate-url]: https://codeclimate.com/github/SungardAS/condensation
[condensation-image]: ./docs/images/condensation_logo.png?raw=true
[coveralls-image]: https://coveralls.io/repos/SungardAS/condensation/badge.svg
[coveralls-url]: https://coveralls.io/r/SungardAS/condensation
[docker-condensation-url]: https://github.com/SungardAS/docker-condensation
[daviddm-image]: https://david-dm.org/SungardAS/condensation.svg?theme=shields.io
[daviddm-url]: https://david-dm.org/SungardAS/condensation
[gitter-image]: https://badges.gitter.im/Join%20Chat.svg
[gitter-url]: https://gitter.im/SungardAS/condensation?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge
[labs-github-url]: https://sungardas.github.io
[labs-logo]: https://raw.githubusercontent.com/SungardAS/repo-assets/master/images/logos/sungardas-labs-logo-small.png
[npm-image]: https://badge.fury.io/js/condensation.svg
[npm-url]: https://npmjs.org/package/condensation
[travis-image]: https://travis-ci.org/SungardAS/condensation.svg?branch=master
[travis-url]: https://travis-ci.org/SungardAS/condensation