sfn 0.5.0 → 1.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 +19 -8
- data/README.md +85 -53
- data/bin/generate_sfn_docs +37 -0
- data/lib/sfn/callback/stack_policy.rb +94 -0
- data/lib/sfn/callback.rb +48 -0
- data/lib/sfn/command/create.rb +19 -20
- data/lib/sfn/command/describe.rb +16 -10
- data/lib/sfn/command/destroy.rb +8 -3
- data/lib/sfn/command/events.rb +24 -22
- data/lib/sfn/command/inspect.rb +8 -6
- data/lib/sfn/command/update.rb +49 -72
- data/lib/sfn/command/validate.rb +30 -4
- data/lib/sfn/command.rb +8 -5
- data/lib/sfn/command_module/base.rb +17 -2
- data/lib/sfn/command_module/callbacks.rb +69 -0
- data/lib/sfn/command_module/stack.rb +107 -9
- data/lib/sfn/command_module/template.rb +201 -129
- data/lib/sfn/command_module.rb +1 -0
- data/lib/sfn/config/update.rb +0 -4
- data/lib/sfn/config/validate.rb +12 -2
- data/lib/sfn/monkey_patch/stack.rb +72 -0
- data/lib/sfn/utils/path_selector.rb +3 -0
- data/lib/sfn/version.rb +1 -1
- data/lib/sfn.rb +1 -0
- data/sfn.gemspec +8 -10
- metadata +19 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e25f48c5fa80038624e08c5e224e62c740be5a8
|
4
|
+
data.tar.gz: 2a983906bcdb4b5e02d81c9762b1a033c3b4410e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b41dd94c68cff3b29a487c4d03e86c36d352b4a3403d99787db582d3eaf54e7b2f93418e54398c4dcf8e3083813830cbc24a1a897c70765cce0869c236a5f76
|
7
|
+
data.tar.gz: 230a3ef0bcf85adc1c6fd4bb80617dd2b20ab19de4c6b91b43a319fb2265a3cf9d50b7cee4195b119c787ea68528bd47817c75ccddbfb147670c6dd727974103
|
data/CHANGELOG.md
CHANGED
@@ -1,11 +1,22 @@
|
|
1
|
-
##
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
*
|
1
|
+
## v1.0.0
|
2
|
+
|
3
|
+
_NOTE: This release contains breaking changes! Please review the
|
4
|
+
changes in this release and test your configuration and
|
5
|
+
templates. Changes that may introduce breakage have been
|
6
|
+
labeled below._
|
7
|
+
|
8
|
+
* [BREAKING] Update sparkle_formation constraint to 1.0 versions
|
9
|
+
* [BREAKING] Default to "deep" style nesting (previous default: "shallow")
|
10
|
+
* [BREAKING] Template loading via SparklePacks in place of direct file loading
|
11
|
+
* Provide support for shallow and deep stack nesting styles
|
12
|
+
* Add support for customized callbacks
|
13
|
+
* Fix `--print-only` behavior on `update` command, add to `validate` command
|
14
|
+
* On validation of template with nesting, validate all nested templates _and_ root template
|
15
|
+
* Display details of all nested stacks on `describe` command
|
16
|
+
* Disable automatic stack inspection on failed `create` / `update` command
|
17
|
+
* Add support for SparklePacks
|
18
|
+
* Add support for AWS stack policies via optional callback
|
19
|
+
* And lots of internal refactors!
|
9
20
|
|
10
21
|
## v0.4.12
|
11
22
|
* Fix transient uninitialized constant error for update command
|
data/README.md
CHANGED
@@ -1,8 +1,14 @@
|
|
1
|
+

|
2
|
+
|
1
3
|
# SparkleFormation CLI
|
2
4
|
|
3
5
|
SparkleFormation command line interface for interacting
|
4
6
|
with orchestration APIs.
|
5
7
|
|
8
|
+
## Extra Documentation
|
9
|
+
|
10
|
+
* [User Documentation](https://sparkleformation.github.io/sfn/UserDocs)
|
11
|
+
|
6
12
|
## API Compatibility
|
7
13
|
|
8
14
|
* AWS
|
@@ -26,7 +32,7 @@ formats:
|
|
26
32
|
```json
|
27
33
|
{
|
28
34
|
"credentials": {
|
29
|
-
|
35
|
+
MIASMA_CREDENTIALS
|
30
36
|
},
|
31
37
|
"options": {
|
32
38
|
"disable_rollback": true
|
@@ -34,7 +40,7 @@ formats:
|
|
34
40
|
}
|
35
41
|
```
|
36
42
|
|
37
|
-
|
43
|
+
#### YAML
|
38
44
|
|
39
45
|
```yaml
|
40
46
|
---
|
@@ -44,12 +50,12 @@ formats:
|
|
44
50
|
:disable_rollback: true
|
45
51
|
```
|
46
52
|
|
47
|
-
|
53
|
+
#### XML
|
48
54
|
|
49
55
|
```xml
|
50
56
|
<configuration>
|
51
57
|
<credentials>
|
52
|
-
|
58
|
+
MIASMA_CREDENTIALS
|
53
59
|
</credentials>
|
54
60
|
<options>
|
55
61
|
<disable_rollback>
|
@@ -59,17 +65,86 @@ formats:
|
|
59
65
|
</configuration>
|
60
66
|
```
|
61
67
|
|
62
|
-
|
68
|
+
#### Ruby
|
63
69
|
|
64
70
|
```ruby
|
65
71
|
Configuration.new do
|
66
72
|
credentials do
|
67
|
-
|
73
|
+
MIASMA_CREDENTIALS
|
68
74
|
end
|
69
|
-
options.
|
75
|
+
options.on_failure 'nothing'
|
70
76
|
end
|
71
77
|
```
|
72
78
|
|
79
|
+
### Configuration Options
|
80
|
+
|
81
|
+
* `processing` - Enable SparkleFormation processing
|
82
|
+
* Valid: Boolean
|
83
|
+
* Default: `true`
|
84
|
+
|
85
|
+
* `apply_nesting` - Style of nested stack processing
|
86
|
+
* Valid: `"shallow"`, `"deep"`
|
87
|
+
* Default: `"deep"`
|
88
|
+
|
89
|
+
* `options` - API options for target orchestration API (see miasma)
|
90
|
+
* Valid: `Hash`
|
91
|
+
* Default: none
|
92
|
+
|
93
|
+
* `ssh_attempt_users` - List of users to attempt SSH connection on node failure
|
94
|
+
* Valid: `Array<String>`
|
95
|
+
* Default: none
|
96
|
+
|
97
|
+
* `identity_file` - Custom SSH identity file to use for connection on node failure
|
98
|
+
* Valid: `String`
|
99
|
+
* Default: none
|
100
|
+
|
101
|
+
* `nesting_bucket` - Name of bucket to store nested stack templates
|
102
|
+
* Valid: `String`
|
103
|
+
* Default: none
|
104
|
+
|
105
|
+
* `credentials` - API credentials for target orchestration API (see [miasma](https://github.com/miasma-rb/miasma))
|
106
|
+
* Valid: `Hash`
|
107
|
+
* Default: none
|
108
|
+
|
109
|
+
* `callbacks` - Callbacks to execute around API calls
|
110
|
+
* Valid: `Hash`
|
111
|
+
* Default: none
|
112
|
+
* `before` - Callbacks to execute before _any_ API call
|
113
|
+
* Valid: `Array<String>`
|
114
|
+
* Default: none
|
115
|
+
* `after` - Callbacks to execute after _any_ API call
|
116
|
+
* Valid: `Array<String>`
|
117
|
+
* Default: none
|
118
|
+
* `before_COMMAND` - Callbacks to execute before specific `COMMAND` API call
|
119
|
+
* Valid: `Array<String>`
|
120
|
+
* Default: none
|
121
|
+
* `after_COMMAND` - Callbacks to execute after specific `COMMAND` API call
|
122
|
+
* Valid: `Array<String>`
|
123
|
+
* Default: none
|
124
|
+
* `template` - Callbacks to execute on template
|
125
|
+
* Valid: `Array<String>`
|
126
|
+
* Default: none
|
127
|
+
* `default` - Callbacks to always execute
|
128
|
+
* Valid: `Array<String>`
|
129
|
+
* Default: none
|
130
|
+
* `require` - List of custom libraries to load
|
131
|
+
* Valid: `Array<String>`
|
132
|
+
* Default: none
|
133
|
+
|
134
|
+
* `retry` - Configuration of API request retries
|
135
|
+
* Valid: `Hash`
|
136
|
+
* Default: none
|
137
|
+
* `type` - Type of retry
|
138
|
+
* Valid: `"flat"`, `"linear"`, `"exponential"`
|
139
|
+
* Default: `"exponential"`
|
140
|
+
* `interval` - Base wait interval for retry
|
141
|
+
* Valid: `Numeric`
|
142
|
+
* Default: 5
|
143
|
+
* `max_attempts` - Maximum number of attempts allowed
|
144
|
+
* Valid: `Numeric`
|
145
|
+
* Default: 20
|
146
|
+
* _NOTE_: Set to `nil` for infinite retry
|
147
|
+
|
73
148
|
## Commands
|
74
149
|
|
75
150
|
* `sfn list`
|
@@ -81,45 +156,20 @@ end
|
|
81
156
|
* `sfn inspect`
|
82
157
|
* `sfn validate`
|
83
158
|
|
159
|
+
_NOTE: All commands respond to `--help` and will provide a full list of valid options._
|
160
|
+
|
84
161
|
### `sfn list`
|
85
162
|
|
86
163
|
Provides listing of current stacks and state of each stack.
|
87
164
|
|
88
|
-
#### Supported options
|
89
|
-
|
90
|
-
* `--attribute ATTR` stack attribute to display
|
91
|
-
* `--status STATUS` match stacks with given status
|
92
|
-
|
93
165
|
### `sfn validate`
|
94
166
|
|
95
167
|
Validates template with API
|
96
168
|
|
97
|
-
#### Supported options
|
98
|
-
|
99
|
-
* `--[no-]processing` enable template processing
|
100
|
-
* `--file PATH` path to stack template file
|
101
|
-
* `--translate PROVIDER` translate template to provider
|
102
|
-
* `--[no-]apply-nesting` apply template nesting logic
|
103
|
-
* `--nesting-bucket BUCKET` asset store bucket to place nested stack templates
|
104
|
-
|
105
169
|
### `sfn create NAME`
|
106
170
|
|
107
171
|
Creates a new stack with the provided name (`NAME`).
|
108
172
|
|
109
|
-
#### Supported options
|
110
|
-
|
111
|
-
* `--timeout MINUTES` stack creation timeout limit
|
112
|
-
* `--[no-]rollback` disable rollback on failure
|
113
|
-
* `--capability CAPABILITY` enable capability within API
|
114
|
-
* `--notifications ARN` add notification ARN
|
115
|
-
* `--print-only` print stack template JSON and exit
|
116
|
-
* `--apply-stack NAME` apply existing stack outputs
|
117
|
-
* `--[no-]processing` enable template processing
|
118
|
-
* `--file PATH` path to stack template file
|
119
|
-
* `--translate PROVIDER` translate template to provider
|
120
|
-
* `--[no-]apply-nesting` apply template nesting logic
|
121
|
-
* `--nesting-bucket BUCKET` asset store bucket to place nested stack templates
|
122
|
-
|
123
173
|
#### Apply Stacks
|
124
174
|
|
125
175
|
The `--apply-stack` option allows providing the name of an existing
|
@@ -193,16 +243,6 @@ resources are supported.
|
|
193
243
|
|
194
244
|
Update an existing stack.
|
195
245
|
|
196
|
-
#### Supported options
|
197
|
-
|
198
|
-
* `--print-only` print stack template JSON and exit
|
199
|
-
* `--apply-stack NAME` apply existing stack outputs
|
200
|
-
* `--[no-]processing` enable template processing
|
201
|
-
* `--file PATH` path to stack template file
|
202
|
-
* `--translate PROVIDER` translate template to provider
|
203
|
-
* `--[no-]apply-nesting` apply template nesting logic
|
204
|
-
* `--nesting-bucket BUCKET` asset store bucket to place nested stack templates
|
205
|
-
|
206
246
|
### `sfn destroy STACK`
|
207
247
|
|
208
248
|
Destroy an existing stack.
|
@@ -232,18 +272,10 @@ stack is "in progress", the polling option will result in
|
|
232
272
|
polling and displaying new events until the stack reaches a
|
233
273
|
completed state.
|
234
274
|
|
235
|
-
#### Supported options
|
236
|
-
|
237
|
-
* `--[no-]poll` poll for new events until completed state reached
|
238
|
-
|
239
275
|
### `sfn describe STACK`
|
240
276
|
|
241
277
|
Display resources and outputs of give stack.
|
242
278
|
|
243
|
-
#### Supported options
|
244
|
-
|
245
|
-
* `--resources` display resources
|
246
|
-
* `--outputs` display outputs
|
247
279
|
|
248
280
|
### `sfn inspect STACK`
|
249
281
|
|
@@ -252,7 +284,7 @@ underlying resource modeling objects provided via the
|
|
252
284
|
[miasma][miasma] library. It also provides extra helpers for
|
253
285
|
running common inspection commands.
|
254
286
|
|
255
|
-
###
|
287
|
+
### Interesting `inspect` options
|
256
288
|
|
257
289
|
* `--nodes` list node addresses within stack
|
258
290
|
* `--instance-failure [LOG_FILE]` print log file from failed instance
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
unless(system("yardoc"))
|
5
|
+
$stderr.puts 'ACK: Failed to create docs!'
|
6
|
+
exit -1
|
7
|
+
end
|
8
|
+
|
9
|
+
FileUtils.mkdir_p('doc/UserDocs')
|
10
|
+
|
11
|
+
Dir.glob('docs/**/*').each do |path|
|
12
|
+
next unless File.file?(path)
|
13
|
+
content = File.read(path)
|
14
|
+
rel_path = path.sub(/.*?docs\//, '')
|
15
|
+
new_path = File.join('doc/UserDocs', rel_path)
|
16
|
+
user_doc_root = (['..'] * rel_path.scan('/').size).join('/')
|
17
|
+
unless(user_doc_root.to_s.empty?)
|
18
|
+
user_doc_root << '/'
|
19
|
+
end
|
20
|
+
FileUtils.mkdir_p(File.dirname(new_path))
|
21
|
+
File.open(new_path, 'w') do |file|
|
22
|
+
file.puts content
|
23
|
+
end
|
24
|
+
if(new_path.end_with?('.md'))
|
25
|
+
File.open(new_path.sub('.md', '.html'), 'w') do |file|
|
26
|
+
file.print "<!DOCTYPE html><html><head><title>SparkleFormation CLI User Documentation</title><script src=\"#{user_doc_root}v/0.3.2/marked.js\"></script><script src=\"#{user_doc_root}v/jquery-2.1.3.min.js\"></script><script src=\"#{user_doc_root}v/loader.js\"></script><script src=\"#{user_doc_root}v/highlight.min.js\"></script><link rel=\"stylesheet\" href=\"#{user_doc_root}v/bootstrap.min.css\"></link><link rel=\"stylesheet\" href=\"#{user_doc_root}v/highlight.min.css\"></link><link rel=\"stylesheet\" href=\"#{user_doc_root}v/finalizer.css\"></link>"
|
27
|
+
file.print "</head><body><div class=\"markdown-body\"><div class=\"navbar navbar-top\"><div class=\"navbar-inner\"><div class=\"container\"><div class=\"navbar-brand\"><a href=\"#{user_doc_root}README.html\">SparkleFormation - User documentation</a></div></div></div></div><div class=\"panel panel-default\"><div class=\"panel-body\" id=\"content\"></div></div></div>"
|
28
|
+
file.print "</body></html>"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
File.open('doc/UserDocs/index.html', 'w') do |file|
|
34
|
+
file.puts '<html><head><meta http-equiv="refresh" content="0; url=README.html" /></head></html>'
|
35
|
+
end
|
36
|
+
|
37
|
+
puts 'done.'
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'sfn'
|
2
|
+
|
3
|
+
module Sfn
|
4
|
+
class Callback
|
5
|
+
class StackPolicy < Callback
|
6
|
+
|
7
|
+
# Policy to apply prior to stack deletion
|
8
|
+
DEFENSELESS_POLICY = {
|
9
|
+
'Statement' => [{
|
10
|
+
'Effect' => 'Allow',
|
11
|
+
'Action' => 'Update:*',
|
12
|
+
'Resource' => '*',
|
13
|
+
'Principal' => '*'
|
14
|
+
}]
|
15
|
+
}
|
16
|
+
|
17
|
+
# @return [Smash] cached policies
|
18
|
+
attr_reader :policies
|
19
|
+
|
20
|
+
# Overload to init policy cache
|
21
|
+
#
|
22
|
+
# @return [self]
|
23
|
+
def initialize(*args)
|
24
|
+
super
|
25
|
+
@policies = Smash.new
|
26
|
+
end
|
27
|
+
|
28
|
+
# Submit all cached policies
|
29
|
+
#
|
30
|
+
# @param args [Hash]
|
31
|
+
def submit_policy(args)
|
32
|
+
ui.info 'Submitting stack policy documents'
|
33
|
+
stack = args[:api_stack]
|
34
|
+
([stack] + stack.nested_stacks).compact.each do |p_stack|
|
35
|
+
run_action "Applying stack policy to #{ui.color(p_stack.name, :yellow)}" do
|
36
|
+
save_stack_policy(p_stack)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
ui.info 'Stack policy documents successfully submitted!'
|
40
|
+
end
|
41
|
+
alias_method :after_create, :submit_policy
|
42
|
+
alias_method :after_update, :submit_policy
|
43
|
+
|
44
|
+
# Update all policies to allow resource destruction
|
45
|
+
def before_destroy(args)
|
46
|
+
ui.warn 'All policies will be disabled for stack destruction!'
|
47
|
+
ui.confirm 'Continue with stack destruction'
|
48
|
+
stack = args[:api_stack]
|
49
|
+
([stack] + stack.nested_stacks).compact.each do |p_stack|
|
50
|
+
@policies[p_stack.name] = DEFENSELESS_POLICY
|
51
|
+
run_action "Disabling stack policy for #{ui.color(p_stack.name, :yellow)}" do
|
52
|
+
save_stack_policy(p_stack)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
ui.warn "Policy modification for deletion not currently enabled!"
|
56
|
+
end
|
57
|
+
|
58
|
+
# Generate stack policy for stack and cache for the after hook
|
59
|
+
# to handle
|
60
|
+
#
|
61
|
+
# @param info [Hash]
|
62
|
+
def template(info)
|
63
|
+
if(info[:sparkle_stack])
|
64
|
+
@policies.set(info[:stack_name],
|
65
|
+
info[:sparkle_stack].generate_policy
|
66
|
+
)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Save the cached policy for the given stack
|
71
|
+
#
|
72
|
+
# @param p_stack [Miasma::Models::Orchestration::Stack]
|
73
|
+
# @return [NilClass]
|
74
|
+
def save_stack_policy(p_stack)
|
75
|
+
result = p_stack.api.request(
|
76
|
+
:path => '/',
|
77
|
+
:method => :post,
|
78
|
+
:form => Smash.new(
|
79
|
+
'Action' => 'SetStackPolicy',
|
80
|
+
'StackName' => p_stack.id,
|
81
|
+
'StackPolicyBody' => MultiJson.dump(
|
82
|
+
@policies.fetch(p_stack.id,
|
83
|
+
@policies.fetch(p_stack.data[:logical_id],
|
84
|
+
@policies[p_stack.name]
|
85
|
+
)
|
86
|
+
)
|
87
|
+
)
|
88
|
+
)
|
89
|
+
)
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
data/lib/sfn/callback.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'sfn'
|
2
|
+
|
3
|
+
module Sfn
|
4
|
+
# Interface for injecting custom functionality
|
5
|
+
class Callback
|
6
|
+
|
7
|
+
autoload :StackPolicy, 'sfn/callback/stack_policy'
|
8
|
+
|
9
|
+
# @return [Bogo::Ui]
|
10
|
+
attr_reader :ui
|
11
|
+
# @return [Smash]
|
12
|
+
attr_reader :config
|
13
|
+
|
14
|
+
# Create a new callback instance
|
15
|
+
#
|
16
|
+
# @param [Bogo::Ui]
|
17
|
+
# @param [Smash] configuration hash
|
18
|
+
# @param [Array<String>] arguments from the CLI
|
19
|
+
# @param [Provider] API connection
|
20
|
+
#
|
21
|
+
# @return [self]
|
22
|
+
def initialize(ui, config, arguments, api)
|
23
|
+
@ui = ui
|
24
|
+
@config = config
|
25
|
+
@arguments = arguments
|
26
|
+
@api = api
|
27
|
+
end
|
28
|
+
|
29
|
+
# Wrap action within status text
|
30
|
+
#
|
31
|
+
# @param msg [String] action text
|
32
|
+
# @yieldblock action to perform
|
33
|
+
# @return [Object] result of yield
|
34
|
+
def run_action(msg)
|
35
|
+
ui.info("#{msg}... ", :nonewline)
|
36
|
+
begin
|
37
|
+
result = yield
|
38
|
+
ui.puts ui.color('complete!', :green, :bold)
|
39
|
+
result
|
40
|
+
rescue => e
|
41
|
+
ui.puts ui.color('error!', :red, :bold)
|
42
|
+
ui.error "Reason - #{e}"
|
43
|
+
raise
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
data/lib/sfn/command/create.rb
CHANGED
@@ -25,7 +25,7 @@ module Sfn
|
|
25
25
|
end
|
26
26
|
|
27
27
|
unless(config[:print_only])
|
28
|
-
ui.info "#{ui.color('
|
28
|
+
ui.info "#{ui.color('Cloud Formation:', :bold)} #{ui.color('create', :green)}"
|
29
29
|
end
|
30
30
|
|
31
31
|
stack_info = "#{ui.color('Name:', :bold)} #{name}"
|
@@ -66,32 +66,31 @@ module Sfn
|
|
66
66
|
end
|
67
67
|
|
68
68
|
populate_parameters!(stack.template)
|
69
|
-
stack.parameters =
|
69
|
+
stack.parameters = config_root_parameters
|
70
70
|
|
71
71
|
stack.template = translate_template(stack.template)
|
72
|
-
stack.save
|
73
72
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
73
|
+
api_action!(:api_stack => stack) do
|
74
|
+
stack.save
|
75
|
+
if(config[:poll])
|
76
|
+
poll_stack(stack.name)
|
77
|
+
stack = provider.connection.stacks.get(name)
|
78
|
+
|
79
|
+
if(stack.reload.state == :create_complete)
|
80
|
+
ui.info "Stack create complete: #{ui.color('SUCCESS', :green)}"
|
81
|
+
namespace.const_get(:Describe).new({:outputs => true}, [name]).execute!
|
82
|
+
else
|
83
|
+
ui.fatal "Create of new stack #{ui.color(name, :bold)}: #{ui.color('FAILED', :red, :bold)}"
|
84
|
+
raise
|
85
|
+
end
|
84
86
|
else
|
85
|
-
ui.
|
86
|
-
ui.info ""
|
87
|
-
namespace.const_get(:Inspect).new({:instance_failure => true}, [name]).execute!
|
88
|
-
raise
|
87
|
+
ui.warn 'Stack state polling has been disabled.'
|
88
|
+
ui.info "Stack creation initialized for #{ui.color(name, :green)}"
|
89
89
|
end
|
90
|
-
else
|
91
|
-
ui.warn 'Stack state polling has been disabled.'
|
92
|
-
ui.info "Stack creation initialized for #{ui.color(name, :green)}"
|
93
90
|
end
|
91
|
+
|
94
92
|
end
|
93
|
+
|
95
94
|
end
|
96
95
|
|
97
96
|
end
|
data/lib/sfn/command/describe.rb
CHANGED
@@ -15,18 +15,24 @@ module Sfn
|
|
15
15
|
# Run the stack describe action
|
16
16
|
def execute!
|
17
17
|
stack_name = name_args.last
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
root_stack = api_action! do
|
19
|
+
provider.connection.stacks.get(stack_name)
|
20
|
+
end
|
21
|
+
if(root_stack)
|
22
|
+
([root_stack] + root_stack.nested_stacks).compact.each do |stack|
|
23
|
+
ui.info "Stack description of #{ui.color(stack.name, :bold)}:"
|
24
|
+
display = [].tap do |to_display|
|
25
|
+
AVAILABLE_DISPLAYS.each do |display_option|
|
26
|
+
if(config[display_option])
|
27
|
+
to_display << display_option
|
28
|
+
end
|
24
29
|
end
|
25
30
|
end
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
31
|
+
display = AVAILABLE_DISPLAYS.dup if display.empty?
|
32
|
+
display.each do |display_method|
|
33
|
+
self.send(display_method, stack)
|
34
|
+
end
|
35
|
+
ui.puts
|
30
36
|
end
|
31
37
|
else
|
32
38
|
ui.fatal "Failed to find requested stack: #{ui.color(stack_name, :bold, :red)}"
|
data/lib/sfn/command/destroy.rb
CHANGED
@@ -29,7 +29,9 @@ module Sfn
|
|
29
29
|
stack = provider.connection.stacks.get(stack_name)
|
30
30
|
if(stack)
|
31
31
|
nested_stack_cleanup!(stack)
|
32
|
-
stack
|
32
|
+
api_action!(:api_stack => stack) do
|
33
|
+
stack.destroy
|
34
|
+
end
|
33
35
|
ui.info "Destroy request complete for stack: #{ui.color(stack_name, :red)}"
|
34
36
|
else
|
35
37
|
ui.warn "Failed to locate requested stack: #{ui.color(stack_name, :bold)}"
|
@@ -42,13 +44,16 @@ module Sfn
|
|
42
44
|
ui.error "Stack polling is not available when multiple stack deletion is requested!"
|
43
45
|
end
|
44
46
|
end
|
45
|
-
ui.info " -> Destroyed
|
47
|
+
ui.info " -> Destroyed Cloud Formation#{plural}: #{ui.color(stacks.join(', '), :bold, :red)}"
|
46
48
|
end
|
47
49
|
|
48
50
|
# Cleanup persisted templates if nested stack resources are included
|
49
51
|
def nested_stack_cleanup!(stack)
|
52
|
+
stack.nested_stacks.each do |n_stack|
|
53
|
+
nested_stack_cleanup!(n_stack)
|
54
|
+
end
|
50
55
|
nest_stacks = stack.template.fetch('Resources', {}).values.find_all do |resource|
|
51
|
-
resource['Type'] ==
|
56
|
+
resource['Type'] == stack.api.class.const_get(:RESOURCE_MAPPING).key(stack.class).to_s
|
52
57
|
end.each do |resource|
|
53
58
|
url = resource['Properties']['TemplateURL']
|
54
59
|
if(url)
|
data/lib/sfn/command/events.rb
CHANGED
@@ -19,32 +19,34 @@ module Sfn
|
|
19
19
|
@stacks << stack
|
20
20
|
discover_stacks(stack)
|
21
21
|
if(stack)
|
22
|
-
|
23
|
-
table
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
column attr.split('_').map(&:capitalize).join(' '), :width => ((val = events.map{|e| e[attr].to_s.length}.push(attr.length).max + 2) > 70 ? 70 : val)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
events.each do |event|
|
31
|
-
row do
|
22
|
+
api_action!(:api_stack => stack) do
|
23
|
+
table = ui.table(self) do
|
24
|
+
table(:border => false) do
|
25
|
+
events = get_events
|
26
|
+
row(:header => true) do
|
32
27
|
allowed_attributes.each do |attr|
|
33
|
-
column
|
28
|
+
column attr.split('_').map(&:capitalize).join(' '), :width => ((val = events.map{|e| e[attr].to_s.length}.push(attr.length).max + 2) > 70 ? 70 : val)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
events.each do |event|
|
32
|
+
row do
|
33
|
+
allowed_attributes.each do |attr|
|
34
|
+
column event[attr]
|
35
|
+
end
|
34
36
|
end
|
35
37
|
end
|
36
38
|
end
|
37
|
-
end
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
39
|
+
end.display
|
40
|
+
if(config[:poll])
|
41
|
+
while(stack.in_progress?)
|
42
|
+
to_wait = config.fetch(:poll_wait_time, 10).to_f
|
43
|
+
while(to_wait > 0)
|
44
|
+
sleep(0.1)
|
45
|
+
to_wait -= 0.1
|
46
|
+
end
|
47
|
+
stack.reload
|
48
|
+
table.display
|
45
49
|
end
|
46
|
-
stack.reload
|
47
|
-
table.display
|
48
50
|
end
|
49
51
|
end
|
50
52
|
else
|
@@ -64,7 +66,7 @@ module Sfn
|
|
64
66
|
stack.events.all.map do |e|
|
65
67
|
e.attributes.merge(:stack_name => stack.name).to_smash
|
66
68
|
end
|
67
|
-
end.flatten.compact
|
69
|
+
end.flatten.compact.find_all{|e| e[:time] }
|
68
70
|
stack_events.sort do |x,y|
|
69
71
|
Time.parse(x[:time].to_s) <=> Time.parse(y[:time].to_s)
|
70
72
|
end
|
data/lib/sfn/command/inspect.rb
CHANGED
@@ -13,12 +13,14 @@ module Sfn
|
|
13
13
|
stack_name = name_args.last
|
14
14
|
stack = provider.connection.stacks.get(stack_name)
|
15
15
|
ui.info "Stack inspection #{ui.color(stack_name, :bold)}:"
|
16
|
-
outputs =
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
16
|
+
outputs = api_action!(:api_stack => stack) do
|
17
|
+
[:attribute, :nodes, :instance_failure].map do |key|
|
18
|
+
if(config.has_key?(key))
|
19
|
+
send("display_#{key}", stack)
|
20
|
+
key
|
21
|
+
end
|
22
|
+
end.compact
|
23
|
+
end
|
22
24
|
if(outputs.empty?)
|
23
25
|
ui.info ' Stack dump:'
|
24
26
|
ui.puts MultiJson.dump(
|