sfn 2.2.0 → 3.0.0
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 +4 -4
- data/CHANGELOG.md +20 -0
- data/bin/command-config-generator +44 -0
- data/bin/sfn +1 -5
- data/docs/README.md +2 -1
- data/docs/callbacks.md +18 -0
- data/docs/command-config.md +1276 -0
- data/docs/configuration.md +0 -105
- data/docs/overview.md +1 -0
- data/lib/sfn.rb +1 -0
- data/lib/sfn/api_provider.rb +9 -0
- data/lib/sfn/api_provider/google.rb +84 -0
- data/lib/sfn/command.rb +22 -0
- data/lib/sfn/command/create.rb +33 -45
- data/lib/sfn/command/describe.rb +1 -1
- data/lib/sfn/command/destroy.rb +7 -1
- data/lib/sfn/command/diff.rb +4 -5
- data/lib/sfn/command/graph.rb +1 -3
- data/lib/sfn/command/print.rb +3 -4
- data/lib/sfn/command/update.rb +89 -87
- data/lib/sfn/command/validate.rb +24 -11
- data/lib/sfn/command_module/base.rb +1 -12
- data/lib/sfn/command_module/stack.rb +45 -56
- data/lib/sfn/command_module/template.rb +74 -33
- data/lib/sfn/config/print.rb +5 -0
- data/lib/sfn/config/update.rb +4 -0
- data/lib/sfn/config/validate.rb +4 -0
- data/lib/sfn/monkey_patch/stack.rb +153 -83
- data/lib/sfn/monkey_patch/stack/azure.rb +23 -0
- data/lib/sfn/monkey_patch/stack/google.rb +129 -0
- data/lib/sfn/planner/aws.rb +111 -72
- data/lib/sfn/utils/json.rb +3 -0
- data/lib/sfn/utils/stack_parameter_scrubber.rb +20 -23
- data/lib/sfn/utils/stack_parameter_validator.rb +162 -157
- data/lib/sfn/version.rb +1 -1
- data/sfn.gemspec +3 -2
- metadata +34 -8
data/docs/configuration.md
CHANGED
@@ -61,109 +61,4 @@ can be accessed via:
|
|
61
61
|
$ knife sparkleformation --help
|
62
62
|
~~~
|
63
63
|
|
64
|
-
### Configuration Options
|
65
|
-
|
66
|
-
| Option | Attribute | Value
|
67
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
68
|
-
| `processing` | Description | Enable SparkleFormation processing
|
69
|
-
| | Valid | `TrueClass`, `FalseClass`
|
70
|
-
| | Default | `true`
|
71
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
72
|
-
| `apply_nesting` | Description | Style of nested stack processing
|
73
|
-
| | Valid | `"shallow"`, `"deep"`
|
74
|
-
| | Default | `"deep"`
|
75
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
76
|
-
| `options` | Description | API options for target API (see miasma)
|
77
|
-
| | Valid | `Hash`
|
78
|
-
| | Default | none
|
79
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
80
|
-
| `merge_api_options` | Description | Merges API options on stack update
|
81
|
-
| | Valid | `TrueClass`, `FalseClass`
|
82
|
-
| | Default | `false`
|
83
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
84
|
-
| `ssh_attempt_users` | Description | List of users to attempt SSH connection on node failure
|
85
|
-
| | Valid | `Array<String>`
|
86
|
-
| | Default | none
|
87
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
88
|
-
| `identity_file` | Description | Custom SSH identity file for node failure connection
|
89
|
-
| | Valid | `String`
|
90
|
-
| | Default | none
|
91
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
92
|
-
| `nesting_bucket` | Description | Name of bucket to store nested stack templates
|
93
|
-
| | Valid | `String`
|
94
|
-
| | Default | none
|
95
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
96
|
-
| `nesting_prefix` | Description | Prefix to prepend to template file name within object store
|
97
|
-
| | Valid | `String`
|
98
|
-
| | Default | none
|
99
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
100
|
-
| `sparkle_pack` | Description | SparklePacks to load
|
101
|
-
| | Valid | `Array<String>`
|
102
|
-
| | Default | none
|
103
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
104
|
-
| `parameters` | Description | Stack runtime parameters
|
105
|
-
| | Valid | `Hash`
|
106
|
-
| | Default | none
|
107
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
108
|
-
| `credentials` | Description | API credentials for target orchestration API
|
109
|
-
| | Valid | `Hash`
|
110
|
-
| | Default | none
|
111
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
112
|
-
| `callbacks` | Description | Callbacks to execute around API calls
|
113
|
-
| | Valid | `Hash`
|
114
|
-
| | Default | none
|
115
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
116
|
-
| `callbacks.before` | Description | Callbacks to execute before _any_ API call
|
117
|
-
| | Valid | `Array<String>`
|
118
|
-
| | Default | none
|
119
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
120
|
-
| `callbacks.after` | Description | Callbacks to execute after _any_ API call
|
121
|
-
| | Valid | `Array<String>`
|
122
|
-
| | Default | none
|
123
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
124
|
-
| `callbacks.before_COMMAND` | Description | Callbacks to execute before specific `COMMAND` API call
|
125
|
-
| | Valid | `Array<String>`
|
126
|
-
| | Default | none
|
127
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
128
|
-
| `callbacks.after_COMMAND` | Description | Callbacks to execute after specific `COMMAND` API call
|
129
|
-
| | Valid | `Array<String>`
|
130
|
-
| | Default | none
|
131
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
132
|
-
| `callbacks.template` | Description | Callbacks to execute on template
|
133
|
-
| | Valid | `Array<String>`
|
134
|
-
| | Default | none
|
135
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
136
|
-
| `callbacks.default` | Description | Callbacks to always execute
|
137
|
-
| | Valid | `Array<String>`
|
138
|
-
| | Default | none
|
139
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
140
|
-
| `callbacks.require` | Description | List of custom libraries to load
|
141
|
-
| | Valid | `Array<String>`
|
142
|
-
| | Default | none
|
143
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
144
|
-
| `retries` | Description | Configuration of API request retries
|
145
|
-
| | Valid | `Hash`
|
146
|
-
| | Default | none
|
147
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
148
|
-
| `retries.type` | Description | Retry implementation
|
149
|
-
| | Valid | `"flat"`, `"linear"`, `"exponential"`
|
150
|
-
| | Default | `"exponential"`
|
151
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
152
|
-
| `retries.interval` | Description | Base wait interval for retry
|
153
|
-
| | Valid | `Numeric`
|
154
|
-
| | Default | `5`
|
155
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
156
|
-
| `retries.max_attempts` | Description | Maximum number of attempts allowed (`nil` for infinite retry)
|
157
|
-
| | Valid | `Numeric`, `NilClass`
|
158
|
-
| | Default | `20`
|
159
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
160
|
-
| `stack_types` | Description | Define customized stack resource types
|
161
|
-
| | Valid | `Array<String>`
|
162
|
-
| | Default | `[DEFAULT_PROVIDER_TYPE]`
|
163
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
164
|
-
| `locations` | Description | API credentials for named locations (JackalStack resources)
|
165
|
-
| | Valid | `Hash`
|
166
|
-
| | Default | none
|
167
|
-
|----------------------------|---------------|---------------------------------------------------------------
|
168
|
-
|
169
64
|
[knife]: https://docs.chef.io/knife.html
|
data/docs/overview.md
CHANGED
data/lib/sfn.rb
CHANGED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'sfn'
|
2
|
+
|
3
|
+
module Sfn
|
4
|
+
module ApiProvider
|
5
|
+
|
6
|
+
module Google
|
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?('$(') || val.start_with?('{{')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Set parameters into parent resource properites
|
52
|
+
def populate_parameters!(template, opts={})
|
53
|
+
result = super
|
54
|
+
result.each_pair do |key, value|
|
55
|
+
if(template.parent)
|
56
|
+
template.parent.compile.resources.set!(template.name).properties.set!(key, value)
|
57
|
+
else
|
58
|
+
template.compile.resources.set!(template.name).properties.set!(key, value)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
{}
|
62
|
+
end
|
63
|
+
|
64
|
+
# Override requirement of nesting bucket
|
65
|
+
def validate_nesting_bucket!
|
66
|
+
true
|
67
|
+
end
|
68
|
+
|
69
|
+
# Override template content extraction to disable scrub behavior
|
70
|
+
#
|
71
|
+
# @param thing [SparkleFormation, Hash]
|
72
|
+
# @return [Hash]
|
73
|
+
def template_content(thing, *_)
|
74
|
+
if(thing.is_a?(SparkleFormation))
|
75
|
+
config[:sparkle_dump] ? thing.sparkle_dump : thing.dump
|
76
|
+
else
|
77
|
+
thing
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
data/lib/sfn/command.rb
CHANGED
@@ -45,6 +45,7 @@ module Sfn
|
|
45
45
|
ENV['DEBUG'] = 'true' if cli_opts[:debug]
|
46
46
|
end
|
47
47
|
super(cli_opts, args)
|
48
|
+
load_api_provider_extensions!
|
48
49
|
run_callbacks_for(:after_config)
|
49
50
|
run_callbacks_for("after_config_#{Bogo::Utility.snake(self.class.name.split('::').last)}")
|
50
51
|
end
|
@@ -58,6 +59,27 @@ module Sfn
|
|
58
59
|
|
59
60
|
protected
|
60
61
|
|
62
|
+
# Load API provider specific overrides to customize behavior
|
63
|
+
#
|
64
|
+
# @return [TrueClass, FalseClass]
|
65
|
+
def load_api_provider_extensions!
|
66
|
+
if(config.get(:credentials, :provider))
|
67
|
+
base_ext = Bogo::Utility.camel(config.get(:credentials, :provider))
|
68
|
+
targ_ext = self.class.name.split('::').last
|
69
|
+
if(ApiProvider.const_defined?(base_ext))
|
70
|
+
base_module = ApiProvider.const_get(base_ext)
|
71
|
+
ui.debug "Loading core provider extensions via `#{base_module}`"
|
72
|
+
extend base_module
|
73
|
+
if(base_module.const_defined?(targ_ext))
|
74
|
+
targ_module = base_module.const_get(targ_ext)
|
75
|
+
ui.debug "Loading targeted provider extensions via `#{targ_module}`"
|
76
|
+
extend targ_module
|
77
|
+
end
|
78
|
+
true
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
61
83
|
# Start with current working directory and traverse to root
|
62
84
|
# looking for a `.sfn` configuration file
|
63
85
|
#
|
data/lib/sfn/command/create.rb
CHANGED
@@ -22,7 +22,6 @@ module Sfn
|
|
22
22
|
file = config[:template]
|
23
23
|
else
|
24
24
|
file = load_template_file
|
25
|
-
nested_stacks_unpack = file.delete('sfn_nested_stack')
|
26
25
|
end
|
27
26
|
|
28
27
|
unless(config[:print_only])
|
@@ -34,66 +33,55 @@ module Sfn
|
|
34
33
|
stack_info << " #{ui.color('Path:', :bold)} #{config[:file]}"
|
35
34
|
end
|
36
35
|
|
37
|
-
|
36
|
+
if(config[:print_only])
|
37
|
+
ui.puts format_json(parameter_scrub!(template_content(file)))
|
38
|
+
return
|
39
|
+
else
|
38
40
|
ui.info " -> #{stack_info}"
|
39
41
|
end
|
40
42
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
ui.puts _format_json(
|
47
|
-
translate_template(
|
48
|
-
Sfn::Utils::StackParameterScrubber.scrub!(file)
|
49
|
-
)
|
50
|
-
)
|
51
|
-
return
|
52
|
-
end
|
53
|
-
|
54
|
-
stack = provider.connection.stacks.build(
|
55
|
-
config.fetch(:options, Smash.new).dup.merge(
|
56
|
-
:name => name,
|
57
|
-
:template => file
|
58
|
-
)
|
43
|
+
stack = provider.connection.stacks.build(
|
44
|
+
config.fetch(:options, Smash.new).dup.merge(
|
45
|
+
:name => name,
|
46
|
+
:template => template_content(file),
|
47
|
+
:parameters => Smash.new
|
59
48
|
)
|
49
|
+
)
|
60
50
|
|
61
|
-
|
62
|
-
|
51
|
+
apply_stacks!(stack)
|
52
|
+
populate_parameters!(file, :current_parameters => stack.parameters)
|
63
53
|
|
64
|
-
|
65
|
-
ui.puts _format_json(translate_template(stack.template))
|
66
|
-
return
|
67
|
-
end
|
68
|
-
|
69
|
-
populate_parameters!(stack.template)
|
70
|
-
stack.parameters = config_root_parameters
|
54
|
+
stack.parameters = config_root_parameters
|
71
55
|
|
72
|
-
|
56
|
+
if(config[:upload_root_template])
|
57
|
+
upload_result = store_template(name, file, Smash.new)
|
58
|
+
stack.template_url = upload_result[:url]
|
59
|
+
else
|
60
|
+
stack.template = parameter_scrub!(template_content(file, :scrub))
|
61
|
+
end
|
73
62
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
63
|
+
api_action!(:api_stack => stack) do
|
64
|
+
stack.save
|
65
|
+
if(config[:poll])
|
66
|
+
poll_stack(stack.name)
|
67
|
+
stack = provider.stack(name)
|
79
68
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
else
|
84
|
-
ui.fatal "Create of new stack #{ui.color(name, :bold)}: #{ui.color('FAILED', :red, :bold)}"
|
85
|
-
raise 'Stack did not reach a successful completion state.'
|
86
|
-
end
|
69
|
+
if(stack.reload.state == :create_complete)
|
70
|
+
ui.info "Stack create complete: #{ui.color('SUCCESS', :green)}"
|
71
|
+
namespace.const_get(:Describe).new({:outputs => true}, [name]).execute!
|
87
72
|
else
|
88
|
-
ui.
|
89
|
-
|
73
|
+
ui.fatal "Create of new stack #{ui.color(name, :bold)}: #{ui.color('FAILED', :red, :bold)}"
|
74
|
+
raise 'Stack did not reach a successful completion state.'
|
90
75
|
end
|
76
|
+
else
|
77
|
+
ui.warn 'Stack state polling has been disabled.'
|
78
|
+
ui.info "Stack creation initialized for #{ui.color(name, :green)}"
|
91
79
|
end
|
92
|
-
|
93
80
|
end
|
94
81
|
|
95
82
|
end
|
96
83
|
|
97
84
|
end
|
85
|
+
|
98
86
|
end
|
99
87
|
end
|
data/lib/sfn/command/describe.rb
CHANGED
@@ -73,7 +73,7 @@ module Sfn
|
|
73
73
|
# @param stack [Miasma::Models::Orchestration::Stack]
|
74
74
|
def outputs(stack)
|
75
75
|
ui.info "Outputs for stack: #{ui.color(stack.name, :bold)}"
|
76
|
-
unless(stack.outputs.empty?)
|
76
|
+
unless(stack.outputs.nil? || stack.outputs.empty?)
|
77
77
|
stack.outputs.each do |output|
|
78
78
|
key, value = output.key, output.value
|
79
79
|
key = snake(key).to_s.split('_').map(&:capitalize).join(' ')
|
data/lib/sfn/command/destroy.rb
CHANGED
@@ -40,7 +40,13 @@ module Sfn
|
|
40
40
|
end
|
41
41
|
if(config[:poll])
|
42
42
|
if(stacks.size == 1)
|
43
|
-
|
43
|
+
begin
|
44
|
+
poll_stack(stacks.first)
|
45
|
+
rescue Miasma::Error::ApiError::RequestError => error
|
46
|
+
unless(error.response.code == 404)
|
47
|
+
raise error
|
48
|
+
end
|
49
|
+
end
|
44
50
|
else
|
45
51
|
ui.error "Stack polling is not available when multiple stack deletion is requested!"
|
46
52
|
end
|
data/lib/sfn/command/diff.rb
CHANGED
@@ -17,7 +17,7 @@ module Sfn
|
|
17
17
|
name = name_args.first
|
18
18
|
|
19
19
|
begin
|
20
|
-
stack = provider.
|
20
|
+
stack = provider.stack(name)
|
21
21
|
rescue Miasma::Error::ApiError::RequestError
|
22
22
|
stack = nil
|
23
23
|
end
|
@@ -25,9 +25,7 @@ module Sfn
|
|
25
25
|
if(stack)
|
26
26
|
config[:print_only] = true
|
27
27
|
file = load_template_file
|
28
|
-
file.
|
29
|
-
file = Sfn::Utils::StackParameterScrubber.scrub!(file)
|
30
|
-
file = translate_template(file)
|
28
|
+
file = parameter_scrub!(file.dump)
|
31
29
|
|
32
30
|
ui.info "#{ui.color('SparkleFormation:', :bold)} #{ui.color('diff', :blue)} - #{name}"
|
33
31
|
ui.puts
|
@@ -39,10 +37,11 @@ module Sfn
|
|
39
37
|
end
|
40
38
|
end
|
41
39
|
|
40
|
+
# @todo needs updates for better provider compat
|
42
41
|
def diff_stack(stack, file, parent_names=[])
|
43
42
|
stack_template = stack.template
|
44
43
|
nested_stacks = Hash[
|
45
|
-
file
|
44
|
+
file.fetch('Resources', file.fetch('resources', {})).find_all do |name, value|
|
46
45
|
value.fetch('Properties', {})['Stack']
|
47
46
|
end
|
48
47
|
]
|
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.
|
25
|
-
file = Sfn::Utils::StackParameterScrubber.scrub!(file)
|
26
|
-
file = translate_template(file)
|
24
|
+
file = parameter_scrub!(file.sparkle_dump)
|
27
25
|
@outputs = Smash.new
|
28
26
|
file = file.to_smash
|
29
27
|
ui.info "Template resource graph generation - Style: #{ui.color(config[:graph_style], :bold)}"
|
data/lib/sfn/command/print.rb
CHANGED
@@ -10,14 +10,13 @@ module Sfn
|
|
10
10
|
include Sfn::CommandModule::Template
|
11
11
|
include Sfn::CommandModule::Stack
|
12
12
|
|
13
|
+
# Print the requested template
|
13
14
|
def execute!
|
14
15
|
config[:print_only] = true
|
15
16
|
file = load_template_file
|
16
|
-
file.delete('sfn_nested_stack')
|
17
|
-
file = Sfn::Utils::StackParameterScrubber.scrub!(file)
|
18
|
-
file = translate_template(file)
|
19
17
|
|
20
|
-
json_content =
|
18
|
+
json_content = format_json(parameter_scrub!(template_content(file)))
|
19
|
+
|
21
20
|
if(config[:write_to_file])
|
22
21
|
unless(File.directory?(File.dirname(config[:write_to_file])))
|
23
22
|
run_action 'Creating parent directory' do
|