kitchen-dokken 2.10.0 → 2.12.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/lib/kitchen/driver/dokken.rb +177 -129
- data/lib/kitchen/driver/dokken_version.rb +1 -1
- data/lib/kitchen/helpers.rb +49 -46
- data/lib/kitchen/provisioner/dokken.rb +19 -16
- data/lib/kitchen/transport/dokken.rb +36 -35
- metadata +16 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 517d0d0706aed8e8fc5889c874d6817fe65cfa571ba3a7a082d8256f707986cd
|
|
4
|
+
data.tar.gz: f5beb66dc47d9c4f58022c26af3ce8657c7fae40443eb2d3ee1b5ef2c01f5d0e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fd3d097a36e249e21f88ea3a1999207f9e45e464a9eb649d10c870d24d4a0705766dfb57df3ced2c82cda4e6cee04d5b53587b36743dbdd887da036d00c5d7c8
|
|
7
|
+
data.tar.gz: 755b9671c1aa2cbf14a90ddb9c730e3d50d5326a6244f2d8ece875b5bf5b5e9567c3c5f9661cd6cb6a00e6e4ec0594efcd5aa2fe0daf56e0fca7bf78c6a76d61
|
|
@@ -15,12 +15,12 @@
|
|
|
15
15
|
# See the License for the specific language governing permissions and
|
|
16
16
|
# limitations under the License.
|
|
17
17
|
|
|
18
|
-
require
|
|
19
|
-
require
|
|
20
|
-
require
|
|
21
|
-
require
|
|
22
|
-
require
|
|
23
|
-
require_relative
|
|
18
|
+
require "digest" unless defined?(Digest)
|
|
19
|
+
require "kitchen"
|
|
20
|
+
require "tmpdir" unless defined?(Dir.mktmpdir)
|
|
21
|
+
require "docker"
|
|
22
|
+
require "lockfile"
|
|
23
|
+
require_relative "../helpers"
|
|
24
24
|
|
|
25
25
|
include Dokken::Helpers
|
|
26
26
|
|
|
@@ -37,31 +37,32 @@ module Kitchen
|
|
|
37
37
|
default_config :binds, []
|
|
38
38
|
default_config :cap_add, nil
|
|
39
39
|
default_config :cap_drop, nil
|
|
40
|
-
default_config :chef_image,
|
|
41
|
-
default_config :chef_version,
|
|
42
|
-
default_config :data_image,
|
|
40
|
+
default_config :chef_image, "chef/chef"
|
|
41
|
+
default_config :chef_version, "latest"
|
|
42
|
+
default_config :data_image, "dokken/kitchen-cache:latest"
|
|
43
43
|
default_config :dns, nil
|
|
44
44
|
default_config :dns_search, nil
|
|
45
|
+
default_config :docker_host_url, default_docker_host
|
|
45
46
|
default_config :docker_info, docker_info
|
|
47
|
+
default_config :docker_registry, nil
|
|
46
48
|
default_config :entrypoint, nil
|
|
47
49
|
default_config :env, nil
|
|
48
|
-
default_config :
|
|
49
|
-
default_config :docker_host_url, default_docker_host
|
|
50
|
-
default_config :hostname, 'dokken'
|
|
50
|
+
default_config :hostname, "dokken"
|
|
51
51
|
default_config :image_prefix, nil
|
|
52
52
|
default_config :links, nil
|
|
53
|
-
default_config :
|
|
53
|
+
default_config :memory_limit, 0
|
|
54
|
+
default_config :network_mode, "dokken"
|
|
54
55
|
default_config :pid_one_command, 'sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done"'
|
|
56
|
+
default_config :ports, nil
|
|
55
57
|
default_config :privileged, false
|
|
58
|
+
default_config :pull_chef_image, true
|
|
59
|
+
default_config :pull_platform_image, true
|
|
56
60
|
default_config :read_timeout, 3600
|
|
57
61
|
default_config :security_opt, nil
|
|
58
62
|
default_config :tmpfs, {}
|
|
63
|
+
default_config :userns_host, false
|
|
59
64
|
default_config :volumes, nil
|
|
60
65
|
default_config :write_timeout, 3600
|
|
61
|
-
default_config :userns_host, false
|
|
62
|
-
default_config :pull_platform_image, true
|
|
63
|
-
default_config :pull_chef_image, true
|
|
64
|
-
default_config :memory_limit, 0
|
|
65
66
|
|
|
66
67
|
# (see Base#create)
|
|
67
68
|
def create(state)
|
|
@@ -126,37 +127,38 @@ module Kitchen
|
|
|
126
127
|
|
|
127
128
|
def delete_work_image
|
|
128
129
|
return unless ::Docker::Image.exist?(work_image, {}, docker_connection)
|
|
130
|
+
|
|
129
131
|
with_retries { @work_image = ::Docker::Image.get(work_image, {}, docker_connection) }
|
|
130
132
|
|
|
131
133
|
with_retries do
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
|
|
135
|
+
with_retries { @work_image.remove(force: true) }
|
|
136
|
+
rescue ::Docker::Error::ConflictError
|
|
137
|
+
debug "driver - #{work_image} cannot be removed"
|
|
138
|
+
|
|
137
139
|
end
|
|
138
140
|
end
|
|
139
141
|
|
|
140
142
|
def build_work_image(state)
|
|
141
|
-
info(
|
|
143
|
+
info("Building work image..")
|
|
142
144
|
return if ::Docker::Image.exist?(work_image, {}, docker_connection)
|
|
143
145
|
|
|
144
146
|
begin
|
|
145
147
|
@intermediate_image = ::Docker::Image.build(
|
|
146
148
|
work_image_dockerfile,
|
|
147
149
|
{
|
|
148
|
-
|
|
150
|
+
"t" => work_image,
|
|
149
151
|
},
|
|
150
152
|
docker_connection
|
|
151
153
|
)
|
|
152
154
|
# credit to https://github.com/someara/kitchen-dokken/issues/95#issue-224697526
|
|
153
155
|
rescue Docker::Error::UnexpectedResponseError => e
|
|
154
|
-
msg =
|
|
155
|
-
msg += JSON.parse(e.to_s.split("\r\n").last)[
|
|
156
|
-
msg +=
|
|
157
|
-
msg +=
|
|
158
|
-
msg +=
|
|
159
|
-
msg +=
|
|
156
|
+
msg = "work_image build failed: "
|
|
157
|
+
msg += JSON.parse(e.to_s.split("\r\n").last)["error"].to_s
|
|
158
|
+
msg += ". The common scenarios are incorrect intermediate "
|
|
159
|
+
msg += "instructions such as not including `-y` on an `apt-get` "
|
|
160
|
+
msg += "or similar. The other common scenario is a transient "
|
|
161
|
+
msg += "error such as an unresponsive mirror."
|
|
160
162
|
raise msg
|
|
161
163
|
# fallback rescue above should catch most of the errors
|
|
162
164
|
rescue => e
|
|
@@ -167,8 +169,10 @@ module Kitchen
|
|
|
167
169
|
end
|
|
168
170
|
|
|
169
171
|
def work_image_dockerfile
|
|
172
|
+
from = registry_image_path(platform_image)
|
|
173
|
+
debug("driver - Building work image from #{from}")
|
|
170
174
|
dockerfile_contents = [
|
|
171
|
-
"FROM #{
|
|
175
|
+
"FROM #{from}",
|
|
172
176
|
"LABEL X-Built-By=kitchen-dokken X-Built-From=#{platform_image}",
|
|
173
177
|
]
|
|
174
178
|
Array(config[:intermediate_instructions]).each do |c|
|
|
@@ -219,6 +223,7 @@ module Kitchen
|
|
|
219
223
|
|
|
220
224
|
def work_image
|
|
221
225
|
return "#{image_prefix}/#{instance_name}" unless image_prefix.nil?
|
|
226
|
+
|
|
222
227
|
instance_name
|
|
223
228
|
end
|
|
224
229
|
|
|
@@ -244,7 +249,7 @@ module Kitchen
|
|
|
244
249
|
v
|
|
245
250
|
else
|
|
246
251
|
Array(v).each_with_object({}) do |y, h|
|
|
247
|
-
name, opts = y.split(
|
|
252
|
+
name, opts = y.split(":", 2)
|
|
248
253
|
h[name.to_s] = opts.to_s
|
|
249
254
|
end
|
|
250
255
|
end
|
|
@@ -260,12 +265,13 @@ module Kitchen
|
|
|
260
265
|
b = []
|
|
261
266
|
v = Array(v).to_a # in case v.is_A?(Chef::Node::ImmutableArray)
|
|
262
267
|
v.delete_if do |x|
|
|
263
|
-
parts = x.split(
|
|
268
|
+
parts = x.split(":")
|
|
264
269
|
b << x if parts.length > 1
|
|
265
270
|
end
|
|
266
271
|
b = nil if b.empty?
|
|
267
272
|
config[:binds].push(b) unless config[:binds].include?(b) || b.nil?
|
|
268
273
|
return PartialHash.new if v.empty?
|
|
274
|
+
|
|
269
275
|
v.each_with_object(PartialHash.new) { |volume, h| h[volume] = {} }
|
|
270
276
|
end
|
|
271
277
|
end
|
|
@@ -281,41 +287,42 @@ module Kitchen
|
|
|
281
287
|
debug "driver - starting #{runner_container_name}"
|
|
282
288
|
|
|
283
289
|
config = {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
290
|
+
"name" => runner_container_name,
|
|
291
|
+
"Cmd" => Shellwords.shellwords(self[:pid_one_command]),
|
|
292
|
+
# locally built image, must use short-name
|
|
293
|
+
"Image" => short_image_path(work_image),
|
|
294
|
+
"Hostname" => self[:hostname],
|
|
295
|
+
"Env" => self[:env],
|
|
296
|
+
"ExposedPorts" => exposed_ports,
|
|
297
|
+
"Volumes" => dokken_volumes,
|
|
298
|
+
"HostConfig" => {
|
|
299
|
+
"Privileged" => self[:privileged],
|
|
300
|
+
"VolumesFrom" => dokken_volumes_from,
|
|
301
|
+
"Binds" => dokken_binds,
|
|
302
|
+
"Dns" => self[:dns],
|
|
303
|
+
"DnsSearch" => self[:dns_search],
|
|
304
|
+
"Links" => Array(self[:links]),
|
|
305
|
+
"CapAdd" => Array(self[:cap_add]),
|
|
306
|
+
"CapDrop" => Array(self[:cap_drop]),
|
|
307
|
+
"SecurityOpt" => Array(self[:security_opt]),
|
|
308
|
+
"NetworkMode" => self[:network_mode],
|
|
309
|
+
"PortBindings" => port_bindings,
|
|
310
|
+
"Tmpfs" => dokken_tmpfs,
|
|
311
|
+
"Memory" => self[:memory_limit],
|
|
305
312
|
},
|
|
306
|
-
|
|
307
|
-
|
|
313
|
+
"NetworkingConfig" => {
|
|
314
|
+
"EndpointsConfig" => {
|
|
308
315
|
self[:network_mode] => {
|
|
309
|
-
|
|
316
|
+
"Aliases" => Array(self[:hostname]),
|
|
310
317
|
},
|
|
311
318
|
},
|
|
312
319
|
},
|
|
313
320
|
}
|
|
314
321
|
unless self[:entrypoint].to_s.empty?
|
|
315
|
-
config[
|
|
322
|
+
config["Entrypoint"] = self[:entrypoint]
|
|
316
323
|
end
|
|
317
324
|
if self[:userns_host]
|
|
318
|
-
config[
|
|
325
|
+
config["HostConfig"]["UsernsMode"] = "host"
|
|
319
326
|
end
|
|
320
327
|
runner_container = run_container(config)
|
|
321
328
|
state[:runner_container] = runner_container.json
|
|
@@ -324,17 +331,18 @@ module Kitchen
|
|
|
324
331
|
def start_data_container(state)
|
|
325
332
|
debug "driver - creating #{data_container_name}"
|
|
326
333
|
config = {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
334
|
+
"name" => data_container_name,
|
|
335
|
+
# locally built image, must use short-name
|
|
336
|
+
"Image" => short_image_path(data_image),
|
|
337
|
+
"HostConfig" => {
|
|
338
|
+
"PortBindings" => port_bindings,
|
|
339
|
+
"PublishAllPorts" => true,
|
|
340
|
+
"NetworkMode" => "bridge",
|
|
333
341
|
},
|
|
334
|
-
|
|
335
|
-
|
|
342
|
+
"NetworkingConfig" => {
|
|
343
|
+
"EndpointsConfig" => {
|
|
336
344
|
self[:network_mode] => {
|
|
337
|
-
|
|
345
|
+
"Aliases" => Array(self[:hostname]),
|
|
338
346
|
},
|
|
339
347
|
},
|
|
340
348
|
},
|
|
@@ -347,10 +355,10 @@ module Kitchen
|
|
|
347
355
|
lockfile = Lockfile.new "#{home_dir}/.dokken-network.lock"
|
|
348
356
|
begin
|
|
349
357
|
lockfile.lock
|
|
350
|
-
with_retries { ::Docker::Network.get(
|
|
351
|
-
rescue
|
|
358
|
+
with_retries { ::Docker::Network.get("dokken", {}, docker_connection) }
|
|
359
|
+
rescue ::Docker::Error::NotFoundError
|
|
352
360
|
begin
|
|
353
|
-
with_retries { ::Docker::Network.create(
|
|
361
|
+
with_retries { ::Docker::Network.create("dokken", {}) }
|
|
354
362
|
rescue ::Docker::Error => e
|
|
355
363
|
debug "driver - error :#{e}:"
|
|
356
364
|
end
|
|
@@ -360,32 +368,39 @@ module Kitchen
|
|
|
360
368
|
end
|
|
361
369
|
|
|
362
370
|
def make_data_image
|
|
363
|
-
debug
|
|
364
|
-
create_data_image
|
|
371
|
+
debug "driver - calling create_data_image"
|
|
372
|
+
create_data_image(config[:docker_registry])
|
|
365
373
|
end
|
|
366
374
|
|
|
367
375
|
def create_chef_container(state)
|
|
368
376
|
lockfile = Lockfile.new "#{home_dir}/.dokken-#{chef_container_name}.lock"
|
|
369
377
|
begin
|
|
370
378
|
lockfile.lock
|
|
371
|
-
with_retries {
|
|
379
|
+
with_retries {
|
|
380
|
+
# TEMPORARY FIX - docker-api 2.0.0 has a buggy Docker::Container.get - use .all instead
|
|
381
|
+
# https://github.com/swipely/docker-api/issues/566
|
|
382
|
+
# ::Docker::Container.get(chef_container_name, {}, docker_connection)
|
|
383
|
+
found = ::Docker::Container.all({ all: true }, docker_connection).select { |c| c.info["Names"].include?("/#{chef_container_name}") }
|
|
384
|
+
raise ::Docker::Error::NotFoundError.new(chef_container_name) if found.empty?
|
|
385
|
+
|
|
386
|
+
debug "Chef container already exists, continuing"
|
|
387
|
+
}
|
|
372
388
|
rescue ::Docker::Error::NotFoundError
|
|
389
|
+
debug "Chef container does not exist, creating a new Chef container"
|
|
373
390
|
with_retries do
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
raise "driver - #{chef_container_name} failed to create #{e}"
|
|
388
|
-
end
|
|
391
|
+
debug "driver - creating volume container #{chef_container_name} from #{chef_image}"
|
|
392
|
+
config = {
|
|
393
|
+
"name" => chef_container_name,
|
|
394
|
+
"Cmd" => "true",
|
|
395
|
+
"Image" => registry_image_path(chef_image),
|
|
396
|
+
"HostConfig" => {
|
|
397
|
+
"NetworkMode" => self[:network_mode],
|
|
398
|
+
},
|
|
399
|
+
}
|
|
400
|
+
chef_container = create_container(config)
|
|
401
|
+
state[:chef_container] = chef_container.json
|
|
402
|
+
rescue ::Docker::Error, StandardError => e
|
|
403
|
+
raise "driver - #{chef_container_name} failed to create #{e}"
|
|
389
404
|
end
|
|
390
405
|
ensure
|
|
391
406
|
lockfile.unlock
|
|
@@ -393,12 +408,12 @@ module Kitchen
|
|
|
393
408
|
end
|
|
394
409
|
|
|
395
410
|
def pull_platform_image
|
|
396
|
-
debug "driver - pulling #{
|
|
411
|
+
debug "driver - pulling #{short_image_path(platform_image)}"
|
|
397
412
|
config[:pull_platform_image] ? pull_image(platform_image) : pull_if_missing(platform_image)
|
|
398
413
|
end
|
|
399
414
|
|
|
400
415
|
def pull_chef_image
|
|
401
|
-
debug "driver - pulling #{
|
|
416
|
+
debug "driver - pulling #{short_image_path(chef_image)}"
|
|
402
417
|
config[:pull_chef_image] ? pull_image(chef_image) : pull_if_missing(chef_image)
|
|
403
418
|
end
|
|
404
419
|
|
|
@@ -411,50 +426,83 @@ module Kitchen
|
|
|
411
426
|
|
|
412
427
|
def container_exist?(name)
|
|
413
428
|
return true if ::Docker::Container.get(name, {}, docker_connection)
|
|
414
|
-
rescue
|
|
429
|
+
rescue StandardError, ::Docker::Error::NotFoundError
|
|
415
430
|
false
|
|
416
431
|
end
|
|
417
432
|
|
|
418
433
|
def parse_image_name(image)
|
|
419
|
-
parts = image.split(
|
|
434
|
+
parts = image.split(":")
|
|
420
435
|
|
|
421
436
|
if parts.size > 2
|
|
422
437
|
tag = parts.pop
|
|
423
|
-
repo = parts.join(
|
|
438
|
+
repo = parts.join(":")
|
|
424
439
|
else
|
|
425
|
-
tag = parts[1] ||
|
|
440
|
+
tag = parts[1] || "latest"
|
|
426
441
|
repo = parts[0]
|
|
427
442
|
end
|
|
428
443
|
|
|
429
444
|
[repo, tag]
|
|
430
445
|
end
|
|
431
446
|
|
|
447
|
+
# Return the 'repo' half of a docker image path. Agnostic about if a
|
|
448
|
+
# registry is included, this effectively is just "before the colon"
|
|
449
|
+
#
|
|
450
|
+
# @param image [String] the docker image path to parse
|
|
451
|
+
# @return [String] the repo portion of `image`
|
|
432
452
|
def repo(image)
|
|
433
453
|
parse_image_name(image)[0]
|
|
434
454
|
end
|
|
435
455
|
|
|
456
|
+
# Return the 'tag' of a docker image path. Will be `latest` if there
|
|
457
|
+
# is no explicit tag in the image path.
|
|
458
|
+
#
|
|
459
|
+
# @param image [String] the docker image path to parse
|
|
460
|
+
# @return [String] the tag of `image`
|
|
461
|
+
def tag(image)
|
|
462
|
+
parse_image_name(image)[1]
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
# Ensures an explicit tag on an image path.
|
|
466
|
+
#
|
|
467
|
+
# @param image [String] the docker image path to parse
|
|
468
|
+
# @return [String] `repo`:`tag`
|
|
469
|
+
def short_image_path(image)
|
|
470
|
+
"#{repo(image)}:#{tag(image)}"
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
# Qualifies the results of `short_image_path` with any registry the
|
|
474
|
+
# user has requested
|
|
475
|
+
#
|
|
476
|
+
# @param image [String] the docker image path to parse
|
|
477
|
+
# @return [String] The most fully-qualified registry path we cn make
|
|
478
|
+
def registry_image_path(image)
|
|
479
|
+
if config[:docker_registry]
|
|
480
|
+
"#{config[:docker_registry]}/#{short_image_path(image)}"
|
|
481
|
+
else
|
|
482
|
+
short_image_path(image)
|
|
483
|
+
end
|
|
484
|
+
end
|
|
485
|
+
|
|
436
486
|
def create_container(args)
|
|
437
|
-
with_retries { @container = ::Docker::Container.get(args[
|
|
487
|
+
with_retries { @container = ::Docker::Container.get(args["name"], {}, docker_connection) }
|
|
438
488
|
rescue
|
|
439
489
|
with_retries do
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
with_retries { @container = ::Docker::Container.get(args['name'], {}, docker_connection) }
|
|
452
|
-
end
|
|
453
|
-
end
|
|
454
|
-
rescue ::Docker::Error => e
|
|
455
|
-
debug "driver - error :#{e}:"
|
|
456
|
-
raise "driver - failed to create_container #{args['name']}"
|
|
490
|
+
args["Env"] = [] if args["Env"].nil?
|
|
491
|
+
args["Env"] << "TEST_KITCHEN=1"
|
|
492
|
+
args["Env"] << "CI=#{ENV["CI"]}" if ENV.include? "CI"
|
|
493
|
+
info "Creating container #{args["name"]}"
|
|
494
|
+
debug "driver - create_container args #{args}"
|
|
495
|
+
with_retries do
|
|
496
|
+
|
|
497
|
+
@container = ::Docker::Container.create(args.clone, docker_connection)
|
|
498
|
+
rescue ::Docker::Error::ConflictError
|
|
499
|
+
debug "driver - rescue ConflictError: #{args["name"]}"
|
|
500
|
+
with_retries { @container = ::Docker::Container.get(args["name"], {}, docker_connection) }
|
|
457
501
|
end
|
|
502
|
+
rescue ::Docker::Error => e
|
|
503
|
+
debug "driver - error :#{e}:"
|
|
504
|
+
raise "driver - failed to create_container #{args["name"]}"
|
|
505
|
+
|
|
458
506
|
end
|
|
459
507
|
end
|
|
460
508
|
|
|
@@ -462,14 +510,14 @@ module Kitchen
|
|
|
462
510
|
create_container(args)
|
|
463
511
|
with_retries do
|
|
464
512
|
@container.start
|
|
465
|
-
@container = ::Docker::Container.get(args[
|
|
466
|
-
wait_running_state(args[
|
|
513
|
+
@container = ::Docker::Container.get(args["name"], {}, docker_connection)
|
|
514
|
+
wait_running_state(args["name"], true)
|
|
467
515
|
end
|
|
468
516
|
@container
|
|
469
517
|
end
|
|
470
518
|
|
|
471
519
|
def container_state
|
|
472
|
-
@container ? @container.info[
|
|
520
|
+
@container ? @container.info["State"] : {}
|
|
473
521
|
end
|
|
474
522
|
|
|
475
523
|
def stop_container(name)
|
|
@@ -493,18 +541,15 @@ module Kitchen
|
|
|
493
541
|
@container = ::Docker::Container.get(name, {}, docker_connection)
|
|
494
542
|
i = 0
|
|
495
543
|
tries = 20
|
|
496
|
-
until container_state[
|
|
544
|
+
until container_state["Running"] == v || container_state["FinishedAt"] != "0001-01-01T00:00:00Z"
|
|
497
545
|
i += 1
|
|
498
546
|
break if i == tries
|
|
547
|
+
|
|
499
548
|
sleep 0.1
|
|
500
549
|
@container = ::Docker::Container.get(name, {}, docker_connection)
|
|
501
550
|
end
|
|
502
551
|
end
|
|
503
552
|
|
|
504
|
-
def tag(image)
|
|
505
|
-
parse_image_name(image)[1]
|
|
506
|
-
end
|
|
507
|
-
|
|
508
553
|
def chef_container_name
|
|
509
554
|
"chef-#{chef_version}"
|
|
510
555
|
end
|
|
@@ -514,7 +559,8 @@ module Kitchen
|
|
|
514
559
|
end
|
|
515
560
|
|
|
516
561
|
def chef_version
|
|
517
|
-
return
|
|
562
|
+
return "latest" if config[:chef_version] == "stable"
|
|
563
|
+
|
|
518
564
|
config[:chef_version]
|
|
519
565
|
end
|
|
520
566
|
|
|
@@ -531,27 +577,29 @@ module Kitchen
|
|
|
531
577
|
end
|
|
532
578
|
|
|
533
579
|
def platform_image_from_name
|
|
534
|
-
platform, release = instance.platform.name.split(
|
|
535
|
-
release ? [platform, release].join(
|
|
580
|
+
platform, release = instance.platform.name.split("-")
|
|
581
|
+
release ? [platform, release].join(":") : platform
|
|
536
582
|
end
|
|
537
583
|
|
|
538
584
|
def pull_if_missing(image)
|
|
539
|
-
return if ::Docker::Image.exist?(
|
|
585
|
+
return if ::Docker::Image.exist?(registry_image_path(image), {}, docker_connection)
|
|
586
|
+
|
|
540
587
|
pull_image image
|
|
541
588
|
end
|
|
542
589
|
|
|
543
590
|
# https://github.com/docker/docker/blob/4fcb9ac40ce33c4d6e08d5669af6be5e076e2574/registry/auth.go#L231
|
|
544
591
|
def parse_registry_host(val)
|
|
545
|
-
val.sub(%r{https?://},
|
|
592
|
+
val.sub(%r{https?://}, "").split("/").first
|
|
546
593
|
end
|
|
547
594
|
|
|
548
595
|
def pull_image(image)
|
|
596
|
+
path = registry_image_path(image)
|
|
549
597
|
with_retries do
|
|
550
|
-
if Docker::Image.exist?(
|
|
551
|
-
original_image = Docker::Image.get(
|
|
598
|
+
if Docker::Image.exist?(path, {}, docker_connection)
|
|
599
|
+
original_image = Docker::Image.get(path, {}, docker_connection)
|
|
552
600
|
end
|
|
553
601
|
|
|
554
|
-
new_image = Docker::Image.create({
|
|
602
|
+
new_image = Docker::Image.create({ "fromImage" => path }, docker_connection)
|
|
555
603
|
|
|
556
604
|
!(original_image && original_image.id.start_with?(new_image.id))
|
|
557
605
|
end
|
data/lib/kitchen/helpers.rb
CHANGED
|
@@ -1,23 +1,20 @@
|
|
|
1
1
|
module Dokken
|
|
2
2
|
module Helpers
|
|
3
3
|
# https://stackoverflow.com/questions/517219/ruby-see-if-a-port-is-open
|
|
4
|
-
require
|
|
5
|
-
require
|
|
4
|
+
require "socket" unless defined?(Socket)
|
|
5
|
+
require "timeout" unless defined?(Timeout)
|
|
6
6
|
|
|
7
7
|
def port_open?(ip, port)
|
|
8
8
|
begin
|
|
9
9
|
Timeout.timeout(1) do
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
return false
|
|
16
|
-
end
|
|
10
|
+
s = TCPSocket.new(ip, port)
|
|
11
|
+
s.close
|
|
12
|
+
return true
|
|
13
|
+
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, Errno::ENETDOWN
|
|
14
|
+
return false
|
|
17
15
|
end
|
|
18
16
|
rescue Timeout::Error
|
|
19
17
|
end
|
|
20
|
-
|
|
21
18
|
false
|
|
22
19
|
end
|
|
23
20
|
|
|
@@ -59,9 +56,13 @@ X8N2N9ZNnORJqK374yGj1jWUU66mQhPvn49QpG8P2HEoh2RQjNvyHA==
|
|
|
59
56
|
EOF
|
|
60
57
|
end
|
|
61
58
|
|
|
62
|
-
def data_dockerfile
|
|
59
|
+
def data_dockerfile(registry)
|
|
60
|
+
from = "centos:7"
|
|
61
|
+
if registry
|
|
62
|
+
from = "#{registry}/#{from}"
|
|
63
|
+
end
|
|
63
64
|
<<-EOF
|
|
64
|
-
FROM
|
|
65
|
+
FROM #{from}
|
|
65
66
|
MAINTAINER Sean OMeara \"sean@sean.io\"
|
|
66
67
|
ENV LANG en_US.UTF-8
|
|
67
68
|
|
|
@@ -86,32 +87,32 @@ VOLUME /opt/verifier
|
|
|
86
87
|
EOF
|
|
87
88
|
end
|
|
88
89
|
|
|
89
|
-
def create_data_image
|
|
90
|
+
def create_data_image(registry)
|
|
90
91
|
return if ::Docker::Image.exist?(data_image)
|
|
91
92
|
|
|
92
93
|
tmpdir = Dir.tmpdir
|
|
93
94
|
FileUtils.mkdir_p "#{tmpdir}/dokken"
|
|
94
|
-
File.write("#{tmpdir}/dokken/Dockerfile", data_dockerfile)
|
|
95
|
+
File.write("#{tmpdir}/dokken/Dockerfile", data_dockerfile(registry))
|
|
95
96
|
File.write("#{tmpdir}/dokken/authorized_keys", insecure_ssh_public_key)
|
|
96
97
|
|
|
97
98
|
i = ::Docker::Image.build_from_dir(
|
|
98
99
|
"#{tmpdir}/dokken",
|
|
99
|
-
|
|
100
|
-
|
|
100
|
+
"nocache" => true,
|
|
101
|
+
"rm" => true
|
|
101
102
|
)
|
|
102
|
-
i.tag(
|
|
103
|
+
i.tag("repo" => repo(data_image), "tag" => tag(data_image), "force" => true)
|
|
103
104
|
end
|
|
104
105
|
|
|
105
106
|
def default_docker_host
|
|
106
|
-
if ENV[
|
|
107
|
-
ENV[
|
|
108
|
-
elsif File.exist?(
|
|
109
|
-
|
|
107
|
+
if ENV["DOCKER_HOST"]
|
|
108
|
+
ENV["DOCKER_HOST"]
|
|
109
|
+
elsif File.exist?("/var/run/docker.sock")
|
|
110
|
+
"unix:///var/run/docker.sock"
|
|
110
111
|
# TODO: Docker for Windows also operates over a named pipe at
|
|
111
112
|
# //./pipe/docker_engine that can be used if named pipe support is
|
|
112
113
|
# added to the docker-api gem.
|
|
113
114
|
else
|
|
114
|
-
|
|
115
|
+
"tcp://127.0.0.1:2375"
|
|
115
116
|
end
|
|
116
117
|
end
|
|
117
118
|
|
|
@@ -152,7 +153,8 @@ VOLUME /opt/verifier
|
|
|
152
153
|
# refs:
|
|
153
154
|
# https://github.com/docker/machine/issues/1814
|
|
154
155
|
# https://github.com/docker/toolbox/issues/607
|
|
155
|
-
return Dir.home.sub
|
|
156
|
+
return Dir.home.sub "C:/Users", "/c/Users" if Dir.home =~ /^C:/ && remote_docker_host?
|
|
157
|
+
|
|
156
158
|
Dir.home
|
|
157
159
|
end
|
|
158
160
|
|
|
@@ -185,7 +187,7 @@ VOLUME /opt/verifier
|
|
|
185
187
|
x = Array(v).map { |a| parse_port(a) }
|
|
186
188
|
x.flatten!
|
|
187
189
|
x.each_with_object({}) do |y, h|
|
|
188
|
-
h[y[
|
|
190
|
+
h[y["container_port"]] = {}
|
|
189
191
|
end
|
|
190
192
|
end
|
|
191
193
|
end
|
|
@@ -198,52 +200,53 @@ VOLUME /opt/verifier
|
|
|
198
200
|
x = Array(v).map { |a| parse_port(a) }
|
|
199
201
|
x.flatten!
|
|
200
202
|
x.each_with_object({}) do |y, h|
|
|
201
|
-
h[y[
|
|
202
|
-
h[y[
|
|
203
|
-
|
|
204
|
-
|
|
203
|
+
h[y["container_port"]] = [] unless h[y["container_port"]]
|
|
204
|
+
h[y["container_port"]] << {
|
|
205
|
+
"HostIp" => y["host_ip"],
|
|
206
|
+
"HostPort" => y["host_port"],
|
|
205
207
|
}
|
|
206
208
|
end
|
|
207
209
|
end
|
|
208
210
|
end
|
|
209
211
|
|
|
210
212
|
def parse_port(v)
|
|
211
|
-
parts = v.split(
|
|
213
|
+
parts = v.split(":")
|
|
212
214
|
case parts.length
|
|
213
215
|
when 3
|
|
214
216
|
host_ip = parts[0]
|
|
215
217
|
host_port = parts[1]
|
|
216
218
|
container_port = parts[2]
|
|
217
219
|
when 2
|
|
218
|
-
host_ip =
|
|
220
|
+
host_ip = "0.0.0.0"
|
|
219
221
|
host_port = parts[0]
|
|
220
222
|
container_port = parts[1]
|
|
221
223
|
when 1
|
|
222
|
-
host_ip =
|
|
223
|
-
host_port =
|
|
224
|
+
host_ip = ""
|
|
225
|
+
host_port = ""
|
|
224
226
|
container_port = parts[0]
|
|
225
227
|
end
|
|
226
|
-
port_range, protocol = container_port.split(
|
|
227
|
-
if port_range.include?(
|
|
228
|
-
port_range = container_port.split(
|
|
228
|
+
port_range, protocol = container_port.split("/")
|
|
229
|
+
if port_range.include?("-")
|
|
230
|
+
port_range = container_port.split("-")
|
|
229
231
|
port_range.map!(&:to_i)
|
|
230
232
|
Chef::Log.fatal("FATAL: Invalid port range! #{container_port}") if port_range[0] > port_range[1]
|
|
231
233
|
port_range = (port_range[0]..port_range[1]).to_a
|
|
232
234
|
end
|
|
233
235
|
# qualify the port-binding protocol even when it is implicitly tcp #427.
|
|
234
|
-
protocol =
|
|
236
|
+
protocol = "tcp" if protocol.nil?
|
|
235
237
|
Array(port_range).map do |port|
|
|
236
238
|
{
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
239
|
+
"host_ip" => host_ip,
|
|
240
|
+
"host_port" => host_port,
|
|
241
|
+
"container_port" => "#{port}/#{protocol}",
|
|
240
242
|
}
|
|
241
243
|
end
|
|
242
244
|
end
|
|
243
245
|
|
|
244
246
|
def remote_docker_host?
|
|
245
|
-
return false if config[:docker_info][
|
|
246
|
-
return true if config[:docker_host_url]
|
|
247
|
+
return false if config[:docker_info]["OperatingSystem"].include?("Boot2Docker")
|
|
248
|
+
return true if /^tcp:/.match?(config[:docker_host_url])
|
|
249
|
+
|
|
247
250
|
false
|
|
248
251
|
end
|
|
249
252
|
|
|
@@ -252,13 +255,13 @@ VOLUME /opt/verifier
|
|
|
252
255
|
end
|
|
253
256
|
|
|
254
257
|
def sandbox_dirs
|
|
255
|
-
Dir.glob(File.join(sandbox_path,
|
|
258
|
+
Dir.glob(File.join(sandbox_path, "*"))
|
|
256
259
|
end
|
|
257
260
|
|
|
258
261
|
def create_sandbox
|
|
259
262
|
info("Creating kitchen sandbox in #{sandbox_path}")
|
|
260
263
|
unless ::Dir.exist?(sandbox_path)
|
|
261
|
-
FileUtils.mkdir_p(sandbox_path, :
|
|
264
|
+
FileUtils.mkdir_p(sandbox_path, mode: 0o755)
|
|
262
265
|
end
|
|
263
266
|
end
|
|
264
267
|
end
|
|
@@ -269,7 +272,7 @@ module Kitchen
|
|
|
269
272
|
class Base
|
|
270
273
|
def create_sandbox
|
|
271
274
|
info("Creating kitchen sandbox in #{sandbox_path}")
|
|
272
|
-
FileUtils.mkdir_p(sandbox_path, :
|
|
275
|
+
FileUtils.mkdir_p(sandbox_path, mode: 0o755)
|
|
273
276
|
end
|
|
274
277
|
|
|
275
278
|
# this MUST be named 'sandbox_path' because ruby.
|
|
@@ -291,7 +294,7 @@ module Kitchen
|
|
|
291
294
|
def create_sandbox
|
|
292
295
|
info("Creating kitchen sandbox in #{sandbox_path}")
|
|
293
296
|
unless ::Dir.exist?(sandbox_path)
|
|
294
|
-
FileUtils.mkdir_p(sandbox_path, :
|
|
297
|
+
FileUtils.mkdir_p(sandbox_path, mode: 0o755)
|
|
295
298
|
end
|
|
296
299
|
end
|
|
297
300
|
|
|
@@ -313,7 +316,7 @@ module Kitchen
|
|
|
313
316
|
conn.execute(init_command)
|
|
314
317
|
info("Transferring files to #{instance.to_str}")
|
|
315
318
|
conn.upload(sandbox_dirs, config[:root_path])
|
|
316
|
-
debug(
|
|
319
|
+
debug("Transfer complete")
|
|
317
320
|
end
|
|
318
321
|
|
|
319
322
|
conn.execute(prepare_command)
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
# See the License for the specific language governing permissions and
|
|
16
16
|
# limitations under the License.
|
|
17
17
|
|
|
18
|
-
require
|
|
19
|
-
require
|
|
20
|
-
require_relative
|
|
18
|
+
require "kitchen"
|
|
19
|
+
require "kitchen/provisioner/chef_zero"
|
|
20
|
+
require_relative "../helpers"
|
|
21
21
|
|
|
22
22
|
include Dokken::Helpers
|
|
23
23
|
|
|
@@ -29,11 +29,12 @@ module Kitchen
|
|
|
29
29
|
|
|
30
30
|
plugin_version Kitchen::VERSION
|
|
31
31
|
|
|
32
|
-
default_config :root_path,
|
|
33
|
-
default_config :chef_binary,
|
|
34
|
-
default_config :chef_options,
|
|
35
|
-
default_config :chef_log_level,
|
|
36
|
-
default_config :chef_output_format,
|
|
32
|
+
default_config :root_path, "/opt/kitchen"
|
|
33
|
+
default_config :chef_binary, "/opt/chef/bin/chef-client"
|
|
34
|
+
default_config :chef_options, " -z"
|
|
35
|
+
default_config :chef_log_level, "warn"
|
|
36
|
+
default_config :chef_output_format, "doc"
|
|
37
|
+
default_config :profile_ruby, false
|
|
37
38
|
default_config :docker_info, docker_info
|
|
38
39
|
default_config :docker_host_url, default_docker_host
|
|
39
40
|
|
|
@@ -45,7 +46,7 @@ module Kitchen
|
|
|
45
46
|
# driver and set it here. If we remove this, users will set their chef_version
|
|
46
47
|
# to 14 in the driver and still get prompted for license acceptance because
|
|
47
48
|
# the ChefZero provisioner defaults product_version to 'latest'.
|
|
48
|
-
default_config :product_name,
|
|
49
|
+
default_config :product_name, "chef"
|
|
49
50
|
default_config :product_version do |provisioner|
|
|
50
51
|
driver = provisioner.instance.driver
|
|
51
52
|
driver[:chef_version]
|
|
@@ -73,15 +74,16 @@ module Kitchen
|
|
|
73
74
|
rescue Kitchen::Transport::TransportFailed => ex
|
|
74
75
|
raise ActionFailed, ex.message
|
|
75
76
|
ensure
|
|
76
|
-
return unless config[:clean_dokken_sandbox]
|
|
77
|
+
return unless config[:clean_dokken_sandbox] # rubocop: disable Lint/EnsureReturn
|
|
78
|
+
|
|
77
79
|
cleanup_dokken_sandbox
|
|
78
80
|
end
|
|
79
81
|
|
|
80
82
|
def validate_config
|
|
81
83
|
# check if we have an space for the user provided options
|
|
82
84
|
# or add it if not to avoid issues
|
|
83
|
-
unless config[:chef_options].start_with?
|
|
84
|
-
config[:chef_options].prepend(
|
|
85
|
+
unless config[:chef_options].start_with? " "
|
|
86
|
+
config[:chef_options].prepend(" ")
|
|
85
87
|
end
|
|
86
88
|
|
|
87
89
|
# strip spaces from all other options
|
|
@@ -91,8 +93,8 @@ module Kitchen
|
|
|
91
93
|
|
|
92
94
|
# if the user wants to be funny and pass empty strings
|
|
93
95
|
# just use the defaults
|
|
94
|
-
config[:chef_log_level] =
|
|
95
|
-
config[:chef_output_format] =
|
|
96
|
+
config[:chef_log_level] = "warn" if config[:chef_log_level].empty?
|
|
97
|
+
config[:chef_output_format] = "doc" if config[:chef_output_format].empty?
|
|
96
98
|
end
|
|
97
99
|
|
|
98
100
|
private
|
|
@@ -104,8 +106,9 @@ module Kitchen
|
|
|
104
106
|
cmd << config[:chef_options].to_s
|
|
105
107
|
cmd << " -l #{config[:chef_log_level]}"
|
|
106
108
|
cmd << " -F #{config[:chef_output_format]}"
|
|
107
|
-
cmd <<
|
|
108
|
-
cmd <<
|
|
109
|
+
cmd << " -c /opt/kitchen/client.rb"
|
|
110
|
+
cmd << " -j /opt/kitchen/dna.json"
|
|
111
|
+
cmd << "--profile-ruby" if config[:profile_ruby]
|
|
109
112
|
|
|
110
113
|
chef_cmd(cmd)
|
|
111
114
|
end
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
# See the License for the specific language governing permissions and
|
|
16
16
|
# limitations under the License.
|
|
17
17
|
|
|
18
|
-
require
|
|
19
|
-
require
|
|
20
|
-
require
|
|
21
|
-
require
|
|
22
|
-
require_relative
|
|
18
|
+
require "kitchen"
|
|
19
|
+
require "net/scp"
|
|
20
|
+
require "tmpdir" unless defined?(Dir.mktmpdir)
|
|
21
|
+
require "digest/sha1" unless defined?(Digest::SHA1)
|
|
22
|
+
require_relative "../helpers"
|
|
23
23
|
|
|
24
24
|
include Dokken::Helpers
|
|
25
25
|
|
|
@@ -44,7 +44,7 @@ module Kitchen
|
|
|
44
44
|
default_config :read_timeout, 3600
|
|
45
45
|
default_config :write_timeout, 3600
|
|
46
46
|
default_config :host_ip_override do |transport|
|
|
47
|
-
transport.docker_for_mac_or_win? ?
|
|
47
|
+
transport.docker_for_mac_or_win? ? "localhost" : false
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
# (see Base#connection)
|
|
@@ -69,7 +69,7 @@ module Kitchen
|
|
|
69
69
|
|
|
70
70
|
with_retries { @runner = ::Docker::Container.get(instance_name, {}, docker_connection) }
|
|
71
71
|
with_retries do
|
|
72
|
-
o = @runner.exec(Shellwords.shellwords(command), wait: options[:timeout],
|
|
72
|
+
o = @runner.exec(Shellwords.shellwords(command), wait: options[:timeout], "e" => { "TERM" => "xterm" }) { |_stream, chunk| print chunk.to_s }
|
|
73
73
|
@exit_code = o[2]
|
|
74
74
|
end
|
|
75
75
|
|
|
@@ -82,26 +82,26 @@ module Kitchen
|
|
|
82
82
|
ssh_ip = options[:host_ip_override]
|
|
83
83
|
ssh_port = options[:data_container][:NetworkSettings][:Ports][:"22/tcp"][0][:HostPort]
|
|
84
84
|
|
|
85
|
-
elsif options[:docker_host_url]
|
|
86
|
-
if options[:data_container][:NetworkSettings][:Ports][:"22/tcp"][0][:HostIp] ==
|
|
85
|
+
elsif /unix:/.match?(options[:docker_host_url])
|
|
86
|
+
if options[:data_container][:NetworkSettings][:Ports][:"22/tcp"][0][:HostIp] == "0.0.0.0"
|
|
87
87
|
ssh_ip = options[:data_container][:NetworkSettings][:IPAddress]
|
|
88
|
-
ssh_port =
|
|
88
|
+
ssh_port = "22"
|
|
89
89
|
else
|
|
90
90
|
# we should read the proper mapped ip, since this allows us to upload the files
|
|
91
91
|
ssh_ip = options[:data_container][:NetworkSettings][:Ports][:"22/tcp"][0][:HostIp]
|
|
92
92
|
ssh_port = options[:data_container][:NetworkSettings][:Ports][:"22/tcp"][0][:HostPort]
|
|
93
93
|
end
|
|
94
94
|
|
|
95
|
-
elsif options[:docker_host_url]
|
|
95
|
+
elsif /tcp:/.match?(options[:docker_host_url])
|
|
96
96
|
name = options[:data_container][:Name]
|
|
97
97
|
|
|
98
98
|
# DOCKER_HOST
|
|
99
|
-
docker_host_url_ip = options[:docker_host_url].split(
|
|
99
|
+
docker_host_url_ip = options[:docker_host_url].split("tcp://")[1].split(":")[0]
|
|
100
100
|
|
|
101
101
|
# mapped IP of data container
|
|
102
|
-
candidate_ip = ::Docker::Container.all.
|
|
103
|
-
x.info[
|
|
104
|
-
end.
|
|
102
|
+
candidate_ip = ::Docker::Container.all.find do |x|
|
|
103
|
+
x.info["Names"][0].eql?(name)
|
|
104
|
+
end.info["NetworkSettings"]["Networks"]["dokken"]["IPAddress"]
|
|
105
105
|
|
|
106
106
|
# mapped port
|
|
107
107
|
candidate_ssh_port = options[:data_container][:NetworkSettings][:Ports][:"22/tcp"][0][:HostPort]
|
|
@@ -114,22 +114,22 @@ module Kitchen
|
|
|
114
114
|
ssh_ip = candidate_ip
|
|
115
115
|
ssh_port = candidate_ssh_port
|
|
116
116
|
|
|
117
|
-
elsif port_open?(candidate_ip,
|
|
117
|
+
elsif port_open?(candidate_ip, "22")
|
|
118
118
|
ssh_ip = candidate_ip
|
|
119
|
-
ssh_port =
|
|
119
|
+
ssh_port = "22"
|
|
120
120
|
debug "candidate_ip - #{candidate_ip}/22 open"
|
|
121
121
|
else
|
|
122
122
|
ssh_ip = docker_host_url_ip
|
|
123
123
|
ssh_port = candidate_ssh_port
|
|
124
124
|
end
|
|
125
125
|
else
|
|
126
|
-
raise Kitchen::UserError,
|
|
126
|
+
raise Kitchen::UserError, "docker_host_url must be tcp:// or unix://"
|
|
127
127
|
end
|
|
128
128
|
|
|
129
129
|
debug "ssh_ip : #{ssh_ip}"
|
|
130
130
|
debug "ssh_port : #{ssh_port}"
|
|
131
131
|
|
|
132
|
-
tmpdir = Dir.tmpdir +
|
|
132
|
+
tmpdir = Dir.tmpdir + "/dokken/"
|
|
133
133
|
FileUtils.mkdir_p tmpdir.to_s, mode: 0o777
|
|
134
134
|
tmpdir += Process.uid.to_s
|
|
135
135
|
FileUtils.mkdir_p tmpdir.to_s
|
|
@@ -137,26 +137,26 @@ module Kitchen
|
|
|
137
137
|
FileUtils.chmod(0o600, "#{tmpdir}/id_rsa")
|
|
138
138
|
|
|
139
139
|
begin
|
|
140
|
-
rsync_cmd =
|
|
141
|
-
rsync_cmd <<
|
|
142
|
-
rsync_cmd <<
|
|
140
|
+
rsync_cmd = "/usr/bin/rsync -a -e"
|
|
141
|
+
rsync_cmd << " '"
|
|
142
|
+
rsync_cmd << "ssh -2"
|
|
143
143
|
rsync_cmd << " -i #{tmpdir}/id_rsa"
|
|
144
|
-
rsync_cmd <<
|
|
145
|
-
rsync_cmd <<
|
|
146
|
-
rsync_cmd <<
|
|
147
|
-
rsync_cmd <<
|
|
148
|
-
rsync_cmd <<
|
|
149
|
-
rsync_cmd <<
|
|
144
|
+
rsync_cmd << " -o CheckHostIP=no"
|
|
145
|
+
rsync_cmd << " -o Compression=no"
|
|
146
|
+
rsync_cmd << " -o PasswordAuthentication=no"
|
|
147
|
+
rsync_cmd << " -o StrictHostKeyChecking=no"
|
|
148
|
+
rsync_cmd << " -o UserKnownHostsFile=/dev/null"
|
|
149
|
+
rsync_cmd << " -o LogLevel=ERROR"
|
|
150
150
|
rsync_cmd << " -p #{ssh_port}"
|
|
151
|
-
rsync_cmd << '
|
|
152
|
-
rsync_cmd << " #{locals.join(
|
|
151
|
+
rsync_cmd << "'"
|
|
152
|
+
rsync_cmd << " #{locals.join(" ")} root@#{ssh_ip}:#{remote}"
|
|
153
153
|
debug "rsync_cmd :#{rsync_cmd}:"
|
|
154
154
|
`#{rsync_cmd}`
|
|
155
155
|
rescue Errno::ENOENT
|
|
156
|
-
debug
|
|
156
|
+
debug "Rsync is not installed. Falling back to SCP."
|
|
157
157
|
locals.each do |local|
|
|
158
158
|
Net::SCP.upload!(ssh_ip,
|
|
159
|
-
|
|
159
|
+
"root",
|
|
160
160
|
local,
|
|
161
161
|
remote,
|
|
162
162
|
recursive: true,
|
|
@@ -169,8 +169,8 @@ module Kitchen
|
|
|
169
169
|
@runner = options[:instance_name].to_s
|
|
170
170
|
cols = `tput cols`
|
|
171
171
|
lines = `tput lines`
|
|
172
|
-
args = [
|
|
173
|
-
LoginCommand.new(
|
|
172
|
+
args = ["exec", "-e", "COLUMNS=#{cols}", "-e", "LINES=#{lines}", "-it", @runner, "/bin/bash", "-login", "-i"]
|
|
173
|
+
LoginCommand.new("docker", args)
|
|
174
174
|
end
|
|
175
175
|
|
|
176
176
|
private
|
|
@@ -181,6 +181,7 @@ module Kitchen
|
|
|
181
181
|
|
|
182
182
|
def work_image
|
|
183
183
|
return "#{image_prefix}/#{instance_name}" unless image_prefix.nil?
|
|
184
|
+
|
|
184
185
|
instance_name
|
|
185
186
|
end
|
|
186
187
|
|
|
@@ -208,7 +209,7 @@ module Kitchen
|
|
|
208
209
|
#
|
|
209
210
|
# @return [TrueClass,FalseClass]
|
|
210
211
|
def docker_for_mac_or_win?
|
|
211
|
-
::Docker.info(::Docker::Connection.new(config[:docker_host_url], {}))[
|
|
212
|
+
::Docker.info(::Docker::Connection.new(config[:docker_host_url], {}))["Name"] == "moby"
|
|
212
213
|
rescue
|
|
213
214
|
false
|
|
214
215
|
end
|
metadata
CHANGED
|
@@ -1,29 +1,35 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kitchen-dokken
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.12.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sean OMeara
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-03-01 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: docker-api
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "
|
|
17
|
+
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
19
|
version: '1.33'
|
|
20
|
+
- - "<"
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: '3'
|
|
20
23
|
type: :runtime
|
|
21
24
|
prerelease: false
|
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
26
|
requirements:
|
|
24
|
-
- - "
|
|
27
|
+
- - ">="
|
|
25
28
|
- !ruby/object:Gem::Version
|
|
26
29
|
version: '1.33'
|
|
30
|
+
- - "<"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '3'
|
|
27
33
|
- !ruby/object:Gem::Dependency
|
|
28
34
|
name: lockfile
|
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -58,7 +64,8 @@ dependencies:
|
|
|
58
64
|
- - "<"
|
|
59
65
|
- !ruby/object:Gem::Version
|
|
60
66
|
version: '3'
|
|
61
|
-
description: A Test Kitchen Driver for
|
|
67
|
+
description: A Test Kitchen Driver for Docker & Chef Infra optimized for rapid testing
|
|
68
|
+
using Chef Infra docker images
|
|
62
69
|
email:
|
|
63
70
|
- sean@sean.io
|
|
64
71
|
executables: []
|
|
@@ -83,16 +90,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
83
90
|
requirements:
|
|
84
91
|
- - ">="
|
|
85
92
|
- !ruby/object:Gem::Version
|
|
86
|
-
version: '
|
|
93
|
+
version: '2.5'
|
|
87
94
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
88
95
|
requirements:
|
|
89
96
|
- - ">="
|
|
90
97
|
- !ruby/object:Gem::Version
|
|
91
98
|
version: '0'
|
|
92
99
|
requirements: []
|
|
93
|
-
rubygems_version: 3.1.
|
|
100
|
+
rubygems_version: 3.1.4
|
|
94
101
|
signing_key:
|
|
95
102
|
specification_version: 4
|
|
96
|
-
summary: A Test Kitchen Driver
|
|
97
|
-
|
|
103
|
+
summary: A Test Kitchen Driver for Docker & Chef Infra optimized for rapid testing
|
|
104
|
+
using Chef Infra docker images
|
|
98
105
|
test_files: []
|