sfn 3.0.28 → 3.0.30
Sign up to get free protection for your applications and to get access to all the features.
- 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
|