class Docker::Image

This class represents a Docker Image.

Public Class Methods

all(opts = {}, conn = Docker.connection) click to toggle source

Return every Image.

# File lib/docker/image.rb, line 219
def all(opts = {}, conn = Docker.connection)
  hashes = Docker::Util.parse_json(conn.get('/images/json', opts)) || []
  hashes.map { |hash| new(conn, hash) }
end
build(commands, opts = {}, connection = Docker.connection, &block) click to toggle source

Given a Dockerfile as a string, builds an Image.

# File lib/docker/image.rb, line 271
def build(commands, opts = {}, connection = Docker.connection, &block)
  body = +""
  connection.post(
    '/build', opts,
    :body => Docker::Util.create_tar('Dockerfile' => commands),
    :response_block => response_block(body, &block)
  )
  new(connection, 'id' => Docker::Util.extract_id(body))
rescue Docker::Error::ServerError
  raise Docker::Error::UnexpectedResponseError
end
build_from_dir(dir, opts = {}, connection = Docker.connection, creds = nil, &block) click to toggle source

Given a directory that contains a Dockerfile, builds an Image.

If a block is passed, chunks of output produced by Docker will be passed to that block.

# File lib/docker/image.rb, line 309
def build_from_dir(dir, opts = {}, connection = Docker.connection,
                   creds = nil, &block)

  tar = Docker::Util.create_dir_tar(dir)
  build_from_tar tar, opts, connection, creds, &block
ensure
  unless tar.nil?
    tar.close
    FileUtils.rm(tar.path, force: true)
  end
end
build_from_tar(tar, opts = {}, connection = Docker.connection, creds = nil, &block) click to toggle source

Given File like object containing a tar file, builds an Image.

If a block is passed, chunks of output produced by Docker will be passed to that block.

# File lib/docker/image.rb, line 287
def build_from_tar(tar, opts = {}, connection = Docker.connection,
                   creds = nil, &block)

  headers = build_headers(creds)

  # The response_block passed to Excon will build up this body variable.
  body = +""
  connection.post(
    '/build', opts,
    :headers => headers,
    :response_block => response_block(body, &block)
  ) { tar.read(Excon.defaults[:chunk_size]).to_s }

  new(connection,
      'id' => Docker::Util.extract_id(body),
      :headers => headers)
end
build_headers(creds=nil) click to toggle source

A method to build the config header and merge it into the headers sent by build_from_dir.

# File lib/docker/image.rb, line 326
def self.build_headers(creds=nil)
  credentials = creds || Docker.creds || {}
  config_header = Docker::Util.build_config_header(credentials)

  headers = { 'Content-Type'      => 'application/tar',
              'Transfer-Encoding' => 'chunked' }
  headers = headers.merge(config_header) if config_header
  headers
end
create(opts = {}, creds = nil, conn = Docker.connection, &block) click to toggle source

Create a new Image.

# File lib/docker/image.rb, line 121
def create(opts = {}, creds = nil, conn = Docker.connection, &block)
  credentials = creds.nil? ? Docker.creds : MultiJson.dump(creds)
  headers = credentials && Docker::Util.build_auth_header(credentials) || {}
  body = +''
  conn.post(
    '/images/create',
    opts,
    :headers => headers,
    :response_block => response_block(body, &block)
    )
  # NOTE: see associated tests for why we're looking at image#end_with?
  image = opts['fromImage'] || opts[:fromImage]
  tag = opts['tag'] || opts[:tag]
  image = "#{image}:#{tag}" if tag && !image.end_with?(":#{tag}")
  get(image, {}, conn)
end
delete(id, opts = {}, conn = Docker.connection)
Alias for: remove
exist?(id, opts = {}, conn = Docker.connection) click to toggle source

Check if an image exists.

# File lib/docker/image.rb, line 211
def exist?(id, opts = {}, conn = Docker.connection)
  get(id, opts, conn)
  true
rescue Docker::Error::NotFoundError
  false
end
get(id, opts = {}, conn = Docker.connection) click to toggle source

Return a specific image.

# File lib/docker/image.rb, line 139
def get(id, opts = {}, conn = Docker.connection)
  image_json = conn.get("/images/#{id}/json", opts)
  hash = Docker::Util.parse_json(image_json) || {}
  new(conn, hash)
end
import(imp, opts = {}, conn = Docker.connection) click to toggle source

Import an Image from the output of Docker::Container#export. The first argument may either be a File or URI.

# File lib/docker/image.rb, line 240
def import(imp, opts = {}, conn = Docker.connection)
  require 'open-uri'

  # This differs after Ruby 2.4
  if URI.public_methods.include?(:open)
    munged_open = URI.method(:open)
  else
    munged_open = self.method(:open)
  end

  munged_open.call(imp) do |io|
    import_stream(opts, conn) do
      io.read(Excon.defaults[:chunk_size]).to_s
    end
  end
rescue StandardError
  raise Docker::Error::IOError, "Could not import '#{imp}'"
end
import_stream(options = {}, connection = Docker.connection, &block) click to toggle source
# File lib/docker/image.rb, line 259
def import_stream(options = {}, connection = Docker.connection, &block)
  body = connection.post(
    '/images/create',
     options.merge('fromSrc' => '-'),
     :headers => { 'Content-Type' => 'application/tar',
                   'Transfer-Encoding' => 'chunked' },
     &block
  )
  new(connection, 'id'=> Docker::Util.parse_json(body)['status'])
end
load(tar, opts = {}, conn = Docker.connection, creds = nil, &block) click to toggle source

Load a tar Image

# File lib/docker/image.rb, line 198
def load(tar, opts = {}, conn = Docker.connection, creds = nil, &block)
   headers = build_headers(creds)
   io = tar.is_a?(String) ? File.open(tar, 'rb') : tar
   body = +""
   conn.post(
     '/images/load',
     opts,
     :headers => headers,
     :response_block => response_block(body, &block)
   ) { io.read(Excon.defaults[:chunk_size]).to_s }
end
prune(conn = Docker.connection) click to toggle source

Prune images

# File lib/docker/image.rb, line 152
def prune(conn = Docker.connection)
  conn.post("/images/prune", {})
end
remove(id, opts = {}, conn = Docker.connection) click to toggle source

Delete a specific image

# File lib/docker/image.rb, line 146
def remove(id, opts = {}, conn = Docker.connection)
  conn.delete("/images/#{id}", opts)
end
Also aliased as: delete
response_block(body) { |chunk| ... } click to toggle source

Generates the block to be passed as a reponse block to Excon. The returned lambda will append Docker output to the first argument, and yield output to the passed block, if a block is given.

# File lib/docker/image.rb, line 362
def self.response_block(body)
  lambda do |chunk, remaining, total|
    body << chunk
    yield chunk if block_given?
  end
end
response_block_for_save(file) click to toggle source

Generates the block to be passed in to the save request. This lambda will append the streaming data to the file provided.

# File lib/docker/image.rb, line 371
def self.response_block_for_save(file)
  lambda do |chunk, remianing, total|
    file << chunk
  end
end
save(names, filename = nil, conn = Docker.connection) click to toggle source

Save the raw binary representation or one or more Docker images

@param names [String, Array#String] The image(s) you wish to save @param filename [String] The file to export the data to. @param conn [Docker::Connection] The Docker connection to use

@return [NilClass, String] If filename is nil, return the string representation of the binary data. If the filename is not nil, then return nil.

# File lib/docker/image.rb, line 166
def save(names, filename = nil, conn = Docker.connection)
  if filename
    File.open(filename, 'wb') do |file|
      save_stream(names, {}, conn, &response_block_for_save(file))
    end
    nil
  else
    string = +''
    save_stream(names, {}, conn, &response_block_for_save(string))
    string
  end
end
save_stream(names, opts = {}, conn = Docker.connection, &block) click to toggle source

Stream the contents of Docker image(s) to a block.

@param names [String, Array#String] The image(s) you wish to save @param conn [Docker::Connection] The Docker connection to use @yield chunk [String] a chunk of the Docker image(s).

# File lib/docker/image.rb, line 184
def save_stream(names, opts = {}, conn = Docker.connection, &block)
  # By using compare_by_identity we can create a Hash that has
  # the same key multiple times.
  query = {}.tap(&:compare_by_identity)
  Array(names).each { |name| query['names'.dup] = name }
  conn.get(
    '/images/get',
    query,
    opts.merge(:response_block => block)
  )
  nil
end

Public Instance Methods

delete(opts = {})
Alias for: remove
insert_local(opts = {}) click to toggle source

Given a path of a local file and the path it should be inserted, creates a new Image that has that file.

# File lib/docker/image.rb, line 53
def insert_local(opts = {})
  local_paths = opts.delete('localPath')
  output_path = opts.delete('outputPath')

  local_paths = [ local_paths ] unless local_paths.is_a?(Array)

  file_hash = Docker::Util.file_hash_from_paths(local_paths)

  file_hash['Dockerfile'] = dockerfile_for(file_hash, output_path)

  tar = Docker::Util.create_tar(file_hash)
  body = connection.post('/build', opts, :body => tar)
  self.class.send(:new, connection, 'id' => Docker::Util.extract_id(body))
end
push(creds = nil, options = {}, &block) click to toggle source

Push the Image to the Docker registry.

# File lib/docker/image.rb, line 27
def push(creds = nil, options = {}, &block)
  repo_tag = options.delete(:repo_tag) || ensure_repo_tags.first
  raise ArgumentError, "Image is untagged" if repo_tag.nil?
  repo, tag = Docker::Util.parse_repo_tag(repo_tag)
  raise ArgumentError, "Image does not have a name to push." if repo.nil?

  body = +""
  credentials = creds || Docker.creds || {}
  headers = Docker::Util.build_auth_header(credentials)
  opts = {:tag => tag}.merge(options)
  connection.post("/images/#{repo}/push", opts, :headers => headers,
                  :response_block => self.class.response_block(body, &block))
  self
end
refresh!() click to toggle source

Update the @info hash, which is the only mutable state in this object.

# File lib/docker/image.rb, line 109
def refresh!
  img = Docker::Image.all({:all => true}, connection).find { |image|
    image.id.start_with?(self.id) || self.id.start_with?(image.id)
  }
  info.merge!(self.json)
  img && info.merge!(img.info)
  self
end
remove(opts = {}) click to toggle source

Remove the Image from the server.

# File lib/docker/image.rb, line 69
def remove(opts = {})
  name = opts.delete(:name)

  unless name
    if ::Docker.podman?(connection)
      name = self.id.split(':').last
    else
      name = self.id
    end
  end

  connection.delete("/images/#{name}", opts)
end
Also aliased as: delete
run(cmd = nil, options = {}) click to toggle source

Given a command and optional list of streams to attach to, run a command on an Image. This will not modify the Image, but rather create a new Container to run the Image. If the image has an embedded config, no command is necessary, but it will fail with 500 if no config is saved with the image

# File lib/docker/image.rb, line 11
def run(cmd = nil, options = {})
  opts = {'Image' => self.id}.merge(options)
  opts["Cmd"] = cmd.is_a?(String) ? cmd.split(/\s+/) : cmd
  begin
    Docker::Container.create(opts, connection)
                     .tap(&:start!)
  rescue ServerError, ClientError => ex
    if cmd
      raise ex
    else
      raise ex, "No command specified."
    end
  end
end
save(filename = nil) click to toggle source

Save the image as a tarball

# File lib/docker/image.rb, line 99
def save(filename = nil)
  self.class.save(self.id, filename, connection)
end
save_stream(opts = {}, &block) click to toggle source

Save the image as a tarball to an IO object.

# File lib/docker/image.rb, line 104
def save_stream(opts = {}, &block)
  self.class.save_stream(self.id, opts, connection, &block)
end
tag(opts = {}) click to toggle source

Tag the Image.

# File lib/docker/image.rb, line 43
def tag(opts = {})
  self.info['RepoTags'] ||= []
  connection.post(path_for(:tag), opts)
  repo = opts['repo'] || opts[:repo]
  tag = opts['tag'] || opts[:tag] || 'latest'
  self.info['RepoTags'] << "#{repo}:#{tag}"
end
to_s() click to toggle source

Return a String representation of the Image.

# File lib/docker/image.rb, line 85
def to_s
  "Docker::Image { :id => #{self.id}, :info => #{self.info.inspect}, "\
    ":connection => #{self.connection} }"
end

Private Instance Methods

dockerfile_for(file_hash, output_path) click to toggle source

Convience method to get the Dockerfile for a file hash and a path to output to.

# File lib/docker/image.rb, line 344
def dockerfile_for(file_hash, output_path)
  dockerfile = +"from #{self.id}\n"

  file_hash.keys.each do |basename|
    dockerfile << "add #{basename} #{output_path}\n"
  end

  dockerfile
end
ensure_repo_tags() click to toggle source
# File lib/docker/image.rb, line 354
def ensure_repo_tags
  refresh! unless info.has_key?('RepoTags')
  info['RepoTags']
end
path_for(resource) click to toggle source

Convenience method to return the path for a particular resource.

# File lib/docker/image.rb, line 337
def path_for(resource)
  "/images/#{self.id}/#{resource}"
end