cumuliform 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
[](https://travis-ci.org/tape-tv/cumuliform) [](https://codeclimate.com/github/tape-tv/cumuliform) [](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:
|