cfndk 0.1.0 → 0.1.1

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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +23 -14
  3. data/.gitignore +0 -1
  4. data/.rspec_parallel +6 -0
  5. data/Gemfile +1 -0
  6. data/Gemfile.lock +811 -0
  7. data/README.md +122 -10
  8. data/cfndk.gemspec +1 -0
  9. data/lib/cfndk/change_set_command.rb +97 -0
  10. data/lib/cfndk/command.rb +15 -181
  11. data/lib/cfndk/config_file_loadable.rb +13 -0
  12. data/lib/cfndk/global_config.rb +15 -0
  13. data/lib/cfndk/key_pair.rb +7 -4
  14. data/lib/cfndk/key_pair_command.rb +53 -0
  15. data/lib/cfndk/key_pairs.rb +2 -1
  16. data/lib/cfndk/logger.rb +1 -1
  17. data/lib/cfndk/stack.rb +382 -103
  18. data/lib/cfndk/stack_command.rb +110 -0
  19. data/lib/cfndk/stacks.rb +40 -14
  20. data/lib/cfndk/subcommand_help_returnable.rb +16 -0
  21. data/lib/cfndk/version.rb +1 -1
  22. data/lib/cfndk.rb +6 -0
  23. data/skel/cfndk.yml +4 -0
  24. data/spec/cfndk_change_set_create_spec.rb +436 -0
  25. data/spec/cfndk_change_set_destroy_spec.rb +160 -0
  26. data/spec/cfndk_change_set_execute_spec.rb +179 -0
  27. data/spec/cfndk_change_set_report_spec.rb +107 -0
  28. data/spec/cfndk_change_set_spec.rb +37 -0
  29. data/spec/cfndk_create_spec.rb +56 -141
  30. data/spec/cfndk_destroy_spec.rb +4 -2
  31. data/spec/cfndk_keypiar_spec.rb +11 -9
  32. data/spec/cfndk_report_spec.rb +3 -1
  33. data/spec/cfndk_spec.rb +5 -3
  34. data/spec/cfndk_stack_create_spec.rb +454 -0
  35. data/spec/cfndk_stack_destroy_spec.rb +161 -0
  36. data/spec/cfndk_stack_report_spec.rb +181 -0
  37. data/spec/cfndk_stack_spec.rb +6 -1146
  38. data/spec/cfndk_stack_update_spec.rb +467 -0
  39. data/spec/spec_helper.rb +4 -1
  40. data/spec/support/aruba.rb +1 -0
  41. metadata +42 -2
@@ -0,0 +1,110 @@
1
+ module CFnDK
2
+ class StackCommand < Thor
3
+ include SubcommandHelpReturnable
4
+ include ConfigFileLoadable
5
+
6
+ class_option :verbose, type: :boolean, aliases: 'v', desc: 'More verbose output.'
7
+ class_option :color, type: :boolean, default: true, desc: 'Use colored output'
8
+ class_option :config_path, type: :string, aliases: 'c', default: "#{Dir.getwd}/cfndk.yml", desc: 'The configuration file to use'
9
+ class_option :stack_names, type: :array, desc: 'Target stack names'
10
+
11
+ desc 'create', 'Create stack'
12
+ option :uuid, type: :string, aliases: 'u', default: ENV['CFNDK_UUID'] || nil, desc: 'Use UUID'
13
+ option :properties, type: :hash, aliases: 'p', default: {}, desc: 'Set property'
14
+ def create
15
+ CFnDK.logger.info 'create...'.color(:green)
16
+ data = load_config_data(options)
17
+
18
+ credentials = CFnDK::CredentialProviderChain.new.resolve
19
+ stacks = CFnDK::Stacks.new(data, options, credentials)
20
+ stacks.validate
21
+ stacks.create
22
+ return 0
23
+ rescue => e
24
+ CFnDK.logger.error "#{e.class}: #{e.message}".color(:red)
25
+ e.backtrace_locations.each do |line|
26
+ CFnDK.logger.debug line
27
+ end
28
+ return 1
29
+ end
30
+
31
+ desc 'update', 'Update stack'
32
+ option :uuid, type: :string, aliases: 'u', default: ENV['CFNDK_UUID'] || nil, desc: 'Use UUID'
33
+ option :properties, type: :hash, aliases: 'p', default: {}, desc: 'Set property'
34
+ def update
35
+ CFnDK.logger.info 'update...'.color(:green)
36
+ data = load_config_data(options)
37
+
38
+ credentials = CFnDK::CredentialProviderChain.new.resolve
39
+ stacks = CFnDK::Stacks.new(data, options, credentials)
40
+ stacks.validate
41
+ stacks.update
42
+ return 0
43
+ rescue => e
44
+ CFnDK.logger.error "#{e.class}: #{e.message}".color(:red)
45
+ e.backtrace_locations.each do |line|
46
+ CFnDK.logger.debug line
47
+ end
48
+ return 1
49
+ end
50
+
51
+ desc 'destroy', 'Destroy stack'
52
+ option :force, type: :boolean, aliases: 'f', default: false, desc: 'Say yes to all prompts for confirmation'
53
+ option :uuid, type: :string, aliases: 'u', default: ENV['CFNDK_UUID'] || nil, desc: 'Use UUID'
54
+ def destroy
55
+ CFnDK.logger.info 'destroy...'.color(:green)
56
+ data = load_config_data(options)
57
+
58
+ credentials = CFnDK::CredentialProviderChain.new.resolve
59
+ stacks = CFnDK::Stacks.new(data, options, credentials)
60
+
61
+ if options[:force] || yes?('Are you sure you want to destroy? (y/n)', :yellow)
62
+ stacks.destroy
63
+ return 0
64
+ else
65
+ CFnDK.logger.info 'destroy command was canceled'.color(:green)
66
+ return 2
67
+ end
68
+ rescue => e
69
+ CFnDK.logger.error "#{e.class}: #{e.message}".color(:red)
70
+ e.backtrace_locations.each do |line|
71
+ CFnDK.logger.debug line
72
+ end
73
+ return 1
74
+ end
75
+
76
+ desc 'validate', 'Validate stack'
77
+ def validate
78
+ CFnDK.logger.info 'validate...'.color(:green)
79
+ data = load_config_data(options)
80
+ credentials = CFnDK::CredentialProviderChain.new.resolve
81
+ stacks = CFnDK::Stacks.new(data, options, credentials)
82
+ stacks.validate
83
+ return 0
84
+ rescue => e
85
+ CFnDK.logger.error "#{e.class}: #{e.message}".color(:red)
86
+ e.backtrace_locations.each do |line|
87
+ CFnDK.logger.debug line
88
+ end
89
+ return 1
90
+ end
91
+
92
+ desc 'report', 'Report stack'
93
+ option :uuid, type: :string, aliases: 'u', default: ENV['CFNDK_UUID'] || nil, desc: 'Use UUID'
94
+ option :types, type: :array, default: %w(tag output parameter resource event), desc: 'Report type'
95
+ def report
96
+ CFnDK.logger.info 'report...'.color(:green)
97
+ data = load_config_data(options)
98
+ credentials = CFnDK::CredentialProviderChain.new.resolve
99
+ stacks = CFnDK::Stacks.new(data, options, credentials)
100
+ stacks.report
101
+ return 0
102
+ rescue => e
103
+ CFnDK.logger.error "#{e.class}: #{e.message}".color(:red)
104
+ e.backtrace_locations.each do |line|
105
+ CFnDK.logger.debug line
106
+ end
107
+ return 1
108
+ end
109
+ end
110
+ end
data/lib/cfndk/stacks.rb CHANGED
@@ -3,7 +3,7 @@ module CFnDK
3
3
  def initialize(data, option, credentials)
4
4
  @option = option
5
5
  @credentials = credentials
6
-
6
+ @global_config = CFnDK::GlobalConfig.new(data, option)
7
7
  prepare_stack(data)
8
8
  prepare_sequence
9
9
  end
@@ -51,24 +51,50 @@ module CFnDK
51
51
  end
52
52
  end
53
53
 
54
- def create_or_changeset
54
+ def create_change_set
55
55
  @sequence.each do |stacks|
56
- create_stacks = []
57
- changeset_stacks = []
56
+ wait_until_stacks = []
58
57
  stacks.each do |name|
59
- if @stacks[name].exits?
60
- @stacks[name].create_change_set
61
- changeset_stacks.push name
58
+ wait_until_stacks.push(@stacks[name].create_change_set)
59
+ end
60
+ wait_until_stacks.compact!
61
+ wait_until_stacks.each do |name|
62
+ @stacks[name].wait_until_create_change_set
63
+ end
64
+ end
65
+ end
66
+
67
+ def execute_change_set
68
+ @sequence.each do |stacks|
69
+ created_stacks = []
70
+ wait_until_stacks = []
71
+ stacks.each do |name|
72
+ created_stacks.push(name) if @stacks[name].created?
73
+ wait_until_stacks.push(@stacks[name].execute_change_set)
74
+ end
75
+ wait_until_stacks.compact!
76
+ wait_until_stacks.each do |name|
77
+ if created_stacks.include?(name)
78
+ @stacks[name].wait_until_update
62
79
  else
63
- @stacks[name].create
64
- create_stacks.push name
80
+ @stacks[name].wait_until_create
65
81
  end
66
82
  end
67
- create_stacks.each do |name|
68
- @stacks[name].wait_until_create
83
+ end
84
+ end
85
+
86
+ def delete_change_set
87
+ @sequence.reverse_each do |stacks|
88
+ stacks.each do |name|
89
+ @stacks[name].delete_change_set
69
90
  end
70
- changeset_stacks.each do |name|
71
- @stacks[name].wait_until_create_change_set
91
+ end
92
+ end
93
+
94
+ def report_change_set
95
+ @sequence.each do |stacks|
96
+ stacks.each do |name|
97
+ @stacks[name].report_change_set
72
98
  end
73
99
  end
74
100
  end
@@ -87,7 +113,7 @@ module CFnDK
87
113
  @stacks = {}
88
114
  return unless data['stacks'].is_a?(Hash)
89
115
  data['stacks'].each do |name, properties|
90
- @stacks[name] = Stack.new(name, properties, @option, @credentials)
116
+ @stacks[name] = Stack.new(name, properties, @option, @global_config, @credentials)
91
117
  end
92
118
  end
93
119
 
@@ -0,0 +1,16 @@
1
+ module CFnDK
2
+ module SubcommandHelpReturnable
3
+ module ClassMethods
4
+ def subcommand_help(cmd)
5
+ desc 'help [COMMAND]', 'Describe subcommands or one specific subcommand'
6
+ class_eval "
7
+ def help(command = nil, subcommand = true); super; return 2; end
8
+ "
9
+ end
10
+ end
11
+ extend ClassMethods
12
+ def self.included(klass)
13
+ klass.extend ClassMethods
14
+ end
15
+ end
16
+ end
data/lib/cfndk/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module CFnDK
2
- VERSION = '0.1.0'.freeze
2
+ VERSION = '0.1.1'.freeze
3
3
  end
data/lib/cfndk.rb CHANGED
@@ -25,8 +25,14 @@ require 'cfndk/stacks'
25
25
  require 'cfndk/key_pair'
26
26
  require 'cfndk/key_pairs'
27
27
  require 'cfndk/erb_string'
28
+ require 'cfndk/global_config'
28
29
  require 'cfndk/logger'
29
30
  require 'cfndk/credential_provider_chain'
31
+ require 'cfndk/subcommand_help_returnable'
32
+ require 'cfndk/config_file_loadable'
33
+ require 'cfndk/key_pair_command'
34
+ require 'cfndk/stack_command'
35
+ require 'cfndk/change_set_command'
30
36
  require 'cfndk/command'
31
37
 
32
38
  module CFnDK
data/skel/cfndk.yml CHANGED
@@ -1,3 +1,7 @@
1
+ global:
2
+ region: ap-northeast-1
3
+ s3_template_bucket: cfndk-templates
4
+ timeout_in_minutes: 10
1
5
  keypairs:
2
6
  CFnDKSampleKey:
3
7
  CFnDKSampleKey2:
@@ -0,0 +1,436 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'CFnDK', type: :aruba do
4
+ before(:each) { set_environment_variable('AWS_REGION', ENV['AWS_REGION']) }
5
+ before(:each) { set_environment_variable('AWS_PROFILE', ENV['AWS_PROFILE']) }
6
+ before(:each) { set_environment_variable('AWS_ACCESS_KEY_ID', ENV["AWS_ACCESS_KEY_ID#{ENV['TEST_ENV_NUMBER']}"]) }
7
+ before(:each) { set_environment_variable('AWS_SECRET_ACCESS_KEY', ENV["AWS_SECRET_ACCESS_KEY#{ENV['TEST_ENV_NUMBER']}"]) }
8
+ describe 'bin/cfndk' do
9
+ before(:each) { setup_aruba }
10
+ let(:file) { 'cfndk.yml' }
11
+ let(:file2) { 'cfndk2.yml' }
12
+ let(:uuid) { '38437346-c75c-47c5-83b4-d504f85e275b' }
13
+ let(:change_set_uuid) { '38437346-c75c-47c5-83b4-d504f85e27ca' }
14
+
15
+ describe 'changeset' do
16
+ describe 'create', create: true do
17
+ context 'without cfndk.yml' do
18
+ before(:each) { run_command('cfndk changeset create') }
19
+ it 'displays file does not exist error and status code = 1' do
20
+ aggregate_failures do
21
+ expect(last_command_started).to have_exit_status(1)
22
+ expect(last_command_started).to have_output(/ERROR RuntimeError: File does not exist./)
23
+ end
24
+ end
25
+ end
26
+
27
+ context 'with cfndk2.yml' do
28
+ yaml = <<-"YAML"
29
+ keypairs:
30
+ YAML
31
+ before(:each) { write_file(file2, yaml) }
32
+ context 'when -c cfndk2.yml and empty stacks' do
33
+ before(:each) { run_command("cfndk changeset create -c=#{file2}") }
34
+ it 'displays empty stack log' do
35
+ aggregate_failures do
36
+ expect(last_command_started).to be_successfully_executed
37
+ expect(last_command_started).to have_output(/INFO create.../)
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ context 'with cfndk.yml' do
44
+ context 'when cfndk.yml is empty' do
45
+ before(:each) { touch(file) }
46
+ before(:each) { run_command('cfndk changeset create') }
47
+ it 'displays File is empty error and status code = 1' do
48
+ aggregate_failures do
49
+ expect(last_command_started).to have_exit_status(1)
50
+ expect(last_command_started).to have_output(/ERROR File is empty./)
51
+ end
52
+ end
53
+ end
54
+
55
+ context 'with stacks:' do
56
+ context 'without stack' do
57
+ before(:each) { write_file(file, 'stacks:') }
58
+ before(:each) { run_command('cfndk changeset create') }
59
+ it 'displays create log' do
60
+ aggregate_failures do
61
+ expect(last_command_started).to be_successfully_executed
62
+ expect(last_command_started).to have_output(/INFO create.../)
63
+ end
64
+ end
65
+ end
66
+
67
+ context 'with a stack' do
68
+ yaml = <<-"YAML"
69
+ stacks:
70
+ Test:
71
+ template_file: vpc.yaml
72
+ parameter_input: vpc.json
73
+ timeout_in_minutes: 2
74
+ YAML
75
+ before(:each) { write_file(file, yaml) }
76
+ before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
77
+ before(:each) { copy('%/vpc.json', 'vpc.json') }
78
+ before(:each) { append_to_file('vpc.yaml', ' ' * (51200 + 1 - file_size('vpc.yaml').to_i)) }
79
+ before(:each) { run_command('cfndk changeset create') }
80
+ it 'displays created log' do
81
+ aggregate_failures do
82
+ expect(last_command_started).to be_successfully_executed
83
+ expect(last_command_started).to have_output(/INFO validate stack: Test$/)
84
+ expect(last_command_started).to have_output(/INFO creating change set: Test$/)
85
+ expect(last_command_started).to have_output(/INFO created change set: Test$/)
86
+ end
87
+ end
88
+ after(:each) { run_command('cfndk destroy -f') }
89
+ end
90
+ context 'with two stacks' do
91
+ yaml = <<-"YAML"
92
+ stacks:
93
+ Test:
94
+ template_file: vpc.yaml
95
+ parameter_input: vpc.json
96
+ timeout_in_minutes: 2
97
+ Test2:
98
+ template_file: sg.yaml
99
+ parameter_input: sg.json
100
+ depends:
101
+ - Test
102
+ YAML
103
+
104
+ before(:each) { write_file(file, yaml) }
105
+ before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
106
+ before(:each) { copy('%/vpc.json', 'vpc.json') }
107
+ before(:each) { copy('%/sg.yaml', 'sg.yaml') }
108
+ before(:each) { copy('%/sg.json', 'sg.json') }
109
+ before(:each) { run_command('cfndk changeset create') }
110
+ it 'displays created logs' do
111
+ aggregate_failures do
112
+ expect(last_command_started).to be_successfully_executed
113
+ expect(last_command_started).to have_output(/INFO validate stack: Test$/)
114
+ expect(last_command_started).to have_output(/INFO creating change set: Test$/)
115
+ expect(last_command_started).to have_output(/INFO created change set: Test$/)
116
+ expect(last_command_started).to have_output(/INFO validate stack: Test2$/)
117
+ expect(last_command_started).to have_output(/INFO creating change set: Test2$/)
118
+ expect(last_command_started).to have_output(/INFO created change set: Test2$/)
119
+ end
120
+ end
121
+ after(:each) { run_command('cfndk destroy -f') }
122
+ end
123
+ context 'when invalid dependency', dependency: true do
124
+ yaml = <<-"YAML"
125
+ stacks:
126
+ Test:
127
+ template_file: vpc.yaml
128
+ parameter_input: vpc.json
129
+ timeout_in_minutes: 2
130
+ depends:
131
+ - Test2
132
+ Test2:
133
+ template_file: sg.yaml
134
+ parameter_input: sg.json
135
+ YAML
136
+
137
+ before(:each) { write_file(file, yaml) }
138
+ before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
139
+ before(:each) { copy('%/vpc.json', 'vpc.json') }
140
+ before(:each) { copy('%/sg.yaml', 'sg.yaml') }
141
+ before(:each) { copy('%/sg.json', 'sg.json') }
142
+ before(:each) { run_command('cfndk changeset create') }
143
+ it 'displays created logs' do
144
+ aggregate_failures do
145
+ expect(last_command_started).to be_successfully_executed
146
+ expect(last_command_started).to have_output(/INFO validate stack: Test$/)
147
+ expect(last_command_started).to have_output(/INFO creating change set: Test$/)
148
+ expect(last_command_started).to have_output(/INFO created change set: Test$/)
149
+ expect(last_command_started).to have_output(/INFO validate stack: Test2$/)
150
+ expect(last_command_started).to have_output(/INFO creating change set: Test2$/)
151
+ expect(last_command_started).to have_output(/INFO created change set: Test2$/)
152
+ end
153
+ end
154
+ after(:each) { run_command('cfndk destroy -f') }
155
+ end
156
+ context 'when cyclic dependency', dependency: true do
157
+ yaml = <<-"YAML"
158
+ stacks:
159
+ Test:
160
+ template_file: vpc.yaml
161
+ parameter_input: vpc.json
162
+ timeout_in_minutes: 2
163
+ depends:
164
+ - Test2
165
+ Test2:
166
+ template_file: sg.yaml
167
+ parameter_input: sg.json
168
+ depends:
169
+ - Test
170
+ YAML
171
+
172
+ before(:each) { write_file(file, yaml) }
173
+ before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
174
+ before(:each) { copy('%/vpc.json', 'vpc.json') }
175
+ before(:each) { copy('%/sg.yaml', 'sg.yaml') }
176
+ before(:each) { copy('%/sg.json', 'sg.json') }
177
+ before(:each) { run_command('cfndk changeset create') }
178
+ it 'displays cyclic dependency error and exit code = 1' do
179
+ aggregate_failures do
180
+ expect(last_command_started).to have_exit_status(1)
181
+ expect(last_command_started).to have_output(/ERROR RuntimeError: There are cyclic dependency or stack doesn't exist. unprocessed_stack: Test,Test2$/)
182
+ end
183
+ end
184
+ after(:each) { run_command('cfndk destroy -f') }
185
+ end
186
+ context 'when requires capabilities without capabilities', capabilities: true do
187
+ yaml = <<-"YAML"
188
+ stacks:
189
+ Test:
190
+ template_file: iam.yaml
191
+ parameter_input: iam.json
192
+ timeout_in_minutes: 2
193
+ YAML
194
+
195
+ before(:each) { write_file(file, yaml) }
196
+ before(:each) { copy('%/iam.yaml', 'iam.yaml') }
197
+ before(:each) { copy('%/iam.json', 'iam.json') }
198
+ before(:each) { run_command('cfndk changeset create') }
199
+ it 'displays Requires capabilities error and exit code = 1' do
200
+ aggregate_failures do
201
+ expect(last_command_started).to have_exit_status(1)
202
+ expect(last_command_started).to have_output(/ERROR Aws::CloudFormation::Errors::InsufficientCapabilitiesException: Requires capabilities : \[CAPABILITY_NAMED_IAM\]/)
203
+ end
204
+ end
205
+ after(:each) { run_command('cfndk destroy -f') }
206
+ end
207
+ context 'when success with capabilities', capabilities: true do
208
+ yaml = <<-"YAML"
209
+ stacks:
210
+ Test:
211
+ template_file: iam.yaml
212
+ parameter_input: iam.json
213
+ capabilities:
214
+ - CAPABILITY_NAMED_IAM
215
+ timeout_in_minutes: 3
216
+ YAML
217
+
218
+ before(:each) { write_file(file, yaml) }
219
+ before(:each) { copy('%/iam.yaml', 'iam.yaml') }
220
+ before(:each) { copy('%/iam.json', 'iam.json') }
221
+ before(:each) { run_command('cfndk changeset create') }
222
+ it do
223
+ aggregate_failures do
224
+ expect(last_command_started).to be_successfully_executed
225
+ expect(last_command_started).to have_output(/INFO created change set: Test$/)
226
+ end
227
+ end
228
+ after(:each) { run_command('cfndk destroy -f') }
229
+ end
230
+ context 'with UUID', uuid: true do
231
+ context 'when -u 38437346-c75c-47c5-83b4-d504f85e275b' do
232
+ yaml = <<-"YAML"
233
+ stacks:
234
+ Test:
235
+ template_file: vpc.yaml
236
+ parameter_input: vpc.json
237
+ parameters:
238
+ VpcName: sample<%= append_uuid%>
239
+ timeout_in_minutes: 2
240
+ Test2:
241
+ template_file: sg.yaml
242
+ parameter_input: sg.json
243
+ parameters:
244
+ VpcName: sample<%= append_uuid%>
245
+ depends:
246
+ - Test
247
+ YAML
248
+ before(:each) { write_file(file, yaml) }
249
+ before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
250
+ before(:each) { copy('%/vpc.json', 'vpc.json') }
251
+ before(:each) { copy('%/sg.yaml', 'sg.yaml') }
252
+ before(:each) { copy('%/sg.json', 'sg.json') }
253
+ before(:each) { run_command("cfndk changeset create -u=#{uuid}") }
254
+ it do
255
+ aggregate_failures do
256
+ expect(last_command_started).to be_successfully_executed
257
+ expect(last_command_started).to have_output(/INFO validate stack: Test-#{uuid}$/)
258
+ expect(last_command_started).to have_output(/INFO creating change set: Test$/)
259
+ expect(last_command_started).to have_output(/INFO created change set: Test$/)
260
+ expect(last_command_started).to have_output(/INFO validate stack: Test2-#{uuid}$/)
261
+ expect(last_command_started).to have_output(/INFO creating change set: Test2$/)
262
+ expect(last_command_started).to have_output(/INFO created change set: Test2$/)
263
+ end
264
+ end
265
+ after(:each) { run_command("cfndk destroy -f -u=#{uuid}") }
266
+ end
267
+ context 'when env CFNDK_UUID=38437346-c75c-47c5-83b4-d504f85e275b' do
268
+ before(:each) { set_environment_variable('CFNDK_UUID', uuid) }
269
+ context 'with two stacks' do
270
+ yaml = <<-"YAML"
271
+ stacks:
272
+ Test:
273
+ template_file: vpc.yaml
274
+ parameter_input: vpc.json
275
+ parameters:
276
+ VpcName: sample<%= append_uuid%>
277
+ timeout_in_minutes: 2
278
+ Test2:
279
+ template_file: sg.yaml
280
+ parameter_input: sg.json
281
+ parameters:
282
+ VpcName: sample<%= append_uuid%>
283
+ depends:
284
+ - Test
285
+ YAML
286
+ before(:each) { write_file(file, yaml) }
287
+ before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
288
+ before(:each) { copy('%/vpc.json', 'vpc.json') }
289
+ before(:each) { copy('%/sg.yaml', 'sg.yaml') }
290
+ before(:each) { copy('%/sg.json', 'sg.json') }
291
+ before(:each) { run_command('cfndk changeset create') }
292
+ it do
293
+ aggregate_failures do
294
+ expect(last_command_started).to be_successfully_executed
295
+ expect(last_command_started).to have_output(/INFO validate stack: Test-#{uuid}$/)
296
+ expect(last_command_started).to have_output(/INFO creating change set: Test$/)
297
+ expect(last_command_started).to have_output(/INFO created change set: Test$/)
298
+ expect(last_command_started).to have_output(/INFO validate stack: Test2-#{uuid}$/)
299
+ expect(last_command_started).to have_output(/INFO creating change set: Test2$/)
300
+ expect(last_command_started).to have_output(/INFO created change set: Test2$/)
301
+ end
302
+ end
303
+ after(:each) { run_command('cfndk destroy -f') }
304
+ end
305
+ context 'when --stack-names=Test' do
306
+ yaml = <<-"YAML"
307
+ stacks:
308
+ Test:
309
+ template_file: vpc.yaml
310
+ parameter_input: vpc.json
311
+ parameters:
312
+ VpcName: sample<%= append_uuid%>
313
+ timeout_in_minutes: 2
314
+ Test2:
315
+ template_file: sg.yaml
316
+ parameter_input: sg.json
317
+ parameters:
318
+ VpcName: sample<%= append_uuid%>
319
+ depends:
320
+ - Test
321
+ YAML
322
+ before(:each) { write_file(file, yaml) }
323
+ before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
324
+ before(:each) { copy('%/vpc.json', 'vpc.json') }
325
+ before(:each) { copy('%/sg.yaml', 'sg.yaml') }
326
+ before(:each) { copy('%/sg.json', 'sg.json') }
327
+ before(:each) { run_command('cfndk changeset create --stack-names=Test') }
328
+ it do
329
+ aggregate_failures do
330
+ expect(last_command_started).to be_successfully_executed
331
+ expect(last_command_started).to have_output(/INFO create.../)
332
+ expect(last_command_started).to have_output(/INFO validate stack: Test-#{uuid}$/)
333
+ expect(last_command_started).to have_output(/INFO creating change set: Test$/)
334
+ expect(last_command_started).to have_output(/INFO created change set: Test$/)
335
+ expect(last_command_started).not_to have_output(/INFO validate stack: Test2-#{uuid}$/)
336
+ expect(last_command_started).not_to have_output(/INFO creating change set: Test2$/)
337
+ expect(last_command_started).not_to have_output(/INFO created change set: Test2$/)
338
+ end
339
+ end
340
+ after(:each) { run_command('cfndk destroy -f') }
341
+ end
342
+ context 'when --stack-names=Test Test2' do
343
+ yaml = <<-"YAML"
344
+ stacks:
345
+ Test:
346
+ template_file: vpc.yaml
347
+ parameter_input: vpc.json
348
+ parameters:
349
+ VpcName: sample<%= append_uuid%>
350
+ timeout_in_minutes: 2
351
+ Test2:
352
+ template_file: sg.yaml
353
+ parameter_input: sg.json
354
+ parameters:
355
+ VpcName: sample<%= append_uuid%>
356
+ depends:
357
+ - Test
358
+ Test3:
359
+ template_file: iam.yaml
360
+ parameter_input: iam.json
361
+ parameters:
362
+ WebRoleName: WebhRole<%= append_uuid%>
363
+ capabilities:
364
+ - CAPABILITY_NAMED_IAM
365
+ timeout_in_minutes: 3
366
+ YAML
367
+ before(:each) { write_file(file, yaml) }
368
+ before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
369
+ before(:each) { copy('%/vpc.json', 'vpc.json') }
370
+ before(:each) { copy('%/sg.yaml', 'sg.yaml') }
371
+ before(:each) { copy('%/sg.json', 'sg.json') }
372
+ before(:each) { copy('%/iam.yaml', 'iam.yaml') }
373
+ before(:each) { copy('%/iam.json', 'iam.json') }
374
+ before(:each) { run_command('cfndk changeset create --stack-names=Test Test2') }
375
+ it do
376
+ aggregate_failures do
377
+ expect(last_command_started).to be_successfully_executed
378
+ expect(last_command_started).to have_output(/INFO create.../)
379
+ expect(last_command_started).to have_output(/INFO validate stack: Test-#{uuid}$/)
380
+ expect(last_command_started).to have_output(/INFO creating change set: Test$/)
381
+ expect(last_command_started).to have_output(/INFO created change set: Test$/)
382
+ expect(last_command_started).to have_output(/INFO validate stack: Test2-#{uuid}$/)
383
+ expect(last_command_started).to have_output(/INFO creating change set: Test2$/)
384
+ expect(last_command_started).to have_output(/INFO created change set: Test2$/)
385
+ expect(last_command_started).not_to have_output(/INFO validate stack: Test3-#{uuid}$/)
386
+ expect(last_command_started).not_to have_output(/INFO creating change set: Test3$/)
387
+ expect(last_command_started).not_to have_output(/INFO created change set: Test3$/)
388
+ end
389
+ end
390
+ after(:each) { run_command('cfndk destroy -f') }
391
+ end
392
+ end
393
+
394
+ context 'when -u 38437346-c75c-47c5-83b4-d504f85e275b and --change-set-uuid 38437346-c75c-47c5-83b4-d504f85e275c' do
395
+ yaml = <<-"YAML"
396
+ stacks:
397
+ Test:
398
+ template_file: vpc.yaml
399
+ parameter_input: vpc.json
400
+ parameters:
401
+ VpcName: sample<%= append_uuid%>
402
+ timeout_in_minutes: 2
403
+ Test2:
404
+ template_file: sg.yaml
405
+ parameter_input: sg.json
406
+ parameters:
407
+ VpcName: sample<%= append_uuid%>
408
+ depends:
409
+ - Test
410
+ YAML
411
+ before(:each) { write_file(file, yaml) }
412
+ before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
413
+ before(:each) { copy('%/vpc.json', 'vpc.json') }
414
+ before(:each) { copy('%/sg.yaml', 'sg.yaml') }
415
+ before(:each) { copy('%/sg.json', 'sg.json') }
416
+ before(:each) { run_command("cfndk changeset create -u=#{uuid} --change-set-uuid 38437346-c75c-47c5-83b4-d504f85e275c") }
417
+ it do
418
+ aggregate_failures do
419
+ expect(last_command_started).to be_successfully_executed
420
+ expect(last_command_started).to have_output(/INFO validate stack: Test-#{uuid}$/)
421
+ expect(last_command_started).to have_output(/INFO creating change set: Test-38437346-c75c-47c5-83b4-d504f85e275c$/)
422
+ expect(last_command_started).to have_output(/INFO created change set: Test-38437346-c75c-47c5-83b4-d504f85e275c$/)
423
+ expect(last_command_started).to have_output(/INFO validate stack: Test2-#{uuid}$/)
424
+ expect(last_command_started).to have_output(/INFO creating change set: Test2-38437346-c75c-47c5-83b4-d504f85e275c$/)
425
+ expect(last_command_started).to have_output(/INFO created change set: Test2-38437346-c75c-47c5-83b4-d504f85e275c$/)
426
+ end
427
+ end
428
+ after(:each) { run_command("cfndk destroy -f -u=#{uuid}") }
429
+ end
430
+ end
431
+ end
432
+ end
433
+ end
434
+ end
435
+ end
436
+ end