cfndk 0.0.7 → 0.1.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.
Files changed (78) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +79 -0
  3. data/.gitignore +1 -1
  4. data/.rspec +2 -0
  5. data/.rspec_parallel +6 -0
  6. data/.simplecov +9 -0
  7. data/Gemfile +11 -1
  8. data/Gemfile.lock +815 -0
  9. data/README.md +269 -76
  10. data/bin/cfndk +3 -18
  11. data/cfndk.gemspec +15 -6
  12. data/docker/Dockerfile +8 -0
  13. data/docker/build.sh +3 -0
  14. data/docker/cfndk.sh +14 -0
  15. data/lib/cfndk.rb +36 -0
  16. data/lib/cfndk/change_set_command.rb +103 -0
  17. data/lib/cfndk/command.rb +125 -119
  18. data/lib/cfndk/config_file_loadable.rb +13 -0
  19. data/lib/cfndk/credential_provider_chain.rb +12 -42
  20. data/lib/cfndk/credential_resolvable.rb +10 -0
  21. data/lib/cfndk/diff.rb +38 -0
  22. data/lib/cfndk/global_config.rb +46 -0
  23. data/lib/cfndk/key_pair.rb +66 -14
  24. data/lib/cfndk/key_pair_command.rb +60 -0
  25. data/lib/cfndk/key_pairs.rb +22 -5
  26. data/lib/cfndk/logger.rb +12 -3
  27. data/lib/cfndk/stack.rb +427 -126
  28. data/lib/cfndk/stack_command.rb +128 -0
  29. data/lib/cfndk/stacks.rb +48 -22
  30. data/lib/cfndk/subcommand_help_returnable.rb +16 -0
  31. data/lib/cfndk/template_packager.rb +210 -0
  32. data/lib/cfndk/uuid.rb +10 -0
  33. data/lib/cfndk/version.rb +1 -1
  34. data/skel/cfndk.yml +4 -0
  35. data/spec/.gitignore +1 -0
  36. data/spec/cfndk_change_set_create_spec.rb +436 -0
  37. data/spec/cfndk_change_set_destroy_spec.rb +160 -0
  38. data/spec/cfndk_change_set_execute_spec.rb +179 -0
  39. data/spec/cfndk_change_set_report_spec.rb +107 -0
  40. data/spec/cfndk_change_set_spec.rb +37 -0
  41. data/spec/cfndk_create_spec.rb +504 -0
  42. data/spec/cfndk_destroy_spec.rb +148 -0
  43. data/spec/cfndk_keypiar_spec.rb +397 -0
  44. data/spec/cfndk_report_spec.rb +164 -0
  45. data/spec/cfndk_spec.rb +103 -0
  46. data/spec/cfndk_stack_create_spec.rb +814 -0
  47. data/spec/cfndk_stack_destroy_spec.rb +225 -0
  48. data/spec/cfndk_stack_report_spec.rb +181 -0
  49. data/spec/cfndk_stack_spec.rb +133 -0
  50. data/spec/cfndk_stack_update_spec.rb +553 -0
  51. data/spec/fixtures/big_vpc.yaml +533 -0
  52. data/spec/fixtures/empty_resource.yaml +2 -0
  53. data/spec/fixtures/iam.json +8 -0
  54. data/spec/fixtures/iam.yaml +38 -0
  55. data/spec/fixtures/iam_different.json +8 -0
  56. data/spec/fixtures/invalid_vpc.yaml +21 -0
  57. data/spec/fixtures/lambda_function/index.js +4 -0
  58. data/spec/fixtures/lambda_function/lambda_function.json +4 -0
  59. data/spec/fixtures/lambda_function/lambda_function.yaml +28 -0
  60. data/spec/fixtures/nested_stack.json +35 -0
  61. data/spec/fixtures/nested_stack.yaml +20 -0
  62. data/spec/fixtures/serverless_function/index.js +4 -0
  63. data/spec/fixtures/serverless_function/serverless_function.json +4 -0
  64. data/spec/fixtures/serverless_function/serverless_function.yaml +21 -0
  65. data/spec/fixtures/sg.json +8 -0
  66. data/spec/fixtures/sg.yaml +27 -0
  67. data/spec/fixtures/sg_different.yaml +22 -0
  68. data/spec/fixtures/stack.json +8 -0
  69. data/spec/fixtures/stack.template.json +39 -0
  70. data/spec/fixtures/stack.yaml +22 -0
  71. data/spec/fixtures/vpc.json +8 -0
  72. data/spec/fixtures/vpc.template.json +40 -0
  73. data/spec/fixtures/vpc.yaml +21 -0
  74. data/spec/fixtures/vpc_different.yaml +21 -0
  75. data/spec/spec_helper.rb +14 -0
  76. data/spec/support/aruba.rb +6 -0
  77. data/vagrant/Vagrantfile +89 -0
  78. metadata +259 -31
@@ -1,148 +1,352 @@
1
1
  module CFnDK
2
2
  class Stack
3
- attr_reader :template_file, :parameter_input, :capabilities, :depends, :timeout_in_minutes
4
- def initialize(name, data, option, credentials)
3
+ attr_reader :template_file, :parameter_input, :capabilities, :depends, :timeout_in_minutes, :region, :role_arn, :package, :enabled, :pre_command, :post_command
4
+ def initialize(name, data, option, global_config, credentials)
5
+ @global_config = global_config
5
6
  @name = name
6
7
  @template_file = data['template_file'] || ''
7
8
  @parameter_input = data['parameter_input'] || ''
8
9
  @capabilities = data['capabilities'] || []
9
10
  @depends = data['depends'] || []
10
- @timeout_in_minutes = data['timeout_in_minutes'] || 1
11
+ @region = data['region'] || @global_config.region
12
+ @role_arn = @global_config.role_arn
13
+ @package = data['package'] || @global_config.package
14
+ @pre_command = data['pre_command'] || nil
15
+ @post_command = data['post_command'] || nil
16
+ @enabled = true
17
+ @enabled = false if data['enabled'] === false
18
+ @timeout_in_minutes = data['timeout_in_minutes'] || @global_config.timeout_in_minutes
11
19
  @override_parameters = data['parameters'] || {}
12
20
  @option = option
13
- @client = Aws::CloudFormation::Client.new(credentials: credentials)
14
- @logger = CFnDK::Logger.new(option)
21
+ @client = Aws::CloudFormation::Client.new(credentials: credentials, region: @region)
22
+ @s3_client = Aws::S3::Client.new(credentials: credentials, region: @region)
23
+ @sts_client = Aws::STS::Client.new(credentials: credentials, region: @region)
24
+ @tp = CFnDK::TemplatePackager.new(@template_file, @region, @package, @global_config, @s3_client, @sts_client)
15
25
  end
16
26
 
17
27
  def create
18
28
  return if @option[:stack_names].instance_of?(Array) && !@option[:stack_names].include?(@name)
19
- @logger.info(('creating stack: ' + @name).color(:green))
20
- @logger.debug('Name :' + name)
21
- @logger.debug('Parametres :' + parameters.inspect)
22
- @logger.debug('Capabilities:' + capabilities.inspect)
23
- @logger.debug('Timeout :' + timeout_in_minutes.to_s)
24
- @client.create_stack(
29
+ return unless @enabled
30
+ CFnDK.logger.info(('creating stack: ' + name).color(:green))
31
+ CFnDK.logger.debug('Name :' + name)
32
+ CFnDK.logger.debug('Parametres :' + parameters.inspect)
33
+ CFnDK.logger.debug('Capabilities:' + capabilities.inspect)
34
+ CFnDK.logger.debug('Timeout :' + timeout_in_minutes.to_s)
35
+ CFnDK.logger.debug('Region :' + region)
36
+ tags = [
37
+ {
38
+ key: 'origina_name',
39
+ value: @name,
40
+ },
41
+ ]
42
+ tags.push(
43
+ key: 'UUID',
44
+ value: @option[:uuid]
45
+ ) if @option[:uuid]
46
+ hash = {
25
47
  stack_name: name,
26
- template_body: template_body,
27
48
  parameters: parameters,
28
49
  capabilities: capabilities,
29
- timeout_in_minutes: timeout_in_minutes
50
+ timeout_in_minutes: timeout_in_minutes,
51
+ tags: tags,
52
+ }
53
+ hash[:role_arn] = @role_arn if @role_arn
54
+
55
+ if @tp.large_template?
56
+ hash[:template_url] = @tp.upload_template_file()
57
+ else
58
+ hash[:template_body] = @tp.template_body()
59
+ end
60
+ @client.create_stack(
61
+ hash
30
62
  )
31
63
  end
32
64
 
33
65
  def wait_until_create
34
66
  return if @option[:stack_names].instance_of?(Array) && !@option[:stack_names].include?(@name)
67
+ return unless @enabled
68
+ CFnDK.logger.info(('waiting create stack: ' + name).color(:green))
35
69
  begin
36
70
  @client.wait_until(
37
71
  :stack_create_complete,
38
72
  stack_name: name
39
- )
40
- @logger.info(('created stack: ' + @name).color(:green))
73
+ ) do |w|
74
+ w.max_attempts = 360
75
+ w.delay = 10
76
+ end
77
+ CFnDK.logger.info(('created stack: ' + name).color(:green))
41
78
  rescue Aws::Waiters::Errors::FailureStateError => ex
42
- @logger.error ex.message
43
- report_event
79
+ CFnDK.logger.error "#{ex.class}: #{ex.message}".color(:red)
80
+ @option[:type] = %w(tag output parameter resource event)
81
+ report
44
82
  raise ex
45
83
  end
46
84
  end
47
85
 
48
86
  def update
49
87
  return false if @option[:stack_names].instance_of?(Array) && !@option[:stack_names].include?(@name)
50
- @logger.info(('updating stack: ' + @name).color(:green))
51
- @logger.debug('Name :' + name)
52
- @logger.debug('Parametres :' + parameters.inspect)
53
- @logger.debug('Capabilities:' + capabilities.inspect)
54
- @logger.debug('Timeout :' + timeout_in_minutes.to_s)
88
+ return unless @enabled
89
+ CFnDK.logger.info(('updating stack: ' + name).color(:green))
90
+ CFnDK.logger.debug('Name :' + name)
91
+ CFnDK.logger.debug('Parametres :' + parameters.inspect)
92
+ CFnDK.logger.debug('Capabilities:' + capabilities.inspect)
93
+ CFnDK.logger.debug('Timeout :' + timeout_in_minutes.to_s)
94
+ CFnDK.logger.debug('Region :' + region)
55
95
  begin
56
- @client.update_stack(
96
+ hash = {
57
97
  stack_name: name,
58
- template_body: template_body,
59
98
  parameters: parameters,
60
- capabilities: capabilities
99
+ capabilities: capabilities,
100
+ }
101
+ hash[:role_arn] = @role_arn if @role_arn
102
+ if @tp.large_template?
103
+ hash[:template_url] = @tp.upload_template_file()
104
+ else
105
+ hash[:template_body] = @tp.template_body()
106
+ end
107
+ @client.update_stack(
108
+ hash
61
109
  )
62
110
  true
63
111
  rescue Aws::CloudFormation::Errors::ValidationError => ex
64
- @logger.error ex.message.color(:red)
65
- false
112
+ case ex.message
113
+ when 'No updates are to be performed.'
114
+ CFnDK.logger.warn "#{ex.message}: #{name}".color(:red)
115
+ false
116
+ else
117
+ raise ex
118
+ end
66
119
  end
67
120
  end
68
121
 
69
122
  def wait_until_update
70
123
  return if @option[:stack_names].instance_of?(Array) && !@option[:stack_names].include?(@name)
124
+ return unless @enabled
125
+ CFnDK.logger.info(('waiting update stack: ' + name).color(:green))
71
126
  @client.wait_until(
72
127
  :stack_update_complete,
73
128
  stack_name: name
74
- )
75
- @logger.info(('updated stack: ' + @name).color(:green))
129
+ ) do |w|
130
+ w.max_attempts = 360
131
+ w.delay = 10
132
+ end
133
+ CFnDK.logger.info(('updated stack: ' + name).color(:green))
76
134
  end
77
135
 
78
136
  def destroy
79
137
  return if @option[:stack_names].instance_of?(Array) && !@option[:stack_names].include?(@name)
80
- @logger.info(('deleting stack: ' + @name).color(:green))
81
- @logger.debug('Name :' + name)
82
- @client.delete_stack(
83
- stack_name: name
84
- )
138
+ return unless @enabled
139
+ if exits?
140
+ CFnDK.logger.info(('deleting stack: ' + name).color(:green))
141
+ CFnDK.logger.debug('Name :' + name)
142
+ CFnDK.logger.debug('Region :' + region)
143
+ hash = {
144
+ stack_name: name,
145
+ }
146
+ hash[:role_arn] = @role_arn if @role_arn
147
+ @client.delete_stack(
148
+ hash
149
+ )
150
+ else
151
+ CFnDK.logger.info(('do not delete stack: ' + name).color(:red))
152
+ end
85
153
  end
86
154
 
87
155
  def wait_until_destroy
88
156
  return if @option[:stack_names].instance_of?(Array) && !@option[:stack_names].include?(@name)
157
+ return unless @enabled
158
+ return unless exits?
159
+ CFnDK.logger.info(('waiting delete stack: ' + name).color(:green))
89
160
  @client.wait_until(
90
161
  :stack_delete_complete,
91
162
  stack_name: name
92
- )
93
- @logger.info(('deleted stack: ' + @name).color(:green))
163
+ ) do |w|
164
+ w.max_attempts = 360
165
+ w.delay = 10
166
+ end
167
+ CFnDK.logger.info(('deleted stack: ' + name).color(:green))
94
168
  end
95
169
 
96
170
  def create_change_set
97
- return if @option[:stack_names].instance_of?(Array) && !@option[:stack_names].include?(@name)
98
- @logger.info(('creating change set: ' + @name).color(:green))
99
- @logger.debug('Name :' + name)
100
- @logger.debug('Parametres :' + parameters.inspect)
101
- @logger.debug('Capabilities:' + capabilities.inspect)
102
- @client.create_change_set(
171
+ return nil if @option[:stack_names].instance_of?(Array) && !@option[:stack_names].include?(@name)
172
+ return unless @enabled
173
+ CFnDK.logger.info(('creating change set: ' + change_set_name).color(:green))
174
+ CFnDK.logger.debug('Parametres :' + parameters.inspect)
175
+ CFnDK.logger.debug('Capabilities:' + capabilities.inspect)
176
+ CFnDK.logger.debug('Region :' + region)
177
+ tags = [
178
+ {
179
+ key: 'origina_name',
180
+ value: @name,
181
+ },
182
+ ]
183
+ tags.push(
184
+ key: 'UUID',
185
+ value: @option[:uuid]
186
+ ) if @option[:uuid]
187
+ tags.push(
188
+ key: 'CHANGE_SET_UUID',
189
+ value: @option[:change_set_uuid]
190
+ ) if @option[:change_set_uuid]
191
+ hash = {
103
192
  stack_name: name,
104
- template_body: template_body,
105
193
  parameters: parameters,
106
194
  capabilities: capabilities,
107
- change_set_name: name
195
+ change_set_name: change_set_name,
196
+ change_set_type: exits? ? 'UPDATE' : 'CREATE',
197
+ tags: tags,
198
+ }
199
+ hash[:role_arn] = @role_arn if @role_arn
200
+ if @tp.large_template?
201
+ hash[:template_url] = @tp.upload_template_file()
202
+ else
203
+ hash[:template_body] = @tp.template_body()
204
+ end
205
+ @client.create_change_set(
206
+ hash
108
207
  )
208
+ @name
209
+ rescue Aws::CloudFormation::Errors::ValidationError => ex
210
+ if review_in_progress?
211
+ CFnDK.logger.warn("failed create change set because the stack on REVIEW_IN_PROGRESS already exist : #{change_set_name}".color(:orange))
212
+ nil
213
+ else
214
+ CFnDK.logger.error("failed create change set: #{change_set_name}".color(:red))
215
+ raise ex
216
+ end
109
217
  end
110
218
 
111
219
  def wait_until_create_change_set
112
220
  return if @option[:stack_names].instance_of?(Array) && !@option[:stack_names].include?(@name)
113
- begin
114
- @client.wait_until(
115
- :change_set_create_complete,
221
+ return unless @enabled
222
+ return unless exits?
223
+ CFnDK.logger.info(('waiting create change set: ' + change_set_name).color(:green))
224
+ @client.wait_until(
225
+ :change_set_create_complete,
226
+ stack_name: name,
227
+ change_set_name: change_set_name
228
+ ) do |w|
229
+ w.max_attempts = 360
230
+ w.delay = 10
231
+ end
232
+ CFnDK.logger.info("created change set: #{change_set_name}".color(:green))
233
+ rescue Aws::Waiters::Errors::FailureStateError => ex
234
+ case ex.message
235
+ when 'stopped waiting, encountered a failure state'
236
+ unless available_change_set?
237
+ delete_change_set
238
+ CFnDK.logger.warn("failed create change set because this change set is UNAVAILABLE: #{change_set_name}".color(:orange))
239
+ return
240
+ end
241
+ end
242
+ raise ex
243
+ end
244
+
245
+ def execute_change_set
246
+ return nil if @option[:stack_names].instance_of?(Array) && !@option[:stack_names].include?(@name)
247
+ return unless @enabled
248
+ if available_change_set?
249
+ CFnDK.logger.info(('executing change set: ' + change_set_name).color(:green))
250
+ @client.execute_change_set(
116
251
  stack_name: name,
117
- change_set_name: name
118
- )
119
- @logger.info(('created chnage set: ' + name).color(:green))
120
- rescue Aws::Waiters::Errors::FailureStateError => ex
121
- resp = @client.describe_change_set(
122
- change_set_name: name,
123
- stack_name: name
252
+ change_set_name: change_set_name
124
253
  )
125
- if resp.status_reason != "The submitted information didn't contain changes. Submit different information to create a change set."
126
- @logger.error ex.message.color(:red)
127
- raise ex
128
- else
129
- @logger.error(('failed create change set: ' + name).color(:red))
130
- @logger.error resp.status_reason
131
- @client.delete_change_set(
132
- change_set_name: name,
133
- stack_name: name
134
- )
135
- @logger.info(('deleted change set: ' + name).color(:red))
254
+ CFnDK.logger.info(('execute change set: ' + change_set_name).color(:green))
255
+ @name
256
+ else
257
+ CFnDK.logger.warn("failed execute change set because this change set is not AVAILABLE: #{change_set_name}".color(:orange))
258
+ nil
259
+ end
260
+ end
261
+
262
+ def delete_change_set
263
+ return if @option[:stack_names].instance_of?(Array) && !@option[:stack_names].include?(@name)
264
+ return unless @enabled
265
+ CFnDK.logger.info(('deleting change set: ' + change_set_name).color(:green))
266
+ @client.delete_change_set(
267
+ stack_name: name,
268
+ change_set_name: change_set_name
269
+ )
270
+ CFnDK.logger.info(('deleted change set: ' + change_set_name).color(:green))
271
+ end
272
+
273
+ def report_change_set
274
+ return if @option[:stack_names].instance_of?(Array) && !@option[:stack_names].include?(@name)
275
+ return unless @enabled
276
+ CFnDK.logger.info('*****************************************************'.color(:green))
277
+ CFnDK.logger.info(('change set: ' + change_set_name).color(:green))
278
+ CFnDK.logger.info('*****************************************************'.color(:green))
279
+ CFnDK.logger.info('')
280
+ resp = @client.describe_change_set(
281
+ change_set_name: change_set_name,
282
+ stack_name: name
283
+ )
284
+ CFnDK.logger.info('Execution Status: '.color(:green) + colored_status(resp.execution_status))
285
+ CFnDK.logger.info('Status: '.color(:green) + colored_status(resp.status))
286
+ CFnDK.logger.info('Reason: '.color(:green) + resp.status_reason) if resp.status_reason
287
+ if @option[:types].instance_of?(Array) && @option[:types].include?('tag')
288
+ CFnDK.logger.info('Tags:'.color(:green))
289
+ tags_rows = resp.tags.map do |item|
290
+ [
291
+ item.key,
292
+ item.value,
293
+ ]
294
+ end
295
+ unless tags_rows.empty?
296
+ table = Terminal::Table.new headings: %w(Key Value), rows: tags_rows
297
+ CFnDK.logger.info table
298
+ end
299
+ end
300
+ if @option[:types].instance_of?(Array) && @option[:types].include?('parameter')
301
+ CFnDK.logger.info('Parameters:'.color(:green))
302
+ parameter_rows = resp.parameters.map do |item|
303
+ [
304
+ item.parameter_key,
305
+ item.parameter_value,
306
+ item.use_previous_value,
307
+ item.resolved_value,
308
+ ]
309
+ end
310
+ unless parameter_rows.empty?
311
+ table = Terminal::Table.new headings: ['Key', 'Value', 'Use Previous Value', 'Resolved Value'], rows: parameter_rows
312
+ CFnDK.logger.info table
313
+ end
314
+ end
315
+ if @option[:types].instance_of?(Array) && @option[:types].include?('changes')
316
+ CFnDK.logger.info('Changes:'.color(:green))
317
+ changes_rows = resp.changes.map do |item|
318
+ [
319
+ item.resource_change.action,
320
+ item.resource_change.logical_resource_id,
321
+ item.resource_change.physical_resource_id,
322
+ item.resource_change.resource_type,
323
+ item.resource_change.replacement,
324
+ ]
325
+ end
326
+ unless changes_rows.empty?
327
+ table = Terminal::Table.new headings: %w(Action Logical Physical Type Replacement), rows: changes_rows
328
+ CFnDK.logger.info table
136
329
  end
137
330
  end
331
+ rescue Aws::CloudFormation::Errors::ValidationError => ex
332
+ CFnDK.logger.warn "#{ex.class}: #{ex.message}".color(:red)
333
+ rescue Aws::CloudFormation::Errors::ChangeSetNotFound => ex
334
+ CFnDK.logger.warn "#{ex.class}: #{ex.message}".color(:red)
138
335
  end
139
336
 
140
337
  def validate
141
338
  return if @option[:stack_names].instance_of?(Array) && !@option[:stack_names].include?(@name)
142
- @logger.info(('validate stack: ' + @name).color(:green))
143
- @logger.debug('Name :' + name)
339
+ return unless @enabled
340
+ CFnDK.logger.info(('validate stack: ' + name).color(:green))
341
+ CFnDK.logger.debug('Name :' + @name)
342
+ hash = {}
343
+ if @tp.large_template?
344
+ hash[:template_url] = @tp.upload_template_file()
345
+ else
346
+ hash[:template_body] = @tp.template_body()
347
+ end
144
348
  @client.validate_template(
145
- template_body: template_body
349
+ hash
146
350
  )
147
351
  end
148
352
 
@@ -155,71 +359,140 @@ module CFnDK
155
359
  false
156
360
  end
157
361
 
158
- def report_stack
159
- return if @option[:stack_names].instance_of?(Array) && !@option[:stack_names].include?(@name)
160
- @logger.info(('stack: ' + @name).color(:green))
161
- @logger.debug('Name :' + name)
162
- begin
163
- rows = @client.describe_stacks(
164
- stack_name: name
165
- ).stacks.map do |item|
166
- [
167
- item.stack_name,
168
- item.creation_time,
169
- item.deletion_time,
170
- colored_status(item.stack_status),
171
- item.stack_status_reason]
172
- end
173
- table = Terminal::Table.new headings: %w(Name Creation Deletion Status Reason), rows: rows
174
- @logger.info table
175
- rescue Aws::CloudFormation::Errors::ValidationError => ex
176
- @logger.warn ex.message
177
- end
362
+ def created?
363
+ resp = @client.describe_stacks(
364
+ stack_name: name
365
+ )
366
+ return false if resp.stacks[0].stack_status == 'REVIEW_IN_PROGRESS'
367
+ true
368
+ rescue Aws::CloudFormation::Errors::ValidationError
369
+ false
178
370
  end
179
371
 
180
- def report_event
181
- return if @option[:stack_names].instance_of?(Array) && !@option[:stack_names].include?(@name)
182
- @logger.info(('stack: ' + @name).color(:green))
183
- @logger.debug('Name :' + name)
184
- begin
185
- rows = @client.describe_stack_events(
186
- stack_name: name
187
- ).stack_events.map do |item|
188
- [
189
- item.resource_type,
190
- item.timestamp,
191
- colored_status(item.resource_status),
192
- item.resource_status_reason]
193
- end
194
- table = Terminal::Table.new headings: %w(Type Time Status Reason), rows: rows
195
- @logger.info table
196
- rescue Aws::CloudFormation::Errors::ValidationError => ex
197
- @logger.warn ex.message
198
- end
372
+ def review_in_progress?
373
+ resp = @client.describe_stacks(
374
+ stack_name: name
375
+ )
376
+ return true if resp.stacks[0].stack_status == 'REVIEW_IN_PROGRESS'
377
+ false
378
+ rescue Aws::CloudFormation::Errors::ValidationError
379
+ false
380
+ end
381
+
382
+ def available_change_set?
383
+ resp = @client.describe_change_set(
384
+ change_set_name: change_set_name,
385
+ stack_name: name
386
+ )
387
+ return true if resp.execution_status == 'AVAILABLE'
388
+ false
389
+ rescue Aws::CloudFormation::Errors::ChangeSetNotFound
390
+ false
199
391
  end
200
392
 
201
- def report_stack_resource
393
+ def report
202
394
  return if @option[:stack_names].instance_of?(Array) && !@option[:stack_names].include?(@name)
203
- @logger.info(('stack: ' + @name).color(:green))
204
- @logger.debug('Name :' + name)
395
+ return unless @enabled
396
+ CFnDK.logger.info('*****************************************************'.color(:green))
397
+ CFnDK.logger.info(('stack: ' + name).color(:green))
398
+ CFnDK.logger.info('*****************************************************'.color(:green))
399
+ CFnDK.logger.info('')
205
400
  begin
206
- rows = @client.describe_stack_resources(
401
+ resp = @client.describe_stacks(
207
402
  stack_name: name
208
- ).stack_resources.map do |item|
209
- [
210
- item.logical_resource_id,
211
- item.physical_resource_id,
212
- item.resource_type,
213
- item.timestamp,
214
- colored_status(item.resource_status),
215
- item.resource_status_reason,
216
- item.description,
217
- ]
403
+ ).stacks[0]
404
+ CFnDK.logger.info('Status: '.color(:green) + colored_status(resp.stack_status))
405
+ CFnDK.logger.info('Reason: '.color(:green) + resp.stack_status_reason) if resp.stack_status_reason
406
+ if @option[:types].instance_of?(Array) && @option[:types].include?('tag')
407
+ CFnDK.logger.info('Tags:'.color(:green))
408
+ tags_rows = resp.tags.map do |item|
409
+ [
410
+ item.key,
411
+ item.value,
412
+ ]
413
+ end
414
+ unless tags_rows.empty?
415
+ table = Terminal::Table.new headings: %w(Key Value), rows: tags_rows
416
+ CFnDK.logger.info table
417
+ end
418
+ end
419
+ if @option[:types].instance_of?(Array) && @option[:types].include?('parameter')
420
+ CFnDK.logger.info('Parameters:'.color(:green))
421
+ parameter_rows = resp.parameters.map do |item|
422
+ [
423
+ item.parameter_key,
424
+ item.parameter_value,
425
+ item.use_previous_value,
426
+ item.resolved_value,
427
+ ]
428
+ end
429
+ unless parameter_rows.empty?
430
+ table = Terminal::Table.new headings: ['Key', 'Value', 'Use Previous Value', 'Resolved Value'], rows: parameter_rows
431
+ CFnDK.logger.info table
432
+ end
433
+ end
434
+ if @option[:types].instance_of?(Array) && @option[:types].include?('output')
435
+ CFnDK.logger.info('Outputs:'.color(:green))
436
+ output_rows = resp.outputs.map do |item|
437
+ [
438
+ item.output_key,
439
+ item.output_value,
440
+ item.export_name,
441
+ item.description,
442
+ ]
443
+ end
444
+ unless output_rows.empty?
445
+ table = Terminal::Table.new headings: ['Key', 'Value', 'Export Name', 'Description'], rows: output_rows
446
+ CFnDK.logger.info table
447
+ end
218
448
  end
219
- table = Terminal::Table.new headings: %w(L-name P-name Type Timestamp Status Reason Desc), rows: rows
220
- @logger.info table
221
449
  rescue Aws::CloudFormation::Errors::ValidationError => ex
222
- @logger.warn ex.message
450
+ CFnDK.logger.warn "#{ex.class}: #{ex.message}".color(:red)
451
+ end
452
+ if @option[:types].instance_of?(Array) && @option[:types].include?('resource')
453
+ begin
454
+ CFnDK.logger.info('Resources:'.color(:green))
455
+ rows = @client.describe_stack_resources(
456
+ stack_name: name
457
+ ).stack_resources.map do |item|
458
+ [
459
+ item.logical_resource_id,
460
+ item.physical_resource_id,
461
+ item.resource_type,
462
+ item.timestamp,
463
+ colored_status(item.resource_status),
464
+ item.resource_status_reason,
465
+ item.description,
466
+ ]
467
+ end
468
+ unless rows.empty?
469
+ table = Terminal::Table.new headings: %w(Logical Physical Type Timestamp Status Reason Desc), rows: rows
470
+ CFnDK.logger.info table
471
+ end
472
+ rescue Aws::CloudFormation::Errors::ValidationError => ex
473
+ CFnDK.logger.warn "#{ex.class}: #{ex.message}".color(:red)
474
+ end
475
+ end
476
+ if @option[:types].instance_of?(Array) && @option[:types].include?('event')
477
+ CFnDK.logger.info('Events:'.color(:green))
478
+ begin
479
+ rows = @client.describe_stack_events(
480
+ stack_name: name
481
+ ).stack_events.map do |item|
482
+ [
483
+ item.resource_type,
484
+ item.timestamp,
485
+ colored_status(item.resource_status),
486
+ item.resource_status_reason,
487
+ ]
488
+ end
489
+ unless rows.empty?
490
+ table = Terminal::Table.new headings: %w(Type Time Status Reason), rows: rows
491
+ CFnDK.logger.info table
492
+ end
493
+ rescue Aws::CloudFormation::Errors::ValidationError => ex
494
+ CFnDK.logger.warn "#{ex.class}: #{ex.message}".color(:red)
495
+ end
223
496
  end
224
497
  end
225
498
 
@@ -227,8 +500,8 @@ module CFnDK
227
500
  [@name, @option[:uuid]].compact.join('-')
228
501
  end
229
502
 
230
- def template_body
231
- File.open(@template_file, 'r').read
503
+ def change_set_name
504
+ [@name, @option[:change_set_uuid]].compact.join('-')
232
505
  end
233
506
 
234
507
  def parameters
@@ -242,6 +515,34 @@ module CFnDK
242
515
  end.compact
243
516
  end
244
517
 
518
+ def pre_command_execute
519
+ return if @option[:stack_names].instance_of?(Array) && !@option[:stack_names].include?(@name)
520
+ return unless @enabled
521
+ if @pre_command
522
+ CFnDK.logger.info(('execute pre command: ' + @pre_command).color(:green))
523
+ IO.popen(@pre_command, :err => [:child, :out]) do |io|
524
+ io.each_line do |line|
525
+ CFnDK.logger.info((line).color(:green))
526
+ end
527
+ end
528
+ raise 'pre command is error. status: ' + $?.exitstatus.to_s + ' command: ' + @pre_command if $?.exitstatus != 0
529
+ end
530
+ end
531
+
532
+ def post_command_execute
533
+ return if @option[:stack_names].instance_of?(Array) && !@option[:stack_names].include?(@name)
534
+ return unless @enabled
535
+ if @post_command
536
+ CFnDK.logger.info(('execute post command: ' + @post_command).color(:green))
537
+ IO.popen(@post_command, :err => [:child, :out]) do |io|
538
+ io.each_line do |line|
539
+ CFnDK.logger.info((line).color(:green))
540
+ end
541
+ end
542
+ raise 'post command is error. status: ' + $?.exitstatus.to_s + ' command: ' + @post_command if $?.exitstatus != 0
543
+ end
544
+ end
545
+
245
546
  private
246
547
 
247
548
  def colored_status(str)