beaker-docker 0.5.3 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,14 +1,6 @@
1
1
  require 'spec_helper'
2
2
  require 'fakefs/spec_helpers'
3
3
 
4
- # fake the docker-api
5
- module Docker
6
- class Image
7
- end
8
- class Container
9
- end
10
- end
11
-
12
4
  module Beaker
13
5
  platforms = [
14
6
  "ubuntu-14.04-x86_64",
@@ -20,6 +12,8 @@ module Beaker
20
12
  ]
21
13
 
22
14
  describe Docker do
15
+ require 'docker'
16
+
23
17
  let(:hosts) {
24
18
  the_hosts = make_hosts
25
19
  the_hosts[2]['dockeropts'] = {
@@ -60,14 +54,15 @@ module Beaker
60
54
  image
61
55
  end
62
56
 
63
- let(:container) do
64
- container = double('Docker::Container')
65
- allow( container ).to receive(:id).and_return('abcdef')
66
- allow( container ).to receive(:start)
67
- allow( container ).to receive(:info).and_return(
68
- *(0..2).map { |index| { 'Names' => ["/spec-container-#{index}"] } }
69
- )
70
- allow( container ).to receive(:json).and_return({
57
+ let(:container_mode) do
58
+ 'rootless'
59
+ end
60
+
61
+ let(:container_config) do
62
+ conf = {
63
+ 'HostConfig' => {
64
+ 'NetworkMode' => 'slirp4netns'
65
+ },
71
66
  'NetworkSettings' => {
72
67
  'IPAddress' => '192.0.2.1',
73
68
  'Ports' => {
@@ -80,7 +75,23 @@ module Beaker
80
75
  },
81
76
  'Gateway' => '192.0.2.254'
82
77
  }
83
- })
78
+ }
79
+
80
+ unless container_mode == 'rootless'
81
+ conf['HostConfig']['NetworkMode'] = 'bridge'
82
+ end
83
+
84
+ conf
85
+ end
86
+
87
+ let(:container) do
88
+ container = double('Docker::Container')
89
+ allow( container ).to receive(:id).and_return('abcdef')
90
+ allow( container ).to receive(:start)
91
+ allow( container ).to receive(:info).and_return(
92
+ *(0..2).map { |index| { 'Names' => ["/spec-container-#{index}"] } }
93
+ )
94
+ allow( container ).to receive(:json).and_return(container_config)
84
95
  allow( container ).to receive(:kill)
85
96
  allow( container ).to receive(:delete)
86
97
  allow( container ).to receive(:exec)
@@ -88,603 +99,617 @@ module Beaker
88
99
  end
89
100
 
90
101
  let (:docker) { ::Beaker::Docker.new( hosts, options ) }
102
+
91
103
  let(:docker_options) { nil }
104
+
92
105
  let (:version) { {"ApiVersion"=>"1.18", "Arch"=>"amd64", "GitCommit"=>"4749651", "GoVersion"=>"go1.4.2", "KernelVersion"=>"3.16.0-37-generic", "Os"=>"linux", "Version"=>"1.6.0"} }
93
106
 
94
- before :each do
95
- # Stub out all of the docker-api gem. we should never really call it
96
- # from these tests
97
- allow_any_instance_of( ::Beaker::Docker ).to receive(:require).with('docker')
98
- allow( ::Docker ).to receive(:options).and_return(docker_options)
99
- allow( ::Docker ).to receive(:options=)
100
- allow( ::Docker ).to receive(:logger=)
101
- allow( ::Docker ).to receive(:version).and_return(version)
102
- allow( ::Docker::Image ).to receive(:build).and_return(image)
103
- allow( ::Docker::Image ).to receive(:create).and_return(image)
104
- allow( ::Docker::Container ).to receive(:create).and_return(container)
105
- allow_any_instance_of( ::Docker::Container ).to receive(:start)
106
- end
107
+ context 'with connection failure' do
108
+ describe '#initialize' do
109
+ before :each do
110
+ require 'excon'
111
+ expect( ::Docker ).to receive(:version).and_raise(Excon::Errors::SocketError.new( StandardError.new('oops') )).exactly(4).times
112
+ end
107
113
 
108
- describe '#initialize, failure to validate' do
109
- before :each do
110
- require 'excon'
111
- allow( ::Docker ).to receive(:validate_version!).and_raise(Excon::Errors::SocketError.new( StandardError.new('oops') ))
112
- end
113
- it 'should fail when docker not present' do
114
- expect { docker }.to raise_error(RuntimeError, /Docker instance not connectable./)
115
- expect { docker }.to raise_error(RuntimeError, /Check your DOCKER_HOST variable has been set/)
116
- expect { docker }.to raise_error(RuntimeError, /If you are on OSX or Windows, you might not have Docker Machine setup correctly/)
117
- expect { docker }.to raise_error(RuntimeError, /Error was: oops/)
114
+ it 'should fail when docker not present' do
115
+ expect { docker }.to raise_error(RuntimeError, /Docker instance not connectable/)
116
+ expect { docker }.to raise_error(RuntimeError, /Check your DOCKER_HOST variable has been set/)
117
+ expect { docker }.to raise_error(RuntimeError, /If you are on OSX or Windows, you might not have Docker Machine setup correctly/)
118
+ expect { docker }.to raise_error(RuntimeError, /Error was: oops/)
119
+ end
118
120
  end
119
121
  end
120
122
 
121
- describe '#initialize' do
123
+
124
+ context 'with a working connection' do
122
125
  before :each do
123
- allow( ::Docker ).to receive(:validate_version!)
124
- end
126
+ # Stub out all of the docker-api gem. we should never really call it
127
+ # from these tests
128
+ allow_any_instance_of( ::Beaker::Docker ).to receive(:require).with('docker')
129
+ allow( ::Docker ).to receive(:options).and_return(docker_options)
130
+ allow( ::Docker ).to receive(:options=)
131
+ allow( ::Docker ).to receive(:logger=)
132
+ allow( ::Docker ).to receive(:version).and_return(version)
133
+ allow( ::Docker::Image ).to receive(:build).and_return(image)
134
+ allow( ::Docker::Image ).to receive(:create).and_return(image)
135
+ allow( ::Docker::Container ).to receive(:create).and_return(container)
136
+ allow_any_instance_of( ::Docker::Container ).to receive(:start)
137
+ end
138
+
139
+ describe '#initialize' do
140
+ it 'should require the docker gem' do
141
+ expect_any_instance_of( ::Beaker::Docker ).to receive(:require).with('docker').once
125
142
 
126
- it 'should require the docker gem' do
127
- expect_any_instance_of( ::Beaker::Docker ).to receive(:require).with('docker').once
143
+ docker
144
+ end
128
145
 
129
- docker
130
- end
146
+ it 'should fail when the gem is absent' do
147
+ allow_any_instance_of( ::Beaker::Docker ).to receive(:require).with('docker').and_raise(LoadError)
148
+ expect { docker }.to raise_error(LoadError)
149
+ end
131
150
 
132
- it 'should fail when the gem is absent' do
133
- allow_any_instance_of( ::Beaker::Docker ).to receive(:require).with('docker').and_raise(LoadError)
134
- expect { docker }.to raise_error(LoadError)
135
- end
151
+ it 'should set Docker options' do
152
+ expect( ::Docker ).to receive(:options=).with({:write_timeout => 300, :read_timeout => 300}).once
136
153
 
137
- it 'should set Docker options' do
138
- expect( ::Docker ).to receive(:options=).with({:write_timeout => 300, :read_timeout => 300}).once
154
+ docker
155
+ end
139
156
 
140
- docker
141
- end
157
+ context 'when Docker options are already set' do
158
+ let(:docker_options) {{:write_timeout => 600, :foo => :bar}}
142
159
 
143
- context 'when Docker options are already set' do
144
- let(:docker_options) {{:write_timeout => 600, :foo => :bar}}
160
+ it 'should not override Docker options' do
161
+ expect( ::Docker ).to receive(:options=).with({:write_timeout => 600, :read_timeout => 300, :foo => :bar}).once
145
162
 
146
- it 'should not override Docker options' do
147
- expect( ::Docker ).to receive(:options=).with({:write_timeout => 600, :read_timeout => 300, :foo => :bar}).once
163
+ docker
164
+ end
165
+ end
148
166
 
167
+ it 'should check the Docker gem can work with the api' do
149
168
  docker
150
169
  end
151
- end
152
170
 
153
- it 'should check the Docker gem can work with the api' do
154
- expect( ::Docker ).to receive(:validate_version!).once
171
+ it 'should hook the Beaker logger into the Docker one' do
172
+ expect( ::Docker ).to receive(:logger=).with(logger)
155
173
 
156
- docker
174
+ docker
175
+ end
157
176
  end
158
177
 
159
- it 'should hook the Beaker logger into the Docker one' do
160
- expect( ::Docker ).to receive(:logger=).with(logger)
161
-
162
- docker
163
- end
164
- end
178
+ describe '#install_ssh_components' do
179
+ let(:test_container) { double('container') }
180
+ let(:host) {hosts[0]}
181
+ before :each do
182
+ allow( docker ).to receive(:dockerfile_for)
183
+ end
165
184
 
166
- describe '#install_ssh_components' do
167
- let(:test_container) { double('container') }
168
- let(:host) {hosts[0]}
169
- before :each do
170
- allow( ::Docker ).to receive(:validate_version!)
171
- allow( docker ).to receive(:dockerfile_for)
172
- end
185
+ platforms.each do |platform|
186
+ it 'should call exec at least twice' do
187
+ host['platform'] = platform
188
+ expect(test_container).to receive(:exec).at_least(:twice)
189
+ docker.install_ssh_components(test_container, host)
190
+ end
191
+ end
173
192
 
174
- platforms.each do |platform|
175
- it 'should call exec at least twice' do
176
- host['platform'] = platform
193
+ it 'should accept alpine as valid platform' do
194
+ host['platform'] = 'alpine-3.8-x86_64'
177
195
  expect(test_container).to receive(:exec).at_least(:twice)
178
196
  docker.install_ssh_components(test_container, host)
179
197
  end
180
- end
181
198
 
182
- it 'should accept alpine as valid platform' do
183
- host['platform'] = 'alpine-3.8-x86_64'
184
- expect(test_container).to receive(:exec).at_least(:twice)
185
- docker.install_ssh_components(test_container, host)
199
+ it 'should raise an error with an unsupported platform' do
200
+ host['platform'] = 'boogeyman-2000-x86_64'
201
+ expect{docker.install_ssh_components(test_container, host)}.to raise_error(RuntimeError, /boogeyman/)
202
+ end
186
203
  end
187
204
 
188
- it 'should raise an error with an unsupported platform' do
189
- host['platform'] = 'boogeyman-2000-x86_64'
190
- expect{docker.install_ssh_components(test_container, host)}.to raise_error(RuntimeError, /boogeyman/)
191
- end
192
- end
205
+ describe '#provision' do
206
+ before :each do
207
+ allow( docker ).to receive(:dockerfile_for)
208
+ end
193
209
 
194
- describe '#provision' do
195
- before :each do
196
- allow( ::Docker ).to receive(:validate_version!)
197
- allow( docker ).to receive(:dockerfile_for)
198
- end
210
+ context 'when the host has "tag" defined' do
211
+ before :each do
212
+ hosts.each do |host|
213
+ host['tag'] = 'my_tag'
214
+ end
215
+ end
199
216
 
200
- context 'when the host has "tag" defined' do
201
- before :each do
202
- hosts.each do |host|
203
- host['tag'] = 'my_tag'
217
+ it 'will tag the image with the value of the tag' do
218
+ expect( image ).to receive(:tag).with({:repo => 'my_tag'}).exactly(3).times
219
+ docker.provision
204
220
  end
205
221
  end
206
222
 
207
- it 'will tag the image with the value of the tag' do
208
- expect( image ).to receive(:tag).with({:repo => 'my_tag'}).exactly(3).times
209
- docker.provision
210
- end
211
- end
223
+ context 'when the host has "use_image_entry_point" set to true on the host' do
212
224
 
213
- context 'when the host has "use_image_entry_point" set to true on the host' do
225
+ before :each do
226
+ hosts.each do |host|
227
+ host['use_image_entry_point'] = true
228
+ end
229
+ end
214
230
 
215
- before :each do
216
- hosts.each do |host|
217
- host['use_image_entry_point'] = true
231
+ it 'should not call #dockerfile_for but run methods necessary for ssh installation' do
232
+ expect( docker ).not_to receive(:dockerfile_for)
233
+ expect( docker ).to receive(:install_ssh_components).exactly(3).times #once per host
234
+ expect( docker ).to receive(:fix_ssh).exactly(3).times #once per host
235
+ docker.provision
218
236
  end
219
237
  end
220
238
 
221
- it 'should not call #dockerfile_for but run methods necessary for ssh installation' do
222
- expect( docker ).not_to receive(:dockerfile_for)
223
- expect( docker ).to receive(:install_ssh_components).exactly(3).times #once per host
224
- expect( docker ).to receive(:fix_ssh).exactly(3).times #once per host
225
- docker.provision
226
- end
227
- end
239
+ context 'when the host has a "dockerfile" for the host' do
228
240
 
229
- context 'when the host has a "dockerfile" for the host' do
241
+ before :each do
242
+ allow( docker ).to receive(:buildargs_for).and_return('buildargs')
243
+ hosts.each do |host|
244
+ host['dockerfile'] = 'mydockerfile'
245
+ end
246
+ end
230
247
 
231
- before :each do
232
- allow( docker ).to receive(:buildargs_for).and_return('buildargs')
233
- hosts.each do |host|
234
- host['dockerfile'] = 'mydockerfile'
248
+ it 'should not call #dockerfile_for but run methods necessary for ssh installation' do
249
+ allow( File ).to receive(:exist?).with('mydockerfile').and_return(true)
250
+ allow( ::Docker::Image ).to receive(:build_from_dir).with("/", hash_including(:rm => true, :buildargs => 'buildargs')).and_return(image)
251
+ expect( docker ).not_to receive(:dockerfile_for)
252
+ expect( docker ).to receive(:install_ssh_components).exactly(3).times #once per host
253
+ expect( docker ).to receive(:fix_ssh).exactly(3).times #once per host
254
+ docker.provision
235
255
  end
236
256
  end
237
257
 
238
- it 'should not call #dockerfile_for but run methods necessary for ssh installation' do
239
- allow( File ).to receive(:exist?).with('mydockerfile').and_return(true)
240
- allow( ::Docker::Image ).to receive(:build_from_dir).with("/", hash_including(:rm => true, :buildargs => 'buildargs')).and_return(image)
241
- expect( docker ).not_to receive(:dockerfile_for)
242
- expect( docker ).to receive(:install_ssh_components).exactly(3).times #once per host
243
- expect( docker ).to receive(:fix_ssh).exactly(3).times #once per host
244
- docker.provision
245
- end
246
- end
258
+ it 'should call image create for hosts when use_image_as_is is defined' do
259
+ hosts.each do |host|
260
+ host['use_image_as_is'] = true
261
+ expect( docker ).not_to receive(:install_ssh_components)
262
+ expect( docker ).not_to receive(:fix_ssh)
263
+ expect( ::Docker::Image ).to receive(:create).with('fromImage' => host['image']) #once per host
264
+ expect( ::Docker::Image ).not_to receive(:build)
265
+ expect( ::Docker::Image ).not_to receive(:build_from_dir)
266
+ end
247
267
 
248
- it 'should call image create for hosts when use_image_as_is is defined' do
249
- hosts.each do |host|
250
- host['use_image_as_is'] = true
251
- expect( docker ).not_to receive(:install_ssh_components)
252
- expect( docker ).not_to receive(:fix_ssh)
253
- expect( ::Docker::Image ).to receive(:create).with('fromImage' => host['image']) #once per host
254
- expect( ::Docker::Image ).not_to receive(:build)
255
- expect( ::Docker::Image ).not_to receive(:build_from_dir)
268
+ docker.provision
256
269
  end
257
270
 
258
- docker.provision
259
- end
271
+ it 'should call dockerfile_for with all the hosts' do
272
+ hosts.each do |host|
273
+ expect( docker ).not_to receive(:install_ssh_components)
274
+ expect( docker ).not_to receive(:fix_ssh)
275
+ expect( docker ).to receive(:dockerfile_for).with(host).and_return('')
276
+ end
260
277
 
261
- it 'should call dockerfile_for with all the hosts' do
262
- hosts.each do |host|
263
- expect( docker ).not_to receive(:install_ssh_components)
264
- expect( docker ).not_to receive(:fix_ssh)
265
- expect( docker ).to receive(:dockerfile_for).with(host).and_return('')
278
+ docker.provision
266
279
  end
267
280
 
268
- docker.provision
269
- end
281
+ it 'should pass the Dockerfile on to Docker::Image.create' do
282
+ allow( docker ).to receive(:dockerfile_for).and_return('special testing value')
283
+ expect( ::Docker::Image ).to receive(:build).with('special testing value', { :rm => true, :buildargs => '{}' })
270
284
 
271
- it 'should pass the Dockerfile on to Docker::Image.create' do
272
- allow( docker ).to receive(:dockerfile_for).and_return('special testing value')
273
- expect( ::Docker::Image ).to receive(:build).with('special testing value', { :rm => true, :buildargs => '{}' })
274
-
275
- docker.provision
276
- end
285
+ docker.provision
286
+ end
277
287
 
278
- it 'should pass the buildargs from ENV DOCKER_BUILDARGS on to Docker::Image.create' do
279
- allow( docker ).to receive(:dockerfile_for).and_return('special testing value')
280
- ENV['DOCKER_BUILDARGS'] = 'HTTP_PROXY=http://1.1.1.1:3128'
281
- expect( ::Docker::Image ).to receive(:build).with('special testing value', { :rm => true, :buildargs => "{\"HTTP_PROXY\":\"http://1.1.1.1:3128\"}" })
288
+ it 'should pass the buildargs from ENV DOCKER_BUILDARGS on to Docker::Image.create' do
289
+ allow( docker ).to receive(:dockerfile_for).and_return('special testing value')
290
+ ENV['DOCKER_BUILDARGS'] = 'HTTP_PROXY=http://1.1.1.1:3128'
291
+ expect( ::Docker::Image ).to receive(:build).with('special testing value', { :rm => true, :buildargs => "{\"HTTP_PROXY\":\"http://1.1.1.1:3128\"}" })
282
292
 
283
- docker.provision
284
- end
293
+ docker.provision
294
+ end
285
295
 
286
- it 'should create a container based on the Image (identified by image.id)' do
287
- hosts.each do |host|
288
- expect( ::Docker::Container ).to receive(:create).with({
289
- 'Image' => image.id,
290
- 'Hostname' => host.name,
291
- 'HostConfig' => {
292
- 'PortBindings' => {
293
- '22/tcp' => [{ 'HostPort' => /\b\d{4}\b/, 'HostIp' => '0.0.0.0'}]
296
+ it 'should create a container based on the Image (identified by image.id)' do
297
+ hosts.each_with_index do |host,index|
298
+ expect( ::Docker::Container ).to receive(:create).with({
299
+ 'Image' => image.id,
300
+ 'Hostname' => host.name,
301
+ 'HostConfig' => {
302
+ 'PortBindings' => {
303
+ '22/tcp' => [{ 'HostPort' => /\b\d{4}\b/, 'HostIp' => '0.0.0.0'}]
304
+ },
305
+ 'PublishAllPorts' => true,
306
+ 'RestartPolicy' => {
307
+ 'Name' => 'always'
308
+ }
294
309
  },
295
- 'PublishAllPorts' => true,
296
- 'Privileged' => true,
297
- 'RestartPolicy' => {
298
- 'Name' => 'always'
299
- }
300
- },
301
- 'Labels' => {
302
- 'one' => 1,
303
- 'two' => 2,
304
- },
305
- }).with(hash_excluding('name'))
306
- end
310
+ 'Labels' => {
311
+ 'one' => (index == 2 ? 3 : 1),
312
+ 'two' => (index == 2 ? 4 : 2),
313
+ },
314
+ 'name' => /\Abeaker-/
315
+ })
316
+ end
307
317
 
308
- docker.provision
309
- end
318
+ docker.provision
319
+ end
310
320
 
311
- it 'should pass the multiple buildargs from ENV DOCKER_BUILDARGS on to Docker::Image.create' do
312
- allow( docker ).to receive(:dockerfile_for).and_return('special testing value')
313
- ENV['DOCKER_BUILDARGS'] = 'HTTP_PROXY=http://1.1.1.1:3128 HTTPS_PROXY=https://1.1.1.1:3129'
314
- expect( ::Docker::Image ).to receive(:build).with('special testing value', { :rm => true, :buildargs => "{\"HTTP_PROXY\":\"http://1.1.1.1:3128\",\"HTTPS_PROXY\":\"https://1.1.1.1:3129\"}" })
321
+ it 'should pass the multiple buildargs from ENV DOCKER_BUILDARGS on to Docker::Image.create' do
322
+ allow( docker ).to receive(:dockerfile_for).and_return('special testing value')
323
+ ENV['DOCKER_BUILDARGS'] = 'HTTP_PROXY=http://1.1.1.1:3128 HTTPS_PROXY=https://1.1.1.1:3129'
324
+ expect( ::Docker::Image ).to receive(:build).with('special testing value', { :rm => true, :buildargs => "{\"HTTP_PROXY\":\"http://1.1.1.1:3128\",\"HTTPS_PROXY\":\"https://1.1.1.1:3129\"}" })
315
325
 
316
- docker.provision
317
- end
326
+ docker.provision
327
+ end
318
328
 
319
- it 'should create a container based on the Image (identified by image.id)' do
320
- hosts.each do |host|
321
- expect( ::Docker::Container ).to receive(:create).with({
322
- 'Image' => image.id,
323
- 'Hostname' => host.name,
324
- 'HostConfig' => {
325
- 'PortBindings' => {
326
- '22/tcp' => [{ 'HostPort' => /\b\d{4}\b/, 'HostIp' => '0.0.0.0'}]
329
+ it 'should create a container based on the Image (identified by image.id)' do
330
+ hosts.each_with_index do |host,index|
331
+ expect( ::Docker::Container ).to receive(:create).with({
332
+ 'Image' => image.id,
333
+ 'Hostname' => host.name,
334
+ 'HostConfig' => {
335
+ 'PortBindings' => {
336
+ '22/tcp' => [{ 'HostPort' => /\b\d{4}\b/, 'HostIp' => '0.0.0.0'}]
337
+ },
338
+ 'PublishAllPorts' => true,
339
+ 'RestartPolicy' => {
340
+ 'Name' => 'always'
341
+ }
327
342
  },
328
- 'PublishAllPorts' => true,
329
- 'Privileged' => true,
330
- 'RestartPolicy' => {
331
- 'Name' => 'always'
332
- }
333
- },
334
- 'Labels' => {
335
- 'one' => 1,
336
- 'two' => 2,
337
- },
338
- }).with(hash_excluding('name'))
343
+ 'Labels' => {
344
+ 'one' => (index == 2 ? 3 : 1),
345
+ 'two' => (index == 2 ? 4 : 2),
346
+ },
347
+ 'name' => /\Abeaker-/
348
+ })
349
+ end
350
+
351
+ docker.provision
339
352
  end
340
353
 
341
- docker.provision
342
- end
354
+ it 'should create a named container based on the Image (identified by image.id)' do
355
+ hosts.each_with_index do |host, index|
356
+ container_name = "spec-container-#{index}"
357
+ host['docker_container_name'] = container_name
343
358
 
344
- it 'should create a named container based on the Image (identified by image.id)' do
345
- hosts.each_with_index do |host, index|
346
- container_name = "spec-container-#{index}"
347
- host['docker_container_name'] = container_name
348
-
349
- allow(::Docker::Container).to receive(:all).and_return([])
350
- expect( ::Docker::Container ).to receive(:create).with({
351
- 'Image' => image.id,
352
- 'Hostname' => host.name,
353
- 'name' => container_name,
354
- 'HostConfig' => {
355
- 'PortBindings' => {
356
- '22/tcp' => [{ 'HostPort' => /\b\d{4}\b/, 'HostIp' => '0.0.0.0'}]
359
+ allow(::Docker::Container).to receive(:all).and_return([])
360
+ expect( ::Docker::Container ).to receive(:create).with({
361
+ 'Image' => image.id,
362
+ 'Hostname' => host.name,
363
+ 'name' => container_name,
364
+ 'HostConfig' => {
365
+ 'PortBindings' => {
366
+ '22/tcp' => [{ 'HostPort' => /\b\d{4}\b/, 'HostIp' => '0.0.0.0'}]
367
+ },
368
+ 'PublishAllPorts' => true,
369
+ 'RestartPolicy' => {
370
+ 'Name' => 'always'
371
+ }
357
372
  },
358
- 'PublishAllPorts' => true,
359
- 'Privileged' => true,
360
- 'RestartPolicy' => {
361
- 'Name' => 'always'
362
- }
363
- },
364
- 'Labels' => {
365
- 'one' => (index == 2 ? 3 : 1),
366
- 'two' => (index == 2 ? 4 : 2),
367
- },
368
- })
369
- end
373
+ 'Labels' => {
374
+ 'one' => (index == 2 ? 3 : 1),
375
+ 'two' => (index == 2 ? 4 : 2),
376
+ },
377
+ })
378
+ end
370
379
 
371
- docker.provision
372
- end
380
+ docker.provision
381
+ end
373
382
 
374
383
 
375
- it 'should create a container with volumes bound' do
376
- hosts.each_with_index do |host, index|
377
- host['mount_folders'] = {
378
- 'mount1' => {
379
- 'host_path' => '/source_folder',
380
- 'container_path' => '/mount_point',
381
- },
382
- 'mount2' => {
383
- 'host_path' => '/another_folder',
384
- 'container_path' => '/another_mount',
385
- 'opts' => 'ro',
386
- },
387
- 'mount3' => {
388
- 'host_path' => '/different_folder',
389
- 'container_path' => '/different_mount',
390
- 'opts' => 'rw',
391
- },
392
- 'mount4' => {
393
- 'host_path' => './',
394
- 'container_path' => '/relative_mount',
395
- },
396
- 'mount5' => {
397
- 'host_path' => 'local_folder',
398
- 'container_path' => '/another_relative_mount',
399
- }
400
- }
401
-
402
- expect( ::Docker::Container ).to receive(:create).with({
403
- 'Image' => image.id,
404
- 'Hostname' => host.name,
405
- 'HostConfig' => {
406
- 'Binds' => [
407
- '/source_folder:/mount_point',
408
- '/another_folder:/another_mount:ro',
409
- '/different_folder:/different_mount:rw',
410
- "#{File.expand_path('./')}:/relative_mount",
411
- "#{File.expand_path('local_folder')}:/another_relative_mount",
412
- ],
413
- 'PortBindings' => {
414
- '22/tcp' => [{ 'HostPort' => /\b\d{4}\b/, 'HostIp' => '0.0.0.0'}]
384
+ it 'should create a container with volumes bound' do
385
+ hosts.each_with_index do |host, index|
386
+ host['mount_folders'] = {
387
+ 'mount1' => {
388
+ 'host_path' => '/source_folder',
389
+ 'container_path' => '/mount_point',
390
+ },
391
+ 'mount2' => {
392
+ 'host_path' => '/another_folder',
393
+ 'container_path' => '/another_mount',
394
+ 'opts' => 'ro',
415
395
  },
416
- 'PublishAllPorts' => true,
417
- 'Privileged' => true,
418
- 'RestartPolicy' => {
419
- 'Name' => 'always'
396
+ 'mount3' => {
397
+ 'host_path' => '/different_folder',
398
+ 'container_path' => '/different_mount',
399
+ 'opts' => 'rw',
400
+ },
401
+ 'mount4' => {
402
+ 'host_path' => './',
403
+ 'container_path' => '/relative_mount',
404
+ },
405
+ 'mount5' => {
406
+ 'host_path' => 'local_folder',
407
+ 'container_path' => '/another_relative_mount',
420
408
  }
421
- },
422
- 'Labels' => {
423
- 'one' => (index == 2 ? 3 : 1),
424
- 'two' => (index == 2 ? 4 : 2),
425
- },
426
- })
427
- end
409
+ }
428
410
 
429
- docker.provision
430
- end
411
+ expect( ::Docker::Container ).to receive(:create).with({
412
+ 'Image' => image.id,
413
+ 'Hostname' => host.name,
414
+ 'HostConfig' => {
415
+ 'Binds' => [
416
+ '/source_folder:/mount_point:z',
417
+ '/another_folder:/another_mount:ro',
418
+ '/different_folder:/different_mount:rw',
419
+ "#{File.expand_path('./')}:/relative_mount:z",
420
+ "#{File.expand_path('local_folder')}:/another_relative_mount:z",
421
+ ],
422
+ 'PortBindings' => {
423
+ '22/tcp' => [{ 'HostPort' => /\b\d{4}\b/, 'HostIp' => '0.0.0.0'}]
424
+ },
425
+ 'PublishAllPorts' => true,
426
+ 'RestartPolicy' => {
427
+ 'Name' => 'always'
428
+ }
429
+ },
430
+ 'Labels' => {
431
+ 'one' => (index == 2 ? 3 : 1),
432
+ 'two' => (index == 2 ? 4 : 2),
433
+ },
434
+ 'name' => /\Abeaker-/
435
+ })
436
+ end
431
437
 
432
- it 'should create a container with capabilities added' do
433
- hosts.each_with_index do |host, index|
434
- host['docker_cap_add'] = ['NET_ADMIN', 'SYS_ADMIN']
438
+ docker.provision
439
+ end
435
440
 
436
- expect( ::Docker::Container ).to receive(:create).with({
437
- 'Image' => image.id,
438
- 'Hostname' => host.name,
439
- 'HostConfig' => {
440
- 'PortBindings' => {
441
- '22/tcp' => [{ 'HostPort' => /\b\d{4}\b/, 'HostIp' => '0.0.0.0'}]
441
+ it 'should create a container with capabilities added' do
442
+ hosts.each_with_index do |host, index|
443
+ host['docker_cap_add'] = ['NET_ADMIN', 'SYS_ADMIN']
444
+
445
+ expect( ::Docker::Container ).to receive(:create).with({
446
+ 'Image' => image.id,
447
+ 'Hostname' => host.name,
448
+ 'HostConfig' => {
449
+ 'PortBindings' => {
450
+ '22/tcp' => [{ 'HostPort' => /\b\d{4}\b/, 'HostIp' => '0.0.0.0'}]
451
+ },
452
+ 'PublishAllPorts' => true,
453
+ 'RestartPolicy' => {
454
+ 'Name' => 'always'
455
+ },
456
+ 'CapAdd' => ['NET_ADMIN', 'SYS_ADMIN']
442
457
  },
443
- 'PublishAllPorts' => true,
444
- 'Privileged' => true,
445
- 'RestartPolicy' => {
446
- 'Name' => 'always'
458
+ 'Labels' => {
459
+ 'one' => (index == 2 ? 3 : 1),
460
+ 'two' => (index == 2 ? 4 : 2),
447
461
  },
448
- 'CapAdd' => ['NET_ADMIN', 'SYS_ADMIN']
449
- },
450
- 'Labels' => {
451
- 'one' => (index == 2 ? 3 : 1),
452
- 'two' => (index == 2 ? 4 : 2),
453
- },
454
- })
462
+ 'name' => /\Abeaker-/
463
+ })
464
+ end
465
+
466
+ docker.provision
455
467
  end
456
468
 
457
- docker.provision
458
- end
469
+ it 'should start the container' do
470
+ expect( container ).to receive(:start)
459
471
 
460
- it 'should start the container' do
461
- expect( container ).to receive(:start)
472
+ docker.provision
473
+ end
462
474
 
463
- docker.provision
464
- end
475
+ context "connecting to ssh" do
476
+ context "rootless" do
477
+ before { @docker_host = ENV['DOCKER_HOST'] }
478
+ after { ENV['DOCKER_HOST'] = @docker_host }
479
+
480
+ it 'should expose port 22 to beaker' do
481
+ ENV['DOCKER_HOST'] = nil
482
+ docker.provision
483
+
484
+ expect( hosts[0]['ip'] ).to be === '127.0.1.1'
485
+ expect( hosts[0]['port'] ).to be === 8022
486
+ end
487
+
488
+ it 'should expose port 22 to beaker when using DOCKER_HOST' do
489
+ ENV['DOCKER_HOST'] = "tcp://192.0.2.2:2375"
490
+ docker.provision
491
+
492
+ expect( hosts[0]['ip'] ).to be === '192.0.2.2'
493
+ expect( hosts[0]['port'] ).to be === 8022
494
+ end
495
+
496
+ it 'should have ssh agent forwarding enabled' do
497
+ ENV['DOCKER_HOST'] = nil
498
+ docker.provision
499
+
500
+ expect( hosts[0]['ip'] ).to be === '127.0.1.1'
501
+ expect( hosts[0]['port'] ).to be === 8022
502
+ expect( hosts[0]['ssh'][:password] ).to be === 'root'
503
+ expect( hosts[0]['ssh'][:port] ).to be === 8022
504
+ expect( hosts[0]['ssh'][:forward_agent] ).to be === true
505
+ end
506
+
507
+ it 'should connect to gateway ip' do
508
+ FakeFS do
509
+ File.open('/.dockerenv', 'w') { }
510
+ docker.provision
511
+
512
+ expect( hosts[0]['ip'] ).to be === '192.0.2.254'
513
+ expect( hosts[0]['port'] ).to be === 8022
514
+ end
515
+ end
516
+ end
465
517
 
466
- context "connecting to ssh" do
467
- before { @docker_host = ENV['DOCKER_HOST'] }
468
- after { ENV['DOCKER_HOST'] = @docker_host }
518
+ context 'rootful' do
519
+ before { @docker_host = ENV['DOCKER_HOST'] }
520
+ after { ENV['DOCKER_HOST'] = @docker_host }
469
521
 
470
- it 'should expose port 22 to beaker' do
471
- ENV['DOCKER_HOST'] = nil
472
- docker.provision
522
+ let(:container_mode) do
523
+ 'rootful'
524
+ end
473
525
 
474
- expect( hosts[0]['ip'] ).to be === '127.0.1.1'
475
- expect( hosts[0]['port'] ).to be === 8022
476
- end
526
+ it 'should expose port 22 to beaker' do
527
+ ENV['DOCKER_HOST'] = nil
528
+ docker.provision
477
529
 
478
- it 'should expose port 22 to beaker when using DOCKER_HOST' do
479
- ENV['DOCKER_HOST'] = "tcp://192.0.2.2:2375"
480
- docker.provision
530
+ expect( hosts[0]['ip'] ).to be === '192.0.2.1'
531
+ expect( hosts[0]['port'] ).to be === '22'
532
+ end
533
+ end
481
534
 
482
- expect( hosts[0]['ip'] ).to be === '192.0.2.2'
483
- expect( hosts[0]['port'] ).to be === 8022
484
535
  end
485
536
 
486
- it 'should have ssh agent forwarding enabled' do
537
+ it "should generate a new /etc/hosts file referencing each host" do
487
538
  ENV['DOCKER_HOST'] = nil
488
539
  docker.provision
489
-
490
- expect( hosts[0]['ip'] ).to be === '127.0.1.1'
491
- expect( hosts[0]['port'] ).to be === 8022
492
- expect( hosts[0]['ssh'][:password] ).to be === 'root'
493
- expect( hosts[0]['ssh'][:port] ).to be === 8022
494
- expect( hosts[0]['ssh'][:forward_agent] ).to be === true
495
- end
496
-
497
- it 'should connect to gateway ip' do
498
- FakeFS do
499
- File.open('/.dockerenv', 'w') { }
500
- docker.provision
501
-
502
- expect( hosts[0]['ip'] ).to be === '192.0.2.254'
503
- expect( hosts[0]['port'] ).to be === 8022
540
+ hosts.each do |host|
541
+ expect( docker ).to receive( :get_domain_name ).with( host ).and_return( 'labs.lan' )
542
+ expect( docker ).to receive( :set_etc_hosts ).with( host, "127.0.0.1\tlocalhost localhost.localdomain\n192.0.2.1\tvm1.labs.lan vm1\n192.0.2.1\tvm2.labs.lan vm2\n192.0.2.1\tvm3.labs.lan vm3\n" ).once
504
543
  end
544
+ docker.hack_etc_hosts( hosts, options )
505
545
  end
506
546
 
507
- end
547
+ it 'should record the image and container for later' do
548
+ docker.provision
508
549
 
509
- it "should generate a new /etc/hosts file referencing each host" do
510
- ENV['DOCKER_HOST'] = nil
511
- docker.provision
512
- hosts.each do |host|
513
- expect( docker ).to receive( :get_domain_name ).with( host ).and_return( 'labs.lan' )
514
- expect( docker ).to receive( :set_etc_hosts ).with( host, "127.0.0.1\tlocalhost localhost.localdomain\n192.0.2.1\tvm1.labs.lan vm1\n192.0.2.1\tvm2.labs.lan vm2\n192.0.2.1\tvm3.labs.lan vm3\n" ).once
550
+ expect( hosts[0]['docker_image_id'] ).to be === image.id
551
+ expect( hosts[0]['docker_container_id'] ).to be === container.id
515
552
  end
516
- docker.hack_etc_hosts( hosts, options )
517
- end
518
-
519
- it 'should record the image and container for later' do
520
- docker.provision
521
553
 
522
- expect( hosts[0]['docker_image_id'] ).to be === image.id
523
- expect( hosts[0]['docker_container_id'] ).to be === container.id
524
- end
554
+ context 'provision=false' do
555
+ let(:options) {{
556
+ :logger => logger,
557
+ :forward_ssh_agent => true,
558
+ :provision => false
559
+ }}
525
560
 
526
- context 'provision=false' do
527
- let(:options) {{
528
- :logger => logger,
529
- :forward_ssh_agent => true,
530
- :provision => false
531
- }}
532
561
 
562
+ it 'should fix ssh' do
563
+ hosts.each_with_index do |host, index|
564
+ container_name = "spec-container-#{index}"
565
+ host['docker_container_name'] = container_name
533
566
 
534
- it 'should fix ssh' do
535
- hosts.each_with_index do |host, index|
536
- container_name = "spec-container-#{index}"
537
- host['docker_container_name'] = container_name
538
-
539
- expect( ::Docker::Container ).to receive(:all).and_return([container])
540
- expect(docker).to receive(:fix_ssh).exactly(1).times
567
+ expect( ::Docker::Container ).to receive(:all).and_return([container])
568
+ expect(docker).to receive(:fix_ssh).exactly(1).times
569
+ end
570
+ docker.provision
541
571
  end
542
- docker.provision
543
- end
544
572
 
545
- it 'should not create a container if a named one already exists' do
546
- hosts.each_with_index do |host, index|
547
- container_name = "spec-container-#{index}"
548
- host['docker_container_name'] = container_name
573
+ it 'should not create a container if a named one already exists' do
574
+ hosts.each_with_index do |host, index|
575
+ container_name = "spec-container-#{index}"
576
+ host['docker_container_name'] = container_name
549
577
 
550
- expect( ::Docker::Container ).to receive(:all).and_return([container])
551
- expect( ::Docker::Container ).not_to receive(:create)
552
- end
578
+ expect( ::Docker::Container ).to receive(:all).and_return([container])
579
+ expect( ::Docker::Container ).not_to receive(:create)
580
+ end
553
581
 
554
- docker.provision
582
+ docker.provision
583
+ end
555
584
  end
556
585
  end
557
- end
558
586
 
559
- describe '#cleanup' do
560
- before :each do
561
- # get into a state where there's something to clean
562
- allow( ::Docker ).to receive(:validate_version!)
563
- allow( ::Docker::Container ).to receive(:all).and_return([container])
564
- allow( ::Docker::Image ).to receive(:remove).with(image.id)
565
- allow( docker ).to receive(:dockerfile_for)
566
- docker.provision
567
- end
568
-
569
- it 'should stop the containers' do
570
- allow( docker ).to receive( :sleep ).and_return(true)
571
- expect( container ).to receive(:kill)
572
- docker.cleanup
573
- end
587
+ describe '#cleanup' do
588
+ before :each do
589
+ # get into a state where there's something to clean
590
+ allow( ::Docker::Container ).to receive(:all).and_return([container])
591
+ allow( ::Docker::Image ).to receive(:remove).with(image.id)
592
+ allow( docker ).to receive(:dockerfile_for)
593
+ docker.provision
594
+ end
574
595
 
575
- it 'should delete the containers' do
576
- allow( docker ).to receive( :sleep ).and_return(true)
577
- expect( container ).to receive(:delete)
578
- docker.cleanup
579
- end
596
+ it 'should stop the containers' do
597
+ allow( docker ).to receive( :sleep ).and_return(true)
598
+ expect( container ).to receive(:kill)
599
+ docker.cleanup
600
+ end
580
601
 
581
- it 'should delete the images' do
582
- allow( docker ).to receive( :sleep ).and_return(true)
583
- expect( ::Docker::Image ).to receive(:remove).with(image.id)
584
- docker.cleanup
585
- end
602
+ it 'should delete the containers' do
603
+ allow( docker ).to receive( :sleep ).and_return(true)
604
+ expect( container ).to receive(:delete)
605
+ docker.cleanup
606
+ end
586
607
 
587
- it 'should not delete the image if docker_preserve_image is set to true' do
588
- allow( docker ).to receive( :sleep ).and_return(true)
589
- hosts.each do |host|
590
- host['docker_preserve_image']=true
608
+ it 'should delete the images' do
609
+ allow( docker ).to receive( :sleep ).and_return(true)
610
+ expect( ::Docker::Image ).to receive(:remove).with(image.id)
611
+ docker.cleanup
591
612
  end
592
- expect( ::Docker::Image ).to_not receive(:remove)
593
- docker.cleanup
594
- end
595
613
 
596
- it 'should delete the image if docker_preserve_image is set to false' do
597
- allow( docker ).to receive( :sleep ).and_return(true)
598
- hosts.each do |host|
599
- host['docker_preserve_image']=false
614
+ it 'should not delete the image if docker_preserve_image is set to true' do
615
+ allow( docker ).to receive( :sleep ).and_return(true)
616
+ hosts.each do |host|
617
+ host['docker_preserve_image']=true
618
+ end
619
+ expect( ::Docker::Image ).to_not receive(:remove)
620
+ docker.cleanup
600
621
  end
601
- expect( ::Docker::Image ).to receive(:remove).with(image.id)
602
- docker.cleanup
603
- end
604
622
 
605
- end
623
+ it 'should delete the image if docker_preserve_image is set to false' do
624
+ allow( docker ).to receive( :sleep ).and_return(true)
625
+ hosts.each do |host|
626
+ host['docker_preserve_image']=false
627
+ end
628
+ expect( ::Docker::Image ).to receive(:remove).with(image.id)
629
+ docker.cleanup
630
+ end
606
631
 
607
- describe '#dockerfile_for' do
608
- FakeFS.deactivate!
609
- before :each do
610
- allow( ::Docker ).to receive(:validate_version!)
611
- end
612
- it 'should raise on an unsupported platform' do
613
- expect { docker.send(:dockerfile_for, {'platform' => 'a_sidewalk', 'image' => 'foobar' }) }.to raise_error(/platform a_sidewalk not yet supported/)
614
632
  end
615
633
 
616
- it 'should set "ENV container docker"' do
634
+ describe '#dockerfile_for' do
617
635
  FakeFS.deactivate!
618
- platforms.each do |platform|
619
- dockerfile = docker.send(:dockerfile_for, {
620
- 'platform' => platform,
621
- 'image' => 'foobar',
622
- })
623
- expect( dockerfile ).to be =~ /ENV container docker/
636
+ it 'should raise on an unsupported platform' do
637
+ expect { docker.send(:dockerfile_for, {'platform' => 'a_sidewalk', 'image' => 'foobar' }) }.to raise_error(/platform a_sidewalk not yet supported/)
624
638
  end
625
- end
626
639
 
627
- it 'should add docker_image_commands as RUN statements' do
628
- FakeFS.deactivate!
629
- platforms.each do |platform|
630
- dockerfile = docker.send(:dockerfile_for, {
631
- 'platform' => platform,
632
- 'image' => 'foobar',
633
- 'docker_image_commands' => [
634
- 'special one',
635
- 'special two',
636
- 'special three',
637
- ]
638
- })
640
+ it 'should set "ENV container docker"' do
641
+ FakeFS.deactivate!
642
+ platforms.each do |platform|
643
+ dockerfile = docker.send(:dockerfile_for, {
644
+ 'platform' => platform,
645
+ 'image' => 'foobar',
646
+ })
647
+ expect( dockerfile ).to be =~ /ENV container docker/
648
+ end
649
+ end
639
650
 
640
- expect( dockerfile ).to be =~ /RUN special one\nRUN special two\nRUN special three/
651
+ it 'should add docker_image_commands as RUN statements' do
652
+ FakeFS.deactivate!
653
+ platforms.each do |platform|
654
+ dockerfile = docker.send(:dockerfile_for, {
655
+ 'platform' => platform,
656
+ 'image' => 'foobar',
657
+ 'docker_image_commands' => [
658
+ 'special one',
659
+ 'special two',
660
+ 'special three',
661
+ ]
662
+ })
663
+
664
+ expect( dockerfile ).to be =~ /RUN special one\nRUN special two\nRUN special three/
665
+ end
641
666
  end
642
- end
643
667
 
644
- it 'should add docker_image_entrypoint' do
645
- FakeFS.deactivate!
646
- platforms.each do |platform|
668
+ it 'should add docker_image_entrypoint' do
669
+ FakeFS.deactivate!
670
+ platforms.each do |platform|
671
+ dockerfile = docker.send(:dockerfile_for, {
672
+ 'platform' => platform,
673
+ 'image' => 'foobar',
674
+ 'docker_image_entrypoint' => '/bin/bash'
675
+ })
676
+
677
+ expect( dockerfile ).to be =~ %r{ENTRYPOINT /bin/bash}
678
+ end
679
+ end
680
+
681
+ it 'should use zypper on sles' do
682
+ FakeFS.deactivate!
647
683
  dockerfile = docker.send(:dockerfile_for, {
648
- 'platform' => platform,
684
+ 'platform' => 'sles-12-x86_64',
649
685
  'image' => 'foobar',
650
- 'docker_image_entrypoint' => '/bin/bash'
651
686
  })
652
687
 
653
- expect( dockerfile ).to be =~ %r{ENTRYPOINT /bin/bash}
688
+ expect( dockerfile ).to be =~ /RUN zypper -n in openssh/
654
689
  end
655
- end
656
690
 
657
- it 'should use zypper on sles' do
658
- FakeFS.deactivate!
659
- dockerfile = docker.send(:dockerfile_for, {
660
- 'platform' => 'sles-12-x86_64',
661
- 'image' => 'foobar',
662
- })
691
+ (22..29).to_a.each do | fedora_release |
692
+ it "should use dnf on fedora #{fedora_release}" do
693
+ FakeFS.deactivate!
694
+ dockerfile = docker.send(:dockerfile_for, {
695
+ 'platform' => "fedora-#{fedora_release}-x86_64",
696
+ 'image' => 'foobar',
697
+ })
663
698
 
664
- expect( dockerfile ).to be =~ /RUN zypper -n in openssh/
665
- end
699
+ expect( dockerfile ).to be =~ /RUN dnf install -y sudo/
700
+ end
701
+ end
666
702
 
667
- (22..29).to_a.each do | fedora_release |
668
- it "should use dnf on fedora #{fedora_release}" do
703
+ it 'should use pacman on archlinux' do
669
704
  FakeFS.deactivate!
670
705
  dockerfile = docker.send(:dockerfile_for, {
671
- 'platform' => "fedora-#{fedora_release}-x86_64",
706
+ 'platform' => 'archlinux-current-x86_64',
672
707
  'image' => 'foobar',
673
708
  })
674
709
 
675
- expect( dockerfile ).to be =~ /RUN dnf install -y sudo/
710
+ expect( dockerfile ).to be =~ /RUN pacman -S --noconfirm openssh/
676
711
  end
677
712
  end
678
-
679
- it 'should use pacman on archlinux' do
680
- FakeFS.deactivate!
681
- dockerfile = docker.send(:dockerfile_for, {
682
- 'platform' => 'archlinux-current-x86_64',
683
- 'image' => 'foobar',
684
- })
685
-
686
- expect( dockerfile ).to be =~ /RUN pacman -S --noconfirm openssh/
687
- end
688
713
  end
689
714
  end
690
715
  end