sfn 3.0.20 → 3.0.22

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: fb7f6574c00a8cf09a14557610e3a00ea89e22d0
4
- data.tar.gz: e606f5fd3a2b9a9ba7b6ddad048a138d52259ea3
3
+ metadata.gz: 279982d00c24881c257eff78a3d14ed604952146
4
+ data.tar.gz: 9a093919f17154f3fc20920b933691f0438c0583
5
5
  SHA512:
6
- metadata.gz: 29704f3a0467a4e32a597b3565598852f5f38e15e6964d5f869930d46db46fbf0a9affea9605cbc8dac0f61267f1b63d2cb3c307b81e77d132d90f27932eda69
7
- data.tar.gz: 8985b3018da481d53f3214aa9302b58d5800730c94e16d42baa9b94ba9976b214ec7f759b80d4337ac9d51f19d45672e52acfdbe1ced3abefaa7ea3c48dffe1f
6
+ metadata.gz: 01741b34e7ef10214fa4f8902d2d35d1f175752d822f632e8f21e20ffdf5721e0a667fdf2f5ed1d5d56c87e87d3c8afb24319622bcbd62af70aa8e4c509b1a45
7
+ data.tar.gz: 57220d7bc625e74aa0b7f9f5ecbbc4fc22e77f56d11a3fda68bd1d5583ef4b84bb0084322496f7188b16d061212c51eeaf839c731290bc12e85ec523733a61ec
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ # v3.0.22
2
+ * [fix] Properly match compile time parameters (#235)
3
+ * [fix] Remove AWS policy statements for undefined resources (#240)
4
+ * [enhancement] Support conditions when possible within planner (#230)
5
+ * [feature] Add alpha support for Terraform (#236)
6
+
1
7
  # v3.0.20
2
8
  * [fix] Only dump templates when dumpable (#220, #223)
3
9
  * [enhancement] Support NoEcho template parameters (#226)
data/README.md CHANGED
@@ -13,6 +13,7 @@ with orchestration APIs.
13
13
  * Heat
14
14
  * OpenStack
15
15
  * Rackspace
16
+ * Terraform
16
17
 
17
18
  ## Documentation
18
19
 
@@ -4,6 +4,7 @@ module Sfn
4
4
  module ApiProvider
5
5
 
6
6
  autoload :Google, 'sfn/api_provider/google'
7
+ autoload :Terraform, 'sfn/api_provider/terraform'
7
8
 
8
9
  end
9
10
  end
@@ -0,0 +1,71 @@
1
+ require 'sfn'
2
+
3
+ module Sfn
4
+ module ApiProvider
5
+
6
+ module Terraform
7
+
8
+ # Disable remote template storage
9
+ def store_template(*_)
10
+ end
11
+
12
+ # No formatting required on stack results
13
+ def format_nested_stack_results(*_)
14
+ {}
15
+ end
16
+
17
+ # Extract current parameters from parent template
18
+ #
19
+ # @param stack [SparkleFormation]
20
+ # @param stack_name [String]
21
+ # @param c_stack [Miasma::Models::Orchestration::Stack]
22
+ # @return [Hash]
23
+ def extract_current_nested_template_parameters(stack, stack_name, c_stack)
24
+ if(c_stack && c_stack.data[:parent_stack])
25
+ c_stack.data[:parent_stack].sparkleish_template(:remove_wrapper).fetch(
26
+ :resources, stack_name, :properties, :parameters, Smash.new
27
+ )
28
+ elsif(stack.parent)
29
+ val = stack.parent.compile.resources.set!(stack_name).properties
30
+ val.nil? ? Smash.new : val._dump
31
+ else
32
+ Smash.new
33
+ end
34
+ end
35
+
36
+ # Disable parameter validate as we can't adjust them without template modifications
37
+ def validate_stack_parameter(*_)
38
+ true
39
+ end
40
+
41
+ # Determine if parameter was set via intrinsic function
42
+ #
43
+ # @param val [Object]
44
+ # @return [TrueClass, FalseClass]
45
+ def function_set_parameter?(val)
46
+ if(val)
47
+ val.start_with?('${')
48
+ end
49
+ end
50
+
51
+ # Override requirement of nesting bucket
52
+ def validate_nesting_bucket!
53
+ true
54
+ end
55
+
56
+ # Override template content extraction to disable scrub behavior
57
+ #
58
+ # @param thing [SparkleFormation, Hash]
59
+ # @return [Hash]
60
+ def template_content(thing, *_)
61
+ if(thing.is_a?(SparkleFormation))
62
+ config[:sparkle_dump] ? thing.sparkle_dump : thing.dump
63
+ else
64
+ thing
65
+ end
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+ end
@@ -74,19 +74,28 @@ module Sfn
74
74
  # @param p_stack [Miasma::Models::Orchestration::Stack]
75
75
  # @return [NilClass]
76
76
  def save_stack_policy(p_stack)
77
+ valid_logical_ids = p_stack.resources.reload.all.map(&:logical_id)
78
+ stack_policy = @policies.fetch(p_stack.id,
79
+ @policies.fetch(p_stack.data[:logical_id]),
80
+ @policies[p_stack.name]
81
+ ).to_smash
82
+ if(stack_policy)
83
+ stack_policy[:statement].delete_if do |policy_item|
84
+ policy_match = policy_item[:resource].to_s.match(
85
+ %r{LogicalResourceId/(?<logical_id>.+)$}
86
+ )
87
+ if(policy_match)
88
+ !valid_logical_ids.include?(policy_match["logical_id"])
89
+ end
90
+ end
91
+ end
77
92
  result = p_stack.api.request(
78
93
  :path => '/',
79
94
  :method => :post,
80
95
  :form => Smash.new(
81
96
  'Action' => 'SetStackPolicy',
82
97
  'StackName' => p_stack.id,
83
- 'StackPolicyBody' => MultiJson.dump(
84
- @policies.fetch(p_stack.id,
85
- @policies.fetch(p_stack.data[:logical_id],
86
- @policies[p_stack.name]
87
- )
88
- )
89
- )
98
+ 'StackPolicyBody' => MultiJson.dump(stack_policy)
90
99
  )
91
100
  )
92
101
  end
@@ -83,7 +83,7 @@ Configuration.new do
83
83
  # nesting_prefix 'nested-templates'
84
84
  # Remote provider credentials
85
85
  credentials do
86
- # Remote provider name (:aws, :azure, :google, :open_stack, :rackspace)
86
+ # Remote provider name (:aws, :azure, :google, :open_stack, :rackspace, :terraform)
87
87
  provider :aws
88
88
  # AWS credentials information
89
89
  aws_access_key_id ENV['AWS_ACCESS_KEY_ID']
@@ -123,6 +123,14 @@ Configuration.new do
123
123
  google_service_account_email ENV['GOOGLE_SERVICE_ACCOUNT_EMAIL']
124
124
  google_service_account_private_key ENV['GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY']
125
125
  google_project ENV['GOOGLE_PROJECT']
126
+ # Terraform credentials information
127
+ # Valid driver names: :tfe, :boule, :local
128
+ terraform_driver :local
129
+ terraform_tfe_endpoint ENV['TFE_URL']
130
+ terraform_tfe_token ENV['TFE_TOKEN']
131
+ terraform_boule_endpoint ENV['BOULE_URL']
132
+ terraform_local_directory './terraform-stacks'
133
+ terraform_local_scrub_destroyed false
126
134
  end
127
135
  end
128
136
  EOF
@@ -30,8 +30,14 @@ module Sfn
30
30
  stack = provider.connection.stacks.get(stack_name)
31
31
  if(stack)
32
32
  nested_stack_cleanup!(stack)
33
- api_action!(:api_stack => stack) do
34
- stack.destroy
33
+ begin
34
+ api_action!(:api_stack => stack) do
35
+ stack.destroy
36
+ end
37
+ rescue Miasma::Error::ApiError::RequestError => error
38
+ raise unless error.response.code == 404
39
+ # if stack is already gone, disable polling
40
+ config[:poll] = false
35
41
  end
36
42
  ui.info "Destroy request complete for stack: #{ui.color(stack_name, :red)}"
37
43
  else
@@ -21,9 +21,7 @@ module Sfn
21
21
  config[:print_only] = true
22
22
  validate_graph_style!
23
23
  file = load_template_file
24
- file = parameter_scrub!(file.sparkle_dump)
25
24
  @outputs = Smash.new
26
- file = file.to_smash
27
25
  ui.info "Template resource graph generation - Style: #{ui.color(config[:graph_style], :bold)}"
28
26
  if(config[:file])
29
27
  ui.puts " -> path: #{config[:file]}"
@@ -38,14 +36,14 @@ module Sfn
38
36
  end
39
37
  graph = nil
40
38
  run_action 'Generating resource graph' do
41
- graph = generate_graph(file.to_smash)
39
+ graph = generate_graph(file)
42
40
  nil
43
41
  end
44
42
  run_action 'Writing graph result' do
45
43
  FileUtils.mkdir_p(File.dirname(config[:output_file]))
46
44
  if(config[:output_type] == 'dot')
47
- File.open("#{config[:output_file]}.dot", 'w') do |file|
48
- file.puts graph.to_s
45
+ File.open("#{config[:output_file]}.dot", 'w') do |o_file|
46
+ o_file.puts graph.to_s
49
47
  end
50
48
  else
51
49
  graph.save config[:output_file], config[:output_type]
@@ -74,10 +72,11 @@ module Sfn
74
72
  end
75
73
 
76
74
  def output_discovery(template, outputs, resource_name, parent_template, name='')
77
- if(template['Resources'])
78
- template['Resources'].each_pair do |r_name, r_info|
79
- if(r_info['Type'] == 'AWS::CloudFormation::Stack')
80
- output_discovery(r_info['Properties']['Stack'], outputs, r_name, template, r_name)
75
+ unless(template.resources.nil?)
76
+ template.resources.keys!.each do |r_name|
77
+ r_info = template.resources[r_name]
78
+ if(r_info.type == template._self.stack_resource_name)
79
+ output_discovery(r_info.properties.stack, outputs, r_name, template, r_name)
81
80
  end
82
81
  end
83
82
  end
@@ -69,7 +69,6 @@ module Sfn
69
69
  end
70
70
  end
71
71
  ui.info " -> #{stack_info}"
72
-
73
72
  if(file)
74
73
  if(config[:print_only])
75
74
  ui.puts format_json(parameter_scrub!(template_content(file)))
@@ -16,6 +16,8 @@ module Sfn
16
16
  TEMPLATE_PARAMETER_DEFAULTS = ['Default', 'defaultValue', 'default']
17
17
  # Template parameter no echo locations
18
18
  TEMPLATE_PARAMETER_NOECHO = ['NoEcho']
19
+ # Template parameter no echo custom
20
+ TEMPLATE_PARAMETER_SFN_NOECHO = ['Quiet', 'quiet']
19
21
 
20
22
  # Apply any defined remote stacks
21
23
  #
@@ -143,16 +145,19 @@ module Sfn
143
145
  # @param parameter_prefix [Array<String>] nesting prefix names
144
146
  # @param parameter_name [String] parameter name
145
147
  # @return [Array<String>] [expected_template_key, configuration_used_key]
146
- def locate_config_parameter_key(parameter_prefix, parameter_name)
148
+ def locate_config_parameter_key(parameter_prefix, parameter_name, root_name)
147
149
  check_name = parameter_name.downcase.tr('-_', '')
148
150
  check_prefix = parameter_prefix.map{|i| i.downcase.tr('-_', '') }
149
151
  key_match = config[:parameters].keys.detect do |cp_key|
150
152
  cp_key = cp_key.to_s.downcase.split('__').map{|i| i.tr('-_', '') }.join('__')
151
- cp_key.start_with?(check_prefix.join('__')) &&
152
- cp_key.split('__').last == check_name
153
+ non_root_matcher = (check_prefix + [check_name]).join('__')
154
+ root_matcher = ([root_name] + check_prefix + [check_name]).join('__')
155
+ cp_key == non_root_matcher ||
156
+ cp_key == root_matcher
153
157
  end
154
158
  actual_key = (parameter_prefix + [parameter_name]).compact.join('__')
155
159
  if(key_match)
160
+ ui.debug "Remapping configuration runtime parameter `#{key_match}` -> `#{actual_key}`"
156
161
  config[:parameters][actual_key] = config[:parameters].delete(key_match)
157
162
  end
158
163
  actual_key
@@ -186,12 +191,19 @@ module Sfn
186
191
  )
187
192
  )
188
193
  if(config[:interactive_parameters])
194
+ no_echo = !!TEMPLATE_PARAMETER_NOECHO.detect{|loc_key|
195
+ param_value[loc_key].to_s.downcase == 'true'
196
+ }
197
+ sfn_no_echo = TEMPLATE_PARAMETER_SFN_NOECHO.map do |loc_key|
198
+ res = param_value.delete(loc_key).to_s.downcase
199
+ res if !res.empty? && res != 'false'
200
+ end.compact.first
201
+ no_echo = sfn_no_echo if sfn_no_echo
189
202
  answer = ui.ask_question(
190
203
  "#{param_name.split(/([A-Z]+[^A-Z]*)/).find_all{|s|!s.empty?}.join(' ')}",
191
204
  :default => default,
192
- :no_echo => !!TEMPLATE_PARAMETER_NOECHO.detect{|loc_key|
193
- param_value[loc_key].to_s.downcase == 'true'
194
- }
205
+ :hide_default => sfn_no_echo == 'all',
206
+ :no_echo => !!no_echo
195
207
  )
196
208
  else
197
209
  answer = default
@@ -221,21 +233,25 @@ module Sfn
221
233
  # @option opts [Miasma::Models::Orchestration::Stack] :stack existing stack
222
234
  # @return [Hash]
223
235
  def populate_parameters!(sparkle, opts={})
224
- current_parameters = opts.fetch(:current_parameters, {})
236
+ current_parameters = opts[:current_parameters] || {}
225
237
  current_stack = opts[:stack]
226
238
  parameter_prefix, stack_parameters = prefix_parameters_setup(sparkle)
227
239
  unless(stack_parameters.empty?)
228
240
  format_config_parameters!
229
241
  param_banner = false
230
242
  stack_parameters.each do |param_name, param_value|
231
- ns_key = locate_config_parameter_key(parameter_prefix, param_name)
243
+ ns_key = locate_config_parameter_key(parameter_prefix, param_name, sparkle.root.name)
232
244
  # When parameter is a hash type, it is being set via
233
245
  # intrinsic function and we don't modify
234
246
  if(function_set_parameter?(current_parameters[param_name]))
235
- if(current_stack)
236
- enable_set = validate_stack_parameter(current_stack, param_name, ns_key, current_parameters[param_name])
247
+ if(!config[:parameters][ns_key].nil?)
248
+ ui.warn "Overriding mapped parameter value with explicit assignment `#{ns_key}`!"
237
249
  else
238
- enable_set = true
250
+ if(current_stack)
251
+ enable_set = validate_stack_parameter(current_stack, param_name, ns_key, current_parameters[param_name])
252
+ else
253
+ enable_set = true
254
+ end
239
255
  end
240
256
  if(enable_set)
241
257
  # NOTE: direct set dumps the stack (nfi). Smash will
@@ -180,13 +180,30 @@ module Sfn
180
180
  else
181
181
  current_state = compile_state.fetch(f_name, Smash.new)
182
182
  end
183
+
184
+ # NOTE: Prevent nesting stack compile state within stack compile state
185
+ current_state.delete("#{f_name}__#{f_name}")
186
+
183
187
  if(formation.compile_state)
184
188
  current_state = current_state.merge(formation.compile_state)
185
189
  end
186
190
  unless(formation.parameters.empty?)
187
191
  ui.info "#{ui.color('Compile time parameters:', :bold)} - template: #{ui.color(pathed_name, :green, :bold)}" unless config[:print_only]
188
192
  formation.parameters.each do |k,v|
189
- current_state[k] = request_compile_parameter(k, v, current_state[k], !!formation.parent)
193
+ valid_keys = [
194
+ "#{f_name}__#{k}",
195
+ Bogo::Utility.camel("#{f_name}__#{k}").downcase,
196
+ k,
197
+ Bogo::Utility.camel(k).downcase
198
+ ]
199
+ current_value = valid_keys.map do |key|
200
+ current_state[key]
201
+ end.compact.first
202
+ primary_key, secondary_key = ["#{f_name}__#{k}", k]
203
+ current_state[k] = request_compile_parameter(k, v,
204
+ current_value,
205
+ !!formation.parent
206
+ )
190
207
  end
191
208
  formation.compile_state = current_state
192
209
  end
@@ -231,19 +248,19 @@ module Sfn
231
248
  # core parameter set
232
249
  def merge_compile_time_parameters
233
250
  compile_state = config.fetch(:compile_parameters, Smash.new)
251
+ ui.debug "Initial compile parameters - #{compile_state}"
234
252
  compile_state.keys.each do |cs_key|
235
- if(cs_key.to_s.start_with?("#{arguments.first}__"))
236
- cli_provided = compile_state.delete(cs_key.to_s.sub("#{arguments.first.to_s}__", ''))
237
- if(cli_provided)
238
- compile_state[cs_key].deep_merge!(cli_provided)
253
+ unless(cs_key.to_s.start_with?("#{arguments.first}__"))
254
+ named_cs_key = "#{arguments.first}__#{cs_key}"
255
+ non_named = compile_state.delete(cs_key)
256
+ if(non_named && !compile_state.key?(named_cs_key))
257
+ ui.debug "Setting non-named compile parameter `#{cs_key}` into `#{named_cs_key}`"
258
+ compile_state[named_cs_key] = non_named
259
+ else
260
+ ui.debug "Discarding non-named compile parameter due to set named - `#{cs_key}` </> `#{named_cs_key}`"
239
261
  end
240
262
  end
241
263
  end
242
- compile_state.keys.each do |cs_key|
243
- unless(cs_key.start_with?("#{arguments.first}__"))
244
- compile_state["#{arguments.first}__#{cs_key}"] = compile_state.delete(cs_key)
245
- end
246
- end
247
264
  ui.debug "Merged compile parameters - #{compile_state}"
248
265
  compile_state
249
266
  end
@@ -82,13 +82,22 @@ module Sfn
82
82
  result = Smash.new
83
83
  v.split(',').each do |item_pair|
84
84
  key, value = item_pair.split(/[=:]/, 2)
85
- key = key.split('__')
86
- key = [key.pop, key.join('__')].reverse
87
- result.set(*key, value)
85
+ result[key] = value
88
86
  end
89
87
  result
90
88
  when Hash
91
- v.to_smash
89
+ result = Smash.new
90
+ extractor = lambda do |data, prefix|
91
+ data.each_pair do |key, value|
92
+ local_key = "#{prefix}__#{key}"
93
+ if(value.is_a?(Hash))
94
+ extractor.call(value, local_key)
95
+ else
96
+ result[local_key] = data
97
+ end
98
+ end
99
+ end
100
+ result
92
101
  else
93
102
  v
94
103
  end
@@ -14,6 +14,8 @@ module Sfn
14
14
  REF_MAPPING = {}
15
15
  FN_MAPPING = {}
16
16
 
17
+ UNKNOWN_RUNTIME_RESULT = '__UNKNOWN_RUNTIME_RESULT__'
18
+
17
19
  # @return [Array<String>] flagged items for value replacement
18
20
  attr_reader :flagged
19
21
 
@@ -23,6 +25,11 @@ module Sfn
23
25
  @flagged = []
24
26
  end
25
27
 
28
+ # @return [Hash] defined conditions
29
+ def conditions
30
+ @original.fetch('Conditions', {})
31
+ end
32
+
26
33
  # Flag a reference as modified
27
34
  #
28
35
  # @param ref_name [String]
@@ -48,30 +55,25 @@ module Sfn
48
55
  # @note also allows 'Ref' within funcs to provide mapping
49
56
  # replacements using the REF_MAPPING constant
50
57
  def apply_function(hash, funcs=[])
51
- k,v = hash.first
52
- if(hash.size == 1 && (k.start_with?('Fn') || k == 'Ref') && (funcs.empty? || funcs.include?(k)))
53
- case k
54
- when 'Fn::Join'
55
- v.last.join(v.first)
56
- when 'Fn::FindInMap'
57
- map_holder = mappings[v[0]]
58
- if(map_holder)
59
- map_item = map_holder[dereference(v[1])]
60
- if(map_item)
61
- map_item[v[2]]
58
+ if(hash.is_a?(Hash))
59
+ k,v = hash.first
60
+ if(hash.size == 1 && (k.start_with?('Fn') || k == 'Ref') && (funcs.include?(:all) || funcs.empty? || funcs.include?(k) || funcs == ['DEREF']))
61
+ method_name = Bogo::Utility.snake(k.gsub('::', ''))
62
+ if((funcs.include?(k) || funcs.include?(:all)) && respond_to?(method_name))
63
+ apply_function(send(method_name, v), funcs)
64
+ else
65
+ case k
66
+ when 'Fn::GetAtt'
67
+ funcs.include?('DEREF') ? dereference(hash) : hash
68
+ when 'Ref'
69
+ if(funcs.include?('DEREF'))
70
+ dereference(hash)
71
+ else
72
+ {'Ref' => self.class.const_get(:REF_MAPPING).fetch(v, v)}
73
+ end
62
74
  else
63
- raise "Failed to find mapping item! (#{v[0]} -> #{v[1]})"
75
+ hash
64
76
  end
65
- else
66
- raise "Failed to find mapping! (#{v[0]})"
67
- end
68
- when 'Fn::GetAtt'
69
- func.include?('DEREF') ? dereference(hash) : hash
70
- when 'Ref'
71
- if(funcs.include?('DEREF'))
72
- dereference(hash)
73
- else
74
- {'Ref' => self.class.const_get(:REF_MAPPING).fetch(v, v)}
75
77
  end
76
78
  else
77
79
  hash
@@ -81,6 +83,113 @@ module Sfn
81
83
  end
82
84
  end
83
85
 
86
+ # Evaluate given condition
87
+ #
88
+ # @param name [String] condition name
89
+ # @return [TrueClass, FalseClass]
90
+ def apply_condition(name)
91
+ condition = conditions[name]
92
+ if(condition)
93
+ apply_function(condition, [:all, 'DEREF'])
94
+ else
95
+ raise "Failed to locate condition with name `#{name}`!"
96
+ end
97
+ end
98
+
99
+ # Evaluate `if` conditional
100
+ #
101
+ # @param value [Array] {0: condition name, 1: true value, 2: false value}
102
+ # @return [Object] true or false value
103
+ def fn_if(value)
104
+ result = apply_condition(value[0])
105
+ if(result != UNKNOWN_RUNTIME_RESULT)
106
+ result ? value[1] : value[2]
107
+ else
108
+ UNKNOWN_RUNTIME_RESULT
109
+ result
110
+ end
111
+ end
112
+
113
+ # Determine if all conditions are true
114
+ #
115
+ # @param value [Array<String>] condition names
116
+ # @return [TrueClass, FalseClass]
117
+ def fn_and(value)
118
+ result = value.map do |val|
119
+ apply_condition(val)
120
+ end
121
+ if(result.to_s.include?(RUNTIME_MODIFIED))
122
+ UNKNOWN_RUNTIME_RESULT
123
+ else
124
+ result.all?
125
+ end
126
+ end
127
+
128
+ # Determine if any values are true
129
+ #
130
+ # @param value [Array<String>] condition names
131
+ # @return [TrueClass, FalseClass]
132
+ def fn_or(value)
133
+ result = value.map do |val|
134
+ apply_condition(val)
135
+ end
136
+ if(result.to_s.include?(RUNTIME_MODIFIED))
137
+ UNKNOWN_RUNTIME_RESULT
138
+ else
139
+ result.any?
140
+ end
141
+ end
142
+
143
+ # Negate given value
144
+ #
145
+ # @param value [Array<Hash>]
146
+ # @return [TrueClass, FalseClass]
147
+ def fn_not(value)
148
+ result = apply_function(value)
149
+ result == RUNTIME_MODIFIED ? UNKNOWN_RUNTIME_RESULT : !result
150
+ end
151
+
152
+ # Determine if values are equal
153
+ #
154
+ # @param value [Array] values
155
+ # @return [TrueClass, FalseClass]
156
+ def fn_equals(value)
157
+ value = value.map do |val|
158
+ apply_function(val)
159
+ end
160
+ if(value.to_s.include?(RUNTIME_MODIFIED))
161
+ UNKNOWN_RUNTIME_RESULT
162
+ else
163
+ value.first == value.last
164
+ end
165
+ end
166
+
167
+ # Join values with given delimiter
168
+ #
169
+ # @param value [Array<String,Array<String>>]
170
+ # @return [String]
171
+ def fn_join(value)
172
+ value.last.join(value.first)
173
+ end
174
+
175
+ # Lookup value in mappings
176
+ #
177
+ # @param value [Array]
178
+ # @return [String, Fixnum]
179
+ def fn_find_in_map(value)
180
+ map_holder = mappings[value[0]]
181
+ if(map_holder)
182
+ map_item = map_holder[dereference(value[1])]
183
+ if(map_item)
184
+ map_item[value[2]]
185
+ else
186
+ raise "Failed to find mapping item! (#{value[0]} -> #{value[1]})"
187
+ end
188
+ else
189
+ raise "Failed to find mapping! (#{value[0]})"
190
+ end
191
+ end
192
+
84
193
  # Override the parent dereference behavior to return junk
85
194
  # value on flagged resource match
86
195
  #
@@ -416,15 +525,19 @@ module Sfn
416
525
  ]
417
526
  )
418
527
  begin
419
- r_info = SparkleFormation::Resources::Aws.resource_lookup(type)
420
- r_property = r_info.property(property_name)
421
- if(r_property)
422
- effect = r_property.update_causes(
423
- templates.get(:update, 'Resources', resource_name),
424
- templates.get(:origin, 'Resources', resource_name)
425
- )
528
+ if(templates.get(:update, 'Resources', resource_name, 'Properties', property_name) == Translator::UNKNOWN_RUNTIME_RESULT)
529
+ effect = :unknown
426
530
  else
427
- raise KeyError.new 'Unknown property'
531
+ r_info = SparkleFormation::Resources::Aws.resource_lookup(type)
532
+ r_property = r_info.property(property_name)
533
+ if(r_property)
534
+ effect = r_property.update_causes(
535
+ templates.get(:update, 'Resources', resource_name),
536
+ templates.get(:origin, 'Resources', resource_name)
537
+ )
538
+ else
539
+ raise KeyError.new 'Unknown property'
540
+ end
428
541
  end
429
542
  case effect.to_sym
430
543
  when :replacement
@@ -507,19 +620,30 @@ module Sfn
507
620
  template.keys.each do |t_key|
508
621
  next if ['Outputs', 'Resources'].include?(t_key)
509
622
  template[t_key] = translator.dereference_processor(
510
- template[t_key], ['Ref', 'Fn', 'DEREF', 'Fn::FindInMap']
623
+ template[t_key], ['DEREF']
511
624
  )
512
625
  end
513
626
  translator.original.replace(template)
514
- if(template['Resources'])
515
- template['Resources'] = translator.dereference_processor(
516
- template['Resources'], ['Ref', 'Fn', 'DEREF', 'Fn::FindInMap']
517
- )
627
+ ['Outputs', 'Resources'].each do |t_key|
628
+ if(template[t_key])
629
+ template[t_key] = translator.dereference_processor(
630
+ template[t_key], ['DEREF', :all]
631
+ )
632
+ end
518
633
  end
519
- if(template['Outputs'])
520
- template['Outputs'] = translator.dereference_processor(
521
- template['Outputs'], ['Ref', 'Fn', 'DEREF', 'Fn::FindInMap']
522
- )
634
+ if(template['Resources'])
635
+ valid_resources = template['Resources'].map do |resource_name, resource_value|
636
+ if(resource_value['OnCondition'])
637
+ if(translator.apply_condition(resource_value['OnCondition']))
638
+ resource_name
639
+ end
640
+ else
641
+ resource_name
642
+ end
643
+ end.compact
644
+ (template['Resources'].keys - valid_resources).each do |resource_to_remove|
645
+ template['Resources'].delete(resource_to_remove)
646
+ end
523
647
  end
524
648
  translator.original.replace({})
525
649
  template
data/lib/sfn/provider.rb CHANGED
@@ -78,7 +78,7 @@ module Sfn
78
78
  )
79
79
  @cache = args.fetch(:cache, Cache.new(:local))
80
80
  @async = args.fetch(:async, true)
81
- @miamsa_args = args[:miasma].dup
81
+ @miasma_args = args[:miasma].dup
82
82
  cache.init(:stacks_lock, :lock, :timeout => 0.1)
83
83
  cache.init(:stacks, :stamped)
84
84
  cache.init(:stack_expansion_lock, :lock, :timeout => 0.1)
data/lib/sfn/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Sfn
2
2
  # Current library version
3
- VERSION = Gem::Version.new('3.0.20')
3
+ VERSION = Gem::Version.new('3.0.22')
4
4
  end
data/sfn.gemspec CHANGED
@@ -11,20 +11,23 @@ Gem::Specification.new do |s|
11
11
  s.license = 'Apache-2.0'
12
12
  s.require_path = 'lib'
13
13
  s.add_runtime_dependency 'bogo-cli', '>= 0.2.5', '< 0.4'
14
- s.add_runtime_dependency 'bogo-ui', '>= 0.1.20', '< 0.4'
14
+ s.add_runtime_dependency 'bogo-ui', '>= 0.1.22', '< 0.4'
15
15
  s.add_runtime_dependency 'miasma', '>= 0.3.0', '< 0.4'
16
16
  s.add_runtime_dependency 'miasma-aws', '>= 0.3.6', '< 0.4'
17
17
  s.add_runtime_dependency 'miasma-azure', '>= 0.1.0', '< 0.3'
18
18
  s.add_runtime_dependency 'miasma-open-stack', '>= 0.1.0', '< 0.3'
19
19
  s.add_runtime_dependency 'miasma-rackspace', '>= 0.1.0', '< 0.3'
20
20
  s.add_runtime_dependency 'miasma-google', '>= 0.1.0', '< 0.3'
21
+ s.add_runtime_dependency 'miasma-terraform', '>= 0.1.0', '< 0.2.0'
21
22
  s.add_runtime_dependency 'jmespath'
22
23
  s.add_runtime_dependency 'net-ssh'
23
- s.add_runtime_dependency 'sparkle_formation', '>= 3.0.3', '< 4'
24
+ s.add_runtime_dependency 'sparkle_formation', '>= 3.0.11', '< 4'
24
25
  s.add_runtime_dependency 'hashdiff', '~> 0.2.2'
25
26
  s.add_runtime_dependency 'graph', '~> 2.8.1'
26
27
  s.add_development_dependency 'rake', '~> 10'
27
28
  s.add_development_dependency 'minitest'
29
+ s.add_development_dependency 'rspec', '~> 3.5'
30
+ s.add_development_dependency 'rubocop', '0.38.0'
28
31
  s.add_development_dependency 'mocha'
29
32
  s.add_development_dependency 'yard'
30
33
  s.executables << 'sfn'
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.20
4
+ version: 3.0.22
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Roberts
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-10-02 00:00:00.000000000 Z
11
+ date: 2017-02-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bogo-cli
@@ -36,7 +36,7 @@ dependencies:
36
36
  requirements:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
- version: 0.1.20
39
+ version: 0.1.22
40
40
  - - "<"
41
41
  - !ruby/object:Gem::Version
42
42
  version: '0.4'
@@ -46,7 +46,7 @@ dependencies:
46
46
  requirements:
47
47
  - - ">="
48
48
  - !ruby/object:Gem::Version
49
- version: 0.1.20
49
+ version: 0.1.22
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
52
  version: '0.4'
@@ -170,6 +170,26 @@ dependencies:
170
170
  - - "<"
171
171
  - !ruby/object:Gem::Version
172
172
  version: '0.3'
173
+ - !ruby/object:Gem::Dependency
174
+ name: miasma-terraform
175
+ requirement: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: 0.1.0
180
+ - - "<"
181
+ - !ruby/object:Gem::Version
182
+ version: 0.2.0
183
+ type: :runtime
184
+ prerelease: false
185
+ version_requirements: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - ">="
188
+ - !ruby/object:Gem::Version
189
+ version: 0.1.0
190
+ - - "<"
191
+ - !ruby/object:Gem::Version
192
+ version: 0.2.0
173
193
  - !ruby/object:Gem::Dependency
174
194
  name: jmespath
175
195
  requirement: !ruby/object:Gem::Requirement
@@ -204,7 +224,7 @@ dependencies:
204
224
  requirements:
205
225
  - - ">="
206
226
  - !ruby/object:Gem::Version
207
- version: 3.0.3
227
+ version: 3.0.11
208
228
  - - "<"
209
229
  - !ruby/object:Gem::Version
210
230
  version: '4'
@@ -214,7 +234,7 @@ dependencies:
214
234
  requirements:
215
235
  - - ">="
216
236
  - !ruby/object:Gem::Version
217
- version: 3.0.3
237
+ version: 3.0.11
218
238
  - - "<"
219
239
  - !ruby/object:Gem::Version
220
240
  version: '4'
@@ -274,6 +294,34 @@ dependencies:
274
294
  - - ">="
275
295
  - !ruby/object:Gem::Version
276
296
  version: '0'
297
+ - !ruby/object:Gem::Dependency
298
+ name: rspec
299
+ requirement: !ruby/object:Gem::Requirement
300
+ requirements:
301
+ - - "~>"
302
+ - !ruby/object:Gem::Version
303
+ version: '3.5'
304
+ type: :development
305
+ prerelease: false
306
+ version_requirements: !ruby/object:Gem::Requirement
307
+ requirements:
308
+ - - "~>"
309
+ - !ruby/object:Gem::Version
310
+ version: '3.5'
311
+ - !ruby/object:Gem::Dependency
312
+ name: rubocop
313
+ requirement: !ruby/object:Gem::Requirement
314
+ requirements:
315
+ - - '='
316
+ - !ruby/object:Gem::Version
317
+ version: 0.38.0
318
+ type: :development
319
+ prerelease: false
320
+ version_requirements: !ruby/object:Gem::Requirement
321
+ requirements:
322
+ - - '='
323
+ - !ruby/object:Gem::Version
324
+ version: 0.38.0
277
325
  - !ruby/object:Gem::Dependency
278
326
  name: mocha
279
327
  requirement: !ruby/object:Gem::Requirement
@@ -346,6 +394,7 @@ files:
346
394
  - lib/sfn.rb
347
395
  - lib/sfn/api_provider.rb
348
396
  - lib/sfn/api_provider/google.rb
397
+ - lib/sfn/api_provider/terraform.rb
349
398
  - lib/sfn/cache.rb
350
399
  - lib/sfn/callback.rb
351
400
  - lib/sfn/callback/aws_assume_role.rb
@@ -435,7 +484,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
435
484
  version: '0'
436
485
  requirements: []
437
486
  rubyforge_project:
438
- rubygems_version: 2.5.1
487
+ rubygems_version: 2.4.8
439
488
  signing_key:
440
489
  specification_version: 4
441
490
  summary: SparkleFormation CLI