stackup 1.4.2 → 1.4.3
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 +5 -0
- data/bin/stackup +13 -0
- data/lib/stackup/change_set.rb +1 -1
- data/lib/stackup/differ.rb +1 -1
- data/lib/stackup/parameters.rb +1 -0
- data/lib/stackup/rake_tasks.rb +58 -29
- data/lib/stackup/source.rb +1 -1
- data/lib/stackup/stack.rb +3 -0
- data/lib/stackup/stack_watcher.rb +1 -0
- data/lib/stackup/version.rb +1 -1
- data/lib/stackup/yaml.rb +1 -0
- data/spec/stackup/stack_spec.rb +63 -0
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 01e367ca4b2044872b8bffc12075970ad962f5542e143a3d8f47cc6cd9ec6773
|
4
|
+
data.tar.gz: a3b4dd683a84e01885ffdc60ec306e18d212e24fefddec660cd451b8ca8c5d23
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1fc1090d8365094a4ec26df52d8f4ba745d5ff9dc275001630d4ebb013a7673105d658749ee0d3214da89c1559c0acbaa3a5f9ee1cb17ab8e643ab16436d0ac0
|
7
|
+
data.tar.gz: 578e511731086edfe83a22245bde31c50ec8c194504772f6f4ae3cd2ac56fe5819e2adfc2c11e34b576e07071207f70b2f3f2c38f61d16a0ca74f639e1668333
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# CHANGES
|
2
2
|
|
3
|
+
## 1.4.3 (2019-09-05)
|
4
|
+
|
5
|
+
* Add support for CloudFormation capabilities via CLI and Rake
|
6
|
+
* Fix: Prevent failure when creating a stack with change sets
|
7
|
+
|
3
8
|
## 1.4.2 (2019-01-21)
|
4
9
|
|
5
10
|
* Fix #64: Create and Update functions should not mutate the options parameter
|
data/bin/stackup
CHANGED
@@ -26,6 +26,7 @@ Clamp do
|
|
26
26
|
|
27
27
|
option ["--region"], "REGION", "set region" do |arg|
|
28
28
|
raise ArgumentError, "#{arg.inspect} doesn't look like a region" unless arg =~ /^[a-z]{2}-[a-z]+-\d$/
|
29
|
+
|
29
30
|
arg
|
30
31
|
end
|
31
32
|
|
@@ -84,6 +85,7 @@ Clamp do
|
|
84
85
|
|
85
86
|
def role_arn=(arg)
|
86
87
|
raise ArgumentError, "#{arg.inspect} doesn't look like a role ARN" unless arg =~ %r{^arn:aws:iam::\d+:role/}
|
88
|
+
|
87
89
|
@role_arn = arg
|
88
90
|
end
|
89
91
|
|
@@ -102,6 +104,7 @@ Clamp do
|
|
102
104
|
|
103
105
|
def aws_config
|
104
106
|
return base_aws_config unless role_arn
|
107
|
+
|
105
108
|
assumed_credentials = Aws::AssumeRoleCredentials.new(
|
106
109
|
:client => Aws::STS::Client.new(base_aws_config),
|
107
110
|
:role_arn => role_arn,
|
@@ -190,6 +193,7 @@ Clamp do
|
|
190
193
|
|
191
194
|
option "--service-role-arn", "SERVICE_ROLE_ARN", "cloudformation service role ARN" do |arg|
|
192
195
|
raise ArgumentError, "#{arg.inspect} doesn't look like a role ARN" unless arg =~ %r{^arn:aws:iam::\d+:role/}
|
196
|
+
|
193
197
|
arg
|
194
198
|
end
|
195
199
|
|
@@ -197,6 +201,9 @@ Clamp do
|
|
197
201
|
"when stack creation fails: DO_NOTHING, ROLLBACK, or DELETE",
|
198
202
|
:default => "ROLLBACK"
|
199
203
|
|
204
|
+
option "--capability", "CAPABILITY", "cloudformation capability",
|
205
|
+
:multivalued => true, :default => ["CAPABILITY_NAMED_IAM"]
|
206
|
+
|
200
207
|
def execute
|
201
208
|
unless template_source || use_previous_template?
|
202
209
|
signal_usage_error "Specify either --template or --use-previous-template"
|
@@ -221,6 +228,7 @@ Clamp do
|
|
221
228
|
end
|
222
229
|
options[:role_arn] = service_role_arn if service_role_arn
|
223
230
|
options[:use_previous_template] = use_previous_template?
|
231
|
+
options[:capabilities] = capability_list
|
224
232
|
report_change do
|
225
233
|
stack.create_or_update(options)
|
226
234
|
end
|
@@ -275,6 +283,9 @@ Clamp do
|
|
275
283
|
:attribute_name => :tag_source,
|
276
284
|
&Stackup::Source.method(:new)
|
277
285
|
|
286
|
+
option "--capability", "CAPABILITY", "cloudformation capability",
|
287
|
+
:multivalued => true, :default => ["CAPABILITY_NAMED_IAM"]
|
288
|
+
|
278
289
|
def execute
|
279
290
|
unless template_source || use_previous_template?
|
280
291
|
signal_usage_error "Specify either --template or --use-previous-template"
|
@@ -292,6 +303,7 @@ Clamp do
|
|
292
303
|
options[:tags] = tag_source.data if tag_source
|
293
304
|
options[:use_previous_template] = use_previous_template?
|
294
305
|
options[:force] = force?
|
306
|
+
options[:capabilities] = capability_list
|
295
307
|
report_change do
|
296
308
|
change_set.create(options)
|
297
309
|
end
|
@@ -434,6 +446,7 @@ Clamp do
|
|
434
446
|
display_event(event)
|
435
447
|
end
|
436
448
|
break unless follow?
|
449
|
+
|
437
450
|
sleep 5
|
438
451
|
end
|
439
452
|
end
|
data/lib/stackup/change_set.rb
CHANGED
@@ -87,7 +87,7 @@ module Stackup
|
|
87
87
|
# @raise [Stackup::StackUpdateError] if operation fails
|
88
88
|
#
|
89
89
|
def execute
|
90
|
-
modify_stack(
|
90
|
+
modify_stack(/(CREATE|UPDATE)_COMPLETE/, "update failed") do
|
91
91
|
cf_client.execute_change_set(:stack_name => stack.name, :change_set_name => name)
|
92
92
|
end
|
93
93
|
end
|
data/lib/stackup/differ.rb
CHANGED
@@ -20,7 +20,7 @@ module Stackup
|
|
20
20
|
def diff(existing_data, pending_data, context_lines = nil)
|
21
21
|
existing = format(normalize_data(existing_data)) + "\n"
|
22
22
|
pending = format(normalize_data(pending_data)) + "\n"
|
23
|
-
diff = Diffy::Diff.new(existing, pending, context
|
23
|
+
diff = Diffy::Diff.new(existing, pending, :context => context_lines).to_s(diff_style)
|
24
24
|
diff unless diff =~ /\A\s*\Z/
|
25
25
|
end
|
26
26
|
|
data/lib/stackup/parameters.rb
CHANGED
data/lib/stackup/rake_tasks.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require "rake/tasklib"
|
2
2
|
require "tempfile"
|
3
3
|
require "yaml"
|
4
|
+
require "Pathname"
|
4
5
|
|
5
6
|
module Stackup
|
6
7
|
|
@@ -13,6 +14,7 @@ module Stackup
|
|
13
14
|
attr_accessor :template
|
14
15
|
attr_accessor :parameters
|
15
16
|
attr_accessor :tags
|
17
|
+
attr_accessor :capabilities
|
16
18
|
|
17
19
|
alias namespace= name=
|
18
20
|
|
@@ -23,6 +25,7 @@ module Stackup
|
|
23
25
|
yield self if block_given?
|
24
26
|
raise ArgumentError, "no name provided" unless @name
|
25
27
|
raise ArgumentError, "no template provided" unless @template
|
28
|
+
|
26
29
|
define
|
27
30
|
end
|
28
31
|
|
@@ -36,14 +39,15 @@ module Stackup
|
|
36
39
|
def define
|
37
40
|
namespace(name) do
|
38
41
|
|
39
|
-
data_options =
|
40
|
-
data_options
|
41
|
-
data_options
|
42
|
-
data_options
|
42
|
+
data_options = []
|
43
|
+
data_options << DataOption.for("--template", template)
|
44
|
+
data_options << DataOption.for("--parameters", parameters) if parameters
|
45
|
+
data_options << DataOption.for("--tags", tags) if tag
|
43
46
|
|
44
47
|
desc "Update #{stack} stack"
|
45
|
-
task "up" => data_options.
|
46
|
-
|
48
|
+
task "up" => data_options.grep(DataOptionFile).map(&:argument) do
|
49
|
+
data_options << DataOption.for("--capability", capabilities) if capabilities
|
50
|
+
stackup "up", *data_options.map(&:to_a).flatten
|
47
51
|
end
|
48
52
|
|
49
53
|
desc "Cancel update of #{stack} stack"
|
@@ -52,8 +56,8 @@ module Stackup
|
|
52
56
|
end
|
53
57
|
|
54
58
|
desc "Show pending changes to #{stack} stack"
|
55
|
-
task "diff" => data_options.
|
56
|
-
stackup "diff", *data_options.to_a
|
59
|
+
task "diff" => data_options.grep(DataOptionFile).map(&:argument) do
|
60
|
+
stackup "diff", *data_options.map(&:to_a).flatten
|
57
61
|
end
|
58
62
|
|
59
63
|
desc "Show #{stack} stack outputs and resources"
|
@@ -74,41 +78,66 @@ module Stackup
|
|
74
78
|
end
|
75
79
|
end
|
76
80
|
|
77
|
-
#
|
78
|
-
|
79
|
-
class DataOptions
|
80
|
-
|
81
|
-
def initialize
|
82
|
-
@options = {}
|
83
|
-
end
|
81
|
+
# A flag with optional argument that will be passed to stackup
|
82
|
+
class DataOption
|
84
83
|
|
85
|
-
def
|
86
|
-
@
|
84
|
+
def initialize(flag, argument)
|
85
|
+
@flag = flag
|
86
|
+
@argument = argument
|
87
87
|
end
|
88
88
|
|
89
|
-
def
|
90
|
-
@
|
89
|
+
def to_a
|
90
|
+
[@flag, @argument]
|
91
91
|
end
|
92
92
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
93
|
+
# Factory method for initialising DataOptions based on class
|
94
|
+
def self.for(flag, argument)
|
95
|
+
if argument.is_a?(Hash)
|
96
|
+
DataOptionHash.new(flag, argument)
|
97
|
+
elsif argument.is_a?(Array)
|
98
|
+
DataOptionArray.new(flag, argument)
|
99
|
+
elsif argument.is_a?(String) && File.exist?(argument)
|
100
|
+
DataOptionFile.new(flag, argument)
|
101
|
+
else
|
102
|
+
DataOption.new(flag, argument)
|
99
103
|
end
|
100
104
|
end
|
101
105
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
+
attr_reader :flag
|
107
|
+
attr_reader :argument
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
# An option with a Hash argument
|
112
|
+
# Hash content is stored in a temporary file upon conversion
|
113
|
+
class DataOptionHash < DataOption
|
114
|
+
|
115
|
+
def as_tempfile(filename, data)
|
116
|
+
tempfile = Tempfile.new([filename, ".yml"])
|
117
|
+
tempfile.write(YAML.dump(data))
|
106
118
|
tempfile.close
|
107
119
|
tempfile.path.to_s
|
108
120
|
end
|
109
121
|
|
122
|
+
def to_a
|
123
|
+
[@flag, as_tempfile(@flag[2..-1], @argument)]
|
124
|
+
end
|
125
|
+
|
110
126
|
end
|
111
127
|
|
128
|
+
# An option with an Array argument
|
129
|
+
# Flag is repeated for every Array member upon conversion
|
130
|
+
class DataOptionArray < DataOption
|
131
|
+
|
132
|
+
def to_a
|
133
|
+
@argument.map { |a| [@flag, a] }.flatten
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
# An option with a File argument
|
139
|
+
class DataOptionFile < DataOption; end
|
140
|
+
|
112
141
|
end
|
113
142
|
|
114
143
|
end
|
data/lib/stackup/source.rb
CHANGED
data/lib/stackup/stack.rb
CHANGED
@@ -41,6 +41,7 @@ module Stackup
|
|
41
41
|
def on_event(event_handler = nil, &block)
|
42
42
|
event_handler ||= block
|
43
43
|
raise ArgumentError, "no event_handler provided" if event_handler.nil?
|
44
|
+
|
44
45
|
@event_handler = event_handler
|
45
46
|
end
|
46
47
|
|
@@ -324,6 +325,7 @@ module Stackup
|
|
324
325
|
if wait?
|
325
326
|
status = modify_stack_synchronously(&block)
|
326
327
|
raise StackUpdateError, failure_message unless target_status === status
|
328
|
+
|
327
329
|
status
|
328
330
|
else
|
329
331
|
modify_stack_asynchronously(&block)
|
@@ -344,6 +346,7 @@ module Stackup
|
|
344
346
|
status = self.status
|
345
347
|
logger.debug("stack_status=#{status}")
|
346
348
|
return status if status.nil? || status =~ /_(COMPLETE|FAILED)$/
|
349
|
+
|
347
350
|
sleep(wait_poll_interval)
|
348
351
|
end
|
349
352
|
end
|
data/lib/stackup/version.rb
CHANGED
data/lib/stackup/yaml.rb
CHANGED
data/spec/stackup/stack_spec.rb
CHANGED
@@ -280,6 +280,22 @@ describe Stackup::Stack do
|
|
280
280
|
|
281
281
|
end
|
282
282
|
|
283
|
+
context "with :capabilities as an Array" do
|
284
|
+
|
285
|
+
before do
|
286
|
+
options[:capabilities] = %w[CAPABILITY_IAM CAPABILITY_NAMED_IAM]
|
287
|
+
end
|
288
|
+
|
289
|
+
it "passes them through" do
|
290
|
+
expected_capabilities = %w[CAPABILITY_IAM CAPABILITY_NAMED_IAM]
|
291
|
+
create_or_update
|
292
|
+
expect(cf_client).to have_received(:create_stack) do |options|
|
293
|
+
expect(options[:capabilities]).to eq(expected_capabilities)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
end
|
298
|
+
|
283
299
|
end
|
284
300
|
|
285
301
|
describe "#change_set#create" do
|
@@ -360,6 +376,53 @@ describe Stackup::Stack do
|
|
360
376
|
|
361
377
|
end
|
362
378
|
|
379
|
+
context "with :capabilities as an Array" do
|
380
|
+
|
381
|
+
before do
|
382
|
+
options[:capabilities] = %w[CAPABILITY_IAM CAPABILITY_NAMED_IAM]
|
383
|
+
end
|
384
|
+
|
385
|
+
it "passes them through" do
|
386
|
+
expected_capabilities = %w[CAPABILITY_IAM CAPABILITY_NAMED_IAM]
|
387
|
+
create_change_set
|
388
|
+
expect(cf_client).to have_received(:create_change_set) do |options|
|
389
|
+
expect(options[:capabilities]).to eq(expected_capabilities)
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
end
|
394
|
+
|
395
|
+
end
|
396
|
+
|
397
|
+
describe "#change_set#execute" do
|
398
|
+
|
399
|
+
let(:change_set_name) { "create-it" }
|
400
|
+
|
401
|
+
let(:describe_stacks_responses) do
|
402
|
+
[
|
403
|
+
stack_description("CREATE_IN_PROGRESS"),
|
404
|
+
stack_description("CREATE_COMPLETE")
|
405
|
+
]
|
406
|
+
end
|
407
|
+
|
408
|
+
def execute_change_set
|
409
|
+
stack.change_set(change_set_name).execute
|
410
|
+
end
|
411
|
+
|
412
|
+
it "calls :execute_change_set" do
|
413
|
+
execute_change_set
|
414
|
+
expected_args = {
|
415
|
+
:stack_name => stack_name,
|
416
|
+
:change_set_name => change_set_name
|
417
|
+
}
|
418
|
+
expect(cf_client).to have_received(:execute_change_set)
|
419
|
+
.with(hash_including(expected_args))
|
420
|
+
end
|
421
|
+
|
422
|
+
it "returns status" do
|
423
|
+
expect(execute_change_set).to eq("CREATE_COMPLETE")
|
424
|
+
end
|
425
|
+
|
363
426
|
end
|
364
427
|
|
365
428
|
end
|
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: 1.4.
|
4
|
+
version: 1.4.3
|
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: 2019-
|
12
|
+
date: 2019-09-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: aws-sdk-cloudformation
|
@@ -134,8 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
134
134
|
- !ruby/object:Gem::Version
|
135
135
|
version: '0'
|
136
136
|
requirements: []
|
137
|
-
|
138
|
-
rubygems_version: 2.7.6
|
137
|
+
rubygems_version: 3.0.3
|
139
138
|
signing_key:
|
140
139
|
specification_version: 4
|
141
140
|
summary: Manage CloudFormation stacks
|