sfn 2.2.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|