sfn 3.0.28 → 3.0.30
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 +5 -5
- data/CHANGELOG.md +5 -0
- data/docs/callbacks.md +1 -0
- data/lib/chef/knife/knife_plugin_seed.rb +11 -17
- data/lib/sfn.rb +0 -2
- data/lib/sfn/api_provider.rb +0 -2
- data/lib/sfn/api_provider/google.rb +6 -9
- data/lib/sfn/api_provider/terraform.rb +4 -6
- data/lib/sfn/cache.rb +36 -39
- data/lib/sfn/callback.rb +0 -2
- data/lib/sfn/callback/aws_assume_role.rb +7 -8
- data/lib/sfn/callback/aws_mfa.rb +7 -8
- data/lib/sfn/callback/stack_policy.rb +15 -17
- data/lib/sfn/command.rb +9 -11
- data/lib/sfn/command/conf.rb +7 -10
- data/lib/sfn/command/create.rb +8 -12
- data/lib/sfn/command/describe.rb +6 -8
- data/lib/sfn/command/destroy.rb +8 -10
- data/lib/sfn/command/diff.rb +18 -25
- data/lib/sfn/command/events.rb +15 -16
- data/lib/sfn/command/export.rb +13 -17
- data/lib/sfn/command/graph.rb +11 -13
- data/lib/sfn/command/graph/aws.rb +27 -29
- data/lib/sfn/command/graph/terraform.rb +22 -23
- data/lib/sfn/command/import.rb +13 -16
- data/lib/sfn/command/init.rb +5 -7
- data/lib/sfn/command/inspect.rb +26 -29
- data/lib/sfn/command/lint.rb +10 -12
- data/lib/sfn/command/list.rb +5 -8
- data/lib/sfn/command/print.rb +3 -5
- data/lib/sfn/command/promote.rb +0 -2
- data/lib/sfn/command/update.rb +42 -46
- data/lib/sfn/command/validate.rb +4 -6
- data/lib/sfn/command_module/base.rb +17 -25
- data/lib/sfn/command_module/callbacks.rb +12 -8
- data/lib/sfn/command_module/stack.rb +39 -43
- data/lib/sfn/command_module/template.rb +89 -90
- data/lib/sfn/config.rb +30 -31
- data/lib/sfn/config/conf.rb +1 -3
- data/lib/sfn/config/create.rb +5 -7
- data/lib/sfn/config/describe.rb +3 -5
- data/lib/sfn/config/diff.rb +1 -1
- data/lib/sfn/config/events.rb +6 -8
- data/lib/sfn/config/export.rb +4 -7
- data/lib/sfn/config/graph.rb +4 -6
- data/lib/sfn/config/import.rb +3 -5
- data/lib/sfn/config/init.rb +0 -1
- data/lib/sfn/config/inspect.rb +7 -9
- data/lib/sfn/config/lint.rb +4 -4
- data/lib/sfn/config/list.rb +3 -5
- data/lib/sfn/config/print.rb +3 -5
- data/lib/sfn/config/promote.rb +3 -5
- data/lib/sfn/config/update.rb +10 -12
- data/lib/sfn/config/validate.rb +18 -20
- data/lib/sfn/lint.rb +0 -2
- data/lib/sfn/lint/definition.rb +3 -5
- data/lib/sfn/lint/rule.rb +7 -8
- data/lib/sfn/lint/rule_set.rb +11 -20
- data/lib/sfn/monkey_patch/stack.rb +32 -34
- data/lib/sfn/monkey_patch/stack/azure.rb +0 -1
- data/lib/sfn/monkey_patch/stack/google.rb +15 -16
- data/lib/sfn/planner.rb +1 -3
- data/lib/sfn/planner/aws.rb +82 -89
- data/lib/sfn/provider.rb +21 -23
- data/lib/sfn/utils.rb +0 -2
- data/lib/sfn/utils/debug.rb +1 -2
- data/lib/sfn/utils/json.rb +3 -2
- data/lib/sfn/utils/object_storage.rb +1 -2
- data/lib/sfn/utils/output.rb +8 -9
- data/lib/sfn/utils/path_selector.rb +9 -10
- data/lib/sfn/utils/ssher.rb +2 -3
- data/lib/sfn/utils/stack_exporter.rb +20 -21
- data/lib/sfn/utils/stack_parameter_scrubber.rb +6 -7
- data/lib/sfn/utils/stack_parameter_validator.rb +14 -16
- data/lib/sfn/version.rb +1 -1
- data/sfn.gemspec +1 -1
- metadata +8 -8
@@ -6,7 +6,6 @@ module Sfn
|
|
6
6
|
|
7
7
|
# Expand stack model functionality
|
8
8
|
module Stack
|
9
|
-
|
10
9
|
autoload :Azure, 'sfn/monkey_patch/stack/azure'
|
11
10
|
autoload :Google, 'sfn/monkey_patch/stack/google'
|
12
11
|
|
@@ -92,7 +91,7 @@ module Sfn
|
|
92
91
|
|
93
92
|
# @return [String] action currently being performed
|
94
93
|
def performing
|
95
|
-
if
|
94
|
+
if in_progress?
|
96
95
|
status.to_s.downcase.split('_').first.to_sym
|
97
96
|
end
|
98
97
|
end
|
@@ -140,10 +139,10 @@ module Sfn
|
|
140
139
|
# @param min [Integer] lowest allowed return value (defaults 5)
|
141
140
|
# @return [Integer] percent complete (0..100)
|
142
141
|
def percent_complete(min = 5)
|
143
|
-
if
|
142
|
+
if self.respond_to?("percent_complete_#{api.provider}")
|
144
143
|
self.send("percent_complete_#{api.provider}", min)
|
145
144
|
else
|
146
|
-
if
|
145
|
+
if in_progress?
|
147
146
|
total_resources = template.fetch('Resources', []).size
|
148
147
|
total_complete = resources.all.find_all do |resource|
|
149
148
|
resource.status.downcase.end_with?('complete')
|
@@ -166,21 +165,21 @@ module Sfn
|
|
166
165
|
# @return [self]
|
167
166
|
# @note setting `DisableApply` within parameter hash will
|
168
167
|
# prevent parameters being overridden
|
169
|
-
def apply_stack(remote_stack, opts={}, ignore_params=nil)
|
170
|
-
if
|
168
|
+
def apply_stack(remote_stack, opts = {}, ignore_params = nil)
|
169
|
+
if self.respond_to?("apply_stack_#{api.provider}")
|
171
170
|
self.send("apply_stack_#{api.provider}", remote_stack, opts, ignore_params)
|
172
171
|
else
|
173
|
-
unless
|
172
|
+
unless opts[:mapping]
|
174
173
|
opts[:mapping] = {}
|
175
174
|
end
|
176
|
-
if
|
175
|
+
if opts[:parameter_key]
|
177
176
|
stack_parameters = template[opts[:parameter_key]]
|
178
177
|
default_key = opts.fetch(
|
179
178
|
:default_key,
|
180
|
-
opts[:parameter_key].to_s[0,1].match(/[a-z]/) ? 'default' : 'Default'
|
179
|
+
opts[:parameter_key].to_s[0, 1].match(/[a-z]/) ? 'default' : 'Default'
|
181
180
|
)
|
182
181
|
else
|
183
|
-
if
|
182
|
+
if template['Parameters']
|
184
183
|
default_key = 'Default'
|
185
184
|
stack_parameters = template['Parameters']
|
186
185
|
else
|
@@ -188,11 +187,11 @@ module Sfn
|
|
188
187
|
stack_parameters = template['parameters']
|
189
188
|
end
|
190
189
|
end
|
191
|
-
if
|
190
|
+
if stack_parameters
|
192
191
|
valid_parameters = stack_parameters.find_all do |key, val|
|
193
192
|
!val['DisableApply'] && !val['disable_apply']
|
194
193
|
end.map(&:first)
|
195
|
-
if
|
194
|
+
if ignore_params
|
196
195
|
valid_parameters.reject! do |key|
|
197
196
|
ignore_params.include?(key)
|
198
197
|
end
|
@@ -202,17 +201,17 @@ module Sfn
|
|
202
201
|
p_key = valid_parameters.detect do |v_param|
|
203
202
|
v_param.downcase.tr('_', '') == o_key
|
204
203
|
end
|
205
|
-
unless
|
204
|
+
unless p_key
|
206
205
|
map_key = opts[:mapping].keys.detect do |map_key|
|
207
206
|
map_key.downcase.tr('_', '') == o_key
|
208
207
|
end
|
209
|
-
if
|
208
|
+
if map_key
|
210
209
|
p_key = valid_parameters.detect do |v_param|
|
211
210
|
v_param.downcase.tr('_', '') == opts[:mapping][map_key].downcase.tr('_', '')
|
212
211
|
end
|
213
212
|
end
|
214
213
|
end
|
215
|
-
if
|
214
|
+
if p_key
|
216
215
|
self.parameters = parameters.merge(p_key => output.value)
|
217
216
|
end
|
218
217
|
end
|
@@ -225,30 +224,30 @@ module Sfn
|
|
225
224
|
#
|
226
225
|
# @param recurse [TrueClass, FalseClass] recurse to fetch _all_ stacks
|
227
226
|
# @return [Array<Miasma::Models::Orchestration::Stack>]
|
228
|
-
def nested_stacks(recurse=true)
|
229
|
-
if
|
227
|
+
def nested_stacks(recurse = true)
|
228
|
+
if self.respond_to?("nested_stacks_#{api.provider}")
|
230
229
|
self.send("nested_stacks_#{api.provider}", recurse)
|
231
230
|
else
|
232
231
|
resources.reload.all.map do |resource|
|
233
|
-
if
|
232
|
+
if api.data.fetch(:stack_types, []).include?(resource.type)
|
234
233
|
# Custom remote load support
|
235
|
-
if
|
234
|
+
if resource.type == 'Custom::JackalStack'
|
236
235
|
location, stack_id = resource.id.to_s.split('-', 2)
|
237
|
-
if
|
236
|
+
if l_conf = api.data[:locations][location]
|
238
237
|
n_stack = Miasma.api(
|
239
238
|
:type => :orchestration,
|
240
239
|
:provider => l_conf[:provider],
|
241
|
-
:credentials => l_conf
|
240
|
+
:credentials => l_conf,
|
242
241
|
).stacks.get(stack_id)
|
243
242
|
end
|
244
243
|
else
|
245
244
|
n_stack = resource.expand
|
246
245
|
end
|
247
|
-
if
|
246
|
+
if n_stack
|
248
247
|
n_stack.data[:logical_id] = resource.name
|
249
248
|
n_stack.data[:parent_stack] = self
|
250
249
|
n_stack.api.data[:stack_types] = api.data[:stack_types]
|
251
|
-
if
|
250
|
+
if recurse
|
252
251
|
[n_stack] + n_stack.nested_stacks(recurse)
|
253
252
|
else
|
254
253
|
n_stack
|
@@ -261,7 +260,7 @@ module Sfn
|
|
261
260
|
|
262
261
|
# @return [TrueClass, FalseClass] stack contains nested stacks
|
263
262
|
def nested?
|
264
|
-
if
|
263
|
+
if self.respond_to?("nested_#{api.provider}?")
|
265
264
|
self.send("nested_#{api.provider}?")
|
266
265
|
else
|
267
266
|
!!resources.detect do |resource|
|
@@ -274,22 +273,22 @@ module Sfn
|
|
274
273
|
#
|
275
274
|
# @return [Smash, NilClass]
|
276
275
|
def policy
|
277
|
-
if
|
276
|
+
if self.respond_to?("policy_#{api.provider}")
|
278
277
|
self.send("policy_#{api.provider}")
|
279
278
|
else
|
280
|
-
if(self.api.provider == :aws) # cause this is the only one
|
279
|
+
if (self.api.provider == :aws) # cause this is the only one
|
281
280
|
begin
|
282
281
|
result = self.api.request(
|
283
282
|
:path => '/',
|
284
283
|
:form => Smash.new(
|
285
284
|
'Action' => 'GetStackPolicy',
|
286
|
-
'StackName' => self.id
|
287
|
-
)
|
285
|
+
'StackName' => self.id,
|
286
|
+
),
|
288
287
|
)
|
289
288
|
serialized_policy = result.get(:body, 'GetStackPolicyResult', 'StackPolicyBody')
|
290
289
|
MultiJson.load(serialized_policy).to_smash
|
291
290
|
rescue Miasma::Error::ApiError::RequestError => e
|
292
|
-
if
|
291
|
+
if e.response.code == 404
|
293
292
|
nil
|
294
293
|
else
|
295
294
|
raise
|
@@ -307,10 +306,10 @@ module Sfn
|
|
307
306
|
# contain any direct values for parameters (which is what we
|
308
307
|
# are testing for)
|
309
308
|
def nesting_style
|
310
|
-
if
|
309
|
+
if self.respond_to?("nesting_style_#{api.provider}")
|
311
310
|
self.send("nesting_style_#{api.provider}")
|
312
311
|
else
|
313
|
-
if
|
312
|
+
if nested?
|
314
313
|
self.template['Resources'].find_all do |t_resource|
|
315
314
|
t_resource['Type'] == self.api.class.const_get(:RESOURCE_MAPPING).key(self.class)
|
316
315
|
end.detect do |t_resource|
|
@@ -326,7 +325,7 @@ module Sfn
|
|
326
325
|
#
|
327
326
|
# @return [Hash]
|
328
327
|
def sparkleish_template(*args)
|
329
|
-
if
|
328
|
+
if self.respond_to?("sparkleish_template_#{api.provider}")
|
330
329
|
self.send("sparkleish_template_#{api.provider}", *args)
|
331
330
|
else
|
332
331
|
template
|
@@ -337,13 +336,12 @@ module Sfn
|
|
337
336
|
#
|
338
337
|
# @return [Hash]
|
339
338
|
def root_parameters
|
340
|
-
if
|
339
|
+
if self.respond_to?("root_parameters_#{api.provider}")
|
341
340
|
self.send("root_parameters_#{api.provider}")
|
342
341
|
else
|
343
342
|
parameters
|
344
343
|
end
|
345
344
|
end
|
346
|
-
|
347
345
|
end
|
348
346
|
end
|
349
347
|
end
|
@@ -25,7 +25,7 @@ module Sfn
|
|
25
25
|
collection = Miasma::Models::Orchestration::Stack::Resources.new(self)
|
26
26
|
collection.define_singleton_method(:perform_population) do
|
27
27
|
valid = stack.sparkleish_template.fetch(:resources, {}).keys
|
28
|
-
stack.custom[:resources].find_all{|r| valid.include?(r[:name])}.map do |attrs|
|
28
|
+
stack.custom[:resources].find_all { |r| valid.include?(r[:name]) }.map do |attrs|
|
29
29
|
Miasma::Models::Orchestration::Stack::Resource.new(stack, attrs).valid_state
|
30
30
|
end
|
31
31
|
end
|
@@ -35,7 +35,7 @@ module Sfn
|
|
35
35
|
# Sub-stacks never provide events
|
36
36
|
def events
|
37
37
|
collection = Miasma::Models::Orchestration::Stack::Events.new(self)
|
38
|
-
collection.define_singleton_method(:perform_population){ [] }
|
38
|
+
collection.define_singleton_method(:perform_population) { [] }
|
39
39
|
collection
|
40
40
|
end
|
41
41
|
end
|
@@ -44,33 +44,33 @@ module Sfn
|
|
44
44
|
#
|
45
45
|
# @param recurse [TrueClass, FalseClass] recurse to fetch _all_ stacks
|
46
46
|
# @return [Array<Miasma::Models::Orchestration::Stack>]
|
47
|
-
def nested_stacks_google(recurse=true)
|
47
|
+
def nested_stacks_google(recurse = true)
|
48
48
|
my_template = sparkleish_template
|
49
|
-
if
|
49
|
+
if my_template[:resources][name]
|
50
50
|
my_template = my_template.get(:resources, name, :properties, :stack)
|
51
51
|
end
|
52
52
|
n_stacks = my_template[:resources].map do |s_name, content|
|
53
|
-
if
|
53
|
+
if content[:type] == 'sparkleformation.stack'
|
54
54
|
n_stack = self.class.new(api)
|
55
55
|
n_stack.extend PretendStack
|
56
|
-
n_layout = custom.fetch(:layout, {}).fetch(:resources, []).detect{|r| r[:name] == name}
|
57
|
-
n_layout = (n_layout || custom.fetch(:layout, {})).fetch(:resources, []).detect{|r| r[:name] == s_name} || Smash.new
|
56
|
+
n_layout = custom.fetch(:layout, {}).fetch(:resources, []).detect { |r| r[:name] == name }
|
57
|
+
n_layout = (n_layout || custom.fetch(:layout, {})).fetch(:resources, []).detect { |r| r[:name] == s_name } || Smash.new
|
58
58
|
n_stack.load_data(
|
59
59
|
:name => s_name,
|
60
60
|
:id => s_name,
|
61
61
|
:template => content.get(:properties, :stack),
|
62
|
-
:outputs => n_layout.fetch('outputs', []).map{|o_val| Smash.new(:key => o_val[:name], :value => o_val['finalValue'])},
|
62
|
+
:outputs => n_layout.fetch('outputs', []).map { |o_val| Smash.new(:key => o_val[:name], :value => o_val['finalValue']) },
|
63
63
|
:custom => {
|
64
64
|
:resources => resources.all.map(&:attributes),
|
65
|
-
:layout => n_layout
|
66
|
-
}
|
65
|
+
:layout => n_layout,
|
66
|
+
},
|
67
67
|
).valid_state
|
68
68
|
n_stack.data[:logical_id] = s_name
|
69
69
|
n_stack.data[:parent_stack] = self
|
70
70
|
n_stack
|
71
71
|
end
|
72
72
|
end.compact
|
73
|
-
if
|
73
|
+
if recurse
|
74
74
|
(n_stacks + n_stacks.map(&:nested_stacks)).flatten.compact
|
75
75
|
else
|
76
76
|
n_stacks
|
@@ -84,18 +84,18 @@ module Sfn
|
|
84
84
|
result = template.to_smash
|
85
85
|
(result.delete(:resources) || []).each do |t_resource|
|
86
86
|
t_name = t_resource.delete(:name)
|
87
|
-
if
|
87
|
+
if t_resource[:type].to_s.end_with?('.jinja')
|
88
88
|
schema = copy_template.fetch(:config, :content, :imports, []).delete("#{t_resource[:type]}.schema")
|
89
89
|
schema_content = copy_template.fetch(:imports, []).detect do |s_item|
|
90
90
|
s_item[:name] == schema
|
91
91
|
end
|
92
|
-
if
|
92
|
+
if schema_content
|
93
93
|
t_resource.set(:parameters, schema_content.get(:content, :properties))
|
94
94
|
end
|
95
95
|
n_template = copy_template.fetch(:imports, []).detect do |s_item|
|
96
96
|
s_item[:name] == t_resource[:type]
|
97
97
|
end
|
98
|
-
if
|
98
|
+
if n_template
|
99
99
|
t_resource[:type] = 'sparkleformation.stack'
|
100
100
|
current_properties = t_resource.delete(:properties)
|
101
101
|
t_resource.set(:properties, :parameters, current_properties) if current_properties
|
@@ -107,7 +107,7 @@ module Sfn
|
|
107
107
|
result
|
108
108
|
end
|
109
109
|
s_template = deref.call(Smash.new(:resources => copy_template.get(:config, :content, :resources)))
|
110
|
-
if
|
110
|
+
if s_template.empty?
|
111
111
|
template.to_smash
|
112
112
|
else
|
113
113
|
layout = custom.fetch(:layout, {}).to_smash
|
@@ -122,7 +122,6 @@ module Sfn
|
|
122
122
|
def root_parameters_google
|
123
123
|
sparkleish_template.fetch(:resources, name, :properties, :parameters, Smash.new)
|
124
124
|
end
|
125
|
-
|
126
125
|
end
|
127
126
|
end
|
128
127
|
end
|
data/lib/sfn/planner.rb
CHANGED
@@ -3,7 +3,6 @@ require 'sfn'
|
|
3
3
|
module Sfn
|
4
4
|
# Interface for generating plan report
|
5
5
|
class Planner
|
6
|
-
|
7
6
|
autoload :Aws, 'sfn/planner/aws'
|
8
7
|
|
9
8
|
# Value to flag runtime modification
|
@@ -29,7 +28,7 @@ module Sfn
|
|
29
28
|
# @param opts [Hash]
|
30
29
|
#
|
31
30
|
# @return [self]
|
32
|
-
def initialize(ui, config, arguments, stack, opts={})
|
31
|
+
def initialize(ui, config, arguments, stack, opts = {})
|
33
32
|
@ui = ui
|
34
33
|
@config = config
|
35
34
|
@arguments = arguments
|
@@ -46,6 +45,5 @@ module Sfn
|
|
46
45
|
def generate_plan(template, parameters)
|
47
46
|
raise NotImplementedError
|
48
47
|
end
|
49
|
-
|
50
48
|
end
|
51
49
|
end
|
data/lib/sfn/planner/aws.rb
CHANGED
@@ -9,7 +9,6 @@ module Sfn
|
|
9
9
|
|
10
10
|
# Customized translator to dereference template
|
11
11
|
class Translator < SparkleFormation::Translation
|
12
|
-
|
13
12
|
MAP = {}
|
14
13
|
REF_MAPPING = {}
|
15
14
|
FN_MAPPING = {}
|
@@ -20,7 +19,7 @@ module Sfn
|
|
20
19
|
attr_reader :flagged
|
21
20
|
|
22
21
|
# Override to init flagged array
|
23
|
-
def initialize(template_hash, args={})
|
22
|
+
def initialize(template_hash, args = {})
|
24
23
|
super
|
25
24
|
@flagged = []
|
26
25
|
end
|
@@ -54,19 +53,19 @@ module Sfn
|
|
54
53
|
# @return [Hash]
|
55
54
|
# @note also allows 'Ref' within funcs to provide mapping
|
56
55
|
# replacements using the REF_MAPPING constant
|
57
|
-
def apply_function(hash, funcs=[])
|
58
|
-
if
|
59
|
-
k,v = hash.first
|
60
|
-
if
|
56
|
+
def apply_function(hash, funcs = [])
|
57
|
+
if hash.is_a?(Hash)
|
58
|
+
k, v = hash.first
|
59
|
+
if hash.size == 1 && (k.start_with?('Fn') || k == 'Ref') && (funcs.include?(:all) || funcs.empty? || funcs.include?(k) || funcs == ['DEREF'])
|
61
60
|
method_name = Bogo::Utility.snake(k.gsub('::', ''))
|
62
|
-
if(
|
61
|
+
if (funcs.include?(k) || funcs.include?(:all)) && respond_to?(method_name)
|
63
62
|
apply_function(send(method_name, v), funcs)
|
64
63
|
else
|
65
64
|
case k
|
66
65
|
when 'Fn::GetAtt'
|
67
66
|
funcs.include?('DEREF') ? dereference(hash) : hash
|
68
67
|
when 'Ref'
|
69
|
-
if
|
68
|
+
if funcs.include?('DEREF')
|
70
69
|
dereference(hash)
|
71
70
|
else
|
72
71
|
{'Ref' => self.class.const_get(:REF_MAPPING).fetch(v, v)}
|
@@ -89,7 +88,7 @@ module Sfn
|
|
89
88
|
# @return [TrueClass, FalseClass]
|
90
89
|
def apply_condition(name)
|
91
90
|
condition = conditions[name]
|
92
|
-
if
|
91
|
+
if condition
|
93
92
|
apply_function(condition, [:all, 'DEREF'])
|
94
93
|
else
|
95
94
|
raise "Failed to locate condition with name `#{name}`!"
|
@@ -102,7 +101,7 @@ module Sfn
|
|
102
101
|
# @return [Object] true or false value
|
103
102
|
def fn_if(value)
|
104
103
|
result = apply_condition(value[0])
|
105
|
-
if
|
104
|
+
if result != UNKNOWN_RUNTIME_RESULT
|
106
105
|
result ? value[1] : value[2]
|
107
106
|
else
|
108
107
|
UNKNOWN_RUNTIME_RESULT
|
@@ -118,7 +117,7 @@ module Sfn
|
|
118
117
|
result = value.map do |val|
|
119
118
|
apply_condition(val)
|
120
119
|
end
|
121
|
-
if
|
120
|
+
if result.to_s.include?(RUNTIME_MODIFIED)
|
122
121
|
UNKNOWN_RUNTIME_RESULT
|
123
122
|
else
|
124
123
|
result.all?
|
@@ -133,7 +132,7 @@ module Sfn
|
|
133
132
|
result = value.map do |val|
|
134
133
|
apply_condition(val)
|
135
134
|
end
|
136
|
-
if
|
135
|
+
if result.to_s.include?(RUNTIME_MODIFIED)
|
137
136
|
UNKNOWN_RUNTIME_RESULT
|
138
137
|
else
|
139
138
|
result.any?
|
@@ -157,7 +156,7 @@ module Sfn
|
|
157
156
|
value = value.map do |val|
|
158
157
|
apply_function(val)
|
159
158
|
end
|
160
|
-
if
|
159
|
+
if value.to_s.include?(RUNTIME_MODIFIED)
|
161
160
|
UNKNOWN_RUNTIME_RESULT
|
162
161
|
else
|
163
162
|
value.first == value.last
|
@@ -169,7 +168,7 @@ module Sfn
|
|
169
168
|
# @param value [Array<String,Array<String>>]
|
170
169
|
# @return [String]
|
171
170
|
def fn_join(value)
|
172
|
-
unless
|
171
|
+
unless value.last.is_a?(Array)
|
173
172
|
val = value.last.to_s.split(',')
|
174
173
|
else
|
175
174
|
val = value.last
|
@@ -183,9 +182,9 @@ module Sfn
|
|
183
182
|
# @return [String, Fixnum]
|
184
183
|
def fn_find_in_map(value)
|
185
184
|
map_holder = mappings[value[0]]
|
186
|
-
if
|
185
|
+
if map_holder
|
187
186
|
map_item = map_holder[dereference(value[1])]
|
188
|
-
if
|
187
|
+
if map_item
|
189
188
|
map_item[value[2]]
|
190
189
|
else
|
191
190
|
raise "Failed to find mapping item! (#{value[0]} -> #{value[1]})"
|
@@ -202,32 +201,31 @@ module Sfn
|
|
202
201
|
# @return [Hash, String]
|
203
202
|
def dereference(hash)
|
204
203
|
result = nil
|
205
|
-
if
|
206
|
-
if
|
204
|
+
if hash.is_a?(Hash)
|
205
|
+
if hash.keys.first == 'Ref' && flagged?(hash.values.first)
|
207
206
|
result = RUNTIME_MODIFIED
|
208
|
-
elsif
|
209
|
-
if
|
210
|
-
if
|
207
|
+
elsif hash.keys.first == 'Fn::GetAtt'
|
208
|
+
if hash.values.last.last.start_with?('Outputs.')
|
209
|
+
if flagged?(hash.values.join('_'))
|
211
210
|
result = RUNTIME_MODIFIED
|
212
211
|
end
|
213
|
-
elsif
|
212
|
+
elsif flagged?(hash.values.first)
|
214
213
|
result = RUNTIME_MODIFIED
|
215
214
|
end
|
216
215
|
end
|
217
216
|
end
|
218
217
|
result = result.nil? ? super : result
|
219
|
-
unless
|
218
|
+
unless result.is_a?(Enumerable)
|
220
219
|
result = result.to_s
|
221
220
|
end
|
222
221
|
result
|
223
222
|
end
|
224
|
-
|
225
223
|
end
|
226
224
|
|
227
225
|
# Resources that will be replaced on metadata init updates
|
228
226
|
REPLACE_ON_CFN_INIT_UPDATE = [
|
229
227
|
'AWS::AutoScaling::LaunchConfiguration',
|
230
|
-
'AWS::EC2::Instance'
|
228
|
+
'AWS::EC2::Instance',
|
231
229
|
]
|
232
230
|
|
233
231
|
# @return [Smash] initialized translators
|
@@ -248,21 +246,21 @@ module Sfn
|
|
248
246
|
#
|
249
247
|
# @return [Hash] report
|
250
248
|
def generate_plan(template, parameters)
|
251
|
-
parameters = Smash[parameters.map{|k,v| [k, v.to_s]}]
|
249
|
+
parameters = Smash[parameters.map { |k, v| [k, v.to_s] }]
|
252
250
|
result = Smash.new(
|
253
251
|
:stacks => Smash.new(
|
254
252
|
origin_stack.name => plan_stack(
|
255
253
|
origin_stack,
|
256
254
|
template,
|
257
255
|
parameters
|
258
|
-
)
|
256
|
+
),
|
259
257
|
),
|
260
258
|
:added => Smash.new,
|
261
259
|
:removed => Smash.new,
|
262
260
|
:replace => Smash.new,
|
263
261
|
:interrupt => Smash.new,
|
264
262
|
:unavailable => Smash.new,
|
265
|
-
:unknown => Smash.new
|
263
|
+
:unknown => Smash.new,
|
266
264
|
)
|
267
265
|
result
|
268
266
|
end
|
@@ -274,9 +272,9 @@ module Sfn
|
|
274
272
|
# @param template [Hash]
|
275
273
|
# @return [TrueClass]
|
276
274
|
def scrub_stack_properties(template)
|
277
|
-
if
|
275
|
+
if template['Resources']
|
278
276
|
template['Resources'].each do |name, info|
|
279
|
-
if
|
277
|
+
if is_stack?(info['Type']) && info['Properties'].is_a?(Hash)
|
280
278
|
info['Properties'].delete('Stack')
|
281
279
|
end
|
282
280
|
end
|
@@ -295,7 +293,7 @@ module Sfn
|
|
295
293
|
'AWS::AccountId' => stack.id.split(':')[4],
|
296
294
|
'AWS::NotificationARNs' => stack.notification_topics,
|
297
295
|
'AWS::StackId' => stack.id,
|
298
|
-
'AWS::StackName' => stack.name
|
296
|
+
'AWS::StackName' => stack.name,
|
299
297
|
).merge(config.fetch(:planner, :global_parameters, {}))
|
300
298
|
end
|
301
299
|
|
@@ -315,14 +313,14 @@ module Sfn
|
|
315
313
|
:unavailable => Smash.new,
|
316
314
|
:unknown => Smash.new,
|
317
315
|
:outputs => Smash.new,
|
318
|
-
:n_outputs => []
|
316
|
+
:n_outputs => [],
|
319
317
|
)
|
320
318
|
|
321
319
|
origin_template = dereference_template(
|
322
320
|
"#{stack.data.checksum}_origin",
|
323
321
|
stack.template,
|
324
322
|
Smash[
|
325
|
-
stack.parameters.map do |k,v|
|
323
|
+
stack.parameters.map do |k, v|
|
326
324
|
[k, v.to_s]
|
327
325
|
end
|
328
326
|
].merge(get_global_parameters(stack))
|
@@ -333,7 +331,7 @@ module Sfn
|
|
333
331
|
|
334
332
|
new_checksum = nil
|
335
333
|
current_checksum = false
|
336
|
-
until
|
334
|
+
until new_checksum == current_checksum
|
337
335
|
current_checksum = plan_results.checksum
|
338
336
|
run_stack_diff(stack, translator_key, plan_results, origin_template, new_template, new_parameters)
|
339
337
|
new_checksum = plan_results.checksum
|
@@ -357,7 +355,7 @@ module Sfn
|
|
357
355
|
# @return [NilClass]
|
358
356
|
def scrub_plan(results)
|
359
357
|
precedence = [:unavailable, :replace, :interrupt, :unavailable, :unknown]
|
360
|
-
until
|
358
|
+
until precedence.empty?
|
361
359
|
key = precedence.shift
|
362
360
|
results[key].keys.each do |k|
|
363
361
|
precedence.each do |p_key|
|
@@ -380,9 +378,9 @@ module Sfn
|
|
380
378
|
def run_stack_diff(stack, t_key, plan_results, origin_template, new_template, new_parameters)
|
381
379
|
translator = translator_for(t_key)
|
382
380
|
new_parameters = new_parameters.dup
|
383
|
-
if
|
384
|
-
stack.parameters.each do |k,v|
|
385
|
-
if
|
381
|
+
if stack.parameters
|
382
|
+
stack.parameters.each do |k, v|
|
383
|
+
if new_parameters[k].is_a?(Hash)
|
386
384
|
val = translator.dereference(new_parameters[k])
|
387
385
|
new_parameters[k] = val == new_parameters[k] ? v : val
|
388
386
|
end
|
@@ -406,7 +404,7 @@ module Sfn
|
|
406
404
|
plan_results, a_path, diff_items, translator_for(t_key),
|
407
405
|
Smash.new(
|
408
406
|
:origin => origin_template,
|
409
|
-
:update => update_template
|
407
|
+
:update => update_template,
|
410
408
|
)
|
411
409
|
)
|
412
410
|
end
|
@@ -436,14 +434,13 @@ module Sfn
|
|
436
434
|
new_stack_template = new_template_hash.fetch('Resources', stack_name, 'Properties', 'Stack', Smash.new)
|
437
435
|
new_stack_parameters = new_template_hash.fetch('Resources', stack_name, 'Properties', 'Parameters', Smash.new)
|
438
436
|
new_stack_type = new_template_hash.fetch('Resources', stack_name, 'Type',
|
439
|
-
|
440
|
-
)
|
437
|
+
origin_template.get('Resources', stack_name, 'Type'))
|
441
438
|
resource = Smash.new(
|
442
439
|
:name => stack_name,
|
443
440
|
:type => new_stack_type,
|
444
|
-
:properties => []
|
441
|
+
:properties => [],
|
445
442
|
)
|
446
|
-
if
|
443
|
+
if original_stack && new_stack_template
|
447
444
|
new_stack_parameters = Smash[
|
448
445
|
new_stack_parameters.map do |new_param_key, new_param_value|
|
449
446
|
[new_param_key, translator.dereference(new_param_value)]
|
@@ -454,9 +451,9 @@ module Sfn
|
|
454
451
|
translator.flag_ref("#{stack_name}_Outputs.#{modified_output}")
|
455
452
|
end
|
456
453
|
plan_results[:stacks][stack_name] = result
|
457
|
-
elsif
|
454
|
+
elsif original_stack && (!new_stack_template && !new_stack_exists)
|
458
455
|
plan_results[:removed][stack_name] = resource
|
459
|
-
elsif
|
456
|
+
elsif new_stack_template && !original_stack
|
460
457
|
plan_results[:added][stack_name] = resource
|
461
458
|
end
|
462
459
|
end
|
@@ -470,15 +467,15 @@ module Sfn
|
|
470
467
|
# @return [Smash]
|
471
468
|
def diff_init(diff, path)
|
472
469
|
Smash.new.tap do |di|
|
473
|
-
if
|
474
|
-
updated = diff.detect{|x| x.first == '+'}
|
475
|
-
original = diff.detect{|x| x.first == '-'}
|
470
|
+
if diff.size > 1
|
471
|
+
updated = diff.detect { |x| x.first == '+' }
|
472
|
+
original = diff.detect { |x| x.first == '-' }
|
476
473
|
di[:original] = original.last.to_s
|
477
474
|
di[:updated] = updated.last.to_s
|
478
475
|
else
|
479
476
|
diff_data = diff.first
|
480
477
|
di[:path] = path
|
481
|
-
if
|
478
|
+
if diff_data.size == 3
|
482
479
|
di[diff_data.first == '+' ? :updated : :original] = diff_data.last
|
483
480
|
else
|
484
481
|
di[:original] = diff_data[diff_data.size - 2].to_s
|
@@ -498,9 +495,9 @@ module Sfn
|
|
498
495
|
# @option :templates [Smash] :update
|
499
496
|
def register_diff(results, path, diff, translator, templates)
|
500
497
|
diff_info = diff_init(diff, path)
|
501
|
-
if
|
498
|
+
if path.start_with?('Resources')
|
502
499
|
p_path = path.split('.')
|
503
|
-
if
|
500
|
+
if p_path.size == 2
|
504
501
|
diff = diff.first
|
505
502
|
key = diff.first == '+' ? :added : :removed
|
506
503
|
type = (key == :added ? templates[:update] : templates[:origin]).get('Resources', p_path.last, 'Type')
|
@@ -509,13 +506,13 @@ module Sfn
|
|
509
506
|
:type => type,
|
510
507
|
:properties => [],
|
511
508
|
:diffs => [
|
512
|
-
diff_info
|
513
|
-
]
|
509
|
+
diff_info,
|
510
|
+
],
|
514
511
|
)
|
515
512
|
else
|
516
|
-
if
|
513
|
+
if p_path.include?('Properties')
|
517
514
|
resource_name = p_path[1]
|
518
|
-
if
|
515
|
+
if p_path.size < 4 && p_path.last == 'Properties'
|
519
516
|
property_name = diff.flatten.compact.last.keys.first
|
520
517
|
else
|
521
518
|
property_name = p_path[3].to_s.sub(/\[\d+\]$/, '')
|
@@ -526,16 +523,16 @@ module Sfn
|
|
526
523
|
:type => type,
|
527
524
|
:properties => [property_name],
|
528
525
|
:diffs => [
|
529
|
-
diff_info.merge(:property_name => property_name)
|
530
|
-
]
|
526
|
+
diff_info.merge(:property_name => property_name),
|
527
|
+
],
|
531
528
|
)
|
532
529
|
begin
|
533
|
-
if
|
530
|
+
if templates.get(:update, 'Resources', resource_name, 'Properties', property_name) == Translator::UNKNOWN_RUNTIME_RESULT
|
534
531
|
effect = :unknown
|
535
532
|
else
|
536
533
|
r_info = SparkleFormation::Resources::Aws.resource_lookup(type)
|
537
534
|
r_property = r_info.property(property_name)
|
538
|
-
if
|
535
|
+
if r_property
|
539
536
|
effect = r_property.update_causes(
|
540
537
|
templates.get(:update, 'Resources', resource_name),
|
541
538
|
templates.get(:origin, 'Resources', resource_name)
|
@@ -559,32 +556,31 @@ module Sfn
|
|
559
556
|
rescue KeyError
|
560
557
|
set_resource(:unknown, results, resource_name, resource)
|
561
558
|
end
|
562
|
-
elsif
|
559
|
+
elsif p_path.include?('AWS::CloudFormation::Init')
|
563
560
|
resource_name = p_path[1]
|
564
561
|
type = templates[:origin]['Resources'][resource_name]['Type']
|
565
|
-
if
|
562
|
+
if REPLACE_ON_CFN_INIT_UPDATE.include?(type)
|
566
563
|
set_resource(:replace, results, resource_name,
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
)
|
564
|
+
Smash.new(
|
565
|
+
:name => resource_name,
|
566
|
+
:type => type,
|
567
|
+
:properties => ['AWS::CloudFormation::Init'],
|
568
|
+
:diffs => [
|
569
|
+
diff_info,
|
570
|
+
],
|
571
|
+
))
|
576
572
|
end
|
577
573
|
end
|
578
574
|
end
|
579
|
-
elsif
|
575
|
+
elsif path.start_with?('Outputs')
|
580
576
|
o_resource_name = path.split('.')[1]
|
581
|
-
if
|
577
|
+
if o_resource_name
|
582
578
|
set_resource(
|
583
579
|
:outputs, results, o_resource_name,
|
584
580
|
:properties => [],
|
585
581
|
:diffs => [
|
586
|
-
diff_info
|
587
|
-
]
|
582
|
+
diff_info,
|
583
|
+
],
|
588
584
|
)
|
589
585
|
end
|
590
586
|
end
|
@@ -597,7 +593,7 @@ module Sfn
|
|
597
593
|
# @param name [String]
|
598
594
|
# @param resource [Hash]
|
599
595
|
def set_resource(kind, results, name, resource)
|
600
|
-
if
|
596
|
+
if results[kind][name]
|
601
597
|
results[kind][name][:properties] += resource[:properties]
|
602
598
|
results[kind][name][:properties].uniq!
|
603
599
|
results[kind][name][:diffs] += resource[:diffs]
|
@@ -616,7 +612,7 @@ module Sfn
|
|
616
612
|
# @param flagged [Array<String>]
|
617
613
|
#
|
618
614
|
# @return [Hash]
|
619
|
-
def dereference_template(t_key, template, parameters, flagged=[])
|
615
|
+
def dereference_template(t_key, template, parameters, flagged = [])
|
620
616
|
template = template.to_smash
|
621
617
|
translator = translator_for(t_key, template, parameters)
|
622
618
|
flagged.each do |item|
|
@@ -630,16 +626,16 @@ module Sfn
|
|
630
626
|
end
|
631
627
|
translator.original.replace(template)
|
632
628
|
['Outputs', 'Resources'].each do |t_key|
|
633
|
-
if
|
629
|
+
if template[t_key]
|
634
630
|
template[t_key] = translator.dereference_processor(
|
635
631
|
template[t_key], ['DEREF', :all]
|
636
632
|
)
|
637
633
|
end
|
638
634
|
end
|
639
|
-
if
|
635
|
+
if template['Resources']
|
640
636
|
valid_resources = template['Resources'].map do |resource_name, resource_value|
|
641
|
-
if
|
642
|
-
if
|
637
|
+
if resource_value['OnCondition']
|
638
|
+
if translator.apply_condition(resource_value['OnCondition'])
|
643
639
|
resource_name
|
644
640
|
end
|
645
641
|
else
|
@@ -660,13 +656,12 @@ module Sfn
|
|
660
656
|
# @param template [Hash] stack template
|
661
657
|
# @param parameters [Hash] stack parameters
|
662
658
|
# @return [Translator]
|
663
|
-
def translator_for(t_key, template=nil, parameters=nil)
|
659
|
+
def translator_for(t_key, template = nil, parameters = nil)
|
664
660
|
o_translator = translators[t_key]
|
665
|
-
if
|
661
|
+
if template
|
666
662
|
translator = Translator.new(template,
|
667
|
-
|
668
|
-
|
669
|
-
if(o_translator)
|
663
|
+
:parameters => parameters)
|
664
|
+
if o_translator
|
670
665
|
o_translator.flagged.each do |i|
|
671
666
|
translator.flag_ref(i)
|
672
667
|
end
|
@@ -674,15 +669,13 @@ module Sfn
|
|
674
669
|
translators[t_key] = translator
|
675
670
|
o_translator = translator
|
676
671
|
else
|
677
|
-
unless
|
672
|
+
unless o_translator
|
678
673
|
o_translator = Translator.new({},
|
679
|
-
|
680
|
-
)
|
674
|
+
:parameters => {})
|
681
675
|
end
|
682
676
|
end
|
683
677
|
o_translator
|
684
678
|
end
|
685
|
-
|
686
679
|
end
|
687
680
|
end
|
688
681
|
end
|