cfndk 0.0.7 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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