stackup 0.8.4 → 0.9.2
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/CHANGES.md +7 -0
- data/bin/stackup +7 -1
- data/lib/stackup/stack.rb +43 -15
- data/lib/stackup/stack_watcher.rb +10 -8
- data/lib/stackup/version.rb +1 -1
- data/spec/stackup/stack_spec.rb +44 -4
- data/spec/stackup/stack_watcher_spec.rb +5 -3
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a8edc4a00c69a1f93ac2549985d3268aecc40c0c
|
4
|
+
data.tar.gz: 8d5c670e3c2b3fba4718df0368b363dd129ddf40
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dbf64ed470760758b6c6976724502d877f40f37a60537d80a82e708c480ffc9768b958c0532997d4f97b5893c7a3a4d3698276106c85d6e5bdecf8210fb1e21a
|
7
|
+
data.tar.gz: 120becc33de075bfadc14a5062375d83bdd2138b026eb4926e37256a6a5812b9ee04016069771f96ad785e0963d5052c732922510feb4b4c279a7067910985f6
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
## 0.9.2 (2016-08-04)
|
2
|
+
|
3
|
+
* Make poll_interval (during deployment) configurable.
|
4
|
+
* Add `--wait-poll-interval` option.
|
5
|
+
* Minimise calls to "DescribeStackEvents" (esp. for older stacks).
|
6
|
+
* Add `--no-wait` option.
|
7
|
+
|
1
8
|
## 0.8.4 (2016-07-08)
|
2
9
|
|
3
10
|
* Ensure stack tag values are strings.
|
data/bin/stackup
CHANGED
@@ -37,6 +37,12 @@ Clamp do
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
+
option ["--[no-]wait"], :flag, "wait for stack updates to complete",
|
41
|
+
:default => true
|
42
|
+
|
43
|
+
option ["--wait-poll-interval"], "N", "polling interval while waiting for updates",
|
44
|
+
:default => 5, &method(:Integer)
|
45
|
+
|
40
46
|
option "--debug", :flag, "enable debugging"
|
41
47
|
|
42
48
|
option ["--version"], :flag, "display version" do
|
@@ -79,7 +85,7 @@ Clamp do
|
|
79
85
|
end
|
80
86
|
|
81
87
|
def stack
|
82
|
-
stackup.stack(stack_name)
|
88
|
+
stackup.stack(stack_name, :wait => wait?, :wait_poll_interval => wait_poll_interval)
|
83
89
|
end
|
84
90
|
|
85
91
|
def list_stacks
|
data/lib/stackup/stack.rb
CHANGED
@@ -11,16 +11,27 @@ module Stackup
|
|
11
11
|
#
|
12
12
|
class Stack
|
13
13
|
|
14
|
+
DEFAULT_WAIT_POLL_INTERVAL = 5 # seconds
|
15
|
+
|
14
16
|
def initialize(name, client = {}, options = {})
|
15
17
|
client = Aws::CloudFormation::Client.new(client) if client.is_a?(Hash)
|
16
18
|
@name = name
|
17
19
|
@cf_client = client
|
20
|
+
@wait = true
|
18
21
|
options.each do |key, value|
|
19
22
|
public_send("#{key}=", value)
|
20
23
|
end
|
24
|
+
@wait_poll_interval ||= DEFAULT_WAIT_POLL_INTERVAL
|
21
25
|
end
|
22
26
|
|
23
27
|
attr_reader :name
|
28
|
+
attr_accessor :wait_poll_interval
|
29
|
+
|
30
|
+
attr_writer :wait
|
31
|
+
|
32
|
+
def wait?
|
33
|
+
@wait
|
34
|
+
end
|
24
35
|
|
25
36
|
# Register a handler for reporting of stack events.
|
26
37
|
# @param [Proc] event_handler
|
@@ -141,11 +152,9 @@ module Stackup
|
|
141
152
|
rescue NoSuchStack
|
142
153
|
return nil
|
143
154
|
end
|
144
|
-
|
155
|
+
modify_stack("DELETE_COMPLETE", "stack delete failed") do
|
145
156
|
cf_stack.delete
|
146
157
|
end
|
147
|
-
fail StackUpdateError, "stack delete failed" unless status == "DELETE_COMPLETE"
|
148
|
-
status
|
149
158
|
ensure
|
150
159
|
@stack_id = nil
|
151
160
|
end
|
@@ -158,11 +167,9 @@ module Stackup
|
|
158
167
|
# @raise [Stackup::StackUpdateError] if operation fails
|
159
168
|
#
|
160
169
|
def cancel_update
|
161
|
-
|
170
|
+
modify_stack(/_COMPLETE$/, "update cancel failed") do
|
162
171
|
cf_stack.cancel_update
|
163
172
|
end
|
164
|
-
fail StackUpdateError, "update cancel failed" unless status =~ /_COMPLETE$/
|
165
|
-
status
|
166
173
|
rescue InvalidStateError
|
167
174
|
nil
|
168
175
|
end
|
@@ -172,7 +179,7 @@ module Stackup
|
|
172
179
|
# @return [String] status, once stable
|
173
180
|
#
|
174
181
|
def wait
|
175
|
-
modify_stack do
|
182
|
+
modify_stack(/./, "failed to stabilize") do
|
176
183
|
# nothing
|
177
184
|
end
|
178
185
|
end
|
@@ -249,22 +256,18 @@ module Stackup
|
|
249
256
|
options[:stack_name] = name
|
250
257
|
options.delete(:stack_policy_during_update_body)
|
251
258
|
options.delete(:stack_policy_during_update_url)
|
252
|
-
|
259
|
+
modify_stack("CREATE_COMPLETE", "stack creation failed") do
|
253
260
|
cf.create_stack(options)
|
254
261
|
end
|
255
|
-
fail StackUpdateError, "stack creation failed" unless status == "CREATE_COMPLETE"
|
256
|
-
status
|
257
262
|
end
|
258
263
|
|
259
264
|
def update(options)
|
260
265
|
options.delete(:disable_rollback)
|
261
266
|
options.delete(:on_failure)
|
262
267
|
options.delete(:timeout_in_minutes)
|
263
|
-
|
268
|
+
modify_stack("UPDATE_COMPLETE", "stack update failed") do
|
264
269
|
cf_stack.update(options)
|
265
270
|
end
|
266
|
-
fail StackUpdateError, "stack update failed" unless status == "UPDATE_COMPLETE"
|
267
|
-
status
|
268
271
|
rescue NoUpdateRequired
|
269
272
|
logger.info "No update required"
|
270
273
|
nil
|
@@ -283,11 +286,25 @@ module Stackup
|
|
283
286
|
end
|
284
287
|
end
|
285
288
|
|
289
|
+
# Execute a block, to modify the stack.
|
290
|
+
#
|
291
|
+
# @return the stack status
|
292
|
+
#
|
293
|
+
def modify_stack(target_status, failure_message, &block)
|
294
|
+
if wait?
|
295
|
+
status = modify_stack_synchronously(&block)
|
296
|
+
fail StackUpdateError, failure_message unless target_status === status
|
297
|
+
status
|
298
|
+
else
|
299
|
+
modify_stack_asynchronously(&block)
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
286
303
|
# Execute a block, reporting stack events, until the stack is stable.
|
287
304
|
#
|
288
305
|
# @return the final stack status
|
289
306
|
#
|
290
|
-
def
|
307
|
+
def modify_stack_synchronously
|
291
308
|
watch do |watcher|
|
292
309
|
handling_validation_error do
|
293
310
|
yield
|
@@ -297,11 +314,22 @@ module Stackup
|
|
297
314
|
status = self.status
|
298
315
|
logger.debug("stack_status=#{status}")
|
299
316
|
return status if status.nil? || status =~ /_(COMPLETE|FAILED)$/
|
300
|
-
sleep(
|
317
|
+
sleep(wait_poll_interval)
|
301
318
|
end
|
302
319
|
end
|
303
320
|
end
|
304
321
|
|
322
|
+
# Execute a block to instigate stack modification, but don't wait.
|
323
|
+
#
|
324
|
+
# @return the stack status
|
325
|
+
#
|
326
|
+
def modify_stack_asynchronously
|
327
|
+
handling_validation_error do
|
328
|
+
yield
|
329
|
+
end
|
330
|
+
self.status
|
331
|
+
end
|
332
|
+
|
305
333
|
def normalize_tags(tags)
|
306
334
|
if tags.is_a?(Hash)
|
307
335
|
tags.map do |key, value|
|
@@ -10,7 +10,6 @@ module Stackup
|
|
10
10
|
|
11
11
|
def initialize(stack)
|
12
12
|
@stack = stack
|
13
|
-
@processed_event_ids = Set.new
|
14
13
|
end
|
15
14
|
|
16
15
|
attr_accessor :stack
|
@@ -19,14 +18,14 @@ module Stackup
|
|
19
18
|
#
|
20
19
|
def each_new_event
|
21
20
|
# rubocop:disable Lint/HandleExceptions
|
22
|
-
|
21
|
+
new_events = []
|
23
22
|
stack.events.each do |event|
|
24
|
-
break if
|
25
|
-
|
23
|
+
break if event.id == @last_processed_event_id
|
24
|
+
new_events.unshift(event)
|
26
25
|
end
|
27
|
-
|
28
|
-
yield event
|
29
|
-
@
|
26
|
+
new_events.each do |event|
|
27
|
+
yield event
|
28
|
+
@last_processed_event_id = event.id
|
30
29
|
end
|
31
30
|
rescue Aws::CloudFormation::Errors::ValidationError
|
32
31
|
end
|
@@ -34,8 +33,11 @@ module Stackup
|
|
34
33
|
# Consume all new events
|
35
34
|
#
|
36
35
|
def zero
|
37
|
-
|
36
|
+
# rubocop:disable Lint/HandleExceptions
|
37
|
+
last_event = stack.events.first
|
38
|
+
@last_processed_event_id = last_event.id unless last_event.nil?
|
38
39
|
nil
|
40
|
+
rescue Aws::CloudFormation::Errors::ValidationError
|
39
41
|
end
|
40
42
|
|
41
43
|
private
|
data/lib/stackup/version.rb
CHANGED
data/spec/stackup/stack_spec.rb
CHANGED
@@ -8,8 +8,9 @@ describe Stackup::Stack do
|
|
8
8
|
|
9
9
|
let(:stack_name) { "stack_name" }
|
10
10
|
let(:unique_stack_id) { "ID:#{stack_name}" }
|
11
|
+
let(:stack_options) { {} }
|
11
12
|
|
12
|
-
subject(:stack) { described_class.new(stack_name, cf_client) }
|
13
|
+
subject(:stack) { described_class.new(stack_name, cf_client, stack_options) }
|
13
14
|
|
14
15
|
before do
|
15
16
|
cf_client.stub_responses(:describe_stacks, *describe_stacks_responses)
|
@@ -93,7 +94,28 @@ describe Stackup::Stack do
|
|
93
94
|
|
94
95
|
let(:final_status) { "CREATE_COMPLETE" }
|
95
96
|
|
96
|
-
|
97
|
+
it "calls :create_stack" do
|
98
|
+
expected_args = {
|
99
|
+
:stack_name => stack_name,
|
100
|
+
:template_body => template
|
101
|
+
}
|
102
|
+
create_or_update
|
103
|
+
expect(cf_client).to have_received(:create_stack)
|
104
|
+
.with(hash_including(expected_args))
|
105
|
+
end
|
106
|
+
|
107
|
+
it "it sleeps" do
|
108
|
+
create_or_update
|
109
|
+
expect(stack).to have_received(:sleep).with(5)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "returns status" do
|
113
|
+
expect(create_or_update).to eq("CREATE_COMPLETE")
|
114
|
+
end
|
115
|
+
|
116
|
+
context "with :wait = false" do
|
117
|
+
|
118
|
+
let(:stack_options) { { :wait => false } }
|
97
119
|
|
98
120
|
it "calls :create_stack" do
|
99
121
|
expected_args = {
|
@@ -105,8 +127,13 @@ describe Stackup::Stack do
|
|
105
127
|
.with(hash_including(expected_args))
|
106
128
|
end
|
107
129
|
|
108
|
-
it "
|
109
|
-
|
130
|
+
it "it does not sleep" do
|
131
|
+
create_or_update
|
132
|
+
expect(stack).not_to have_received(:sleep)
|
133
|
+
end
|
134
|
+
|
135
|
+
it "returns initial status" do
|
136
|
+
expect(create_or_update).to eq("CREATE_IN_PROGRESS")
|
110
137
|
end
|
111
138
|
|
112
139
|
end
|
@@ -122,6 +149,19 @@ describe Stackup::Stack do
|
|
122
149
|
|
123
150
|
end
|
124
151
|
|
152
|
+
context "with a custom wait_poll_interval" do
|
153
|
+
|
154
|
+
let(:stack_options) do
|
155
|
+
{ :wait_poll_interval => 12.3 }
|
156
|
+
end
|
157
|
+
|
158
|
+
it "it sleeps for the specified interval" do
|
159
|
+
create_or_update
|
160
|
+
expect(stack).to have_received(:sleep).with(12.3)
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|
125
165
|
context "with :template as data" do
|
126
166
|
|
127
167
|
let(:options) do
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
require "aws-sdk-resources"
|
4
|
+
require "securerandom"
|
4
5
|
require "stackup/stack_watcher"
|
5
6
|
|
6
7
|
describe Stackup::StackWatcher do
|
@@ -11,13 +12,14 @@ describe Stackup::StackWatcher do
|
|
11
12
|
subject(:monitor) { described_class.new(stack) }
|
12
13
|
|
13
14
|
def add_event(description)
|
14
|
-
|
15
|
+
event_id = SecureRandom.uuid
|
15
16
|
event = instance_double(
|
16
17
|
Aws::CloudFormation::Event,
|
17
|
-
:event_id =>
|
18
|
+
:event_id => event_id,
|
19
|
+
:id => event_id,
|
20
|
+
:resource_status_reason => description
|
18
21
|
)
|
19
22
|
events.unshift(event)
|
20
|
-
@event_id += 1
|
21
23
|
end
|
22
24
|
|
23
25
|
def new_event_reasons
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stackup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Williams
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-
|
12
|
+
date: 2016-08-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: aws-sdk-resources
|
@@ -129,7 +129,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
129
129
|
version: '0'
|
130
130
|
requirements: []
|
131
131
|
rubyforge_project:
|
132
|
-
rubygems_version: 2.
|
132
|
+
rubygems_version: 2.6.6
|
133
133
|
signing_key:
|
134
134
|
specification_version: 4
|
135
135
|
summary: Manage CloudFormation stacks
|