File: exec.rb

package info (click to toggle)
ruby-docker-api 2.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 432 kB
  • sloc: ruby: 4,044; sh: 138; makefile: 5
file content (114 lines) | stat: -rw-r--r-- 3,558 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# This class represents a Docker Exec Instance.
class Docker::Exec
  include Docker::Base

  # Convert details about the object into a string
  #
  # @return [String] String representation of the Exec instance object
  def to_s
    "Docker::Exec { :id => #{self.id}, :connection => #{self.connection} }"
  end

  # Create a new Exec instance in a running container. Please note, this does
  # NOT execute the instance - you must run #start. Also, each instance is
  # one-time use only.
  #
  # @param options [Hash] Parameters to pass in to the API.
  # @param conn [Docker::Connection] Connection to Docker Remote API
  #
  # @return [Docker::Exec] self
  def self.create(options = {}, conn = Docker.connection)
    container = options.delete('Container')

    # Podman does not attach these by default but does require them to be attached
    if ::Docker.podman?(conn)
      options['AttachStderr'] = true if options['AttachStderr'].nil?
      options['AttachStdout'] = true if options['AttachStdout'].nil?
    end

    resp = conn.post("/containers/#{container}/exec", {},
      body: MultiJson.dump(options))
    hash = Docker::Util.parse_json(resp) || {}
    new(conn, hash)
  end

  # Get info about the Exec instance
  #
  def json
    Docker::Util.parse_json(connection.get(path_for(:json), {}))
  end

  # Start the Exec instance. The Exec instance is deleted after this so this
  # command can only be run once.
  #
  # @param options [Hash] Options to dictate behavior of the instance
  # @option options [Object] :stdin (nil) The object to pass to STDIN.
  # @option options [TrueClass, FalseClass] :detach (false) Whether to attach
  #     to STDOUT/STDERR.
  # @option options [TrueClass, FalseClass] :tty (false) Whether to attach using
  #     a pseudo-TTY.
  #
  # @return [Array, Array, Int] The STDOUT, STDERR and exit code
  def start!(options = {}, &block)

    # Parse the Options
    tty = !!options.delete(:tty)
    detached = !!options.delete(:detach)
    stdin = options[:stdin]
    read_timeout = options[:wait]

    # Create API Request Body
    body = MultiJson.dump(
      'Tty' => tty,
      'Detach' => detached
    )
    excon_params = { body: body }

    msgs = Docker::Messages.new
    unless detached
      if stdin
        excon_params[:hijack_block] = Docker::Util.hijack_for(stdin, block,
          msgs, tty)
      else
        excon_params[:response_block] = Docker::Util.attach_for(block,
          msgs, tty)
      end
    end

    excon_params[:read_timeout] = read_timeout unless read_timeout.nil?

    connection.post(path_for(:start), nil, excon_params)
    [msgs.stdout_messages, msgs.stderr_messages, self.json['ExitCode']]
  end

  # #start! performs the associated action and returns the output.
  # #start does the same, but rescues from ServerErrors.
  [:start].each do |method|
    define_method(method) do |*args|
      begin; public_send(:"#{method}!", *args); rescue ServerError; self end
    end
  end

  # Resize the TTY associated with the Exec instance
  #
  # @param query [Hash] API query parameters
  # @option query [Fixnum] h Height of the TTY
  # @option query [Fixnum] w Width of the TTY
  #
  # @return [Docker::Exec] self
  def resize(query = {})
    connection.post(path_for(:resize), query)
    self
  end

  # Get the request URI for the given endpoint
  #
  # @param endpoint [Symbol] The endpoint to grab
  # @return [String] The full Remote API endpoint with ID
  def path_for(endpoint)
    "/exec/#{self.id}/#{endpoint}"
  end

  private :path_for
  private_class_method :new
end