kitchen-dokken 2.23.4 → 2.23.6
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 +56 -1
- data/lib/kitchen/driver/dokken_version.rb +1 -1
- data/lib/kitchen/transport/dokken.rb +54 -18
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2c7f5b5652cdde267df1ead2dad29ea1c7e3f642cec4b86f3c5ef4c13612a3f3
|
|
4
|
+
data.tar.gz: 8b94c596b93899da42069d35faed37d4be565c9af5617839ee84f9e44fcc9a86
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d48c19a4bdbed503978b68451cded18f2437d2aa0c048d8285344447c4a27503b48937eaf29d93d2fd429316f9c8db240942f09a3333616c939a5cd58555f26d
|
|
7
|
+
data.tar.gz: 305e81615cc269fdfc685436bbd19b47de69c465006c8ac7b55b42eb8911e4dbfd3e2b36759417347e109c56418176dfa69b5f5136f33669ff2b3e5ffbed4f62
|
|
@@ -543,7 +543,8 @@ module Kitchen
|
|
|
543
543
|
return unless self[:network_mode] == "dokken"
|
|
544
544
|
|
|
545
545
|
with_file_lock("#{home_dir}/.dokken-network.lock") do
|
|
546
|
-
with_retries { ::Docker::Network.get("dokken", {}, docker_connection) }
|
|
546
|
+
network = with_retries { ::Docker::Network.get("dokken", {}, docker_connection) }
|
|
547
|
+
warn_on_ipv6_mismatch(network)
|
|
547
548
|
rescue ::Docker::Error::NotFoundError
|
|
548
549
|
begin
|
|
549
550
|
with_retries { ::Docker::Network.create("dokken", network_settings) }
|
|
@@ -553,6 +554,34 @@ module Kitchen
|
|
|
553
554
|
end
|
|
554
555
|
end
|
|
555
556
|
|
|
557
|
+
# Say something when the shared network cannot honour `ipv6: true`.
|
|
558
|
+
#
|
|
559
|
+
# The dokken network is created once and shared by every instance, and
|
|
560
|
+
# `destroy` deliberately leaves it behind -- so on any workstation that
|
|
561
|
+
# has run a non-ipv6 suite, it already exists without ipv6. Since the
|
|
562
|
+
# network is only created when absent, a later `ipv6: true` suite
|
|
563
|
+
# quietly reuses it, the container gets no ipv6 address, and nothing
|
|
564
|
+
# anywhere says why.
|
|
565
|
+
#
|
|
566
|
+
# Deliberately a warning rather than an error: the network may be in use
|
|
567
|
+
# by other instances right now, and removing it is the user's call.
|
|
568
|
+
#
|
|
569
|
+
# @param network [::Docker::Network] the existing dokken network
|
|
570
|
+
# @return [void]
|
|
571
|
+
def warn_on_ipv6_mismatch(network)
|
|
572
|
+
return unless self[:ipv6]
|
|
573
|
+
|
|
574
|
+
# A daemon that does not report the flag must not produce a warning on
|
|
575
|
+
# every converge.
|
|
576
|
+
enabled = network.info["EnableIPv6"] if network.respond_to?(:info)
|
|
577
|
+
return if enabled.nil? || enabled
|
|
578
|
+
|
|
579
|
+
warn "The existing dokken network was created without IPv6, so `ipv6: true` " \
|
|
580
|
+
"will have no effect and this instance will get no IPv6 address. The " \
|
|
581
|
+
"network is shared and `kitchen destroy` leaves it in place; recreate it " \
|
|
582
|
+
"with `docker network rm dokken` once no containers are using it."
|
|
583
|
+
end
|
|
584
|
+
|
|
556
585
|
# Build the data image, unless it is already present.
|
|
557
586
|
#
|
|
558
587
|
# @return [void]
|
|
@@ -907,6 +936,7 @@ module Kitchen
|
|
|
907
936
|
# @param args [Hash] the `/containers/create` body
|
|
908
937
|
# @param platform [String, nil] an OCI platform to pin the container to
|
|
909
938
|
# @return [::Docker::Container] the running container
|
|
939
|
+
# @raise [Kitchen::ActionFailed] if the container will not stay running
|
|
910
940
|
def run_container(args, platform: nil)
|
|
911
941
|
@container = create_container(args, platform: platform)
|
|
912
942
|
with_retries do
|
|
@@ -914,9 +944,34 @@ module Kitchen
|
|
|
914
944
|
@container = ::Docker::Container.get(args["name"], {}, docker_connection)
|
|
915
945
|
wait_running_state(args["name"], true)
|
|
916
946
|
end
|
|
947
|
+
assert_running!(args["name"])
|
|
917
948
|
@container
|
|
918
949
|
end
|
|
919
950
|
|
|
951
|
+
# Fail the action when a container that has to run is not running.
|
|
952
|
+
#
|
|
953
|
+
# wait_running_state stops polling as soon as `FinishedAt` is set, which
|
|
954
|
+
# is precisely the case for a container whose pid 1 exited -- so without
|
|
955
|
+
# this check `kitchen create` reported success and exited 0, leaving the
|
|
956
|
+
# user to discover the problem at converge as a bare docker API message:
|
|
957
|
+
# "container dd55d579... is not running". A container id, no instance
|
|
958
|
+
# name, and no clue that pid 1 was the cause.
|
|
959
|
+
#
|
|
960
|
+
# Only containers that must actually run reach here; the chef container
|
|
961
|
+
# is a volume and is never started.
|
|
962
|
+
#
|
|
963
|
+
# @param name [String] the container name
|
|
964
|
+
# @return [void]
|
|
965
|
+
# @raise [Kitchen::ActionFailed] if the container is not running
|
|
966
|
+
def assert_running!(name)
|
|
967
|
+
return if container_state["Running"]
|
|
968
|
+
|
|
969
|
+
raise ActionFailed,
|
|
970
|
+
"The #{name} container exited immediately after being started. " \
|
|
971
|
+
"Its pid 1 did not stay up: check `pid_one_command`, `entrypoint`, " \
|
|
972
|
+
"and that the image can boot (`docker logs #{name}` shows why)."
|
|
973
|
+
end
|
|
974
|
+
|
|
920
975
|
# The current container's `State` payload.
|
|
921
976
|
#
|
|
922
977
|
# @return [Hash] the state, or an empty hash if there is no container
|
|
@@ -211,6 +211,31 @@ module Kitchen
|
|
|
211
211
|
"The data container has no address on any docker network: #{settings[:Networks].inspect}"
|
|
212
212
|
end
|
|
213
213
|
|
|
214
|
+
# Every address the data container has, best candidate first.
|
|
215
|
+
#
|
|
216
|
+
# A user-defined network comes before the default bridge. That order
|
|
217
|
+
# matters when kitchen is itself a container: a sibling on the dokken
|
|
218
|
+
# network can reach the container there but has no route to its
|
|
219
|
+
# bridge address, and preferring the bridge would send every upload
|
|
220
|
+
# to the docker host instead.
|
|
221
|
+
#
|
|
222
|
+
# The legacy top-level `IPAddress` is the default bridge's, so it
|
|
223
|
+
# sorts with the bridge and is deduplicated against it.
|
|
224
|
+
#
|
|
225
|
+
# @return [Array<String>] addresses, most specific network first
|
|
226
|
+
# @api private
|
|
227
|
+
def data_container_addresses
|
|
228
|
+
settings = options[:data_container][:NetworkSettings]
|
|
229
|
+
networks = settings[:Networks] || {}
|
|
230
|
+
|
|
231
|
+
user_defined, default_bridge = networks.partition { |name, _| name.to_s != "bridge" }
|
|
232
|
+
|
|
233
|
+
addresses = (user_defined + default_bridge).map { |_, network| network[:IPAddress].to_s }
|
|
234
|
+
addresses << settings[:IPAddress].to_s
|
|
235
|
+
|
|
236
|
+
addresses.reject(&:empty?).uniq
|
|
237
|
+
end
|
|
238
|
+
|
|
214
239
|
# Pick an endpoint for a daemon reached over tcp.
|
|
215
240
|
#
|
|
216
241
|
# The container's address on the dokken network is preferred, since it
|
|
@@ -221,31 +246,42 @@ module Kitchen
|
|
|
221
246
|
# @return [Array(String, String)] the address and port to ssh to
|
|
222
247
|
# @api private
|
|
223
248
|
def tcp_ssh_endpoint
|
|
224
|
-
name = options[:data_container][:Name]
|
|
225
|
-
|
|
226
249
|
# DOCKER_HOST
|
|
227
250
|
docker_host_url_ip = options[:docker_host_url].split("tcp://")[1].split(":")[0]
|
|
228
251
|
|
|
229
|
-
# mapped IP of data container
|
|
230
|
-
candidate_ip = ::Docker::Container.all.find do |x|
|
|
231
|
-
x.info["Names"][0].eql?(name)
|
|
232
|
-
end.info["NetworkSettings"]["Networks"]["dokken"]["IPAddress"]
|
|
233
|
-
|
|
234
252
|
# mapped port
|
|
235
253
|
candidate_ssh_port = published_ssh_port
|
|
236
254
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
255
|
+
# The addresses come from the state the driver recorded after it
|
|
256
|
+
# started the container. This used to ask the daemon instead --
|
|
257
|
+
# Docker::Container.all, find ours by name, then read
|
|
258
|
+
# Networks["dokken"]["IPAddress"] -- which was wrong twice over.
|
|
259
|
+
#
|
|
260
|
+
# Container.all lists only *running* containers, so a data container
|
|
261
|
+
# that had exited made `find` return nil and the chained `.info`
|
|
262
|
+
# raise `undefined method 'info' for nil`. And the dokken network is
|
|
263
|
+
# only attached when network_mode is left at its default:
|
|
264
|
+
# start_data_container adds the endpoint
|
|
265
|
+
# "unless %w{host bridge}.include?" and names it after network_mode,
|
|
266
|
+
# so `bridge`, `host` and every custom network name produced
|
|
267
|
+
# `undefined method '[]' for nil` on a remote daemon.
|
|
268
|
+
data_container_addresses.each do |candidate_ip|
|
|
269
|
+
debug "candidate_ip - #{candidate_ip}"
|
|
270
|
+
debug "candidate_ssh_port - #{candidate_ssh_port}"
|
|
271
|
+
|
|
272
|
+
if port_open?(candidate_ip, candidate_ssh_port)
|
|
273
|
+
debug "candidate_ip - #{candidate_ip}/#{candidate_ssh_port} open"
|
|
274
|
+
return [candidate_ip, candidate_ssh_port]
|
|
275
|
+
elsif port_open?(candidate_ip, "22")
|
|
276
|
+
debug "candidate_ip - #{candidate_ip}/22 open"
|
|
277
|
+
return [candidate_ip, "22"]
|
|
278
|
+
end
|
|
248
279
|
end
|
|
280
|
+
|
|
281
|
+
# Nothing answered, or -- with host networking -- the container has
|
|
282
|
+
# no address of its own to try. The docker host is the endpoint.
|
|
283
|
+
debug "no data container address answered; falling back to the docker host"
|
|
284
|
+
[docker_host_url_ip, candidate_ssh_port]
|
|
249
285
|
end
|
|
250
286
|
|
|
251
287
|
# Write the built-in insecure private key somewhere ssh will accept it.
|