kitchen-docker 2.8.0 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  #
3
2
  # Copyright (C) 2014, Sean Porter
4
3
  #
@@ -17,15 +16,14 @@
17
16
  require 'kitchen'
18
17
  require 'json'
19
18
  require 'securerandom'
20
- require 'uri'
21
19
  require 'net/ssh'
22
- require 'tempfile'
23
- require 'shellwords'
24
- require 'base64'
25
20
 
26
21
  require 'kitchen/driver/base'
27
22
 
28
- require_relative './docker/erb'
23
+ require_relative '../docker/container/linux'
24
+ require_relative '../docker/container/windows'
25
+ require_relative '../docker/helpers/cli_helper'
26
+ require_relative '../docker/helpers/container_helper'
29
27
 
30
28
  module Kitchen
31
29
  module Driver
@@ -33,48 +31,44 @@ module Kitchen
33
31
  #
34
32
  # @author Sean Porter <portertech@gmail.com>
35
33
  class Docker < Kitchen::Driver::Base
34
+ include Kitchen::Docker::Helpers::CliHelper
35
+ include Kitchen::Docker::Helpers::ContainerHelper
36
36
  include ShellOut
37
37
 
38
38
  default_config :binary, 'docker'
39
- default_config :socket, ENV['DOCKER_HOST'] || 'unix:///var/run/docker.sock'
40
- default_config :privileged, false
39
+ default_config :build_options, nil
41
40
  default_config :cap_add, nil
42
41
  default_config :cap_drop, nil
43
- default_config :security_opt, nil
44
- default_config :use_cache, true
42
+ default_config :disable_upstart, true
43
+ default_config :env_variables, nil
44
+ default_config :isolation, nil
45
+ default_config :interactive, false
46
+ default_config :private_key, File.join(Dir.pwd, '.kitchen', 'docker_id_rsa')
47
+ default_config :privileged, false
48
+ default_config :public_key, File.join(Dir.pwd, '.kitchen', 'docker_id_rsa.pub')
49
+ default_config :publish_all, false
45
50
  default_config :remove_images, false
46
- default_config :run_command, '/usr/sbin/sshd -D -o UseDNS=no -o UsePAM=no -o PasswordAuthentication=yes ' +
47
- '-o UsePrivilegeSeparation=no -o PidFile=/tmp/sshd.pid'
48
- default_config :username, 'kitchen'
51
+ default_config :run_options, nil
52
+ default_config :security_opt, nil
49
53
  default_config :tls, false
50
- default_config :tls_verify, false
51
54
  default_config :tls_cacert, nil
52
55
  default_config :tls_cert, nil
53
56
  default_config :tls_key, nil
54
- default_config :publish_all, false
55
- default_config :wait_for_sshd, true
56
- default_config :private_key, File.join(Dir.pwd, '.kitchen', 'docker_id_rsa')
57
- default_config :public_key, File.join(Dir.pwd, '.kitchen', 'docker_id_rsa.pub')
58
- default_config :build_options, nil
59
- default_config :run_options, nil
57
+ default_config :tls_verify, false
58
+ default_config :tty, false
59
+ default_config :use_cache, true
60
60
  default_config :use_internal_docker_network, false
61
-
62
61
  default_config :use_sudo, false
63
-
64
- default_config :image do |driver|
65
- driver.default_image
66
- end
67
-
68
- default_config :platform do |driver|
69
- driver.default_platform
70
- end
71
-
72
- default_config :disable_upstart, true
62
+ default_config :wait_for_transport, true
73
63
 
74
64
  default_config :build_context do |driver|
75
65
  !driver.remote_socket?
76
66
  end
77
67
 
68
+ default_config :image do |driver|
69
+ driver.default_image
70
+ end
71
+
78
72
  default_config :instance_name do |driver|
79
73
  # Borrowed from kitchen-rackspace
80
74
  [
@@ -82,368 +76,90 @@ module Kitchen
82
76
  (Etc.getlogin || 'nologin').gsub(/\W/, ''),
83
77
  Socket.gethostname.gsub(/\W/, '')[0..20],
84
78
  Array.new(8) { rand(36).to_s(36) }.join
85
- ].join('-')
86
- end
87
-
88
- MUTEX_FOR_SSH_KEYS = Mutex.new
89
-
90
- def verify_dependencies
91
- run_command("#{config[:binary]} >> #{dev_null} 2>&1", quiet: true, use_sudo: config[:use_sudo])
92
- rescue
93
- raise UserError,
94
- 'You must first install the Docker CLI tool http://www.docker.io/gettingstarted/'
95
- end
96
-
97
- def dev_null
98
- case RbConfig::CONFIG["host_os"]
99
- when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
100
- "NUL"
101
- else
102
- "/dev/null"
103
- end
104
- end
105
-
106
- def default_image
107
- platform, release = instance.platform.name.split('-')
108
- if platform == 'centos' && release
109
- release = 'centos' + release.split('.').first
110
- end
111
- release ? [platform, release].join(':') : platform
79
+ ].join('-').downcase
112
80
  end
113
81
 
114
- def default_platform
115
- instance.platform.name.split('-').first
116
- end
117
-
118
- def create(state)
119
- generate_keys
120
- state[:username] = config[:username]
121
- state[:ssh_key] = config[:private_key]
122
- state[:image_id] = build_image(state) unless state[:image_id]
123
- state[:container_id] = run_container(state) unless state[:container_id]
124
- state[:hostname] = 'localhost'
125
- if remote_socket?
126
- state[:hostname] = socket_uri.host
127
- elsif config[:use_internal_docker_network]
128
- state[:hostname] = container_ip(state)
129
- end
130
- state[:port] = container_ssh_port(state)
131
- if config[:wait_for_sshd]
132
- instance.transport.connection(state) do |conn|
133
- conn.wait_until_ready
134
- end
135
- end
136
- end
137
-
138
- def destroy(state)
139
- rm_container(state) if container_exists?(state)
140
- if config[:remove_images] && state[:image_id]
141
- rm_image(state) if image_exists?(state)
142
- end
143
- end
144
-
145
- def remote_socket?
146
- config[:socket] ? socket_uri.scheme == 'tcp' : false
147
- end
148
-
149
- protected
150
-
151
- def socket_uri
152
- URI.parse(config[:socket])
153
- end
154
-
155
- def docker_command(cmd, options={})
156
- docker = config[:binary].dup
157
- docker << " -H #{config[:socket]}" if config[:socket]
158
- docker << " --tls" if config[:tls]
159
- docker << " --tlsverify" if config[:tls_verify]
160
- docker << " --tlscacert=#{config[:tls_cacert]}" if config[:tls_cacert]
161
- docker << " --tlscert=#{config[:tls_cert]}" if config[:tls_cert]
162
- docker << " --tlskey=#{config[:tls_key]}" if config[:tls_key]
163
- run_command("#{docker} #{cmd}", options.merge({
164
- quiet: !logger.debug?,
165
- use_sudo: config[:use_sudo],
166
- log_subject: Thor::Util.snake_case(self.class.to_s),
167
- }))
82
+ default_config :platform do |driver|
83
+ driver.default_platform
168
84
  end
169
85
 
170
- def generate_keys
171
- MUTEX_FOR_SSH_KEYS.synchronize do
172
- if !File.exist?(config[:public_key]) || !File.exist?(config[:private_key])
173
- private_key = OpenSSL::PKey::RSA.new(2048)
174
- blobbed_key = Base64.encode64(private_key.to_blob).gsub("\n", '')
175
- public_key = "ssh-rsa #{blobbed_key} kitchen_docker_key"
176
- File.open(config[:private_key], 'w') do |file|
177
- file.write(private_key)
178
- file.chmod(0600)
179
- end
180
- File.open(config[:public_key], 'w') do |file|
181
- file.write(public_key)
182
- file.chmod(0600)
183
- end
86
+ default_config :run_command do |driver|
87
+ if driver.windows_os?
88
+ # Launch arbitrary process to keep the Windows container alive
89
+ # If running in interactive mode, launch powershell.exe instead
90
+ if driver[:interactive]
91
+ 'powershell.exe'
92
+ else
93
+ 'ping -t localhost'
184
94
  end
185
- end
186
- end
187
-
188
- def build_dockerfile
189
- from = "FROM #{config[:image]}"
190
-
191
- env_variables = ''
192
- if config[:http_proxy]
193
- env_variables << "ENV http_proxy #{config[:http_proxy]}\n"
194
- env_variables << "ENV HTTP_PROXY #{config[:http_proxy]}\n"
195
- end
196
-
197
- if config[:https_proxy]
198
- env_variables << "ENV https_proxy #{config[:https_proxy]}\n"
199
- env_variables << "ENV HTTPS_PROXY #{config[:https_proxy]}\n"
200
- end
201
-
202
- if config[:no_proxy]
203
- env_variables << "ENV no_proxy #{config[:no_proxy]}\n"
204
- env_variables << "ENV NO_PROXY #{config[:no_proxy]}\n"
205
- end
206
-
207
- platform = case config[:platform]
208
- when 'debian', 'ubuntu'
209
- disable_upstart = <<-eos
210
- RUN [ ! -f "/sbin/initctl" ] || dpkg-divert --local --rename --add /sbin/initctl && ln -sf /bin/true /sbin/initctl
211
- eos
212
- packages = <<-eos
213
- ENV DEBIAN_FRONTEND noninteractive
214
- ENV container docker
215
- RUN apt-get update
216
- RUN apt-get install -y sudo openssh-server curl lsb-release
217
- eos
218
- config[:disable_upstart] ? disable_upstart + packages : packages
219
- when 'rhel', 'centos', 'fedora', 'oraclelinux'
220
- <<-eos
221
- ENV container docker
222
- RUN yum clean all
223
- RUN yum install -y sudo openssh-server openssh-clients which curl
224
- RUN [ -f "/etc/ssh/ssh_host_rsa_key" ] || ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N ''
225
- RUN [ -f "/etc/ssh/ssh_host_dsa_key" ] || ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key -N ''
226
- eos
227
- when 'opensuse', 'sles'
228
- <<-eos
229
- ENV container docker
230
- RUN zypper install -y sudo openssh which curl
231
- RUN [ -f "/etc/ssh/ssh_host_rsa_key" ] || ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N ''
232
- RUN [ -f "/etc/ssh/ssh_host_dsa_key" ] || ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key -N ''
233
- eos
234
- when 'arch'
235
- # See https://bugs.archlinux.org/task/47052 for why we
236
- # blank out limits.conf.
237
- <<-eos
238
- RUN pacman --noconfirm -Sy archlinux-keyring
239
- RUN pacman-db-upgrade
240
- RUN pacman --noconfirm -Syu openssl openssh sudo curl
241
- RUN [ -f "/etc/ssh/ssh_host_rsa_key" ] || ssh-keygen -A -t rsa -f /etc/ssh/ssh_host_rsa_key
242
- RUN [ -f "/etc/ssh/ssh_host_dsa_key" ] || ssh-keygen -A -t dsa -f /etc/ssh/ssh_host_dsa_key
243
- RUN echo >/etc/security/limits.conf
244
- eos
245
- when 'gentoo'
246
- <<-eos
247
- RUN emerge --sync
248
- RUN emerge net-misc/openssh app-admin/sudo
249
- RUN [ -f "/etc/ssh/ssh_host_rsa_key" ] || ssh-keygen -A -t rsa -f /etc/ssh/ssh_host_rsa_key
250
- RUN [ -f "/etc/ssh/ssh_host_dsa_key" ] || ssh-keygen -A -t dsa -f /etc/ssh/ssh_host_dsa_key
251
- eos
252
- when 'gentoo-paludis'
253
- <<-eos
254
- RUN cave sync
255
- RUN cave resolve -zx net-misc/openssh app-admin/sudo
256
- RUN [ -f "/etc/ssh/ssh_host_rsa_key" ] || ssh-keygen -A -t rsa -f /etc/ssh/ssh_host_rsa_key
257
- RUN [ -f "/etc/ssh/ssh_host_dsa_key" ] || ssh-keygen -A -t dsa -f /etc/ssh/ssh_host_dsa_key
258
- eos
259
- else
260
- raise ActionFailed,
261
- "Unknown platform '#{config[:platform]}'"
262
- end
263
-
264
- username = config[:username]
265
- public_key = IO.read(config[:public_key]).strip
266
- homedir = username == 'root' ? '/root' : "/home/#{username}"
267
-
268
- base = <<-eos
269
- RUN if ! getent passwd #{username}; then \
270
- useradd -d #{homedir} -m -s /bin/bash -p '*' #{username}; \
271
- fi
272
- RUN echo "#{username} ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
273
- RUN echo "Defaults !requiretty" >> /etc/sudoers
274
- RUN mkdir -p #{homedir}/.ssh
275
- RUN chown -R #{username} #{homedir}/.ssh
276
- RUN chmod 0700 #{homedir}/.ssh
277
- RUN touch #{homedir}/.ssh/authorized_keys
278
- RUN chown #{username} #{homedir}/.ssh/authorized_keys
279
- RUN chmod 0600 #{homedir}/.ssh/authorized_keys
280
- RUN mkdir -p /run/sshd
281
- eos
282
- custom = ''
283
- Array(config[:provision_command]).each do |cmd|
284
- custom << "RUN #{cmd}\n"
285
- end
286
- ssh_key = "RUN echo #{Shellwords.escape(public_key)} >> #{homedir}/.ssh/authorized_keys"
287
- # Empty string to ensure the file ends with a newline.
288
- [from, env_variables, platform, base, custom, ssh_key, ''].join("\n")
289
- end
290
-
291
- def dockerfile
292
- if config[:dockerfile]
293
- template = IO.read(File.expand_path(config[:dockerfile]))
294
- context = DockerERBContext.new(config.to_hash)
295
- ERB.new(template).result(context.get_binding)
296
95
  else
297
- build_dockerfile
298
- end
299
- end
300
-
301
- def parse_image_id(output)
302
- output.each_line do |line|
303
- if line =~ /image id|build successful|successfully built/i
304
- return line.split(/\s+/).last
305
- end
96
+ '/usr/sbin/sshd -D -o UseDNS=no -o UsePAM=no -o PasswordAuthentication=yes '\
97
+ '-o UsePrivilegeSeparation=no -o PidFile=/tmp/sshd.pid'
306
98
  end
307
- raise ActionFailed,
308
- 'Could not parse Docker build output for image ID'
309
99
  end
310
100
 
311
- def build_image(state)
312
- cmd = "build"
313
- cmd << " --no-cache" unless config[:use_cache]
314
- extra_build_options = config_to_options(config[:build_options])
315
- cmd << " #{extra_build_options}" unless extra_build_options.empty?
316
- dockerfile_contents = dockerfile
317
- build_context = config[:build_context] ? '.' : '-'
318
- file = Tempfile.new('Dockerfile-kitchen', Dir.pwd)
319
- output = begin
320
- file.write(dockerfile)
321
- file.close
322
- docker_command("#{cmd} -f #{Shellwords.escape(dockerfile_path(file))} #{build_context}", :input => dockerfile_contents)
323
- ensure
324
- file.close unless file.closed?
325
- file.unlink
326
- end
327
- parse_image_id(output)
101
+ default_config :socket do |driver|
102
+ socket = 'unix:///var/run/docker.sock'
103
+ socket = 'npipe:////./pipe/docker_engine' if driver.windows_os?
104
+ ENV['DOCKER_HOST'] || socket
328
105
  end
329
106
 
330
- def parse_container_id(output)
331
- container_id = output.chomp
332
- unless [12, 64].include?(container_id.size)
333
- raise ActionFailed,
334
- 'Could not parse Docker run output for container ID'
107
+ default_config :username do |driver|
108
+ # Return nil to prevent username from being added to Docker
109
+ # command line args for Windows if a username was not specified
110
+ if driver.windows_os?
111
+ nil
112
+ else
113
+ 'kitchen'
335
114
  end
336
- container_id
337
115
  end
338
116
 
339
- def build_run_command(image_id)
340
- cmd = "run -d -p 22"
341
- Array(config[:forward]).each {|port| cmd << " -p #{port}"}
342
- Array(config[:dns]).each {|dns| cmd << " --dns #{dns}"}
343
- Array(config[:add_host]).each {|host, ip| cmd << " --add-host=#{host}:#{ip}"}
344
- Array(config[:volume]).each {|volume| cmd << " -v #{volume}"}
345
- Array(config[:volumes_from]).each {|container| cmd << " --volumes-from #{container}"}
346
- Array(config[:links]).each {|link| cmd << " --link #{link}"}
347
- Array(config[:devices]).each {|device| cmd << " --device #{device}"}
348
- cmd << " --name #{config[:instance_name]}" if config[:instance_name]
349
- cmd << " -P" if config[:publish_all]
350
- cmd << " -h #{config[:hostname]}" if config[:hostname]
351
- cmd << " -m #{config[:memory]}" if config[:memory]
352
- cmd << " -c #{config[:cpu]}" if config[:cpu]
353
- cmd << " -e http_proxy=#{config[:http_proxy]}" if config[:http_proxy]
354
- cmd << " -e https_proxy=#{config[:https_proxy]}" if config[:https_proxy]
355
- cmd << " --privileged" if config[:privileged]
356
- Array(config[:cap_add]).each {|cap| cmd << " --cap-add=#{cap}"} if config[:cap_add]
357
- Array(config[:cap_drop]).each {|cap| cmd << " --cap-drop=#{cap}"} if config[:cap_drop]
358
- Array(config[:security_opt]).each {|opt| cmd << " --security-opt=#{opt}"} if config[:security_opt]
359
- extra_run_options = config_to_options(config[:run_options])
360
- cmd << " #{extra_run_options}" unless extra_run_options.empty?
361
- cmd << " #{image_id} #{config[:run_command]}"
362
- cmd
363
- end
364
-
365
- def run_container(state)
366
- cmd = build_run_command(state[:image_id])
367
- output = docker_command(cmd)
368
- parse_container_id(output)
117
+ def verify_dependencies
118
+ run_command("#{config[:binary]} >> #{dev_null} 2>&1", quiet: true, use_sudo: config[:use_sudo])
119
+ rescue
120
+ raise UserError, 'You must first install the Docker CLI tool https://www.docker.com/get-started'
369
121
  end
370
122
 
371
- def container_exists?(state)
372
- state[:container_id] && !!docker_command("top #{state[:container_id]}") rescue false
373
- end
123
+ def create(state)
124
+ container.create(state)
374
125
 
375
- def image_exists?(state)
376
- state[:image_id] && !!docker_command("docker inspect --type=image #{state[:image_id]}") rescue false
126
+ wait_for_transport(state)
377
127
  end
378
128
 
379
- def parse_container_ssh_port(output)
380
- begin
381
- _host, port = output.split(':')
382
- port.to_i
383
- rescue
384
- raise ActionFailed,
385
- 'Could not parse Docker port output for container SSH port'
386
- end
129
+ def destroy(state)
130
+ container.destroy(state)
387
131
  end
388
132
 
389
- def container_ssh_port(state)
390
- begin
391
- if config[:use_internal_docker_network]
392
- return 22
133
+ def wait_for_transport(state)
134
+ if config[:wait_for_transport]
135
+ instance.transport.connection(state) do |conn|
136
+ conn.wait_until_ready
393
137
  end
394
- output = docker_command("port #{state[:container_id]} 22/tcp")
395
- parse_container_ssh_port(output)
396
- rescue
397
- raise ActionFailed,
398
- 'Docker reports container has no ssh port mapped'
399
138
  end
400
139
  end
401
140
 
402
- def container_ip(state)
403
- begin
404
- cmd = "inspect --format '{{ .NetworkSettings.IPAddress }}'"
405
- cmd << " #{state[:container_id]}"
406
- docker_command(cmd).strip
407
- rescue
408
- raise ActionFailed,
409
- 'Error getting internal IP of Docker container'
141
+ def default_image
142
+ platform, release = instance.platform.name.split('-')
143
+ if platform == 'centos' && release
144
+ release = 'centos' + release.split('.').first
410
145
  end
146
+ release ? [platform, release].join(':') : platform
411
147
  end
412
148
 
413
- def rm_container(state)
414
- container_id = state[:container_id]
415
- docker_command("stop -t 0 #{container_id}")
416
- docker_command("rm #{container_id}")
417
- end
418
-
419
- def rm_image(state)
420
- image_id = state[:image_id]
421
- docker_command("rmi #{image_id}")
149
+ def default_platform
150
+ instance.platform.name.split('-').first
422
151
  end
423
152
 
424
- # Convert the config input for `:build_options` or `:run_options` in to a
425
- # command line string for use with Docker.
426
- #
427
- # @since 2.5.0
428
- # @param config [nil, String, Array, Hash] Config data to convert.
429
- # @return [String]
430
- def config_to_options(config)
431
- case config
432
- when nil
433
- ''
434
- when String
435
- config
436
- when Array
437
- config.map {|c| config_to_options(c) }.join(' ')
438
- when Hash
439
- config.map {|k, v| Array(v).map {|c| "--#{k}=#{Shellwords.escape(c)}" }.join(' ') }.join(' ')
440
- end
441
- end
153
+ protected
442
154
 
443
- def dockerfile_path(file)
444
- config[:build_context] ? Pathname.new(file.path).relative_path_from(Pathname.pwd).to_s : file.path
155
+ def container
156
+ @container ||= if windows_os?
157
+ Kitchen::Docker::Container::Windows.new(config)
158
+ else
159
+ Kitchen::Docker::Container::Linux.new(config)
160
+ end
161
+ @container
445
162
  end
446
-
447
163
  end
448
164
  end
449
165
  end
@@ -0,0 +1,111 @@
1
+ #
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
14
+ require 'kitchen'
15
+
16
+ require_relative '../docker/container/linux'
17
+ require_relative '../docker/container/windows'
18
+
19
+ require_relative '../docker/helpers/inspec_helper'
20
+
21
+ require_relative '../../docker/version.rb'
22
+ require_relative '../../train/docker.rb'
23
+
24
+ module Kitchen
25
+ module Transport
26
+ class Docker < Kitchen::Transport::Base
27
+ class DockerFailed < TransportFailed; end
28
+
29
+ kitchen_transport_api_version 1
30
+ plugin_version Kitchen::VERSION
31
+
32
+ default_config :binary, 'docker'
33
+ default_config :env_variables, nil
34
+ default_config :interactive, false
35
+ default_config :privileged, false
36
+ default_config :tls, false
37
+ default_config :tls_cacert, nil
38
+ default_config :tls_cert, nil
39
+ default_config :tls_key, nil
40
+ default_config :tls_verify, false
41
+ default_config :tty, false
42
+ default_config :working_dir, nil
43
+
44
+ default_config :socket do |transport|
45
+ socket = 'unix:///var/run/docker.sock'
46
+ socket = 'npipe:////./pipe/docker_engine' if transport.windows_os?
47
+ ENV['DOCKER_HOST'] || socket
48
+ end
49
+
50
+ default_config :temp_dir do |transport|
51
+ if transport.windows_os?
52
+ '$env:TEMP'
53
+ else
54
+ '/tmp'
55
+ end
56
+ end
57
+
58
+ default_config :username do |transport|
59
+ # Return an empty string to prevent username from being added to Docker
60
+ # command line args for Windows if a username was not specified
61
+ if transport.windows_os?
62
+ nil
63
+ else
64
+ 'kitchen'
65
+ end
66
+ end
67
+
68
+ def connection(state, &block)
69
+ options = config.to_hash.merge(state)
70
+ options[:platform] = instance.platform.name
71
+
72
+ # Set value for DOCKER_HOST environment variable for the docker-api gem
73
+ # This allows Windows systems to use the TCP socket for the InSpec verifier
74
+ # See the lib/docker.rb file here: https://github.com/swipely/docker-api/blob/master/lib/docker.rb
75
+ # default_socket_url is set to a Unix socket and env_url requires an environment variable to be set
76
+ ENV['DOCKER_HOST'] = options[:socket] if !options[:socket].nil? && ENV['DOCKER_HOST'].nil?
77
+
78
+ Kitchen::Transport::Docker::Connection.new(options, &block)
79
+ end
80
+
81
+ class Connection < Kitchen::Transport::Docker::Connection
82
+ # Include the InSpec patches to be able to execute tests on Windows containers
83
+ include Kitchen::Docker::Helpers::InspecHelper
84
+
85
+ def execute(command)
86
+ return if command.nil?
87
+
88
+ debug("[Docker] Executing command: #{command}")
89
+ info("[Docker] Executing command on container")
90
+
91
+ container.execute(command)
92
+ rescue => e
93
+ raise DockerFailed, "Docker failed to execute command on container. Error Details: #{e}"
94
+ end
95
+
96
+ def upload(locals, remote)
97
+ container.upload(locals, remote)
98
+ end
99
+
100
+ def container
101
+ @container ||= if @options[:platform].include?('windows')
102
+ Kitchen::Docker::Container::Windows.new(@options)
103
+ else
104
+ Kitchen::Docker::Container::Linux.new(@options)
105
+ end
106
+ @container
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end