Class: Docker::Session

Inherits:
Object
  • Object
show all
Defined in:
lib/docker/session.rb

Overview

A Ruby OOP interface to a docker session. A session is bound to a particular docker host (which is set at initialize time) time) and invokes whichever docker command is resident in $PATH.

Run docker commands by calling instance methods of this class and passing positional and kwargs that are equivalent to the CLI options you would pass to the command-line tool.

Note that the Ruby command methods usually expose a subset of the options allowed by the docker CLI, and that options are sometimes renamed for clarity. Each command method is extensively documented.

Constant Summary collapse

PS_HEADER =

Hint that we are able to parse ps output

/ID\s+IMAGE\s+COMMAND\s+CREATED\s+STATUS\s+PORTS\s+NAMES$/

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(shell = Backticks::Runner.new(cli: Docker::CLI::Getopt), host: ENV['DOCKER_HOST']) ⇒ Session

Returns a new instance of Session.



26
27
28
29
# File 'lib/docker/session.rb', line 26

def initialize(shell=Backticks::Runner.new(cli: Docker::CLI::Getopt), host:ENV['DOCKER_HOST'])
  @host = host
  @shell = shell
end

Instance Attribute Details

#hostString (readonly)

Returns URL of the Docker host associated with this session.

Returns:

  • (String)

    URL of the Docker host associated with this session



18
19
20
# File 'lib/docker/session.rb', line 18

def host
  @host
end

#shell#command (readonly)

Returns:

  • (#command)


21
22
23
# File 'lib/docker/session.rb', line 21

def shell
  @shell
end

Instance Method Details

#inspect(container_s) ⇒ Container, Array

Get detailed information about a container(s).

Parameters:

  • container (Array, String)

    ID/name or list of IDs/names

Returns:

  • (Container, Array)

    one container if one was asked about; a list of containers otherwise



35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/docker/session.rb', line 35

def inspect(container_s)
  containers = container_s
  containers = [containers] unless container_s.is_a?(Array)
  return [] if containers.empty?
  out = run!('inspect', containers)
  result = JSON.parse(out).map { |c| Container.new(c, session:self)}
  if container_s.is_a?(Array)
    result
  else
    result.first
  end
end

#kill(container, signal: nil) ⇒ Object

Kill a running container.

Parameters:

  • container (String)

    id or name of container

  • signal (String) (defaults to: nil)

    Unix signal to send: KILL, TERM, QUIT, HUP, etc



52
53
54
# File 'lib/docker/session.rb', line 52

def kill(container, signal:nil)
  run!('kill', {signal:signal}, container)
end

#ps(all: false, before: nil, latest: false, since: nil) ⇒ Array

List containers. This actually does a ‘ps` followed by a very large `inspect`, so it’s expensive but super detailed.

Parameters:

Returns:

  • (Array)

    list of Docker::Container objects



61
62
63
64
65
66
67
# File 'lib/docker/session.rb', line 61

def ps(all:false, before:nil, latest:false, since:nil)
  out = run!('ps', all:all,before:before,latest:latest,since:since)
  lines = out.split(/[\n\r]+/)
  header = lines.shift
  ids = lines.map { |line| line.split(/\s+/).first }
  inspect(ids)
end

#rm(container, force: false, volumes: false) ⇒ Object

Remove a container.

Parameters:

  • container (String)

    id or name of container

  • force (Boolean) (defaults to: false)

    remove the container even if it’s in use

  • volumes (Boolean) (defaults to: false)

    remove associated data volumes



161
162
163
# File 'lib/docker/session.rb', line 161

def rm(container, force:false, volumes:false)
  run!('rm', {force:force,volumes:volumes},container).strip
end

#run(image, *command_and_args, add_host: [], attach: [], cpu_period: nil, cpu_quota: nil, detach: false, env: {}, env_file: nil, expose: [], hostname: nil, interactive: false, link: [], memory: nil, name: nil, publish: [], publish_all: false, restart: false, rm: false, tty: false, user: nil, volume: [], volumes_from: nil) {|stream, data| ... } ⇒ Object

Run a command in a new container.

Examples:

open a busybox shell

session.run('busybox', '/bin/sh', tty:true, interactive:true)

open busybox and remove vowels from user input

session.run('busybox', '/bin/sh', tty:true, interactive:true) do |stream, data|
  if [:stdout, :stderr].include?(stream)
    puts data
  else
    data.gsub(/[aeiouy]/, '')
  end
end

Parameters:

  • image (String)

    id or name of base image to use for container

  • command_and_args (Array)

    optional command to run in container

  • cpu_period (Integer) (defaults to: nil)

    scheduler period (μs)

  • cpu_quota (Integer) (defaults to: nil)

    maximum runtime (μs) during one scheduler period

  • detach (Boolean) (defaults to: false)

    run container in background and return immediately

  • env (Array, Hash) (defaults to: {})

    environment variables; map of K:V pairs or list of [“K=V”] assignments

  • env_file (String) (defaults to: nil)

    name of file to read environment variables from

  • expose (Array) (defaults to: [])

    list of Integer/String ports or port-ranges to expose to other containers e.g. 80, “1024-2048”

  • hostname (String) (defaults to: nil)

    Unix hostname inside container

  • interactive (Boolean) (defaults to: false)

    allocate an STDIN for the container

  • link (Array) (defaults to: [])

    list of container ids or names to link to the container

  • memory (String) (defaults to: nil)

    limit on memory consumption e.g. “640k”, “32m” or “4g”

  • name (String) (defaults to: nil)

    name of container; leave blank to let Docker generate one

  • publish (Array) (defaults to: [])

    list of Integer/String ports or port-ranges to publish to the host; use “X:Y” to map container’s X to host’s Y

  • publish_all (Boolean) (defaults to: false)

    automatically publish all of container’s ports to the host

  • restart (Boolean) (defaults to: false)

    automatically restart container when it fails

  • rm (Boolean) (defaults to: false)

    clean up container once it exits

  • tty (Boolean) (defaults to: false)

    allocate a pseudo-TTY for the container’s STDOUT

  • user (String) (defaults to: nil)

    name or uid of Unix user to run container as

  • volume (Array) (defaults to: [])

    list of volumes to mount inside container; use “X:Y” to map host’s X to container’s Y

  • volumes_from (String) (defaults to: nil)

    id or name of container to import all volumes from

Yields:

  • (stream, data)

    intercepts container I/O and passes it to the block

Yield Parameters:

  • stream (Symbol)

    :stdin, :stdout or :stderr

  • data (String)

    the intercepted stream activity



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/docker/session.rb', line 108

def run(image, *command_and_args,
        add_host:[],
        attach:[],
        cpu_period:nil,
        cpu_quota:nil,
        detach:false,
        env:{},
        env_file:nil,
        expose:[],
        hostname:nil,
        interactive:false,
        link:[],
        memory:nil,
        name:nil,
        publish:[],
        publish_all:false,
        restart:false,
        rm:false,
        tty:false,
        user:nil,
        volume:[],
        volumes_from:nil, &block)

  cmd = []

  # if env was provided as a hash, turn it into an array
  env = env.map { |k, v| "#{k}=#{v}" } if env.is_a?(Hash)

  # our keyword args are formatted properly for run! to handle them; echo
  # them into the command line verbatim.
  # TODO find a way to DRY out this repetitive mess...
  cmd << {add_host:add_host, attach:attach, cpu_period:cpu_period,
          cpu_quota:cpu_quota, detach:detach, env_file:env_file, env:env,
          expose:expose, hostname:hostname, interactive:interactive,
          link:link, memory:memory, name:name, publish:publish,
          publish_all:publish_all, restart:restart, rm:rm, tty:tty,
          user:user, volume:volume, volumes_from:volumes_from
  }.reject { |k, v| v.nil? || (v.respond_to?(:empty?) && v.empty?) }


  # after the options come the image and command
  cmd << image
  cmd.concat(command_and_args)

  # return the output of `docker run` minus extra whitespace
  run!('run', *cmd, &block).strip
end

#run!(*args) {|stream, data| ... } ⇒ String

Run a docker command without validating that the CLI parameters make sense. Prepend implicit options if suitable.

Parameters:

  • args (Array)

    command-line arguments in the format accepted by Backticks::Runner#command

Yields:

  • (stream, data)

    intercepts command I/O and passes it to the block

Yield Parameters:

  • stream (Symbol)

    :stdin, :stdout or :stderr

  • data (String)

    the intercepted stream activity

Returns:

  • (String)

    output of the command

Raises:

  • (RuntimeError)

    if command fails



219
220
221
222
223
224
225
226
227
228
# File 'lib/docker/session.rb', line 219

def run!(*args, &block)
  # STDERR.puts "+ " + (['docker'] + args).inspect
  cmd = @shell.run('docker', *args)
  cmd.tap(&block) if block_given?
  cmd.join

  status, out, err = cmd.status, cmd.captured_output, cmd.captured_error
  status.success? || raise(Error.new(args.first, status, err))
  out
end

#start(container, attach: false, interactive: false) ⇒ Object

Start a stopped container.

Parameters:

  • container (String)

    id or name of container

  • attach (Boolean) (defaults to: false)

    attach STDOUT/STDERR and forward signals

  • interactive (Boolean) (defaults to: false)

    attach container’s STDIN



178
179
180
# File 'lib/docker/session.rb', line 178

def start(container, attach:false, interactive:false)
  run!('start', {attach:attach,interactive:interactive}, container).strip
end

#stop(container, time: nil) ⇒ Object

Stop a running container.

Parameters:

  • container (String)

    id or name of container

  • time (Integer) (defaults to: nil)

    seconds to wait for stop before killing it



169
170
171
# File 'lib/docker/session.rb', line 169

def stop(container, time:nil)
  run!('stop', {time:time}, container).strip
end

#versionHash

Provide version information about the Docker client and server.

Returns:

  • (Hash)

    dictionary of strings describing version/build info

Raises:

  • (Error)

    if command fails



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/docker/session.rb', line 186

def version
  result = run!('version')

  lines = result.split(/[\r\n]+/)

  info = {}
  prefix = ''

  lines.each do |line|
    if line =~ /^Client/
      prefix = 'Client '
    elsif line =~ /^Server/
      prefix = 'Server '
    else
      pair = line.split(':',2).map { |e| e.strip }
      info["#{prefix}#{pair[0]}"] = pair[1]
    end
  end

  info
end