bora 1.1.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +36 -1
- data/lib/bora/cli.rb +12 -1
- data/lib/bora/parameter_resolver.rb +44 -14
- data/lib/bora/stack.rb +4 -1
- data/lib/bora/template.rb +11 -3
- data/lib/bora/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 741e43489dd8279e5b9a2fa73068bd45bbfcc7de
|
4
|
+
data.tar.gz: 708c036c31038bec8dc57a61541af3065f4bf2c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85b831a26bb9876db1a32a00238b1d489582a5f87adcb105d5103414d1274d175f53bc8123287a603a811e0f43ee2e336b0704e71107d85698507cbd84e176ac
|
7
|
+
data.tar.gz: 957e597af2294f73976630840ef64dbcdb2f078ea2085b39e0aa9d4d2e9950168ac7c292b1aa67fc9d394ee52abcade685573070d7e7ff419c7a5fda6349eb11
|
data/README.md
CHANGED
@@ -102,7 +102,7 @@ templates:
|
|
102
102
|
# If you don't supply this, the name will be the template
|
103
103
|
# name concatenated with the stack name as defined in this file,
|
104
104
|
# eg: "app-prod".
|
105
|
-
|
105
|
+
cfn_stack_name: prod-application-stack
|
106
106
|
|
107
107
|
# Optional. Default region for this stack.
|
108
108
|
# Overrides "default_region" at the template level.
|
@@ -219,6 +219,17 @@ There are a number of resolvers that come with Bora (documented below),
|
|
219
219
|
or you can write your own.
|
220
220
|
|
221
221
|
|
222
|
+
### Parameter Lookup
|
223
|
+
Any substitution that does not specify a "scheme" is treated as a reference to another parameter value.
|
224
|
+
For example:
|
225
|
+
|
226
|
+
```yaml
|
227
|
+
params:
|
228
|
+
domain: example.com
|
229
|
+
url: http://${domain}/foo
|
230
|
+
```
|
231
|
+
|
232
|
+
|
222
233
|
### Stack Output Lookup
|
223
234
|
|
224
235
|
You can look up outputs from stacks in the same region.
|
@@ -280,6 +291,30 @@ $ rake web-uat:apply[instance_type=t2.micro,ami=ami-11032472]
|
|
280
291
|
```
|
281
292
|
|
282
293
|
|
294
|
+
## Creating Multiple Instances of a Stack
|
295
|
+
Sometimes it can be useful to create multiple instances of a single stack.
|
296
|
+
For example, you may define a single "qa" stack with all the settings for a testing environment.
|
297
|
+
Then you might want to stand up this stack multiple times so you can have multiple testing environments,
|
298
|
+
eg "qa1", "qa2", etc.
|
299
|
+
|
300
|
+
Bora makes this possible by allowing you to override the name of the stack that gets created in CloudFormation.
|
301
|
+
For example:
|
302
|
+
|
303
|
+
```bash
|
304
|
+
$ bora apply web-qa --cfn-stack-name "web-qa-1"
|
305
|
+
$ bora apply web-qa --cfn-stack-name "web-qa-2"
|
306
|
+
```
|
307
|
+
|
308
|
+
Remember that if you use this functionality you must remember to pass in the stack name to *every* command or you will get unexepected results.
|
309
|
+
|
310
|
+
```bash
|
311
|
+
$ bora outputs web-qa --cfn-stack-name "web-qa-1"
|
312
|
+
```
|
313
|
+
|
314
|
+
Work is underway to improve how Bora handles this use case.
|
315
|
+
If this is of interest to you, please have a look at the [GitHub issue](https://github.com/ampedandwired/bora/issues/10) for this functionality.
|
316
|
+
|
317
|
+
|
283
318
|
## Related Projects
|
284
319
|
The following projects provided inspiration for Bora:
|
285
320
|
* [CfnDsl](https://github.com/stevenjack/cfndsl) - A Ruby DSL for CloudFormation templates
|
data/lib/bora/cli.rb
CHANGED
@@ -15,6 +15,12 @@ class Bora
|
|
15
15
|
default: nil,
|
16
16
|
desc: "The region to use for the stack operation. Overrides any regions specified in the Bora config file."
|
17
17
|
|
18
|
+
class_option "cfn-stack-name",
|
19
|
+
type: :string,
|
20
|
+
aliases: :c,
|
21
|
+
default: nil,
|
22
|
+
desc: "The name to give the stack in CloudFormation. Overrides any CFN stack name setting in the Bora config file."
|
23
|
+
|
18
24
|
desc "list", "Lists the available stacks"
|
19
25
|
def list
|
20
26
|
templates = bora(options.file).templates
|
@@ -84,7 +90,12 @@ class Bora
|
|
84
90
|
|
85
91
|
def stack(config_file, stack_name)
|
86
92
|
region = options.region
|
87
|
-
|
93
|
+
cfn_stack_name = options["cfn-stack-name"]
|
94
|
+
|
95
|
+
override_config = {}
|
96
|
+
override_config["default_region"] = region if region
|
97
|
+
override_config["cfn_stack_name"] = cfn_stack_name if cfn_stack_name
|
98
|
+
|
88
99
|
bora = bora(config_file, override_config)
|
89
100
|
stack = bora.stack(stack_name)
|
90
101
|
if !stack
|
@@ -3,6 +3,10 @@ require 'bora/parameter_resolver_loader'
|
|
3
3
|
|
4
4
|
class Bora
|
5
5
|
class ParameterResolver
|
6
|
+
UnresolvedSubstitutionError = Class.new(StandardError)
|
7
|
+
|
8
|
+
PLACEHOLDER_REGEX = /\${[^}]+}/
|
9
|
+
|
6
10
|
def initialize(stack)
|
7
11
|
@stack = stack
|
8
12
|
@loader = ParameterResolverLoader.new
|
@@ -10,26 +14,49 @@ class Bora
|
|
10
14
|
end
|
11
15
|
|
12
16
|
def resolve(params)
|
13
|
-
|
17
|
+
unresolved_placeholders_still_remain = true
|
18
|
+
while unresolved_placeholders_still_remain
|
19
|
+
unresolved_placeholders_still_remain = false
|
20
|
+
placeholders_were_substituted = false
|
21
|
+
params.each do |k, v|
|
22
|
+
resolved_value = process_param_substitutions(v, params)
|
23
|
+
unresolved_placeholders_still_remain ||= has_unresolved_placeholder?(resolved_value)
|
24
|
+
placeholders_were_substituted ||= resolved_value != v
|
25
|
+
params[k] = resolved_value
|
26
|
+
end
|
27
|
+
if unresolved_placeholders_still_remain && !placeholders_were_substituted
|
28
|
+
raise UnresolvedSubstitutionError, "Parameter substitutions could not be resolved:\n#{unresolved_placeholders_as_string(params)}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
params
|
14
32
|
end
|
15
33
|
|
16
34
|
|
17
35
|
private
|
18
36
|
|
19
|
-
def process_param_substitutions(val)
|
37
|
+
def process_param_substitutions(val, params)
|
20
38
|
return val unless val.is_a? String
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
39
|
+
val.gsub(PLACEHOLDER_REGEX) do |placeholder|
|
40
|
+
process_placeholder(placeholder, params)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def process_placeholder(placeholder, params)
|
45
|
+
uri = parse_uri(placeholder[2..-2])
|
46
|
+
if !uri.scheme
|
47
|
+
# This token refers to another parameter, rather than a resolver
|
48
|
+
value_to_substitute = params[uri.path]
|
49
|
+
!value_to_substitute || has_unresolved_placeholder?(value_to_substitute) ? placeholder : value_to_substitute
|
50
|
+
else
|
51
|
+
# This token needs to be resolved by a resolver
|
52
|
+
resolver_name = uri.scheme
|
53
|
+
resolver = @resolver_cache[resolver_name] || @loader.load_resolver(resolver_name).new(@stack)
|
54
|
+
resolver.resolve(uri)
|
31
55
|
end
|
32
|
-
|
56
|
+
end
|
57
|
+
|
58
|
+
def has_unresolved_placeholder?(val)
|
59
|
+
val =~ PLACEHOLDER_REGEX
|
33
60
|
end
|
34
61
|
|
35
62
|
def parse_uri(s)
|
@@ -40,9 +67,12 @@ class Bora
|
|
40
67
|
if !uri.scheme && uri.path && uri.path.count("/") == 2
|
41
68
|
uri = URI("cfn://#{s}")
|
42
69
|
end
|
43
|
-
|
44
70
|
uri
|
45
71
|
end
|
46
72
|
|
73
|
+
def unresolved_placeholders_as_string(params)
|
74
|
+
params.select { |k, v| has_unresolved_placeholder?(v) }.to_a.map { |k, v| "#{k}: #{v}" }.join("\n")
|
75
|
+
end
|
76
|
+
|
47
77
|
end
|
48
78
|
end
|
data/lib/bora/stack.rb
CHANGED
@@ -18,7 +18,10 @@ class Bora
|
|
18
18
|
|
19
19
|
def initialize(stack_name, template_file, stack_config)
|
20
20
|
@stack_name = stack_name
|
21
|
-
@cfn_stack_name = stack_config['stack_name'] || @stack_name
|
21
|
+
@cfn_stack_name = stack_config['cfn_stack_name'] || stack_config['stack_name'] || @stack_name
|
22
|
+
if stack_config['stack_name']
|
23
|
+
puts "DEPRECATED: The 'stack_name' setting is deprecated. Please use 'cfn_stack_name' instead."
|
24
|
+
end
|
22
25
|
@template_file = template_file
|
23
26
|
@stack_config = stack_config
|
24
27
|
@region = @stack_config['default_region']
|
data/lib/bora/template.rb
CHANGED
@@ -2,16 +2,20 @@ require 'bora/stack'
|
|
2
2
|
|
3
3
|
class Bora
|
4
4
|
class Template
|
5
|
+
# These are properties that you can define on the template, but which can also be defined in the stack
|
5
6
|
INHERITABLE_PROPERTIES = ["capabilities", "default_region"]
|
6
7
|
|
8
|
+
# These are properties that can be passed in from the command line to override what's defined inthe stack
|
9
|
+
OVERRIDABLE_PROPERTIES = ["cfn_stack_name"]
|
10
|
+
|
7
11
|
def initialize(template_name, template_config, override_config = {})
|
8
12
|
@template_name = template_name
|
9
13
|
@template_config = template_config
|
10
14
|
@stacks = {}
|
11
15
|
template_config['stacks'].each do |stack_name, stack_config|
|
12
16
|
stack_name = "#{template_name}-#{stack_name}"
|
13
|
-
|
14
|
-
@stacks[stack_name] = Stack.new(stack_name, template_config['template_file'],
|
17
|
+
resolved_config = resolve_stack_config(template_config, stack_config, override_config)
|
18
|
+
@stacks[stack_name] = Stack.new(stack_name, template_config['template_file'], resolved_config)
|
15
19
|
end
|
16
20
|
end
|
17
21
|
|
@@ -31,12 +35,16 @@ class Bora
|
|
31
35
|
private
|
32
36
|
|
33
37
|
def resolve_stack_config(template_config, stack_config, override_config)
|
34
|
-
inheritable_properties(template_config).merge(stack_config).merge(
|
38
|
+
inheritable_properties(template_config).merge(stack_config).merge(overridable_properties(override_config))
|
35
39
|
end
|
36
40
|
|
37
41
|
def inheritable_properties(config)
|
38
42
|
config.select { |k| INHERITABLE_PROPERTIES.include?(k) }
|
39
43
|
end
|
40
44
|
|
45
|
+
def overridable_properties(config)
|
46
|
+
config.select { |k| INHERITABLE_PROPERTIES.include?(k) || OVERRIDABLE_PROPERTIES.include?(k) }
|
47
|
+
end
|
48
|
+
|
41
49
|
end
|
42
50
|
end
|
data/lib/bora/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bora
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Charles Blaxland
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-10-
|
11
|
+
date: 2016-10-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk
|