class Docker::Connection

This class represents a Connection to a Docker server. The Connection is immutable in that once the url and options is set they cannot be changed.

Attributes

options[R]
url[R]

Public Class Methods

new(url, opts) click to toggle source

Create a new Connection. This method takes a url (String) and options (Hash). These are passed to Excon, so any options valid for ‘Excon.new` can be passed here.

# File lib/docker/connection.rb, line 16
def initialize(url, opts)
  case
  when !url.is_a?(String)
    raise ArgumentError, "Expected a String, got: '#{url}'"
  when !opts.is_a?(Hash)
    raise ArgumentError, "Expected a Hash, got: '#{opts}'"
  else
    uri = URI.parse(url)
    if uri.scheme == "unix"
      @url, @options = 'unix:///', {:socket => uri.path}.merge(opts)
    elsif uri.scheme =~ /^(https?|tcp)$/
      @url, @options = url, opts
    else
      @url, @options = "http://#{uri}", opts
    end
  end
end

Public Instance Methods

info() click to toggle source

Common attribute requests

# File lib/docker/connection.rb, line 115
def info
  Docker::Util.parse_json(get('/info'))
end
log_request(request) click to toggle source
# File lib/docker/connection.rb, line 97
def log_request(request)
  if Docker.logger
    Docker.logger.debug(
      [request[:method], request[:path], request[:query], request[:body]]
    )
  end
end
ping() click to toggle source
# File lib/docker/connection.rb, line 119
def ping
  get('/_ping')
end
podman?() click to toggle source
# File lib/docker/connection.rb, line 123
def podman?
  @podman ||= !(
    Array(version['Components']).find do |component|
      component['Name'].include?('Podman')
    end
  ).nil?
end
request(*args, &block) click to toggle source

Send a request to the server with the ‘

# File lib/docker/connection.rb, line 42
  def request(*args, &block)
    retries ||= 0
    request = compile_request_params(*args, &block)
    log_request(request)
    begin
      resource.request(request).body
    rescue Excon::Errors::BadRequest => ex
      if retries < 2
        response_cause = ''
        begin
          response_cause = JSON.parse(ex.response.body)['cause']
        rescue JSON::ParserError
          #noop
        end

        if response_cause.is_a?(String)
          # The error message will tell the application type given and then the
          # application type that the message should be
          #
          # This is not perfect since it relies on processing a message that
          # could change in the future. However, it should be a good stop-gap
          # until all methods are updated to pass in the appropriate content
          # type.
          #
          # A current example message is:
          #   * 'Content-Type: application/json is not supported. Should be "application/x-tar"'
          matches = response_cause.delete('"\'').scan(%r{(application/\S+)})
          unless matches.count < 2
            Docker.logger.warn(
              <<~RETRY_WARNING
              Automatically retrying with content type '#{response_cause}'
                Original Error: #{ex}
              RETRY_WARNING
            ) if Docker.logger

            request[:headers]['Content-Type'] = matches.last.first
            retries += 1
            retry
          end
        end
      end
      raise ClientError, ex.response.body
    rescue Excon::Errors::Unauthorized => ex
      raise UnauthorizedError, ex.response.body
    rescue Excon::Errors::NotFound => ex
      raise NotFoundError, ex.response.body
    rescue Excon::Errors::Conflict => ex
      raise ConflictError, ex.response.body
    rescue Excon::Errors::InternalServerError => ex
      raise ServerError, ex.response.body
    rescue Excon::Errors::Timeout => ex
      raise TimeoutError, ex.message
    end
  end
rootless?() click to toggle source
# File lib/docker/connection.rb, line 131
def rootless?
  @rootless ||= (info['Rootless'] == true)
end
to_s() click to toggle source
# File lib/docker/connection.rb, line 105
def to_s
  "Docker::Connection { :url => #{url}, :options => #{options} }"
end
version() click to toggle source
# File lib/docker/connection.rb, line 135
def version
  @version ||= Docker::Util.parse_json(get('/version'))
end

Private Instance Methods

compile_request_params(http_method, path, query = nil, opts = nil, &block) click to toggle source

Given an HTTP method, path, optional query, extra options, and block, compiles a request.

# File lib/docker/connection.rb, line 142
def compile_request_params(http_method, path, query = nil, opts = nil, &block)
  query ||= {}
  opts ||= {}
  headers = opts.delete(:headers) || {}
  content_type = opts[:body].nil? ?  'text/plain' : 'application/json'
  user_agent = "Swipely/Docker-API #{Docker::VERSION}"
  {
    :method        => http_method,
    :path          => path,
    :query         => query,
    :headers       => { 'Content-Type' => content_type,
                        'User-Agent'   => user_agent,
                      }.merge(headers),
    :expects       => (200..204).to_a << 301 << 304,
    :idempotent    => http_method == :get,
    :request_block => block,
  }.merge(opts).reject { |_, v| v.nil? }
end
resource() click to toggle source

The actual client that sends HTTP methods to the Docker server. This value is not cached, since doing so may cause socket errors after bad requests.

# File lib/docker/connection.rb, line 36
def resource
  Excon.new(url, options)
end