kitchen-docker 3.4.0 → 3.4.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.
- checksums.yaml +4 -4
- data/.release-please-manifest.json +1 -1
- data/CHANGELOG.md +9 -0
- data/README.md +5 -2
- data/lib/kitchen/docker/container/linux.rb +4 -1
- data/lib/kitchen/docker/container/windows.rb +5 -1
- data/lib/kitchen/docker/docker_version.rb +1 -1
- data/lib/kitchen/docker/helpers/cli_helper.rb +1 -1
- data/lib/kitchen/docker/helpers/container_helper.rb +12 -1
- data/lib/kitchen/docker/helpers/image_helper.rb +10 -0
- data/lib/kitchen/driver/docker.rb +8 -0
- data/lib/kitchen/transport/docker.rb +8 -2
- data/spec/container_helper_spec.rb +83 -0
- data/spec/docker_spec.rb +18 -0
- data/spec/image_helper_spec.rb +24 -0
- data/spec/linux_container_spec.rb +27 -0
- data/spec/support/docker_output.rb +9 -0
- data/spec/transport_docker_spec.rb +20 -0
- data/spec/windows_container_spec.rb +54 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2d994f876f76b4950f4f85521fba2ed15fe2ed54d06b9993d464a578f2fd9c69
|
|
4
|
+
data.tar.gz: d942290a8f115d5b0937421b747ec3f413e180fd55cfc8af245524b8337b27d5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7db4fee864798aa758a3e253f433db4e120d7247e8b5125e34764cf393f4836c9885eb3df2eff767501a6910c2f895b4efab467b8a24f7e1ad6120cc58eeede2
|
|
7
|
+
data.tar.gz: f80f60d52168ea008378af1cb66530136bf1e53b6474b75877a9275ff336f0ae632f754833f3e3db7aadd2c0f3910d64269fd39be0bb3a90baf5367d6708f115
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,15 @@ Future CHANGELOG notes will be in GitHub release notes
|
|
|
6
6
|
|
|
7
7
|
* Docs: document the last four options and split contributor docs ([#463](https://github.com/test-kitchen/kitchen-docker/pull/463)) ([4818bce](https://github.com/test-kitchen/kitchen-docker/commit/4818bce))
|
|
8
8
|
|
|
9
|
+
## [3.4.1](https://github.com/test-kitchen/kitchen-docker/compare/v3.4.0...v3.4.1) (2026-08-30)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* quote container paths interpolated into docker exec command lines ([#496](https://github.com/test-kitchen/kitchen-docker/issues/496)) ([ae3a754](https://github.com/test-kitchen/kitchen-docker/commit/ae3a754046cdb7c6d9fdb8622a6cef818643ad56))
|
|
15
|
+
* read the image id from a quiet build ([#489](https://github.com/test-kitchen/kitchen-docker/issues/489)) ([ddc58b5](https://github.com/test-kitchen/kitchen-docker/commit/ddc58b50a16b7236ed047071228f5641092060a1))
|
|
16
|
+
* report this gem's own version to kitchen diagnose ([#490](https://github.com/test-kitchen/kitchen-docker/issues/490)) ([e28171d](https://github.com/test-kitchen/kitchen-docker/commit/e28171d268ab0a4950c0d553fcee12688663e626))
|
|
17
|
+
|
|
9
18
|
## [3.4.0](https://github.com/test-kitchen/kitchen-docker/compare/v3.3.5...v3.4.0) (2026-08-23)
|
|
10
19
|
|
|
11
20
|
|
data/README.md
CHANGED
|
@@ -205,7 +205,7 @@ platforms:
|
|
|
205
205
|
| `dockerfile` | *(none)* | Path to your own Dockerfile, used instead of the generated one. Rendered as [ERB](#using-a-custom-dockerfile). |
|
|
206
206
|
| `build_context` | `true` locally, `false` for a remote daemon | Send the working directory to the daemon as build context. Required for `ADD` and `COPY`; slow against a remote daemon. |
|
|
207
207
|
| `build_options` | *(none)* | Extra flags for `docker build`, as a string or a map. |
|
|
208
|
-
| `build_tempdir` | working directory |
|
|
208
|
+
| `build_tempdir` | working directory | Directory the generated Dockerfile is written to. A relative path is resolved against the working directory, and the path must be inside the build context, since `docker build -f` is given it relative to the working directory. |
|
|
209
209
|
| `use_cache` | `true` | Use Docker's build cache. `false` adds `--no-cache`. |
|
|
210
210
|
| `remove_images` | `false` | Remove the built image on `kitchen destroy`. |
|
|
211
211
|
| `package_name` | the instance name, tagged `latest` | Image `kitchen package` commits the container to. |
|
|
@@ -237,7 +237,9 @@ platforms:
|
|
|
237
237
|
| `tty` | `false` | Pass `-t`, allocating a pseudo-TTY. |
|
|
238
238
|
| `env_variables` | *(none)* | Environment variables set in the container, as a map. |
|
|
239
239
|
| `wait_for_transport` | `true` | Wait for the transport to answer before converging. Set `false` for containers that do not stay up. |
|
|
240
|
-
|
|
240
|
+
|
|
241
|
+
The container itself is always started detached — see [`detach`](#transport-configuration)
|
|
242
|
+
under the transport for how provisioner commands are run.
|
|
241
243
|
|
|
242
244
|
### Networking
|
|
243
245
|
|
|
@@ -314,6 +316,7 @@ These options go under `transport:`, not `driver:`.
|
|
|
314
316
|
| `working_dir` | *(none)* | Working directory inside the container (`-w`). |
|
|
315
317
|
| `temp_dir` | `/tmp`, or `$env:TEMP` on Windows | Directory used to stage uploaded files. |
|
|
316
318
|
| `env_variables` | *(none)* | Environment variables for each command. |
|
|
319
|
+
| `detach` | `false` | Run provisioner commands with `docker exec -d`, returning immediately instead of waiting for them to finish. `kitchen login` ignores it, so the shell stays usable. |
|
|
317
320
|
| `privileged` | `false` | Run commands with `--privileged`. |
|
|
318
321
|
| `interactive` | `false` | Pass `-i`. |
|
|
319
322
|
| `tty` | `false` | Pass `-t`. |
|
|
@@ -84,7 +84,10 @@ module Kitchen
|
|
|
84
84
|
debug("Executing temp script #{remote_path}/#{filename} on container")
|
|
85
85
|
remote_path = replace_env_variables(@config, remote_path)
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
# Escaped because the exec command line is assembled as one string:
|
|
88
|
+
# a temp_dir with a space in it was split before docker saw it, and
|
|
89
|
+
# bash was handed the first half of the directory as the script.
|
|
90
|
+
container_exec(@config, "/bin/bash #{Shellwords.escape("#{remote_path}/#{filename}")}")
|
|
88
91
|
rescue => e
|
|
89
92
|
raise "Failed to execute command on Linux container. #{e}"
|
|
90
93
|
ensure
|
|
@@ -69,7 +69,11 @@ module Kitchen
|
|
|
69
69
|
# Replace any environment variables used in the path and execute script file
|
|
70
70
|
debug("Executing temp script #{remote_path}\\#{filename} on container")
|
|
71
71
|
remote_path = replace_env_variables(@config, remote_path)
|
|
72
|
-
|
|
72
|
+
# Quoted because PowerShell's -File takes exactly one argument. An
|
|
73
|
+
# unquoted path with a space in it -- which $env:TEMP has whenever the
|
|
74
|
+
# user's name does -- left PowerShell looking for a script named
|
|
75
|
+
# after the first word of the directory.
|
|
76
|
+
cmd = build_powershell_command(%{-File "#{remote_path}\\#{filename}"})
|
|
73
77
|
|
|
74
78
|
container_exec(@config, cmd)
|
|
75
79
|
rescue => e
|
|
@@ -107,7 +107,7 @@ module Kitchen
|
|
|
107
107
|
# @param cmd [String] the command to run
|
|
108
108
|
# @param options [Hash] shell-out options
|
|
109
109
|
# @return [String] combined stdout and stderr
|
|
110
|
-
# @raise [Kitchen::ShellCommandFailed] if the command exits non-zero
|
|
110
|
+
# @raise [Kitchen::ShellOut::ShellCommandFailed] if the command exits non-zero
|
|
111
111
|
def run_command(cmd, options = {})
|
|
112
112
|
if options.fetch(:use_sudo, false)
|
|
113
113
|
cmd = "#{options.fetch(:sudo_command, "sudo -E")} #{cmd}"
|
|
@@ -155,6 +155,17 @@ module Kitchen
|
|
|
155
155
|
|
|
156
156
|
# Creates a directory inside the container, on Linux or Windows.
|
|
157
157
|
#
|
|
158
|
+
# The path is escaped for the shell, because it comes from the
|
|
159
|
+
# transport's +temp_dir+ and a `docker exec` command line is assembled
|
|
160
|
+
# as one string. A directory with a space in it was torn in two before
|
|
161
|
+
# docker ever saw it, and `mkdir -p` obligingly created both halves --
|
|
162
|
+
# neither of them the directory that was asked for. Every upload that
|
|
163
|
+
# followed then went to a path that did not exist.
|
|
164
|
+
#
|
|
165
|
+
# The PowerShell branch already quotes the path itself, and its
|
|
166
|
+
# argument is reassembled by PowerShell rather than split by a shell,
|
|
167
|
+
# so it is left as it is.
|
|
168
|
+
#
|
|
158
169
|
# @param state [Hash] instance state naming the container
|
|
159
170
|
# @param path [String] the directory to create; environment variable
|
|
160
171
|
# references are expanded first
|
|
@@ -162,7 +173,7 @@ module Kitchen
|
|
|
162
173
|
# @raise [RuntimeError] if the directory cannot be created
|
|
163
174
|
def create_dir_on_container(state, path)
|
|
164
175
|
path = replace_env_variables(state, path)
|
|
165
|
-
cmd = "mkdir -p #{path}"
|
|
176
|
+
cmd = "mkdir -p #{Shellwords.escape(path)}"
|
|
166
177
|
|
|
167
178
|
if state[:platform].include?("windows")
|
|
168
179
|
psh = "-Command if(-not (Test-Path '#{path}')) { New-Item -Path '#{path}' -Force }"
|
|
@@ -27,6 +27,9 @@ module Kitchen
|
|
|
27
27
|
include Kitchen::Docker::Helpers::CliHelper
|
|
28
28
|
include Kitchen::Docker::Helpers::ContainerHelper
|
|
29
29
|
|
|
30
|
+
# An id on a line of its own, which is all `docker build -q` prints.
|
|
31
|
+
QUIET_BUILD_IMAGE_ID = /\A(sha256:[[:xdigit:]]{64})\z/
|
|
32
|
+
|
|
30
33
|
# Pulls the built image's id out of `docker build` output.
|
|
31
34
|
#
|
|
32
35
|
# Scanned in reverse, and against several patterns, because the wording has
|
|
@@ -37,6 +40,13 @@ module Kitchen
|
|
|
37
40
|
# @raise [Kitchen::ActionFailed] if no id could be found
|
|
38
41
|
def parse_image_id(output)
|
|
39
42
|
output.split("\n").reverse_each do |line|
|
|
43
|
+
line = line.strip
|
|
44
|
+
# `docker build -q` prints the id and nothing else -- none of the
|
|
45
|
+
# wording below appears -- so a build with `build_options: -q` had
|
|
46
|
+
# no line any of these matched and failed with "Could not parse
|
|
47
|
+
# Docker build output for image ID" (#225).
|
|
48
|
+
return Regexp.last_match(1) if line.match(QUIET_BUILD_IMAGE_ID)
|
|
49
|
+
|
|
40
50
|
if line =~ /writing image (sha256:[[:xdigit:]]{64})(?: \d*\.\ds)? done/i
|
|
41
51
|
img_id = line[/writing image (sha256:[[:xdigit:]]{64})(?: \d*\.\ds)? done/i, 1]
|
|
42
52
|
return img_id
|
|
@@ -23,6 +23,7 @@ require "kitchen/driver/base"
|
|
|
23
23
|
|
|
24
24
|
require_relative "../docker/container/linux"
|
|
25
25
|
require_relative "../docker/container/windows"
|
|
26
|
+
require_relative "../docker/docker_version"
|
|
26
27
|
require_relative "../docker/helpers/cli_helper"
|
|
27
28
|
require_relative "../docker/helpers/container_helper"
|
|
28
29
|
|
|
@@ -37,6 +38,13 @@ module Kitchen
|
|
|
37
38
|
include Kitchen::Docker::Helpers::ContainerHelper
|
|
38
39
|
include ShellOut
|
|
39
40
|
|
|
41
|
+
# Reported by `kitchen diagnose`, which is what a bug report is asked to
|
|
42
|
+
# include. The version is this gem's own: the transport used to report
|
|
43
|
+
# Kitchen::VERSION, which is Test Kitchen's, so a diagnose said the
|
|
44
|
+
# plugin was at whatever version Test Kitchen happened to be.
|
|
45
|
+
kitchen_driver_api_version 2
|
|
46
|
+
plugin_version Kitchen::Docker::DOCKER_VERSION
|
|
47
|
+
|
|
40
48
|
default_config :binary, "docker"
|
|
41
49
|
default_config :build_options, nil
|
|
42
50
|
default_config :build_tempdir, Dir.pwd
|
|
@@ -15,6 +15,7 @@ require "kitchen"
|
|
|
15
15
|
|
|
16
16
|
require_relative "../docker/container/linux"
|
|
17
17
|
require_relative "../docker/container/windows"
|
|
18
|
+
require_relative "../docker/docker_version"
|
|
18
19
|
|
|
19
20
|
require_relative "../docker/helpers/inspec_helper"
|
|
20
21
|
|
|
@@ -31,8 +32,11 @@ module Kitchen
|
|
|
31
32
|
# Raised when a docker command against the container fails.
|
|
32
33
|
class DockerFailed < TransportFailed; end
|
|
33
34
|
|
|
34
|
-
#
|
|
35
|
-
|
|
35
|
+
# Reported by `kitchen diagnose`. plugin_version was Kitchen::VERSION,
|
|
36
|
+
# which is Test Kitchen's version rather than this gem's, so a diagnose
|
|
37
|
+
# reported the transport as 4.1.1 while kitchen-docker was at 3.3.4.
|
|
38
|
+
kitchen_transport_api_version 1
|
|
39
|
+
plugin_version Kitchen::Docker::DOCKER_VERSION
|
|
36
40
|
|
|
37
41
|
default_config :binary, "docker"
|
|
38
42
|
default_config :env_variables, nil
|
|
@@ -79,6 +83,8 @@ module Kitchen
|
|
|
79
83
|
# than from Test Kitchen's configuration.
|
|
80
84
|
#
|
|
81
85
|
# @param state [Hash] instance state naming the container
|
|
86
|
+
# @param block [Proc, nil] forwarded to the connection's constructor, which
|
|
87
|
+
# yields the new connection to it; the connection is not closed afterwards
|
|
82
88
|
# @yieldparam connection [Connection] if a block is given
|
|
83
89
|
# @return [Connection]
|
|
84
90
|
def connection(state, &block)
|
|
@@ -333,6 +333,89 @@ describe Kitchen::Docker::Helpers::ContainerHelper do
|
|
|
333
333
|
end
|
|
334
334
|
end
|
|
335
335
|
|
|
336
|
+
describe "#create_dir_on_container" do
|
|
337
|
+
def dir_maker(state)
|
|
338
|
+
helper.tap do |h|
|
|
339
|
+
@commands = []
|
|
340
|
+
allow(h).to receive(:replace_env_variables) { |_s, path| path }
|
|
341
|
+
allow(h).to receive(:docker_command) { |cmd, _opts = {}| @commands << cmd; "" }
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
it "creates the directory inside the container" do
|
|
346
|
+
dir_maker(nil).create_dir_on_container({ container_id: "abc", platform: "ubuntu-24.04" }, "/tmp")
|
|
347
|
+
expect(argv(@commands.first)).to include_consecutive("mkdir", "-p", "/tmp")
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
it "expands an environment variable reference before creating it" do
|
|
351
|
+
h = helper
|
|
352
|
+
allow(h).to receive(:container_env_variables).and_return("TEMP" => "/var/tmp")
|
|
353
|
+
allow(h).to receive(:docker_command) { |cmd, _opts = {}| @cmd = cmd; "" }
|
|
354
|
+
h.create_dir_on_container({ container_id: "abc", platform: "ubuntu-24.04" }, "$TEMP/kitchen")
|
|
355
|
+
expect(argv(@cmd)).to include_consecutive("mkdir", "-p", "/var/tmp/kitchen")
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
# A temp_dir with a space in it reached `mkdir -p` unquoted, so the shell
|
|
359
|
+
# tore it in two and mkdir made two directories -- neither of them the one
|
|
360
|
+
# asked for. Every later upload then landed somewhere that did not exist.
|
|
361
|
+
it "keeps a path containing a space as one argument" do
|
|
362
|
+
dir_maker(nil).create_dir_on_container({ container_id: "abc", platform: "ubuntu-24.04" },
|
|
363
|
+
"/var/tmp/kitchen docker")
|
|
364
|
+
expect(argv(@commands.first)).to include_consecutive("mkdir", "-p", "/var/tmp/kitchen docker")
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
it "uses PowerShell on a Windows container" do
|
|
368
|
+
dir_maker(nil).create_dir_on_container({ container_id: "abc", platform: "windows-2022" }, 'C:\\Temp')
|
|
369
|
+
expect(@commands.first).to include("powershell").and include("New-Item")
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
it "says which directory it could not create" do
|
|
373
|
+
h = helper
|
|
374
|
+
allow(h).to receive(:replace_env_variables) { |_s, path| path }
|
|
375
|
+
allow(h).to receive(:docker_command).and_raise("boom")
|
|
376
|
+
expect { h.create_dir_on_container({ container_id: "abc", platform: "ubuntu-24.04" }, "/tmp/kitchen") }
|
|
377
|
+
.to raise_error(RuntimeError, %r{Failed to create directory /tmp/kitchen})
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
describe "#container_exec" do
|
|
382
|
+
it "runs the command through docker exec" do
|
|
383
|
+
h = helper
|
|
384
|
+
allow(h).to receive(:docker_command) { |cmd, _opts = {}| @cmd = cmd; "output" }
|
|
385
|
+
expect(h.container_exec({ container_id: "abc" }, "echo hi")).to eq "output"
|
|
386
|
+
expect(argv(@cmd)).to include_consecutive("exec", "abc", "echo", "hi")
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
it "names the container operation when the command fails" do
|
|
390
|
+
h = helper
|
|
391
|
+
allow(h).to receive(:docker_command).and_raise("boom")
|
|
392
|
+
expect { h.container_exec({ container_id: "abc" }, "echo hi") }
|
|
393
|
+
.to raise_error(RuntimeError, /Failed to execute command on Docker container/)
|
|
394
|
+
end
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
describe "#run_container" do
|
|
398
|
+
it "returns the id docker printed for the container it started" do
|
|
399
|
+
h = helper(instance_name: "kitchen-test")
|
|
400
|
+
allow(h).to receive(:docker_command).and_return(DockerOutput::RUN_CLEAN)
|
|
401
|
+
expect(h.run_container({ image_id: "sha256:abc" }, 22)).to eq DockerOutput::RUN_CONTAINER_ID
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
it "publishes the port it was given" do
|
|
405
|
+
h = helper
|
|
406
|
+
allow(h).to receive(:docker_command) { |cmd, _opts = {}| @cmd = cmd; DockerOutput::RUN_CLEAN }
|
|
407
|
+
h.run_container({ image_id: "sha256:abc" }, 22)
|
|
408
|
+
expect(argv(@cmd)).to include_consecutive("-p", "22")
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
it "publishes no port when there is none, as for a Windows container" do
|
|
412
|
+
h = helper
|
|
413
|
+
allow(h).to receive(:docker_command) { |cmd, _opts = {}| @cmd = cmd; DockerOutput::RUN_CLEAN }
|
|
414
|
+
h.run_container(image_id: "sha256:abc")
|
|
415
|
+
expect(argv(@cmd)).not_to include("-p")
|
|
416
|
+
end
|
|
417
|
+
end
|
|
418
|
+
|
|
336
419
|
describe "#copy_file_to_container" do
|
|
337
420
|
let(:state) { { container_id: "abc", platform: "ubuntu-24.04" } }
|
|
338
421
|
|
data/spec/docker_spec.rb
CHANGED
|
@@ -17,6 +17,24 @@
|
|
|
17
17
|
require "spec_helper"
|
|
18
18
|
|
|
19
19
|
describe Kitchen::Driver::Docker do
|
|
20
|
+
# `kitchen diagnose` is what bug reports are asked to include, so what it
|
|
21
|
+
# says about the plugin has to be true. The transport reported
|
|
22
|
+
# Kitchen::VERSION, which is Test Kitchen's version, and the driver reported
|
|
23
|
+
# nothing at all.
|
|
24
|
+
describe "plugin metadata" do
|
|
25
|
+
it "reports this gem's version, not Test Kitchen's" do
|
|
26
|
+
expect(described_class.diagnose[:version]).to eq Kitchen::Docker::DOCKER_VERSION
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "does not report Test Kitchen's version" do
|
|
30
|
+
expect(described_class.diagnose[:version]).not_to eq Kitchen::VERSION
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "declares the driver API version it is written against" do
|
|
34
|
+
expect(described_class.diagnose[:api_version]).to eq 2
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
20
38
|
describe "#config_to_options" do
|
|
21
39
|
let(:config) {}
|
|
22
40
|
subject { described_class.new.send(:config_to_options, config) }
|
data/spec/image_helper_spec.rb
CHANGED
|
@@ -16,6 +16,30 @@ require "spec_helper"
|
|
|
16
16
|
|
|
17
17
|
describe Kitchen::Docker::Helpers::ImageHelper do
|
|
18
18
|
describe "#parse_image_id" do
|
|
19
|
+
# From #225. `docker build -q` prints the id on a line of its own and
|
|
20
|
+
# nothing else -- no "writing image", no "naming to", no "successfully
|
|
21
|
+
# built" -- so every pattern the parser had missed it, and a build with
|
|
22
|
+
# `build_options: -q` failed with "Could not parse Docker build output for
|
|
23
|
+
# image ID" rather than producing an instance.
|
|
24
|
+
context "with a quiet build" do
|
|
25
|
+
it "reads the id docker printed on its own" do
|
|
26
|
+
expect(helper.parse_image_id(DockerOutput::BUILD_QUIET))
|
|
27
|
+
.to eq DockerOutput::BUILD_QUIET_IMAGE_ID
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "reads it when docker also wrote a warning to stderr" do
|
|
31
|
+
expect(helper.parse_image_id("WARNING: something happened\n#{DockerOutput::BUILD_QUIET}"))
|
|
32
|
+
.to eq DockerOutput::BUILD_QUIET_IMAGE_ID
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "does not mistake a digest that is part of a longer line for the id" do
|
|
36
|
+
# Ordinary build output is full of "... sha256:... done" lines. Only a
|
|
37
|
+
# line that is nothing but a digest is the quiet form.
|
|
38
|
+
expect { helper.parse_image_id("#6 exporting manifest sha256:#{"a" * 64} done\n") }
|
|
39
|
+
.to raise_error(Kitchen::ActionFailed)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
19
43
|
# Docker has changed how it reports the built image's id several times, and
|
|
20
44
|
# each change has broken this parser. Every format the driver claims to
|
|
21
45
|
# support gets a case here, against output copied from a real build.
|
|
@@ -211,6 +211,33 @@ describe Kitchen::Docker::Container::Linux do
|
|
|
211
211
|
c.execute("echo hi")
|
|
212
212
|
expect(uploaded).to eq "echo hi"
|
|
213
213
|
end
|
|
214
|
+
|
|
215
|
+
# The staged script is run by path, and that path is built from temp_dir,
|
|
216
|
+
# which the user sets.
|
|
217
|
+
def ran_in(temp_dir)
|
|
218
|
+
c = container(temp_dir: temp_dir)
|
|
219
|
+
allow(c).to receive(:create_dir_on_container)
|
|
220
|
+
allow(c).to receive(:replace_env_variables) { |_cfg, path| path }
|
|
221
|
+
allow(c).to receive(:upload)
|
|
222
|
+
ran = nil
|
|
223
|
+
allow(c).to receive(:container_exec) { |_cfg, cmd| ran = cmd }
|
|
224
|
+
c.execute("echo hi")
|
|
225
|
+
ran
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
it "runs the staged script with bash" do
|
|
229
|
+
ran = ran_in("/tmp")
|
|
230
|
+
expect(argv(ran).first).to eq "/bin/bash"
|
|
231
|
+
expect(argv(ran).last).to match(%r{\A/tmp/docker-[0-9a-f-]+\.sh\z})
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# Interpolated unquoted, a temp_dir with a space in it reached `docker
|
|
235
|
+
# exec` as two arguments, and bash was handed the first half of the
|
|
236
|
+
# directory as the script to run.
|
|
237
|
+
it "keeps a temp_dir containing a space as one argument" do
|
|
238
|
+
expect(argv(ran_in("/var/tmp/kitchen docker")).last)
|
|
239
|
+
.to match(%r{\A/var/tmp/kitchen docker/docker-[0-9a-f-]+\.sh\z})
|
|
240
|
+
end
|
|
214
241
|
end
|
|
215
242
|
|
|
216
243
|
describe "#generate_keys" do
|
|
@@ -81,6 +81,15 @@ module DockerOutput
|
|
|
81
81
|
|
|
82
82
|
BUILD_LEGACY_IMAGE_ID = "1a2b3c4d5e6f".freeze
|
|
83
83
|
|
|
84
|
+
# `docker build -q` on Docker 29.7.2. Quiet mode prints the id and nothing
|
|
85
|
+
# else -- no step lines, no exporting lines, none of the wording the other
|
|
86
|
+
# fixtures here are built around. Reachable through the driver as
|
|
87
|
+
# `build_options: -q`.
|
|
88
|
+
BUILD_QUIET = "sha256:ab86ce908a36ffb7de411a72550e416a4d8c268570a0f7313c284c79344d6c0f\n".freeze
|
|
89
|
+
|
|
90
|
+
BUILD_QUIET_IMAGE_ID =
|
|
91
|
+
"sha256:ab86ce908a36ffb7de411a72550e416a4d8c268570a0f7313c284c79344d6c0f".freeze
|
|
92
|
+
|
|
84
93
|
# `docker run -d`, the ordinary case: the id and nothing else.
|
|
85
94
|
RUN_CONTAINER_ID = "b89e1e8b07664a1ee0bd09decb833146eaf9cc810a152950e3576a56745944db".freeze
|
|
86
95
|
RUN_CLEAN = "#{RUN_CONTAINER_ID}\n".freeze
|
|
@@ -15,6 +15,26 @@
|
|
|
15
15
|
require "spec_helper"
|
|
16
16
|
require "kitchen/transport/docker"
|
|
17
17
|
|
|
18
|
+
describe Kitchen::Transport::Docker do
|
|
19
|
+
# `kitchen diagnose` is what bug reports are asked to include, so what it
|
|
20
|
+
# says about the plugin has to be true.
|
|
21
|
+
describe "plugin metadata" do
|
|
22
|
+
it "reports this gem's version, not Test Kitchen's" do
|
|
23
|
+
expect(described_class.diagnose[:version]).to eq Kitchen::Docker::DOCKER_VERSION
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "does not report Test Kitchen's version" do
|
|
27
|
+
# It did: `plugin_version Kitchen::VERSION` made a diagnose say the
|
|
28
|
+
# transport was at Test Kitchen's version rather than this gem's.
|
|
29
|
+
expect(described_class.diagnose[:version]).not_to eq Kitchen::VERSION
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "declares the transport API version it is written against" do
|
|
33
|
+
expect(described_class.diagnose[:api_version]).to eq 1
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
18
38
|
describe Kitchen::Transport::Docker::Connection do
|
|
19
39
|
let(:options) do
|
|
20
40
|
{
|
|
@@ -64,6 +64,60 @@ describe Kitchen::Docker::Container::Windows do
|
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
+
describe "#execute" do
|
|
68
|
+
def staged(config = {})
|
|
69
|
+
c = container({ temp_dir: 'C:\\Temp' }.merge(config))
|
|
70
|
+
allow(c).to receive(:create_dir_on_container)
|
|
71
|
+
allow(c).to receive(:replace_env_variables) { |_cfg, path| path }
|
|
72
|
+
allow(c).to receive(:upload)
|
|
73
|
+
allow(c).to receive(:container_exec) { |_cfg, cmd| @ran = cmd }
|
|
74
|
+
c
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
around do |example|
|
|
78
|
+
Dir.mktmpdir { |dir| Dir.chdir(dir) { example.run } }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it "runs the staged script with powershell" do
|
|
82
|
+
staged.execute("Write-Host hi")
|
|
83
|
+
expect(@ran).to start_with "powershell -ExecutionPolicy Bypass -NoLogo "
|
|
84
|
+
expect(@ran).to match(/-File .*docker-[0-9a-f-]+\.ps1/)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "stages the script under the configured temp_dir" do
|
|
88
|
+
staged.execute("Write-Host hi")
|
|
89
|
+
expect(@ran).to include 'C:\\Temp\\docker-'
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "accepts a temp_dir written with forward slashes" do
|
|
93
|
+
# Kitchen configuration is YAML that is often shared with Linux suites,
|
|
94
|
+
# so the separator is normalised rather than rejected.
|
|
95
|
+
staged(temp_dir: "C:/Temp").execute("Write-Host hi")
|
|
96
|
+
expect(@ran).to include 'C:\\Temp\\docker-'
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# A Windows temp_dir routinely contains a space -- $env:TEMP under a user
|
|
100
|
+
# whose name has one does. PowerShell's -File takes exactly one argument,
|
|
101
|
+
# so an unquoted path left it looking for a script named after the first
|
|
102
|
+
# word.
|
|
103
|
+
it "quotes a script path containing a space" do
|
|
104
|
+
staged(temp_dir: 'C:\\Users\\Foo Bar\\Temp').execute("Write-Host hi")
|
|
105
|
+
expect(@ran).to include('-File "C:\\Users\\Foo Bar\\Temp\\docker-').and end_with('.ps1"')
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it "removes the staged script once the command has run" do
|
|
109
|
+
staged.execute("Write-Host hi")
|
|
110
|
+
expect(Dir.glob(".kitchen/temp/docker-*.ps1")).to be_empty
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "removes the staged script when the command fails" do
|
|
114
|
+
c = staged
|
|
115
|
+
allow(c).to receive(:container_exec).and_raise("command exploded")
|
|
116
|
+
expect { c.execute("Write-Host hi") }.to raise_error(/Failed to execute command/)
|
|
117
|
+
expect(Dir.glob(".kitchen/temp/docker-*.ps1")).to be_empty
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
67
121
|
describe "the contract it shares with the Linux container" do
|
|
68
122
|
# The two classes share almost no code but must agree on the state they
|
|
69
123
|
# populate, because the driver and transport read the same keys whichever
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kitchen-docker
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.4.
|
|
4
|
+
version: 3.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sean Porter
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08-
|
|
11
|
+
date: 2026-08-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: test-kitchen
|