docker-api 1.27.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +110 -10
- data/lib/docker.rb +7 -14
- data/lib/docker/connection.rb +3 -3
- data/lib/docker/container.rb +103 -45
- data/lib/docker/event.rb +100 -14
- data/lib/docker/exec.rb +6 -6
- data/lib/docker/image.rb +32 -11
- data/lib/docker/network.rb +16 -12
- data/lib/docker/util.rb +56 -16
- data/lib/docker/version.rb +1 -4
- data/lib/docker/volume.rb +8 -4
- metadata +16 -66
- data/.cane +0 -2
- data/.gitignore +0 -6
- data/.rspec +0 -1
- data/.simplecov +0 -4
- data/.travis.yml +0 -25
- data/Dockerfile +0 -2
- data/Gemfile +0 -3
- data/Rakefile +0 -54
- data/TESTING.md +0 -49
- data/docker-api.gemspec +0 -28
- data/script/docker +0 -149
- data/script/docker.conf +0 -61
- data/script/install_docker.sh +0 -35
- data/spec/docker/connection_spec.rb +0 -123
- data/spec/docker/container_spec.rb +0 -801
- data/spec/docker/event_spec.rb +0 -89
- data/spec/docker/exec_spec.rb +0 -181
- data/spec/docker/image_spec.rb +0 -683
- data/spec/docker/messages_spec.rb +0 -97
- data/spec/docker/messages_stack.rb +0 -26
- data/spec/docker/network_spec.rb +0 -150
- data/spec/docker/util_spec.rb +0 -154
- data/spec/docker/volume_spec.rb +0 -46
- data/spec/docker_spec.rb +0 -258
- data/spec/fixtures/build_from_dir/Dockerfile +0 -2
- data/spec/fixtures/export.tar +0 -0
- data/spec/fixtures/load.tar +0 -0
- data/spec/fixtures/top/Dockerfile +0 -2
- data/spec/spec_helper.rb +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7c8d229ece5b5b347a925c62c3f199a940393e58de0b02049aed295090739b04
|
4
|
+
data.tar.gz: 619467ed3697f6b9221f89bab145ba298bd47f5f26209e86df89347b6e83fe08
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7a1a3a2a995c4a172217fc80eb573501502f7f05a337080bf4723d90bb2ba9053cde786aaa994993bd2841ebeeb18cc8a5e4dfa342792bb558fb84a3f4688b89
|
7
|
+
data.tar.gz: c9bbb7ae229ba1784859ddb0e3bc6e7df1651718d552779baac4e2ad49d34096aba760e6ce99fa41dfd14ef6ea0f3a5ddfc9178cf1c7c7f286a8385be1c59385
|
data/README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
docker-api
|
2
2
|
==========
|
3
|
-
[![Gem Version](https://badge.fury.io/rb/docker-api.
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/docker-api.svg)](https://badge.fury.io/rb/docker-api) [![travis-ci](https://travis-ci.org/swipely/docker-api.svg?branch=master)](https://travis-ci.org/swipely/docker-api) [![Code Climate](https://codeclimate.com/github/swipely/docker-api.svg)](https://codeclimate.com/github/swipely/docker-api)
|
4
4
|
|
5
|
-
This gem provides an object-oriented interface to the [Docker
|
5
|
+
This gem provides an object-oriented interface to the [Docker Engine API](https://docs.docker.com/develop/sdk/). Every method listed there is implemented. At the time of this writing, docker-api is meant to interface with Docker version 1.4.*
|
6
6
|
|
7
7
|
If you're interested in using Docker to package your apps, we recommend the [dockly](https://github.com/swipely/dockly) gem. Dockly provides a simple DSL for describing Docker containers that install as Debian packages and are controlled by upstart scripts.
|
8
8
|
|
@@ -36,7 +36,7 @@ docker-api is designed to be very lightweight. Almost no state is cached (aside
|
|
36
36
|
|
37
37
|
## Starting up
|
38
38
|
|
39
|
-
Follow the [installation instructions](https://docs.docker.com/
|
39
|
+
Follow the [installation instructions](https://docs.docker.com/install/), and then run:
|
40
40
|
|
41
41
|
```shell
|
42
42
|
$ sudo docker -d
|
@@ -52,7 +52,7 @@ If you're running Docker locally as a socket, there is no setup to do in Ruby. I
|
|
52
52
|
Docker.url = 'tcp://example.com:5422'
|
53
53
|
```
|
54
54
|
|
55
|
-
Two things to note here. The first is that this gem uses [excon](
|
55
|
+
Two things to note here. The first is that this gem uses [excon](https://github.com/excon/excon), so any of the options that are valid for `Excon.new` are also valid for `Docker.options`. Second, by default Docker runs on a socket. The gem will assume you want to connect to the socket unless you specify otherwise.
|
56
56
|
|
57
57
|
Also, you may set the above variables via `ENV` variables. For example:
|
58
58
|
|
@@ -94,6 +94,21 @@ Docker.options = {
|
|
94
94
|
}
|
95
95
|
```
|
96
96
|
|
97
|
+
If you want to load the cert files from a variable, e.g. you want to load them from ENV as needed on Heroku:
|
98
|
+
|
99
|
+
```
|
100
|
+
cert_store = OpenSSL::X509::Store.new
|
101
|
+
certificate = OpenSSL::X509::Certificate.new ENV["DOCKER_CA"]
|
102
|
+
cert_store.add_cert certificate
|
103
|
+
|
104
|
+
Docker.options = {
|
105
|
+
client_cert_data: ENV["DOCKER_CERT"],
|
106
|
+
client_key_data: ENV["DOCKER_KEY"],
|
107
|
+
ssl_cert_store: cert_store,
|
108
|
+
scheme: 'https'
|
109
|
+
}
|
110
|
+
```
|
111
|
+
|
97
112
|
If you need to disable SSL verification, set the DOCKER_SSL_VERIFY variable to 'false'.
|
98
113
|
|
99
114
|
## Global calls
|
@@ -108,13 +123,17 @@ require 'docker'
|
|
108
123
|
Docker.version
|
109
124
|
# => { 'Version' => '0.5.2', 'GoVersion' => 'go1.1' }
|
110
125
|
|
111
|
-
# docker command for reference: docker info
|
126
|
+
# docker command for reference: docker info
|
112
127
|
Docker.info
|
113
128
|
# => { "Debug" => false, "Containers" => 187, "Images" => 196, "NFd" => 10, "NGoroutines" => 9, "MemoryLimit" => true }
|
114
129
|
|
115
130
|
# docker command for reference: docker login
|
116
131
|
Docker.authenticate!('username' => 'docker-fan-boi', 'password' => 'i<3docker', 'email' => 'dockerboy22@aol.com')
|
117
132
|
# => true
|
133
|
+
|
134
|
+
# docker command for reference: docker login registry.gitlab.com
|
135
|
+
Docker.authenticate!('username' => 'docker-fan-boi', 'password' => 'i<3docker', 'email' => 'dockerboy22@aol.com', 'serveraddress' => 'https://registry.gitlab.com/v1/')
|
136
|
+
# => true
|
118
137
|
```
|
119
138
|
|
120
139
|
## Images
|
@@ -245,6 +264,16 @@ Docker::Image.get('df4f1bdecf40')
|
|
245
264
|
Docker::Image.exist?('ef723dcdac09')
|
246
265
|
# => true
|
247
266
|
|
267
|
+
# Load an image from the file system
|
268
|
+
Docker::Image.load('./my-image.tar')
|
269
|
+
# => ""
|
270
|
+
|
271
|
+
# An IO object may also be specified for loading
|
272
|
+
File.open('./my-image.tar', 'rb') do |file|
|
273
|
+
Docker::Image.load(file)
|
274
|
+
end
|
275
|
+
# => ""
|
276
|
+
|
248
277
|
# Export multiple images to a single tarball
|
249
278
|
# docker command for reference: docker save my_image1 my_image2:not_latest > my_export.tar
|
250
279
|
names = %w( my_image1 my_image2:not_latest )
|
@@ -314,9 +343,77 @@ container.kill(:signal => "SIGHUP")
|
|
314
343
|
container.top
|
315
344
|
# => [{"PID"=>"4851", "TTY"=>"pts/0", "TIME"=>"00:00:00", "CMD"=>"lxc-start"}]
|
316
345
|
|
346
|
+
# Same as above, but uses the original format
|
347
|
+
container.top(format: :hash)
|
348
|
+
# => {
|
349
|
+
# "Titles" => ["PID", "TTY", "TIME", "CMD"],
|
350
|
+
# "Processes" => [["4851", "pts/0", "00:00:00", "lxc-start"]]
|
351
|
+
# }
|
352
|
+
|
353
|
+
# To expose 1234 to bridge
|
354
|
+
# In Dockerfile: EXPOSE 1234/tcp
|
355
|
+
# docker run resulting-image-name
|
356
|
+
Docker::Container.create(
|
357
|
+
'Image' => 'image-name',
|
358
|
+
'HostConfig' => {
|
359
|
+
'PortBindings' => {
|
360
|
+
'1234/tcp' => [{}]
|
361
|
+
}
|
362
|
+
}
|
363
|
+
)
|
364
|
+
|
365
|
+
# To expose 1234 to host with any port
|
366
|
+
# docker run -p 1234 image-name
|
367
|
+
Docker::Container.create(
|
368
|
+
'Image' => 'image-name',
|
369
|
+
'ExposedPorts' => { '1234/tcp' => {} },
|
370
|
+
'HostConfig' => {
|
371
|
+
'PortBindings' => {
|
372
|
+
'1234/tcp' => [{}]
|
373
|
+
}
|
374
|
+
}
|
375
|
+
)
|
376
|
+
|
377
|
+
# To expose 1234 to host with a specified host port
|
378
|
+
# docker run -p 1234:1234 image-name
|
379
|
+
Docker::Container.create(
|
380
|
+
'Image' => 'image-name',
|
381
|
+
'ExposedPorts' => { '1234/tcp' => {} },
|
382
|
+
'HostConfig' => {
|
383
|
+
'PortBindings' => {
|
384
|
+
'1234/tcp' => [{ 'HostPort' => '1234' }]
|
385
|
+
}
|
386
|
+
}
|
387
|
+
)
|
388
|
+
|
389
|
+
# To expose 1234 to host with a specified host port and host IP
|
390
|
+
# docker run -p 192.168.99.100:1234:1234 image-name
|
391
|
+
Docker::Container.create(
|
392
|
+
'Image' => 'image-name',
|
393
|
+
'ExposedPorts' => { '1234/tcp' => {} },
|
394
|
+
'HostConfig' => {
|
395
|
+
'PortBindings' => {
|
396
|
+
'1234/tcp' => [{ 'HostPort' => '1234', 'HostIp' => '192.168.99.100' }]
|
397
|
+
}
|
398
|
+
}
|
399
|
+
)
|
400
|
+
|
401
|
+
# To set container name pass `name` key to options
|
402
|
+
Docker::Container.create(
|
403
|
+
'name' => 'my-new-container',
|
404
|
+
'Image' => 'image-name'
|
405
|
+
)
|
406
|
+
|
407
|
+
# Stores a file with the given content in the container
|
408
|
+
container.store_file("/test", "Hello world")
|
409
|
+
|
410
|
+
# Reads a file from the container
|
411
|
+
container.read_file("/test")
|
412
|
+
# => "Hello world"
|
413
|
+
|
317
414
|
# Export a Container. Since an export is typically at least 300M, chunks of the
|
318
415
|
# export are yielded instead of just returning the whole thing.
|
319
|
-
File.open('export.tar', 'w') do |
|
416
|
+
File.open('export.tar', 'w') do |file|
|
320
417
|
container.export { |chunk| file.write(chunk) }
|
321
418
|
end
|
322
419
|
# => nil
|
@@ -391,6 +488,10 @@ container = Docker::Container.create('Image' => 'ubuntu', 'Cmd' => command, 'Tty
|
|
391
488
|
container.tap(&:start).attach(:tty => true)
|
392
489
|
# => [["I'm a TTY!"], []]
|
393
490
|
|
491
|
+
# Obtaining the current statistics of a container
|
492
|
+
container.stats
|
493
|
+
# => {"read"=>"2016-02-29T20:47:05.221608695Z", "precpu_stats"=>{"cpu_usage"=> ... }
|
494
|
+
|
394
495
|
# Create an Image from a Container's changes.
|
395
496
|
container.commit
|
396
497
|
# => Docker::Image { :id => eaeb8d00efdf, :connection => Docker::Connection { :url => tcp://localhost, :options => {:port=>2375} } }
|
@@ -436,6 +537,9 @@ container.exec(command, wait: 120)
|
|
436
537
|
container.delete(:force => true)
|
437
538
|
# => nil
|
438
539
|
|
540
|
+
# Update the container.
|
541
|
+
container.update("CpuShares" => 50000")
|
542
|
+
|
439
543
|
# Request a Container by ID or name.
|
440
544
|
Docker::Container.get('500f53b25e6e')
|
441
545
|
# => Docker::Container { :id => , :connection => Docker::Connection { :url => tcp://localhost, :options => {:port=>2375} } }
|
@@ -518,10 +622,6 @@ image 'repo:new_tag' => 'repo:tag' do
|
|
518
622
|
end
|
519
623
|
```
|
520
624
|
|
521
|
-
## Known issues
|
522
|
-
|
523
|
-
* If the docker daemon is always responding to your requests with a 400 Bad Request when using UNIX sockets, verify you're running Excon version 0.46.0 or greater. [Link](https://github.com/swipely/docker-api/issues/381)
|
524
|
-
|
525
625
|
## Not supported (yet)
|
526
626
|
|
527
627
|
* Generating a tarball of images and metadata for a repository specified by a name: https://docs.docker.com/engine/reference/api/docker_remote_api_v1.14/#get-a-tarball-containing-all-images-and-tags-in-a-repository
|
data/lib/docker.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'cgi'
|
2
|
-
require '
|
2
|
+
require 'multi_json'
|
3
3
|
require 'excon'
|
4
4
|
require 'tempfile'
|
5
5
|
require 'base64'
|
@@ -14,7 +14,9 @@ require 'open-uri'
|
|
14
14
|
require 'excon/middlewares/hijack'
|
15
15
|
Excon.defaults[:middlewares].unshift Excon::Middleware::Hijack
|
16
16
|
|
17
|
-
|
17
|
+
Excon.defaults[:middlewares] << Excon::Middleware::RedirectFollower
|
18
|
+
|
19
|
+
# The top-level module for this gem. Its purpose is to hold global
|
18
20
|
# configuration variables that are used as defaults in other classes.
|
19
21
|
module Docker
|
20
22
|
attr_accessor :creds, :logger
|
@@ -119,25 +121,16 @@ module Docker
|
|
119
121
|
|
120
122
|
# Login to the Docker registry.
|
121
123
|
def authenticate!(options = {}, connection = self.connection)
|
122
|
-
creds = options
|
123
|
-
connection.post('/auth', {}, :
|
124
|
+
creds = MultiJson.dump(options)
|
125
|
+
connection.post('/auth', {}, body: creds)
|
124
126
|
@creds = creds
|
125
127
|
true
|
126
128
|
rescue Docker::Error::ServerError, Docker::Error::UnauthorizedError
|
127
129
|
raise Docker::Error::AuthenticationError
|
128
130
|
end
|
129
131
|
|
130
|
-
# When the correct version of Docker is installed, returns true. Otherwise,
|
131
|
-
# raises a VersionError.
|
132
|
-
def validate_version!
|
133
|
-
Docker.info
|
134
|
-
true
|
135
|
-
rescue Docker::Error::DockerError
|
136
|
-
raise Docker::Error::VersionError, "Expected API Version: #{API_VERSION}"
|
137
|
-
end
|
138
|
-
|
139
132
|
module_function :default_socket_url, :env_url, :url, :url=, :env_options,
|
140
133
|
:options, :options=, :creds, :creds=, :logger, :logger=,
|
141
134
|
:connection, :reset!, :reset_connection!, :version, :info,
|
142
|
-
:ping, :authenticate!, :
|
135
|
+
:ping, :authenticate!, :ssl_options
|
143
136
|
end
|
data/lib/docker/connection.rb
CHANGED
@@ -80,14 +80,14 @@ private
|
|
80
80
|
user_agent = "Swipely/Docker-API #{Docker::VERSION}"
|
81
81
|
{
|
82
82
|
:method => http_method,
|
83
|
-
:path =>
|
83
|
+
:path => path,
|
84
84
|
:query => query,
|
85
85
|
:headers => { 'Content-Type' => content_type,
|
86
86
|
'User-Agent' => user_agent,
|
87
87
|
}.merge(headers),
|
88
|
-
:expects => (200..204).to_a << 304,
|
88
|
+
:expects => (200..204).to_a << 301 << 304,
|
89
89
|
:idempotent => http_method == :get,
|
90
|
-
:request_block => block
|
90
|
+
:request_block => block,
|
91
91
|
}.merge(opts).reject { |_, v| v.nil? }
|
92
92
|
end
|
93
93
|
end
|
data/lib/docker/container.rb
CHANGED
@@ -11,17 +11,18 @@ class Docker::Container
|
|
11
11
|
}
|
12
12
|
|
13
13
|
info.merge!(self.json)
|
14
|
-
other && info.merge!(other.info)
|
14
|
+
other && info.merge!(other.info) { |key, info_value, other_value| info_value }
|
15
15
|
self
|
16
16
|
end
|
17
17
|
|
18
18
|
# Return a List of Hashes that represents the top running processes.
|
19
19
|
def top(opts = {})
|
20
|
+
format = opts.delete(:format) { :array }
|
20
21
|
resp = Docker::Util.parse_json(connection.get(path_for(:top), opts))
|
21
22
|
if resp['Processes'].nil?
|
22
|
-
[]
|
23
|
+
format == :array ? [] : {}
|
23
24
|
else
|
24
|
-
resp['Processes'].map { |ary| Hash[resp['Titles'].zip(ary)] }
|
25
|
+
format == :array ? resp['Processes'].map { |ary| Hash[resp['Titles'].zip(ary)] } : resp
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
@@ -51,33 +52,37 @@ class Docker::Container
|
|
51
52
|
# @param options [Hash] The options to pass to Docker::Exec
|
52
53
|
#
|
53
54
|
# @return [Docker::Exec] The Exec instance
|
54
|
-
def exec(command,
|
55
|
+
def exec(command, options = {}, &block)
|
55
56
|
# Establish values
|
56
|
-
tty =
|
57
|
-
detach =
|
58
|
-
user =
|
59
|
-
stdin =
|
60
|
-
stdout =
|
61
|
-
stderr =
|
57
|
+
tty = options.delete(:tty) || false
|
58
|
+
detach = options.delete(:detach) || false
|
59
|
+
user = options.delete(:user)
|
60
|
+
stdin = options.delete(:stdin)
|
61
|
+
stdout = options.delete(:stdout) || !detach
|
62
|
+
stderr = options.delete(:stderr) || !detach
|
63
|
+
wait = options.delete(:wait)
|
64
|
+
|
65
|
+
opts = {
|
66
|
+
'Container' => self.id,
|
67
|
+
'User' => user,
|
68
|
+
'AttachStdin' => !!stdin,
|
69
|
+
'AttachStdout' => stdout,
|
70
|
+
'AttachStderr' => stderr,
|
71
|
+
'Tty' => tty,
|
72
|
+
'Cmd' => command
|
73
|
+
}.merge(options)
|
62
74
|
|
63
75
|
# Create Exec Instance
|
64
76
|
instance = Docker::Exec.create(
|
65
|
-
|
66
|
-
'Container' => self.id,
|
67
|
-
'User' => user,
|
68
|
-
'AttachStdin' => !!stdin,
|
69
|
-
'AttachStdout' => stdout,
|
70
|
-
'AttachStderr' => stderr,
|
71
|
-
'Tty' => tty,
|
72
|
-
'Cmd' => command
|
73
|
-
},
|
77
|
+
opts,
|
74
78
|
self.connection
|
75
79
|
)
|
76
80
|
|
77
81
|
start_opts = {
|
78
82
|
:tty => tty,
|
79
83
|
:stdin => stdin,
|
80
|
-
:detach => detach
|
84
|
+
:detach => detach,
|
85
|
+
:wait => wait
|
81
86
|
}
|
82
87
|
|
83
88
|
if detach
|
@@ -95,7 +100,7 @@ class Docker::Container
|
|
95
100
|
end
|
96
101
|
|
97
102
|
# Attach to a container's standard streams / logs.
|
98
|
-
def attach(options = {}, &block)
|
103
|
+
def attach(options = {}, excon_params = {}, &block)
|
99
104
|
stdin = options.delete(:stdin)
|
100
105
|
tty = options.delete(:tty)
|
101
106
|
|
@@ -105,8 +110,6 @@ class Docker::Container
|
|
105
110
|
# Creates list to store stdout and stderr messages
|
106
111
|
msgs = Docker::Messages.new
|
107
112
|
|
108
|
-
excon_params = {}
|
109
|
-
|
110
113
|
if stdin
|
111
114
|
# If attaching to stdin, we must hijack the underlying TCP connection
|
112
115
|
# so we can stream stdin to the remote Docker process
|
@@ -132,10 +135,10 @@ class Docker::Container
|
|
132
135
|
# Based on the link, the config passed as run, needs to be passed as the
|
133
136
|
# body of the post so capture it, remove from the options, and pass it via
|
134
137
|
# the post body
|
135
|
-
config = options.delete('run')
|
136
|
-
hash = Docker::Util.parse_json(
|
137
|
-
|
138
|
-
|
138
|
+
config = MultiJson.dump(options.delete('run'))
|
139
|
+
hash = Docker::Util.parse_json(
|
140
|
+
connection.post('/commit', options, body: config)
|
141
|
+
)
|
139
142
|
Docker::Image.send(:new, self.connection, hash)
|
140
143
|
end
|
141
144
|
|
@@ -156,24 +159,47 @@ class Docker::Container
|
|
156
159
|
connection.get(path_for(:logs), opts)
|
157
160
|
end
|
158
161
|
|
162
|
+
def stats(options = {})
|
163
|
+
if block_given?
|
164
|
+
options[:read_timeout] ||= 10
|
165
|
+
options[:idempotent] ||= false
|
166
|
+
parser = lambda do |chunk, remaining_bytes, total_bytes|
|
167
|
+
yield Docker::Util.parse_json(chunk)
|
168
|
+
end
|
169
|
+
begin
|
170
|
+
connection.get(path_for(:stats), nil, {response_block: parser}.merge(options))
|
171
|
+
rescue Docker::Error::TimeoutError
|
172
|
+
# If the container stops, the docker daemon will hold the connection
|
173
|
+
# open forever, but stop sending events.
|
174
|
+
# So this Timeout indicates the stream is over.
|
175
|
+
end
|
176
|
+
else
|
177
|
+
Docker::Util.parse_json(connection.get(path_for(:stats), {stream: 0}.merge(options)))
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
159
181
|
def rename(new_name)
|
160
182
|
query = {}
|
161
183
|
query['name'] = new_name
|
162
184
|
connection.post(path_for(:rename), query)
|
163
185
|
end
|
164
186
|
|
187
|
+
def update(opts)
|
188
|
+
connection.post(path_for(:update), {}, body: MultiJson.dump(opts))
|
189
|
+
end
|
190
|
+
|
165
191
|
def streaming_logs(opts = {}, &block)
|
166
|
-
stack_size = opts.delete('stack_size') || -1
|
192
|
+
stack_size = opts.delete('stack_size') || opts.delete(:stack_size) || -1
|
167
193
|
tty = opts.delete('tty') || opts.delete(:tty) || false
|
168
194
|
msgs = Docker::MessagesStack.new(stack_size)
|
169
|
-
excon_params = {response_block: Docker::Util.attach_for(block, msgs, tty)}
|
195
|
+
excon_params = {response_block: Docker::Util.attach_for(block, msgs, tty), idempotent: false}
|
170
196
|
|
171
197
|
connection.get(path_for(:logs), opts, excon_params)
|
172
198
|
msgs.messages.join
|
173
199
|
end
|
174
200
|
|
175
201
|
def start!(opts = {})
|
176
|
-
connection.post(path_for(:start), {}, :
|
202
|
+
connection.post(path_for(:start), {}, body: MultiJson.dump(opts))
|
177
203
|
self
|
178
204
|
end
|
179
205
|
|
@@ -198,8 +224,18 @@ class Docker::Container
|
|
198
224
|
define_method(:"#{method}!") do |opts = {}|
|
199
225
|
timeout = opts.delete('timeout')
|
200
226
|
query = {}
|
201
|
-
|
202
|
-
|
227
|
+
request_options = {
|
228
|
+
:body => MultiJson.dump(opts)
|
229
|
+
}
|
230
|
+
if timeout
|
231
|
+
query['t'] = timeout
|
232
|
+
# Ensure request does not timeout before Docker timeout
|
233
|
+
request_options.merge!(
|
234
|
+
read_timeout: timeout.to_i + 5,
|
235
|
+
write_timeout: timeout.to_i + 5
|
236
|
+
)
|
237
|
+
end
|
238
|
+
connection.post(path_for(method), query, request_options)
|
203
239
|
self
|
204
240
|
end
|
205
241
|
|
@@ -230,14 +266,6 @@ class Docker::Container
|
|
230
266
|
end
|
231
267
|
end
|
232
268
|
|
233
|
-
def copy(path, &block)
|
234
|
-
connection.post(path_for(:copy), {},
|
235
|
-
:body => { "Resource" => path }.to_json,
|
236
|
-
:response_block => block
|
237
|
-
)
|
238
|
-
self
|
239
|
-
end
|
240
|
-
|
241
269
|
def archive_out(path, &block)
|
242
270
|
connection.get(
|
243
271
|
path_for(:archive),
|
@@ -269,19 +297,43 @@ class Docker::Container
|
|
269
297
|
self
|
270
298
|
end
|
271
299
|
|
300
|
+
def read_file(path)
|
301
|
+
content = StringIO.new
|
302
|
+
archive_out(path) do |chunk|
|
303
|
+
content.write chunk
|
304
|
+
end
|
305
|
+
|
306
|
+
content.rewind
|
307
|
+
|
308
|
+
Gem::Package::TarReader.new(content) do |tar|
|
309
|
+
tar.each do |tarfile|
|
310
|
+
return tarfile.read
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
def store_file(path, file_content)
|
316
|
+
output_io = StringIO.new(
|
317
|
+
Docker::Util.create_tar(
|
318
|
+
path => file_content
|
319
|
+
)
|
320
|
+
)
|
321
|
+
|
322
|
+
archive_in_stream("/", overwrite: true) { output_io.read }
|
323
|
+
end
|
324
|
+
|
272
325
|
# Create a new Container.
|
273
326
|
def self.create(opts = {}, conn = Docker.connection)
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
resp = conn.post('/containers/create', query, :body => opts.to_json)
|
327
|
+
query = opts.select {|key| ['name', :name].include?(key) }
|
328
|
+
clean_opts = opts.reject {|key| ['name', :name].include?(key) }
|
329
|
+
resp = conn.post('/containers/create', query, :body => MultiJson.dump(clean_opts))
|
278
330
|
hash = Docker::Util.parse_json(resp) || {}
|
279
331
|
new(conn, hash)
|
280
332
|
end
|
281
333
|
|
282
334
|
# Return the container with specified ID
|
283
335
|
def self.get(id, opts = {}, conn = Docker.connection)
|
284
|
-
container_json = conn.get("/containers/#{
|
336
|
+
container_json = conn.get("/containers/#{id}/json", opts)
|
285
337
|
hash = Docker::Util.parse_json(container_json) || {}
|
286
338
|
new(conn, hash)
|
287
339
|
end
|
@@ -292,6 +344,12 @@ class Docker::Container
|
|
292
344
|
hashes.map { |hash| new(conn, hash) }
|
293
345
|
end
|
294
346
|
|
347
|
+
# Prune images
|
348
|
+
def self.prune(conn = Docker.connection)
|
349
|
+
conn.post("/containers/prune", {})
|
350
|
+
nil
|
351
|
+
end
|
352
|
+
|
295
353
|
# Convenience method to return the path for a particular resource.
|
296
354
|
def path_for(resource)
|
297
355
|
"/containers/#{self.id}/#{resource}"
|