beaker-docker 0.5.4 → 0.8.1

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