kitchen-terraform 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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +1 -0
- data.tar.gz.sig +0 -0
- data/lib/kitchen/driver/terraform.rb +57 -0
- data/lib/kitchen/provisioner/terraform.rb +58 -0
- data/lib/kitchen/verifier/terraform.rb +109 -0
- data/lib/terraform/apply_command.rb +32 -0
- data/lib/terraform/client.rb +102 -0
- data/lib/terraform/client_holder.rb +26 -0
- data/lib/terraform/command.rb +58 -0
- data/lib/terraform/command_options.rb +45 -0
- data/lib/terraform/error.rb +20 -0
- data/lib/terraform/get_command.rb +32 -0
- data/lib/terraform/inspec_runner.rb +44 -0
- data/lib/terraform/invalid_version.rb +34 -0
- data/lib/terraform/output_command.rb +38 -0
- data/lib/terraform/output_not_found.rb +23 -0
- data/lib/terraform/plan_command.rb +35 -0
- data/lib/terraform/validate_command.rb +32 -0
- data/lib/terraform/version.rb +19 -0
- data/lib/terraform/version_command.rb +32 -0
- data/spec/lib/kitchen/driver/terraform_spec.rb +126 -0
- data/spec/lib/kitchen/provisioner/terraform_spec.rb +106 -0
- data/spec/lib/kitchen/verifier/terraform_spec.rb +302 -0
- data/spec/lib/terraform/apply_command_spec.rb +32 -0
- data/spec/lib/terraform/client_spec.rb +211 -0
- data/spec/lib/terraform/command_options_spec.rb +34 -0
- data/spec/lib/terraform/get_command_spec.rb +30 -0
- data/spec/lib/terraform/inspec_runner_spec.rb +67 -0
- data/spec/lib/terraform/output_command_spec.rb +58 -0
- data/spec/lib/terraform/plan_command_spec.rb +46 -0
- data/spec/lib/terraform/validate_command_spec.rb +30 -0
- data/spec/lib/terraform/version_command_spec.rb +30 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/support/coverage.rb +21 -0
- data/spec/support/terraform/client_holder_context.rb +26 -0
- data/spec/support/terraform/client_holder_examples.rb +36 -0
- data/spec/support/terraform/command_examples.rb +80 -0
- data/spec/support/terraform/versions_are_set_examples.rb +35 -0
- metadata +329 -0
- metadata.gz.sig +2 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2016 New Context Services, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'kitchen/provisioner/terraform'
|
18
|
+
require 'terraform/error'
|
19
|
+
require 'support/terraform/client_holder_context'
|
20
|
+
require 'support/terraform/client_holder_examples'
|
21
|
+
require 'support/terraform/versions_are_set_examples'
|
22
|
+
|
23
|
+
RSpec.describe Kitchen::Provisioner::Terraform do
|
24
|
+
let(:described_instance) { described_class.new kitchen_root: kitchen_root }
|
25
|
+
|
26
|
+
let(:kitchen_root) { '<kitchen_root>' }
|
27
|
+
|
28
|
+
it_behaves_like Terraform::ClientHolder
|
29
|
+
|
30
|
+
it_behaves_like 'versions are set'
|
31
|
+
|
32
|
+
describe '#call(_state = nil)' do
|
33
|
+
include_context '#client'
|
34
|
+
|
35
|
+
let(:call_method) { described_instance.call }
|
36
|
+
|
37
|
+
context 'when the configuration can be applied' do
|
38
|
+
before do
|
39
|
+
allow(client).to receive(:validate_configuration_files).with no_args
|
40
|
+
|
41
|
+
allow(client).to receive(:download_modules).with no_args
|
42
|
+
|
43
|
+
allow(client).to receive(:plan_execution).with no_args
|
44
|
+
|
45
|
+
allow(client).to receive(:apply_execution_plan).with no_args
|
46
|
+
end
|
47
|
+
|
48
|
+
after { call_method }
|
49
|
+
|
50
|
+
subject { client }
|
51
|
+
|
52
|
+
it 'validates the configuration files' do
|
53
|
+
is_expected.to receive(:validate_configuration_files).with no_args
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'downloads the modules' do
|
57
|
+
is_expected.to receive(:download_modules).with no_args
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'plans the execution' do
|
61
|
+
is_expected.to receive(:plan_execution).with no_args
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'applies the execution plan' do
|
65
|
+
is_expected.to receive(:apply_execution_plan).with no_args
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'when the configuration can not be applied due to failed command' do
|
70
|
+
before do
|
71
|
+
allow(client).to receive(:validate_configuration_files)
|
72
|
+
.and_raise Terraform::Error
|
73
|
+
end
|
74
|
+
|
75
|
+
subject { proc { call_method } }
|
76
|
+
|
77
|
+
it('raises an error') { is_expected.to raise_error Kitchen::ActionFailed }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe '#directory' do
|
82
|
+
subject { described_instance.directory.to_s }
|
83
|
+
|
84
|
+
it 'defaults to the Test Kitchen root directory' do
|
85
|
+
is_expected.to eq kitchen_root
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe '#kitchen_root' do
|
90
|
+
subject { described_instance.kitchen_root.to_s }
|
91
|
+
|
92
|
+
it('is the Test Kitchen root directory') { is_expected.to eq kitchen_root }
|
93
|
+
end
|
94
|
+
|
95
|
+
describe '#variable_files' do
|
96
|
+
subject { described_instance.variable_files }
|
97
|
+
|
98
|
+
it('defaults to empty array') { is_expected.to eq [] }
|
99
|
+
end
|
100
|
+
|
101
|
+
describe '#variables' do
|
102
|
+
subject { described_instance.variables }
|
103
|
+
|
104
|
+
it('defaults to empty array') { is_expected.to eq [] }
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,302 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2016 New Context Services, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'inspec'
|
18
|
+
require 'kitchen/verifier/terraform'
|
19
|
+
require 'support/terraform/client_holder_context'
|
20
|
+
require 'support/terraform/client_holder_examples'
|
21
|
+
require 'support/terraform/versions_are_set_examples'
|
22
|
+
|
23
|
+
RSpec.describe Kitchen::Verifier::Terraform do
|
24
|
+
let(:config) { { kitchen_root: '<kitchen_root>' } }
|
25
|
+
|
26
|
+
let(:described_instance) { described_class.new config }
|
27
|
+
|
28
|
+
let(:state) { {} }
|
29
|
+
|
30
|
+
shared_context '#instance' do
|
31
|
+
let(:instance) { instance_double Kitchen::Instance }
|
32
|
+
|
33
|
+
let(:logger) { instance_double Kitchen::Logger }
|
34
|
+
|
35
|
+
let(:transport) { Kitchen::Transport::Ssh.new }
|
36
|
+
|
37
|
+
let(:transport_config) { {} }
|
38
|
+
|
39
|
+
before do
|
40
|
+
described_instance.finalize_config! instance
|
41
|
+
|
42
|
+
allow(instance).to receive(:logger).with(no_args).and_return logger
|
43
|
+
|
44
|
+
allow(instance).to receive(:transport).with(no_args).and_return transport
|
45
|
+
|
46
|
+
allow(logger).to receive :info
|
47
|
+
|
48
|
+
allow(transport).to receive(:config).with(no_args)
|
49
|
+
.and_return Kitchen::LazyHash
|
50
|
+
.new(transport_config, instance_double(Object))
|
51
|
+
|
52
|
+
allow(transport).to receive(:diagnose).with(no_args)
|
53
|
+
.and_return transport_config
|
54
|
+
|
55
|
+
allow(transport).to receive(:name).with(no_args)
|
56
|
+
.and_return instance_double Object
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it_behaves_like Terraform::ClientHolder
|
61
|
+
|
62
|
+
it_behaves_like 'versions are set'
|
63
|
+
|
64
|
+
describe '#attributes(group:)' do
|
65
|
+
subject { described_instance.attributes group: {} }
|
66
|
+
|
67
|
+
it('defaults to an empty hash') { is_expected.to eq({}) }
|
68
|
+
end
|
69
|
+
|
70
|
+
describe '#call(state)' do
|
71
|
+
include_context '#client'
|
72
|
+
|
73
|
+
let(:call_method) { described_instance.call state }
|
74
|
+
|
75
|
+
let(:config) { { groups: [group] } }
|
76
|
+
|
77
|
+
let(:group) { { hostnames: hostnames } }
|
78
|
+
|
79
|
+
let(:hostnames) { instance_double Object }
|
80
|
+
|
81
|
+
context 'when the hostnames list output can be extracted' do
|
82
|
+
let(:output) { instance_double Object }
|
83
|
+
|
84
|
+
before do
|
85
|
+
allow(client).to receive(:extract_list_output).with(name: hostnames)
|
86
|
+
.and_yield output
|
87
|
+
end
|
88
|
+
|
89
|
+
after { call_method }
|
90
|
+
|
91
|
+
subject { described_instance }
|
92
|
+
|
93
|
+
it 'verifies the hosts of each group' do
|
94
|
+
is_expected.to receive(:verify).with group: group, hostnames: output,
|
95
|
+
state: state
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'when the hostnames list output can not be extracted' do
|
100
|
+
before do
|
101
|
+
allow(client).to receive(:extract_list_output).with(name: hostnames)
|
102
|
+
.and_raise Terraform::Error
|
103
|
+
end
|
104
|
+
|
105
|
+
subject { proc { call_method } }
|
106
|
+
|
107
|
+
it('raises an error') { is_expected.to raise_error Kitchen::ActionFailed }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe '#controls(group:)' do
|
112
|
+
subject { described_instance.controls group: {} }
|
113
|
+
|
114
|
+
it('defaults to an empty array') { is_expected.to eq [] }
|
115
|
+
end
|
116
|
+
|
117
|
+
describe '#evaluate(exit_code:)' do
|
118
|
+
subject { proc { described_instance.evaluate exit_code: exit_code } }
|
119
|
+
|
120
|
+
context 'when the exit code is 0' do
|
121
|
+
let(:exit_code) { 0 }
|
122
|
+
|
123
|
+
it('does not raise an error') { is_expected.to_not raise_error }
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'when the exit code is not 0' do
|
127
|
+
let(:exit_code) { 1 }
|
128
|
+
|
129
|
+
it('raises an error') { is_expected.to raise_error RuntimeError }
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe '#groups' do
|
134
|
+
subject { described_instance.groups }
|
135
|
+
|
136
|
+
it('defaults to an empty array') { is_expected.to eq [] }
|
137
|
+
end
|
138
|
+
|
139
|
+
describe '#initialize_runner(group:, hostname:, state:)' do
|
140
|
+
let(:group) { instance_double Object }
|
141
|
+
|
142
|
+
let(:hostname) { instance_double Object }
|
143
|
+
|
144
|
+
let(:inspec_runner) { instance_double Terraform::InspecRunner }
|
145
|
+
|
146
|
+
let :inspec_runner_class do
|
147
|
+
class_double(Terraform::InspecRunner).as_stubbed_const
|
148
|
+
end
|
149
|
+
|
150
|
+
let(:name) { instance_double Object }
|
151
|
+
|
152
|
+
let(:options) { instance_double Object }
|
153
|
+
|
154
|
+
let(:state) { instance_double Object }
|
155
|
+
|
156
|
+
let(:value) { instance_double Object }
|
157
|
+
|
158
|
+
before do
|
159
|
+
allow(described_instance).to receive(:runner_options_for_terraform)
|
160
|
+
.with(group: group, hostname: hostname, state: state).and_return options
|
161
|
+
|
162
|
+
allow(inspec_runner_class).to receive(:new).with(options)
|
163
|
+
.and_yield inspec_runner
|
164
|
+
|
165
|
+
allow(described_instance).to receive(:resolve_attributes)
|
166
|
+
.with(group: group).and_yield name, value
|
167
|
+
|
168
|
+
allow(inspec_runner).to receive(:define_attribute).with name: name,
|
169
|
+
value: value
|
170
|
+
|
171
|
+
allow(described_instance).to receive(:collect_tests).and_return []
|
172
|
+
|
173
|
+
allow(inspec_runner).to receive(:add).with targets: kind_of(Array)
|
174
|
+
end
|
175
|
+
|
176
|
+
subject do
|
177
|
+
lambda do |block|
|
178
|
+
described_instance.initialize_runner group: group, hostname: hostname,
|
179
|
+
state: state, &block
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'yields an InspecRunner for the group host' do
|
184
|
+
is_expected.to yield_with_args inspec_runner
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
describe '#port(group:)' do
|
189
|
+
include_context '#instance'
|
190
|
+
|
191
|
+
let(:group) { {} }
|
192
|
+
|
193
|
+
let(:port) { instance_double Object }
|
194
|
+
|
195
|
+
let(:transport_config) { { port: port } }
|
196
|
+
|
197
|
+
subject { described_instance.port group: group }
|
198
|
+
|
199
|
+
it 'defaults to the transport port configuration' do
|
200
|
+
is_expected.to be port
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
describe '#resolve_attributes(group:)' do
|
205
|
+
include_context '#client'
|
206
|
+
|
207
|
+
let(:method_name) { instance_double Object }
|
208
|
+
|
209
|
+
let(:output) { instance_double Object }
|
210
|
+
|
211
|
+
let(:variable_name) { instance_double Object }
|
212
|
+
|
213
|
+
before do
|
214
|
+
allow(client).to receive(:extract_output).with(name: variable_name)
|
215
|
+
.and_yield output
|
216
|
+
end
|
217
|
+
|
218
|
+
subject do
|
219
|
+
lambda do |block|
|
220
|
+
described_instance.resolve_attributes group:
|
221
|
+
{ attributes: { method_name => variable_name } }, &block
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'extracts an output value for each attribute pair in the group' do
|
226
|
+
is_expected.to yield_with_args method_name, output
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
describe '#runner_options_for_terraform(group:, hostname:, state:)' do
|
231
|
+
include_context '#instance'
|
232
|
+
|
233
|
+
let(:controls) { instance_double Object }
|
234
|
+
|
235
|
+
let(:group) { { controls: controls, port: port, username: username } }
|
236
|
+
|
237
|
+
let(:hostname) { instance_double Object }
|
238
|
+
|
239
|
+
let(:port) { instance_double Object }
|
240
|
+
|
241
|
+
let(:username) { instance_double Object }
|
242
|
+
|
243
|
+
before do
|
244
|
+
allow(described_instance).to receive(:runner_options)
|
245
|
+
.with(transport, state).and_return({})
|
246
|
+
end
|
247
|
+
|
248
|
+
subject do
|
249
|
+
described_instance.runner_options_for_terraform group: group,
|
250
|
+
hostname: hostname,
|
251
|
+
state: state
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'adds the group controls, host, port and user to the runner options' do
|
255
|
+
is_expected.to include controls: controls, host: hostname, port: port,
|
256
|
+
user: username
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
describe '#username(group:)' do
|
261
|
+
include_context '#instance'
|
262
|
+
|
263
|
+
let(:transport_config) { { username: username } }
|
264
|
+
|
265
|
+
let(:username) { instance_double Object }
|
266
|
+
|
267
|
+
before do
|
268
|
+
allow(transport_config).to receive(:fetch).with(:username)
|
269
|
+
.and_return username
|
270
|
+
end
|
271
|
+
|
272
|
+
subject { described_instance.username group: {} }
|
273
|
+
|
274
|
+
it('defaults to the transport username') { is_expected.to be username }
|
275
|
+
end
|
276
|
+
|
277
|
+
describe '#verify(group:, hostnames:, state:)' do
|
278
|
+
let(:group) { { name: instance_double(Object) } }
|
279
|
+
|
280
|
+
let(:hostname) { instance_double Object }
|
281
|
+
|
282
|
+
let(:runner) { instance_double Terraform::InspecRunner }
|
283
|
+
|
284
|
+
before do
|
285
|
+
allow(described_instance).to receive(:initialize_runner)
|
286
|
+
.with(group: group, hostname: hostname, state: state).and_yield runner
|
287
|
+
|
288
|
+
allow(runner).to receive(:verify_run).with verifier: described_instance
|
289
|
+
end
|
290
|
+
|
291
|
+
after do
|
292
|
+
described_instance.verify group: group, hostnames: [hostname],
|
293
|
+
state: state
|
294
|
+
end
|
295
|
+
|
296
|
+
subject { runner }
|
297
|
+
|
298
|
+
it 'verifies the Inspec run' do
|
299
|
+
is_expected.to receive(:verify_run).with verifier: described_instance
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2016 New Context Services, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'terraform/apply_command'
|
18
|
+
require 'support/terraform/command_examples'
|
19
|
+
|
20
|
+
RSpec.describe Terraform::ApplyCommand do
|
21
|
+
it_behaves_like Terraform::Command do
|
22
|
+
let(:command_options) { "-input=false -state=#{state}" }
|
23
|
+
|
24
|
+
let(:described_instance) { described_class.new state: state, plan: target }
|
25
|
+
|
26
|
+
let(:name) { 'apply' }
|
27
|
+
|
28
|
+
let(:state) { '<state_pathname>' }
|
29
|
+
|
30
|
+
let(:target) { '<plan_pathname>' }
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright 2016 New Context Services, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'kitchen/provisioner/terraform'
|
18
|
+
require 'terraform/client'
|
19
|
+
require 'terraform/command'
|
20
|
+
|
21
|
+
RSpec.describe Terraform::Client do
|
22
|
+
let(:described_instance) { described_class.new instance: instance }
|
23
|
+
|
24
|
+
let(:instance) { instance_double Kitchen::Instance }
|
25
|
+
|
26
|
+
let :instance_directory do
|
27
|
+
"#{kitchen_root}/.kitchen/kitchen-terraform/#{instance_name}"
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:instance_name) { '<instance_name>' }
|
31
|
+
|
32
|
+
let(:kitchen_root) { '<kitchen_root>' }
|
33
|
+
|
34
|
+
let :provisioner do
|
35
|
+
Kitchen::Provisioner::Terraform.new kitchen_root: kitchen_root
|
36
|
+
end
|
37
|
+
|
38
|
+
before do
|
39
|
+
allow(instance).to receive(:name).with(no_args).and_return instance_name
|
40
|
+
|
41
|
+
allow(instance).to receive(:provisioner).with(no_args)
|
42
|
+
.and_return provisioner
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#apply_execution_plan' do
|
46
|
+
after { described_instance.apply_execution_plan }
|
47
|
+
|
48
|
+
subject { described_instance }
|
49
|
+
|
50
|
+
it 'applies the plan to the state' do
|
51
|
+
is_expected.to receive(:run)
|
52
|
+
.with command_class: Terraform::ApplyCommand,
|
53
|
+
state: described_instance.state_pathname,
|
54
|
+
plan: described_instance.plan_pathname
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#download_modules' do
|
59
|
+
after { described_instance.download_modules }
|
60
|
+
|
61
|
+
subject { described_instance }
|
62
|
+
|
63
|
+
it 'downloads the modules required in the directory' do
|
64
|
+
is_expected.to receive(:run).with command_class: Terraform::GetCommand,
|
65
|
+
dir: described_instance.directory
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#extract_list_output(name:)' do
|
70
|
+
let(:name) { instance_double Object }
|
71
|
+
|
72
|
+
let(:output) { 'foo,bar' }
|
73
|
+
|
74
|
+
before do
|
75
|
+
allow(described_instance).to receive(:extract_output).with(name: name)
|
76
|
+
.and_yield output
|
77
|
+
end
|
78
|
+
|
79
|
+
subject do
|
80
|
+
->(block) { described_instance.extract_list_output name: name, &block }
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'splits and yields the extracted comma seperated output' do
|
84
|
+
is_expected.to yield_with_args %w(foo bar)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe '#extract_output(name:)' do
|
89
|
+
let(:name) { instance_double Object }
|
90
|
+
|
91
|
+
let(:output) { "foo\n" }
|
92
|
+
|
93
|
+
before do
|
94
|
+
allow(described_instance).to receive(:run).with(
|
95
|
+
command_class: Terraform::OutputCommand,
|
96
|
+
state: described_instance.state_pathname, name: name
|
97
|
+
).and_yield output
|
98
|
+
end
|
99
|
+
|
100
|
+
subject do
|
101
|
+
->(block) { described_instance.extract_output name: name, &block }
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'chomps and yields the extracted output from the state' do
|
105
|
+
is_expected.to yield_with_args 'foo'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe '#fetch_version' do
|
110
|
+
let(:output) { instance_double Object }
|
111
|
+
|
112
|
+
before do
|
113
|
+
allow(described_instance).to receive(:run)
|
114
|
+
.with(command_class: Terraform::VersionCommand).and_yield output
|
115
|
+
end
|
116
|
+
|
117
|
+
subject { ->(block) { described_instance.fetch_version(&block) } }
|
118
|
+
|
119
|
+
it 'yields the Terraform version' do
|
120
|
+
is_expected.to yield_with_args output
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe '#instance_directory' do
|
125
|
+
subject { described_instance.instance_directory.to_s }
|
126
|
+
|
127
|
+
it { is_expected.to eq instance_directory }
|
128
|
+
end
|
129
|
+
|
130
|
+
describe '#plan_destructive_execution' do
|
131
|
+
after { described_instance.plan_destructive_execution }
|
132
|
+
|
133
|
+
subject { described_instance }
|
134
|
+
|
135
|
+
it 'plans a destructive execution against the state' do
|
136
|
+
is_expected.to receive(:run)
|
137
|
+
.with command_class: Terraform::PlanCommand, destroy: true,
|
138
|
+
out: described_instance.plan_pathname,
|
139
|
+
state: described_instance.state_pathname,
|
140
|
+
var: described_instance.variables,
|
141
|
+
var_file: described_instance.variable_files,
|
142
|
+
dir: described_instance.directory
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe '#plan_execution' do
|
147
|
+
after { described_instance.plan_execution }
|
148
|
+
|
149
|
+
subject { described_instance }
|
150
|
+
|
151
|
+
it 'plans an execution against the state' do
|
152
|
+
is_expected.to receive(:run)
|
153
|
+
.with command_class: Terraform::PlanCommand, destroy: false,
|
154
|
+
out: described_instance.plan_pathname,
|
155
|
+
state: described_instance.state_pathname,
|
156
|
+
var: described_instance.variables,
|
157
|
+
var_file: described_instance.variable_files,
|
158
|
+
dir: described_instance.directory
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe '#plan_pathname' do
|
163
|
+
subject { described_instance.plan_pathname.to_s }
|
164
|
+
|
165
|
+
it { is_expected.to eq "#{instance_directory}/terraform.tfplan" }
|
166
|
+
end
|
167
|
+
|
168
|
+
describe '#run(command_class:, **parameters)' do
|
169
|
+
let(:command) { instance_double Terraform::Command }
|
170
|
+
|
171
|
+
let(:command_class) { Class.new.include Terraform::Command }
|
172
|
+
|
173
|
+
let(:output) { instance_double Object }
|
174
|
+
|
175
|
+
let(:parameters) { { foo: 'bar' } }
|
176
|
+
|
177
|
+
before do
|
178
|
+
allow(command_class).to receive(:new).with(**parameters)
|
179
|
+
.and_yield command
|
180
|
+
|
181
|
+
allow(command).to receive(:execute).with(no_args).and_yield output
|
182
|
+
end
|
183
|
+
|
184
|
+
subject do
|
185
|
+
lambda do |block|
|
186
|
+
described_instance.run command_class: command_class, **parameters,
|
187
|
+
&block
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
it('yields the command output') { is_expected.to yield_with_args output }
|
192
|
+
end
|
193
|
+
|
194
|
+
describe '#state_pathname' do
|
195
|
+
subject { described_instance.state_pathname.to_s }
|
196
|
+
|
197
|
+
it { is_expected.to eq "#{instance_directory}/terraform.tfstate" }
|
198
|
+
end
|
199
|
+
|
200
|
+
describe '#validate_configuration_files' do
|
201
|
+
after { described_instance.validate_configuration_files }
|
202
|
+
|
203
|
+
subject { described_instance }
|
204
|
+
|
205
|
+
it 'validates the configuration files in the directory' do
|
206
|
+
is_expected.to receive(:run)
|
207
|
+
.with command_class: Terraform::ValidateCommand,
|
208
|
+
dir: described_instance.directory
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|