cfndk 0.1.1.2 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.circleci/config.yml +1 -1
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/Gemfile.lock +9 -5
- data/README.md +124 -10
- data/cfndk.gemspec +3 -0
- data/docker/Dockerfile +8 -0
- data/docker/build.sh +3 -0
- data/docker/cfndk.sh +14 -0
- data/lib/cfndk.rb +9 -0
- data/lib/cfndk/change_set_command.rb +14 -8
- data/lib/cfndk/command.rb +14 -6
- data/lib/cfndk/credential_provider_chain.rb +12 -42
- data/lib/cfndk/credential_resolvable.rb +10 -0
- data/lib/cfndk/diff.rb +38 -0
- data/lib/cfndk/global_config.rb +32 -2
- data/lib/cfndk/key_pair.rb +33 -1
- data/lib/cfndk/key_pair_command.rb +10 -3
- data/lib/cfndk/key_pairs.rb +12 -0
- data/lib/cfndk/stack.rb +58 -59
- data/lib/cfndk/stack_command.rb +26 -8
- data/lib/cfndk/stacks.rb +16 -0
- data/lib/cfndk/template_packager.rb +210 -0
- data/lib/cfndk/uuid.rb +10 -0
- data/lib/cfndk/version.rb +1 -1
- data/spec/cfndk_spec.rb +1 -1
- data/spec/cfndk_stack_create_spec.rb +365 -5
- data/spec/cfndk_stack_destroy_spec.rb +64 -0
- data/spec/cfndk_stack_update_spec.rb +86 -0
- data/spec/fixtures/big_vpc.yaml +533 -0
- data/spec/fixtures/lambda_function/index.js +4 -0
- data/spec/fixtures/lambda_function/lambda_function.json +4 -0
- data/spec/fixtures/lambda_function/lambda_function.yaml +28 -0
- data/spec/fixtures/nested_stack.json +35 -0
- data/spec/fixtures/nested_stack.yaml +20 -0
- data/spec/fixtures/serverless_function/index.js +4 -0
- data/spec/fixtures/serverless_function/serverless_function.json +4 -0
- data/spec/fixtures/serverless_function/serverless_function.yaml +21 -0
- data/spec/fixtures/stack.json +8 -0
- data/spec/fixtures/stack.template.json +39 -0
- data/spec/fixtures/stack.yaml +22 -0
- data/spec/fixtures/vpc.template.json +40 -0
- data/vagrant/Vagrantfile +89 -0
- metadata +80 -4
data/lib/cfndk/stack_command.rb
CHANGED
@@ -2,11 +2,12 @@ module CFnDK
|
|
2
2
|
class StackCommand < Thor
|
3
3
|
include SubcommandHelpReturnable
|
4
4
|
include ConfigFileLoadable
|
5
|
+
include CredentialResolvable
|
5
6
|
|
6
7
|
class_option :verbose, type: :boolean, aliases: 'v', desc: 'More verbose output.'
|
7
8
|
class_option :color, type: :boolean, default: true, desc: 'Use colored output'
|
8
9
|
class_option :config_path, type: :string, aliases: 'c', default: "#{Dir.getwd}/cfndk.yml", desc: 'The configuration file to use'
|
9
|
-
class_option :stack_names, type: :array, desc: 'Target stack names'
|
10
|
+
class_option :stack_names, type: :array, aliases: 's', desc: 'Target stack names'
|
10
11
|
|
11
12
|
desc 'create', 'Create stack'
|
12
13
|
option :uuid, type: :string, aliases: 'u', default: ENV['CFNDK_UUID'] || nil, desc: 'Use UUID'
|
@@ -14,11 +15,16 @@ module CFnDK
|
|
14
15
|
def create
|
15
16
|
CFnDK.logger.info 'create...'.color(:green)
|
16
17
|
data = load_config_data(options)
|
17
|
-
|
18
|
-
|
18
|
+
credentials = resolve_credential(data, options)
|
19
|
+
global_config = CFnDK::GlobalConfig.new(data, options)
|
19
20
|
stacks = CFnDK::Stacks.new(data, options, credentials)
|
21
|
+
|
22
|
+
global_config.pre_command_execute
|
23
|
+
stacks.pre_command_execute
|
20
24
|
stacks.validate
|
21
25
|
stacks.create
|
26
|
+
stacks.post_command_execute
|
27
|
+
global_config.post_command_execute
|
22
28
|
return 0
|
23
29
|
rescue => e
|
24
30
|
CFnDK.logger.error "#{e.class}: #{e.message}".color(:red)
|
@@ -34,11 +40,16 @@ module CFnDK
|
|
34
40
|
def update
|
35
41
|
CFnDK.logger.info 'update...'.color(:green)
|
36
42
|
data = load_config_data(options)
|
37
|
-
|
38
|
-
|
43
|
+
credentials = resolve_credential(data, options)
|
44
|
+
global_config = CFnDK::GlobalConfig.new(data, options)
|
39
45
|
stacks = CFnDK::Stacks.new(data, options, credentials)
|
46
|
+
|
47
|
+
global_config.pre_command_execute
|
48
|
+
stacks.pre_command_execute
|
40
49
|
stacks.validate
|
41
50
|
stacks.update
|
51
|
+
stacks.post_command_execute
|
52
|
+
global_config.post_command_execute
|
42
53
|
return 0
|
43
54
|
rescue => e
|
44
55
|
CFnDK.logger.error "#{e.class}: #{e.message}".color(:red)
|
@@ -54,8 +65,8 @@ module CFnDK
|
|
54
65
|
def destroy
|
55
66
|
CFnDK.logger.info 'destroy...'.color(:green)
|
56
67
|
data = load_config_data(options)
|
68
|
+
credentials = resolve_credential(data, options)
|
57
69
|
|
58
|
-
credentials = CFnDK::CredentialProviderChain.new.resolve
|
59
70
|
stacks = CFnDK::Stacks.new(data, options, credentials)
|
60
71
|
|
61
72
|
if options[:force] || yes?('Are you sure you want to destroy? (y/n)', :yellow)
|
@@ -77,9 +88,15 @@ module CFnDK
|
|
77
88
|
def validate
|
78
89
|
CFnDK.logger.info 'validate...'.color(:green)
|
79
90
|
data = load_config_data(options)
|
80
|
-
credentials =
|
91
|
+
credentials = resolve_credential(data, options)
|
92
|
+
global_config = CFnDK::GlobalConfig.new(data, options)
|
81
93
|
stacks = CFnDK::Stacks.new(data, options, credentials)
|
94
|
+
|
95
|
+
global_config.pre_command_execute
|
96
|
+
stacks.pre_command_execute
|
82
97
|
stacks.validate
|
98
|
+
stacks.post_command_execute
|
99
|
+
global_config.post_command_execute
|
83
100
|
return 0
|
84
101
|
rescue => e
|
85
102
|
CFnDK.logger.error "#{e.class}: #{e.message}".color(:red)
|
@@ -95,7 +112,8 @@ module CFnDK
|
|
95
112
|
def report
|
96
113
|
CFnDK.logger.info 'report...'.color(:green)
|
97
114
|
data = load_config_data(options)
|
98
|
-
credentials =
|
115
|
+
credentials = resolve_credential(data, options)
|
116
|
+
|
99
117
|
stacks = CFnDK::Stacks.new(data, options, credentials)
|
100
118
|
stacks.report
|
101
119
|
return 0
|
data/lib/cfndk/stacks.rb
CHANGED
@@ -107,6 +107,22 @@ module CFnDK
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
110
|
+
def pre_command_execute
|
111
|
+
@sequence.each do |stacks|
|
112
|
+
stacks.each do |name|
|
113
|
+
@stacks[name].pre_command_execute
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def post_command_execute
|
119
|
+
@sequence.each do |stacks|
|
120
|
+
stacks.each do |name|
|
121
|
+
@stacks[name].post_command_execute
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
110
126
|
private
|
111
127
|
|
112
128
|
def prepare_stack(data)
|
@@ -0,0 +1,210 @@
|
|
1
|
+
using Polyfill(
|
2
|
+
String: %w[#delete_prefix]
|
3
|
+
)
|
4
|
+
|
5
|
+
module CFnDK
|
6
|
+
class TemplatePackager
|
7
|
+
def initialize(template_file, region, package, global_config, s3_client, sts_client)
|
8
|
+
@template_file = template_file
|
9
|
+
@region = region
|
10
|
+
@package = package
|
11
|
+
@global_config = global_config
|
12
|
+
@s3_client = s3_client
|
13
|
+
@sts_client = sts_client
|
14
|
+
@template_body = nil
|
15
|
+
@is_uploaded = false
|
16
|
+
end
|
17
|
+
|
18
|
+
def large_template?
|
19
|
+
template_body.size > 51200
|
20
|
+
end
|
21
|
+
|
22
|
+
def template_body
|
23
|
+
package_templte
|
24
|
+
end
|
25
|
+
|
26
|
+
def upload_template_file
|
27
|
+
key = [@global_config.s3_template_hash, @template_file].compact.join('/')
|
28
|
+
url = "https://s3.amazonaws.com/#{bucket_name}/#{key}"
|
29
|
+
|
30
|
+
unless @is_uploaded
|
31
|
+
create_bucket
|
32
|
+
@s3_client.put_object(
|
33
|
+
body: template_body,
|
34
|
+
bucket: bucket_name,
|
35
|
+
key: key
|
36
|
+
)
|
37
|
+
@is_uploaded = true
|
38
|
+
CFnDK.logger.info('Put S3 object: ' + url + ' Size: ' + template_body.size.to_s)
|
39
|
+
end
|
40
|
+
url
|
41
|
+
end
|
42
|
+
|
43
|
+
def package_templte
|
44
|
+
if !@template_body
|
45
|
+
if !@package
|
46
|
+
@template_body = File.open(@template_file, 'r').read
|
47
|
+
return @template_body
|
48
|
+
end
|
49
|
+
orgTemplate = File.open(@template_file, 'r').read
|
50
|
+
CFnDK.logger.debug('Original Template:' + orgTemplate)
|
51
|
+
if is_json?(orgTemplate)
|
52
|
+
data = JSON.parse(orgTemplate)
|
53
|
+
else
|
54
|
+
data = YAML.load(orgTemplate.gsub(/!/, '____CFNDK!____'))
|
55
|
+
end
|
56
|
+
|
57
|
+
if data['Resources']
|
58
|
+
data['Resources'].each do |k, v|
|
59
|
+
next unless v.key?('Type')
|
60
|
+
t = v['Type']
|
61
|
+
properties = v['Properties'] || {}
|
62
|
+
case t
|
63
|
+
when 'AWS::CloudFormation::Stack' then
|
64
|
+
if properties['TemplateURL'] =~ /^\s*./
|
65
|
+
tp = TemplatePackager.new(File.dirname(@template_file) + '/' + properties['TemplateURL'].sub(/^\s*.\//, ''), @region, @package, @global_config, @s3_client, @sts_client)
|
66
|
+
v['Properties']['TemplateURL'] = tp.upload_template_file
|
67
|
+
end
|
68
|
+
when 'AWS::Lambda::Function' then
|
69
|
+
if properties['Code'].kind_of?(String)
|
70
|
+
result = upload_zip_file(File.dirname(@template_file) + '/' + properties['Code'].sub(/^\s*.\//, ''))
|
71
|
+
v['Properties']['Code'] = {
|
72
|
+
'S3Bucket' => result['bucket'],
|
73
|
+
'S3Key' => result['key']
|
74
|
+
}
|
75
|
+
end
|
76
|
+
when 'AWS::Serverless::Function' then
|
77
|
+
if properties['CodeUri'].kind_of?(String)
|
78
|
+
result = upload_zip_file(File.dirname(@template_file) + '/' + properties['CodeUri'].sub(/^\s*.\//, ''))
|
79
|
+
v['Properties']['CodeUri'] = {
|
80
|
+
'Bucket' => result['bucket'],
|
81
|
+
'Key' => result['key']
|
82
|
+
}
|
83
|
+
end
|
84
|
+
when 'AWS::Serverless::Api' then
|
85
|
+
if properties['DefinitionUri'].kind_of?(String)
|
86
|
+
result = upload_file(File.dirname(@template_file) + '/' + properties['DefinitionUri'].sub(/^\s*.\//, ''))
|
87
|
+
v['Properties']['DefinitionUri'] = {
|
88
|
+
'Bucket' => result['bucket'],
|
89
|
+
'Key' => result['key']
|
90
|
+
}
|
91
|
+
end
|
92
|
+
when 'AWS::ApiGateway::RestApi' then
|
93
|
+
if properties['BodyS3Location'].kind_of?(String)
|
94
|
+
result = upload_file(File.dirname(@template_file) + '/' + properties['BodyS3Location'].sub(/^\s*.\//, ''))
|
95
|
+
v['Properties']['BodyS3Location'] = {
|
96
|
+
'Bucket' => result['bucket'],
|
97
|
+
'Key' => result['key']
|
98
|
+
}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
## TODO support resources
|
102
|
+
# * AWS::AppSync::GraphQLSchema DefinitionS3Location
|
103
|
+
# * AWS::AppSync::Resolver RequestMappingTemplateS3Location
|
104
|
+
# * AWS::AppSync::Resolver ResponseMappingTemplateS3Location
|
105
|
+
# * AWS::ElasticBeanstalk::ApplicationVersion SourceBundle
|
106
|
+
# * AWS::Glue::Job Command ScriptLocation
|
107
|
+
# * AWS::Include Location
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
if is_json?(orgTemplate)
|
112
|
+
@template_body = JSON.dump(data)
|
113
|
+
else
|
114
|
+
@template_body = YAML.dump_stream(data).gsub(/____CFNDK!____/, '!')
|
115
|
+
end
|
116
|
+
CFnDK.logger.info('Template Packager diff: ' + @template_file)
|
117
|
+
CFnDK.logger.info(CFnDK.diff(orgTemplate, @template_body).to_s)
|
118
|
+
CFnDK.logger.debug('Package Template size: ' + @template_body.size.to_s)
|
119
|
+
CFnDK.logger.debug('Package Template:' + @template_body)
|
120
|
+
end
|
121
|
+
@template_body
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def upload_zip_file(path)
|
127
|
+
create_bucket
|
128
|
+
key = [@global_config.s3_template_hash, path.sub(/^.\//, '') + ".zip"].compact.join('/')
|
129
|
+
|
130
|
+
|
131
|
+
buffer = Zip::OutputStream.write_buffer do |out|
|
132
|
+
Dir.glob(path + '/**/*') do |file|
|
133
|
+
if (!File.directory?(file))
|
134
|
+
out.put_next_entry(file.delete_prefix(path + '/'))
|
135
|
+
out.write(File.open(file, 'r').read)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
@s3_client.put_object(
|
141
|
+
body: buffer.string,
|
142
|
+
bucket: bucket_name,
|
143
|
+
key: key
|
144
|
+
)
|
145
|
+
url = "https://s3.amazonaws.com/#{bucket_name}/#{key}"
|
146
|
+
CFnDK.logger.info('Put S3 object: ' + url)
|
147
|
+
{
|
148
|
+
'bucket' => bucket_name,
|
149
|
+
'key' => key
|
150
|
+
}
|
151
|
+
end
|
152
|
+
|
153
|
+
def upload_file(path)
|
154
|
+
create_bucket
|
155
|
+
key = [@global_config.s3_template_hash, path.sub(/^.\//, '')].compact.join('/')
|
156
|
+
|
157
|
+
@s3_client.put_object(
|
158
|
+
body: File.open(path, 'r').read,
|
159
|
+
bucket: bucket_name,
|
160
|
+
key: key
|
161
|
+
)
|
162
|
+
url = "https://s3.amazonaws.com/#{bucket_name}/#{key}"
|
163
|
+
CFnDK.logger.info('Put S3 object: ' + url)
|
164
|
+
{
|
165
|
+
'bucket' => bucket_name,
|
166
|
+
'key' => key
|
167
|
+
}
|
168
|
+
end
|
169
|
+
|
170
|
+
def create_bucket
|
171
|
+
begin
|
172
|
+
@s3_client.head_bucket(bucket: bucket_name)
|
173
|
+
rescue Aws::S3::Errors::NotFound, Aws::S3::Errors::Forbidden
|
174
|
+
@s3_client.create_bucket(bucket: bucket_name)
|
175
|
+
CFnDK.logger.info('Creatt S3 bucket: ' + bucket_name)
|
176
|
+
@s3_client.put_bucket_lifecycle_configuration(
|
177
|
+
bucket: bucket_name,
|
178
|
+
lifecycle_configuration: {
|
179
|
+
rules: [
|
180
|
+
{
|
181
|
+
expiration: {
|
182
|
+
days: 1,
|
183
|
+
},
|
184
|
+
status: 'Enabled',
|
185
|
+
id: 'Delete Old Files',
|
186
|
+
prefix: '',
|
187
|
+
abort_incomplete_multipart_upload: {
|
188
|
+
days_after_initiation: 1,
|
189
|
+
},
|
190
|
+
},
|
191
|
+
],
|
192
|
+
}
|
193
|
+
)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def bucket_name
|
198
|
+
resp = @sts_client.get_caller_identity({})
|
199
|
+
resp.account + '-' + @region + '-' + @global_config.s3_template_bucket
|
200
|
+
end
|
201
|
+
|
202
|
+
def is_json?(str)
|
203
|
+
begin
|
204
|
+
!!JSON.parse(str)
|
205
|
+
rescue
|
206
|
+
false
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
data/lib/cfndk/uuid.rb
ADDED
data/lib/cfndk/version.rb
CHANGED
data/spec/cfndk_spec.rb
CHANGED
@@ -36,7 +36,7 @@ RSpec.describe 'CFnDK', type: :aruba do
|
|
36
36
|
it 'displays version' do
|
37
37
|
aggregate_failures do
|
38
38
|
expect(last_command_started).to be_successfully_executed
|
39
|
-
expect(last_command_started).to have_output(/0.1.
|
39
|
+
expect(last_command_started).to have_output(/0.1.2/)
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
@@ -97,7 +97,7 @@ RSpec.describe 'CFnDK', type: :aruba do
|
|
97
97
|
end
|
98
98
|
after(:each) { run_command('cfndk destroy -f') }
|
99
99
|
end
|
100
|
-
context 'with a
|
100
|
+
context 'with a stack and enabled is true', enabled: true do
|
101
101
|
yaml = <<-"YAML"
|
102
102
|
global:
|
103
103
|
stacks:
|
@@ -105,11 +105,59 @@ RSpec.describe 'CFnDK', type: :aruba do
|
|
105
105
|
template_file: vpc.yaml
|
106
106
|
parameter_input: vpc.json
|
107
107
|
timeout_in_minutes: 2
|
108
|
+
enabled: true
|
108
109
|
YAML
|
109
110
|
before(:each) { write_file(file, yaml) }
|
110
111
|
before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
|
111
112
|
before(:each) { copy('%/vpc.json', 'vpc.json') }
|
112
|
-
before(:each) {
|
113
|
+
before(:each) { run_command('cfndk stack create') }
|
114
|
+
it do
|
115
|
+
aggregate_failures do
|
116
|
+
expect(last_command_started).to be_successfully_executed
|
117
|
+
expect(last_command_started).to have_output(/INFO validate stack: Test$/)
|
118
|
+
expect(last_command_started).to have_output(/INFO creating stack: Test$/)
|
119
|
+
expect(last_command_started).to have_output(/INFO created stack: Test$/)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
after(:each) { run_command('cfndk destroy -f') }
|
123
|
+
end
|
124
|
+
context 'with a stack and enabled is false', enabled: true do
|
125
|
+
yaml = <<-"YAML"
|
126
|
+
global:
|
127
|
+
stacks:
|
128
|
+
Test:
|
129
|
+
template_file: vpc.yaml
|
130
|
+
parameter_input: vpc.json
|
131
|
+
timeout_in_minutes: 2
|
132
|
+
enabled: false
|
133
|
+
YAML
|
134
|
+
before(:each) { write_file(file, yaml) }
|
135
|
+
before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
|
136
|
+
before(:each) { copy('%/vpc.json', 'vpc.json') }
|
137
|
+
before(:each) { run_command('cfndk stack create') }
|
138
|
+
it do
|
139
|
+
aggregate_failures do
|
140
|
+
expect(last_command_started).to be_successfully_executed
|
141
|
+
expect(last_command_started).to have_output(/INFO create.../)
|
142
|
+
expect(last_command_started).not_to have_output(/INFO validate stack: Test$/)
|
143
|
+
expect(last_command_started).not_to have_output(/INFO creating stack: Test$/)
|
144
|
+
expect(last_command_started).not_to have_output(/INFO created stack: Test$/)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
after(:each) { run_command('cfndk destroy -f') }
|
148
|
+
end
|
149
|
+
context 'with a 51200byte template stack' do
|
150
|
+
yaml = <<-"YAML"
|
151
|
+
global:
|
152
|
+
stacks:
|
153
|
+
Test:
|
154
|
+
template_file: vpc.yaml
|
155
|
+
parameter_input: vpc.json
|
156
|
+
timeout_in_minutes: 2
|
157
|
+
YAML
|
158
|
+
before(:each) { write_file(file, yaml) }
|
159
|
+
before(:each) { copy('%/big_vpc.yaml', 'vpc.yaml') }
|
160
|
+
before(:each) { copy('%/vpc.json', 'vpc.json') }
|
113
161
|
before(:each) { run_command('cfndk stack create') }
|
114
162
|
it 'displays created stack log' do
|
115
163
|
aggregate_failures do
|
@@ -122,7 +170,7 @@ RSpec.describe 'CFnDK', type: :aruba do
|
|
122
170
|
end
|
123
171
|
after(:each) { run_command('cfndk destroy -f') }
|
124
172
|
end
|
125
|
-
context 'with a 51201byte template stack', big: true do
|
173
|
+
context 'with a 51201byte template stack', big: true, bigbig: true do
|
126
174
|
yaml = <<-"YAML"
|
127
175
|
global:
|
128
176
|
stacks:
|
@@ -132,9 +180,9 @@ RSpec.describe 'CFnDK', type: :aruba do
|
|
132
180
|
timeout_in_minutes: 2
|
133
181
|
YAML
|
134
182
|
before(:each) { write_file(file, yaml) }
|
135
|
-
before(:each) { copy('%/
|
183
|
+
before(:each) { copy('%/big_vpc.yaml', 'vpc.yaml') }
|
136
184
|
before(:each) { copy('%/vpc.json', 'vpc.json') }
|
137
|
-
before(:each) { append_to_file('vpc.yaml', '
|
185
|
+
before(:each) { append_to_file('vpc.yaml', '1') }
|
138
186
|
before(:each) { run_command('cfndk stack create') }
|
139
187
|
it 'displays created stack log' do
|
140
188
|
aggregate_failures do
|
@@ -147,6 +195,183 @@ RSpec.describe 'CFnDK', type: :aruba do
|
|
147
195
|
end
|
148
196
|
after(:each) { run_command('cfndk destroy -f') }
|
149
197
|
end
|
198
|
+
context 'with stack and nested stack', nested: true do
|
199
|
+
yaml = <<-"YAML"
|
200
|
+
global:
|
201
|
+
stacks:
|
202
|
+
Test:
|
203
|
+
template_file: vpc.yaml
|
204
|
+
parameter_input: vpc.json
|
205
|
+
timeout_in_minutes: 2
|
206
|
+
package: true
|
207
|
+
YAML
|
208
|
+
before(:each) { write_file(file, yaml) }
|
209
|
+
before(:each) { copy('%/stack.yaml', 'vpc.yaml') }
|
210
|
+
before(:each) { copy('%/stack.json', 'vpc.json') }
|
211
|
+
before(:each) { copy('%/nested_stack.yaml', 'nested_stack.yaml') }
|
212
|
+
before(:each) { run_command('cfndk stack create') }
|
213
|
+
it 'displays created stack log' do
|
214
|
+
aggregate_failures do
|
215
|
+
expect(last_command_started).to be_successfully_executed
|
216
|
+
expect(last_command_started).to have_output(/INFO validate stack: Test$/)
|
217
|
+
expect(last_command_started).to have_output(/INFO creating stack: Test$/)
|
218
|
+
expect(last_command_started).to have_output(/INFO created stack: Test$/)
|
219
|
+
expect(last_command_started).to have_output(%r{INFO Put S3 object: https://s3.amazonaws.com/[0-9]+-ap-northeast-1-cfndk-templates/.+/nested_stack.yaml})
|
220
|
+
end
|
221
|
+
end
|
222
|
+
after(:each) { run_command('cfndk destroy -f') }
|
223
|
+
end
|
224
|
+
context 'with stack with directory and nested stack', directory_nested: true do
|
225
|
+
yaml = <<-"YAML"
|
226
|
+
global:
|
227
|
+
stacks:
|
228
|
+
Test:
|
229
|
+
template_file: vpc/vpc.yaml
|
230
|
+
parameter_input: vpc/vpc.json
|
231
|
+
timeout_in_minutes: 2
|
232
|
+
package: true
|
233
|
+
YAML
|
234
|
+
before(:each) { write_file(file, yaml) }
|
235
|
+
before(:each) { copy('%/stack.yaml', 'vpc/vpc.yaml') }
|
236
|
+
before(:each) { copy('%/stack.json', 'vpc/vpc.json') }
|
237
|
+
before(:each) { copy('%/nested_stack.yaml', 'vpc/nested_stack.yaml') }
|
238
|
+
before(:each) { run_command('cfndk stack create') }
|
239
|
+
it 'displays created stack log' do
|
240
|
+
aggregate_failures do
|
241
|
+
expect(last_command_started).to be_successfully_executed
|
242
|
+
expect(last_command_started).to have_output(/INFO validate stack: Test$/)
|
243
|
+
expect(last_command_started).to have_output(/INFO creating stack: Test$/)
|
244
|
+
expect(last_command_started).to have_output(/INFO created stack: Test$/)
|
245
|
+
expect(last_command_started).to have_output(%r{INFO Put S3 object: https://s3.amazonaws.com/[0-9]+-ap-northeast-1-cfndk-templates/.+/nested_stack.yaml})
|
246
|
+
end
|
247
|
+
end
|
248
|
+
after(:each) { run_command('cfndk destroy -f') }
|
249
|
+
end
|
250
|
+
context 'with a 51201byte template stack and nested stack', nested: true, big: true, nested_big: true do
|
251
|
+
yaml = <<-"YAML"
|
252
|
+
global:
|
253
|
+
stacks:
|
254
|
+
Test:
|
255
|
+
template_file: vpc.yaml
|
256
|
+
parameter_input: vpc.json
|
257
|
+
timeout_in_minutes: 2
|
258
|
+
package: true
|
259
|
+
YAML
|
260
|
+
before(:each) { write_file(file, yaml) }
|
261
|
+
before(:each) { copy('%/stack.yaml', 'vpc.yaml') }
|
262
|
+
before(:each) { copy('%/stack.json', 'vpc.json') }
|
263
|
+
before(:each) { copy('%/nested_stack.yaml', 'nested_stack.yaml') }
|
264
|
+
before(:each) {
|
265
|
+
append_to_file('vpc.yaml', "\nOutputs:\n")
|
266
|
+
for number in 1..40 do
|
267
|
+
stack_append = <<-"YAML"
|
268
|
+
VpcId012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345#{number.to_s}:
|
269
|
+
Description: 01234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345678901234567890123
|
270
|
+
Value: !Ref Vpc
|
271
|
+
Export:
|
272
|
+
Name: !Sub ${VpcName}-VpcId012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890012345#{number.to_s}
|
273
|
+
YAML
|
274
|
+
append_to_file('vpc.yaml', stack_append)
|
275
|
+
# p read('vpc.yaml').join("\n").length
|
276
|
+
end
|
277
|
+
}
|
278
|
+
before(:each) { append_to_file('nested_stack.yaml', "\n" + '#' * (51200 + 1 - 2 - file_size('nested_stack.yaml').to_i)) }
|
279
|
+
before(:each) { run_command('cfndk stack create') }
|
280
|
+
it 'displays created stack log' do
|
281
|
+
aggregate_failures do
|
282
|
+
expect(last_command_started).to be_successfully_executed
|
283
|
+
expect(last_command_started).to have_output(/INFO validate stack: Test$/)
|
284
|
+
expect(last_command_started).to have_output(/INFO creating stack: Test$/)
|
285
|
+
expect(last_command_started).to have_output(/INFO created stack: Test$/)
|
286
|
+
expect(last_command_started).to have_output(%r{INFO Put S3 object: https://s3.amazonaws.com/[0-9]+-ap-northeast-1-cfndk-templates/.+/vpc.yaml})
|
287
|
+
expect(last_command_started).to have_output(%r{INFO Put S3 object: https://s3.amazonaws.com/[0-9]+-ap-northeast-1-cfndk-templates/.+/nested_stack.yaml})
|
288
|
+
end
|
289
|
+
end
|
290
|
+
after(:each) { run_command('cfndk destroy -f') }
|
291
|
+
end
|
292
|
+
context 'with json stack and json nested stack', nested: true, json: true do
|
293
|
+
yaml = <<-"YAML"
|
294
|
+
global:
|
295
|
+
stacks:
|
296
|
+
Test:
|
297
|
+
template_file: vpc.template.json
|
298
|
+
parameter_input: vpc.json
|
299
|
+
timeout_in_minutes: 2
|
300
|
+
package: true
|
301
|
+
YAML
|
302
|
+
before(:each) { write_file(file, yaml) }
|
303
|
+
before(:each) { copy('%/stack.template.json', 'vpc.template.json') }
|
304
|
+
before(:each) { copy('%/stack.json', 'vpc.json') }
|
305
|
+
before(:each) { copy('%/nested_stack.json', 'nested_stack.json') }
|
306
|
+
before(:each) { run_command('cfndk stack create') }
|
307
|
+
it 'displays created stack log' do
|
308
|
+
aggregate_failures do
|
309
|
+
expect(last_command_started).to be_successfully_executed
|
310
|
+
expect(last_command_started).to have_output(/INFO validate stack: Test$/)
|
311
|
+
expect(last_command_started).to have_output(/INFO creating stack: Test$/)
|
312
|
+
expect(last_command_started).to have_output(/INFO created stack: Test$/)
|
313
|
+
expect(last_command_started).to have_output(%r{INFO Put S3 object: https://s3.amazonaws.com/[0-9]+-ap-northeast-1-cfndk-templates/.+/nested_stack.json})
|
314
|
+
end
|
315
|
+
end
|
316
|
+
after(:each) { run_command('cfndk destroy -f') }
|
317
|
+
end
|
318
|
+
context 'with lambda function and zip file', lambda_function: true do
|
319
|
+
yaml = <<-"YAML"
|
320
|
+
global:
|
321
|
+
stacks:
|
322
|
+
Test:
|
323
|
+
template_file: lambda_function.yaml
|
324
|
+
parameter_input: lambda_function.json
|
325
|
+
timeout_in_minutes: 2
|
326
|
+
capabilities:
|
327
|
+
- CAPABILITY_IAM
|
328
|
+
package: true
|
329
|
+
YAML
|
330
|
+
before(:each) { write_file(file, yaml) }
|
331
|
+
before(:each) { copy('%/lambda_function/lambda_function.yaml', 'lambda_function.yaml') }
|
332
|
+
before(:each) { copy('%/lambda_function/lambda_function.json', 'lambda_function.json') }
|
333
|
+
before(:each) { copy('%/lambda_function/index.js', 'lambda_function/index.js') }
|
334
|
+
before(:each) { run_command('cfndk stack create') }
|
335
|
+
it 'displays created stack log' do
|
336
|
+
aggregate_failures do
|
337
|
+
expect(last_command_started).to be_successfully_executed
|
338
|
+
expect(last_command_started).to have_output(/INFO validate stack: Test$/)
|
339
|
+
expect(last_command_started).to have_output(/INFO creating stack: Test$/)
|
340
|
+
expect(last_command_started).to have_output(/INFO created stack: Test$/)
|
341
|
+
expect(last_command_started).to have_output(%r{INFO Put S3 object: https://s3.amazonaws.com/[0-9]+-ap-northeast-1-cfndk-templates/.+/lambda_function.zip})
|
342
|
+
end
|
343
|
+
end
|
344
|
+
after(:each) { run_command('cfndk destroy -f') }
|
345
|
+
end
|
346
|
+
context 'with serverless function and zip file', serverless_function: true do
|
347
|
+
yaml = <<-"YAML"
|
348
|
+
global:
|
349
|
+
stacks:
|
350
|
+
Test:
|
351
|
+
template_file: serverless_function.yaml
|
352
|
+
parameter_input: serverless_function.json
|
353
|
+
timeout_in_minutes: 2
|
354
|
+
capabilities:
|
355
|
+
- CAPABILITY_AUTO_EXPAND
|
356
|
+
- CAPABILITY_IAM
|
357
|
+
package: true
|
358
|
+
YAML
|
359
|
+
before(:each) { write_file(file, yaml) }
|
360
|
+
before(:each) { copy('%/serverless_function/serverless_function.yaml', 'serverless_function.yaml') }
|
361
|
+
before(:each) { copy('%/serverless_function/serverless_function.json', 'serverless_function.json') }
|
362
|
+
before(:each) { copy('%/serverless_function/index.js', 'serverless_function/index.js') }
|
363
|
+
before(:each) { run_command('cfndk stack create') }
|
364
|
+
it 'displays created stack log' do
|
365
|
+
aggregate_failures do
|
366
|
+
expect(last_command_started).to be_successfully_executed
|
367
|
+
expect(last_command_started).to have_output(/INFO validate stack: Test$/)
|
368
|
+
expect(last_command_started).to have_output(/INFO creating stack: Test$/)
|
369
|
+
expect(last_command_started).to have_output(/INFO created stack: Test$/)
|
370
|
+
expect(last_command_started).to have_output(%r{INFO Put S3 object: https://s3.amazonaws.com/[0-9]+-ap-northeast-1-cfndk-templates/.+/serverless_function.zip})
|
371
|
+
end
|
372
|
+
end
|
373
|
+
after(:each) { run_command('cfndk destroy -f') }
|
374
|
+
end
|
150
375
|
context 'with two stacks' do
|
151
376
|
yaml = <<-"YAML"
|
152
377
|
stacks:
|
@@ -180,6 +405,141 @@ RSpec.describe 'CFnDK', type: :aruba do
|
|
180
405
|
end
|
181
406
|
after(:each) { run_command('cfndk destroy -f') }
|
182
407
|
end
|
408
|
+
context 'with stack and command', global_pre_command: true, global_post_command: true, pre_command: true, post_command: true do
|
409
|
+
yaml = <<-"YAML"
|
410
|
+
global:
|
411
|
+
pre_command: echo "global pre command"
|
412
|
+
post_command: echo "global post command"
|
413
|
+
stacks:
|
414
|
+
Test:
|
415
|
+
template_file: vpc.yaml
|
416
|
+
parameter_input: vpc.json
|
417
|
+
timeout_in_minutes: 2
|
418
|
+
pre_command: echo "Test pre command"
|
419
|
+
post_command: echo "Test post command"
|
420
|
+
YAML
|
421
|
+
|
422
|
+
before(:each) { write_file(file, yaml) }
|
423
|
+
before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
|
424
|
+
before(:each) { copy('%/vpc.json', 'vpc.json') }
|
425
|
+
before(:each) { run_command('cfndk stack create') }
|
426
|
+
it do
|
427
|
+
aggregate_failures do
|
428
|
+
expect(last_command_started).to be_successfully_executed
|
429
|
+
expect(last_command_started).to have_output(/INFO execute global pre command: echo "global pre command"$/)
|
430
|
+
expect(last_command_started).to have_output(/INFO global pre command$/)
|
431
|
+
expect(last_command_started).to have_output(/INFO execute pre command: echo "Test pre command"$/)
|
432
|
+
expect(last_command_started).to have_output(/INFO Test pre command$/)
|
433
|
+
expect(last_command_started).to have_output(/INFO validate stack: Test$/)
|
434
|
+
expect(last_command_started).to have_output(/INFO creating stack: Test$/)
|
435
|
+
expect(last_command_started).to have_output(/INFO created stack: Test$/)
|
436
|
+
expect(last_command_started).to have_output(/INFO execute post command: echo "Test post command"$/)
|
437
|
+
expect(last_command_started).to have_output(/INFO Test post command$/)
|
438
|
+
expect(last_command_started).to have_output(/INFO execute global post command: echo "global post command"$/)
|
439
|
+
expect(last_command_started).to have_output(/INFO global post command$/)
|
440
|
+
end
|
441
|
+
end
|
442
|
+
after(:each) { run_command('cfndk destroy -f') }
|
443
|
+
end
|
444
|
+
|
445
|
+
context 'with stack and error global pre command', global_pre_command: true do
|
446
|
+
yaml = <<-"YAML"
|
447
|
+
global:
|
448
|
+
pre_command: exit 1
|
449
|
+
stacks:
|
450
|
+
Test:
|
451
|
+
template_file: vpc.yaml
|
452
|
+
parameter_input: vpc.json
|
453
|
+
timeout_in_minutes: 2
|
454
|
+
YAML
|
455
|
+
|
456
|
+
before(:each) { write_file(file, yaml) }
|
457
|
+
before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
|
458
|
+
before(:each) { copy('%/vpc.json', 'vpc.json') }
|
459
|
+
before(:each) { run_command('cfndk stack create') }
|
460
|
+
it do
|
461
|
+
aggregate_failures do
|
462
|
+
expect(last_command_started).not_to be_successfully_executed
|
463
|
+
expect(last_command_started).to have_output(/INFO execute global pre command: exit 1$/)
|
464
|
+
expect(last_command_started).to have_output(/ERROR RuntimeError: global pre command is error. status: 1 command: exit 1$/)
|
465
|
+
end
|
466
|
+
end
|
467
|
+
after(:each) { run_command('cfndk destroy -f') }
|
468
|
+
end
|
469
|
+
|
470
|
+
context 'with stack and error global post command', global_post_command: true do
|
471
|
+
yaml = <<-"YAML"
|
472
|
+
global:
|
473
|
+
post_command: exit 1
|
474
|
+
stacks:
|
475
|
+
Test:
|
476
|
+
template_file: vpc.yaml
|
477
|
+
parameter_input: vpc.json
|
478
|
+
timeout_in_minutes: 2
|
479
|
+
YAML
|
480
|
+
|
481
|
+
before(:each) { write_file(file, yaml) }
|
482
|
+
before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
|
483
|
+
before(:each) { copy('%/vpc.json', 'vpc.json') }
|
484
|
+
before(:each) { run_command('cfndk stack create') }
|
485
|
+
it do
|
486
|
+
aggregate_failures do
|
487
|
+
expect(last_command_started).not_to be_successfully_executed
|
488
|
+
expect(last_command_started).to have_output(/INFO execute global post command: exit 1$/)
|
489
|
+
expect(last_command_started).to have_output(/ERROR RuntimeError: global post command is error. status: 1 command: exit 1$/)
|
490
|
+
end
|
491
|
+
end
|
492
|
+
after(:each) { run_command('cfndk destroy -f') }
|
493
|
+
end
|
494
|
+
|
495
|
+
context 'with stack and error pre command', pre_command: true do
|
496
|
+
yaml = <<-"YAML"
|
497
|
+
stacks:
|
498
|
+
Test:
|
499
|
+
template_file: vpc.yaml
|
500
|
+
parameter_input: vpc.json
|
501
|
+
timeout_in_minutes: 2
|
502
|
+
pre_command: exit 1
|
503
|
+
YAML
|
504
|
+
|
505
|
+
before(:each) { write_file(file, yaml) }
|
506
|
+
before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
|
507
|
+
before(:each) { copy('%/vpc.json', 'vpc.json') }
|
508
|
+
before(:each) { run_command('cfndk stack create') }
|
509
|
+
it do
|
510
|
+
aggregate_failures do
|
511
|
+
expect(last_command_started).not_to be_successfully_executed
|
512
|
+
expect(last_command_started).to have_output(/INFO execute pre command: exit 1$/)
|
513
|
+
expect(last_command_started).to have_output(/ERROR RuntimeError: pre command is error. status: 1 command: exit 1$/)
|
514
|
+
end
|
515
|
+
end
|
516
|
+
after(:each) { run_command('cfndk destroy -f') }
|
517
|
+
end
|
518
|
+
|
519
|
+
context 'with stack and error post command', post_command: true do
|
520
|
+
yaml = <<-"YAML"
|
521
|
+
stacks:
|
522
|
+
Test:
|
523
|
+
template_file: vpc.yaml
|
524
|
+
parameter_input: vpc.json
|
525
|
+
timeout_in_minutes: 2
|
526
|
+
post_command: exit 1
|
527
|
+
YAML
|
528
|
+
|
529
|
+
before(:each) { write_file(file, yaml) }
|
530
|
+
before(:each) { copy('%/vpc.yaml', 'vpc.yaml') }
|
531
|
+
before(:each) { copy('%/vpc.json', 'vpc.json') }
|
532
|
+
before(:each) { run_command('cfndk stack create') }
|
533
|
+
it do
|
534
|
+
aggregate_failures do
|
535
|
+
expect(last_command_started).not_to be_successfully_executed
|
536
|
+
expect(last_command_started).to have_output(/INFO execute post command: exit 1$/)
|
537
|
+
expect(last_command_started).to have_output(/ERROR RuntimeError: post command is error. status: 1 command: exit 1$/)
|
538
|
+
end
|
539
|
+
end
|
540
|
+
after(:each) { run_command('cfndk destroy -f') }
|
541
|
+
end
|
542
|
+
|
183
543
|
context 'when invalid dependency', dependency: true do
|
184
544
|
yaml = <<-"YAML"
|
185
545
|
stacks:
|