docker-api 2.3.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/base.rb +2 -0
- data/lib/docker/connection.rb +8 -1
- data/lib/docker/container.rb +29 -9
- data/lib/docker/error.rb +2 -0
- data/lib/docker/event.rb +2 -0
- data/lib/docker/exec.rb +4 -2
- data/lib/docker/image.rb +10 -8
- data/lib/docker/messages.rb +2 -0
- data/lib/docker/messages_stack.rb +2 -0
- data/lib/docker/network.rb +5 -3
- data/lib/docker/rake_task.rb +2 -0
- data/lib/docker/util.rb +28 -7
- data/lib/docker/version.rb +3 -1
- data/lib/docker/volume.rb +3 -1
- data/lib/docker-api.rb +2 -0
- data/lib/docker.rb +4 -2
- data/lib/excon/middlewares/hijack.rb +2 -0
- metadata +8 -19
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/base.rb
CHANGED
data/lib/docker/connection.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# This class represents a Connection to a Docker server. The Connection is
|
|
2
4
|
# immutable in that once the url and options is set they cannot be changed.
|
|
3
5
|
class Docker::Connection
|
|
@@ -127,7 +129,12 @@ class Docker::Connection
|
|
|
127
129
|
end
|
|
128
130
|
|
|
129
131
|
def rootless?
|
|
130
|
-
|
|
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)
|
|
131
138
|
end
|
|
132
139
|
|
|
133
140
|
def version
|
data/lib/docker/container.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# This class represents a Docker Container. It's important to note that nothing
|
|
2
4
|
# is cached so that the information is always up to date.
|
|
3
5
|
class Docker::Container
|
|
@@ -58,8 +60,11 @@ class Docker::Container
|
|
|
58
60
|
detach = options.delete(:detach) || false
|
|
59
61
|
user = options.delete(:user)
|
|
60
62
|
stdin = options.delete(:stdin)
|
|
61
|
-
|
|
62
|
-
|
|
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
|
|
63
68
|
wait = options.delete(:wait)
|
|
64
69
|
|
|
65
70
|
opts = {
|
|
@@ -116,6 +121,16 @@ class Docker::Container
|
|
|
116
121
|
opts[:stdin] = true
|
|
117
122
|
excon_params[:hijack_block] = Docker::Util.hijack_for(stdin, block,
|
|
118
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]
|
|
119
134
|
else
|
|
120
135
|
excon_params[:response_block] = Docker::Util.attach_for(block, msgs, tty)
|
|
121
136
|
end
|
|
@@ -135,7 +150,7 @@ class Docker::Container
|
|
|
135
150
|
# Based on the link, the config passed as run, needs to be passed as the
|
|
136
151
|
# body of the post so capture it, remove from the options, and pass it via
|
|
137
152
|
# the post body
|
|
138
|
-
config =
|
|
153
|
+
config = JSON.generate(options.delete('run'))
|
|
139
154
|
hash = Docker::Util.parse_json(
|
|
140
155
|
connection.post('/commit', options, body: config)
|
|
141
156
|
)
|
|
@@ -185,7 +200,7 @@ class Docker::Container
|
|
|
185
200
|
end
|
|
186
201
|
|
|
187
202
|
def update(opts)
|
|
188
|
-
connection.post(path_for(:update), {}, body:
|
|
203
|
+
connection.post(path_for(:update), {}, body: JSON.generate(opts))
|
|
189
204
|
end
|
|
190
205
|
|
|
191
206
|
def streaming_logs(opts = {}, &block)
|
|
@@ -199,7 +214,7 @@ class Docker::Container
|
|
|
199
214
|
end
|
|
200
215
|
|
|
201
216
|
def start!(opts = {})
|
|
202
|
-
connection.post(path_for(:start), {}, body:
|
|
217
|
+
connection.post(path_for(:start), {}, body: JSON.generate(opts))
|
|
203
218
|
self
|
|
204
219
|
end
|
|
205
220
|
|
|
@@ -225,7 +240,7 @@ class Docker::Container
|
|
|
225
240
|
timeout = opts.delete('timeout')
|
|
226
241
|
query = {}
|
|
227
242
|
request_options = {
|
|
228
|
-
:body =>
|
|
243
|
+
:body => JSON.generate(opts)
|
|
229
244
|
}
|
|
230
245
|
if timeout
|
|
231
246
|
query['t'] = timeout
|
|
@@ -322,11 +337,16 @@ class Docker::Container
|
|
|
322
337
|
archive_in_stream("/", overwrite: true) { output_io.read }
|
|
323
338
|
end
|
|
324
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
|
+
|
|
325
345
|
# Create a new Container.
|
|
326
346
|
def self.create(opts = {}, conn = Docker.connection)
|
|
327
|
-
query = opts.select {|key|
|
|
328
|
-
clean_opts = opts.reject {|key|
|
|
329
|
-
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))
|
|
330
350
|
hash = Docker::Util.parse_json(resp) || {}
|
|
331
351
|
new(conn, hash)
|
|
332
352
|
end
|
data/lib/docker/error.rb
CHANGED
data/lib/docker/event.rb
CHANGED
data/lib/docker/exec.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# This class represents a Docker Exec Instance.
|
|
2
4
|
class Docker::Exec
|
|
3
5
|
include Docker::Base
|
|
@@ -27,7 +29,7 @@ class Docker::Exec
|
|
|
27
29
|
end
|
|
28
30
|
|
|
29
31
|
resp = conn.post("/containers/#{container}/exec", {},
|
|
30
|
-
body:
|
|
32
|
+
body: JSON.generate(options))
|
|
31
33
|
hash = Docker::Util.parse_json(resp) || {}
|
|
32
34
|
new(conn, hash)
|
|
33
35
|
end
|
|
@@ -58,7 +60,7 @@ class Docker::Exec
|
|
|
58
60
|
read_timeout = options[:wait]
|
|
59
61
|
|
|
60
62
|
# Create API Request Body
|
|
61
|
-
body =
|
|
63
|
+
body = JSON.generate(
|
|
62
64
|
'Tty' => tty,
|
|
63
65
|
'Detach' => detached
|
|
64
66
|
)
|
data/lib/docker/image.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# This class represents a Docker Image.
|
|
2
4
|
class Docker::Image
|
|
3
5
|
include Docker::Base
|
|
@@ -28,7 +30,7 @@ class Docker::Image
|
|
|
28
30
|
repo, tag = Docker::Util.parse_repo_tag(repo_tag)
|
|
29
31
|
raise ArgumentError, "Image does not have a name to push." if repo.nil?
|
|
30
32
|
|
|
31
|
-
body = ""
|
|
33
|
+
body = +""
|
|
32
34
|
credentials = creds || Docker.creds || {}
|
|
33
35
|
headers = Docker::Util.build_auth_header(credentials)
|
|
34
36
|
opts = {:tag => tag}.merge(options)
|
|
@@ -117,9 +119,9 @@ class Docker::Image
|
|
|
117
119
|
|
|
118
120
|
# Create a new Image.
|
|
119
121
|
def create(opts = {}, creds = nil, conn = Docker.connection, &block)
|
|
120
|
-
credentials = creds.nil? ? Docker.creds :
|
|
122
|
+
credentials = creds.nil? ? Docker.creds : JSON.generate(creds)
|
|
121
123
|
headers = credentials && Docker::Util.build_auth_header(credentials) || {}
|
|
122
|
-
body = ''
|
|
124
|
+
body = +''
|
|
123
125
|
conn.post(
|
|
124
126
|
'/images/create',
|
|
125
127
|
opts,
|
|
@@ -168,7 +170,7 @@ class Docker::Image
|
|
|
168
170
|
end
|
|
169
171
|
nil
|
|
170
172
|
else
|
|
171
|
-
string = ''
|
|
173
|
+
string = +''
|
|
172
174
|
save_stream(names, {}, conn, &response_block_for_save(string))
|
|
173
175
|
string
|
|
174
176
|
end
|
|
@@ -196,7 +198,7 @@ class Docker::Image
|
|
|
196
198
|
def load(tar, opts = {}, conn = Docker.connection, creds = nil, &block)
|
|
197
199
|
headers = build_headers(creds)
|
|
198
200
|
io = tar.is_a?(String) ? File.open(tar, 'rb') : tar
|
|
199
|
-
body = ""
|
|
201
|
+
body = +""
|
|
200
202
|
conn.post(
|
|
201
203
|
'/images/load',
|
|
202
204
|
opts,
|
|
@@ -267,7 +269,7 @@ class Docker::Image
|
|
|
267
269
|
|
|
268
270
|
# Given a Dockerfile as a string, builds an Image.
|
|
269
271
|
def build(commands, opts = {}, connection = Docker.connection, &block)
|
|
270
|
-
body = ""
|
|
272
|
+
body = +""
|
|
271
273
|
connection.post(
|
|
272
274
|
'/build', opts,
|
|
273
275
|
:body => Docker::Util.create_tar('Dockerfile' => commands),
|
|
@@ -288,7 +290,7 @@ class Docker::Image
|
|
|
288
290
|
headers = build_headers(creds)
|
|
289
291
|
|
|
290
292
|
# The response_block passed to Excon will build up this body variable.
|
|
291
|
-
body = ""
|
|
293
|
+
body = +""
|
|
292
294
|
connection.post(
|
|
293
295
|
'/build', opts,
|
|
294
296
|
:headers => headers,
|
|
@@ -340,7 +342,7 @@ class Docker::Image
|
|
|
340
342
|
# Convience method to get the Dockerfile for a file hash and a path to
|
|
341
343
|
# output to.
|
|
342
344
|
def dockerfile_for(file_hash, output_path)
|
|
343
|
-
dockerfile = "from #{self.id}\n"
|
|
345
|
+
dockerfile = +"from #{self.id}\n"
|
|
344
346
|
|
|
345
347
|
file_hash.keys.each do |basename|
|
|
346
348
|
dockerfile << "add #{basename} #{output_path}\n"
|
data/lib/docker/messages.rb
CHANGED
data/lib/docker/network.rb
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# This class represents a Docker Network.
|
|
2
4
|
class Docker::Network
|
|
3
5
|
include Docker::Base
|
|
4
6
|
|
|
5
7
|
def connect(container, opts = {}, body_opts = {})
|
|
6
|
-
body =
|
|
8
|
+
body = JSON.generate({ container: container }.merge(body_opts))
|
|
7
9
|
Docker::Util.parse_json(
|
|
8
10
|
connection.post(path_for('connect'), opts, body: body)
|
|
9
11
|
)
|
|
@@ -11,7 +13,7 @@ class Docker::Network
|
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
def disconnect(container, opts = {})
|
|
14
|
-
body =
|
|
16
|
+
body = JSON.generate(container: container)
|
|
15
17
|
Docker::Util.parse_json(
|
|
16
18
|
connection.post(path_for('disconnect'), opts, body: body)
|
|
17
19
|
)
|
|
@@ -41,7 +43,7 @@ class Docker::Network
|
|
|
41
43
|
|
|
42
44
|
class << self
|
|
43
45
|
def create(name, opts = {}, conn = Docker.connection)
|
|
44
|
-
default_opts =
|
|
46
|
+
default_opts = JSON.generate({
|
|
45
47
|
'Name' => name,
|
|
46
48
|
'CheckDuplicate' => true
|
|
47
49
|
}.merge(opts))
|
data/lib/docker/rake_task.rb
CHANGED
data/lib/docker/util.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'set'
|
|
2
4
|
|
|
3
5
|
# This module holds shared logic that doesn't really belong anywhere else in the
|
|
@@ -104,8 +106,8 @@ module Docker::Util
|
|
|
104
106
|
end
|
|
105
107
|
|
|
106
108
|
def parse_json(body)
|
|
107
|
-
|
|
108
|
-
rescue
|
|
109
|
+
JSON.parse(body) unless body.nil? || body.empty? || (body == 'null')
|
|
110
|
+
rescue JSON::ParserError => ex
|
|
109
111
|
raise UnexpectedResponseError, ex.message
|
|
110
112
|
end
|
|
111
113
|
|
|
@@ -171,14 +173,25 @@ module Docker::Util
|
|
|
171
173
|
end
|
|
172
174
|
|
|
173
175
|
def create_relative_dir_tar(directory, output)
|
|
176
|
+
root = File.realpath(directory)
|
|
177
|
+
|
|
174
178
|
Gem::Package::TarWriter.new(output) do |tar|
|
|
175
179
|
files = docker_context(directory)
|
|
176
180
|
|
|
177
181
|
files.each do |prefixed_file_name|
|
|
178
|
-
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
|
|
179
191
|
next unless stat.file?
|
|
180
192
|
|
|
181
|
-
|
|
193
|
+
next unless contained?(prefixed_file_name, root)
|
|
194
|
+
|
|
182
195
|
add_file_to_tar(
|
|
183
196
|
tar, unprefixed_file_name, stat.mode, stat.size, stat.mtime
|
|
184
197
|
) do |tar_file|
|
|
@@ -188,6 +201,14 @@ module Docker::Util
|
|
|
188
201
|
end
|
|
189
202
|
end
|
|
190
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
|
+
|
|
191
212
|
def add_file_to_tar(tar, name, mode, size, mtime)
|
|
192
213
|
tar.check_closed
|
|
193
214
|
|
|
@@ -259,7 +280,7 @@ module Docker::Util
|
|
|
259
280
|
end
|
|
260
281
|
|
|
261
282
|
def build_auth_header(credentials)
|
|
262
|
-
credentials =
|
|
283
|
+
credentials = JSON.generate(credentials) if credentials.is_a?(Hash)
|
|
263
284
|
encoded_creds = Base64.urlsafe_encode64(credentials)
|
|
264
285
|
{
|
|
265
286
|
'X-Registry-Auth' => encoded_creds
|
|
@@ -268,10 +289,10 @@ module Docker::Util
|
|
|
268
289
|
|
|
269
290
|
def build_config_header(credentials)
|
|
270
291
|
if credentials.is_a?(String)
|
|
271
|
-
credentials =
|
|
292
|
+
credentials = JSON.parse(credentials, symbolize_names: true)
|
|
272
293
|
end
|
|
273
294
|
|
|
274
|
-
header =
|
|
295
|
+
header = JSON.generate(
|
|
275
296
|
credentials[:serveraddress].to_s => {
|
|
276
297
|
'username' => credentials[:username].to_s,
|
|
277
298
|
'password' => credentials[:password].to_s,
|
data/lib/docker/version.rb
CHANGED
data/lib/docker/volume.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# class represents a Docker Volume
|
|
2
4
|
class Docker::Volume
|
|
3
5
|
include Docker::Base
|
|
@@ -31,7 +33,7 @@ class Docker::Volume
|
|
|
31
33
|
# creates a volume with an arbitrary name
|
|
32
34
|
def create(name, opts = {}, conn = Docker.connection)
|
|
33
35
|
opts['Name'] = name
|
|
34
|
-
resp = conn.post('/volumes/create', {}, body:
|
|
36
|
+
resp = conn.post('/volumes/create', {}, body: JSON.generate(opts))
|
|
35
37
|
hash = Docker::Util.parse_json(resp) || {}
|
|
36
38
|
new(conn, hash)
|
|
37
39
|
end
|
data/lib/docker-api.rb
CHANGED
data/lib/docker.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'cgi'
|
|
2
|
-
require '
|
|
4
|
+
require 'json'
|
|
3
5
|
require 'excon'
|
|
4
6
|
require 'tempfile'
|
|
5
7
|
require 'base64'
|
|
@@ -131,7 +133,7 @@ module Docker
|
|
|
131
133
|
|
|
132
134
|
# Login to the Docker registry.
|
|
133
135
|
def authenticate!(options = {}, connection = self.connection)
|
|
134
|
-
creds =
|
|
136
|
+
creds = JSON.generate(options)
|
|
135
137
|
connection.post('/auth', {}, body: creds)
|
|
136
138
|
@creds = creds
|
|
137
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
|
- - ">="
|
|
@@ -80,20 +80,6 @@ dependencies:
|
|
|
80
80
|
- - ">="
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: '0'
|
|
83
|
-
- !ruby/object:Gem::Dependency
|
|
84
|
-
name: cane
|
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
|
86
|
-
requirements:
|
|
87
|
-
- - ">="
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: '0'
|
|
90
|
-
type: :development
|
|
91
|
-
prerelease: false
|
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
-
requirements:
|
|
94
|
-
- - ">="
|
|
95
|
-
- !ruby/object:Gem::Version
|
|
96
|
-
version: '0'
|
|
97
83
|
- !ruby/object:Gem::Dependency
|
|
98
84
|
name: pry
|
|
99
85
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -178,7 +164,10 @@ files:
|
|
|
178
164
|
homepage: https://github.com/upserve/docker-api
|
|
179
165
|
licenses:
|
|
180
166
|
- MIT
|
|
181
|
-
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'
|
|
182
171
|
post_install_message:
|
|
183
172
|
rdoc_options: []
|
|
184
173
|
require_paths:
|
|
@@ -194,7 +183,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
194
183
|
- !ruby/object:Gem::Version
|
|
195
184
|
version: '0'
|
|
196
185
|
requirements: []
|
|
197
|
-
rubygems_version: 3.
|
|
186
|
+
rubygems_version: 3.2.34
|
|
198
187
|
signing_key:
|
|
199
188
|
specification_version: 4
|
|
200
189
|
summary: A simple REST client for the Docker Remote API
|