cfndk 0.0.7 → 0.1.0

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.
@@ -6,38 +6,55 @@ module CFnDK
6
6
  @key_file = nil
7
7
  @key_file = data['key_file'] || nil if data
8
8
  @option = option
9
- @logger = CFnDK::Logger.new(option)
10
9
  @client = Aws::EC2::Client.new(credentials: credentials)
11
10
  end
12
11
 
13
12
  def create
14
- @logger.info(('creating keypair: ' + name).color(:green))
13
+ CFnDK.logger.info(('creating keypair: ' + name).color(:green))
15
14
  key_pair = @client.create_key_pair(
16
15
  key_name: name
17
16
  )
18
- @logger.info(('created keypair: ' + name).color(:green))
17
+ CFnDK.logger.info(('created keypair: ' + name).color(:green))
19
18
 
20
19
  create_key_file(key_pair)
21
20
  end
22
21
 
23
22
  def destroy
24
- @logger.info(('deleting keypair: ' + name).color(:green))
25
- @client.delete_key_pair(
26
- key_name: name
27
- )
28
- @logger.info(('deleted keypair: ' + name).color(:green))
23
+ if exists?
24
+ CFnDK.logger.info(('deleting keypair: ' + name).color(:green))
25
+ @client.delete_key_pair(
26
+ key_name: name
27
+ )
28
+ CFnDK.logger.info(('deleted keypair: ' + name).color(:green))
29
+ else
30
+ CFnDK.logger.info(('do not delete keypair: ' + name).color(:red))
31
+ end
32
+ end
33
+
34
+ def exists?
35
+ !@client.describe_key_pairs(
36
+ key_names: [
37
+ name,
38
+ ]
39
+ ).key_pairs.empty?
40
+ rescue Aws::EC2::Errors::InvalidKeyPairNotFound
41
+ false
29
42
  end
30
43
 
31
44
  def name
32
45
  [@name, @option[:uuid]].compact.join('-')
33
46
  end
34
47
 
48
+ def original_name
49
+ @name
50
+ end
51
+
35
52
  private
36
53
 
37
54
  def create_key_file(key_pair)
38
55
  return unless @key_file
39
56
  key_file = CFnDK::ErbString.new(@key_file, @option).value
40
- @logger.info(('create key file: ' + key_file).color(:green))
57
+ CFnDK.logger.info(('create key file: ' + key_file).color(:green))
41
58
  File.write(key_file, key_pair.key_material)
42
59
  end
43
60
  end
@@ -7,13 +7,17 @@ module CFnDK
7
7
  end
8
8
 
9
9
  def create
10
- return if @option[:stack_names].instance_of?(Array)
11
- @keypairs.each_value(&:create)
10
+ @keypairs.each_value do |keypair|
11
+ next if @option[:keypair_names].instance_of?(Array) && !@option[:keypair_names].include?(keypair.original_name)
12
+ keypair.create
13
+ end
12
14
  end
13
15
 
14
16
  def destroy
15
- return if @option[:stack_names].instance_of?(Array)
16
- @keypairs.each_value(&:destroy)
17
+ @keypairs.each_value do |keypair|
18
+ next if @option[:keypair_names].instance_of?(Array) && !@option[:keypair_names].include?(keypair.original_name)
19
+ keypair.destroy
20
+ end
17
21
  end
18
22
 
19
23
  private
@@ -1,8 +1,17 @@
1
1
  module CFnDK
2
- class Logger < Logger
3
- def initialize(option)
2
+ def self.logger
3
+ @logger = CFnDKLogger.new({}) if @logger.nil?
4
+ @logger
5
+ end
6
+
7
+ def self.logger=(logger)
8
+ @logger = logger
9
+ end
10
+
11
+ class CFnDKLogger < Logger
12
+ def initialize(options)
4
13
  super(STDOUT)
5
- self.level = Logger::INFO unless option[:v]
14
+ self.level = Logger::INFO unless options[:v]
6
15
  self.formatter = proc { |severity, datetime, progname, message|
7
16
  message.to_s.split(/\n/).map do |line|
8
17
  "#{datetime} #{severity} #{line}\n"
@@ -11,16 +11,15 @@ module CFnDK
11
11
  @override_parameters = data['parameters'] || {}
12
12
  @option = option
13
13
  @client = Aws::CloudFormation::Client.new(credentials: credentials)
14
- @logger = CFnDK::Logger.new(option)
15
14
  end
16
15
 
17
16
  def create
18
17
  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)
18
+ CFnDK.logger.info(('creating stack: ' + name).color(:green))
19
+ CFnDK.logger.debug('Name :' + name)
20
+ CFnDK.logger.debug('Parametres :' + parameters.inspect)
21
+ CFnDK.logger.debug('Capabilities:' + capabilities.inspect)
22
+ CFnDK.logger.debug('Timeout :' + timeout_in_minutes.to_s)
24
23
  @client.create_stack(
25
24
  stack_name: name,
26
25
  template_body: template_body,
@@ -37,9 +36,9 @@ module CFnDK
37
36
  :stack_create_complete,
38
37
  stack_name: name
39
38
  )
40
- @logger.info(('created stack: ' + @name).color(:green))
39
+ CFnDK.logger.info(('created stack: ' + name).color(:green))
41
40
  rescue Aws::Waiters::Errors::FailureStateError => ex
42
- @logger.error ex.message
41
+ CFnDK.logger.error ex.message
43
42
  report_event
44
43
  raise ex
45
44
  end
@@ -47,11 +46,11 @@ module CFnDK
47
46
 
48
47
  def update
49
48
  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)
49
+ CFnDK.logger.info(('updating stack: ' + name).color(:green))
50
+ CFnDK.logger.debug('Name :' + name)
51
+ CFnDK.logger.debug('Parametres :' + parameters.inspect)
52
+ CFnDK.logger.debug('Capabilities:' + capabilities.inspect)
53
+ CFnDK.logger.debug('Timeout :' + timeout_in_minutes.to_s)
55
54
  begin
56
55
  @client.update_stack(
57
56
  stack_name: name,
@@ -61,8 +60,13 @@ module CFnDK
61
60
  )
62
61
  true
63
62
  rescue Aws::CloudFormation::Errors::ValidationError => ex
64
- @logger.error ex.message.color(:red)
65
- false
63
+ case ex.message
64
+ when 'No updates are to be performed.'
65
+ CFnDK.logger.warn "#{ex.message}: #{name}".color(:red)
66
+ false
67
+ else
68
+ raise ex
69
+ end
66
70
  end
67
71
  end
68
72
 
@@ -72,33 +76,38 @@ module CFnDK
72
76
  :stack_update_complete,
73
77
  stack_name: name
74
78
  )
75
- @logger.info(('updated stack: ' + @name).color(:green))
79
+ CFnDK.logger.info(('updated stack: ' + name).color(:green))
76
80
  end
77
81
 
78
82
  def destroy
79
83
  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
- )
84
+ if exits?
85
+ CFnDK.logger.info(('deleting stack: ' + name).color(:green))
86
+ CFnDK.logger.debug('Name :' + name)
87
+ @client.delete_stack(
88
+ stack_name: name
89
+ )
90
+ else
91
+ CFnDK.logger.info(('do not delete stack: ' + name).color(:red))
92
+ end
85
93
  end
86
94
 
87
95
  def wait_until_destroy
88
96
  return if @option[:stack_names].instance_of?(Array) && !@option[:stack_names].include?(@name)
97
+ return unless exits?
89
98
  @client.wait_until(
90
99
  :stack_delete_complete,
91
100
  stack_name: name
92
101
  )
93
- @logger.info(('deleted stack: ' + @name).color(:green))
102
+ CFnDK.logger.info(('deleted stack: ' + name).color(:green))
94
103
  end
95
104
 
96
105
  def create_change_set
97
106
  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)
107
+ CFnDK.logger.info(('creating change set: ' + name).color(:green))
108
+ CFnDK.logger.debug('Name :' + name)
109
+ CFnDK.logger.debug('Parametres :' + parameters.inspect)
110
+ CFnDK.logger.debug('Capabilities:' + capabilities.inspect)
102
111
  @client.create_change_set(
103
112
  stack_name: name,
104
113
  template_body: template_body,
@@ -116,31 +125,31 @@ module CFnDK
116
125
  stack_name: name,
117
126
  change_set_name: name
118
127
  )
119
- @logger.info(('created chnage set: ' + name).color(:green))
128
+ CFnDK.logger.info(('created chnage set: ' + name).color(:green))
120
129
  rescue Aws::Waiters::Errors::FailureStateError => ex
121
130
  resp = @client.describe_change_set(
122
131
  change_set_name: name,
123
132
  stack_name: name
124
133
  )
125
134
  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)
135
+ CFnDK.logger.error ex.message.color(:red)
127
136
  raise ex
128
137
  else
129
- @logger.error(('failed create change set: ' + name).color(:red))
130
- @logger.error resp.status_reason
138
+ CFnDK.logger.error(('failed create change set: ' + name).color(:red))
139
+ CFnDK.logger.error resp.status_reason
131
140
  @client.delete_change_set(
132
141
  change_set_name: name,
133
142
  stack_name: name
134
143
  )
135
- @logger.info(('deleted change set: ' + name).color(:red))
144
+ CFnDK.logger.info(('deleted change set: ' + name).color(:red))
136
145
  end
137
146
  end
138
147
  end
139
148
 
140
149
  def validate
141
150
  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)
151
+ CFnDK.logger.info(('validate stack: ' + name).color(:green))
152
+ CFnDK.logger.debug('Name :' + @name)
144
153
  @client.validate_template(
145
154
  template_body: template_body
146
155
  )
@@ -155,10 +164,16 @@ module CFnDK
155
164
  false
156
165
  end
157
166
 
167
+ def report
168
+ report_stack
169
+ report_stack_resource
170
+ report_event
171
+ end
172
+
158
173
  def report_stack
159
174
  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)
175
+ CFnDK.logger.info(('stack: ' + name).color(:green))
176
+ CFnDK.logger.debug('Name :' + name)
162
177
  begin
163
178
  rows = @client.describe_stacks(
164
179
  stack_name: name
@@ -171,16 +186,16 @@ module CFnDK
171
186
  item.stack_status_reason]
172
187
  end
173
188
  table = Terminal::Table.new headings: %w(Name Creation Deletion Status Reason), rows: rows
174
- @logger.info table
189
+ CFnDK.logger.info table
175
190
  rescue Aws::CloudFormation::Errors::ValidationError => ex
176
- @logger.warn ex.message
191
+ CFnDK.logger.warn ex.message
177
192
  end
178
193
  end
179
194
 
180
195
  def report_event
181
196
  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)
197
+ CFnDK.logger.info(('stack: ' + name).color(:green))
198
+ CFnDK.logger.debug('Name :' + name)
184
199
  begin
185
200
  rows = @client.describe_stack_events(
186
201
  stack_name: name
@@ -192,16 +207,16 @@ module CFnDK
192
207
  item.resource_status_reason]
193
208
  end
194
209
  table = Terminal::Table.new headings: %w(Type Time Status Reason), rows: rows
195
- @logger.info table
210
+ CFnDK.logger.info table
196
211
  rescue Aws::CloudFormation::Errors::ValidationError => ex
197
- @logger.warn ex.message
212
+ CFnDK.logger.warn ex.message
198
213
  end
199
214
  end
200
215
 
201
216
  def report_stack_resource
202
217
  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)
218
+ CFnDK.logger.info(('stack: ' + name).color(:green))
219
+ CFnDK.logger.debug('Name :' + name)
205
220
  begin
206
221
  rows = @client.describe_stack_resources(
207
222
  stack_name: name
@@ -217,9 +232,9 @@ module CFnDK
217
232
  ]
218
233
  end
219
234
  table = Terminal::Table.new headings: %w(L-name P-name Type Timestamp Status Reason Desc), rows: rows
220
- @logger.info table
235
+ CFnDK.logger.info table
221
236
  rescue Aws::CloudFormation::Errors::ValidationError => ex
222
- @logger.warn ex.message
237
+ CFnDK.logger.warn ex.message
223
238
  end
224
239
  end
225
240
 
@@ -3,7 +3,6 @@ module CFnDK
3
3
  def initialize(data, option, credentials)
4
4
  @option = option
5
5
  @credentials = credentials
6
- @logger = CFnDK::Logger.new(option)
7
6
 
8
7
  prepare_stack(data)
9
8
  prepare_sequence
@@ -74,26 +73,10 @@ module CFnDK
74
73
  end
75
74
  end
76
75
 
77
- def report_stack
76
+ def report
78
77
  @sequence.each do |stacks|
79
78
  stacks.each do |name|
80
- @stacks[name].report_stack
81
- end
82
- end
83
- end
84
-
85
- def report_stack_resource
86
- @sequence.each do |stacks|
87
- stacks.each do |name|
88
- @stacks[name].report_stack_resource
89
- end
90
- end
91
- end
92
-
93
- def report_event
94
- @sequence.each do |stacks|
95
- stacks.each do |name|
96
- @stacks[name].report_event
79
+ @stacks[name].report
97
80
  end
98
81
  end
99
82
  end
@@ -102,6 +85,7 @@ module CFnDK
102
85
 
103
86
  def prepare_stack(data)
104
87
  @stacks = {}
88
+ return unless data['stacks'].is_a?(Hash)
105
89
  data['stacks'].each do |name, properties|
106
90
  @stacks[name] = Stack.new(name, properties, @option, @credentials)
107
91
  end
@@ -117,7 +101,7 @@ module CFnDK
117
101
  names_of_processed_stack.include? depend_name
118
102
  end
119
103
  end
120
- raise 'There are cyclic dependency or stack is not exit. unprocessed_stack: ' + names_of_upprocessed_stack.join(',') if names.empty?
104
+ raise "There are cyclic dependency or stack doesn't exist. unprocessed_stack: " + names_of_upprocessed_stack.join(',') if names.empty?
121
105
  names_of_processed_stack += names
122
106
  names_of_upprocessed_stack -= names
123
107
  @sequence.push names
@@ -1,3 +1,3 @@
1
1
  module CFnDK
2
- VERSION = '0.0.7'.freeze
2
+ VERSION = '0.1.0'.freeze
3
3
  end
@@ -0,0 +1 @@
1
+ secrets.yml
@@ -0,0 +1,589 @@
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
+ describe 'bin/cfndk' do
7
+ before(:each) { setup_aruba }
8
+ let(:file) { 'cfndk.yml' }
9
+ let(:file2) { 'cfndk2.yml' }
10
+ let(:pem) { 'test.pem' }
11
+ let(:uuid) { '38437346-c75c-47c5-83b4-d504f85e275b' }
12
+
13
+ describe 'create', create: true do
14
+ context 'without cfndk.yml' do
15
+ before(:each) { run_command('cfndk create') }
16
+ it 'displays file does not exist error and status code = 1' do
17
+ aggregate_failures do
18
+ expect(last_command_started).to have_exit_status(1)
19
+ expect(last_command_started).to have_output(/ERROR File does not exist./)
20
+ end
21
+ end
22
+ end
23
+
24
+ context 'with cfndk2.yml' do
25
+ yaml = <<-"YAML"
26
+ keypairs:
27
+ YAML
28
+ before(:each) { write_file(file2, yaml) }
29
+ context 'when -c cfndk2.yml and empty keypairs' do
30
+ before(:each) { run_command("cfndk create -c=#{file2}") }
31
+ it 'displays empty keypair log' do
32
+ aggregate_failures do
33
+ expect(last_command_started).to be_successfully_executed
34
+ expect(last_command_started).to have_output(/INFO create.../)
35
+ end
36
+ end
37
+ end
38
+
39
+ context 'when --config-path cfndk2.yml and empty keypairs' do
40
+ before(:each) { run_command("cfndk create --config-path=#{file2}") }
41
+ it 'displays empty keypair log' do
42
+ aggregate_failures do
43
+ expect(last_command_started).to be_successfully_executed
44
+ expect(last_command_started).to have_output(/INFO create.../)
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ context 'with cfndk.yml' do
51
+ context 'when cfndk.yml is empty' do
52
+ before(:each) { touch(file) }
53
+ before(:each) { run_command('cfndk create') }
54
+ it 'displays File is empty error and status code = 1' do
55
+ aggregate_failures do
56
+ expect(last_command_started).to have_exit_status(1)
57
+ expect(last_command_started).to have_output(/ERROR File is empty./)
58
+ end
59
+ end
60
+ end
61
+
62
+ context 'with keyparis:', keypairs: true do
63
+ context 'without keypair' do
64
+ before(:each) { write_file(file, 'keypairs:') }
65
+ before(:each) { run_command('cfndk create') }
66
+ it do
67
+ aggregate_failures do
68
+ expect(last_command_started).to be_successfully_executed
69
+ expect(last_command_started).to have_output(/INFO create.../)
70
+ end
71
+ end
72
+ end
73
+
74
+ context 'with a keypair' do
75
+ yaml = <<-"YAML"
76
+ keypairs:
77
+ Test:
78
+ YAML
79
+ before(:each) { write_file(file, yaml) }
80
+ before(:each) { run_command('cfndk create') }
81
+ it do
82
+ aggregate_failures do
83
+ expect(last_command_started).to be_successfully_executed
84
+ expect(last_command_started).to have_output(/INFO creating keypair: Test/)
85
+ expect(last_command_started).to have_output(/INFO created keypair: Test/)
86
+ end
87
+ end
88
+ after(:each) { run_command('cfndk destroy -f') }
89
+ end
90
+
91
+ context 'with two keypairs' do
92
+ yaml = <<-"YAML"
93
+ keypairs:
94
+ Foo:
95
+ Bar:
96
+ YAML
97
+ before(:each) { write_file(file, yaml) }
98
+ before(:each) { run_command('cfndk create') }
99
+ it do
100
+ aggregate_failures do
101
+ expect(last_command_started).to be_successfully_executed
102
+ expect(last_command_started).to have_output(/INFO creating keypair: Foo/)
103
+ expect(last_command_started).to have_output(/INFO created keypair: Foo/)
104
+ expect(last_command_started).to have_output(/INFO creating keypair: Bar/)
105
+ expect(last_command_started).to have_output(/INFO created keypair: Bar/)
106
+ end
107
+ end
108
+ after(:each) { run_command('cfndk destroy -f') }
109
+ end
110
+
111
+ context 'with a keypair and a key_file' do
112
+ context 'without UUID', uuid: true do
113
+ context 'without append_uuid' do
114
+ yaml = <<-"YAML"
115
+ keypairs:
116
+ Test:
117
+ key_file: test.pem
118
+ YAML
119
+ before(:each) { write_file(file, yaml) }
120
+ before(:each) { run_command('cfndk create') }
121
+ it do
122
+ aggregate_failures do
123
+ expect(last_command_started).to be_successfully_executed
124
+ expect(last_command_started).to have_output(/INFO create.../)
125
+ expect(last_command_started).to have_output(/INFO creating keypair: Test$/)
126
+ expect(last_command_started).to have_output(/INFO created keypair: Test$/)
127
+ expect(last_command_started).to have_output(/create key file: #{pem}$/)
128
+ expect(pem).to be_an_existing_file
129
+ expect(pem).to have_file_content(/-----END RSA PRIVATE KEY-----/)
130
+ end
131
+ end
132
+ after(:each) { run_command('cfndk destroy -f') }
133
+ end
134
+
135
+ context 'with append_uuid' do
136
+ yaml = <<-"YAML"
137
+ keypairs:
138
+ Test:
139
+ key_file: test<%= append_uuid %>.pem
140
+ YAML
141
+ before(:each) { write_file(file, yaml) }
142
+ before(:each) { run_command('cfndk create') }
143
+ it do
144
+ aggregate_failures do
145
+ expect(last_command_started).to be_successfully_executed
146
+ expect(last_command_started).to have_output(/INFO create.../)
147
+ expect(last_command_started).to have_output(/INFO creating keypair: Test$/)
148
+ expect(last_command_started).to have_output(/INFO created keypair: Test$/)
149
+ expect(last_command_started).to have_output(/create key file: #{pem}/)
150
+ expect(pem).to be_an_existing_file
151
+ expect(pem).to have_file_content(/-----END RSA PRIVATE KEY-----/)
152
+ end
153
+ end
154
+ after(:each) { run_command('cfndk destroy -f') }
155
+ end
156
+ end
157
+
158
+ context 'with UUID', uuid: true do
159
+ yaml = <<-"YAML"
160
+ keypairs:
161
+ Test:
162
+ key_file: test<%= append_uuid %>.pem
163
+ YAML
164
+ before(:each) { write_file(file, yaml) }
165
+ context 'when -u 38437346-c75c-47c5-83b4-d504f85e275b' do
166
+ before(:each) { run_command("cfndk create -u=#{uuid}") }
167
+ it do
168
+ aggregate_failures do
169
+ expect(last_command_started).to be_successfully_executed
170
+ expect(last_command_started).to have_output(/INFO create.../)
171
+ expect(last_command_started).to have_output(/INFO creating keypair: Test-#{uuid}/)
172
+ expect(last_command_started).to have_output(/INFO created keypair: Test-#{uuid}/)
173
+ expect(last_command_started).to have_output(/create key file: test-#{uuid}.pem/)
174
+ expect("test-#{uuid}.pem").to be_an_existing_file
175
+ expect("test-#{uuid}.pem").to have_file_content(/-----END RSA PRIVATE KEY-----/)
176
+ end
177
+ end
178
+ after(:each) { run_command("cfndk destroy -u=#{uuid} -f") }
179
+ end
180
+
181
+ context 'when env CFNDK_UUID=38437346-c75c-47c5-83b4-d504f85e275b' do
182
+ before(:each) { set_environment_variable('CFNDK_UUID', uuid) }
183
+ before(:each) { run_command('cfndk create') }
184
+ it 'runs the command with the expected results' do
185
+ aggregate_failures do
186
+ expect(last_command_started).to be_successfully_executed
187
+ expect(last_command_started).to have_output(/INFO create.../)
188
+ expect(last_command_started).to have_output(/INFO creating keypair: Test-#{uuid}/)
189
+ expect(last_command_started).to have_output(/INFO created keypair: Test-#{uuid}/)
190
+ expect(last_command_started).to have_output(/create key file: test-#{uuid}.pem/)
191
+ expect("test-#{uuid}.pem").to be_an_existing_file
192
+ expect("test-#{uuid}.pem").to have_file_content(/-----END RSA PRIVATE KEY-----/)
193
+ end
194
+ end
195
+ after(:each) { run_command('cfndk destroy -f') }
196
+ end
197
+ end
198
+ end
199
+ context 'with keypairs' do
200
+ yaml = <<-"YAML"
201
+ keypairs:
202
+ Test1:
203
+ Test2:
204
+ Test3:
205
+ YAML
206
+ before(:each) { write_file(file, yaml) }
207
+ context 'when --keypair-names=Test1 Test3' do
208
+ context 'without UUID' do
209
+ before(:each) { run_command('cfndk create --keypair-names=Test1 Test3') }
210
+ it do
211
+ aggregate_failures do
212
+ expect(last_command_started).to be_successfully_executed
213
+ expect(last_command_started).to have_output(/INFO create.../)
214
+ expect(last_command_started).to have_output(/INFO creating keypair: Test1/)
215
+ expect(last_command_started).to have_output(/INFO created keypair: Test1/)
216
+ expect(last_command_started).not_to have_output(/INFO creating keypair: Test2/)
217
+ expect(last_command_started).not_to have_output(/INFO created keypair: Test2/)
218
+ expect(last_command_started).to have_output(/INFO creating keypair: Test3/)
219
+ expect(last_command_started).to have_output(/INFO created keypair: Test3/)
220
+ end
221
+ end
222
+ after(:each) { run_command('cfndk destroy -f') }
223
+ end
224
+ context 'with UUID' do
225
+ context 'when env CFNDK_UUID=38437346-c75c-47c5-83b4-d504f85e275b' do
226
+ before(:each) { set_environment_variable('CFNDK_UUID', uuid) }
227
+ before(:each) { run_command('cfndk create --keypair-names=Test1 Test3') }
228
+ it do
229
+ aggregate_failures do
230
+ expect(last_command_started).to be_successfully_executed
231
+ expect(last_command_started).to have_output(/INFO create.../)
232
+ expect(last_command_started).to have_output(/INFO creating keypair: Test1-#{uuid}/)
233
+ expect(last_command_started).to have_output(/INFO created keypair: Test1-#{uuid}/)
234
+ expect(last_command_started).not_to have_output(/INFO creating keypair: Test2-#{uuid}/)
235
+ expect(last_command_started).not_to have_output(/INFO created keypair: Test2-#{uuid}/)
236
+ expect(last_command_started).to have_output(/INFO creating keypair: Test3-#{uuid}/)
237
+ expect(last_command_started).to have_output(/INFO created keypair: Test3-#{uuid}/)
238
+ end
239
+ end
240
+ after(:each) { run_command('cfndk destroy -f') }
241
+ end
242
+ end
243
+ end
244
+ end
245
+ end
246
+
247
+ context 'with stacks:', stacks: true do
248
+ context 'without stack' do
249
+ before(:each) { write_file(file, 'stacks:') }
250
+ before(:each) { run_command('cfndk create') }
251
+ it do
252
+ aggregate_failures do
253
+ expect(last_command_started).to be_successfully_executed
254
+ expect(last_command_started).to have_output(/INFO create.../)
255
+ end
256
+ end
257
+ end
258
+
259
+ context 'with a stack' do
260
+ yaml = <<-"YAML"
261
+ stacks:
262
+ Test:
263
+ template_file: vpc.yaml
264
+ parameter_input: vpc.json
265
+ timeout_in_minutes: 2
266
+ YAML
267
+ before(:each) { write_file(file, yaml) }
268
+ before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
269
+ before(:each) { copy('%/vpc.json', 'vpc.json') }
270
+ before(:each) { run_command('cfndk create') }
271
+ it 'displays created log and stack exist' do
272
+ aggregate_failures do
273
+ expect(last_command_started).to be_successfully_executed
274
+ expect(last_command_started).to have_output(/INFO validate stack: Test$/)
275
+ expect(last_command_started).to have_output(/INFO creating stack: Test$/)
276
+ expect(last_command_started).to have_output(/INFO created stack: Test$/)
277
+ expect(cloudformation_stack('Test')).to exist
278
+ expect(cloudformation_stack('Test').stack_name).to eq('Test')
279
+ expect(cloudformation_stack('Test').stack_status).to eq('CREATE_COMPLETE')
280
+ expect(cloudformation_stack('Test').timeout_in_minutes).to eq(2)
281
+ expect(cloudformation_stack('Test').parameters[0].parameter_value).to eq('sample')
282
+ end
283
+ end
284
+ after(:each) { run_command('cfndk destroy -f') }
285
+ end
286
+ context 'with two stacks' do
287
+ yaml = <<-"YAML"
288
+ stacks:
289
+ Test:
290
+ template_file: vpc.yaml
291
+ parameter_input: vpc.json
292
+ timeout_in_minutes: 2
293
+ Test2:
294
+ template_file: sg.yaml
295
+ parameter_input: sg.json
296
+ depends:
297
+ - Test
298
+ YAML
299
+
300
+ before(:each) { write_file(file, yaml) }
301
+ before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
302
+ before(:each) { copy('%/vpc.json', 'vpc.json') }
303
+ before(:each) { copy('%/sg.yaml', 'sg.yaml') }
304
+ before(:each) { copy('%/sg.json', 'sg.json') }
305
+ before(:each) { run_command('cfndk create') }
306
+ it do
307
+ aggregate_failures do
308
+ expect(last_command_started).to be_successfully_executed
309
+ expect(last_command_started).to have_output(/INFO validate stack: Test$/)
310
+ expect(last_command_started).to have_output(/INFO creating stack: Test$/)
311
+ expect(last_command_started).to have_output(/INFO created stack: Test$/)
312
+ expect(last_command_started).to have_output(/INFO validate stack: Test2$/)
313
+ expect(last_command_started).to have_output(/INFO creating stack: Test2$/)
314
+ expect(last_command_started).to have_output(/INFO created stack: Test2$/)
315
+ end
316
+ end
317
+ after(:each) { run_command('cfndk destroy -f') }
318
+ end
319
+ context 'when invalid dependency', dependency: true do
320
+ yaml = <<-"YAML"
321
+ stacks:
322
+ Test:
323
+ template_file: vpc.yaml
324
+ parameter_input: vpc.json
325
+ timeout_in_minutes: 2
326
+ depends:
327
+ - Test2
328
+ Test2:
329
+ template_file: sg.yaml
330
+ parameter_input: sg.json
331
+ YAML
332
+
333
+ before(:each) { write_file(file, yaml) }
334
+ before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
335
+ before(:each) { copy('%/vpc.json', 'vpc.json') }
336
+ before(:each) { copy('%/sg.yaml', 'sg.yaml') }
337
+ before(:each) { copy('%/sg.json', 'sg.json') }
338
+ before(:each) { run_command('cfndk create') }
339
+ it do
340
+ aggregate_failures do
341
+ expect(last_command_started).to have_exit_status(1)
342
+ expect(last_command_started).to have_output(/ERROR stopped waiting, encountered a failure state$/)
343
+ end
344
+ end
345
+ after(:each) { run_command('cfndk destroy -f') }
346
+ end
347
+ context 'when cyclic dependency', dependency: true do
348
+ yaml = <<-"YAML"
349
+ stacks:
350
+ Test:
351
+ template_file: vpc.yaml
352
+ parameter_input: vpc.json
353
+ timeout_in_minutes: 2
354
+ depends:
355
+ - Test2
356
+ Test2:
357
+ template_file: sg.yaml
358
+ parameter_input: sg.json
359
+ depends:
360
+ - Test
361
+ YAML
362
+
363
+ before(:each) { write_file(file, yaml) }
364
+ before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
365
+ before(:each) { copy('%/vpc.json', 'vpc.json') }
366
+ before(:each) { copy('%/sg.yaml', 'sg.yaml') }
367
+ before(:each) { copy('%/sg.json', 'sg.json') }
368
+ before(:each) { run_command('cfndk create') }
369
+ it do
370
+ aggregate_failures do
371
+ expect(last_command_started).to have_exit_status(1)
372
+ expect(last_command_started).to have_output(/ERROR There are cyclic dependency or stack doesn't exist. unprocessed_stack: Test,Test2$/)
373
+ end
374
+ end
375
+ after(:each) { run_command('cfndk destroy -f') }
376
+ end
377
+ context 'when requires capabilities without capabilities', capabilities: true do
378
+ yaml = <<-"YAML"
379
+ stacks:
380
+ Test:
381
+ template_file: iam.yaml
382
+ parameter_input: iam.json
383
+ timeout_in_minutes: 2
384
+ YAML
385
+
386
+ before(:each) { write_file(file, yaml) }
387
+ before(:each) { copy('%/iam.yaml', 'iam.yaml') }
388
+ before(:each) { copy('%/iam.json', 'iam.json') }
389
+ before(:each) { run_command('cfndk create') }
390
+ it do
391
+ aggregate_failures do
392
+ expect(last_command_started).to have_exit_status(1)
393
+ expect(last_command_started).to have_output(/ERROR Requires capabilities : \[CAPABILITY_NAMED_IAM\]/)
394
+ end
395
+ end
396
+ after(:each) { run_command('cfndk destroy -f') }
397
+ end
398
+ context 'when success with capabilities', capabilities: true do
399
+ yaml = <<-"YAML"
400
+ stacks:
401
+ Test:
402
+ template_file: iam.yaml
403
+ parameter_input: iam.json
404
+ capabilities:
405
+ - CAPABILITY_NAMED_IAM
406
+ timeout_in_minutes: 3
407
+ YAML
408
+
409
+ before(:each) { write_file(file, yaml) }
410
+ before(:each) { copy('%/iam.yaml', 'iam.yaml') }
411
+ before(:each) { copy('%/iam.json', 'iam.json') }
412
+ before(:each) { run_command('cfndk create') }
413
+ it do
414
+ aggregate_failures do
415
+ expect(last_command_started).to be_successfully_executed
416
+ expect(last_command_started).to have_output(/INFO created stack: Test$/)
417
+ end
418
+ end
419
+ after(:each) { run_command('cfndk destroy -f') }
420
+ end
421
+ context 'with UUID', uuid: true do
422
+ context 'when -u 38437346-c75c-47c5-83b4-d504f85e275b' do
423
+ yaml = <<-"YAML"
424
+ stacks:
425
+ Test:
426
+ template_file: vpc.yaml
427
+ parameter_input: vpc.json
428
+ parameters:
429
+ VpcName: sample<%= append_uuid%>
430
+ timeout_in_minutes: 2
431
+ Test2:
432
+ template_file: sg.yaml
433
+ parameter_input: sg.json
434
+ parameters:
435
+ VpcName: sample<%= append_uuid%>
436
+ depends:
437
+ - Test
438
+ YAML
439
+ before(:each) { write_file(file, yaml) }
440
+ before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
441
+ before(:each) { copy('%/vpc.json', 'vpc.json') }
442
+ before(:each) { copy('%/sg.yaml', 'sg.yaml') }
443
+ before(:each) { copy('%/sg.json', 'sg.json') }
444
+ before(:each) { run_command("cfndk create -u=#{uuid}") }
445
+ it do
446
+ aggregate_failures do
447
+ expect(last_command_started).to be_successfully_executed
448
+ expect(last_command_started).to have_output(/INFO validate stack: Test-#{uuid}$/)
449
+ expect(last_command_started).to have_output(/INFO creating stack: Test-#{uuid}$/)
450
+ expect(last_command_started).to have_output(/INFO created stack: Test-#{uuid}$/)
451
+ expect(last_command_started).to have_output(/INFO validate stack: Test2-#{uuid}$/)
452
+ expect(last_command_started).to have_output(/INFO creating stack: Test2-#{uuid}$/)
453
+ expect(last_command_started).to have_output(/INFO created stack: Test2-#{uuid}$/)
454
+ end
455
+ end
456
+ after(:each) { run_command("cfndk destroy -f -u=#{uuid}") }
457
+ end
458
+ context 'when env CFNDK_UUID=38437346-c75c-47c5-83b4-d504f85e275b' do
459
+ before(:each) { set_environment_variable('CFNDK_UUID', uuid) }
460
+ context 'with two stacks' do
461
+ yaml = <<-"YAML"
462
+ stacks:
463
+ Test:
464
+ template_file: vpc.yaml
465
+ parameter_input: vpc.json
466
+ parameters:
467
+ VpcName: sample<%= append_uuid%>
468
+ timeout_in_minutes: 2
469
+ Test2:
470
+ template_file: sg.yaml
471
+ parameter_input: sg.json
472
+ parameters:
473
+ VpcName: sample<%= append_uuid%>
474
+ depends:
475
+ - Test
476
+ YAML
477
+ before(:each) { write_file(file, yaml) }
478
+ before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
479
+ before(:each) { copy('%/vpc.json', 'vpc.json') }
480
+ before(:each) { copy('%/sg.yaml', 'sg.yaml') }
481
+ before(:each) { copy('%/sg.json', 'sg.json') }
482
+ before(:each) { run_command('cfndk create') }
483
+ it do
484
+ aggregate_failures do
485
+ expect(last_command_started).to be_successfully_executed
486
+ expect(last_command_started).to have_output(/INFO validate stack: Test-#{uuid}$/)
487
+ expect(last_command_started).to have_output(/INFO creating stack: Test-#{uuid}$/)
488
+ expect(last_command_started).to have_output(/INFO created stack: Test-#{uuid}$/)
489
+ expect(last_command_started).to have_output(/INFO validate stack: Test2-#{uuid}$/)
490
+ expect(last_command_started).to have_output(/INFO creating stack: Test2-#{uuid}$/)
491
+ expect(last_command_started).to have_output(/INFO created stack: Test2-#{uuid}$/)
492
+ end
493
+ end
494
+ after(:each) { run_command('cfndk destroy -f') }
495
+ end
496
+ context 'when --stack-names=Test' do
497
+ yaml = <<-"YAML"
498
+ stacks:
499
+ Test:
500
+ template_file: vpc.yaml
501
+ parameter_input: vpc.json
502
+ parameters:
503
+ VpcName: sample<%= append_uuid%>
504
+ timeout_in_minutes: 2
505
+ Test2:
506
+ template_file: sg.yaml
507
+ parameter_input: sg.json
508
+ parameters:
509
+ VpcName: sample<%= append_uuid%>
510
+ depends:
511
+ - Test
512
+ YAML
513
+ before(:each) { write_file(file, yaml) }
514
+ before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
515
+ before(:each) { copy('%/vpc.json', 'vpc.json') }
516
+ before(:each) { copy('%/sg.yaml', 'sg.yaml') }
517
+ before(:each) { copy('%/sg.json', 'sg.json') }
518
+ before(:each) { run_command('cfndk create --stack-names=Test') }
519
+ it do
520
+ aggregate_failures do
521
+ expect(last_command_started).to be_successfully_executed
522
+ expect(last_command_started).to have_output(/INFO create.../)
523
+ expect(last_command_started).to have_output(/INFO validate stack: Test-#{uuid}$/)
524
+ expect(last_command_started).to have_output(/INFO creating stack: Test-#{uuid}$/)
525
+ expect(last_command_started).to have_output(/INFO created stack: Test-#{uuid}$/)
526
+ expect(last_command_started).not_to have_output(/INFO validate stack: Test2-#{uuid}$/)
527
+ expect(last_command_started).not_to have_output(/INFO creating stack: Test2-#{uuid}$/)
528
+ expect(last_command_started).not_to have_output(/INFO created stack: Test2-#{uuid}$/)
529
+ end
530
+ end
531
+ after(:each) { run_command('cfndk destroy -f') }
532
+ end
533
+ context 'when --stack-names=Test Test2' do
534
+ yaml = <<-"YAML"
535
+ stacks:
536
+ Test:
537
+ template_file: vpc.yaml
538
+ parameter_input: vpc.json
539
+ parameters:
540
+ VpcName: sample<%= append_uuid%>
541
+ timeout_in_minutes: 2
542
+ Test2:
543
+ template_file: sg.yaml
544
+ parameter_input: sg.json
545
+ parameters:
546
+ VpcName: sample<%= append_uuid%>
547
+ depends:
548
+ - Test
549
+ Test3:
550
+ template_file: iam.yaml
551
+ parameter_input: iam.json
552
+ parameters:
553
+ WebRoleName: WebhRole<%= append_uuid%>
554
+ capabilities:
555
+ - CAPABILITY_NAMED_IAM
556
+ timeout_in_minutes: 3
557
+ YAML
558
+ before(:each) { write_file(file, yaml) }
559
+ before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
560
+ before(:each) { copy('%/vpc.json', 'vpc.json') }
561
+ before(:each) { copy('%/sg.yaml', 'sg.yaml') }
562
+ before(:each) { copy('%/sg.json', 'sg.json') }
563
+ before(:each) { copy('%/iam.yaml', 'iam.yaml') }
564
+ before(:each) { copy('%/iam.json', 'iam.json') }
565
+ before(:each) { run_command('cfndk create --stack-names=Test Test2') }
566
+ it do
567
+ aggregate_failures do
568
+ expect(last_command_started).to be_successfully_executed
569
+ expect(last_command_started).to have_output(/INFO create.../)
570
+ expect(last_command_started).to have_output(/INFO validate stack: Test-#{uuid}$/)
571
+ expect(last_command_started).to have_output(/INFO creating stack: Test-#{uuid}$/)
572
+ expect(last_command_started).to have_output(/INFO created stack: Test-#{uuid}$/)
573
+ expect(last_command_started).to have_output(/INFO validate stack: Test2-#{uuid}$/)
574
+ expect(last_command_started).to have_output(/INFO creating stack: Test2-#{uuid}$/)
575
+ expect(last_command_started).to have_output(/INFO created stack: Test2-#{uuid}$/)
576
+ expect(last_command_started).not_to have_output(/INFO validate stack: Test3-#{uuid}$/)
577
+ expect(last_command_started).not_to have_output(/INFO creating stack: Test3-#{uuid}$/)
578
+ expect(last_command_started).not_to have_output(/INFO created stack: Test3-#{uuid}$/)
579
+ end
580
+ end
581
+ after(:each) { run_command('cfndk destroy -f') }
582
+ end
583
+ end
584
+ end
585
+ end
586
+ end
587
+ end
588
+ end
589
+ end