sfn 3.0.26 → 3.0.28

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1000514f95a36a106dc13fd6eaf7a38a9e716776
4
- data.tar.gz: fc0d733bafcd09198a2a56252c574956ded1ae22
3
+ metadata.gz: 403602f06deb39fe3f2751236c97dd6f06443431
4
+ data.tar.gz: 69f16806fb62a281b40d8f6588b4d5bf5772419d
5
5
  SHA512:
6
- metadata.gz: 7ef25e6f6722a338b428d5707dde1912d0c94a8c3adab30a297fe9ad830f0cbc415eff1130e3f824bcc0d46bd2f6e423259595f6093486dd3efe51d50e8d801c
7
- data.tar.gz: a179f76dd94173102a5e6d07fb20e91a4f689b21a02a6d79024d09bc10c373dee37403f8e15e7152692642de738c457039d76523c9a5c693408e195df8e2b4dc
6
+ metadata.gz: b36166fbdb2424563aec23d2c068616264582b25192ab4e377ae7312aa210d1565d721270af1885bc14196e4f56a05afa47afa1b926a815de278aa8c90591415
7
+ data.tar.gz: 710cf024266fbe9725150f0930756e28d5a284b85db61ad033b048e106fd90bc3cd94c3c8e4b316f474b65e2148acc3e02afa9b06c2b3f676f557cb48a09c07d
@@ -1,3 +1,8 @@
1
+ # v3.0.28
2
+ * [fix] Fix stack save policy callback (#264)
3
+ * [fix] Prevent processing unset event arrays
4
+ * [enhancement] Support graphing terraform provider templates
5
+
1
6
  # v3.0.26
2
7
  * [fix] Properly support compile time parameter setting with/without stack name (#261)
3
8
  * [fix] Default stack name when storing policy internally if no name provided
@@ -66,6 +66,5 @@ module Sfn
66
66
  end
67
67
 
68
68
  end
69
-
70
69
  end
71
70
  end
@@ -80,8 +80,8 @@ module Sfn
80
80
  @policies[p_stack.name]
81
81
  ).to_smash
82
82
  if(stack_policy)
83
- stack_policy[:statement].delete_if do |policy_item|
84
- policy_match = policy_item[:resource].to_s.match(
83
+ stack_policy[:Statement].delete_if do |policy_item|
84
+ policy_match = policy_item[:Resource].to_s.match(
85
85
  %r{LogicalResourceId/(?<logical_id>.+)$}
86
86
  )
87
87
  if(policy_match)
@@ -65,13 +65,13 @@ module Sfn
65
65
  # @return [TrueClass, FalseClass]
66
66
  def load_api_provider_extensions!
67
67
  if(config.get(:credentials, :provider))
68
- base_ext = Bogo::Utility.camel(config.get(:credentials, :provider))
68
+ base_ext = Bogo::Utility.camel(config.get(:credentials, :provider)).to_sym
69
69
  targ_ext = self.class.name.split('::').last
70
- if(ApiProvider.const_defined?(base_ext))
70
+ if(ApiProvider.constants.include?(base_ext))
71
71
  base_module = ApiProvider.const_get(base_ext)
72
72
  ui.debug "Loading core provider extensions via `#{base_module}`"
73
73
  extend base_module
74
- if(base_module.const_defined?(targ_ext))
74
+ if(base_module.constants.include?(targ_ext))
75
75
  targ_module = base_module.const_get(targ_ext)
76
76
  ui.debug "Loading targeted provider extensions via `#{targ_module}`"
77
77
  extend targ_module
@@ -63,6 +63,7 @@ module Sfn
63
63
  # @return [Array<Hash>]
64
64
  def get_events(*args)
65
65
  stack_events = discover_stacks(stack).map do |i_stack|
66
+ i_events = []
66
67
  begin
67
68
  if(@initial_complete && i_stack.in_progress?)
68
69
  i_events = i_stack.events.update!
@@ -73,12 +74,17 @@ module Sfn
73
74
  if(e.class.to_s.start_with?('Errno'))
74
75
  ui.warn "Connection error encountered: #{e.message} (retrying)"
75
76
  ui.debug "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
76
- sleep(5)
77
- retry
77
+ else
78
+ ui.error "Unexpected error received fetching events: #{e.message}"
79
+ ui.debug "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
78
80
  end
81
+ sleep(5)
82
+ retry
79
83
  end
80
- i_events.map do |e|
81
- e.attributes.merge(:stack_name => i_stack.name).to_smash
84
+ if(i_events)
85
+ i_events.map do |e|
86
+ e.attributes.merge(:stack_name => i_stack.name).to_smash
87
+ end
82
88
  end
83
89
  end.flatten.compact.find_all{|e| e[:time] }.reverse
84
90
  stack_events.delete_if{|evt| @seen_events.include?(evt)}
@@ -6,6 +6,8 @@ module Sfn
6
6
  # Graph command
7
7
  class Graph < Command
8
8
 
9
+ autoload :Provider, 'sfn/command/graph/provider'
10
+
9
11
  include Sfn::CommandModule::Base
10
12
  include Sfn::CommandModule::Template
11
13
  include Sfn::CommandModule::Stack
@@ -21,13 +23,17 @@ module Sfn
21
23
  config[:print_only] = true
22
24
  validate_graph_style!
23
25
  file = load_template_file
24
- if(file.provider == :aws)
26
+ provider = Bogo::Utility.camel(file.provider).to_sym
27
+ if(Provider.constants.include?(provider))
28
+ graph_const = Provider.const_get(provider)
29
+ ui.debug "Loading provider graph implementation - #{graph_const}"
30
+ extend graph_const
25
31
  @outputs = Smash.new
26
32
  ui.info "Template resource graph generation - Style: #{ui.color(config[:graph_style], :bold)}"
27
33
  if(config[:file])
28
34
  ui.puts " -> path: #{config[:file]}"
29
35
  end
30
- template_dump = file.compile.dump!.to_smash
36
+ template_dump = file.compile.sparkle_dump!.to_smash
31
37
  run_action 'Pre-processing template for graphing' do
32
38
  output_discovery(template_dump, @outputs, nil, nil)
33
39
  ui.debug 'Output remapping results from pre-processing:'
@@ -53,8 +59,11 @@ module Sfn
53
59
  nil
54
60
  end
55
61
  else
62
+ valid_providers = Provider.constants.sort.map{ |provider|
63
+ Bogo::Utility.snake(provider)
64
+ }.join('`, `')
56
65
  ui.error "Graphing for provider `#{file.provider}` not currently supported."
57
- ui.error "Currently supported providers: `aws`."
66
+ ui.error "Currently supported providers: `#{valid_providers}`."
58
67
  end
59
68
  end
60
69
 
@@ -77,137 +86,6 @@ module Sfn
77
86
  graph
78
87
  end
79
88
 
80
- def output_discovery(template, outputs, resource_name, parent_template, name='')
81
- if(template['Resources'])
82
- template['Resources'].keys.each do |r_name|
83
- r_info = template['Resources'][r_name]
84
- if(r_info['Type'] == 'AWS::CloudFormation::Stack')
85
- output_discovery(r_info['Properties']['Stack'], outputs, r_name, template, r_name)
86
- end
87
- end
88
- end
89
- if(parent_template)
90
- ui.debug "Pre-processing stack resource `#{resource_name}`"
91
- substack_parameters = Smash[
92
- parent_template.fetch('Resources', resource_name, 'Properties', 'Parameters', {}).map do |key, value|
93
- result = [key, value]
94
- if(value.is_a?(Hash))
95
- v_key = value.keys.first
96
- v_value = value.values.first
97
- if(v_key == 'Fn::GetAtt' && parent_template.fetch('Resources', {}).keys.include?(v_value.first) && v_value.last.start_with?('Outputs.'))
98
- output_key = v_value.first + '__' + v_value.last.split('.', 2).last
99
- ui.debug "Output key for check: #{output_key}"
100
- if(outputs.key?(output_key))
101
- new_value = outputs[output_key]
102
- result = [key, new_value]
103
- ui.debug "Parameter for output swap `#{key}`: #{value} -> #{new_value}"
104
- end
105
- end
106
- end
107
- result
108
- end
109
- ]
110
-
111
- ui.debug "Generated internal parameters for `#{resource_name}`: #{substack_parameters}"
112
-
113
- processor = GraphProcessor.new({},
114
- :parameters => substack_parameters
115
- )
116
- template['Resources'] = processor.dereference_processor(
117
- template['Resources'], ['Ref']
118
- )
119
- template['Outputs'] = processor.dereference_processor(
120
- template['Outputs'], ['Ref']
121
- )
122
- rename_processor = GraphProcessor.new({},
123
- :parameters => Smash[
124
- template.fetch('Resources', {}).keys.map do |r_key|
125
- [r_key, {'Ref' => [name, r_key].join}]
126
- end
127
- ]
128
- )
129
- derefed_outs = rename_processor.dereference_processor(
130
- template.fetch('Outputs', {})
131
- ) || {}
132
-
133
- derefed_outs.each do |o_name, o_data|
134
- o_key = [name, o_name].join('__')
135
- outputs[o_key] = o_data['Value']
136
- end
137
- end
138
- outputs.dup.each do |key, value|
139
- if(value.is_a?(Hash))
140
- v_key = value.keys.first
141
- v_value = value.values.first
142
- if(v_key == 'Fn::GetAtt' && v_value.last.start_with?('Outputs.'))
143
- output_key = v_value.first << '__' << v_value.last.split('.', 2).last
144
- if(outputs.key?(output_key))
145
- outputs[key] = outputs[output_key]
146
- end
147
- end
148
- end
149
- end
150
- end
151
-
152
- def edge_detection(template, graph, name = '', resource_names = [])
153
- resources = template.fetch('Resources', {})
154
- node_prefix = name
155
- resources.each do |resource_name, resource_data|
156
- node_name = [node_prefix, resource_name].join
157
- if(resource_data['Type'] == 'AWS::CloudFormation::Stack')
158
- graph.subgraph << generate_graph(
159
- resource_data['Properties'].delete('Stack'),
160
- :name => resource_name,
161
- :type => resource_data['Type'],
162
- :resource_names => resource_names
163
- )
164
- next
165
- else
166
- graph.node(node_name).attributes << graph.fillcolor(colorize(node_prefix.empty? ? config[:file] : node_prefix).inspect)
167
- graph.box3d << graph.node(node_name)
168
- end
169
- graph.filled << graph.node(node_name)
170
- graph.node(node_name).label "#{resource_name}\n<#{resource_data['Type']}>\n#{name}"
171
- resource_dependencies(resource_data, resource_names + resources.keys).each do |dep_name|
172
- if(resources.keys.include?(dep_name))
173
- dep_name = [node_prefix, dep_name].join
174
- end
175
- if(config[:graph_style] == 'creation')
176
- @root_graph.edge(dep_name, node_name)
177
- else
178
- @root_graph.edge(node_name, dep_name)
179
- end
180
- end
181
- end
182
- resource_names.concat resources.keys.map{|r_name| [node_prefix, r_name].join}
183
- end
184
-
185
- def resource_dependencies(data, names)
186
- case data
187
- when Hash
188
- data.map do |key, value|
189
- if(key == 'Ref' && names.include?(value))
190
- value
191
- elsif(key == 'DependsOn')
192
- [value].flatten.compact.find_all do |dependson_name|
193
- names.include?(dependson_name)
194
- end
195
- elsif(key == 'Fn::GetAtt' && names.include?(res = [value].flatten.compact.first))
196
- res
197
- else
198
- resource_dependencies(key, names) +
199
- resource_dependencies(value, names)
200
- end
201
- end.flatten.compact.uniq
202
- when Array
203
- data.map do |item|
204
- resource_dependencies(item, names)
205
- end.flatten.compact.uniq
206
- else
207
- []
208
- end
209
- end
210
-
211
89
  def colorize(string)
212
90
  hash = string.chars.inject(0) do |memo, chr|
213
91
  if(memo + chr.ord > 127)
@@ -240,38 +118,6 @@ module Sfn
240
118
  end
241
119
  end
242
120
 
243
- class GraphProcessor < SparkleFormation::Translation
244
- MAP = {}
245
- REF_MAPPING = {}
246
- FN_MAPPING = {}
247
-
248
- attr_accessor :name
249
-
250
- def initialize(template, args={})
251
- super
252
- @name = args[:name]
253
- end
254
-
255
- def apply_function(hash, funcs=[])
256
- k, v = hash.first
257
- if(hash.size == 1)
258
- case k
259
- when 'Ref'
260
- parameters.key?(v) ? parameters[v] : hash
261
- when 'Fn::Join'
262
- v.last
263
- when 'Fn::Select'
264
- v.last[v.first.to_i]
265
- else
266
- hash
267
- end
268
- else
269
- hash
270
- end
271
- end
272
-
273
- end
274
-
275
121
  end
276
122
  end
277
123
  end
@@ -0,0 +1,174 @@
1
+ require 'sfn'
2
+
3
+ module Sfn
4
+ class Command
5
+ # Graph command
6
+ class Graph < Command
7
+ module Provider
8
+ module Aws
9
+ class AwsGraphProcessor < SparkleFormation::Translation
10
+ MAP = {}
11
+ REF_MAPPING = {}
12
+ FN_MAPPING = {}
13
+
14
+ attr_accessor :name
15
+
16
+ def initialize(template, args={})
17
+ super
18
+ @name = args[:name]
19
+ end
20
+
21
+ def apply_function(hash, funcs=[])
22
+ k, v = hash.first
23
+ if(hash.size == 1)
24
+ case k
25
+ when 'Ref'
26
+ parameters.key?(v) ? parameters[v] : hash
27
+ when 'Fn::Join'
28
+ v.last
29
+ when 'Fn::Select'
30
+ v.last[v.first.to_i]
31
+ else
32
+ hash
33
+ end
34
+ else
35
+ hash
36
+ end
37
+ end
38
+ end
39
+
40
+ def output_discovery(template, outputs, resource_name, parent_template, name='')
41
+ if(template['Resources'])
42
+ template['Resources'].keys.each do |r_name|
43
+ r_info = template['Resources'][r_name]
44
+ if(r_info['Type'] == 'AWS::CloudFormation::Stack')
45
+ output_discovery(r_info['Properties']['Stack'], outputs, r_name, template, r_name)
46
+ end
47
+ end
48
+ end
49
+ if(parent_template)
50
+ ui.debug "Pre-processing stack resource `#{resource_name}`"
51
+ substack_parameters = Smash[
52
+ parent_template.fetch('Resources', resource_name, 'Properties', 'Parameters', {}).map do |key, value|
53
+ result = [key, value]
54
+ if(value.is_a?(Hash))
55
+ v_key = value.keys.first
56
+ v_value = value.values.first
57
+ if(v_key == 'Fn::GetAtt' && parent_template.fetch('Resources', {}).keys.include?(v_value.first) && v_value.last.start_with?('Outputs.'))
58
+ output_key = v_value.first + '__' + v_value.last.split('.', 2).last
59
+ ui.debug "Output key for check: #{output_key}"
60
+ if(outputs.key?(output_key))
61
+ new_value = outputs[output_key]
62
+ result = [key, new_value]
63
+ ui.debug "Parameter for output swap `#{key}`: #{value} -> #{new_value}"
64
+ end
65
+ end
66
+ end
67
+ result
68
+ end
69
+ ]
70
+
71
+ ui.debug "Generated internal parameters for `#{resource_name}`: #{substack_parameters}"
72
+
73
+ processor = AwsGraphProcessor.new({},
74
+ :parameters => substack_parameters
75
+ )
76
+ template['Resources'] = processor.dereference_processor(
77
+ template['Resources'], ['Ref']
78
+ )
79
+ template['Outputs'] = processor.dereference_processor(
80
+ template['Outputs'], ['Ref']
81
+ )
82
+ rename_processor = AwsGraphProcessor.new({},
83
+ :parameters => Smash[
84
+ template.fetch('Resources', {}).keys.map do |r_key|
85
+ [r_key, {'Ref' => [name, r_key].join}]
86
+ end
87
+ ]
88
+ )
89
+ derefed_outs = rename_processor.dereference_processor(
90
+ template.fetch('Outputs', {})
91
+ ) || {}
92
+
93
+ derefed_outs.each do |o_name, o_data|
94
+ o_key = [name, o_name].join('__')
95
+ outputs[o_key] = o_data['Value']
96
+ end
97
+ end
98
+ outputs.dup.each do |key, value|
99
+ if(value.is_a?(Hash))
100
+ v_key = value.keys.first
101
+ v_value = value.values.first
102
+ if(v_key == 'Fn::GetAtt' && v_value.last.start_with?('Outputs.'))
103
+ output_key = v_value.first << '__' << v_value.last.split('.', 2).last
104
+ if(outputs.key?(output_key))
105
+ outputs[key] = outputs[output_key]
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ def edge_detection(template, graph, name = '', resource_names = [])
113
+ resources = template.fetch('Resources', {})
114
+ node_prefix = name
115
+ resources.each do |resource_name, resource_data|
116
+ node_name = [node_prefix, resource_name].join
117
+ if(resource_data['Type'] == 'AWS::CloudFormation::Stack')
118
+ graph.subgraph << generate_graph(
119
+ resource_data['Properties'].delete('Stack'),
120
+ :name => resource_name,
121
+ :type => resource_data['Type'],
122
+ :resource_names => resource_names
123
+ )
124
+ next
125
+ else
126
+ graph.node(node_name).attributes << graph.fillcolor(colorize(node_prefix.empty? ? config[:file] : node_prefix).inspect)
127
+ graph.box3d << graph.node(node_name)
128
+ end
129
+ graph.filled << graph.node(node_name)
130
+ graph.node(node_name).label "#{resource_name}\n<#{resource_data['Type']}>\n#{name}"
131
+ resource_dependencies(resource_data, resource_names + resources.keys).each do |dep_name|
132
+ if(resources.keys.include?(dep_name))
133
+ dep_name = [node_prefix, dep_name].join
134
+ end
135
+ if(config[:graph_style] == 'creation')
136
+ @root_graph.edge(dep_name, node_name)
137
+ else
138
+ @root_graph.edge(node_name, dep_name)
139
+ end
140
+ end
141
+ end
142
+ resource_names.concat resources.keys.map{|r_name| [node_prefix, r_name].join}
143
+ end
144
+
145
+ def resource_dependencies(data, names)
146
+ case data
147
+ when Hash
148
+ data.map do |key, value|
149
+ if(key == 'Ref' && names.include?(value))
150
+ value
151
+ elsif(key == 'DependsOn')
152
+ [value].flatten.compact.find_all do |dependson_name|
153
+ names.include?(dependson_name)
154
+ end
155
+ elsif(key == 'Fn::GetAtt' && names.include?(res = [value].flatten.compact.first))
156
+ res
157
+ else
158
+ resource_dependencies(key, names) +
159
+ resource_dependencies(value, names)
160
+ end
161
+ end.flatten.compact.uniq
162
+ when Array
163
+ data.map do |item|
164
+ resource_dependencies(item, names)
165
+ end.flatten.compact.uniq
166
+ else
167
+ []
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,13 @@
1
+ require 'sfn'
2
+
3
+ module Sfn
4
+ class Command
5
+ # Graph command
6
+ class Graph < Command
7
+ module Provider
8
+ autoload :Aws, "sfn/command/graph/aws"
9
+ autoload :Terraform, "sfn/command/graph/terraform"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,193 @@
1
+ require 'sfn'
2
+
3
+ module Sfn
4
+ class Command
5
+ # Graph command
6
+ class Graph < Command
7
+ module Provider
8
+ module Terraform
9
+ class TerraformGraphProcessor < SparkleFormation::Translation
10
+ MAP = {}
11
+ REF_MAPPING = {}
12
+ FN_MAPPING = {}
13
+
14
+ attr_accessor :name
15
+
16
+ def initialize(template, args={})
17
+ super
18
+ @name = args[:name]
19
+ end
20
+
21
+ def dereference_processor(obj, funcs=[])
22
+ case obj
23
+ when Array
24
+ obj = obj.map{|v| dereference_processor(v, funcs)}
25
+ when Hash
26
+ new_hash = {}
27
+ obj.each do |k, v|
28
+ new_hash[k] = dereference_processor(v, funcs)
29
+ end
30
+ obj = new_hash
31
+ when String
32
+ obj = apply_function(obj, funcs)
33
+ end
34
+ obj
35
+ end
36
+
37
+ def parameters
38
+ Hash[
39
+ @original.fetch('parameters', {}).map do |k, v|
40
+ [k, v.fetch('default', '')]
41
+ end
42
+ ].merge(@parameters)
43
+ end
44
+
45
+ def resources
46
+ @original.fetch('resources', {})
47
+ end
48
+
49
+ def outputs
50
+ @original.fetch('outputs', {})
51
+ end
52
+
53
+ def apply_function(string, funcs=[])
54
+ # first check for vars and replace with params
55
+ string.scan(/(\$\{var\.(.+?)\})/).each do |match|
56
+ if(parameters[match.last])
57
+ string.sub!(match.first, parameters[match.last])
58
+ end
59
+ end
60
+ string
61
+ end
62
+ end
63
+
64
+ def output_discovery(template, outputs, resource_name, parent_template, name='')
65
+ if(template['resources'])
66
+ template['resources'].keys.each do |r_name|
67
+ r_info = template['resources'][r_name]
68
+ if(r_info['type'] == 'module')
69
+ output_discovery(r_info['properties']['stack'], outputs, r_name, template, r_name)
70
+ end
71
+ end
72
+ end
73
+ if(parent_template)
74
+ ui.debug "Pre-processing stack resource `#{resource_name}`"
75
+ substack_parameters = Smash[
76
+ parent_template.fetch('resources', resource_name, 'properties', 'parameters', {}).map do |key, value|
77
+ result = [key, value]
78
+ if(value.to_s.start_with?('${module.'))
79
+ output_key = value.sub('${module.', '').sub('}', '').sub('.', '__')
80
+ ui.debug "Output key for check: #{output_key}"
81
+ if(outputs.key?(output_key))
82
+ new_value = outputs[output_key]
83
+ result = [key, new_value]
84
+ ui.debug "Parameter for output swap `#{key}`: #{value} -> #{new_value}"
85
+ end
86
+ end
87
+ result
88
+ end
89
+ ]
90
+
91
+ ui.debug "Generated internal parameters for `#{resource_name}`: #{substack_parameters}"
92
+
93
+ processor = TerraformGraphProcessor.new({},
94
+ :parameters => substack_parameters
95
+ )
96
+ template['resources'] = processor.dereference_processor(
97
+ template['resources'], []
98
+ )
99
+ template['outputs'] = processor.dereference_processor(
100
+ template['outputs'], []
101
+ )
102
+ derefed_outs = template['outputs'] || {}
103
+ derefed_outs.each do |o_name, o_data|
104
+ o_key = [name, o_name].join('__')
105
+ val = o_data['value']
106
+ if(val.start_with?('${') && val.scan('.').count == 2)
107
+ val = val.split('.')
108
+ val[1] = "#{name}__#{val[1]}"
109
+ val = val.join('.')
110
+ end
111
+ outputs[o_key] = val
112
+ end
113
+ end
114
+ outputs.dup.each do |key, value|
115
+ if(value.to_s.start_with?('${module.'))
116
+ output_key = value.to_s.sub('${module.', '').sub('}', '').sub('.', '__')
117
+ if(outputs.key?(output_key))
118
+ outputs[key] = outputs[output_key]
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ def edge_detection(template, graph, name = '', resource_names = [])
125
+ resources = (template.fetch('resources', {}) || {})
126
+ node_prefix = name
127
+ resources.each do |resource_name, resource_data|
128
+ node_name = [node_prefix, resource_name].join('__')
129
+ if(resource_data['type'] == 'module')
130
+ graph.subgraph << generate_graph(
131
+ resource_data['properties'].delete('stack'),
132
+ :name => resource_name,
133
+ :type => resource_data['type'],
134
+ :resource_names => resource_names
135
+ )
136
+ next
137
+ else
138
+ graph.node(node_name).attributes << graph.fillcolor(colorize(node_prefix.empty? ? config[:file] : node_prefix).inspect)
139
+ graph.box3d << graph.node(node_name)
140
+ end
141
+ graph.filled << graph.node(node_name)
142
+ graph.node(node_name).label "#{resource_name}\n<#{resource_data['type']}>\n#{name}"
143
+ resource_dependencies(resource_data, resource_names + resources.keys).each do |dep_name|
144
+ if(resources.keys.include?(dep_name))
145
+ dep_name = [node_prefix, dep_name].join('__')
146
+ end
147
+ if(config[:graph_style] == 'creation')
148
+ @root_graph.edge(dep_name, node_name)
149
+ else
150
+ @root_graph.edge(node_name, dep_name)
151
+ end
152
+ end
153
+ end
154
+ resource_names.concat resources.keys.map{|r_name| [node_prefix, r_name].join('__')}
155
+ end
156
+
157
+ def resource_dependencies(data, names)
158
+ case data
159
+ when String
160
+ result = []
161
+ if(data.start_with?('${') && data.scan('.').count >= 1)
162
+ data = data.tr('${}', '')
163
+ check_name = data.split('.')[1]
164
+ if names.include?(check_name)
165
+ result.push(check_name)
166
+ end
167
+ end
168
+ result
169
+ when Hash
170
+ data.map do |key, value|
171
+ if(key == 'depends_on')
172
+ [value].flatten.compact.map do |dependson_name|
173
+ dep_name = dependson_name.split('.').last
174
+ dep_name if names.include?(dep_name)
175
+ end
176
+ else
177
+ resource_dependencies(key, names) +
178
+ resource_dependencies(value, names)
179
+ end
180
+ end.flatten.compact.uniq
181
+ when Array
182
+ data.map do |item|
183
+ resource_dependencies(item, names)
184
+ end.flatten.compact.uniq
185
+ else
186
+ []
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end
@@ -1,4 +1,4 @@
1
1
  module Sfn
2
2
  # Current library version
3
- VERSION = Gem::Version.new('3.0.26')
3
+ VERSION = Gem::Version.new('3.0.28')
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sfn
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.26
4
+ version: 3.0.28
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Roberts
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-25 00:00:00.000000000 Z
11
+ date: 2017-09-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bogo-cli
@@ -409,6 +409,9 @@ files:
409
409
  - lib/sfn/command/events.rb
410
410
  - lib/sfn/command/export.rb
411
411
  - lib/sfn/command/graph.rb
412
+ - lib/sfn/command/graph/aws.rb
413
+ - lib/sfn/command/graph/provider.rb
414
+ - lib/sfn/command/graph/terraform.rb
412
415
  - lib/sfn/command/import.rb
413
416
  - lib/sfn/command/init.rb
414
417
  - lib/sfn/command/inspect.rb
@@ -484,7 +487,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
484
487
  version: '0'
485
488
  requirements: []
486
489
  rubyforge_project:
487
- rubygems_version: 2.4.8
490
+ rubygems_version: 2.6.11
488
491
  signing_key:
489
492
  specification_version: 4
490
493
  summary: SparkleFormation CLI