sfn 0.5.0 → 1.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 +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
|
+
![SparkleFormation CLI](img/sfn.jpg)
|
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(
|