beaker-docker 1.4.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Beaker
4
+ # Docker hypervisor for Beaker acceptance testing framework
2
5
  class Docker < Beaker::Hypervisor
3
-
4
6
  # Docker hypvervisor initializtion
5
7
  # Env variables supported:
6
8
  # DOCKER_REGISTRY: Docker registry URL
@@ -10,13 +12,14 @@ module Beaker
10
12
  # or a role (String or Symbol) that identifies one or more hosts.
11
13
  # @param [Hash{Symbol=>String}] options Options to pass on to the hypervisor
12
14
  def initialize(hosts, options)
15
+ super
13
16
  require 'docker'
14
17
  @options = options
15
18
  @logger = options[:logger] || Beaker::Logger.new
16
19
  @hosts = hosts
17
20
 
18
21
  # increase the http timeouts as provisioning images can be slow
19
- default_docker_options = { :write_timeout => 300, :read_timeout => 300 }.merge(::Docker.options || {})
22
+ default_docker_options = { write_timeout: 300, read_timeout: 300 }.merge(::Docker.options || {})
20
23
  # Merge docker options from the entry in hosts file
21
24
  ::Docker.options = default_docker_options.merge(@options[:docker_options] || {})
22
25
 
@@ -37,13 +40,12 @@ module Beaker
37
40
  ::Docker.logger = @logger
38
41
 
39
42
  # Find out what kind of remote instance we are talking against
40
- if @docker_version['Version'] =~ /swarm/
43
+ if @docker_version['Version'].include?('swarm')
41
44
  @docker_type = 'swarm'
42
- unless ENV['DOCKER_REGISTRY']
43
- raise "Using Swarm with beaker requires a private registry. Please setup the private registry and set the 'DOCKER_REGISTRY' env var"
44
- else
45
- @registry = ENV['DOCKER_REGISTRY']
46
- end
45
+ raise "Using Swarm with beaker requires a private registry. Please setup the private registry and set the 'DOCKER_REGISTRY' env var" unless ENV['DOCKER_REGISTRY']
46
+
47
+ @registry = ENV.fetch('DOCKER_REGISTRY', nil)
48
+
47
49
  elsif ::Docker.respond_to?(:podman?) && ::Docker.podman?
48
50
  @docker_type = 'podman'
49
51
  else
@@ -52,15 +54,15 @@ module Beaker
52
54
  end
53
55
 
54
56
  def install_and_run_ssh(host)
55
- def host.enable_root_login(host,opts)
57
+ def host.enable_root_login(host, _opts)
56
58
  logger.debug("Root login already enabled for #{host}")
57
59
  end
58
60
 
59
61
  # If the container is running ssh as its init process then this method
60
62
  # will cause issues.
61
- if host[:docker_cmd] =~ /sshd/
63
+ if Array(host[:docker_cmd]).first&.include?('sshd')
62
64
  def host.ssh_service_restart
63
- self[:docker_container].exec(%w(kill -1 1))
65
+ self[:docker_container].exec(%w[kill -1 1])
64
66
  end
65
67
  end
66
68
 
@@ -69,49 +71,45 @@ module Beaker
69
71
 
70
72
  def get_container_opts(host, image_name)
71
73
  container_opts = {}
72
- if host['dockerfile']
73
- container_opts['ExposedPorts'] = {'22/tcp' => {} }
74
- end
75
-
76
- container_opts.merge! ( {
77
- 'Image' => image_name,
78
- 'Hostname' => host.name,
79
- 'HostConfig' => {
80
- 'PortBindings' => {
81
- '22/tcp' => [{ 'HostPort' => rand(1025..9999).to_s, 'HostIp' => '0.0.0.0'}]
82
- },
83
- 'PublishAllPorts' => true,
84
- 'RestartPolicy' => {
85
- 'Name' => 'always'
86
- }
87
- }
88
- } )
74
+ container_opts['ExposedPorts'] = { '22/tcp' => {} } if host['dockerfile']
75
+
76
+ container_opts.merge!({
77
+ 'Image' => image_name,
78
+ 'Hostname' => host.name,
79
+ 'HostConfig' => {
80
+ 'PortBindings' => {
81
+ '22/tcp' => [{ 'HostPort' => rand(1025..9999).to_s, 'HostIp' => '0.0.0.0' }],
82
+ },
83
+ 'PublishAllPorts' => true,
84
+ 'RestartPolicy' => {
85
+ 'Name' => 'always',
86
+ },
87
+ },
88
+ })
89
89
  end
90
90
 
91
91
  def get_container_image(host)
92
- @logger.debug("Creating image")
92
+ @logger.debug('Creating image')
93
93
 
94
- if host['use_image_as_is']
95
- return ::Docker::Image.create('fromImage' => host['image'])
96
- end
94
+ return ::Docker::Image.create('fromImage' => host['image']) if host['use_image_as_is']
97
95
 
98
96
  dockerfile = host['dockerfile']
99
97
  if dockerfile
100
98
  # assume that the dockerfile is in the repo and tests are running
101
99
  # from the root of the repo; maybe add support for external Dockerfiles
102
100
  # with external build dependencies later.
103
- if File.exist?(dockerfile)
104
- dir = File.expand_path(dockerfile).chomp(dockerfile)
105
- return ::Docker::Image.build_from_dir(
106
- dir,
107
- { 'dockerfile' => dockerfile,
108
- :rm => true,
109
- :buildargs => buildargs_for(host)
110
- }
111
- )
112
- else
113
- raise "Unable to find dockerfile at #{dockerfile}"
114
- end
101
+ raise "Unable to find dockerfile at #{dockerfile}" unless File.exist?(dockerfile)
102
+
103
+ dir = File.expand_path(dockerfile).chomp(dockerfile)
104
+ return ::Docker::Image.build_from_dir(
105
+ dir,
106
+ {
107
+ 'dockerfile' => dockerfile,
108
+ :rm => true,
109
+ :buildargs => buildargs_for(host),
110
+ },
111
+ )
112
+
115
113
  elsif host['use_image_entry_point']
116
114
  df = <<-DF
117
115
  FROM #{host['image']}
@@ -123,13 +121,12 @@ module Beaker
123
121
  return ::Docker::Image.build(df, { rm: true, buildargs: buildargs_for(host) })
124
122
  end
125
123
 
126
- return ::Docker::Image.build(dockerfile_for(host),
127
- { rm: true, buildargs: buildargs_for(host) })
124
+ ::Docker::Image.build(dockerfile_for(host), { rm: true, buildargs: buildargs_for(host) })
128
125
  end
129
126
 
130
127
  # Nested Docker scenarios
131
128
  def nested_docker?
132
- ENV['DOCKER_IN_DOCKER'] || ENV['WSLENV']
129
+ ENV['DOCKER_IN_DOCKER'] || ENV.fetch('WSLENV', nil)
133
130
  end
134
131
 
135
132
  # Find out where the ssh port is from the container
@@ -139,7 +136,7 @@ module Beaker
139
136
  def get_ssh_connection_info(container)
140
137
  ssh_connection_info = {
141
138
  ip: nil,
142
- port: nil
139
+ port: nil,
143
140
  }
144
141
 
145
142
  container_json = container.json
@@ -149,86 +146,76 @@ module Beaker
149
146
  ip = nil
150
147
  port = nil
151
148
  # Talking against a remote docker host which is a normal docker host
152
- if @docker_type == 'docker' && ENV['DOCKER_HOST'] && !ENV.fetch('DOCKER_HOST','').include?(':///') && !nested_docker?
153
- ip = URI.parse(ENV['DOCKER_HOST']).host
154
- else
149
+ if @docker_type == 'docker' && ENV.fetch('DOCKER_HOST', nil) && !ENV.fetch('DOCKER_HOST', '').include?(':///') && !nested_docker?
150
+ ip = URI.parse(ENV.fetch('DOCKER_HOST', nil)).host
151
+ elsif in_container? && !nested_docker?
155
152
  # Swarm or local docker host
156
- if in_container? && !nested_docker?
157
- gw = network_settings['Gateway']
158
- ip = gw unless (gw.nil? || gw.empty?)
159
- else
160
- # The many faces of container networking
153
+ gw = network_settings['Gateway']
154
+ ip = gw unless gw.nil? || gw.empty?
155
+ else
156
+ # The many faces of container networking
161
157
 
162
- # Host to Container
163
- port22 = network_settings.dig('PortBindings','22/tcp')
164
- if port22.nil? && network_settings.key?('Ports') && !nested_docker?
165
- port22 = network_settings.dig('Ports','22/tcp')
166
- end
158
+ # Host to Container
159
+ port22 = network_settings.dig('PortBindings', '22/tcp')
160
+ port22 = network_settings.dig('Ports', '22/tcp') if port22.nil? && network_settings.key?('Ports') && !nested_docker?
167
161
 
168
- ip = port22[0]['HostIp'] if port22
169
- port = port22[0]['HostPort'] if port22
162
+ ip = port22[0]['HostIp'] if port22
163
+ port = port22[0]['HostPort'] if port22
170
164
 
171
- # Container to container
172
- unless ip && port
173
- ip = nil
174
- port = nil
165
+ # Container to container
166
+ unless ip && port
167
+ ip = network_settings['IPAddress']
168
+ port = ip && !ip.empty? ? 22 : nil
169
+ end
175
170
 
176
- ip = network_settings['IPAddress']
177
- port = 22 if ip && !ip.empty?
178
- end
171
+ # Container through gateway
172
+ unless ip && port
173
+ ip = network_settings['Gateway']
179
174
 
180
- # Container through gateway
181
- unless ip && port
182
- ip = nil
175
+ if ip && !ip.empty?
176
+ port22 = network_settings.dig('PortBindings', '22/tcp')
177
+ port = port22[0]['HostPort'] if port22
178
+ else
183
179
  port = nil
184
-
185
- ip = network_settings['Gateway']
186
-
187
- if ip && !ip.empty?
188
- port22 = network_settings.dig('PortBindings','22/tcp')
189
- port = port22[0]['HostPort'] if port22
190
- end
191
180
  end
181
+ end
192
182
 
193
- # Legacy fallback
194
- unless ip && port
195
- port22 = network_settings.dig('Ports','22/tcp')
196
- ip = port22[0]["HostIp"] if port22
197
- port = port22[0]['HostPort'] if port22
198
- end
183
+ # Legacy fallback
184
+ unless ip && port
185
+ port22 = network_settings.dig('Ports', '22/tcp')
186
+ ip = port22[0]['HostIp'] if port22
187
+ port = port22[0]['HostPort'] if port22
199
188
  end
200
189
  end
201
190
 
202
191
  if host_config['NetworkMode'] != 'slirp4netns' && network_settings['IPAddress'] && !network_settings['IPAddress'].empty?
203
192
  ip = network_settings['IPAddress'] if ip.nil?
204
193
  else
205
- port22 = network_settings.dig('Ports','22/tcp')
194
+ port22 = network_settings.dig('Ports', '22/tcp')
206
195
  port = port22[0]['HostPort'] if port22
207
196
  end
208
197
 
209
- ssh_connection_info[:ip] = (ip == '0.0.0.0') ? '127.0.0.1' : ip
198
+ ssh_connection_info[:ip] = ip == '0.0.0.0' ? '127.0.0.1' : ip
210
199
  ssh_connection_info[:port] = port || '22'
211
200
  ssh_connection_info
212
201
  end
213
202
 
214
203
  def provision
215
- @logger.notify "Provisioning docker"
204
+ @logger.notify 'Provisioning docker'
216
205
 
217
206
  @hosts.each do |host|
218
207
  @logger.notify "provisioning #{host.name}"
219
208
 
220
209
  image = get_container_image(host)
221
210
 
222
- if host['tag']
223
- image.tag({:repo => host['tag']})
224
- end
211
+ image.tag({ repo: host['tag'] }) if host['tag']
225
212
 
226
213
  if @docker_type == 'swarm'
227
214
  image_name = "#{@registry}/beaker/#{image.id}"
228
- ret = ::Docker::Image.search(:term => image_name)
215
+ ret = ::Docker::Image.search(term: image_name)
229
216
  if ret.first.nil?
230
- @logger.debug("Image does not exist on registry. Pushing.")
231
- image.tag({:repo => image_name, :force => true})
217
+ @logger.debug('Image does not exist on registry. Pushing.')
218
+ image.tag({ repo: image_name, force: true })
232
219
  image.push
233
220
  end
234
221
  else
@@ -239,8 +226,8 @@ module Beaker
239
226
 
240
227
  container_opts = get_container_opts(host, image_name)
241
228
  if host['dockeropts'] || @options[:dockeropts]
242
- dockeropts = host['dockeropts'] ? host['dockeropts'] : @options[:dockeropts]
243
- dockeropts.each do |k,v|
229
+ dockeropts = host['dockeropts'] || @options[:dockeropts]
230
+ dockeropts.each do |k, v|
244
231
  container_opts[k] = v
245
232
  end
246
233
  end
@@ -255,12 +242,12 @@ module Beaker
255
242
  container_opts['HostConfig']['Binds'] = host['mount_folders'].values.map do |mount|
256
243
  host_path = File.expand_path(mount['host_path'])
257
244
  # When using docker_toolbox and getting a "(Driveletter):/" path, convert windows path to VM mount
258
- if ENV['DOCKER_TOOLBOX_INSTALL_PATH'] && host_path =~ /^.\:\//
259
- host_path = "/" + host_path.gsub(/^.\:/, host_path[/^(.)/].downcase)
260
- end
261
- a = [ host_path, mount['container_path'] ]
262
- if mount.has_key?('opts')
263
- a << mount['opts'] if mount.has_key?('opts')
245
+ host_path = "/#{host_path.gsub(/^.:/, host_path[/^(.)/].downcase)}" if ENV['DOCKER_TOOLBOX_INSTALL_PATH'] && host_path =~ %r{^.:/}
246
+ a = [host_path, mount['container_path']]
247
+
248
+ # TODO: rewrite this part
249
+ if mount.key?('opts')
250
+ a << mount['opts'] if mount.key?('opts')
264
251
  else
265
252
  a << mount['opts'] = 'z'
266
253
  end
@@ -269,9 +256,7 @@ module Beaker
269
256
  end
270
257
  end
271
258
 
272
- if host['docker_env']
273
- container_opts['Env'] = host['docker_env']
274
- end
259
+ container_opts['Env'] = host['docker_env'] if host['docker_env']
275
260
 
276
261
  # Fixup privileges
277
262
  #
@@ -286,11 +271,7 @@ module Beaker
286
271
  container_opts['HostConfig']['Privileged'] = container_opts['HostConfig']['Privileged'].nil? ? true : container_opts['HostConfig']['Privileged']
287
272
  end
288
273
 
289
- if host['docker_container_name']
290
- container_opts['name'] = host['docker_container_name']
291
- else
292
- container_opts['name'] = ['beaker', host.name, SecureRandom.uuid.split('-').last].join('-')
293
- end
274
+ container_opts['name'] = (host['docker_container_name'] || ['beaker', host.name, SecureRandom.uuid.split('-').last].join('-'))
294
275
 
295
276
  if host['docker_port_bindings']
296
277
  container_opts['ExposedPorts'] = {} if container_opts['ExposedPorts'].nil?
@@ -304,9 +285,9 @@ module Beaker
304
285
 
305
286
  @logger.debug("Creating container from image #{image_name}")
306
287
 
307
- ok=false
308
- retries=0
309
- while(!ok && (retries < 5))
288
+ ok = false
289
+ retries = 0
290
+ while !ok && (retries < 5)
310
291
  container = ::Docker::Container.create(container_opts)
311
292
 
312
293
  ssh_info = get_ssh_connection_info(container)
@@ -316,19 +297,19 @@ module Beaker
316
297
  container.delete(force: true)
317
298
  container = nil
318
299
 
319
- retries+=1
300
+ retries += 1
320
301
  next
321
302
  end
322
303
 
323
- ok=true
304
+ ok = true
324
305
  end
325
306
  else
326
307
  host['use_existing_container'] = true
327
308
  end
328
309
 
329
310
  if container.nil?
330
- raise RuntimeError, 'Cannot continue because no existing container ' +
331
- 'could be found and provisioning is disabled.'
311
+ raise 'Cannot continue because no existing container ' \
312
+ 'could be found and provisioning is disabled.'
332
313
  end
333
314
 
334
315
  fix_ssh(container) if @options[:provision] == false
@@ -368,19 +349,19 @@ module Beaker
368
349
  host['ip'] = ip
369
350
  host['port'] = port
370
351
  host['ssh'] = {
371
- :password => root_password,
372
- :port => port,
373
- :forward_agent => forward_ssh_agent,
374
- :auth_methods => ['password', 'publickey', 'hostbased', 'keyboard-interactive']
352
+ password: root_password,
353
+ port: port,
354
+ forward_agent: forward_ssh_agent,
355
+ auth_methods: %w[password publickey hostbased keyboard-interactive],
375
356
  }
376
357
 
377
358
  @logger.debug("node available as ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no root@#{ip} -p #{port}")
378
359
  host['docker_container_id'] = container.id
379
360
  host['docker_image_id'] = image.id
380
- host['vm_ip'] = container.json["NetworkSettings"]["IPAddress"].to_s
361
+ host['vm_ip'] = container.json['NetworkSettings']['IPAddress'].to_s
381
362
 
382
363
  def host.reboot
383
- @logger.warn("Rebooting containers is ineffective...ignoring")
364
+ @logger.warn('Rebooting containers is ineffective...ignoring')
384
365
  end
385
366
  end
386
367
 
@@ -390,92 +371,88 @@ module Beaker
390
371
  # This sideloads sshd after a container starts
391
372
  def install_ssh_components(container, host)
392
373
  case host['platform']
393
- when /ubuntu/, /debian/
394
- container.exec(%w(apt-get update))
395
- container.exec(%w(apt-get install -y openssh-server openssh-client))
396
- container.exec(%w(sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*))
397
- when /cumulus/
398
- container.exec(%w(apt-get update))
399
- container.exec(%w(apt-get install -y openssh-server openssh-client))
400
- container.exec(%w(sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*))
374
+ when /ubuntu/, /debian/, /cumulus/
375
+ container.exec(%w[apt-get update])
376
+ container.exec(%w[apt-get install -y openssh-server openssh-client])
377
+ container.exec(%w[sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*])
401
378
  when /el-[89]/, /fedora-(2[2-9]|3[0-9])/
402
- container.exec(%w(dnf clean all))
403
- container.exec(%w(dnf install -y sudo openssh-server openssh-clients))
404
- container.exec(%w(ssh-keygen -A))
405
- container.exec(%w(sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*))
379
+ container.exec(%w[dnf clean all])
380
+ container.exec(%w[dnf install -y sudo openssh-server openssh-clients])
381
+ container.exec(%w[ssh-keygen -A])
382
+ container.exec(%w[sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*])
406
383
  when /^el-/, /centos/, /fedora/, /redhat/, /eos/
407
- container.exec(%w(yum clean all))
408
- container.exec(%w(yum install -y sudo openssh-server openssh-clients))
409
- container.exec(%w(ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key))
410
- container.exec(%w(ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key))
411
- container.exec(%w(sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*))
384
+ container.exec(%w[yum clean all])
385
+ container.exec(%w[yum install -y sudo openssh-server openssh-clients])
386
+ container.exec(%w[ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key])
387
+ container.exec(%w[ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key])
388
+ container.exec(%w[sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*])
412
389
  when /opensuse/, /sles/
413
- container.exec(%w(zypper -n in openssh))
414
- container.exec(%w(ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key))
415
- container.exec(%w(ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key))
416
- container.exec(%w(sed -ri 's/^#?UsePAM .*/UsePAM no/' /etc/ssh/sshd_config))
390
+ container.exec(%w[zypper -n in openssh])
391
+ container.exec(%w[ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key])
392
+ container.exec(%w[ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key])
393
+ container.exec(%w[sed -ri 's/^#?UsePAM .*/UsePAM no/' /etc/ssh/sshd_config])
417
394
  when /archlinux/
418
- container.exec(%w(pacman --noconfirm -Sy archlinux-keyring))
419
- container.exec(%w(pacman --noconfirm -Syu))
420
- container.exec(%w(pacman -S --noconfirm openssh))
421
- container.exec(%w(ssh-keygen -A))
422
- container.exec(%w(sed -ri 's/^#?UsePAM .*/UsePAM no/' /etc/ssh/sshd_config))
423
- container.exec(%w(systemctl enable sshd))
395
+ container.exec(%w[pacman --noconfirm -Sy archlinux-keyring])
396
+ container.exec(%w[pacman --noconfirm -Syu])
397
+ container.exec(%w[pacman -S --noconfirm openssh])
398
+ container.exec(%w[ssh-keygen -A])
399
+ container.exec(%w[sed -ri 's/^#?UsePAM .*/UsePAM no/' /etc/ssh/sshd_config])
400
+ container.exec(%w[systemctl enable sshd])
424
401
  when /alpine/
425
- container.exec(%w(apk add --update openssh))
426
- container.exec(%w(ssh-keygen -A))
402
+ container.exec(%w[apk add --update openssh])
403
+ container.exec(%w[ssh-keygen -A])
427
404
  else
428
- # TODO add more platform steps here
405
+ # TODO: add more platform steps here
429
406
  raise "platform #{host['platform']} not yet supported on docker"
430
407
  end
431
408
 
432
409
  # Make sshd directory, set root password
433
- container.exec(%w(mkdir -p /var/run/sshd))
410
+ container.exec(%w[mkdir -p /var/run/sshd])
434
411
  container.exec(['/bin/sh', '-c', "echo root:#{root_password} | chpasswd"])
435
412
  end
436
413
 
437
414
  def cleanup
438
- @logger.notify "Cleaning up docker"
415
+ @logger.notify 'Cleaning up docker'
439
416
  @hosts.each do |host|
440
417
  # leave the container running if docker_preserve_container is set
441
418
  # setting docker_preserve_container also implies docker_preserve_image
442
419
  # is set, since you can't delete an image that's the base of a running
443
420
  # container
444
- unless host['docker_preserve_container']
445
- container = find_container(host)
446
- if container
447
- @logger.debug("stop container #{container.id}")
448
- begin
449
- container.kill
450
- sleep 2 # avoid a race condition where the root FS can't unmount
451
- rescue Excon::Errors::ClientError => e
452
- @logger.warn("stop of container #{container.id} failed: #{e.response.body}")
453
- end
454
- @logger.debug("delete container #{container.id}")
455
- begin
456
- container.delete(force: true)
457
- rescue Excon::Errors::ClientError => e
458
- @logger.warn("deletion of container #{container.id} failed: #{e.response.body}")
459
- end
421
+ next if host['docker_preserve_container']
422
+
423
+ container = find_container(host)
424
+ if container
425
+ @logger.debug("stop container #{container.id}")
426
+ begin
427
+ container.kill
428
+ sleep 2 # avoid a race condition where the root FS can't unmount
429
+ rescue Excon::Errors::ClientError => e
430
+ @logger.warn("stop of container #{container.id} failed: #{e.response.body}")
431
+ end
432
+ @logger.debug("delete container #{container.id}")
433
+ begin
434
+ container.delete(force: true)
435
+ rescue Excon::Errors::ClientError => e
436
+ @logger.warn("deletion of container #{container.id} failed: #{e.response.body}")
460
437
  end
438
+ end
461
439
 
462
- # Do not remove the image if docker_preserve_image is set to true, otherwise remove it
463
- unless host['docker_preserve_image']
464
- image_id = host['docker_image_id']
465
-
466
- if image_id
467
- @logger.debug("deleting image #{image_id}")
468
- begin
469
- ::Docker::Image.remove(image_id)
470
- rescue Excon::Errors::ClientError => e
471
- @logger.warn("deletion of image #{image_id} failed: #{e.response.body}")
472
- rescue ::Docker::Error::DockerError => e
473
- @logger.warn("deletion of image #{image_id} caused internal Docker error: #{e.message}")
474
- end
475
- else
476
- @logger.warn("Intended to delete the host's docker image, but host['docker_image_id'] was not set")
477
- end
440
+ # Do not remove the image if docker_preserve_image is set to true, otherwise remove it
441
+ next if host['docker_preserve_image']
442
+
443
+ image_id = host['docker_image_id']
444
+
445
+ if image_id
446
+ @logger.debug("deleting image #{image_id}")
447
+ begin
448
+ ::Docker::Image.remove(image_id)
449
+ rescue Excon::Errors::ClientError => e
450
+ @logger.warn("deletion of image #{image_id} failed: #{e.response.body}")
451
+ rescue ::Docker::Error::DockerError => e
452
+ @logger.warn("deletion of image #{image_id} caused internal Docker error: #{e.message}")
478
453
  end
454
+ else
455
+ @logger.warn("Intended to delete the host's docker image, but host['docker_image_id'] was not set")
479
456
  end
480
457
  end
481
458
  end
@@ -488,22 +465,20 @@ module Beaker
488
465
 
489
466
  def buildargs_for(host)
490
467
  docker_buildargs = {}
491
- docker_buildargs_env = ENV['DOCKER_BUILDARGS']
492
- if docker_buildargs_env != nil
493
- docker_buildargs_env.split(/ +|\t+/).each do |arg|
494
- key,value=arg.split(/=/)
495
- if key
496
- docker_buildargs[key]=value
497
- else
498
- @logger.warn("DOCKER_BUILDARGS environment variable appears invalid, no key found for value #{value}" )
499
- end
468
+ docker_buildargs_env = ENV.fetch('DOCKER_BUILDARGS', nil)
469
+ docker_buildargs_env&.split(/ +|\t+/)&.each do |arg|
470
+ key, value = arg.split('=')
471
+ if key
472
+ docker_buildargs[key] = value
473
+ else
474
+ @logger.warn("DOCKER_BUILDARGS environment variable appears invalid, no key found for value #{value}")
500
475
  end
501
476
  end
502
- if docker_buildargs.empty?
503
- buildargs = host['docker_buildargs'] || {}
504
- else
505
- buildargs = docker_buildargs
506
- end
477
+ buildargs = if docker_buildargs.empty?
478
+ host['docker_buildargs'] || {}
479
+ else
480
+ docker_buildargs
481
+ end
507
482
  @logger.debug("Docker build buildargs: #{buildargs}")
508
483
  JSON.generate(buildargs)
509
484
  end
@@ -516,7 +491,7 @@ module Beaker
516
491
  DF
517
492
 
518
493
  # Commands before any other commands. Can be used for eg. proxy configuration
519
- dockerfile += (host['docker_image_first_commands'] || []).map { |cmd| "RUN #{cmd}\n" }.join('')
494
+ dockerfile += (host['docker_image_first_commands'] || []).map { |cmd| "RUN #{cmd}\n" }.join
520
495
 
521
496
  # add platform-specific actions
522
497
  service_name = 'sshd'
@@ -538,23 +513,20 @@ module Beaker
538
513
  dockerfile += <<~DF
539
514
  RUN dnf clean all \
540
515
  && dnf install -y sudo openssh-server openssh-clients #{additional_packages.join(' ')} \
541
- && ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key \
542
- && ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key \
516
+ && ssh-keygen -A \
543
517
  && sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*
544
518
  DF
545
519
  when /^el-/, /centos/, /fedora/, /redhat/, /eos/
546
520
  dockerfile += <<~DF
547
521
  RUN yum clean all \
548
522
  && yum install -y sudo openssh-server openssh-clients #{additional_packages.join(' ')} \
549
- && ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key \
550
- && ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key \
523
+ && ssh-keygen -A \
551
524
  && sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*
552
525
  DF
553
526
  when /opensuse/, /sles/
554
527
  dockerfile += <<~DF
555
528
  RUN zypper -n in openssh #{additional_packages.join(' ')} \
556
- && ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key \
557
- && ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key \
529
+ && ssh-keygen -A \
558
530
  && sed -ri 's/^#?UsePAM .*/UsePAM no/' /etc/ssh/sshd_config \
559
531
  && sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/*
560
532
  DF
@@ -592,7 +564,7 @@ module Beaker
592
564
  DF
593
565
 
594
566
  # Any extra commands specified for the host
595
- dockerfile += (host['docker_image_commands'] || []).map { |cmd| "RUN #{cmd}\n" }.join('')
567
+ dockerfile += (host['docker_image_commands'] || []).map { |cmd| "RUN #{cmd}\n" }.join
596
568
 
597
569
  # Override image entrypoint
598
570
  dockerfile += "ENTRYPOINT #{host['docker_image_entrypoint']}\n" if host['docker_image_entrypoint']
@@ -622,7 +594,7 @@ module Beaker
622
594
  '-e', 's/^#?UseDNS .*/UseDNS no/',
623
595
  # Unbreak users with a bunch of SSH keys loaded in their keyring.
624
596
  '-e', 's/^#?MaxAuthTries.*/MaxAuthTries 1000/',
625
- '/etc/ssh/sshd_config'])
597
+ '/etc/ssh/sshd_config',])
626
598
 
627
599
  return unless host
628
600
 
@@ -647,24 +619,25 @@ module Beaker
647
619
 
648
620
  if id
649
621
  @logger.debug("Looking for an existing container with ID #{id}")
650
- container = containers.select { |c| c.id == id }.first
622
+ container = containers.find { |c| c.id == id }
651
623
  end
652
624
 
653
625
  if name && container.nil?
654
626
  @logger.debug("Looking for an existing container with name #{name}")
655
- container = containers.select do |c|
627
+ container = containers.find do |c|
656
628
  c.info['Names'].include? "/#{name}"
657
- end.first
629
+ end
658
630
  end
659
631
 
660
632
  return container unless container.nil?
661
- @logger.debug("Existing container not found")
662
- return nil
633
+
634
+ @logger.debug('Existing container not found')
635
+ nil
663
636
  end
664
637
 
665
638
  # return true if we are inside a docker container
666
639
  def in_container?
667
- return File.file?('/.dockerenv')
640
+ File.file?('/.dockerenv')
668
641
  end
669
642
  end
670
643
  end