bora 0.9.4 → 1.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +144 -115
- data/bora.gemspec +1 -0
- data/exe/bora +5 -0
- data/lib/bora.rb +41 -4
- data/lib/bora/cfn/event.rb +35 -0
- data/lib/bora/cfn/output.rb +24 -0
- data/lib/bora/cfn/stack.rb +168 -0
- data/lib/bora/cfn/stack_status.rb +33 -0
- data/lib/bora/cfn/status.rb +43 -0
- data/lib/bora/cfn_param_resolver.rb +3 -3
- data/lib/bora/cli.rb +81 -0
- data/lib/bora/stack.rb +125 -118
- data/lib/bora/stack_tasks.rb +132 -0
- data/lib/bora/tasks.rb +8 -3
- data/lib/bora/template.rb +37 -0
- data/lib/bora/version.rb +2 -2
- metadata +29 -10
- data/lib/bora/event.rb +0 -31
- data/lib/bora/output.rb +0 -20
- data/lib/bora/rake_tasks.rb +0 -107
- data/lib/bora/stack_status.rb +0 -29
- data/lib/bora/status.rb +0 -41
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0274ebd129ad2e2c1e96f6c93accc024628bb960
|
4
|
+
data.tar.gz: 0b5b69a386da693777967af8692b4ba87cecb648
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3de20877d9013f467d4fe4a95656586234f6bf9383d40db73b8bb4f118224449683ceb8ba1701a585bc28f8fa51089c6227dc1d34d6c9b142622948f1eddc256
|
7
|
+
data.tar.gz: 48257c8f06b1d56a3d952b40135ae72b7c72ddd472b5da9b0c2a845676e9cdc1e1bb05ec969fd05f48cd313e2110d242e8b2fbd4a8be5270caa1fa6946090109
|
data/README.md
CHANGED
@@ -1,169 +1,198 @@
|
|
1
1
|
# Bora
|
2
2
|
|
3
|
-
This gem contains
|
4
|
-
|
3
|
+
This Ruby gem contains a command line utility and [rake](https://github.com/ruby/rake) tasks
|
4
|
+
that help you define and work with [CloudFormation](https://aws.amazon.com/cloudformation/) stacks.
|
5
|
+
|
6
|
+
In a single YAML file you define your templates,
|
7
|
+
the stack instances built from those templates (eg: dev, uat, staging, prod, etc),
|
8
|
+
and the parameters for those stacks. Parameters can even refer to outputs of other stacks.
|
9
|
+
Templates can be written with plain CloudFormation JSON or
|
10
|
+
[cfndsl](https://github.com/stevenjack/cfndsl).
|
11
|
+
|
12
|
+
Given this config, Bora then provides commands (or Rake tasks) to work with those stacks
|
13
|
+
(create, update, delete, diff, etc).
|
5
14
|
|
6
15
|
|
7
16
|
## Installation
|
8
17
|
|
9
|
-
|
18
|
+
If you're using Bundler, add this line to your application's `Gemfile`:
|
10
19
|
|
11
20
|
```ruby
|
12
21
|
gem 'bora'
|
13
22
|
```
|
14
23
|
|
15
|
-
And then
|
24
|
+
And then run `bundle install`.
|
16
25
|
|
17
|
-
|
26
|
+
Alternatively, install directly with `gem install bora`.
|
18
27
|
|
19
|
-
Or install it yourself as:
|
20
|
-
|
21
|
-
$ gem install bora
|
22
28
|
|
23
29
|
## Usage
|
24
30
|
|
25
31
|
### Quick Start
|
26
32
|
|
27
|
-
|
33
|
+
Create a file `bora.yml` in your home directory, something like this:
|
34
|
+
```yaml
|
35
|
+
templates:
|
36
|
+
example:
|
37
|
+
template_file: example.json
|
38
|
+
stacks:
|
39
|
+
uat:
|
40
|
+
params:
|
41
|
+
InstanceType: t2.micro
|
42
|
+
prod:
|
43
|
+
params:
|
44
|
+
InstanceType: m4.xlarge
|
45
|
+
```
|
46
|
+
|
47
|
+
Now run `bora apply example-uat` to create your "uat" stack.
|
48
|
+
Bora will wait until the stack is complete (or failed),
|
49
|
+
and return stack events to you as they happen.
|
50
|
+
To get a full list of available commands, run `bora help`.
|
51
|
+
|
52
|
+
Alternatively if you prefer using Rake, add this to your `Rakefile`:
|
28
53
|
|
29
54
|
```ruby
|
30
55
|
require 'bora'
|
31
|
-
|
32
|
-
Bora::Tasks.new("example", "example.json")
|
56
|
+
Bora.new.rake_tasks
|
33
57
|
```
|
34
58
|
|
35
|
-
|
36
|
-
|
37
|
-
```shell
|
38
|
-
rake stack:example:apply # Creates (or updates) the 'example' stack
|
39
|
-
rake stack:example:current_template # Shows the current template for 'example' stack
|
40
|
-
rake stack:example:delete # Deletes the 'example' stack
|
41
|
-
rake stack:example:diff # Diffs the new template with the 'example' stack's current template
|
42
|
-
rake stack:example:events # Outputs the latest events from the 'example' stack
|
43
|
-
rake stack:example:new_template # Shows the new template for 'example' stack
|
44
|
-
rake stack:example:outputs # Shows the outputs from the 'example' stack
|
45
|
-
rake stack:example:recreate # Recreates (deletes then creates) the 'example' stack
|
46
|
-
rake stack:example:status # Displays the current status of the 'example' stack
|
47
|
-
rake stack:example:validate # Checks the 'example' stack's template for validity
|
48
|
-
```
|
59
|
+
Then run `rake stack:example-uat:apply`.
|
60
|
+
To get a full list of available tasks run `rake -T`.
|
49
61
|
|
50
|
-
You can add as many templates as you like into your Rakefile, simply define an instance of `Bora::Tasks` for each one.
|
51
62
|
|
52
|
-
|
63
|
+
## File Format Reference
|
53
64
|
|
54
|
-
|
55
|
-
The available options are shown below with their default values.
|
65
|
+
The example below is a `bora.yml` file showing all available options:
|
56
66
|
|
57
|
-
```
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
* `colorize` - A boolean that controls whether console output is colored or not
|
67
|
+
```yaml
|
68
|
+
# A map defining all the CloudFormation templates available.
|
69
|
+
# A "template" is effectively a single CloudFormation JSON (or cfndsl template).
|
70
|
+
templates:
|
71
|
+
# A template named "app"
|
72
|
+
app:
|
73
|
+
# This template is a plain old CloudFormation JSON file
|
74
|
+
template_file: app.json
|
66
75
|
|
76
|
+
# Optional. An array of "capabilities" to be passed to the CloudFormation API
|
77
|
+
# (see CloudFormation docs for more details)
|
78
|
+
capabilities: [CAPABILITY_IAM]
|
67
79
|
|
68
|
-
|
69
|
-
|
80
|
+
# A map defining all the "stacks" associated with this template
|
81
|
+
# for example, "uat" and "prod"
|
82
|
+
stacks:
|
83
|
+
# The "uat" stack
|
84
|
+
uat:
|
85
|
+
# The CloudFormation parameters to pass into the stack
|
86
|
+
params:
|
87
|
+
InstanceType: t2.micro
|
88
|
+
AMI: ami-11032472
|
89
|
+
|
90
|
+
# The "prod" stack
|
91
|
+
prod:
|
92
|
+
# Optional. The stack name to use in CloudFormation
|
93
|
+
# If you don't supply this, the name will be the template
|
94
|
+
# name concatenated with the stack name as defined in this file,
|
95
|
+
# eg: "app-prod".
|
96
|
+
stack_name: prod-application-stack
|
97
|
+
params:
|
98
|
+
InstanceType: m4.xlarge
|
99
|
+
AMI: ami-11032472
|
70
100
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
101
|
+
# A template named "web"
|
102
|
+
web:
|
103
|
+
# This template is using cfndsl. Bora treats any template ending in
|
104
|
+
# ".rb" as a cfndsl template.
|
105
|
+
template_file: "web.rb"
|
106
|
+
stacks:
|
107
|
+
uat:
|
108
|
+
# The CloudFormation parameters to pass into the stack.
|
109
|
+
# You can define both cfndsl parameters and traditional CloudFormation
|
110
|
+
# parameters here. Cfndsl will receive all of them, but only those
|
111
|
+
# actually defined in the "Parameters" section of the template will be
|
112
|
+
# passed through to CloudFormation when the stack is applied.
|
113
|
+
params:
|
114
|
+
dns_zone: example.com
|
79
115
|
|
80
|
-
|
116
|
+
# You can use complex data structures with cfndsl parameters:
|
117
|
+
users:
|
118
|
+
- id: joe
|
119
|
+
name: Joe Bloggs
|
120
|
+
- id: mary
|
121
|
+
name: Mary Bloggs
|
81
122
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
Bora::Tasks.new("example", "example.json") do |t|
|
87
|
-
CfnDsl::RakeTask.new do |cfndsl_task|
|
88
|
-
cfndsl_task.cfndsl_opts = {
|
89
|
-
files: [{
|
90
|
-
filename: "example.rb",
|
91
|
-
output: "example.json"
|
92
|
-
}]
|
93
|
-
}
|
94
|
-
end
|
95
|
-
end
|
96
|
-
```
|
123
|
+
# You can refer to outputs of other stacks using "${}" notation too.
|
124
|
+
# See below for further details.
|
125
|
+
app_url: http://${app-uat/outputs/Domain}/api
|
97
126
|
|
98
|
-
|
99
|
-
|
127
|
+
# Traditional CloudFormation parameters
|
128
|
+
InstanceType: t2.micro
|
129
|
+
AMI: ami-11032472
|
100
130
|
|
101
|
-
|
102
|
-
Bora::Tasks.new("example", "example.json") do |t|
|
103
|
-
task :generate do |t, args|
|
104
|
-
arg1, arg2 = args.extras
|
105
|
-
# Generate your template and write it into "example.json" here
|
106
|
-
end
|
107
|
-
end
|
131
|
+
prod: {}
|
108
132
|
```
|
109
|
-
|
110
|
-
|
133
|
+
|
134
|
+
## Parameter Substitution
|
135
|
+
|
136
|
+
Bora supports looking up parameter values from other stacks and interpolating them into input parameters.
|
137
|
+
At present you can only look up the outputs of other stacks,
|
138
|
+
however in the future it may support looking up stack parameters or resources.
|
139
|
+
Other future possibilities include looking up values from other services,
|
140
|
+
for example AMI IDs.
|
141
|
+
|
142
|
+
The format is as follows:
|
143
|
+
|
144
|
+
`${<stack_name>/outputs/<output_name>}`
|
145
|
+
|
146
|
+
For example:
|
147
|
+
```yaml
|
148
|
+
params:
|
149
|
+
api_url: http://${api-stack/outputs/Domain}/api
|
111
150
|
```
|
112
151
|
|
152
|
+
This will look up the `Domain` output from the stack named `api-stack` and substitute it into the `api_url` parameter.
|
113
153
|
|
114
|
-
### API
|
115
154
|
|
116
|
-
|
155
|
+
## Command Line
|
117
156
|
|
118
|
-
|
119
|
-
require 'bora'
|
157
|
+
Run `bora help` to see all available commands.
|
120
158
|
|
121
|
-
|
122
|
-
|
123
|
-
puts event
|
124
|
-
end
|
159
|
+
`bora help [command]` will show you help for a particular command,
|
160
|
+
eg: `bora help apply`.
|
125
161
|
|
126
|
-
puts "Update #{result ? "succeeded" : "failed"}"
|
127
|
-
```
|
128
162
|
|
129
|
-
|
130
|
-
You can define and configure your stacks through YAML too.
|
131
|
-
This interface is currently experimental,
|
132
|
-
but longer term is likely to become the primary way to use this gem.
|
133
|
-
Sample usage is shown below (subject to change).
|
163
|
+
## Rake Tasks
|
134
164
|
|
135
|
-
Rakefile
|
165
|
+
To use the rake tasks, simply put this in your `Rakefile`:
|
136
166
|
```ruby
|
137
|
-
require
|
138
|
-
Bora
|
167
|
+
require 'bora'
|
168
|
+
Bora.new.rake_tasks
|
139
169
|
```
|
140
170
|
|
141
|
-
|
142
|
-
```yaml
|
143
|
-
templates:
|
144
|
-
app:
|
145
|
-
template_file: templates/test.json
|
146
|
-
stacks:
|
147
|
-
dev: {}
|
148
|
-
uat: {}
|
171
|
+
To get a full list of available tasks run `rake -T`.
|
149
172
|
|
150
|
-
web:
|
151
|
-
# Templates ending in ".rb" are treated as cfndsl templates
|
152
|
-
template_file: templates/test.rb
|
153
|
-
capabilities: [CAPABILITY_IAM]
|
154
|
-
stacks:
|
155
|
-
dev:
|
156
|
-
# Set stack name explicitly (otherwise would default to "web-dev")
|
157
|
-
stack_name: foo-dev
|
158
|
-
params:
|
159
|
-
# Look up a value from the outputs of the "app-dev"stack
|
160
|
-
app_sg: ${app-dev/outputs/AppSecurityGroup}
|
161
|
-
uat:
|
162
|
-
params:
|
163
|
-
app_sg: foouatdev
|
164
173
|
|
174
|
+
## Overriding Stack Parameters from the Command Line
|
175
|
+
|
176
|
+
Some commands accept a list of parameters that will override those defined in the YAML file.
|
177
|
+
|
178
|
+
If you are using the Bora command line, you can pass these parameters like this:
|
179
|
+
|
180
|
+
```bash
|
181
|
+
$ bora apply web-uat --params 'instance_type=t2.micro' 'ami=ami-11032472'
|
165
182
|
```
|
166
183
|
|
184
|
+
For rake, he equivalent is:
|
185
|
+
```bash
|
186
|
+
$ rake stack:web-uat:apply[instance_type=t2.micro,ami=ami-11032472]
|
187
|
+
```
|
188
|
+
|
189
|
+
|
190
|
+
## Related Projects
|
191
|
+
The following projects provided inspiration for Bora:
|
192
|
+
* [CfnDsl](https://github.com/stevenjack/cfndsl) - A Ruby DSL for CloudFormation templates
|
193
|
+
* [CloudFormer](https://github.com/kunday/cloudformer) - Rake tasks for CloudFormation
|
194
|
+
* [Cumulus](https://github.com/cotdsa/cumulus) - A Python YAML based tool for working with CloudFormation
|
195
|
+
|
167
196
|
|
168
197
|
## Development
|
169
198
|
|
data/bora.gemspec
CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_dependency "colorize", "~> 0.7"
|
23
23
|
spec.add_dependency "diffy", "~> 3.0"
|
24
24
|
spec.add_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_dependency "thor", "~> 0.19"
|
25
26
|
|
26
27
|
spec.add_development_dependency "bundler", "~> 1.11"
|
27
28
|
spec.add_development_dependency "rspec", "~> 3.0"
|
data/exe/bora
ADDED
data/lib/bora.rb
CHANGED
@@ -1,6 +1,43 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require "colorize"
|
1
3
|
require "bora/version"
|
2
|
-
require "bora/
|
3
|
-
require "bora/event"
|
4
|
-
require "bora/stack"
|
4
|
+
require "bora/template"
|
5
5
|
require "bora/tasks"
|
6
|
-
|
6
|
+
|
7
|
+
class Bora
|
8
|
+
DEFAULT_CONFIG_FILE = "bora.yml"
|
9
|
+
|
10
|
+
def initialize(config_file_or_hash: DEFAULT_CONFIG_FILE, colorize: true)
|
11
|
+
@templates = {}
|
12
|
+
config = load_config(config_file_or_hash)
|
13
|
+
String.disable_colorization = !colorize
|
14
|
+
config['templates'].each do |template_name, template_config|
|
15
|
+
@templates[template_name] = Template.new(template_name, template_config)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def template(name)
|
20
|
+
@templates[name]
|
21
|
+
end
|
22
|
+
|
23
|
+
def stack(stack_name)
|
24
|
+
t = @templates.find { |_, template| template.stack(stack_name) != nil }
|
25
|
+
t ? t[1].stack(stack_name) : nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def rake_tasks
|
29
|
+
@templates.each { |_, t| t.rake_tasks }
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
def load_config(config)
|
36
|
+
if config.class == String
|
37
|
+
return YAML.load_file(config)
|
38
|
+
elsif config.class == Hash
|
39
|
+
return config
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'bora/cfn/status'
|
2
|
+
|
3
|
+
class Bora
|
4
|
+
module Cfn
|
5
|
+
|
6
|
+
class Event
|
7
|
+
def initialize(event)
|
8
|
+
@event = event
|
9
|
+
@status = Status.new(@event.resource_status)
|
10
|
+
end
|
11
|
+
|
12
|
+
def method_missing(sym, *args, &block)
|
13
|
+
@event.send(sym, *args, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def status_success?
|
17
|
+
@status.success?
|
18
|
+
end
|
19
|
+
|
20
|
+
def status_failure?
|
21
|
+
@status.failure?
|
22
|
+
end
|
23
|
+
|
24
|
+
def status_complete?
|
25
|
+
status_success? || status_failure?
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
status_reason = @event.resource_status_reason ? " - #{@event.resource_status_reason}" : ""
|
30
|
+
"#{@event.timestamp.getlocal} - #{@event.resource_type} - #{@event.logical_resource_id} - #{@status}#{status_reason}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class Bora
|
2
|
+
module Cfn
|
3
|
+
|
4
|
+
class Output
|
5
|
+
def initialize(output)
|
6
|
+
@output = output
|
7
|
+
end
|
8
|
+
|
9
|
+
def key
|
10
|
+
@output.output_key
|
11
|
+
end
|
12
|
+
|
13
|
+
def value
|
14
|
+
@output.output_value
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
desc = @output.description ? " (#{@output.description})" : ""
|
19
|
+
"#{@output.output_key} - #{@output.output_value} #{desc}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|