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.
Files changed (77) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +5 -0
  3. data/docs/callbacks.md +1 -0
  4. data/lib/chef/knife/knife_plugin_seed.rb +11 -17
  5. data/lib/sfn.rb +0 -2
  6. data/lib/sfn/api_provider.rb +0 -2
  7. data/lib/sfn/api_provider/google.rb +6 -9
  8. data/lib/sfn/api_provider/terraform.rb +4 -6
  9. data/lib/sfn/cache.rb +36 -39
  10. data/lib/sfn/callback.rb +0 -2
  11. data/lib/sfn/callback/aws_assume_role.rb +7 -8
  12. data/lib/sfn/callback/aws_mfa.rb +7 -8
  13. data/lib/sfn/callback/stack_policy.rb +15 -17
  14. data/lib/sfn/command.rb +9 -11
  15. data/lib/sfn/command/conf.rb +7 -10
  16. data/lib/sfn/command/create.rb +8 -12
  17. data/lib/sfn/command/describe.rb +6 -8
  18. data/lib/sfn/command/destroy.rb +8 -10
  19. data/lib/sfn/command/diff.rb +18 -25
  20. data/lib/sfn/command/events.rb +15 -16
  21. data/lib/sfn/command/export.rb +13 -17
  22. data/lib/sfn/command/graph.rb +11 -13
  23. data/lib/sfn/command/graph/aws.rb +27 -29
  24. data/lib/sfn/command/graph/terraform.rb +22 -23
  25. data/lib/sfn/command/import.rb +13 -16
  26. data/lib/sfn/command/init.rb +5 -7
  27. data/lib/sfn/command/inspect.rb +26 -29
  28. data/lib/sfn/command/lint.rb +10 -12
  29. data/lib/sfn/command/list.rb +5 -8
  30. data/lib/sfn/command/print.rb +3 -5
  31. data/lib/sfn/command/promote.rb +0 -2
  32. data/lib/sfn/command/update.rb +42 -46
  33. data/lib/sfn/command/validate.rb +4 -6
  34. data/lib/sfn/command_module/base.rb +17 -25
  35. data/lib/sfn/command_module/callbacks.rb +12 -8
  36. data/lib/sfn/command_module/stack.rb +39 -43
  37. data/lib/sfn/command_module/template.rb +89 -90
  38. data/lib/sfn/config.rb +30 -31
  39. data/lib/sfn/config/conf.rb +1 -3
  40. data/lib/sfn/config/create.rb +5 -7
  41. data/lib/sfn/config/describe.rb +3 -5
  42. data/lib/sfn/config/diff.rb +1 -1
  43. data/lib/sfn/config/events.rb +6 -8
  44. data/lib/sfn/config/export.rb +4 -7
  45. data/lib/sfn/config/graph.rb +4 -6
  46. data/lib/sfn/config/import.rb +3 -5
  47. data/lib/sfn/config/init.rb +0 -1
  48. data/lib/sfn/config/inspect.rb +7 -9
  49. data/lib/sfn/config/lint.rb +4 -4
  50. data/lib/sfn/config/list.rb +3 -5
  51. data/lib/sfn/config/print.rb +3 -5
  52. data/lib/sfn/config/promote.rb +3 -5
  53. data/lib/sfn/config/update.rb +10 -12
  54. data/lib/sfn/config/validate.rb +18 -20
  55. data/lib/sfn/lint.rb +0 -2
  56. data/lib/sfn/lint/definition.rb +3 -5
  57. data/lib/sfn/lint/rule.rb +7 -8
  58. data/lib/sfn/lint/rule_set.rb +11 -20
  59. data/lib/sfn/monkey_patch/stack.rb +32 -34
  60. data/lib/sfn/monkey_patch/stack/azure.rb +0 -1
  61. data/lib/sfn/monkey_patch/stack/google.rb +15 -16
  62. data/lib/sfn/planner.rb +1 -3
  63. data/lib/sfn/planner/aws.rb +82 -89
  64. data/lib/sfn/provider.rb +21 -23
  65. data/lib/sfn/utils.rb +0 -2
  66. data/lib/sfn/utils/debug.rb +1 -2
  67. data/lib/sfn/utils/json.rb +3 -2
  68. data/lib/sfn/utils/object_storage.rb +1 -2
  69. data/lib/sfn/utils/output.rb +8 -9
  70. data/lib/sfn/utils/path_selector.rb +9 -10
  71. data/lib/sfn/utils/ssher.rb +2 -3
  72. data/lib/sfn/utils/stack_exporter.rb +20 -21
  73. data/lib/sfn/utils/stack_parameter_scrubber.rb +6 -7
  74. data/lib/sfn/utils/stack_parameter_validator.rb +14 -16
  75. data/lib/sfn/version.rb +1 -1
  76. data/sfn.gemspec +1 -1
  77. metadata +8 -8
@@ -4,7 +4,6 @@ module Sfn
4
4
  class Command
5
5
  # Lint command
6
6
  class Lint < Command
7
-
8
7
  include Sfn::CommandModule::Base
9
8
  include Sfn::CommandModule::Template
10
9
 
@@ -18,11 +17,11 @@ module Sfn
18
17
 
19
18
  raw_template = parameter_scrub!(template_content(file))
20
19
 
21
- if(config[:print_only])
20
+ if config[:print_only]
22
21
  ui.puts raw_template
23
22
  else
24
23
  result = lint_template(raw_template)
25
- if(result == true)
24
+ if result == true
26
25
  ui.info ui.color(' -> VALID', :green, :bold)
27
26
  else
28
27
  ui.info ui.color(' -> INVALID', :red, :bold)
@@ -44,7 +43,7 @@ module Sfn
44
43
  def lint_template(template)
45
44
  results = rule_sets.map do |set|
46
45
  result = set.apply(template)
47
- unless(result == true)
46
+ unless result == true
48
47
  Smash.new(:rule_set => set, :failures => result)
49
48
  end
50
49
  end.compact
@@ -54,7 +53,7 @@ module Sfn
54
53
  # @return [Array<Sfn::Lint::RuleSet>]
55
54
  def rule_sets
56
55
  sets = [config[:lint_directory]].flatten.compact.map do |directory|
57
- if(File.directory?(directory))
56
+ if File.directory?(directory)
58
57
  files = Dir.glob(File.join(directory, '**', '**', '*.rb'))
59
58
  files.map do |path|
60
59
  begin
@@ -67,21 +66,20 @@ module Sfn
67
66
  end
68
67
  end
69
68
  end
70
- end.flatten.compact.find_all{|rs| rs.provider == provider.connection.provider}
71
- unless(config[:local_rule_sets_only])
69
+ end.flatten.compact.find_all { |rs| rs.provider == provider.connection.provider }
70
+ unless config[:local_rule_sets_only]
72
71
  sets += Sfn::Lint::RuleSet.get_all(provider.connection.provider)
73
72
  end
74
- if(config[:disabled_rule_set])
73
+ if config[:disabled_rule_set]
75
74
  disabled = [config[:disabled_rule_set]].flatten.compact
76
- sets.delete_if{|i| disabled.include?(i.name.to_s) }
75
+ sets.delete_if { |i| disabled.include?(i.name.to_s) }
77
76
  end
78
- if(config[:enabled_rule_set])
77
+ if config[:enabled_rule_set]
79
78
  enabled = [config[:enabled_rule_set]].flatten.compact
80
- sets.delete_if{|i| enabled.include?(i.name.to_s) }
79
+ sets.delete_if { |i| enabled.include?(i.name.to_s) }
81
80
  end
82
81
  sets
83
82
  end
84
-
85
83
  end
86
84
  end
87
85
  end
@@ -4,18 +4,16 @@ module Sfn
4
4
  class Command
5
5
  # List command
6
6
  class List < Command
7
-
8
7
  include Sfn::CommandModule::Base
9
8
 
10
9
  # Run the list command
11
10
  def execute!
12
11
  ui.table(self) do
13
12
  table(:border => false) do
14
- stacks = api_action!{ get_stacks }
13
+ stacks = api_action! { get_stacks }
15
14
  row(:header => true) do
16
-
17
15
  allowed_attributes.each do |attr|
18
- width_val = stacks.map{|e| e[attr].to_s.length}.push(attr.length).max + 2
16
+ width_val = stacks.map { |e| e[attr].to_s.length }.push(attr.length).max + 2
19
17
  width_val = width_val > 70 ? 70 : width_val < 20 ? 20 : width_val
20
18
  column attr.split('_').map(&:capitalize).join(' '), :width => width_val
21
19
  end
@@ -38,9 +36,9 @@ module Sfn
38
36
  provider.stacks.all.map do |stack|
39
37
  Smash.new(stack.attributes)
40
38
  end.sort do |x, y|
41
- if(y[:created].to_s.empty?)
39
+ if y[:created].to_s.empty?
42
40
  -1
43
- elsif(x[:created].to_s.empty?)
41
+ elsif x[:created].to_s.empty?
44
42
  1
45
43
  else
46
44
  Time.parse(x[:created].to_s) <=> Time.parse(y[:created].to_s)
@@ -50,13 +48,12 @@ module Sfn
50
48
 
51
49
  # @return [Array<String>] default attributes to display
52
50
  def default_attributes
53
- if(provider.connection.provider == :aws)
51
+ if provider.connection.provider == :aws
54
52
  %w(name created updated status template_description)
55
53
  else
56
54
  %w(name created updated status description)
57
55
  end
58
56
  end
59
-
60
57
  end
61
58
  end
62
59
  end
@@ -5,7 +5,6 @@ module Sfn
5
5
  class Command
6
6
  # Print command
7
7
  class Print < Command
8
-
9
8
  include Sfn::CommandModule::Base
10
9
  include Sfn::CommandModule::Template
11
10
  include Sfn::CommandModule::Stack
@@ -16,15 +15,15 @@ module Sfn
16
15
  file = load_template_file
17
16
 
18
17
  output_content = parameter_scrub!(template_content(file))
19
- if(config[:yaml])
18
+ if config[:yaml]
20
19
  require 'yaml'
21
20
  output_content = YAML.dump(output_content)
22
21
  else
23
22
  output_content = format_json(output_content)
24
23
  end
25
24
 
26
- if(config[:write_to_file])
27
- unless(File.directory?(File.dirname(config[:write_to_file])))
25
+ if config[:write_to_file]
26
+ unless File.directory?(File.dirname(config[:write_to_file]))
28
27
  run_action 'Creating parent directory' do
29
28
  FileUtils.mkdir_p(File.dirname(config[:write_to_file]))
30
29
  nil
@@ -38,7 +37,6 @@ module Sfn
38
37
  ui.puts output_content
39
38
  end
40
39
  end
41
-
42
40
  end
43
41
  end
44
42
  end
@@ -4,14 +4,12 @@ module Sfn
4
4
  class Command
5
5
  # Promote command
6
6
  class Promote < Command
7
-
8
7
  include Sfn::CommandModule::Base
9
8
 
10
9
  def execute!
11
10
  raise NotImplementedError.new 'Implementation updates required'
12
11
  stack_name, destination = name_args
13
12
  end
14
-
15
13
  end
16
14
  end
17
15
  end
@@ -4,7 +4,6 @@ module Sfn
4
4
  class Command
5
5
  # Update command
6
6
  class Update < Command
7
-
8
7
  include Sfn::CommandModule::Base
9
8
  include Sfn::CommandModule::Template
10
9
  include Sfn::CommandModule::Stack
@@ -23,16 +22,16 @@ module Sfn
23
22
 
24
23
  config[:compile_parameters] ||= Smash.new
25
24
 
26
- if(config[:file])
25
+ if config[:file]
27
26
  s_name = [name]
28
27
 
29
28
  c_setter = lambda do |c_stack|
30
- if(c_stack.outputs)
29
+ if c_stack.outputs
31
30
  compile_params = c_stack.outputs.detect do |output|
32
31
  output.key == 'CompileState'
33
32
  end
34
33
  end
35
- if(compile_params)
34
+ if compile_params
36
35
  compile_params = MultiJson.load(compile_params.value)
37
36
  c_current = config[:compile_parameters].fetch(s_name.join('__'), Smash.new)
38
37
  config[:compile_parameters][s_name.join('__')] = compile_params.merge(c_current)
@@ -44,7 +43,7 @@ module Sfn
44
43
  end
45
44
  end
46
45
 
47
- if(stack)
46
+ if stack
48
47
  c_setter.call(stack)
49
48
  end
50
49
 
@@ -55,28 +54,28 @@ module Sfn
55
54
  file = stack.template.dup if config[:plan]
56
55
  end
57
56
 
58
- unless(stack)
57
+ unless stack
59
58
  ui.fatal "Failed to locate requested stack: #{ui.color(name, :red, :bold)}"
60
59
  raise "Failed to locate stack: #{name}"
61
60
  end
62
61
 
63
- unless(config[:print_only])
62
+ unless config[:print_only]
64
63
  ui.info "#{ui.color('SparkleFormation:', :bold)} #{ui.color('update', :green)}"
65
64
  end
66
65
 
67
- unless(file)
68
- if(config[:template])
66
+ unless file
67
+ if config[:template]
69
68
  file = config[:template]
70
69
  stack_info << " #{ui.color('(template provided)', :green)}"
71
70
  else
72
71
  stack_info << " #{ui.color('(no template update)', :yellow)}"
73
72
  end
74
73
  end
75
- unless(config[:print_only])
74
+ unless config[:print_only]
76
75
  ui.info " -> #{stack_info}"
77
76
  end
78
- if(file)
79
- if(config[:print_only])
77
+ if file
78
+ if config[:print_only]
80
79
  ui.puts format_json(parameter_scrub!(template_content(file)))
81
80
  return
82
81
  end
@@ -89,12 +88,12 @@ module Sfn
89
88
  populate_parameters!(file, :current_parameters => stack.root_parameters)
90
89
  update_template = stack.template
91
90
 
92
- if(config[:plan])
91
+ if config[:plan]
93
92
  begin
94
93
  stack.template = original_template
95
94
  stack.parameters = original_parameters
96
95
  plan = build_planner(stack)
97
- if(plan)
96
+ if plan
98
97
  result = plan.generate_plan(
99
98
  file.respond_to?(:dump) ? file.dump : file,
100
99
  config_root_parameters
@@ -102,7 +101,7 @@ module Sfn
102
101
  display_plan_information(result)
103
102
  end
104
103
  rescue => e
105
- unless(e.message.include?('Confirmation declined'))
104
+ unless e.message.include?('Confirmation declined')
106
105
  ui.error "Unexpected error when generating plan information: #{e.class} - #{e}"
107
106
  ui.debug "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
108
107
  ui.confirm 'Continue with stack update?' unless config[:plan_only]
@@ -110,14 +109,14 @@ module Sfn
110
109
  raise
111
110
  end
112
111
  end
113
- if(config[:plan_only])
112
+ if config[:plan_only]
114
113
  ui.info 'Plan only mode requested. Exiting.'
115
114
  exit 0
116
115
  end
117
116
  end
118
117
  stack.parameters = config_root_parameters
119
118
 
120
- if(config[:upload_root_template])
119
+ if config[:upload_root_template]
121
120
  upload_result = store_template(name, file, Smash.new)
122
121
  stack.template_url = upload_result[:url]
123
122
  else
@@ -131,9 +130,9 @@ module Sfn
131
130
  end
132
131
 
133
132
  # Set options defined within config into stack instance for update request
134
- if(config[:merge_api_options])
133
+ if config[:merge_api_options]
135
134
  config.fetch(:options, Smash.new).each_pair do |key, value|
136
- if(stack.respond_to?("#{key}="))
135
+ if stack.respond_to?("#{key}=")
137
136
  stack.send("#{key}=", value)
138
137
  end
139
138
  end
@@ -142,9 +141,9 @@ module Sfn
142
141
  begin
143
142
  api_action!(:api_stack => stack) do
144
143
  stack.save
145
- if(config[:poll])
144
+ if config[:poll]
146
145
  poll_stack(stack.name)
147
- if(stack.reload.state == :update_complete)
146
+ if stack.reload.state == :update_complete
148
147
  ui.info "Stack update complete: #{ui.color('SUCCESS', :green)}"
149
148
  namespace.const_get(:Describe).new({:outputs => true}, [name]).execute!
150
149
  else
@@ -157,18 +156,17 @@ module Sfn
157
156
  end
158
157
  end
159
158
  rescue Miasma::Error::ApiError::RequestError => e
160
- if(e.message.downcase.include?('no updates'))
159
+ if e.message.downcase.include?('no updates')
161
160
  ui.warn "No updates detected for stack (#{stack.name})"
162
161
  else
163
162
  raise
164
163
  end
165
164
  end
166
-
167
165
  end
168
166
 
169
167
  def build_planner(stack)
170
168
  klass_name = stack.api.class.to_s.split('::').last
171
- if(Planner.const_defined?(klass_name))
169
+ if Planner.const_defined?(klass_name)
172
170
  Planner.const_get(klass_name).new(ui, config, arguments, stack)
173
171
  else
174
172
  warn "Failed to build planner for current provider. No provider implemented. (`#{klass_name}`)"
@@ -178,62 +176,61 @@ module Sfn
178
176
 
179
177
  def display_plan_information(result)
180
178
  ui.info ui.color('Pre-update resource planning report:', :bold)
181
- unless(print_plan_result(result))
179
+ unless print_plan_result(result)
182
180
  ui.info 'No resources life cycle changes detected in this update!'
183
181
  end
184
182
  ui.confirm 'Apply this stack update?' unless config[:plan_only]
185
183
  end
186
184
 
187
-
188
- def print_plan_result(info, names=[])
185
+ def print_plan_result(info, names = [])
189
186
  said_any_things = false
190
- unless(info[:stacks].empty?)
187
+ unless info[:stacks].empty?
191
188
  info[:stacks].each do |s_name, s_info|
192
189
  result = print_plan_result(s_info, [*names, s_name].compact)
193
190
  said_any_things ||= result
194
191
  end
195
192
  end
196
- unless(names.flatten.compact.empty?)
193
+ unless names.flatten.compact.empty?
197
194
  said_things = false
198
195
  ui.puts
199
196
  ui.puts " #{ui.color('Update plan for:', :bold)} #{ui.color(names.join(' > '), :blue)}"
200
- unless(info[:unknown].empty?)
197
+ unless info[:unknown].empty?
201
198
  ui.puts " #{ui.color('!!! Unknown update effect:', :red, :bold)}"
202
199
  print_plan_items(info, :unknown, :red)
203
200
  ui.puts
204
201
  said_any_things = said_things = true
205
202
  end
206
- unless(info[:unavailable].empty?)
203
+ unless info[:unavailable].empty?
207
204
  ui.puts " #{ui.color('Update request not allowed:', :red, :bold)}"
208
205
  print_plan_items(info, :unavailable, :red)
209
206
  ui.puts
210
207
  said_any_things = said_things = true
211
208
  end
212
- unless(info[:replace].empty?)
209
+ unless info[:replace].empty?
213
210
  ui.puts " #{ui.color('Resources to be replaced:', :red, :bold)}"
214
211
  print_plan_items(info, :replace, :red)
215
212
  ui.puts
216
213
  said_any_things = said_things = true
217
214
  end
218
- unless(info[:interrupt].empty?)
215
+ unless info[:interrupt].empty?
219
216
  ui.puts " #{ui.color('Resources to be interrupted:', :yellow, :bold)}"
220
217
  print_plan_items(info, :interrupt, :yellow)
221
218
  ui.puts
222
219
  said_any_things = said_things = true
223
220
  end
224
- unless(info[:removed].empty?)
221
+ unless info[:removed].empty?
225
222
  ui.puts " #{ui.color('Resources to be removed:', :red, :bold)}"
226
223
  print_plan_items(info, :removed, :red)
227
224
  ui.puts
228
225
  said_any_things = said_things = true
229
226
  end
230
- unless(info[:added].empty?)
227
+ unless info[:added].empty?
231
228
  ui.puts " #{ui.color('Resources to be added:', :green, :bold)}"
232
229
  print_plan_items(info, :added, :green)
233
230
  ui.puts
234
231
  said_any_things = said_things = true
235
232
  end
236
- unless(said_things)
233
+ unless said_things
237
234
  ui.puts " #{ui.color('No resource lifecycle changes detected!', :green)}"
238
235
  ui.puts
239
236
  said_any_things = true
@@ -249,26 +246,26 @@ module Sfn
249
246
  # @param color [Symbol] color to flag
250
247
  def print_plan_items(info, key, color)
251
248
  max_name = info[key].keys.map(&:size).max
252
- max_type = info[key].values.map{|i|i[:type]}.map(&:size).max
253
- max_p = info[key].values.map{|i| i.fetch(:diffs, [])}.flatten(1).map{|d| d.fetch(:property_name, :path).to_s.size}.max
254
- max_o = info[key].values.map{|i| i.fetch(:diffs, [])}.flatten(1).map{|d| d[:original].to_s.size}.max
249
+ max_type = info[key].values.map { |i| i[:type] }.map(&:size).max
250
+ max_p = info[key].values.map { |i| i.fetch(:diffs, []) }.flatten(1).map { |d| d.fetch(:property_name, :path).to_s.size }.max
251
+ max_o = info[key].values.map { |i| i.fetch(:diffs, []) }.flatten(1).map { |d| d[:original].to_s.size }.max
255
252
  info[key].each do |name, val|
256
253
  ui.print ' ' * 6
257
254
  ui.print ui.color("[#{val[:type]}]", color)
258
255
  ui.print ' ' * (max_type - val[:type].size)
259
256
  ui.print ' ' * 4
260
257
  ui.print ui.color(name, :bold)
261
- unless(val[:properties].nil? || val[:properties].empty?)
258
+ unless val[:properties].nil? || val[:properties].empty?
262
259
  ui.print ' ' * (max_name - name.size)
263
260
  ui.print ' ' * 4
264
261
  ui.print "Reason: Updated properties: `#{val[:properties].join('`, `')}`"
265
262
  end
266
263
  ui.puts
267
- if(config[:diffs])
268
- unless(val[:diffs].empty?)
264
+ if config[:diffs]
265
+ unless val[:diffs].empty?
269
266
  p_name = nil
270
267
  val[:diffs].each do |diff|
271
- if(!diff[:updated].nil? || !diff[:original].nil?)
268
+ if !diff[:updated].nil? || !diff[:original].nil?
272
269
  p_name = diff.fetch(:property_name, :path)
273
270
  ui.print ' ' * 8
274
271
  ui.print "#{p_name}: "
@@ -276,10 +273,10 @@ module Sfn
276
273
  ui.print ui.color("-#{diff[:original]}", :red) unless diff[:original].nil?
277
274
  ui.print ' ' * (max_o - diff[:original].to_s.size)
278
275
  ui.print ' '
279
- if(diff[:updated] == Sfn::Planner::RUNTIME_MODIFIED)
276
+ if diff[:updated] == Sfn::Planner::RUNTIME_MODIFIED
280
277
  ui.puts ui.color("+#{diff[:original]} <Dependency Modified>", :green)
281
278
  else
282
- if(diff[:updated].nil?)
279
+ if diff[:updated].nil?
283
280
  ui.puts
284
281
  else
285
282
  ui.puts ui.color("+#{diff[:updated].to_s.gsub('__MODIFIED_REFERENCE_VALUE__', '<Dependency Modified>')}", :green)
@@ -292,7 +289,6 @@ module Sfn
292
289
  end
293
290
  end
294
291
  end
295
-
296
292
  end
297
293
  end
298
294
  end
@@ -5,7 +5,6 @@ module Sfn
5
5
  class Command
6
6
  # Validate command
7
7
  class Validate < Command
8
-
9
8
  include Sfn::CommandModule::Base
10
9
  include Sfn::CommandModule::Template
11
10
  include Sfn::CommandModule::Stack
@@ -19,7 +18,7 @@ module Sfn
19
18
 
20
19
  raw_template = _format_json(parameter_scrub!(template_content(file)))
21
20
 
22
- if(config[:print_only])
21
+ if config[:print_only]
23
22
  ui.puts raw_template
24
23
  else
25
24
  validate_stack(
@@ -46,16 +45,16 @@ module Sfn
46
45
  end
47
46
  begin
48
47
  ui.info "Validating: #{ui.color(name, :bold)}"
49
- if(config[:upload_root_template])
48
+ if config[:upload_root_template]
50
49
  upload_result = store_template('validation-stack', template, Smash.new)
51
50
  stack = provider.connection.stacks.build(
52
51
  :name => 'validation-stack',
53
- :template_url => upload_result[:url]
52
+ :template_url => upload_result[:url],
54
53
  )
55
54
  else
56
55
  stack = provider.connection.stacks.build(
57
56
  :name => 'validation-stack',
58
- :template => parameter_scrub!(template)
57
+ :template => parameter_scrub!(template),
59
58
  )
60
59
  end
61
60
  result = api_action!(:api_stack => stack) do
@@ -69,7 +68,6 @@ module Sfn
69
68
  raise e
70
69
  end
71
70
  end
72
-
73
71
  end
74
72
  end
75
73
  end