cumuliform 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +152 -6
- data/Rakefile +9 -0
- data/examples/Rakefile +6 -0
- data/examples/simplest.rb +19 -0
- data/exe/cumuliform +5 -0
- data/lib/cumuliform/rake_task.rb +23 -0
- data/lib/cumuliform/runner.rb +21 -0
- data/lib/cumuliform/version.rb +1 -1
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dc898679239945b8548cd8b35fac0135ca1c07d4
|
4
|
+
data.tar.gz: 5e5996b0de7f64ba2deb495dcf306374af28947c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1de59e26464fb7370af9cdac344ba606ababdc27ec608d0324cf976352c4eded31b1e78731d4ed40c4282029deb0f3b15b3e42a96e70d9c06bb782c310100a9
|
7
|
+
data.tar.gz: 5511163114e278987878e18844961a03fd8223fb6e20d328bc1653a194c87f3955ec9b5f74257b49f4fbfcb0561a91adecc0fddebe7fac956d07176bc92c0f3a
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,24 @@
|
|
2
2
|
|
3
3
|
[![Build Status](https://travis-ci.org/tape-tv/cumuliform.svg?branch=master)](https://travis-ci.org/tape-tv/cumuliform) [![Code Climate](https://codeclimate.com/github/tape-tv/cumuliform/badges/gpa.svg)](https://codeclimate.com/github/tape-tv/cumuliform) [![Test Coverage](https://codeclimate.com/github/tape-tv/cumuliform/badges/coverage.svg)](https://codeclimate.com/github/tape-tv/cumuliform/coverage)
|
4
4
|
|
5
|
-
|
5
|
+
Amazon’s [CloudFormation AWS service][cf] provides a way to describe
|
6
|
+
infrastructure stacks using a JSON template. We love CloudFormation, and use it
|
7
|
+
a lot, but the JSON templates are hard to write and read, it's very hard to
|
8
|
+
reuse things shared between stacks, and it's very easy to make simple typos
|
9
|
+
which are not discovered until minutes into stack creation when things fail for
|
10
|
+
seemingly crazy reasons.
|
11
|
+
|
12
|
+
[cf]: http://aws.amazon.com/cloudformation/
|
13
|
+
|
14
|
+
Cumuliform is a tool to help eliminate as many sources of reference errors as
|
15
|
+
possible, and to allow easier reuse of template parts between stacks. It
|
16
|
+
provides a simple DSL that generates reliably valid JSON and enforces
|
17
|
+
referential integrity through convenience wrappers around the common points
|
18
|
+
where CloudFormation expects references between resources. provides.
|
19
|
+
|
20
|
+
Cumuliform has been extracted from ops and deployment code at [tape.tv][tape]
|
21
|
+
|
22
|
+
[tape]: https://www.tape.tv/
|
6
23
|
|
7
24
|
## Installation
|
8
25
|
|
@@ -20,15 +37,144 @@ Or install it yourself as:
|
|
20
37
|
|
21
38
|
$ gem install cumuliform
|
22
39
|
|
23
|
-
|
40
|
+
# Getting started
|
41
|
+
|
42
|
+
You’ll probably want to familiarise yourself with the [CloudFormation getting
|
43
|
+
started guide][cf-get-started] if you haven’t already.
|
44
|
+
|
45
|
+
[cf-get-started]: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/GettingStarted.html
|
46
|
+
|
47
|
+
To quickly recap the key points for template authors:
|
48
|
+
|
49
|
+
1. A template is a JSON file containing a single Object (`{}`)
|
50
|
+
2. The template object is split into specific sections through top-level
|
51
|
+
properties (resources, parameters, mappings, and outputs).
|
52
|
+
3. The things we’re actually interested in are object children of those
|
53
|
+
top-level objects, and the keys (‘logical IDs’ in CloudFormation terms) must
|
54
|
+
be unique across each of the four sections.
|
55
|
+
4. Resources, parameters, and the like are just JSON Objects.
|
56
|
+
5. CloudFormation provides what it calls ‘Intrinsic Functions’, e.g. `Fn::Ref`
|
57
|
+
to define links and dependencies between your resources.
|
58
|
+
6. Because a template is just a JSON object, it’s very easy to accidentally
|
59
|
+
define a resource or parameter with the same logical id more than once, which
|
60
|
+
results in a last-one-wins situation where the object defined latest in the
|
61
|
+
file will obliterate the previously defined one.
|
62
|
+
|
63
|
+
Cumuliform provides DSL methods to define objects in each of the four sections,
|
64
|
+
helps catch any duplicate logical IDs and provides wrappers for CloudFormation’s
|
65
|
+
Intrinsic Functions that enforce referential integrity *before* you upload your
|
66
|
+
template and start creating a stack with it.
|
67
|
+
|
68
|
+
## The simplest possible template
|
69
|
+
|
70
|
+
Let’s define a very simple template consisting of one resource and one parameter
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
Cumuliform.template do
|
74
|
+
parameter 'AMI' do
|
75
|
+
{
|
76
|
+
Description: 'The AMI id for our template (defaults to the stock Ubuntu 14.04 image in eu-central-1)',
|
77
|
+
Type: 'String',
|
78
|
+
Default: 'ami-accff2b1'
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
82
|
+
resource 'MyInstance' do
|
83
|
+
{
|
84
|
+
Type: 'AWS::EC2::Instance',
|
85
|
+
Properties: {
|
86
|
+
ImageId: ref('AMI'),
|
87
|
+
InstanceType: 'm3.medium'
|
88
|
+
}
|
89
|
+
}
|
90
|
+
end
|
91
|
+
end
|
92
|
+
```
|
93
|
+
|
94
|
+
Processing the ruby source with cumuliform's command line runner gives us this JSON template:
|
95
|
+
|
96
|
+
```sh
|
97
|
+
$ cumuliform simplest.rb simplest.cform
|
98
|
+
```
|
99
|
+
|
100
|
+
```json
|
101
|
+
{
|
102
|
+
"Parameters": {
|
103
|
+
"AMI": {
|
104
|
+
"Description": "The AMI id for our template (defaults to the stock Ubuntu 14.04 image in eu-central-1)",
|
105
|
+
"Type": "String",
|
106
|
+
"Default": "ami-accff2b1"
|
107
|
+
}
|
108
|
+
},
|
109
|
+
"Resources": {
|
110
|
+
"MyInstance": {
|
111
|
+
"Type": "AWS::EC2::Instance",
|
112
|
+
"Properties": {
|
113
|
+
"ImageId": {
|
114
|
+
"Ref": "AMI"
|
115
|
+
},
|
116
|
+
"InstanceType": "m3.medium"
|
117
|
+
}
|
118
|
+
}
|
119
|
+
}
|
120
|
+
}
|
121
|
+
```
|
122
|
+
|
123
|
+
# Rake tasks and the Command Line runner
|
24
124
|
|
25
|
-
|
125
|
+
Cumuliform provides a very simple command-line runner to turn a `.rb` template
|
126
|
+
into JSON:
|
127
|
+
|
128
|
+
```sh
|
129
|
+
$ cumuliform /path/to/input_template.rb /path/to/output_template.json
|
130
|
+
```
|
131
|
+
|
132
|
+
It also provides a Rake task generator to create a Rake `rule` task to turn
|
133
|
+
`x.rb` into `x.cform`:
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
require 'cumuliform/rake_task'
|
137
|
+
|
138
|
+
Cumuliform::RakeTask.rule '.cform' => '.rb'
|
139
|
+
```
|
140
|
+
|
141
|
+
To transform `filename.rb` into `filename.cform`:
|
142
|
+
|
143
|
+
```sh
|
144
|
+
$ rake filename.cform
|
145
|
+
```
|
146
|
+
|
147
|
+
If you haven't used Rake's `rule` tasks before, this [Rake rules article from
|
148
|
+
Avdi Grimm][rules] is a good place to start.
|
149
|
+
|
150
|
+
[rules]: http://devblog.avdi.org/2014/04/23/rake-part-3-rules/
|
151
|
+
|
152
|
+
You'll almost certainly want something more sophisticated than that. Here's an
|
153
|
+
example that declares the standard rule and adds a `FileList` to list the
|
154
|
+
targets (CloudFormation templates you want to generate) based on your sources
|
155
|
+
(Ruby Cumuliform template files). `rake cform` will transform all `.rb` files
|
156
|
+
in the same dir as your `Rakefile` into the corresponding `.cform` files:
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
require 'cumuliform/rake_task'
|
160
|
+
|
161
|
+
Cumuliform::RakeTask.rule '.cform' => '.rb'
|
162
|
+
|
163
|
+
TARGETS = Rake::FileList['*.rb'].ext('.cform')
|
164
|
+
|
165
|
+
task :cform => TARGETS
|
166
|
+
```
|
26
167
|
|
27
|
-
|
168
|
+
# Development
|
28
169
|
|
29
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
170
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
171
|
+
`bin/console` for an interactive prompt that will allow you to experiment.
|
30
172
|
|
31
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To
|
173
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To
|
174
|
+
release a new version, update the version number in `version.rb`, and then run
|
175
|
+
`bundle exec rake release` to create a git tag for the version, push git
|
176
|
+
commits and tags, and push the `.gem` file to
|
177
|
+
[rubygems.org](https://rubygems.org).
|
32
178
|
|
33
179
|
## Contributing
|
34
180
|
|
data/Rakefile
CHANGED
@@ -6,3 +6,12 @@ begin
|
|
6
6
|
rescue LoadError
|
7
7
|
end
|
8
8
|
|
9
|
+
EXAMPLES = Rake::FileList.new('examples/**/*.rb')
|
10
|
+
EXAMPLE_TARGETS = EXAMPLES.ext('.cform')
|
11
|
+
|
12
|
+
$:.unshift(File.expand_path('../lib', __FILE__))
|
13
|
+
require 'cumuliform/rake_task'
|
14
|
+
|
15
|
+
Cumuliform::RakeTask.rule(".cform" => ".rb")
|
16
|
+
|
17
|
+
task :examples => EXAMPLE_TARGETS
|
data/examples/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Cumuliform.template do
|
2
|
+
parameter 'AMI' do
|
3
|
+
{
|
4
|
+
Description: 'The AMI id for our template (defaults to the stock Ubuntu 14.04 image in eu-central-1)',
|
5
|
+
Type: 'String',
|
6
|
+
Default: 'ami-accff2b1'
|
7
|
+
}
|
8
|
+
end
|
9
|
+
|
10
|
+
resource 'MyInstance' do
|
11
|
+
{
|
12
|
+
Type: 'AWS::EC2::Instance',
|
13
|
+
Properties: {
|
14
|
+
ImageId: ref('AMI'),
|
15
|
+
InstanceType: 'm3.medium'
|
16
|
+
}
|
17
|
+
}
|
18
|
+
end
|
19
|
+
end
|
data/exe/cumuliform
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'cumuliform/runner'
|
2
|
+
|
3
|
+
module Cumuliform
|
4
|
+
module RakeTask
|
5
|
+
extend self
|
6
|
+
|
7
|
+
class TaskLib < Rake::TaskLib
|
8
|
+
include ::Rake::DSL if defined?(::Rake::DSL)
|
9
|
+
|
10
|
+
def define_rule(rule_args)
|
11
|
+
task_body = ->(t, args) {
|
12
|
+
Cumuliform::Runner.process(t.source, t.name)
|
13
|
+
}
|
14
|
+
|
15
|
+
rule(*rule_args, &task_body)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def rule(*args)
|
20
|
+
TaskLib.new.define_rule(args)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'cumuliform'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
module Cumuliform
|
5
|
+
class Runner
|
6
|
+
def self.process_io(io)
|
7
|
+
mod = Module.new
|
8
|
+
path = io.respond_to?(:path) ? io.path : nil
|
9
|
+
args = [io.read, path].compact
|
10
|
+
template = mod.class_eval(*args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.process(input_path, output_path)
|
14
|
+
input_path = Pathname.new(input_path)
|
15
|
+
output_path = Pathname.new(output_path)
|
16
|
+
|
17
|
+
template = process_io(input_path.open)
|
18
|
+
output_path.open('w:utf-8') { |f| f.write(template.to_json) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/cumuliform/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cumuliform
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Patterson
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-06-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -58,7 +58,8 @@ description: |
|
|
58
58
|
non-existent resources because you have a typo.
|
59
59
|
email:
|
60
60
|
- matt@reprocessed.org
|
61
|
-
executables:
|
61
|
+
executables:
|
62
|
+
- cumuliform
|
62
63
|
extensions: []
|
63
64
|
extra_rdoc_files: []
|
64
65
|
files:
|
@@ -73,12 +74,17 @@ files:
|
|
73
74
|
- bin/console
|
74
75
|
- bin/setup
|
75
76
|
- cumuliform.gemspec
|
77
|
+
- examples/Rakefile
|
78
|
+
- examples/simplest.rb
|
79
|
+
- exe/cumuliform
|
76
80
|
- lib/cumuliform.rb
|
77
81
|
- lib/cumuliform/error.rb
|
78
82
|
- lib/cumuliform/fragments.rb
|
79
83
|
- lib/cumuliform/functions.rb
|
80
84
|
- lib/cumuliform/import.rb
|
81
85
|
- lib/cumuliform/output.rb
|
86
|
+
- lib/cumuliform/rake_task.rb
|
87
|
+
- lib/cumuliform/runner.rb
|
82
88
|
- lib/cumuliform/version.rb
|
83
89
|
homepage: https://www.github.com/tape-tv/cumuliform
|
84
90
|
licenses:
|