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
@@ -3,7 +3,6 @@ require 'sfn'
3
3
  module Sfn
4
4
  class Command
5
5
  class Destroy < Command
6
-
7
6
  include Sfn::CommandModule::Base
8
7
 
9
8
  # Run the stack destruction action
@@ -14,7 +13,7 @@ module Sfn
14
13
  globs = stacks.find_all do |s|
15
14
  s !~ /^[a-zA-Z0-9-]+$/
16
15
  end
17
- unless(globs.empty?)
16
+ unless globs.empty?
18
17
  glob_stacks = provider.connection.stacks.all.find_all do |remote_stack|
19
18
  globs.detect do |glob|
20
19
  File.fnmatch(glob, remote_stack.name)
@@ -28,7 +27,7 @@ module Sfn
28
27
  ui.confirm "Destroy listed stack#{plural}?"
29
28
  stacks.each do |stack_name|
30
29
  stack = provider.connection.stacks.get(stack_name)
31
- if(stack)
30
+ if stack
32
31
  nested_stack_cleanup!(stack)
33
32
  begin
34
33
  api_action!(:api_stack => stack) do
@@ -44,12 +43,12 @@ module Sfn
44
43
  ui.warn "Failed to locate requested stack: #{ui.color(stack_name, :bold)}"
45
44
  end
46
45
  end
47
- if(config[:poll])
48
- if(stacks.size == 1)
46
+ if config[:poll]
47
+ if stacks.size == 1
49
48
  begin
50
49
  poll_stack(stacks.first)
51
50
  rescue Miasma::Error::ApiError::RequestError => error
52
- unless(error.response.code == 404)
51
+ unless error.response.code == 404
53
52
  raise error
54
53
  end
55
54
  end
@@ -69,12 +68,12 @@ module Sfn
69
68
  provider.connection.data[:stack_types].include?(resource['Type'])
70
69
  end.each do |resource|
71
70
  url = resource['Properties']['TemplateURL']
72
- if(url && url.is_a?(String))
71
+ if url && url.is_a?(String)
73
72
  _, bucket_name, path = URI.parse(url).path.split('/', 3)
74
73
  bucket = provider.connection.api_for(:storage).buckets.get(bucket_name)
75
- if(bucket)
74
+ if bucket
76
75
  file = bucket.files.get(path)
77
- if(file)
76
+ if file
78
77
  file.destroy
79
78
  ui.info "Deleted nested stack template! (Bucket: #{bucket_name} Template: #{path})"
80
79
  else
@@ -86,7 +85,6 @@ module Sfn
86
85
  end
87
86
  end
88
87
  end
89
-
90
88
  end
91
89
  end
92
90
  end
@@ -6,7 +6,6 @@ module Sfn
6
6
  class Command
7
7
  # Diff command
8
8
  class Diff < Command
9
-
10
9
  include Sfn::CommandModule::Base
11
10
  include Sfn::CommandModule::Template
12
11
  include Sfn::CommandModule::Stack
@@ -22,7 +21,7 @@ module Sfn
22
21
  stack = nil
23
22
  end
24
23
 
25
- if(stack)
24
+ if stack
26
25
  config[:print_only] = true
27
26
  file = load_template_file
28
27
  file = parameter_scrub!(file.dump)
@@ -38,7 +37,7 @@ module Sfn
38
37
  end
39
38
 
40
39
  # @todo needs updates for better provider compat
41
- def diff_stack(stack, file, parent_names=[])
40
+ def diff_stack(stack, file, parent_names = [])
42
41
  stack_template = stack.template
43
42
  nested_stacks = Hash[
44
43
  file.fetch('Resources', file.fetch('resources', {})).find_all do |name, value|
@@ -49,7 +48,7 @@ module Sfn
49
48
  n_stack = stack.nested_stacks(false).detect do |ns|
50
49
  ns.data[:logical_id] == name
51
50
  end
52
- if(n_stack)
51
+ if n_stack
53
52
  diff_stack(n_stack, value['Properties']['Stack'], [*parent_names, stack.data.fetch(:logical_id, stack.name)].compact)
54
53
  end
55
54
  file['Resources'][name]['Properties'].delete('Stack')
@@ -59,12 +58,11 @@ module Sfn
59
58
 
60
59
  stack_diff = HashDiff.diff(stack.template, file)
61
60
 
62
- if(config[:raw_diff])
61
+ if config[:raw_diff]
63
62
  ui.info "Dumping raw template diff:"
64
63
  require 'pp'
65
64
  pp stack_diff
66
65
  else
67
-
68
66
  added_resources = stack_diff.find_all do |item|
69
67
  item.first == '+' && item[1].match(/Resources\.[^.]+$/)
70
68
  end
@@ -77,12 +75,11 @@ module Sfn
77
75
  !item[1].include?('Properties.Parameters')
78
76
  end - added_resources - removed_resources
79
77
 
80
- if(added_resources.empty? && removed_resources.empty? && modified_resources.empty?)
78
+ if added_resources.empty? && removed_resources.empty? && modified_resources.empty?
81
79
  ui.info 'No changes detected'
82
80
  ui.puts
83
81
  else
84
-
85
- unless(added_resources.empty?)
82
+ unless added_resources.empty?
86
83
  ui.info ui.color('Added Resources:', :green, :bold)
87
84
  added_resources.each do |item|
88
85
  ui.print ui.color(" -> #{item[1].split('.').last}", :green)
@@ -91,7 +88,7 @@ module Sfn
91
88
  ui.puts
92
89
  end
93
90
 
94
- unless(modified_resources.empty?)
91
+ unless modified_resources.empty?
95
92
  ui.info ui.color('Modified Resources:', :yellow, :bold)
96
93
  m_resources = Hash.new.tap do |hash|
97
94
  modified_resources.each do |item|
@@ -102,8 +99,8 @@ module Sfn
102
99
  matched = hash[key][prefix].detect do |i|
103
100
  i[:path] == a_key
104
101
  end
105
- if(matched)
106
- if(item.first == '-')
102
+ if matched
103
+ if item.first == '-'
107
104
  matched[:original] = item[2]
108
105
  else
109
106
  matched[:new] = item[2]
@@ -137,7 +134,7 @@ module Sfn
137
134
  ui.puts
138
135
  end
139
136
 
140
- unless(removed_resources.empty?)
137
+ unless removed_resources.empty?
141
138
  ui.info ui.color('Removed Resources:', :red, :bold)
142
139
  removed_resources.each do |item|
143
140
  ui.print ui.color(" <- #{item[1].split('.').last}", :red)
@@ -147,21 +144,17 @@ module Sfn
147
144
  end
148
145
 
149
146
  run_callbacks_for(:after_stack_diff,
150
- :diff => stack_diff,
151
- :diff_info => {
152
- :added => added_resources,
153
- :modified => modified_resources,
154
- :removed => removed_resources
155
- },
156
- :api_stack => stack,
157
- :new_template => file
158
- )
147
+ :diff => stack_diff,
148
+ :diff_info => {
149
+ :added => added_resources,
150
+ :modified => modified_resources,
151
+ :removed => removed_resources,
152
+ },
153
+ :api_stack => stack,
154
+ :new_template => file)
159
155
  end
160
-
161
156
  end
162
-
163
157
  end
164
-
165
158
  end
166
159
  end
167
160
  end
@@ -4,7 +4,6 @@ module Sfn
4
4
  class Command
5
5
  # Events command
6
6
  class Events < Command
7
-
8
7
  include Sfn::CommandModule::Base
9
8
 
10
9
  # @return [Miasma::Models::Orchestration::Stack]
@@ -17,14 +16,14 @@ module Sfn
17
16
  ui.info "Events for Stack: #{ui.color(name, :bold)}\n"
18
17
  @seen_events = []
19
18
  @stack = provider.stack(name)
20
- if(stack)
19
+ if stack
21
20
  api_action!(:api_stack => stack) do
22
21
  table = ui.table(self) do
23
22
  table(:border => false) do
24
23
  events = get_events
25
24
  row(:header => true) do
26
25
  allowed_attributes.each do |attr|
27
- width_val = events.map{|e| e[attr].to_s.length}.push(attr.length).max + 2
26
+ width_val = events.map { |e| e[attr].to_s.length }.push(attr.length).max + 2
28
27
  width_val = width_val > 70 ? 70 : width_val < 20 ? 20 : width_val
29
28
  column attr.split('_').map(&:capitalize).join(' '), :width => width_val
30
29
  end
@@ -38,10 +37,10 @@ module Sfn
38
37
  end
39
38
  end
40
39
  end.display
41
- if(config[:poll])
42
- while(stack.reload.in_progress?)
40
+ if config[:poll]
41
+ while (stack.reload.in_progress?)
43
42
  to_wait = config.fetch(:poll_wait_time, 10).to_f
44
- while(to_wait > 0)
43
+ while (to_wait > 0)
45
44
  sleep(0.1)
46
45
  to_wait -= 0.1
47
46
  end
@@ -65,13 +64,13 @@ module Sfn
65
64
  stack_events = discover_stacks(stack).map do |i_stack|
66
65
  i_events = []
67
66
  begin
68
- if(@initial_complete && i_stack.in_progress?)
67
+ if @initial_complete && i_stack.in_progress?
69
68
  i_events = i_stack.events.update!
70
69
  else
71
70
  i_events = i_stack.events.all
72
71
  end
73
72
  rescue => e
74
- if(e.class.to_s.start_with?('Errno'))
73
+ if e.class.to_s.start_with?('Errno')
75
74
  ui.warn "Connection error encountered: #{e.message} (retrying)"
76
75
  ui.debug "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
77
76
  else
@@ -81,23 +80,23 @@ module Sfn
81
80
  sleep(5)
82
81
  retry
83
82
  end
84
- if(i_events)
83
+ if i_events
85
84
  i_events.map do |e|
86
85
  e.attributes.merge(:stack_name => i_stack.name).to_smash
87
86
  end
88
87
  end
89
- end.flatten.compact.find_all{|e| e[:time] }.reverse
90
- stack_events.delete_if{|evt| @seen_events.include?(evt)}
88
+ end.flatten.compact.find_all { |e| e[:time] }.reverse
89
+ stack_events.delete_if { |evt| @seen_events.include?(evt) }
91
90
  @seen_events.concat(stack_events)
92
- unless(@initial_complete)
93
- stack_events = stack_events.sort_by{|e| e[:time] }
94
- unless(config[:all_events])
91
+ unless @initial_complete
92
+ stack_events = stack_events.sort_by { |e| e[:time] }
93
+ unless config[:all_events]
95
94
  start_index = stack_events.rindex do |item|
96
95
  item[:stack_name] == stack.name &&
97
96
  item[:resource_state].to_s.end_with?('in_progress') &&
98
97
  item[:resource_status_reason].to_s.downcase.include?('user init')
99
98
  end
100
- if(start_index)
99
+ if start_index
101
100
  stack_events.slice!(0, start_index)
102
101
  end
103
102
  end
@@ -121,7 +120,7 @@ module Sfn
121
120
  # @return [Array<String>] allowed attributes for events
122
121
  def allowed_attributes
123
122
  result = super
124
- unless(@stacks.size > 1)
123
+ unless @stacks.size > 1
125
124
  result.delete('stack_name')
126
125
  end
127
126
  result
@@ -4,7 +4,6 @@ module Sfn
4
4
  class Command
5
5
  # Export command
6
6
  class Export < Command
7
-
8
7
  include Sfn::CommandModule::Base
9
8
  include Sfn::Utils::ObjectStorage
10
9
 
@@ -15,7 +14,7 @@ module Sfn
15
14
  ui.info "#{ui.color('Stack Export:', :bold)} #{stack_name}"
16
15
  ui.confirm 'Perform export'
17
16
  stack = provider.stacks.get(stack_name)
18
- if(stack)
17
+ if stack
19
18
  export_options = Smash.new.tap do |opts|
20
19
  [:chef_popsicle, :chef_environment_parameter, :ignore_parameters].each do |key|
21
20
  opts[key] = config[key] unless config[key].nil?
@@ -25,14 +24,14 @@ module Sfn
25
24
  result = exporter.export
26
25
  outputs = [
27
26
  write_to_file(result, stack),
28
- write_to_bucket(result, stack)
27
+ write_to_bucket(result, stack),
29
28
  ].compact
30
- if(outputs.empty?)
29
+ if outputs.empty?
31
30
  ui.warn 'No persistent output location defined. Printing export:'
32
31
  ui.info _format_json(result)
33
32
  end
34
33
  ui.info "#{ui.color('Stack export', :bold)} (#{name_args.first}): #{ui.color('complete', :green)}"
35
- unless(outputs.empty?)
34
+ unless outputs.empty?
36
35
  outputs.each do |output|
37
36
  ui.info ui.color(" -> #{output}", :blue)
38
37
  end
@@ -49,8 +48,8 @@ module Sfn
49
48
  # @return [String] file name
50
49
  def export_file_name(stack)
51
50
  name = config[:file]
52
- if(name)
53
- if(name.respond_to?(:call))
51
+ if name
52
+ if name.respond_to?(:call)
54
53
  name.call(stack)
55
54
  else
56
55
  name.to_s
@@ -67,16 +66,15 @@ module Sfn
67
66
  # @return [String, NilClass] path to file
68
67
  def write_to_file(payload, stack)
69
68
  raise NotImplementedError
70
- if(config[:path])
69
+ if config[:path]
71
70
  full_path = File.join(
72
71
  config[:path],
73
72
  export_file_name(stack)
74
73
  )
75
74
  _, bucket, path = full_path.split('/', 3)
76
75
  directory = provider.service_for(:storage,
77
- :provider => :local,
78
- :local_root => '/'
79
- ).directories.get(bucket)
76
+ :provider => :local,
77
+ :local_root => '/').directories.get(bucket)
80
78
  file_store(payload, path, directory)
81
79
  end
82
80
  end
@@ -88,16 +86,14 @@ module Sfn
88
86
  # @return [String, NilClass] remote bucket key
89
87
  def write_to_bucket(payload, stack)
90
88
  raise NotImplementedError
91
- if(bucket = config[:bucket])
89
+ if bucket = config[:bucket]
92
90
  key_path = File.join(*[
93
- bucket_prefix(stack),
94
- export_file_name(stack)
95
- ].compact
96
- )
91
+ bucket_prefix(stack),
92
+ export_file_name(stack),
93
+ ].compact)
97
94
  file_store(payload, key_path, provider.service_for(:storage).directories.get(bucket))
98
95
  end
99
96
  end
100
-
101
97
  end
102
98
  end
103
99
  end
@@ -5,7 +5,6 @@ module Sfn
5
5
  class Command
6
6
  # Graph command
7
7
  class Graph < Command
8
-
9
8
  autoload :Provider, 'sfn/command/graph/provider'
10
9
 
11
10
  include Sfn::CommandModule::Base
@@ -15,7 +14,7 @@ module Sfn
15
14
  # Valid graph styles
16
15
  GRAPH_STYLES = [
17
16
  'creation',
18
- 'dependency'
17
+ 'dependency',
19
18
  ]
20
19
 
21
20
  # Generate graph
@@ -24,13 +23,13 @@ module Sfn
24
23
  validate_graph_style!
25
24
  file = load_template_file
26
25
  provider = Bogo::Utility.camel(file.provider).to_sym
27
- if(Provider.constants.include?(provider))
26
+ if Provider.constants.include?(provider)
28
27
  graph_const = Provider.const_get(provider)
29
28
  ui.debug "Loading provider graph implementation - #{graph_const}"
30
29
  extend graph_const
31
30
  @outputs = Smash.new
32
31
  ui.info "Template resource graph generation - Style: #{ui.color(config[:graph_style], :bold)}"
33
- if(config[:file])
32
+ if config[:file]
34
33
  ui.puts " -> path: #{config[:file]}"
35
34
  end
36
35
  template_dump = file.compile.sparkle_dump!.to_smash
@@ -49,7 +48,7 @@ module Sfn
49
48
  end
50
49
  run_action 'Writing graph result' do
51
50
  FileUtils.mkdir_p(File.dirname(config[:output_file]))
52
- if(config[:output_type] == 'dot')
51
+ if config[:output_type] == 'dot'
53
52
  File.open("#{config[:output_file]}.dot", 'w') do |o_file|
54
53
  o_file.puts graph.to_s
55
54
  end
@@ -59,7 +58,7 @@ module Sfn
59
58
  nil
60
59
  end
61
60
  else
62
- valid_providers = Provider.constants.sort.map{ |provider|
61
+ valid_providers = Provider.constants.sort.map { |provider|
63
62
  Bogo::Utility.snake(provider)
64
63
  }.join('`, `')
65
64
  ui.error "Graphing for provider `#{file.provider}` not currently supported."
@@ -67,14 +66,14 @@ module Sfn
67
66
  end
68
67
  end
69
68
 
70
- def generate_graph(template, args={})
69
+ def generate_graph(template, args = {})
71
70
  graph = ::Graph.new
72
71
  @root_graph = graph unless @root_graph
73
72
  graph.graph_attribs << ::Graph::Attribute.new('overlap = false')
74
73
  graph.graph_attribs << ::Graph::Attribute.new('splines = true')
75
74
  graph.graph_attribs << ::Graph::Attribute.new('pack = true')
76
75
  graph.graph_attribs << ::Graph::Attribute.new('start = "random"')
77
- if(args[:name])
76
+ if args[:name]
78
77
  graph.name = "cluster_#{args[:name]}"
79
78
  labelnode_key = "cluster_#{args[:name]}"
80
79
  graph.plaintext << graph.node(labelnode_key)
@@ -88,7 +87,7 @@ module Sfn
88
87
 
89
88
  def colorize(string)
90
89
  hash = string.chars.inject(0) do |memo, chr|
91
- if(memo + chr.ord > 127)
90
+ if memo + chr.ord > 127
92
91
  (memo - chr.ord).abs
93
92
  else
94
93
  memo + chr.ord
@@ -98,7 +97,7 @@ module Sfn
98
97
  3.times do |i|
99
98
  color << (255 ^ hash).to_s(16)
100
99
  new_val = hash + (hash * (1 / (i + 1.to_f))).to_i
101
- if(hash * (i + 1) < 127)
100
+ if hash * (i + 1) < 127
102
101
  hash = new_val
103
102
  else
104
103
  hash = hash / (i + 1)
@@ -108,16 +107,15 @@ module Sfn
108
107
  end
109
108
 
110
109
  def validate_graph_style!
111
- if(config[:luckymike])
110
+ if config[:luckymike]
112
111
  ui.warn 'Detected luckymike power override. Forcing `dependency` style!'
113
112
  config[:graph_style] = 'dependency'
114
113
  end
115
114
  config[:graph_style] = config[:graph_style].to_s
116
- unless(GRAPH_STYLES.include?(config[:graph_style]))
115
+ unless GRAPH_STYLES.include?(config[:graph_style])
117
116
  raise ArgumentError.new "Invalid graph style provided `#{config[:graph_style]}`. Valid: `#{GRAPH_STYLES.join('`, `')}`"
118
117
  end
119
118
  end
120
-
121
119
  end
122
120
  end
123
121
  end