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.
@@ -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
@@ -22,6 +22,7 @@ Notable features available via the SparkleFormation CLI:
22
22
  - Eucalyptus
23
23
  - Rackspace Orchestration
24
24
  - OpenStack Heat
25
+ - Google Cloud Deployment Manager
25
26
  - Chef `knife` plugin support
26
27
  - Deep resource inspection
27
28
 
data/lib/sfn.rb CHANGED
@@ -5,6 +5,7 @@ require 'sparkle_formation'
5
5
 
6
6
  module Sfn
7
7
 
8
+ autoload :ApiProvider, 'sfn/api_provider'
8
9
  autoload :Callback, 'sfn/callback'
9
10
  autoload :Provider, 'sfn/provider'
10
11
  autoload :Cache, 'sfn/cache'
@@ -0,0 +1,9 @@
1
+ require 'sfn'
2
+
3
+ module Sfn
4
+ module ApiProvider
5
+
6
+ autoload :Google, 'sfn/api_provider/google'
7
+
8
+ end
9
+ end
@@ -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
@@ -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
  #
@@ -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
- unless(config[:print_only])
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
- if(nested_stacks_unpack)
42
- unpack_nesting(name, file, :create)
43
- else
44
-
45
- if(config[:print_only] && !config[:apply_stacks])
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
- apply_stacks!(stack)
62
- stack.template = Sfn::Utils::StackParameterScrubber.scrub!(scrub_template(stack.template))
51
+ apply_stacks!(stack)
52
+ populate_parameters!(file, :current_parameters => stack.parameters)
63
53
 
64
- if(config[:print_only])
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
- stack.template = translate_template(stack.template)
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
- api_action!(:api_stack => stack) do
75
- stack.save
76
- if(config[:poll])
77
- poll_stack(stack.name)
78
- stack = provider.connection.stacks.get(name)
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
- if(stack.reload.state == :create_complete)
81
- ui.info "Stack create complete: #{ui.color('SUCCESS', :green)}"
82
- namespace.const_get(:Describe).new({:outputs => true}, [name]).execute!
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.warn 'Stack state polling has been disabled.'
89
- ui.info "Stack creation initialized for #{ui.color(name, :green)}"
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
@@ -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(' ')
@@ -40,7 +40,13 @@ module Sfn
40
40
  end
41
41
  if(config[:poll])
42
42
  if(stacks.size == 1)
43
- poll_stack(stacks.first)
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
@@ -17,7 +17,7 @@ module Sfn
17
17
  name = name_args.first
18
18
 
19
19
  begin
20
- stack = provider.connection.stacks.get(name)
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.delete('sfn_nested_stack')
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['Resources'].find_all do |name, value|
44
+ file.fetch('Resources', file.fetch('resources', {})).find_all do |name, value|
46
45
  value.fetch('Properties', {})['Stack']
47
46
  end
48
47
  ]
@@ -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.delete('sfn_nested_stack')
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)}"
@@ -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 = _format_json(file)
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