docker-api 2.4.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +68 -47
- data/lib/docker/connection.rb +6 -1
- data/lib/docker/container.rb +27 -9
- data/lib/docker/exec.rb +2 -2
- data/lib/docker/image.rb +1 -1
- data/lib/docker/network.rb +3 -3
- data/lib/docker/util.rb +26 -7
- data/lib/docker/version.rb +1 -1
- data/lib/docker/volume.rb +1 -1
- data/lib/docker.rb +2 -2
- metadata +8 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8bd06b9a57651660c10d8e279df9ee588c3eaed258e4ced980f4090a5728a0b3
|
|
4
|
+
data.tar.gz: 07f5419a9f3e02af5db30e41fa91fd12afb01cfed84bae20d19fda55de27819b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e778d8fbb81217c9ad405e0879b8e5754e17e79f6bdb072e717a2ac2e7ab044e3a62a8aab0c3d58fc1094a578ef4480451b478a4161e611a1ce10bbb980564cc
|
|
7
|
+
data.tar.gz: aa0670fd34bd8a2ee4aa16422af84a462451bde78807fe9d9ce2401bc4006f432e79b06d38a86aa0d2ee6d2c2a3cc2ca35b2c67e513565b91bd1ee351df75466
|
data/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
docker-api
|
|
2
2
|
==========
|
|
3
|
-
[](https://badge.fury.io/rb/docker-api)
|
|
3
|
+
[](https://badge.fury.io/rb/docker-api)
|
|
4
4
|
|
|
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.
|
|
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. The gem does not pin an API version, so requests use the daemon's default. It is tested against Docker 28 and 29.
|
|
6
6
|
|
|
7
7
|
If you're interested in using Docker to package your apps, we recommend the [dockly](https://github.com/upserve/dockly) gem. Dockly provides a simple DSL for describing Docker containers that install as Debian packages and are controlled by upstart scripts.
|
|
8
8
|
|
|
@@ -41,7 +41,7 @@ At this time, basic `podman` support has been added via the podman docker-compat
|
|
|
41
41
|
Follow the [installation instructions](https://docs.docker.com/install/), and then run:
|
|
42
42
|
|
|
43
43
|
```shell
|
|
44
|
-
$ sudo
|
|
44
|
+
$ sudo dockerd
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
This will daemonize Docker so that it can be used for the remote API calls.
|
|
@@ -138,15 +138,15 @@ Docker.authenticate!('username' => 'docker-fan-boi', 'password' => 'i<3docker',
|
|
|
138
138
|
|
|
139
139
|
## Images
|
|
140
140
|
|
|
141
|
-
Just about every method here has a one-to-one mapping with the [Images](https://docs.docker.com/
|
|
141
|
+
Just about every method here has a one-to-one mapping with the [Images](https://docs.docker.com/reference/api/engine/) section of the API. If an API call accepts query parameters, these can be passed as an Hash to it's corresponding method. Also, note that `Docker::Image.new` is a private method, so you must use `.create`, `.build`, `.build_from_dir`, `build_from_tar`, or `.import` to make an instance.
|
|
142
142
|
|
|
143
143
|
```ruby
|
|
144
144
|
require 'docker'
|
|
145
145
|
# => true
|
|
146
146
|
|
|
147
147
|
# Pull an Image.
|
|
148
|
-
# docker command for reference: docker pull ubuntu:
|
|
149
|
-
image = Docker::Image.create('fromImage' => 'ubuntu:
|
|
148
|
+
# docker command for reference: docker pull ubuntu:24.04
|
|
149
|
+
image = Docker::Image.create('fromImage' => 'ubuntu:24.04')
|
|
150
150
|
# => Docker::Image { :id => ae7ffbcd1, :connection => Docker::Connection { :url => tcp://localhost, :options => {:port=>2375} } }
|
|
151
151
|
|
|
152
152
|
# Insert a local file into an Image.
|
|
@@ -194,12 +194,12 @@ image.run('ls -l')
|
|
|
194
194
|
# Remove the Image from the server.
|
|
195
195
|
# docker command for reference: docker rmi -f <IMAGE.ID>
|
|
196
196
|
image.remove(:force => true)
|
|
197
|
-
# =>
|
|
197
|
+
# => "[{\"Untagged\":\"base2:latest\"}]\n"
|
|
198
198
|
|
|
199
199
|
# Export a single Docker Image to a file
|
|
200
200
|
# docker command for reference: docker save <IMAGE.ID> my_export.tar
|
|
201
201
|
image.save('my_export.tar')
|
|
202
|
-
# =>
|
|
202
|
+
# => nil
|
|
203
203
|
|
|
204
204
|
# Return the raw image binary data
|
|
205
205
|
image.save
|
|
@@ -225,7 +225,7 @@ File.open('my-export.tar') do |file|
|
|
|
225
225
|
end
|
|
226
226
|
|
|
227
227
|
# Create an Image from a Dockerfile as a String.
|
|
228
|
-
Docker::Image.build("
|
|
228
|
+
Docker::Image.build("FROM debian:stable\nRUN touch /test")
|
|
229
229
|
# => Docker::Image { :id => b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc, :connection => Docker::Connection { :url => tcp://localhost, :options => {:port=>2375} } }
|
|
230
230
|
|
|
231
231
|
# Create an Image from a Dockerfile.
|
|
@@ -256,7 +256,7 @@ Docker::Image.all
|
|
|
256
256
|
# => [Docker::Image { :id => b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc, :connection => Docker::Connection { :url => tcp://localhost, :options => {:port=>2375} } }, Docker::Image { :id => 8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c, :connection => Docker::Connection { :url => tcp://localhost, :options => {:port=>2375} } }]
|
|
257
257
|
|
|
258
258
|
# Get Image from the server, with id
|
|
259
|
-
# docker command for reference: docker
|
|
259
|
+
# docker command for reference: docker inspect <IMAGE.ID>
|
|
260
260
|
Docker::Image.get('df4f1bdecf40')
|
|
261
261
|
# => Docker::Image { :id => eb693ec80, :connection => Docker::Connection { :url => tcp://localhost, :options => {:port=>2375} } }
|
|
262
262
|
|
|
@@ -298,13 +298,13 @@ Docker::Image.search('term' => 'sshd')
|
|
|
298
298
|
|
|
299
299
|
## Containers
|
|
300
300
|
|
|
301
|
-
Much like the Images, this object also has a one-to-one mapping with the [Containers](https://docs.docker.com/
|
|
301
|
+
Much like the Images, this object also has a one-to-one mapping with the [Containers](https://docs.docker.com/reference/api/engine/) section of the API. Also like Images, `.new` is a private method, so you must use `.create` to make an instance.
|
|
302
302
|
|
|
303
303
|
```ruby
|
|
304
304
|
require 'docker'
|
|
305
305
|
|
|
306
306
|
# Create a Container.
|
|
307
|
-
container = Docker::Container.create('Cmd' => ['ls'], 'Image' => '
|
|
307
|
+
container = Docker::Container.create('Cmd' => ['ls'], 'Image' => 'debian:stable')
|
|
308
308
|
# => Docker::Container { :id => 492510dd38e4, :connection => Docker::Connection { :url => tcp://localhost, :options => {:port=>2375} } }
|
|
309
309
|
|
|
310
310
|
# Get more information about the Container.
|
|
@@ -423,15 +423,15 @@ container.changes
|
|
|
423
423
|
# => [{'Path'=>'/dev', 'Kind'=>0}, {'Path'=>'/dev/kmsg', 'Kind'=>1}]
|
|
424
424
|
|
|
425
425
|
# Copy files/directories from the Container. Note that these are exported as tars.
|
|
426
|
-
container.
|
|
427
|
-
|
|
428
|
-
hosts0000644000000000000000000000023412100405636007023 0ustar
|
|
429
|
-
127.0.0.1 localhost
|
|
430
|
-
::1 localhost ip6-localhost ip6-loopback
|
|
431
|
-
fe00::0 ip6-localnet
|
|
432
|
-
ff00::0 ip6-mcastprefix
|
|
433
|
-
ff02::1 ip6-allnodes
|
|
434
|
-
ff02::2 ip6-allrouters
|
|
426
|
+
container.archive_out('/etc/hosts') { |chunk| puts chunk }
|
|
427
|
+
|
|
428
|
+
# hosts0000644000000000000000000000023412100405636007023 0ustar
|
|
429
|
+
# 127.0.0.1 localhost
|
|
430
|
+
# ::1 localhost ip6-localhost ip6-loopback
|
|
431
|
+
# fe00::0 ip6-localnet
|
|
432
|
+
# ff00::0 ip6-mcastprefix
|
|
433
|
+
# ff02::1 ip6-allnodes
|
|
434
|
+
# ff02::2 ip6-allrouters
|
|
435
435
|
# => Docker::Container { :id => a1759f3e2873, :connection => Docker::Connection { :url => tcp://localhost, :options => {:port=>2375} } }
|
|
436
436
|
|
|
437
437
|
# Wait for the current command to finish executing. If an argument is given,
|
|
@@ -445,13 +445,13 @@ container.attach(:stream => true, :stdin => nil, :stdout => true, :stderr => tru
|
|
|
445
445
|
# => [["bin\nboot\ndev\netc\nhome\nlib\nlib64\nmedia\nmnt\nopt\nproc\nroot\nrun\nsbin\nselinux\nsrv\nsys\ntmp\nusr\nvar", []]
|
|
446
446
|
|
|
447
447
|
# If you wish to stream the attach method, a block may be supplied.
|
|
448
|
-
container = Docker::Container.create('Image' => '
|
|
448
|
+
container = Docker::Container.create('Image' => 'debian:stable', 'Cmd' => ['find / -name *'])
|
|
449
449
|
container.tap(&:start).attach { |stream, chunk| puts "#{stream}: #{chunk}" }
|
|
450
|
-
stderr: 2013/10/30 17:16:24 Unable to locate find / -name *
|
|
450
|
+
# stderr: 2013/10/30 17:16:24 Unable to locate find / -name *
|
|
451
451
|
# => [[], ["2013/10/30 17:16:24 Unable to locate find / -name *\n"]]
|
|
452
452
|
|
|
453
453
|
# If you want to attach to stdin of the container, supply an IO-like object:
|
|
454
|
-
container = Docker::Container.create('Image' => '
|
|
454
|
+
container = Docker::Container.create('Image' => 'debian:stable', 'Cmd' => ['cat'], 'OpenStdin' => true, 'StdinOnce' => true)
|
|
455
455
|
container.tap(&:start).attach(stdin: StringIO.new("foo\nbar\n"))
|
|
456
456
|
# => [["foo\nbar\n"], []]
|
|
457
457
|
|
|
@@ -470,16 +470,16 @@ container.logs(stdout: true)
|
|
|
470
470
|
|
|
471
471
|
# Streaming logs from non-TTY container removing multiplex prefix with a block printing out each line (block not possible with Container#logs)
|
|
472
472
|
container.streaming_logs(stdout: true) { |stream, chunk| puts "#{stream}: #{chunk}" }
|
|
473
|
-
stdout: 1
|
|
474
|
-
stdout: 2
|
|
475
|
-
stdout: 3
|
|
476
|
-
stdout: 4
|
|
477
|
-
stdout: 5
|
|
478
|
-
stdout: 6
|
|
479
|
-
stdout: 7
|
|
480
|
-
stdout: 8
|
|
481
|
-
stdout: 9
|
|
482
|
-
stdout: 10
|
|
473
|
+
# stdout: 1
|
|
474
|
+
# stdout: 2
|
|
475
|
+
# stdout: 3
|
|
476
|
+
# stdout: 4
|
|
477
|
+
# stdout: 5
|
|
478
|
+
# stdout: 6
|
|
479
|
+
# stdout: 7
|
|
480
|
+
# stdout: 8
|
|
481
|
+
# stdout: 9
|
|
482
|
+
# stdout: 10
|
|
483
483
|
# => "1\n\n2\n\n3\n\n4\n\n5\n\n6\n\n7\n\n8\n\n9\n\n10\n"
|
|
484
484
|
|
|
485
485
|
# If the container has TTY enabled, set `tty => true` to get the raw stream:
|
|
@@ -499,7 +499,7 @@ container.commit
|
|
|
499
499
|
# Commit the Container and run a new command. The second argument is the number
|
|
500
500
|
# of seconds the Container should wait before stopping its current command.
|
|
501
501
|
container.run('pwd', 10)
|
|
502
|
-
# => Docker::
|
|
502
|
+
# => Docker::Container { :id => 4427be4199ac, :connection => Docker::Connection { :url => tcp://localhost, :options => {:port=>2375} } }
|
|
503
503
|
|
|
504
504
|
# Run an Exec instance inside the container and capture its output and exit status
|
|
505
505
|
container.exec(['date'])
|
|
@@ -511,12 +511,13 @@ container.exec(['./my_service'], detach: true)
|
|
|
511
511
|
|
|
512
512
|
# Parse the output of an Exec instance
|
|
513
513
|
container.exec(['find', '/', '-name *']) { |stream, chunk| puts "#{stream}: #{chunk}" }
|
|
514
|
-
stderr: 2013/10/30 17:16:24 Unable to locate find / -name *
|
|
514
|
+
# stderr: 2013/10/30 17:16:24 Unable to locate find / -name *
|
|
515
515
|
# => [[], ["2013/10/30 17:16:24 Unable to locate find / -name *\n"], 1]
|
|
516
516
|
|
|
517
|
-
#
|
|
518
|
-
|
|
519
|
-
|
|
517
|
+
# The return value is [stdout_lines, stderr_lines, exit_code], so destructure
|
|
518
|
+
# it if you only care about one stream.
|
|
519
|
+
stdout, _stderr, _exit_code = container.exec(['date'])
|
|
520
|
+
# stdout => ["Wed Nov 26 11:10:30 CST 2014\n"]
|
|
520
521
|
|
|
521
522
|
# Pass input to an Exec instance command via Stdin
|
|
522
523
|
container.exec(['cat'], stdin: StringIO.new("foo\nbar\n"))
|
|
@@ -529,7 +530,7 @@ container.exec(command, tty: true)
|
|
|
529
530
|
|
|
530
531
|
# Wait for the current command to finish executing. If an argument is given,
|
|
531
532
|
# will timeout after that number of seconds. The default is one minute.
|
|
532
|
-
command = ["bash", "-c", "if [ -t 1 ]; then echo -n \"Set max seconds for exec
|
|
533
|
+
command = ["bash", "-c", "if [ -t 1 ]; then echo -n \"Set max seconds for exec!\"; fi"]
|
|
533
534
|
container.exec(command, wait: 120)
|
|
534
535
|
# => [["Set max seconds for exec!"], [], 0]
|
|
535
536
|
|
|
@@ -538,7 +539,7 @@ container.delete(:force => true)
|
|
|
538
539
|
# => nil
|
|
539
540
|
|
|
540
541
|
# Update the container.
|
|
541
|
-
container.update("CpuShares" => 50000
|
|
542
|
+
container.update("CpuShares" => 50000)
|
|
542
543
|
|
|
543
544
|
# Request a Container by ID or name.
|
|
544
545
|
Docker::Container.get('500f53b25e6e')
|
|
@@ -578,17 +579,37 @@ require 'docker'
|
|
|
578
579
|
|
|
579
580
|
# Action on a stream of events as they come in
|
|
580
581
|
Docker::Event.stream { |event| puts event; break }
|
|
581
|
-
Docker::Event { :status => create, :id => aeb8b55726df63bdd69d41e1b2650131d7ce32ca0d2fa5cbc75f24d0df34c7b0, :from =>
|
|
582
|
+
# Docker::Event { :status => create, :id => aeb8b55726df63bdd69d41e1b2650131d7ce32ca0d2fa5cbc75f24d0df34c7b0, :from => debian:stable, :time => 1416958554 }
|
|
582
583
|
# => nil
|
|
583
584
|
|
|
584
585
|
# Action on all events after a given time (will execute the block for all events up till the current time, and wait to execute on any new events after)
|
|
585
586
|
Docker::Event.since(1416958763) { |event| puts event; puts Time.now.to_i; break }
|
|
586
|
-
Docker::Event { :status => die, :id => 663005cdeb56f50177c395a817dbc8bdcfbdfbdaef329043b409ecb97fb68d7e, :from =>
|
|
587
|
-
1416959041
|
|
587
|
+
# Docker::Event { :status => die, :id => 663005cdeb56f50177c395a817dbc8bdcfbdfbdaef329043b409ecb97fb68d7e, :from => debian:stable, :time => 1416958764 }
|
|
588
|
+
# 1416959041
|
|
588
589
|
# => nil
|
|
589
590
|
```
|
|
590
591
|
|
|
591
|
-
These methods are prone to read timeouts.
|
|
592
|
+
These methods are prone to read timeouts. Note that the first argument to
|
|
593
|
+
`Docker::Event.stream` and `Docker::Event.since` is a hash of **query parameters**
|
|
594
|
+
for the `/events` endpoint, not Excon options. Passing `read_timeout` there sends
|
|
595
|
+
it to Docker as a query parameter and has no effect on the timeout. Set it on the
|
|
596
|
+
connection instead:
|
|
597
|
+
|
|
598
|
+
```ruby
|
|
599
|
+
# Disable timeouts completely, for this call only
|
|
600
|
+
conn = Docker::Connection.new(Docker.url, Docker.options.merge(read_timeout: 0))
|
|
601
|
+
Docker::Event.stream({}, conn) { |event| puts event }
|
|
602
|
+
|
|
603
|
+
# Timeout if no events are received in 24h
|
|
604
|
+
conn = Docker::Connection.new(Docker.url, Docker.options.merge(read_timeout: 60 * 60 * 24))
|
|
605
|
+
Docker::Event.stream({}, conn) { |event| puts event }
|
|
606
|
+
|
|
607
|
+
# Or set a high timeout globally. Be warned that you probably don't want this
|
|
608
|
+
# for other methods. This has to happen before the default connection is first
|
|
609
|
+
# used, since `Docker.connection` is memoized.
|
|
610
|
+
Docker.options[:read_timeout] = 60 * 60 * 24
|
|
611
|
+
Docker::Event.stream { |event| puts event }
|
|
612
|
+
```
|
|
592
613
|
|
|
593
614
|
## Connecting to Multiple Servers
|
|
594
615
|
|
|
@@ -624,8 +645,8 @@ end
|
|
|
624
645
|
|
|
625
646
|
## Not supported (yet)
|
|
626
647
|
|
|
627
|
-
* Generating a tarball of images and metadata for a repository specified by a name
|
|
628
|
-
* Load a tarball generated from docker that contains all the images and metadata of a repository
|
|
648
|
+
* Generating a tarball of images and metadata for a repository specified by a name
|
|
649
|
+
* Load a tarball generated from docker that contains all the images and metadata of a repository
|
|
629
650
|
|
|
630
651
|
License
|
|
631
652
|
-----
|
data/lib/docker/connection.rb
CHANGED
|
@@ -129,7 +129,12 @@ class Docker::Connection
|
|
|
129
129
|
end
|
|
130
130
|
|
|
131
131
|
def rootless?
|
|
132
|
-
|
|
132
|
+
# `||=` cannot cache a false result, so this has to test for the ivar
|
|
133
|
+
# itself. #info is not memoized, so re-evaluating means another /info
|
|
134
|
+
# request on every call against a non-rootless daemon.
|
|
135
|
+
return @rootless if defined?(@rootless)
|
|
136
|
+
|
|
137
|
+
@rootless = (info['Rootless'] == true)
|
|
133
138
|
end
|
|
134
139
|
|
|
135
140
|
def version
|
data/lib/docker/container.rb
CHANGED
|
@@ -60,8 +60,11 @@ class Docker::Container
|
|
|
60
60
|
detach = options.delete(:detach) || false
|
|
61
61
|
user = options.delete(:user)
|
|
62
62
|
stdin = options.delete(:stdin)
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
# `options.delete(:stdout) || !detach` turns an explicit false back into
|
|
64
|
+
# true, so these have to be tested for presence rather than truthiness.
|
|
65
|
+
# They default to the inverse of :detach when the caller says nothing.
|
|
66
|
+
stdout = options.key?(:stdout) ? options.delete(:stdout) : !detach
|
|
67
|
+
stderr = options.key?(:stderr) ? options.delete(:stderr) : !detach
|
|
65
68
|
wait = options.delete(:wait)
|
|
66
69
|
|
|
67
70
|
opts = {
|
|
@@ -118,6 +121,16 @@ class Docker::Container
|
|
|
118
121
|
opts[:stdin] = true
|
|
119
122
|
excon_params[:hijack_block] = Docker::Util.hijack_for(stdin, block,
|
|
120
123
|
msgs, tty)
|
|
124
|
+
# Hijacking means asking the daemon to upgrade the connection. Without
|
|
125
|
+
# these headers Docker answers 200 and leaves the payload on Excon's
|
|
126
|
+
# buffered socket, which the raw hijacked read never looks at, so the
|
|
127
|
+
# attach blocks forever. With them the daemon replies 101 and hands the
|
|
128
|
+
# socket over, so 101 has to be an accepted status.
|
|
129
|
+
excon_params[:headers] = {
|
|
130
|
+
'Connection' => 'Upgrade',
|
|
131
|
+
'Upgrade' => 'tcp'
|
|
132
|
+
}.merge(excon_params[:headers] || {})
|
|
133
|
+
excon_params[:expects] ||= (200..204).to_a + [101, 301, 304]
|
|
121
134
|
else
|
|
122
135
|
excon_params[:response_block] = Docker::Util.attach_for(block, msgs, tty)
|
|
123
136
|
end
|
|
@@ -137,7 +150,7 @@ class Docker::Container
|
|
|
137
150
|
# Based on the link, the config passed as run, needs to be passed as the
|
|
138
151
|
# body of the post so capture it, remove from the options, and pass it via
|
|
139
152
|
# the post body
|
|
140
|
-
config =
|
|
153
|
+
config = JSON.generate(options.delete('run'))
|
|
141
154
|
hash = Docker::Util.parse_json(
|
|
142
155
|
connection.post('/commit', options, body: config)
|
|
143
156
|
)
|
|
@@ -187,7 +200,7 @@ class Docker::Container
|
|
|
187
200
|
end
|
|
188
201
|
|
|
189
202
|
def update(opts)
|
|
190
|
-
connection.post(path_for(:update), {}, body:
|
|
203
|
+
connection.post(path_for(:update), {}, body: JSON.generate(opts))
|
|
191
204
|
end
|
|
192
205
|
|
|
193
206
|
def streaming_logs(opts = {}, &block)
|
|
@@ -201,7 +214,7 @@ class Docker::Container
|
|
|
201
214
|
end
|
|
202
215
|
|
|
203
216
|
def start!(opts = {})
|
|
204
|
-
connection.post(path_for(:start), {}, body:
|
|
217
|
+
connection.post(path_for(:start), {}, body: JSON.generate(opts))
|
|
205
218
|
self
|
|
206
219
|
end
|
|
207
220
|
|
|
@@ -227,7 +240,7 @@ class Docker::Container
|
|
|
227
240
|
timeout = opts.delete('timeout')
|
|
228
241
|
query = {}
|
|
229
242
|
request_options = {
|
|
230
|
-
:body =>
|
|
243
|
+
:body => JSON.generate(opts)
|
|
231
244
|
}
|
|
232
245
|
if timeout
|
|
233
246
|
query['t'] = timeout
|
|
@@ -324,11 +337,16 @@ class Docker::Container
|
|
|
324
337
|
archive_in_stream("/", overwrite: true) { output_io.read }
|
|
325
338
|
end
|
|
326
339
|
|
|
340
|
+
# Keys that /containers/create takes as query parameters rather than in the
|
|
341
|
+
# request body. The daemon silently ignores them if they are sent in the
|
|
342
|
+
# body, so a misplaced key means the option has no effect at all.
|
|
343
|
+
CREATE_QUERY_KEYS = %w[name platform].freeze
|
|
344
|
+
|
|
327
345
|
# Create a new Container.
|
|
328
346
|
def self.create(opts = {}, conn = Docker.connection)
|
|
329
|
-
query = opts.select {|key|
|
|
330
|
-
clean_opts = opts.reject {|key|
|
|
331
|
-
resp = conn.post('/containers/create', query, :body =>
|
|
347
|
+
query = opts.select { |key| CREATE_QUERY_KEYS.include?(key.to_s) }
|
|
348
|
+
clean_opts = opts.reject { |key| CREATE_QUERY_KEYS.include?(key.to_s) }
|
|
349
|
+
resp = conn.post('/containers/create', query, :body => JSON.generate(clean_opts))
|
|
332
350
|
hash = Docker::Util.parse_json(resp) || {}
|
|
333
351
|
new(conn, hash)
|
|
334
352
|
end
|
data/lib/docker/exec.rb
CHANGED
|
@@ -29,7 +29,7 @@ class Docker::Exec
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
resp = conn.post("/containers/#{container}/exec", {},
|
|
32
|
-
body:
|
|
32
|
+
body: JSON.generate(options))
|
|
33
33
|
hash = Docker::Util.parse_json(resp) || {}
|
|
34
34
|
new(conn, hash)
|
|
35
35
|
end
|
|
@@ -60,7 +60,7 @@ class Docker::Exec
|
|
|
60
60
|
read_timeout = options[:wait]
|
|
61
61
|
|
|
62
62
|
# Create API Request Body
|
|
63
|
-
body =
|
|
63
|
+
body = JSON.generate(
|
|
64
64
|
'Tty' => tty,
|
|
65
65
|
'Detach' => detached
|
|
66
66
|
)
|
data/lib/docker/image.rb
CHANGED
|
@@ -119,7 +119,7 @@ class Docker::Image
|
|
|
119
119
|
|
|
120
120
|
# Create a new Image.
|
|
121
121
|
def create(opts = {}, creds = nil, conn = Docker.connection, &block)
|
|
122
|
-
credentials = creds.nil? ? Docker.creds :
|
|
122
|
+
credentials = creds.nil? ? Docker.creds : JSON.generate(creds)
|
|
123
123
|
headers = credentials && Docker::Util.build_auth_header(credentials) || {}
|
|
124
124
|
body = +''
|
|
125
125
|
conn.post(
|
data/lib/docker/network.rb
CHANGED
|
@@ -5,7 +5,7 @@ class Docker::Network
|
|
|
5
5
|
include Docker::Base
|
|
6
6
|
|
|
7
7
|
def connect(container, opts = {}, body_opts = {})
|
|
8
|
-
body =
|
|
8
|
+
body = JSON.generate({ container: container }.merge(body_opts))
|
|
9
9
|
Docker::Util.parse_json(
|
|
10
10
|
connection.post(path_for('connect'), opts, body: body)
|
|
11
11
|
)
|
|
@@ -13,7 +13,7 @@ class Docker::Network
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def disconnect(container, opts = {})
|
|
16
|
-
body =
|
|
16
|
+
body = JSON.generate(container: container)
|
|
17
17
|
Docker::Util.parse_json(
|
|
18
18
|
connection.post(path_for('disconnect'), opts, body: body)
|
|
19
19
|
)
|
|
@@ -43,7 +43,7 @@ class Docker::Network
|
|
|
43
43
|
|
|
44
44
|
class << self
|
|
45
45
|
def create(name, opts = {}, conn = Docker.connection)
|
|
46
|
-
default_opts =
|
|
46
|
+
default_opts = JSON.generate({
|
|
47
47
|
'Name' => name,
|
|
48
48
|
'CheckDuplicate' => true
|
|
49
49
|
}.merge(opts))
|
data/lib/docker/util.rb
CHANGED
|
@@ -106,8 +106,8 @@ module Docker::Util
|
|
|
106
106
|
end
|
|
107
107
|
|
|
108
108
|
def parse_json(body)
|
|
109
|
-
|
|
110
|
-
rescue
|
|
109
|
+
JSON.parse(body) unless body.nil? || body.empty? || (body == 'null')
|
|
110
|
+
rescue JSON::ParserError => ex
|
|
111
111
|
raise UnexpectedResponseError, ex.message
|
|
112
112
|
end
|
|
113
113
|
|
|
@@ -173,14 +173,25 @@ module Docker::Util
|
|
|
173
173
|
end
|
|
174
174
|
|
|
175
175
|
def create_relative_dir_tar(directory, output)
|
|
176
|
+
root = File.realpath(directory)
|
|
177
|
+
|
|
176
178
|
Gem::Package::TarWriter.new(output) do |tar|
|
|
177
179
|
files = docker_context(directory)
|
|
178
180
|
|
|
179
181
|
files.each do |prefixed_file_name|
|
|
180
|
-
stat = File.
|
|
182
|
+
stat = File.lstat(prefixed_file_name)
|
|
183
|
+
unprefixed_file_name = prefixed_file_name[directory.length..-1]
|
|
184
|
+
|
|
185
|
+
if stat.symlink?
|
|
186
|
+
tar.add_symlink(
|
|
187
|
+
unprefixed_file_name, File.readlink(prefixed_file_name), stat.mode
|
|
188
|
+
)
|
|
189
|
+
next
|
|
190
|
+
end
|
|
181
191
|
next unless stat.file?
|
|
182
192
|
|
|
183
|
-
|
|
193
|
+
next unless contained?(prefixed_file_name, root)
|
|
194
|
+
|
|
184
195
|
add_file_to_tar(
|
|
185
196
|
tar, unprefixed_file_name, stat.mode, stat.size, stat.mtime
|
|
186
197
|
) do |tar_file|
|
|
@@ -190,6 +201,14 @@ module Docker::Util
|
|
|
190
201
|
end
|
|
191
202
|
end
|
|
192
203
|
|
|
204
|
+
# True when path resolves, with every symlink and '..' expanded, to
|
|
205
|
+
# something underneath root.
|
|
206
|
+
def contained?(path, root)
|
|
207
|
+
File.realpath(path).start_with?(root + File::SEPARATOR)
|
|
208
|
+
rescue SystemCallError
|
|
209
|
+
false
|
|
210
|
+
end
|
|
211
|
+
|
|
193
212
|
def add_file_to_tar(tar, name, mode, size, mtime)
|
|
194
213
|
tar.check_closed
|
|
195
214
|
|
|
@@ -261,7 +280,7 @@ module Docker::Util
|
|
|
261
280
|
end
|
|
262
281
|
|
|
263
282
|
def build_auth_header(credentials)
|
|
264
|
-
credentials =
|
|
283
|
+
credentials = JSON.generate(credentials) if credentials.is_a?(Hash)
|
|
265
284
|
encoded_creds = Base64.urlsafe_encode64(credentials)
|
|
266
285
|
{
|
|
267
286
|
'X-Registry-Auth' => encoded_creds
|
|
@@ -270,10 +289,10 @@ module Docker::Util
|
|
|
270
289
|
|
|
271
290
|
def build_config_header(credentials)
|
|
272
291
|
if credentials.is_a?(String)
|
|
273
|
-
credentials =
|
|
292
|
+
credentials = JSON.parse(credentials, symbolize_names: true)
|
|
274
293
|
end
|
|
275
294
|
|
|
276
|
-
header =
|
|
295
|
+
header = JSON.generate(
|
|
277
296
|
credentials[:serveraddress].to_s => {
|
|
278
297
|
'username' => credentials[:username].to_s,
|
|
279
298
|
'password' => credentials[:password].to_s,
|
data/lib/docker/version.rb
CHANGED
data/lib/docker/volume.rb
CHANGED
|
@@ -33,7 +33,7 @@ class Docker::Volume
|
|
|
33
33
|
# creates a volume with an arbitrary name
|
|
34
34
|
def create(name, opts = {}, conn = Docker.connection)
|
|
35
35
|
opts['Name'] = name
|
|
36
|
-
resp = conn.post('/volumes/create', {}, body:
|
|
36
|
+
resp = conn.post('/volumes/create', {}, body: JSON.generate(opts))
|
|
37
37
|
hash = Docker::Util.parse_json(resp) || {}
|
|
38
38
|
new(conn, hash)
|
|
39
39
|
end
|
data/lib/docker.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'cgi'
|
|
4
|
-
require '
|
|
4
|
+
require 'json'
|
|
5
5
|
require 'excon'
|
|
6
6
|
require 'tempfile'
|
|
7
7
|
require 'base64'
|
|
@@ -133,7 +133,7 @@ module Docker
|
|
|
133
133
|
|
|
134
134
|
# Login to the Docker registry.
|
|
135
135
|
def authenticate!(options = {}, connection = self.connection)
|
|
136
|
-
creds =
|
|
136
|
+
creds = JSON.generate(options)
|
|
137
137
|
connection.post('/auth', {}, body: creds)
|
|
138
138
|
@creds = creds
|
|
139
139
|
true
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: docker-api
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Swipely, Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-10-27 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: excon
|
|
@@ -25,7 +25,7 @@ dependencies:
|
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: 0.64.0
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
28
|
+
name: base64
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - ">="
|
|
@@ -164,7 +164,10 @@ files:
|
|
|
164
164
|
homepage: https://github.com/upserve/docker-api
|
|
165
165
|
licenses:
|
|
166
166
|
- MIT
|
|
167
|
-
metadata:
|
|
167
|
+
metadata:
|
|
168
|
+
bug_tracker_uri: https://github.com/upserve/docker-api/issues
|
|
169
|
+
source_code_uri: https://github.com/upserve/docker-api
|
|
170
|
+
rubygems_mfa_required: 'true'
|
|
168
171
|
post_install_message:
|
|
169
172
|
rdoc_options: []
|
|
170
173
|
require_paths:
|
|
@@ -180,7 +183,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
180
183
|
- !ruby/object:Gem::Version
|
|
181
184
|
version: '0'
|
|
182
185
|
requirements: []
|
|
183
|
-
rubygems_version: 3.
|
|
186
|
+
rubygems_version: 3.2.34
|
|
184
187
|
signing_key:
|
|
185
188
|
specification_version: 4
|
|
186
189
|
summary: A simple REST client for the Docker Remote API
|