sfn 3.0.20 → 3.0.22
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +1 -0
- data/lib/sfn/api_provider.rb +1 -0
- data/lib/sfn/api_provider/terraform.rb +71 -0
- data/lib/sfn/callback/stack_policy.rb +16 -7
- data/lib/sfn/command/conf.rb +9 -1
- data/lib/sfn/command/destroy.rb +8 -2
- data/lib/sfn/command/graph.rb +8 -9
- data/lib/sfn/command/update.rb +0 -1
- data/lib/sfn/command_module/stack.rb +27 -11
- data/lib/sfn/command_module/template.rb +27 -10
- data/lib/sfn/config/validate.rb +13 -4
- data/lib/sfn/planner/aws.rb +163 -39
- data/lib/sfn/provider.rb +1 -1
- data/lib/sfn/version.rb +1 -1
- data/sfn.gemspec +5 -2
- metadata +56 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 279982d00c24881c257eff78a3d14ed604952146
|
4
|
+
data.tar.gz: 9a093919f17154f3fc20920b933691f0438c0583
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
data/lib/sfn/api_provider.rb
CHANGED
@@ -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
|
data/lib/sfn/command/conf.rb
CHANGED
@@ -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
|
data/lib/sfn/command/destroy.rb
CHANGED
@@ -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
|
-
|
34
|
-
stack
|
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
|
data/lib/sfn/command/graph.rb
CHANGED
@@ -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
|
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 |
|
48
|
-
|
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
|
-
|
78
|
-
template
|
79
|
-
|
80
|
-
|
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
|
data/lib/sfn/command/update.rb
CHANGED
@@ -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
|
-
|
152
|
-
|
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
|
-
:
|
193
|
-
|
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
|
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(
|
236
|
-
|
247
|
+
if(!config[:parameters][ns_key].nil?)
|
248
|
+
ui.warn "Overriding mapped parameter value with explicit assignment `#{ns_key}`!"
|
237
249
|
else
|
238
|
-
|
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
|
-
|
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
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
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
|
data/lib/sfn/config/validate.rb
CHANGED
@@ -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 =
|
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
|
-
|
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
|
data/lib/sfn/planner/aws.rb
CHANGED
@@ -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
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
-
|
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
|
-
|
420
|
-
|
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
|
-
|
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], ['
|
623
|
+
template[t_key], ['DEREF']
|
511
624
|
)
|
512
625
|
end
|
513
626
|
translator.original.replace(template)
|
514
|
-
|
515
|
-
template[
|
516
|
-
template[
|
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['
|
520
|
-
template['
|
521
|
-
|
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
|
-
@
|
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
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.
|
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.
|
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.
|
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:
|
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.
|
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.
|
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.
|
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.
|
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.
|
487
|
+
rubygems_version: 2.4.8
|
439
488
|
signing_key:
|
440
489
|
specification_version: 4
|
441
490
|
summary: SparkleFormation CLI
|