module DockerHelper

Various helper methods to control the Docker command-line client. Main entrance point is the docker helper. Use ::proxy for a self-contained controller object to call these methods on.

See ::docker_command

Constants

VERSION

Attributes

docker_command[W]

Setter for the Docker command (see ::docker_command).

Public Instance Methods

docker(cmd, args...) click to toggle source
docker(cmd, args...) { ... }

Central helper method to execute Docker commands.

If the command (first argument) is a symbol or if the pipe option is set, runs the command through docker_pipe and returns the result as a string. Otherwise, runs the command through docker_system and returns true or false, indicating whether the command exited successfully or not.

In the pipe case, calls docker_fail when the fail_if_empty option is set and the command returned no result.

In the system case, ignores errors when the ignore_errors option is set. The block is passed on to docker_system if given.

# File lib/docker_helper.rb, line 132
def docker(*args, &block)
  options, pipe, fail_if_empty, ignore_errors = DockerHelper.
    extract_options(args, :pipe, :fail_if_empty, :ignore_errors)

  DockerHelper.build_args(args, options)

  if pipe
    docker_pipe(*args).tap { |res|
      if fail_if_empty && !res
        docker_fail(*args)
      end
    }
  else
    if ignore_errors
      options[:err] = :close
      block ||= lambda { |*| }
    end

    docker_system(*args, &block)
  end
end
docker_build(build_path, image) click to toggle source

Builds the image image from the Dockerfile and context at build_path.

Command reference: docker build

# File lib/docker_helper.rb, line 193
def docker_build(build_path, image = nil)
  image ||= docker_image_name

  docker %W[build -t #{image} #{build_path}]  # --force-rm
end
docker_clean(name) click to toggle source

Stops and then removes container name, including associated volumes.

Command reference: docker rm

# File lib/docker_helper.rb, line 325
def docker_clean(name = nil, _ = nil)
  name ||= docker_container_name

  docker_stop name
  docker %W[rm -v -f #{name}], ignore_errors: true
end
docker_clobber(name, image) click to toggle source

Removes container name (see docker_clean) as well as image image.

Command reference: docker rmi

# File lib/docker_helper.rb, line 339
def docker_clobber(name = nil, image = nil)
  name  ||= docker_container_name
  image ||= docker_image_name

  docker_clean name
  docker %W[rmi #{image}], ignore_errors: true
end
docker_command → aString click to toggle source

Returns the Docker command or aborts if none could be found.

Override by setting the DOCKER_COMMAND environment variable or by setting the docker_command attribute on this module.

# File lib/docker_helper.rb, line 58
def docker_command
  @docker_command ||= ENV.fetch('DOCKER_COMMAND') {
    find_docker_command || abort('Docker command not found.') }
end
docker_port(port, name) → aString click to toggle source

Returns the host and port for container name on port port. Fails if container is not running or the specified port is not exposed.

Command reference: docker port

# File lib/docker_helper.rb, line 220
def docker_port(port, name = nil)
  name ||= docker_container_name

  docker :port, name, port
end
docker_ready(host_with_port[, path]) → true or false click to toggle source

Argument host_with_port must be of the form host:port, as returned by docker_port, or an array of host and port.

Returns true if and when the TCP port is available on the host and, if path is given, a HTTP request for path is successful.

Returns false if the port and the path haven't become available after 30 attempts each. Sleeps for 0.1 seconds inbetween attempts.

# File lib/docker_helper.rb, line 246
def docker_ready(host_with_port, path = nil, attempts = 30, sleep = 0.1)
  host, port = host_with_port.is_a?(Array) ?
    host_with_port : host_with_port.split(':')

  docker_socket_ready(host, port, attempts, sleep) &&
    (!path || docker_http_ready(host, port, path, attempts, sleep))
end
docker_reset(name, image) click to toggle source

Resets container name by removing (see docker_clean) and then starting (see docker_start) it from image image.

# File lib/docker_helper.rb, line 352
def docker_reset(name = nil, image = nil)
  docker_clean(name)
  docker_start(name, image)
end
docker_restart(name) click to toggle source

Restarts container name by stopping (see docker_stop) and then starting it.

Command reference: docker start

# File lib/docker_helper.rb, line 311
def docker_restart(name = nil, _ = nil)
  name ||= docker_container_name

  docker_stop name
  docker %W[start #{name}]
end
docker_start(name, image) click to toggle source

Starts container name from image image. This will fail if a container with that name is already running. Use docker_start! in case you want to unconditionally start the container.

Runs the container detached and with all exposed ports published.

Command reference: docker run

# File lib/docker_helper.rb, line 265
def docker_start(name = nil, image = nil)
  name  ||= docker_container_name
  image ||= docker_image_name

  docker %W[run -d -P --name #{name} #{image}]
end
docker_start!(name, image) click to toggle source
docker_start!(name, image) { |name, image| ... }

Unconditionally starts container name from image image.

If the container is already running, it's restarted (see docker_restart). Otherwise, it's started (see docker_start) and its name and image are yielded to the block if given.

# File lib/docker_helper.rb, line 281
def docker_start!(name = nil, image = nil)
  name  ||= docker_container_name
  image ||= docker_image_name

  docker_restart(name) || docker_start(name, image).tap {
    yield name, image if block_given?
  }
end
docker_stop(name) click to toggle source

Stops container name.

Command reference: docker stop

# File lib/docker_helper.rb, line 297
def docker_stop(name = nil, _ = nil)
  name ||= docker_container_name

  docker %W[stop #{name}], ignore_errors: true
end
docker_tags(image) → anArray click to toggle source

Returns the tags associated with image image.

Command reference: docker images

# File lib/docker_helper.rb, line 172
def docker_tags(image = nil)
  image ||= docker_image_name

  needle = image[/[^:]+/]

  docker(:images).lines.map { |line|
    repo, tag, = line.split
    tag if repo == needle
  }.compact.sort.sort_by { |tag|
    tag.split('.').map(&:to_i)
  }
end
docker_url(port, name) → aString click to toggle source

Returns the HTTP URL for container name on port port (see docker_port).

# File lib/docker_helper.rb, line 231
def docker_url(port, name = nil)
  "http://#{docker_port(port, name)}"
end
docker_version → aString click to toggle source

Returns the version number of the Docker client.

Command reference: docker version

# File lib/docker_helper.rb, line 161
def docker_version
  docker(:version).lines.first.split.last
end
docker_volume(volume, name) → aString click to toggle source

Returns the path to volume volume shared by container name.

Command reference: docker inspect

# File lib/docker_helper.rb, line 206
def docker_volume(volume, name = nil)
  name ||= docker_container_name

  docker :inspect, %W[-f {{index\ .Volumes\ "#{volume}"}} #{name}]
end
proxy → aProxy click to toggle source

Returns a new instance of Proxy with helper methods available both in abbreviated and unabbreviated form.

# File lib/docker_helper.rb, line 47
def proxy
  Proxy.new.extend(self)
end

Private Instance Methods

docker_container_name() click to toggle source

Placeholder for default container name; must be implemented by utilizing class.

# File lib/docker_helper.rb, line 361
def docker_container_name
  raise ArgumentError, 'container name missing', caller(1)
end
docker_fail(*args) click to toggle source

Simply aborts; override for different behaviour.

# File lib/docker_helper.rb, line 384
def docker_fail(*args)
  abort
end
docker_http_ready(host, port, path, attempts, sleep) click to toggle source

Checks HTTP connection.

# File lib/docker_helper.rb, line 398
def docker_http_ready(host, port, path, attempts, sleep)
  loop {
    begin
      break if Net::HTTP.get_response(host, path, port).is_a?(Net::HTTPSuccess)
    rescue Errno::ECONNRESET, EOFError => err
      return false unless docker_ready_sleep(sleep, attempts -= 1)
      retry
    end

    return false unless docker_ready_sleep(sleep, attempts -= 1)
  }

  true
end
docker_image_name() click to toggle source

Placeholder for default image name; must be implemented by utilizing class.

# File lib/docker_helper.rb, line 367
def docker_image_name
  raise ArgumentError, 'image name missing', caller(1)
end
docker_pipe(*args) click to toggle source

Executes the command in a subprocess and returns its output as a string, or nil if output is empty; override for different behaviour.

# File lib/docker_helper.rb, line 373
def docker_pipe(*args)
  res = IO.popen(args, &:read).chomp
  res unless res.empty?
end
docker_ready_sleep(sleep, attempts) click to toggle source

Sleeps unless out of attempts.

# File lib/docker_helper.rb, line 414
def docker_ready_sleep(sleep, attempts)
  sleep(sleep) unless attempts.zero?
end
docker_socket_ready(host, port, attempts, sleep) click to toggle source

Checks TCP connection.

# File lib/docker_helper.rb, line 389
def docker_socket_ready(host, port, attempts, sleep)
  TCPSocket.new(host, port).close
  true
rescue Errno::ECONNREFUSED
  return false unless docker_ready_sleep(sleep, attempts -= 1)
  retry
end
docker_system(*args) click to toggle source

Executes the command in a subshell; override for different behaviour.

# File lib/docker_helper.rb, line 379
def docker_system(*args)
  system(*args)
end

Internal

↑ top

Public Instance Methods

build_args(args, options) click to toggle source

Builds arguments array suitable for docker_system and docker_pipe.

Prefixes the command with sudo unless the NOSUDO environment variable is set.

Flattens all arguments, converts them to strings and appends the options hash.

# File lib/docker_helper.rb, line 105
def build_args(args, options)
  args.unshift(docker_command)
  args.unshift(:sudo) unless ENV['NOSUDO']

  args.flatten!
  args.map!(&:to_s) << options
end
extract_options(args, *keys) click to toggle source

Extracts options hash from args and applies default options.

Returns the options hash as well as the values for keys, which will be removed from the options.

# File lib/docker_helper.rb, line 82
def extract_options(args, *keys)
  options = args.last.is_a?(Hash) ? args.pop : {}

  unless options.key?(:pipe)
    options[:pipe] = args.first.is_a?(Symbol)
  end

  unless options.key?(:fail_if_empty)
    options[:fail_if_empty] = options[:pipe]
  end

  [options, *keys.map(&options.method(:delete))]
end
find_docker_command() click to toggle source

Tries to find the Docker command for the host system. Usually, it's just docker, but on Debian-based systems it's docker.io.

# File lib/docker_helper.rb, line 67
def find_docker_command
  commands = %w[docker docker.io]

  require 'nuggets/file/which'
  File.which_command(commands)
rescue LoadError
  commands.first
end