class Hoosegow::Docker

Minimal API client for Docker, allowing attaching to container stdin/stdout/stderr.

Constants

DEFAULT_HOST
DEFAULT_PORT
DEFAULT_SOCKET

Public Class Methods

new(options = {}) click to toggle source

Initialize a new Docker API client.

options - Connection options.

:host   - IP or hostname to connect to (unless using Unix
          socket).
:port   - TCP port to connect to (unless using Unix socket).
:socket - Path to local Unix socket (unless using host and
          port).
:after_create - A proc that will be called after a container is created.
:after_start  - A proc that will be called after a container is started.
:after_stop   - A proc that will be called after a container stops.
:prestart - Start a new container after each `run_container` call.
:volumes  - A mapping of volumes to mount in the container. e.g.
            if the Dockerfile has `VOLUME /work`, where the container will
            write data, and `VOLUME /config` where read-only configuration
            is, you might use
              :volumes => {
                "/config" => "/etc/shared-config",
                "/work"   => "/data/work:rw",
              }
            `:volumes => { "/work" => "/home/localuser/work/to/do" }`
:Other - any option with a capitalized key will be passed on
         to the 'create container' call. See http://docs.docker.io/en/latest/reference/api/docker_remote_api_v1.9/#create-a-container
# File lib/hoosegow/docker.rb, line 40
def initialize(options = {})
  set_docker_url! options
  @after_create      = options[:after_create]
  @after_start       = options[:after_start]
  @after_stop        = options[:after_stop]
  @volumes           = options[:volumes]
  @prestart          = options.fetch(:prestart, true)
  @container_options = options.select { |k,v| k =~ /\A[A-Z]/ }
end

Public Instance Methods

attach_container(data, &block) click to toggle source

Attach to a container, writing data to container's STDIN.

Returns combined STDOUT/STDERR from container.

# File lib/hoosegow/docker.rb, line 106
def attach_container(data, &block)
  stdin = StringIO.new data
  @container.attach :stdin => stdin, &block
end
build_image(name, tarfile) { |obj| ... } click to toggle source

Public: Build a new image.

name - The name to give the image. tarfile - Tarred data for creating image. See docs.docker.io/en/latest/api/docker_remote_api_v1.5/#build-an-image-from-dockerfile-via-stdin

Returns Array of build result objects from the Docker API.

# File lib/hoosegow/docker.rb, line 144
def build_image(name, tarfile)
  # Setup parser to receive chunks and yield parsed JSON objects.
  ret = []
  error = nil
  parser = Yajl::Parser.new
  parser.on_parse_complete = Proc.new do |obj|
    ret << obj
    error = Hoosegow::ImageBuildError.new(obj) if obj["error"]
    yield obj if block_given?
  end

  # Make API call to create image.
  opts = {:t => name, :rm => '1'}
  ::Docker::Image.build_from_tar StringIO.new(tarfile), opts do |chunk|
    parser << chunk
  end

  raise error if error

  # Return Array of received objects.
  ret
end
create_container(image) click to toggle source

Public: Create a container using the specified image.

image - The name of the image to start the container with.

Returns nothing.

# File lib/hoosegow/docker.rb, line 81
def create_container(image)
  create_options = default_container_options(image)

  # Merge in additional :HostConfig options into default options
  if @container_options.has_key?(:HostConfig)
    create_options[:HostConfig].merge!(@container_options[:HostConfig])
  end

  @container = ::Docker::Container.create @container_options.merge(
    create_options
  )
  callback @after_create
end
delete_container() click to toggle source

Public: Delete the last started container.

Returns response body or nil if no container was started.

# File lib/hoosegow/docker.rb, line 131
def delete_container
  return unless @container
  @container.delete :v => 1
rescue ::Docker::Error::ServerError => e
  $stderr.puts "Docker could not delete #{@container.id}: #{e}"
end
image_exist?(name) click to toggle source

Check if a Docker image exists.

name - The name of the image to check for.

Returns true/false.

# File lib/hoosegow/docker.rb, line 172
def image_exist?(name)
  ::Docker::Image.exist? name
end
run_container(image, data, &block) click to toggle source

Public: Create and start a Docker container if one hasn't been started already, then attach to it its stdin/stdout.

image - The image to run. data - The data to pipe to the container's stdin.

Returns the data from the container's stdout.

# File lib/hoosegow/docker.rb, line 57
def run_container(image, data, &block)
  unless @prestart && @container
    create_container(image)
    start_container
  end

  begin
    attach_container(data, &block)
  ensure
    wait_container
    delete_container
    if @prestart
      create_container(image)
      start_container
    end
  end
  nil
end
start_container() click to toggle source

Public: Start a Docker container.

Returns nothing.

# File lib/hoosegow/docker.rb, line 98
def start_container
  @container.start
  callback @after_start
end
stop_container() click to toggle source

Public: Stop the running container.

Returns response body or nil if no container is running.

# File lib/hoosegow/docker.rb, line 122
def stop_container
  return unless @container
  @container.stop :timeout => 0
  callback @after_stop
end
wait_container() click to toggle source

Public: Wait for a container to finish.

Returns nothing.

# File lib/hoosegow/docker.rb, line 114
def wait_container
  @container.wait
  callback @after_stop
end

Private Instance Methods

callback(callback_proc) click to toggle source
# File lib/hoosegow/docker.rb, line 246
def callback(callback_proc)
  callback_proc.call(@container.info) if callback_proc
rescue Object
end
default_container_options(image) click to toggle source

Private: Default options used to create containers

# File lib/hoosegow/docker.rb, line 179
def default_container_options(image)
  {
    :StdinOnce  => true,
    :OpenStdin  => true,
    :HostConfig => {
      :Binds    => volumes_for_bind
    },
    :Image     => image
  }
end
docker_url(options) click to toggle source

Private: Get the URL to use for communicating with Docker. If a host and/or port a present, a TCP socket URL will be generated. Otherwise a Unix socket will be used.

options - A Hash of options for building the URL.

:host   - The hostname or IP of a remote Docker daemon
          (optional).
:port   - The TCP port of the remote Docker daemon (optional).
:socket - The path of a local Unix socket (optional).

Returns a String url.

# File lib/hoosegow/docker.rb, line 208
def docker_url(options)
  if options[:host] || options[:port]
    host = options[:host] || DEFAULT_HOST
    port = options[:port] || DEFAULT_PORT
    "tcp://#{host}:#{port}"
  elsif path = options[:socket]
    "unix://#{path}"
  else
    nil
  end
end
each_volume() { |container_path, local_path, permissions| ... } click to toggle source

Private: Yields information about each `@volume`.

each_volume do |container_path, local_path, permissions|
end
# File lib/hoosegow/docker.rb, line 236
def each_volume
  if @volumes
    @volumes.each do |container_path, local_path|
      local_path, permissions = local_path.split(':', 2)
      permissions ||= "ro"
      yield container_path, local_path, permissions
    end
  end
end
set_docker_url!(options) click to toggle source

Private: Set the docker URL, if related options are present.

# File lib/hoosegow/docker.rb, line 191
def set_docker_url!(options)
  if url = docker_url(options)
    ::Docker.url = url
  end
end
volumes_for_bind() click to toggle source

Private: Generate the `Binds` argument for creating a container.

Given a hash of container_path => local_path in @volumes, generate an array of “local_path:container_path:rw”.

# File lib/hoosegow/docker.rb, line 224
def volumes_for_bind
  result = []
  each_volume do |container_path, local_path, permissions|
    result << "#{local_path}:#{container_path}:#{permissions}"
  end
  result
end