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