Class: Kitchen::Driver::Docker
- Inherits:
-
Base
- Object
- Base
- Kitchen::Driver::Docker
- Includes:
- Kitchen::Docker::Helpers::CliHelper, Kitchen::Docker::Helpers::ContainerHelper, ShellOut
- Defined in:
- lib/kitchen/driver/docker.rb
Overview
Docker driver for Kitchen.
Constant Summary
Constants included from Kitchen::Docker::Helpers::ContainerHelper
Kitchen::Docker::Helpers::ContainerHelper::COPIED_MARKER
Instance Method Summary collapse
-
#container ⇒ Kitchen::Docker::Container
protected
The container implementation for this platform.
-
#create(state) ⇒ void
Builds the image and starts the container.
-
#default_image ⇒ String
The Docker image implied by the platform name.
-
#default_platform ⇒ String
The platform family, e.g.
-
#destroy(state) ⇒ void
Removes the container, and its image when
remove_imagesis set. -
#doctor(state) ⇒ Boolean
Checks the configuration and the daemon it points at.
-
#doctor_container(state) ⇒ Boolean
protected
Whether state names a container that is gone.
-
#doctor_daemon ⇒ Boolean
protected
Whether the daemon could not be reached.
-
#doctor_files ⇒ Boolean
protected
Checks paths the configuration names.
-
#package(state) ⇒ void
Commits the container to a Docker image.
-
#status(state) ⇒ Hash
Reports whether the container backing this instance is up.
-
#verify_dependencies ⇒ void
Checks that the Docker CLI is installed and runnable.
-
#wait_for_transport(state) ⇒ void
Waits for the transport to accept a connection, unless disabled.
Methods included from Kitchen::Docker::Helpers::ContainerHelper
#container_env_variables, #container_exec, #container_exists?, #container_ip_address, #container_running?, #copy_file_to_container, #create_dir_on_container, #dockerfile_path, #dockerfile_proxy_config, #dockerfile_template, #file_on_container?, #ip_address?, #parse_container_id, #proxy_env_vars, #remote_socket?, #remove_container, #replace_env_variables, #run_container, #socket_uri, #verify_file_copied
Methods included from Kitchen::Docker::Helpers::CliHelper
#build_copy_command, #build_env_variable_args, #build_exec_command, #build_powershell_command, #build_run_command, #config_to_options, #dev_null, #docker_command, #docker_shell_opts, #docker_sudo_opts, #run_command, #shell_escape
Instance Method Details
#container ⇒ Kitchen::Docker::Container (protected)
The container implementation for this platform.
300 301 302 303 304 305 306 307 |
# File 'lib/kitchen/driver/docker.rb', line 300 def container @container ||= if windows_os? Kitchen::Docker::Container::Windows.new(config) else Kitchen::Docker::Container::Linux.new(config) end @container end |
#create(state) ⇒ void
This method returns an undefined value.
Builds the image and starts the container.
138 139 140 141 142 |
# File 'lib/kitchen/driver/docker.rb', line 138 def create(state) container.create(state) wait_for_transport(state) end |
#default_image ⇒ String
The Docker image implied by the platform name.
ubuntu-22.04 becomes ubuntu:22.04. CentOS is special-cased, since its
images are tagged centos7 rather than centos:7.
244 245 246 247 248 249 250 |
# File 'lib/kitchen/driver/docker.rb', line 244 def default_image platform, release = instance.platform.name.split("-") if platform == "centos" && release release = "centos" + release.split(".").first end release ? [platform, release].join(":") : platform end |
#default_platform ⇒ String
Returns the platform family, e.g. ubuntu from ubuntu-22.04.
253 254 255 |
# File 'lib/kitchen/driver/docker.rb', line 253 def default_platform instance.platform.name.split("-").first end |
#destroy(state) ⇒ void
This method returns an undefined value.
Removes the container, and its image when remove_images is set.
148 149 150 |
# File 'lib/kitchen/driver/docker.rb', line 148 def destroy(state) container.destroy(state) end |
#doctor(state) ⇒ Boolean
Checks the configuration and the daemon it points at.
Run by kitchen doctor. A true return is how Test Kitchen decides to
exit non-zero, so every check runs and the results are OR-ed together
rather than returning at the first problem -- somebody running doctor
wants the whole list, not the first item on it.
194 195 196 197 198 199 200 |
# File 'lib/kitchen/driver/docker.rb', line 194 def doctor(state) [ doctor_daemon, doctor_files, doctor_container(state), ].any? end |
#doctor_container(state) ⇒ Boolean (protected)
Returns whether state names a container that is gone.
288 289 290 291 292 293 294 295 |
# File 'lib/kitchen/driver/docker.rb', line 288 def doctor_container(state) return false unless state[:container_id] return false if container_exists?(state) error("The state file names container #{state[:container_id]}, which the daemon does " \ "not have. Run `kitchen destroy` to clear it.") true end |
#doctor_daemon ⇒ Boolean (protected)
Returns whether the daemon could not be reached.
260 261 262 263 264 265 266 267 |
# File 'lib/kitchen/driver/docker.rb', line 260 def doctor_daemon version = docker_command("version --format '{{.Server.Version}}'", suppress_output: true).strip info("Docker daemon at #{config[:socket]} is reachable, running #{version}.") false rescue => e error("Cannot reach the Docker daemon at #{config[:socket]}. #{e}") true end |
#doctor_files ⇒ Boolean (protected)
Checks paths the configuration names.
A missing TLS file or Dockerfile is worth catching here because docker reports it far from the cause -- a missing client certificate surfaces as a connection error rather than as a missing file.
276 277 278 279 280 281 282 283 284 |
# File 'lib/kitchen/driver/docker.rb', line 276 def doctor_files %i{tls_cacert tls_cert tls_key dockerfile}.map do |key| path = config[key] next false if path.nil? || ::File.exist?(::File.(path)) error("#{key} is set to #{path}, which does not exist.") true end.any? end |
#package(state) ⇒ void
This method returns an undefined value.
Commits the container to a Docker image.
kitchen package asks a driver to turn a converged instance into
something reusable. For Docker that is an image: docker commit on the
running container, which is the artifact every other docker tool
already takes. Run docker save against the result for a tarball.
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/kitchen/driver/docker.rb', line 162 def package(state) unless state[:container_id] raise ActionFailed, "Cannot package #{instance.name}: it has not been created." end # Asked here rather than left to `docker commit`, which reports a # container that is gone as a bare "Error response from daemon: No such # container: <64 hex characters>" with nothing about the instance or # what to do next. unless container_exists?(state) raise ActionFailed, "Cannot package #{instance.name}: the state file names container " \ "#{state[:container_id]}, which the daemon does not have. " \ "Run `kitchen destroy` to clear it." end name = config[:package_name] info("[Docker] Committing container #{state[:container_id]} to #{name}") output = docker_command("commit #{shell_escape(state[:container_id])} #{shell_escape(name)}", suppress_output: !logger.debug?) image_id = output.lines.map(&:strip).find { |line| line.match?(/\Asha256:[[:xdigit:]]{64}\z/) } info("[Docker] Packaged #{instance.name} as #{name}#{" (#{image_id})" if image_id}") end |
#status(state) ⇒ Hash
Reports whether the container backing this instance is up.
Read by kitchen list --live, which showed "unknown" for every
instance: Base cannot know, and this driver never
said. Docker can answer directly, and these are the same two questions
create and destroy already ask.
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/kitchen/driver/docker.rb', line 211 def status(state) common = { source: "driver", checked_at: Time.now.utc.iso8601, resource_id: state[:container_id] } if !state[:container_id] common.merge(live: false, state: "not created", message: "No container is recorded in the state file") elsif !container_exists?(state) common.merge(live: false, state: "gone", message: "The state file names a container the daemon does not have") elsif container_running?(state) common.merge(live: true, state: "running") else common.merge(live: false, state: "stopped", message: "The container exists but is not running") end end |
#verify_dependencies ⇒ void
This method returns an undefined value.
Checks that the Docker CLI is installed and runnable.
128 129 130 131 132 |
# File 'lib/kitchen/driver/docker.rb', line 128 def verify_dependencies run_command("#{config[:binary]} >> #{dev_null} 2>&1", quiet: true, use_sudo: config[:use_sudo]) rescue raise UserError, "You must first install the Docker CLI tool https://www.docker.com/get-started" end |
#wait_for_transport(state) ⇒ void
This method returns an undefined value.
Waits for the transport to accept a connection, unless disabled.
232 233 234 235 236 |
# File 'lib/kitchen/driver/docker.rb', line 232 def wait_for_transport(state) if config[:wait_for_transport] instance.transport.connection(state, &:wait_until_ready) end end |