sfn 3.0.30 → 3.0.32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/bin/sfn +16 -14
- data/lib/chef/knife/knife_plugin_seed.rb +12 -12
- data/lib/sfn.rb +17 -17
- data/lib/sfn/api_provider.rb +3 -3
- data/lib/sfn/api_provider/google.rb +2 -2
- data/lib/sfn/api_provider/terraform.rb +2 -2
- data/lib/sfn/cache.rb +9 -9
- data/lib/sfn/callback.rb +6 -6
- data/lib/sfn/callback/aws_assume_role.rb +5 -5
- data/lib/sfn/callback/aws_mfa.rb +8 -6
- data/lib/sfn/callback/stack_policy.rb +15 -15
- data/lib/sfn/command.rb +37 -36
- data/lib/sfn/command/conf.rb +12 -12
- data/lib/sfn/command/create.rb +9 -9
- data/lib/sfn/command/describe.rb +6 -6
- data/lib/sfn/command/destroy.rb +8 -8
- data/lib/sfn/command/diff.rb +31 -31
- data/lib/sfn/command/events.rb +6 -6
- data/lib/sfn/command/export.rb +8 -8
- data/lib/sfn/command/graph.rb +21 -21
- data/lib/sfn/command/graph/aws.rb +34 -34
- data/lib/sfn/command/graph/provider.rb +1 -1
- data/lib/sfn/command/graph/terraform.rb +41 -41
- data/lib/sfn/command/import.rb +17 -17
- data/lib/sfn/command/init.rb +15 -15
- data/lib/sfn/command/inspect.rb +16 -16
- data/lib/sfn/command/lint.rb +6 -6
- data/lib/sfn/command/list.rb +2 -2
- data/lib/sfn/command/plan.rb +227 -0
- data/lib/sfn/command/print.rb +4 -4
- data/lib/sfn/command/promote.rb +2 -2
- data/lib/sfn/command/update.rb +19 -144
- data/lib/sfn/command/validate.rb +17 -13
- data/lib/sfn/command_module.rb +6 -5
- data/lib/sfn/command_module/base.rb +8 -8
- data/lib/sfn/command_module/callbacks.rb +5 -5
- data/lib/sfn/command_module/planning.rb +151 -0
- data/lib/sfn/command_module/stack.rb +34 -34
- data/lib/sfn/command_module/template.rb +50 -50
- data/lib/sfn/config.rb +46 -44
- data/lib/sfn/config/conf.rb +3 -3
- data/lib/sfn/config/create.rb +9 -9
- data/lib/sfn/config/describe.rb +7 -7
- data/lib/sfn/config/destroy.rb +1 -1
- data/lib/sfn/config/diff.rb +3 -3
- data/lib/sfn/config/events.rb +9 -9
- data/lib/sfn/config/export.rb +5 -5
- data/lib/sfn/config/graph.rb +10 -10
- data/lib/sfn/config/import.rb +4 -4
- data/lib/sfn/config/init.rb +1 -1
- data/lib/sfn/config/inspect.rb +16 -16
- data/lib/sfn/config/lint.rb +5 -5
- data/lib/sfn/config/list.rb +6 -6
- data/lib/sfn/config/plan.rb +28 -0
- data/lib/sfn/config/print.rb +5 -5
- data/lib/sfn/config/promote.rb +4 -4
- data/lib/sfn/config/update.rb +18 -18
- data/lib/sfn/config/validate.rb +30 -30
- data/lib/sfn/lint.rb +5 -5
- data/lib/sfn/lint/definition.rb +3 -3
- data/lib/sfn/lint/rule.rb +3 -3
- data/lib/sfn/lint/rule_set.rb +2 -2
- data/lib/sfn/monkey_patch.rb +2 -2
- data/lib/sfn/monkey_patch/stack.rb +27 -27
- data/lib/sfn/monkey_patch/stack/azure.rb +1 -1
- data/lib/sfn/monkey_patch/stack/google.rb +5 -5
- data/lib/sfn/planner.rb +4 -4
- data/lib/sfn/planner/aws.rb +114 -70
- data/lib/sfn/provider.rb +13 -13
- data/lib/sfn/utils.rb +10 -10
- data/lib/sfn/utils/debug.rb +2 -2
- data/lib/sfn/utils/json.rb +1 -1
- data/lib/sfn/utils/object_storage.rb +3 -3
- data/lib/sfn/utils/output.rb +4 -4
- data/lib/sfn/utils/path_selector.rb +15 -15
- data/lib/sfn/utils/ssher.rb +4 -4
- data/lib/sfn/utils/stack_exporter.rb +16 -16
- data/lib/sfn/utils/stack_parameter_scrubber.rb +6 -6
- data/lib/sfn/utils/stack_parameter_validator.rb +22 -22
- data/lib/sfn/version.rb +1 -1
- data/sfn.gemspec +32 -32
- metadata +16 -13
@@ -0,0 +1,151 @@
|
|
1
|
+
require "sfn"
|
2
|
+
require "sparkle_formation"
|
3
|
+
|
4
|
+
module Sfn
|
5
|
+
module CommandModule
|
6
|
+
# Planning helpers
|
7
|
+
module Planning
|
8
|
+
# Create a new planner instance
|
9
|
+
#
|
10
|
+
# @param [Miasma::Models::Orchestration::Stack]
|
11
|
+
# @return [Sfn::Planner]
|
12
|
+
def build_planner(stack)
|
13
|
+
klass_name = stack.api.class.to_s.split("::").last
|
14
|
+
if Planner.const_defined?(klass_name)
|
15
|
+
Planner.const_get(klass_name).new(ui, config, arguments, stack)
|
16
|
+
else
|
17
|
+
warn "Failed to build planner for current provider. No provider implemented. (`#{klass_name}`)"
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Display plan result on the UI
|
23
|
+
#
|
24
|
+
# @param result [Miasma::Models::Orchestration::Stack::Plan]
|
25
|
+
def display_plan_information(result)
|
26
|
+
ui.info ui.color("Pre-update resource planning report:", :bold)
|
27
|
+
unless print_plan_result(result, [result.name])
|
28
|
+
ui.info "No resources life cycle changes detected in this update!"
|
29
|
+
end
|
30
|
+
cmd = self.class.to_s.split("::").last.downcase
|
31
|
+
ui.confirm "Apply this stack #{cmd}?" unless config[:plan_only]
|
32
|
+
end
|
33
|
+
|
34
|
+
# Print plan information to the UI
|
35
|
+
#
|
36
|
+
# @param info [Miasma::Models::Orchestration::Stack::Plan]
|
37
|
+
# @param names [Array<String>] nested names
|
38
|
+
def print_plan_result(info, names = [])
|
39
|
+
said_any_things = false
|
40
|
+
unless Array(info.stacks).empty?
|
41
|
+
info.stacks.each do |s_name, s_info|
|
42
|
+
result = print_plan_result(s_info, [*names, s_name].compact)
|
43
|
+
said_any_things ||= result
|
44
|
+
end
|
45
|
+
end
|
46
|
+
if !names.flatten.compact.empty? || info.name
|
47
|
+
said_things = false
|
48
|
+
output_name = names.empty? ? info.name : names.join(" > ")
|
49
|
+
ui.puts
|
50
|
+
ui.puts " #{ui.color("Update plan for:", :bold)} #{ui.color(names.join(" > "), :blue)}"
|
51
|
+
unless Array(info.unknown).empty?
|
52
|
+
ui.puts " #{ui.color("!!! Unknown update effect:", :red, :bold)}"
|
53
|
+
print_plan_items(info, :unknown, :red)
|
54
|
+
ui.puts
|
55
|
+
said_any_things = said_things = true
|
56
|
+
end
|
57
|
+
unless Array(info.unavailable).empty?
|
58
|
+
ui.puts " #{ui.color("Update request not allowed:", :red, :bold)}"
|
59
|
+
print_plan_items(info, :unavailable, :red)
|
60
|
+
ui.puts
|
61
|
+
said_any_things = said_things = true
|
62
|
+
end
|
63
|
+
unless Array(info.replace).empty?
|
64
|
+
ui.puts " #{ui.color("Resources to be replaced:", :red, :bold)}"
|
65
|
+
print_plan_items(info, :replace, :red)
|
66
|
+
ui.puts
|
67
|
+
said_any_things = said_things = true
|
68
|
+
end
|
69
|
+
unless Array(info.interrupt).empty?
|
70
|
+
ui.puts " #{ui.color("Resources to be interrupted:", :yellow, :bold)}"
|
71
|
+
print_plan_items(info, :interrupt, :yellow)
|
72
|
+
ui.puts
|
73
|
+
said_any_things = said_things = true
|
74
|
+
end
|
75
|
+
unless Array(info.remove).empty?
|
76
|
+
ui.puts " #{ui.color("Resources to be removed:", :red, :bold)}"
|
77
|
+
print_plan_items(info, :remove, :red)
|
78
|
+
ui.puts
|
79
|
+
said_any_things = said_things = true
|
80
|
+
end
|
81
|
+
unless Array(info.add).empty?
|
82
|
+
ui.puts " #{ui.color("Resources to be added:", :green, :bold)}"
|
83
|
+
print_plan_items(info, :add, :green)
|
84
|
+
ui.puts
|
85
|
+
said_any_things = said_things = true
|
86
|
+
end
|
87
|
+
unless said_things
|
88
|
+
ui.puts " #{ui.color("No resource lifecycle changes detected!", :green)}"
|
89
|
+
ui.puts
|
90
|
+
said_any_things = true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
said_any_things
|
94
|
+
end
|
95
|
+
|
96
|
+
# Print planning items
|
97
|
+
#
|
98
|
+
# @param info [Miasma::Models::Orchestration::Stack::Plan] plan
|
99
|
+
# @param key [Symbol] key of items
|
100
|
+
# @param color [Symbol] color to flag
|
101
|
+
def print_plan_items(info, key, color)
|
102
|
+
collection = info.send(key)
|
103
|
+
max_name = collection.map(&:name).map(&:size).max
|
104
|
+
max_type = collection.map(&:type).map(&:size).max
|
105
|
+
max_p = collection.map(&:diffs).flatten(1).map(&:name).map(&:to_s).map(&:size).max
|
106
|
+
max_o = collection.map(&:diffs).flatten(1).map(&:current).map(&:to_s).map(&:size).max
|
107
|
+
collection.each do |val|
|
108
|
+
name = val.name
|
109
|
+
ui.print " " * 6
|
110
|
+
ui.print ui.color("[#{val.type}]", color)
|
111
|
+
ui.print " " * (max_type - val.type.size)
|
112
|
+
ui.print " " * 4
|
113
|
+
ui.print ui.color(name, :bold)
|
114
|
+
properties = Array(val.diffs).map(&:name)
|
115
|
+
unless properties.empty?
|
116
|
+
ui.print " " * (max_name - name.size)
|
117
|
+
ui.print " " * 4
|
118
|
+
ui.print "Reason: `#{properties.join("`, `")}`"
|
119
|
+
end
|
120
|
+
ui.puts
|
121
|
+
if config[:diffs]
|
122
|
+
unless val.diffs.empty?
|
123
|
+
p_name = nil
|
124
|
+
val.diffs.each do |diff|
|
125
|
+
if !diff.proposed.nil? || !diff.current.nil?
|
126
|
+
p_name = diff.name
|
127
|
+
ui.print " " * 8
|
128
|
+
ui.print "#{p_name}: "
|
129
|
+
ui.print " " * (max_p - p_name.size)
|
130
|
+
ui.print ui.color("-#{diff.current}", :red) if diff.current
|
131
|
+
ui.print " " * (max_o - diff.current.to_s.size)
|
132
|
+
ui.print " "
|
133
|
+
if diff.proposed == Sfn::Planner::RUNTIME_MODIFIED
|
134
|
+
ui.puts ui.color("+#{diff.current} <Dependency Modified>", :green)
|
135
|
+
else
|
136
|
+
if diff.proposed.nil?
|
137
|
+
ui.puts
|
138
|
+
else
|
139
|
+
ui.puts ui.color("+#{diff.proposed.to_s.gsub("__MODIFIED_REFERENCE_VALUE__", "<Dependency Modified>")}", :green)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
ui.puts if p_name
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "sfn"
|
2
|
+
require "sparkle_formation"
|
3
3
|
|
4
4
|
module Sfn
|
5
5
|
module CommandModule
|
@@ -10,13 +10,13 @@ module Sfn
|
|
10
10
|
# maximum number of attempts to get valid parameter value
|
11
11
|
MAX_PARAMETER_ATTEMPTS = 5
|
12
12
|
# Template parameter locations
|
13
|
-
TEMPLATE_PARAMETER_LOCATIONS = [
|
13
|
+
TEMPLATE_PARAMETER_LOCATIONS = ["Parameters", "parameters"]
|
14
14
|
# Template parameter default value locations
|
15
|
-
TEMPLATE_PARAMETER_DEFAULTS = [
|
15
|
+
TEMPLATE_PARAMETER_DEFAULTS = ["Default", "defaultValue", "default"]
|
16
16
|
# Template parameter no echo locations
|
17
|
-
TEMPLATE_PARAMETER_NOECHO = [
|
17
|
+
TEMPLATE_PARAMETER_NOECHO = ["NoEcho"]
|
18
18
|
# Template parameter no echo custom
|
19
|
-
TEMPLATE_PARAMETER_SFN_NOECHO = [
|
19
|
+
TEMPLATE_PARAMETER_SFN_NOECHO = ["Quiet", "quiet"]
|
20
20
|
|
21
21
|
# Apply any defined remote stacks
|
22
22
|
#
|
@@ -25,7 +25,7 @@ module Sfn
|
|
25
25
|
def apply_stacks!(stack)
|
26
26
|
remote_stacks = [config[:apply_stack]].flatten.compact
|
27
27
|
remote_stacks.each do |stack_name|
|
28
|
-
stack_info = stack_name.split(
|
28
|
+
stack_info = stack_name.split("__")
|
29
29
|
stack_info.unshift(nil) if stack_info.size == 1
|
30
30
|
stack_location, stack_name = stack_info
|
31
31
|
remote_stack = provider_for(stack_location).stack(stack_name)
|
@@ -66,7 +66,7 @@ module Sfn
|
|
66
66
|
if config[:apply_mapping]
|
67
67
|
valid_keys = config[:apply_mapping].keys.find_all do |a_key|
|
68
68
|
a_key = a_key.to_s
|
69
|
-
key_parts = a_key.split(
|
69
|
+
key_parts = a_key.split("__")
|
70
70
|
case key_parts.size
|
71
71
|
when 3
|
72
72
|
provider_stack.api.data[:location] == key_parts[0] &&
|
@@ -85,7 +85,7 @@ module Sfn
|
|
85
85
|
valid_keys -= to_remove
|
86
86
|
Hash[
|
87
87
|
valid_keys.map do |a_key|
|
88
|
-
cut_key = a_key.split(
|
88
|
+
cut_key = a_key.split("__").last
|
89
89
|
[cut_key, config[:apply_mapping][a_key]]
|
90
90
|
end
|
91
91
|
]
|
@@ -148,16 +148,16 @@ module Sfn
|
|
148
148
|
# @param parameter_name [String] parameter name
|
149
149
|
# @return [Array<String>] [expected_template_key, configuration_used_key]
|
150
150
|
def locate_config_parameter_key(parameter_prefix, parameter_name, root_name)
|
151
|
-
check_name = parameter_name.downcase.tr(
|
152
|
-
check_prefix = parameter_prefix.map { |i| i.downcase.tr(
|
151
|
+
check_name = parameter_name.downcase.tr("-_", "")
|
152
|
+
check_prefix = parameter_prefix.map { |i| i.downcase.tr("-_", "") }
|
153
153
|
key_match = config[:parameters].keys.detect do |cp_key|
|
154
|
-
cp_key = cp_key.to_s.downcase.split(
|
155
|
-
non_root_matcher = (check_prefix + [check_name]).join(
|
156
|
-
root_matcher = ([root_name] + check_prefix + [check_name]).join(
|
154
|
+
cp_key = cp_key.to_s.downcase.split("__").map { |i| i.tr("-_", "") }.join("__")
|
155
|
+
non_root_matcher = (check_prefix + [check_name]).join("__")
|
156
|
+
root_matcher = ([root_name] + check_prefix + [check_name]).join("__")
|
157
157
|
cp_key == non_root_matcher ||
|
158
158
|
cp_key == root_matcher
|
159
159
|
end
|
160
|
-
actual_key = (parameter_prefix + [parameter_name]).compact.join(
|
160
|
+
actual_key = (parameter_prefix + [parameter_name]).compact.join("__")
|
161
161
|
if key_match
|
162
162
|
ui.debug "Remapping configuration runtime parameter `#{key_match}` -> `#{actual_key}`"
|
163
163
|
config[:parameters][actual_key] = config[:parameters].delete(key_match)
|
@@ -179,9 +179,9 @@ module Sfn
|
|
179
179
|
attempt = 0
|
180
180
|
if !valid && !param_banner
|
181
181
|
if sparkle.is_a?(SparkleFormation)
|
182
|
-
ui.info "#{ui.color(
|
182
|
+
ui.info "#{ui.color("Stack runtime parameters:", :bold)} - template: #{ui.color(sparkle.root_path.map(&:name).map(&:to_s).join(" > "), :green, :bold)}"
|
183
183
|
else
|
184
|
-
ui.info ui.color(
|
184
|
+
ui.info ui.color("Stack runtime parameters:", :bold)
|
185
185
|
end
|
186
186
|
param_banner = true
|
187
187
|
end
|
@@ -194,17 +194,17 @@ module Sfn
|
|
194
194
|
)
|
195
195
|
if config[:interactive_parameters]
|
196
196
|
no_echo = !!TEMPLATE_PARAMETER_NOECHO.detect { |loc_key|
|
197
|
-
param_value[loc_key].to_s.downcase ==
|
197
|
+
param_value[loc_key].to_s.downcase == "true"
|
198
198
|
}
|
199
199
|
sfn_no_echo = TEMPLATE_PARAMETER_SFN_NOECHO.map do |loc_key|
|
200
200
|
res = param_value.delete(loc_key).to_s.downcase
|
201
|
-
res if !res.empty? && res !=
|
201
|
+
res if !res.empty? && res != "false"
|
202
202
|
end.compact.first
|
203
203
|
no_echo = sfn_no_echo if sfn_no_echo
|
204
204
|
answer = ui.ask_question(
|
205
|
-
"#{param_name.split(/([A-Z]+[^A-Z]*)/).find_all { |s| !s.empty? }.join(
|
205
|
+
"#{param_name.split(/([A-Z]+[^A-Z]*)/).find_all { |s| !s.empty? }.join(" ")}",
|
206
206
|
:default => default,
|
207
|
-
:hide_default => sfn_no_echo ==
|
207
|
+
:hide_default => sfn_no_echo == "all",
|
208
208
|
:no_echo => !!no_echo,
|
209
209
|
)
|
210
210
|
else
|
@@ -216,11 +216,11 @@ module Sfn
|
|
216
216
|
valid = true
|
217
217
|
else
|
218
218
|
validation.each do |validation_error|
|
219
|
-
ui.error validation_error.last
|
219
|
+
ui.error "#{param_name}: #{validation_error.last}"
|
220
220
|
end
|
221
221
|
end
|
222
222
|
if attempt > MAX_PARAMETER_ATTEMPTS
|
223
|
-
ui.fatal
|
223
|
+
ui.fatal "Failed to receive allowed parameter!"
|
224
224
|
exit 1
|
225
225
|
end
|
226
226
|
end
|
@@ -279,8 +279,8 @@ module Sfn
|
|
279
279
|
end
|
280
280
|
Smash[
|
281
281
|
config.fetch(:parameters, {}).map do |k, v|
|
282
|
-
strip_key = parameter_prefix ? k.sub(/#{parameter_prefix.join(
|
283
|
-
unless strip_key.include?(
|
282
|
+
strip_key = parameter_prefix ? k.sub(/#{parameter_prefix.join("__")}_{2}?/, "") : k
|
283
|
+
unless strip_key.include?("__")
|
284
284
|
[strip_key, v]
|
285
285
|
end
|
286
286
|
end.compact
|
@@ -299,7 +299,7 @@ module Sfn
|
|
299
299
|
def config_root_parameters
|
300
300
|
Hash[
|
301
301
|
config.fetch(:parameters, {}).find_all do |k, v|
|
302
|
-
!k.include?(
|
302
|
+
!k.include?("__")
|
303
303
|
end
|
304
304
|
]
|
305
305
|
end
|
@@ -318,13 +318,13 @@ module Sfn
|
|
318
318
|
def validate_stack_parameter(c_stack, p_key, p_ns_key, c_value)
|
319
319
|
stack_value = c_stack.parameters[p_key]
|
320
320
|
p_stack = c_stack.data[:parent_stack]
|
321
|
-
unless config[:parameter_validation] ==
|
321
|
+
unless config[:parameter_validation] == "none"
|
322
322
|
if c_value.is_a?(Hash)
|
323
323
|
case c_value.keys.first
|
324
|
-
when
|
324
|
+
when "Ref"
|
325
325
|
current_value = p_stack.parameters[c_value.values.first]
|
326
|
-
when
|
327
|
-
resource_name, output_name = c_value.values.first.split(
|
326
|
+
when "Fn::Att"
|
327
|
+
resource_name, output_name = c_value.values.first.split(".", 2)
|
328
328
|
ref_stack = p_stack.nested_stacks.detect { |i| i.data[:logical_id] == resource_name }
|
329
329
|
if ref_stack
|
330
330
|
output = ref_stack.outputs.detect do |o|
|
@@ -339,14 +339,14 @@ module Sfn
|
|
339
339
|
current_value = c_value
|
340
340
|
end
|
341
341
|
if current_value && current_value.to_s != stack_value.to_s
|
342
|
-
if config[:parameter_validation] ==
|
343
|
-
ui.warn
|
342
|
+
if config[:parameter_validation] == "default"
|
343
|
+
ui.warn "Nested stack has been altered directly! This update may cause unexpected modifications!"
|
344
344
|
ui.warn "Stack name: #{c_stack.name}. Parameter: #{p_key}. Current value: #{stack_value}. Expected value: #{current_value} (via: #{c_value.inspect})"
|
345
|
-
answer = ui.ask_question("Use current value or expected value for #{p_key} [current/expected]?", :valid => [
|
345
|
+
answer = ui.ask_question("Use current value or expected value for #{p_key} [current/expected]?", :valid => ["current", "expected"])
|
346
346
|
else
|
347
347
|
answer = config[:parameter_validation]
|
348
348
|
end
|
349
|
-
answer ==
|
349
|
+
answer == "expected"
|
350
350
|
else
|
351
351
|
true
|
352
352
|
end
|
@@ -1,7 +1,7 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "sfn"
|
2
|
+
require "sparkle_formation"
|
3
3
|
|
4
|
-
require
|
4
|
+
require "pathname"
|
5
5
|
|
6
6
|
module Sfn
|
7
7
|
module CommandModule
|
@@ -48,7 +48,7 @@ module Sfn
|
|
48
48
|
def request_compile_parameter(p_name, p_config, cur_val, nested = false)
|
49
49
|
result = nil
|
50
50
|
attempts = 0
|
51
|
-
parameter_type = p_config.fetch(:type,
|
51
|
+
parameter_type = p_config.fetch(:type, "string").to_s.downcase.to_sym
|
52
52
|
if parameter_type == :complex
|
53
53
|
ui.debug "Compile time parameter `#{p_name}` is a complex type. Not requesting value from user."
|
54
54
|
if cur_val.nil?
|
@@ -61,13 +61,13 @@ module Sfn
|
|
61
61
|
cur_val = p_config[:default]
|
62
62
|
end
|
63
63
|
if cur_val.is_a?(Array)
|
64
|
-
cur_val = cur_val.map(&:to_s).join(
|
64
|
+
cur_val = cur_val.map(&:to_s).join(",")
|
65
65
|
end
|
66
66
|
until result && (!result.respond_to?(:empty?) || !result.empty?)
|
67
67
|
attempts += 1
|
68
68
|
if config[:interactive_parameters] && (!nested || !p_config.key?(:prompt_when_nested) || p_config[:prompt_when_nested] == true)
|
69
69
|
result = ui.ask_question(
|
70
|
-
p_name.to_s.split(
|
70
|
+
p_name.to_s.split("_").map(&:capitalize).join,
|
71
71
|
:default => cur_val.to_s.empty? ? nil : cur_val.to_s,
|
72
72
|
)
|
73
73
|
else
|
@@ -76,11 +76,11 @@ module Sfn
|
|
76
76
|
case parameter_type
|
77
77
|
when :string
|
78
78
|
if p_config[:multiple]
|
79
|
-
result = result.split(
|
79
|
+
result = result.split(",").map(&:strip)
|
80
80
|
end
|
81
81
|
when :number
|
82
82
|
if p_config[:multiple]
|
83
|
-
result = result.split(
|
83
|
+
result = result.split(",").map(&:strip)
|
84
84
|
new_result = result.map do |item|
|
85
85
|
new_item = item.to_i
|
86
86
|
new_item if new_item.to_s == item
|
@@ -97,7 +97,7 @@ module Sfn
|
|
97
97
|
unless valid == true
|
98
98
|
result = nil
|
99
99
|
valid.each do |invalid_msg|
|
100
|
-
ui.error invalid_msg.last
|
100
|
+
ui.error "#{p_name}: #{invalid_msg.last}"
|
101
101
|
end
|
102
102
|
end
|
103
103
|
if result.nil? || (result.respond_to?(:empty?) && result.empty?)
|
@@ -150,7 +150,7 @@ module Sfn
|
|
150
150
|
end
|
151
151
|
collection.set_root(root_pack)
|
152
152
|
rescue Errno::ENOENT
|
153
|
-
ui.warn
|
153
|
+
ui.warn "No local SparkleFormation files detected"
|
154
154
|
end
|
155
155
|
sparkle_packs.each do |pack|
|
156
156
|
collection.add_sparkle(pack)
|
@@ -185,8 +185,8 @@ module Sfn
|
|
185
185
|
end
|
186
186
|
sf.compile_time_parameter_setter do |formation|
|
187
187
|
f_name = formation.root_path.map(&:name).map(&:to_s)
|
188
|
-
pathed_name = f_name.join(
|
189
|
-
f_name = f_name.join(
|
188
|
+
pathed_name = f_name.join(" > ")
|
189
|
+
f_name = f_name.join("__")
|
190
190
|
if formation.root? && compile_state[f_name].nil?
|
191
191
|
current_state = compile_state
|
192
192
|
else
|
@@ -200,7 +200,7 @@ module Sfn
|
|
200
200
|
current_state = current_state.merge(formation.compile_state)
|
201
201
|
end
|
202
202
|
unless formation.parameters.empty?
|
203
|
-
ui.info "#{ui.color(
|
203
|
+
ui.info "#{ui.color("Compile time parameters:", :bold)} - template: #{ui.color(pathed_name, :green, :bold)}" unless config[:print_only]
|
204
204
|
formation.parameters.each do |k, v|
|
205
205
|
valid_keys = [
|
206
206
|
"#{f_name}__#{k}",
|
@@ -251,7 +251,7 @@ module Sfn
|
|
251
251
|
template
|
252
252
|
end
|
253
253
|
else
|
254
|
-
raise ArgumentError.new
|
254
|
+
raise ArgumentError.new "Failed to locate template for processing!"
|
255
255
|
end
|
256
256
|
end
|
257
257
|
|
@@ -262,7 +262,7 @@ module Sfn
|
|
262
262
|
ui.debug "Initial compile parameters - #{compile_state}"
|
263
263
|
compile_state.keys.each do |cs_key|
|
264
264
|
unless cs_key.to_s.start_with?("#{arguments.first}__")
|
265
|
-
named_cs_key = [arguments.first, cs_key].compact.join(
|
265
|
+
named_cs_key = [arguments.first, cs_key].compact.join("__")
|
266
266
|
non_named = compile_state.delete(cs_key)
|
267
267
|
if non_named && !compile_state.key?(named_cs_key)
|
268
268
|
ui.debug "Setting non-named compile parameter `#{cs_key}` into `#{named_cs_key}`"
|
@@ -282,8 +282,8 @@ module Sfn
|
|
282
282
|
# Force user friendly error if nesting bucket is not set within configuration
|
283
283
|
def validate_nesting_bucket!
|
284
284
|
if config[:nesting_bucket].to_s.empty?
|
285
|
-
ui.error
|
286
|
-
raise ArgumentError.new
|
285
|
+
ui.error "Missing required configuration value for `nesting_bucket`. Cannot generated nested templates!"
|
286
|
+
raise ArgumentError.new "Required configuration value for `nesting_bucket` not provided."
|
287
287
|
end
|
288
288
|
end
|
289
289
|
|
@@ -307,13 +307,13 @@ module Sfn
|
|
307
307
|
end
|
308
308
|
file = bucket.files.build
|
309
309
|
file.name = "#{name_args.first}_#{stack_name}.json"
|
310
|
-
file.content_type =
|
310
|
+
file.content_type = "text/json"
|
311
311
|
file.body = MultiJson.dump(parameter_scrub!(stack_definition))
|
312
312
|
file.save
|
313
313
|
url = URI.parse(file.url)
|
314
314
|
template_url = "#{url.scheme}://#{url.host}#{url.path}"
|
315
315
|
end
|
316
|
-
resource.properties.set!(
|
316
|
+
resource.properties.set!("TemplateURL", template_url)
|
317
317
|
end
|
318
318
|
end
|
319
319
|
|
@@ -331,16 +331,16 @@ module Sfn
|
|
331
331
|
if current_stack && current_stack.data[:parent_stack]
|
332
332
|
current_parameters.merge!(
|
333
333
|
current_stack.data[:parent_stack].template.fetch(
|
334
|
-
|
335
|
-
|
334
|
+
"Resources", stack_name, "Properties", "Parameters", current_stack.data[:parent_stack].template.fetch(
|
335
|
+
"resources", stack_name, "properties", "parameters", Smash.new
|
336
336
|
)
|
337
337
|
)
|
338
338
|
)
|
339
339
|
end
|
340
340
|
full_stack_name = [
|
341
341
|
config[:nesting_prefix],
|
342
|
-
stack.root_path.map(&:name).map(&:to_s).join(
|
343
|
-
].compact.join(
|
342
|
+
stack.root_path.map(&:name).map(&:to_s).join("_"),
|
343
|
+
].compact.join("/")
|
344
344
|
unless config[:print_only]
|
345
345
|
result = Smash.new(
|
346
346
|
:parameters => populate_parameters!(stack,
|
@@ -390,7 +390,7 @@ module Sfn
|
|
390
390
|
end
|
391
391
|
file = bucket.files.build
|
392
392
|
file.name = "#{full_stack_name}.json"
|
393
|
-
file.content_type =
|
393
|
+
file.content_type = "text/json"
|
394
394
|
file.body = MultiJson.dump(parameter_scrub!(stack_definition))
|
395
395
|
file.save
|
396
396
|
result.merge!(
|
@@ -422,9 +422,9 @@ module Sfn
|
|
422
422
|
# @return [Hash]
|
423
423
|
def scrub_template(template)
|
424
424
|
template = parameter_scrub!(template)
|
425
|
-
(template[
|
426
|
-
if valid_stack_types.include?(r_content[
|
427
|
-
result = (r_content[
|
425
|
+
(template["Resources"] || {}).each do |r_name, r_content|
|
426
|
+
if valid_stack_types.include?(r_content["Type"])
|
427
|
+
result = (r_content["Properties"] || {}).delete("Stack")
|
428
428
|
end
|
429
429
|
end
|
430
430
|
template
|
@@ -439,11 +439,11 @@ module Sfn
|
|
439
439
|
case provider
|
440
440
|
when :aws
|
441
441
|
if results[:parameters]
|
442
|
-
results[
|
442
|
+
results["Parameters"] = results.delete(:parameters)
|
443
443
|
end
|
444
444
|
if results[:url]
|
445
445
|
url = URI.parse(results.delete(:url))
|
446
|
-
results[
|
446
|
+
results["TemplateURL"] = "#{url.scheme}://#{url.host}#{url.path}"
|
447
447
|
end
|
448
448
|
results
|
449
449
|
when :heat, :rackspace
|
@@ -461,10 +461,10 @@ module Sfn
|
|
461
461
|
if results[:url]
|
462
462
|
results[:templateLink] = Smash.new(
|
463
463
|
:uri => results.delete(:url),
|
464
|
-
:contentVersion =>
|
464
|
+
:contentVersion => "1.0.0.0",
|
465
465
|
)
|
466
466
|
end
|
467
|
-
results[:mode] =
|
467
|
+
results[:mode] = "Incremental"
|
468
468
|
results
|
469
469
|
else
|
470
470
|
raise "Unknown stack provider value given! `#{provider}`"
|
@@ -491,7 +491,7 @@ module Sfn
|
|
491
491
|
translator = klass.new(template, args)
|
492
492
|
translator.translate!
|
493
493
|
template = translator.translated
|
494
|
-
ui.info "#{ui.color(
|
494
|
+
ui.info "#{ui.color("Translation applied:", :bold)} #{ui.color(klass_name, :yellow)}"
|
495
495
|
end
|
496
496
|
template
|
497
497
|
end
|
@@ -530,9 +530,9 @@ module Sfn
|
|
530
530
|
# @return [String] path to template
|
531
531
|
def prompt_for_template(prefix = nil)
|
532
532
|
if prefix
|
533
|
-
collection_name = prefix.split(
|
534
|
-
c_name.split(
|
535
|
-
end.join(
|
533
|
+
collection_name = prefix.split("__").map do |c_name|
|
534
|
+
c_name.split("_").map(&:capitalize).join(" ")
|
535
|
+
end.join(" / ")
|
536
536
|
ui.info "Viewing collection: #{ui.color(collection_name, :bold)}"
|
537
537
|
template_names = sparkle_collection.templates.fetch(provider.connection.provider, {}).keys.find_all do |t_name|
|
538
538
|
t_name.to_s.start_with?(prefix.to_s)
|
@@ -541,46 +541,46 @@ module Sfn
|
|
541
541
|
template_names = sparkle_collection.templates.fetch(provider.connection.provider, {}).keys
|
542
542
|
end
|
543
543
|
collections = template_names.map do |t_name|
|
544
|
-
t_name = t_name.to_s.sub(/^#{Regexp.escape(prefix.to_s)}/,
|
545
|
-
if t_name.include?(
|
546
|
-
c_name = t_name.split(
|
547
|
-
[[prefix, c_name].compact.join(
|
544
|
+
t_name = t_name.to_s.sub(/^#{Regexp.escape(prefix.to_s)}/, "")
|
545
|
+
if t_name.include?("__")
|
546
|
+
c_name = t_name.split("__").first
|
547
|
+
[[prefix, c_name].compact.join("") + "__", c_name]
|
548
548
|
end
|
549
549
|
end.compact.uniq(&:first)
|
550
550
|
templates = template_names.map do |t_name|
|
551
|
-
t_name = t_name.to_s.sub(/^#{Regexp.escape(prefix.to_s)}/,
|
552
|
-
unless t_name.include?(
|
553
|
-
[[prefix, t_name].compact.join(
|
551
|
+
t_name = t_name.to_s.sub(/^#{Regexp.escape(prefix.to_s)}/, "")
|
552
|
+
unless t_name.include?("__")
|
553
|
+
[[prefix, t_name].compact.join(""), t_name]
|
554
554
|
end
|
555
555
|
end.compact
|
556
556
|
if collections.empty? && templates.empty?
|
557
|
-
ui.error
|
557
|
+
ui.error "Failed to locate any templates!"
|
558
558
|
return nil
|
559
559
|
end
|
560
|
-
ui.info "Please select an entry#{
|
560
|
+
ui.info "Please select an entry#{"(or collection to list)" unless collections.empty?}:"
|
561
561
|
output = []
|
562
562
|
idx = 1
|
563
563
|
valid = {}
|
564
564
|
unless collections.empty?
|
565
|
-
output << ui.color(
|
565
|
+
output << ui.color("Collections:", :bold)
|
566
566
|
collections.each do |full_name, part_name|
|
567
567
|
valid[idx] = {:name => full_name, :type => :collection}
|
568
|
-
output << [idx, part_name.split(
|
568
|
+
output << [idx, part_name.split("_").map(&:capitalize).join(" ")]
|
569
569
|
idx += 1
|
570
570
|
end
|
571
571
|
end
|
572
572
|
unless templates.empty?
|
573
|
-
output << ui.color(
|
573
|
+
output << ui.color("Templates:", :bold)
|
574
574
|
templates.each do |full_name, part_name|
|
575
575
|
valid[idx] = {:name => full_name, :type => :template}
|
576
|
-
output << [idx, part_name.split(
|
576
|
+
output << [idx, part_name.split("_").map(&:capitalize).join(" ")]
|
577
577
|
idx += 1
|
578
578
|
end
|
579
579
|
end
|
580
580
|
max = idx.to_s.length
|
581
581
|
output.map! do |line|
|
582
582
|
if line.is_a?(Array)
|
583
|
-
" #{line.first}.#{
|
583
|
+
" #{line.first}.#{" " * (max - line.first.to_s.length)} #{line.last}"
|
584
584
|
else
|
585
585
|
line
|
586
586
|
end
|
@@ -588,7 +588,7 @@ module Sfn
|
|
588
588
|
ui.puts "#{output.join("\n")}\n"
|
589
589
|
response = nil
|
590
590
|
until valid[response]
|
591
|
-
response = ui.ask_question(
|
591
|
+
response = ui.ask_question("Enter selection").to_i
|
592
592
|
end
|
593
593
|
entry = valid[response]
|
594
594
|
if entry[:type] == :collection
|