Class: Docker::API::Container
- Defined in:
- lib/docker/api/resources/container.rb
Overview
A container on the daemon.
Instance Attribute Summary
Attributes inherited from Resource
Instance Method Summary collapse
-
#archive_in(archive, path:, overwrite_non_directory: true, copy_uid_gid: false) ⇒ self
Copy a tar archive into the container.
-
#archive_out(path) {|chunk| ... } ⇒ String, self
Read a path out of the container as a tar archive.
-
#attach(stdin: false, stdout: true, stderr: true, logs: false) ⇒ IO
Attach to the container's streams, taking over the socket.
-
#commit(repo: nil, tag: nil, comment: nil, author: nil, pause: true) ⇒ Docker::API::Image
Turn the container's filesystem into an image.
-
#exec(command, env: {}, user: nil, working_dir: nil, tty: false, privileged: false) {|stream, chunk| ... } ⇒ Docker::API::ExecResult
Run a command inside the container and wait for it to finish.
-
#image ⇒ String?
The image the container was created from, by the name it was requested under rather than by digest.
-
#ip_address ⇒ String?
The container's address on its primary network.
- #kill(signal: nil) ⇒ self
-
#labels ⇒ Hash
The container's labels.
-
#logs(follow: false, stdout: true, stderr: true, tail: nil, since: nil, timestamps: false) {|stream, chunk| ... } ⇒ String, self
Read the container's output.
-
#name ⇒ String?
The container's name, without the leading slash the daemon puts on it.
-
#networks ⇒ Hash{String => Hash}
Networks this container is attached to.
- #pause ⇒ self
-
#ports ⇒ Array<Hash>
Published ports, in one shape regardless of where the payload came from.
-
#reload ⇒ self
Re-read this container from the daemon.
- #remove(force: false, volumes: false, link: false) ⇒ void
- #rename(name) ⇒ self
- #restart(timeout: nil, signal: nil) ⇒ self
-
#running? ⇒ Boolean
Whether the container is running right now.
- #start(detach_keys: nil) ⇒ self
-
#state ⇒ String?
"running", "exited", "created", and so on.
-
#stats ⇒ Hash
A single resource-usage sample.
- #stop(timeout: nil, signal: nil) ⇒ self
-
#top(ps_args: nil) ⇒ Hash
With "Titles" and "Processes".
-
#tty? ⇒ Boolean
Whether the container was created with a TTY, which decides whether its output stream is multiplexed.
- #unpause ⇒ self
-
#wait(condition: nil) ⇒ Integer
Block until the container stops.
Methods inherited from Resource
#==, #[], #hash, #id, #initialize, #partial?, #stale?, #to_s
Constructor Details
This class inherits a constructor from Docker::API::Resource
Instance Method Details
#archive_in(archive, path:, overwrite_non_directory: true, copy_uid_gid: false) ⇒ self
Copy a tar archive into the container.
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/docker/api/resources/container.rb', line 263 def archive_in(archive, path:, overwrite_non_directory: true, copy_uid_gid: false) operations.put_container_archive( id: id, path: path, # The content type is not a parameter this endpoint declares, so it # is not a keyword the generated layer accepts; the connection # labels raw bodies as archives, which is what this one is. # # An IO is handed over as it stands rather than read into a String. # Slurping defeated the point of accepting one: a container # filesystem is exactly the kind of archive nobody wants resident in # memory, and the connection streams a readable body chunked. body: archive, no_overwrite_dir_non_dir: !overwrite_non_directory, copy_uidgid: copy_uid_gid ) self end |
#archive_out(path) {|chunk| ... } ⇒ String, self
Read a path out of the container as a tar archive.
286 287 288 289 290 291 |
# File 'lib/docker/api/resources/container.rb', line 286 def archive_out(path, &block) return operations.container_archive(id: id, path: path).body unless block operations.container_archive(id: id, path: path, &block) self end |
#attach(stdin: false, stdout: true, stderr: true, logs: false) ⇒ IO
Attach to the container's streams, taking over the socket.
246 247 248 249 250 251 252 253 |
# File 'lib/docker/api/resources/container.rb', line 246 def attach(stdin: false, stdout: true, stderr: true, logs: false) client.connection.hijack( :post, "/containers/#{Path.escape(id)}/attach", query: { "stream" => true, "stdin" => stdin, "stdout" => stdout, "stderr" => stderr, "logs" => logs }, operation: "container_attach" ) end |
#commit(repo: nil, tag: nil, comment: nil, author: nil, pause: true) ⇒ Docker::API::Image
Turn the container's filesystem into an image.
301 302 303 304 305 306 307 |
# File 'lib/docker/api/resources/container.rb', line 301 def commit(repo: nil, tag: nil, comment: nil, author: nil, pause: true) response = operations.image_commit( container: id, repo: repo, tag: tag, comment: comment, author: , pause: pause ) client.images.get(response.json!["Id"]) end |
#exec(command, env: {}, user: nil, working_dir: nil, tty: false, privileged: false) {|stream, chunk| ... } ⇒ Docker::API::ExecResult
Run a command inside the container and wait for it to finish.
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/docker/api/resources/container.rb', line 213 def exec(command, env: {}, user: nil, working_dir: nil, tty: false, privileged: false, &block) exec_id = create_exec(command, env, user, working_dir, tty, privileged) stdout = +"" stderr = +"" sink = lambda do |stream, chunk| (stream == :stderr ? stderr : stdout) << chunk block&.call(stream, chunk) end decoder = tty ? Stream::Raw.new { |chunk| sink.call(:stdout, chunk) } : Stream::Demultiplexer.new(&sink) operations.exec_start( id: exec_id, body: { "Detach" => false, "Tty" => tty } ) { |chunk| decoder << chunk } ExecResult.new( stdout: stdout, stderr: stderr, # Not .to_i. The daemon reports "ExitCode": null while an exec is # still being reaped, and nil.to_i is 0 -- so a command whose result # was not yet known reported success, and #success? agreed. nil # travels through instead, and #success? is false for it. exit_code: operations.exec_inspect(id: exec_id).json!["ExitCode"] ) end |
#image ⇒ String?
Returns the image the container was created from, by the name it was requested under rather than by digest.
42 43 44 45 46 47 |
# File 'lib/docker/api/resources/container.rb', line 42 def image # An inspect puts the friendly name in Config.Image and a digest in # Image; a list puts the friendly name in Image. Preferring # Config.Image gets the readable answer from both without a round trip. detail("Config.Image", "Image") end |
#ip_address ⇒ String?
Returns the container's address on its primary network.
72 73 74 75 |
# File 'lib/docker/api/resources/container.rb', line 72 def ip_address networks.each_value { |net| return net["IPAddress"] unless net["IPAddress"].to_s.empty? } detail("NetworkSettings.IPAddress") end |
#kill(signal: nil) ⇒ self
112 113 114 115 |
# File 'lib/docker/api/resources/container.rb', line 112 def kill(signal: nil) operations.container_kill(id: id, signal: signal) mark_stale end |
#labels ⇒ Hash
Returns the container's labels.
50 51 52 |
# File 'lib/docker/api/resources/container.rb', line 50 def labels detail("Config.Labels", "Labels") || {} end |
#logs(follow: false, stdout: true, stderr: true, tail: nil, since: nil, timestamps: false) {|stream, chunk| ... } ⇒ String, self
Read the container's output.
Without a block the whole log is returned as a string. With a block, chunks are yielded as they arrive, demultiplexed into named streams unless the container has a TTY, in which case the daemon sends one undifferentiated stream and every chunk is reported as :stdout.
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/docker/api/resources/container.rb', line 180 def logs(follow: false, stdout: true, stderr: true, tail: nil, since: nil, timestamps: false, &block) # Defaulted rather than fixed keys: Demultiplexer maps a frame id it # does not recognise to :unknown, and a fixed two-key hash turned that # into `undefined method '<<' for nil` -- one corrupt frame crashing a # log read, with a bare NoMethodError rather than a Docker::API::Error. collected = Hash.new { |streams, name| streams[name] = +"" } sink = block || ->(stream, chunk) { collected[stream] << chunk } decoder = tty? ? Stream::Raw.new { |chunk| sink.call(:stdout, chunk) } : Stream::Demultiplexer.new(&sink) operations.container_logs( id: id, follow: follow, stdout: stdout, stderr: stderr, tail: tail&.to_s, since: since, timestamps: ) { |chunk| decoder << chunk } block ? self : collected[:stdout] + collected[:stderr] end |
#name ⇒ String?
Returns the container's name, without the leading slash the daemon puts on it. Answers identically whether this object came from a list or an inspect.
21 22 23 24 25 26 27 |
# File 'lib/docker/api/resources/container.rb', line 21 def name # "Name" comes from an inspect, "Names" from a list. Both are tried # against the payload in hand before any request is made. value = detail("Name", "Names") value = Array(value).first if value.is_a?(Array) value&.sub(%r{\A/}, "") end |
#networks ⇒ Hash{String => Hash}
Returns networks this container is attached to.
67 68 69 |
# File 'lib/docker/api/resources/container.rb', line 67 def networks detail("NetworkSettings.Networks") || {} end |
#pause ⇒ self
118 119 120 121 |
# File 'lib/docker/api/resources/container.rb', line 118 def pause operations.container_pause(id: id) mark_stale end |
#ports ⇒ Array<Hash>
Published ports, in one shape regardless of where the payload came from. A list response reports an array; an inspect response reports a map keyed by port. Both become the same array of hashes here.
59 60 61 62 63 64 |
# File 'lib/docker/api/resources/container.rb', line 59 def ports listed = raw["Ports"] return normalize_listed_ports(listed) if listed.is_a?(Array) normalize_inspected_ports(detail("NetworkSettings.Ports") || {}) end |
#reload ⇒ self
Re-read this container from the daemon.
86 87 88 |
# File 'lib/docker/api/resources/container.rb', line 86 def reload replace_raw(operations.container_inspect(id: id || name).json) end |
#remove(force: false, volumes: false, link: false) ⇒ void
This method returns an undefined value.
140 141 142 143 |
# File 'lib/docker/api/resources/container.rb', line 140 def remove(force: false, volumes: false, link: false) operations.container_delete(id: id, force: force, v: volumes, link: link) nil end |
#rename(name) ⇒ self
131 132 133 134 |
# File 'lib/docker/api/resources/container.rb', line 131 def rename(name) operations.container_rename(id: id, name: name) reload end |
#restart(timeout: nil, signal: nil) ⇒ self
106 107 108 |
# File 'lib/docker/api/resources/container.rb', line 106 def restart(timeout: nil, signal: nil) idempotently { operations.container_restart(id: id, t: timeout, signal: signal) } end |
#running? ⇒ Boolean
Returns whether the container is running right now.
36 37 38 |
# File 'lib/docker/api/resources/container.rb', line 36 def running? state == "running" end |
#start(detach_keys: nil) ⇒ self
92 93 94 |
# File 'lib/docker/api/resources/container.rb', line 92 def start(detach_keys: nil) idempotently { operations.container_start(id: id, detach_keys: detach_keys) } end |
#state ⇒ String?
Returns "running", "exited", "created", and so on.
30 31 32 33 |
# File 'lib/docker/api/resources/container.rb', line 30 def state value = detail("State") value.is_a?(Hash) ? value["Status"] : value end |
#stats ⇒ Hash
Returns a single resource-usage sample.
160 161 162 |
# File 'lib/docker/api/resources/container.rb', line 160 def stats operations.container_stats(id: id, stream: false, one_shot: true).json end |
#stop(timeout: nil, signal: nil) ⇒ self
99 100 101 |
# File 'lib/docker/api/resources/container.rb', line 99 def stop(timeout: nil, signal: nil) idempotently { operations.container_stop(id: id, t: timeout, signal: signal) } end |
#top(ps_args: nil) ⇒ Hash
Returns with "Titles" and "Processes".
155 156 157 |
# File 'lib/docker/api/resources/container.rb', line 155 def top(ps_args: nil) operations.container_top(id: id, ps_args: ps_args).json end |
#tty? ⇒ Boolean
Returns whether the container was created with a TTY, which decides whether its output stream is multiplexed.
79 80 81 |
# File 'lib/docker/api/resources/container.rb', line 79 def tty? detail("Config.Tty") == true end |
#unpause ⇒ self
124 125 126 127 |
# File 'lib/docker/api/resources/container.rb', line 124 def unpause operations.container_unpause(id: id) mark_stale end |
#wait(condition: nil) ⇒ Integer
Block until the container stops.
149 150 151 |
# File 'lib/docker/api/resources/container.rb', line 149 def wait(condition: nil) operations.container_wait(id: id, condition: condition).json!["StatusCode"] end |