docker-api 0.1.0 → 1.0.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.
- data/README.md +21 -48
- data/lib/docker/connection.rb +8 -1
- data/lib/docker/container.rb +11 -12
- data/lib/docker/error.rb +0 -4
- data/lib/docker/image.rb +44 -30
- data/lib/docker/model.rb +30 -40
- data/lib/docker/version.rb +1 -1
- data/spec/docker/connection_spec.rb +3 -2
- data/spec/docker/container_spec.rb +206 -377
- data/spec/docker/image_spec.rb +123 -237
- data/spec/vcr/Docker_Container/_all/when_the_HTTP_response_is_a_200/materializes_each_Container_into_a_Docker_Container.yml +2503 -263
- data/spec/vcr/Docker_Container/_attach/{when_the_Container_has_been_created/when_the_HTTP_response_status_is_200 → when_the_HTTP_response_status_is_200}/yields_each_chunk.yml +30 -22
- data/spec/vcr/Docker_Container/_changes/{when_the_Container_has_been_created/when_the_HTTP_response_status_is_200 → when_the_HTTP_response_status_is_200}/returns_the_changes_as_an_array.yml +41 -33
- data/spec/vcr/Docker_Container/_commit/{when_the_Container_has_been_created/when_the_HTTP_response_status_is_200 → when_the_HTTP_response_status_is_200}/creates_a_new_Image_from_the_Container_s_changes.yml +34 -28
- data/spec/vcr/Docker_Container/{_create_ → _create}/when_the_Container_does_not_yet_exist_and_the_body_is_a_Hash/when_the_HTTP_request_returns_a_200/sets_the_id.yml +11 -9
- data/spec/vcr/Docker_Container/_export/{when_the_Container_has_been_created/when_the_HTTP_response_status_is_200 → when_the_HTTP_response_status_is_200}/yields_each_chunk.yml +43 -29
- data/spec/vcr/Docker_Container/_json/when_the_HTTP_response_status_is_200/returns_the_description_as_a_Hash.yml +63 -0
- data/spec/vcr/Docker_Container/_kill/when_the_HTTP_response_status_is_204/kills_the_container.yml +1358 -0
- data/spec/vcr/Docker_Container/_restart/{when_the_Container_has_been_created/when_the_HTTP_response_status_is_204 → when_the_HTTP_response_status_is_204}/restarts_the_container.yml +73 -59
- data/spec/vcr/Docker_Container/_start/{when_the_Container_has_been_created/when_the_HTTP_response_status_is_200 → when_the_HTTP_response_status_is_200}/starts_the_container.yml +33 -28
- data/spec/vcr/Docker_Container/_stop/when_the_HTTP_response_status_is_204/stops_the_container.yml +1387 -0
- data/spec/vcr/Docker_Container/_wait/{when_the_Container_has_been_created/when_the_HTTP_response_status_is_200 → when_the_HTTP_response_status_is_200}/waits_for_the_command_to_finish.yml +31 -25
- data/spec/vcr/Docker_Image/_all/when_the_HTTP_response_is_a_200/materializes_each_Image_into_a_Docker_Image.yml +6 -6
- data/spec/vcr/Docker_Image/_build/with_a_valid_Dockerfile/builds_an_image.yml +4 -4
- data/spec/vcr/Docker_Image/_build/with_an_invalid_Dockerfile/throws_a_UnexpectedResponseError.yml +4 -4
- data/spec/vcr/Docker_Image/_build_from_dir/with_a_valid_Dockerfile/builds_the_image.yml +14 -14
- data/spec/vcr/Docker_Image/_create/when_the_Image_does_not_yet_exist_and_the_body_is_a_Hash/when_the_HTTP_request_returns_a_200/sets_the_id.yml +33 -0
- data/spec/vcr/Docker_Image/_history/when_the_HTTP_response_status_is_200/returns_the_history_of_the_Image.yml +63 -0
- data/spec/vcr/Docker_Image/_import/when_the_file_does_exist/creates_the_Image.yml +11 -9
- data/spec/vcr/Docker_Image/_insert/when_the_HTTP_response_status_is_200/inserts_the_url_s_file_into_a_new_Image.yml +220 -0
- data/spec/vcr/Docker_Image/_json/when_the_HTTP_response_status_is_200/returns_additional_information_about_image_image.yml +63 -0
- data/spec/vcr/Docker_Image/_remove/when_the_HTTP_response_status_is_204/removes_the_Image.yml +93 -0
- data/spec/vcr/Docker_Image/_remove/when_the_Image_has_been_created/when_the_HTTP_response_status_is_204/removes_the_Image.yml +63 -0
- data/spec/vcr/Docker_Image/_run/when_the_Image_has_been_created/when_the_argument_is_a_String/splits_the_String_by_spaces_and_creates_a_new_Container.yml +119 -0
- data/spec/vcr/Docker_Image/_run/when_the_Image_has_been_created/when_the_argument_is_an_Array/creates_a_new_Container.yml +119 -0
- data/spec/vcr/Docker_Image/_run/when_the_argument_is_a_String/splits_the_String_by_spaces_and_creates_a_new_Container.yml +119 -0
- data/spec/vcr/Docker_Image/_run/when_the_argument_is_an_Array/creates_a_new_Container.yml +119 -0
- data/spec/vcr/Docker_Image/_tag/when_the_HTTP_response_status_is_200/tags_the_image_with_the_repo_name.yml +63 -0
- metadata +46 -29
- data/spec/vcr/Docker_Container/_json/when_the_Container_has_been_created/when_the_HTTP_response_status_is_200/returns_the_description_as_a_Hash.yml +0 -61
- data/spec/vcr/Docker_Container/_kill/when_the_Container_has_been_created/when_the_HTTP_response_status_is_204/kills_the_container.yml +0 -232
- data/spec/vcr/Docker_Container/_stop/when_the_Container_has_been_created/when_the_HTTP_response_status_is_204/stops_the_container.yml +0 -259
data/README.md
CHANGED
@@ -70,27 +70,16 @@ Docker.authenticate!('username' => 'docker-fan-boi', 'password' => 'i<3docker',
|
|
70
70
|
```
|
71
71
|
|
72
72
|
## Images
|
73
|
-
Just about every method here has a one-to-one mapping with the [Images](http://docs.docker.io/en/latest/api/docker_remote_api_v1.2/#images) section of the API. If an API call accepts query parameters, these can be passed as an Hash to it's corresponding method.
|
73
|
+
Just about every method here has a one-to-one mapping with the [Images](http://docs.docker.io/en/latest/api/docker_remote_api_v1.2/#images) 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`, or `.import` to make an instance.
|
74
74
|
|
75
75
|
```ruby
|
76
76
|
require 'docker'
|
77
77
|
# => true
|
78
78
|
|
79
|
-
#
|
80
|
-
|
81
|
-
# => Docker::Image { :id => , :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }
|
82
|
-
|
83
|
-
# Test if the Image is created.
|
84
|
-
image.created?
|
85
|
-
# => false
|
86
|
-
|
87
|
-
# Create the Image.
|
88
|
-
image.create!('fromRepo' => 'base')
|
79
|
+
# Create an Image.
|
80
|
+
Docker::Image.create('fromRepo' => 'base')
|
89
81
|
# => Docker::Image { :id => ae7ffbcd1, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }
|
90
82
|
|
91
|
-
image.created?
|
92
|
-
# => true
|
93
|
-
|
94
83
|
# Insert a file into an Image. Returns a new Image that contains that file.
|
95
84
|
image.insert('path' => '/google', 'url' => 'http://google.com')
|
96
85
|
# => Docker::Image { :id => 11ef6c882, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }
|
@@ -112,25 +101,18 @@ image.history
|
|
112
101
|
image.push
|
113
102
|
# => true
|
114
103
|
|
104
|
+
# Given a command, create a new Container to run that command in the Image.
|
105
|
+
image.run('ls -l')
|
106
|
+
# => Docker::Container { id => aaef712eda, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }
|
107
|
+
|
115
108
|
# Remove the Image from the server.
|
116
109
|
image.remove
|
117
110
|
# => true
|
118
111
|
|
119
|
-
image.created?
|
120
|
-
# => false
|
121
|
-
|
122
112
|
# Given a Container's export, creates a new Image.
|
123
|
-
|
113
|
+
Docker::Image.import('some-export.tar')
|
124
114
|
# => Docker::Image { :id => 66b712aef, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }
|
125
115
|
|
126
|
-
# Load all Images on your Docker server.
|
127
|
-
Docker::Image.all
|
128
|
-
# => [Docker::Image { :id => b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => 8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }]
|
129
|
-
|
130
|
-
# Search the Docker registry.
|
131
|
-
Docker::Image.search('term' => 'sshd')
|
132
|
-
# => [Docker::Image { :id => cespare/sshd, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => johnfuller/sshd, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => dhrp/mongodb-sshd, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => rayang2004/sshd, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => dhrp/sshd, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => toorop/daemontools-sshd, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => toorop/daemontools-sshd-nginx, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => toorop/daemontools-sshd-nginx-php-fpm, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => mbkan/lamp, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => toorop/golang, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => wma55/u1210sshd, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => jdswinbank/sshd, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => vgauthier/sshd, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }]
|
133
|
-
|
134
116
|
# Create an Image from a Dockerfile as a String.
|
135
117
|
Docker::Image.build("from base\nrun touch /test")
|
136
118
|
# => Docker::Image { :id => b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }
|
@@ -138,29 +120,26 @@ Docker::Image.build("from base\nrun touch /test")
|
|
138
120
|
# Create an Image from a Dockerfile.
|
139
121
|
Dockerfile::Image.build_from_dir('.')
|
140
122
|
# => Docker::Image { :id => 1266dc19e, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }
|
123
|
+
|
124
|
+
# Load all Images on your Docker server.
|
125
|
+
Docker::Image.all
|
126
|
+
# => [Docker::Image { :id => b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => 8dbd9e392a964056420e5d58ca5cc376ef18e2de93b5cc90e868a1bbc8318c1c, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }]
|
127
|
+
|
128
|
+
# Search the Docker registry.
|
129
|
+
Docker::Image.search('term' => 'sshd')
|
130
|
+
# => [Docker::Image { :id => cespare/sshd, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => johnfuller/sshd, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => dhrp/mongodb-sshd, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => rayang2004/sshd, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => dhrp/sshd, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => toorop/daemontools-sshd, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => toorop/daemontools-sshd-nginx, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => toorop/daemontools-sshd-nginx-php-fpm, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => mbkan/lamp, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => toorop/golang, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => wma55/u1210sshd, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => jdswinbank/sshd, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }, Docker::Image { :id => vgauthier/sshd, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }]
|
141
131
|
```
|
142
132
|
|
143
133
|
## Containers
|
144
|
-
Much like the Images, this object also has a one-to-one mapping with the [Containers](http://docs.docker.io/en/latest/api/docker_remote_api_v1.2/#containers) section of the API.
|
134
|
+
Much like the Images, this object also has a one-to-one mapping with the [Containers](http://docs.docker.io/en/latest/api/docker_remote_api_v1.2/#containers) section of the API. Also like Images, `.new` is a private method, so you must use `.create` to make an instance.
|
145
135
|
|
146
136
|
```ruby
|
147
137
|
require 'docker'
|
148
138
|
|
149
|
-
#
|
150
|
-
|
151
|
-
# => Docker::Container { :id => , :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }
|
152
|
-
|
153
|
-
# Test if the has been created.
|
154
|
-
container.created?
|
155
|
-
# => false
|
156
|
-
|
157
|
-
# Create the Container.
|
158
|
-
container.create!('Cmd' => ['ls'], 'Image' => 'base')
|
139
|
+
# Create a Container.
|
140
|
+
Docker::Container.create('Cmd' => ['ls'], 'Image' => 'base')
|
159
141
|
# => Docker::Container { :id => 492510dd38e4, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }
|
160
142
|
|
161
|
-
container.created?
|
162
|
-
# => true
|
163
|
-
|
164
143
|
# Get more information about the Container.
|
165
144
|
container.json
|
166
145
|
# => {"Id"=>"492510dd38e4da7703f36dfccd013de672b8250f57f59d1555ced647766b5e82", "Created"=>"2013-06-20T10:46:02.897548-04:00", "Path"=>"ls", "Args"=>[], "Config"=>{"Hostname"=>"492510dd38e4", "User"=>"", "Memory"=>0, "MemorySwap"=>0, "CpuShares"=>0, "AttachStdin"=>false, "AttachStdout"=>false, "AttachStderr"=>false, "PortSpecs"=>nil, "Tty"=>false, "OpenStdin"=>false, "StdinOnce"=>false, "Env"=>nil, "Cmd"=>["ls"], "Dns"=>nil, "Image"=>"base", "Volumes"=>nil, "VolumesFrom"=>""}, "State"=>{"Running"=>false, "Pid"=>0, "ExitCode"=>0, "StartedAt"=>"0001-01-01T00:00:00Z", "Ghost"=>false}, "Image"=>"b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc", "NetworkSettings"=>{"IpAddress"=>"", "IpPrefixLen"=>0, "Gateway"=>"", "Bridge"=>"", "PortMapping"=>nil}, "SysInitPath"=>"/usr/bin/docker", "ResolvConfPath"=>"/etc/resolv.conf", "Volumes"=>nil}
|
@@ -197,6 +176,7 @@ container.wait
|
|
197
176
|
# => {'StatusCode'=>0}
|
198
177
|
|
199
178
|
# Attach to the Container. Currently, the below options are the only valid ones.
|
179
|
+
# By default, :stream and :stdout are set.
|
200
180
|
container.attach(:stream => true, :stdout => true, :stderr => true, :logs => true)
|
201
181
|
# => "bin\nboot\ndev\netc\nhome\nlib\nlib64\nmedia\nmnt\nopt\nproc\nroot\nrun\nsbin\nselinux\nsrv\nsys\ntmp\nusr\nvar"
|
202
182
|
|
@@ -211,19 +191,12 @@ Docker::Container.all(:all => true)
|
|
211
191
|
|
212
192
|
## Connecting to Multiple Servers
|
213
193
|
|
214
|
-
By default, each object connects to the connection specified by `Docker.connection`. If you need to connect to multiple servers, you can do so by specifying the connection on `#new` or in the utilizing class method.
|
194
|
+
By default, each object connects to the connection specified by `Docker.connection`. If you need to connect to multiple servers, you can do so by specifying the connection on `#new` or in the utilizing class method. For example:
|
215
195
|
|
216
196
|
```ruby
|
217
197
|
require 'docker'
|
218
198
|
|
219
|
-
Docker::Container.new(:connection => Docker::Connection.new(:url => 'http://example.com'))
|
220
199
|
Docker::Container.all({}, Docker::Connection.new(:url => 'http://example.com'))
|
221
|
-
|
222
|
-
Docker::Image.new(:connection => Docker::Connection.new(:url => 'http://example.com'))
|
223
|
-
Docker::Image.all({}, Docker::Connection.new(:url => 'http://example.com'))
|
224
|
-
Docker::Image.build('from base', Docker::Connection.new(:url => 'http://example.com'))
|
225
|
-
Docker::Image.build_from_dir('.', Docker::Connection.new(:url => 'http://example.com'))
|
226
|
-
Docker::Image.search({ :term => 'sshd' }, Docker::Connection.new(:url => 'http://example.com'))
|
227
200
|
```
|
228
201
|
|
229
202
|
## Known Issues
|
data/lib/docker/connection.rb
CHANGED
@@ -20,10 +20,17 @@ class Docker::Connection
|
|
20
20
|
@resource ||= Excon.new(self.url, self.options)
|
21
21
|
end
|
22
22
|
|
23
|
+
# Nil out the connection. This now happens on every request to prevent socket
|
24
|
+
# errors.
|
25
|
+
def reset!
|
26
|
+
@resource = nil
|
27
|
+
end
|
28
|
+
|
23
29
|
# Delegate all HTTP methods to the resource.
|
24
30
|
[:get, :put, :post, :delete, :request].each do |method|
|
25
31
|
define_method(method) do |*args, &block|
|
26
32
|
begin
|
33
|
+
self.reset!
|
27
34
|
self.resource.public_send(method, *args, &block)
|
28
35
|
rescue Excon::Errors::BadRequest => ex
|
29
36
|
raise ClientError, ex.message
|
@@ -37,7 +44,7 @@ class Docker::Connection
|
|
37
44
|
def json_request(method, path, query = {}, &block)
|
38
45
|
params = compile_request_params(method, path, query, &block)
|
39
46
|
body = self.request(params).body
|
40
|
-
JSON.parse(body) unless
|
47
|
+
JSON.parse(body) unless body.nil? || body.empty? || (body == 'null')
|
41
48
|
rescue JSON::ParserError => ex
|
42
49
|
raise UnexpectedResponseError, ex.message
|
43
50
|
end
|
data/lib/docker/container.rb
CHANGED
@@ -13,30 +13,30 @@ class Docker::Container
|
|
13
13
|
:body => body.to_json,
|
14
14
|
:expects => (200..204)
|
15
15
|
)
|
16
|
-
|
16
|
+
@id = JSON.parse(response.body)['Id']
|
17
17
|
self
|
18
18
|
end
|
19
19
|
|
20
20
|
# Export the Container as a .tgz.
|
21
|
-
|
21
|
+
get :export
|
22
22
|
# Get more information about the Container.
|
23
|
-
|
23
|
+
get :json
|
24
24
|
# Wait for the current command to finish executing.
|
25
|
-
|
25
|
+
post :wait
|
26
26
|
# Start the Container.
|
27
|
-
|
27
|
+
post :start
|
28
28
|
# Inspect the Container's changes to the filesysetem
|
29
|
-
|
29
|
+
get :changes
|
30
30
|
# Stop the Container.
|
31
|
-
|
31
|
+
post :stop
|
32
32
|
# Kill the Container.
|
33
|
-
|
33
|
+
post :kill
|
34
34
|
# Restart the Container
|
35
|
-
|
35
|
+
post :restart
|
36
36
|
|
37
37
|
# Attach to a container's standard streams / logs.
|
38
38
|
def attach(options = {})
|
39
|
-
|
39
|
+
options = { :stream => true, :stdout => true }.merge(options)
|
40
40
|
self.connection.post(
|
41
41
|
:path => "/containers/#{self.id}/attach",
|
42
42
|
:headers => { 'Content-Type' => 'text/plain',
|
@@ -48,9 +48,8 @@ class Docker::Container
|
|
48
48
|
|
49
49
|
# Create an Image from a Container's change.s
|
50
50
|
def commit(options = {})
|
51
|
-
ensure_created!
|
52
51
|
options.merge!('container' => self.id[0..7])
|
53
52
|
hash = self.connection.json_request(:post, '/commit', options)
|
54
|
-
Docker::Image.
|
53
|
+
Docker::Image.send(:new, :id => hash['Id'], :connection => self.connection)
|
55
54
|
end
|
56
55
|
end
|
data/lib/docker/error.rb
CHANGED
@@ -8,10 +8,6 @@ module Docker::Error
|
|
8
8
|
# Raised when invalid arguments are passed to a method.
|
9
9
|
class ArgumentError < DockerError; end
|
10
10
|
|
11
|
-
# Raised when a method requires a Model to be in a certain state (typically
|
12
|
-
# created or not created), but the Model is not in that state.
|
13
|
-
class StateError < DockerError; end
|
14
|
-
|
15
11
|
# Raised when a request returns a 400.
|
16
12
|
class ClientError < DockerError; end
|
17
13
|
|
data/lib/docker/image.rb
CHANGED
@@ -5,13 +5,13 @@ class Docker::Image
|
|
5
5
|
|
6
6
|
resource_prefix '/images'
|
7
7
|
|
8
|
-
create_request do |options
|
9
|
-
body = self.connection.post(
|
10
|
-
:path => '/
|
8
|
+
create_request do |options|
|
9
|
+
body = self.connection.post(
|
10
|
+
:path => '/images/create',
|
11
11
|
:headers => { 'User-Agent' => 'Docker-Client/0.4.6' },
|
12
12
|
:query => options,
|
13
13
|
:expects => (200..204)
|
14
|
-
)
|
14
|
+
).body
|
15
15
|
@id = JSON.parse(body)['status'] rescue nil
|
16
16
|
@id ||= options['fromImage']
|
17
17
|
@id ||= "#{options['repo']}/#{options['tag']}"
|
@@ -19,15 +19,24 @@ class Docker::Image
|
|
19
19
|
end
|
20
20
|
|
21
21
|
# Tag the Image.
|
22
|
-
|
22
|
+
post :tag
|
23
23
|
# Get more information about the Image.
|
24
|
-
|
24
|
+
get :json
|
25
25
|
# Get the history of the Image.
|
26
|
-
|
26
|
+
get :history
|
27
|
+
|
28
|
+
# Given a command and optional list of streams to attach to, run a command on
|
29
|
+
# an Image. This will not modify the Image, but rather create a new Container
|
30
|
+
# to run the Image.
|
31
|
+
def run(cmd)
|
32
|
+
cmd = cmd.split(/\s+/) if cmd.is_a?(String)
|
33
|
+
Docker::Container.create({ 'Image' => self.id, 'Cmd' => cmd },
|
34
|
+
self.connection)
|
35
|
+
.tap(&:start)
|
36
|
+
end
|
27
37
|
|
28
38
|
# Push the Image to the Docker registry.
|
29
39
|
def push(options = {})
|
30
|
-
ensure_created!
|
31
40
|
self.connection.post(
|
32
41
|
:path => "/images/#{self.id}/push",
|
33
42
|
:headers => { 'Content-Type' => 'text/plain',
|
@@ -41,7 +50,6 @@ class Docker::Image
|
|
41
50
|
|
42
51
|
# Insert a file into the Image, returns a new Image that has that file.
|
43
52
|
def insert(query = {})
|
44
|
-
ensure_created!
|
45
53
|
body = self.connection.post(
|
46
54
|
:path => "/images/#{self.id}/insert",
|
47
55
|
:headers => { 'Content-Type' => 'text/plain',
|
@@ -52,16 +60,13 @@ class Docker::Image
|
|
52
60
|
if (id = body.match(/{"Id":"([a-f0-9]+)"}\z/)).nil? || id[1].empty?
|
53
61
|
raise UnexpectedResponseError, "Could not find Id in '#{body}'"
|
54
62
|
else
|
55
|
-
|
63
|
+
self.class.send(:new, :id => id[1], :connection => self.connection)
|
56
64
|
end
|
57
65
|
end
|
58
66
|
|
59
67
|
# Remove the Image from the server.
|
60
68
|
def remove
|
61
|
-
ensure_created!
|
62
69
|
self.connection.json_request(:delete, "/images/#{self.id}", nil)
|
63
|
-
self.id = nil
|
64
|
-
true
|
65
70
|
end
|
66
71
|
|
67
72
|
class << self
|
@@ -74,46 +79,51 @@ class Docker::Image
|
|
74
79
|
hashes.map { |hash| new(:id => hash['Name'], :connection => connection) }
|
75
80
|
end
|
76
81
|
|
82
|
+
# Import an Image from the output of Docker::Container#export.
|
77
83
|
def import(file, options = {}, connection = Docker.connection)
|
78
84
|
File.open(file, 'r') do |io|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
85
|
+
body = connection.post(
|
86
|
+
:path => '/images/create',
|
87
|
+
:headers => { 'User-Agent' => 'Docker-Client/0.4.6',
|
88
|
+
'Transfer-Encoding' => 'chunked' },
|
89
|
+
:query => options.merge('fromSrc' => '-'),
|
90
|
+
:request_block => proc { io.read(Excon.defaults[:chunk_size]).to_s },
|
91
|
+
:expects => (200..204)
|
92
|
+
).body
|
93
|
+
new(:id => JSON.parse(body)['status'], :connection => connection)
|
83
94
|
end
|
84
95
|
end
|
85
96
|
|
86
97
|
# Given a Dockerfile as a string, builds an Image.
|
87
98
|
def build(commands, connection = Docker.connection)
|
88
99
|
body = connection.post(
|
89
|
-
:path => '/
|
100
|
+
:path => '/build',
|
90
101
|
:body => create_tar(commands),
|
91
102
|
:expects => (200..204)
|
92
103
|
).body
|
93
104
|
new(:id => extract_id(body), :connection => connection)
|
94
105
|
end
|
95
106
|
|
107
|
+
# Given a directory that contains a Dockerfile, builds an Image.
|
96
108
|
def build_from_dir(dir, connection = Docker.connection)
|
97
|
-
|
98
|
-
FileUtils.cd(dir)
|
99
|
-
tar = create_dir_tar('.')
|
109
|
+
tar = create_dir_tar(dir)
|
100
110
|
body = connection.post(
|
101
|
-
:path
|
102
|
-
:headers
|
103
|
-
|
111
|
+
:path => '/build',
|
112
|
+
:headers => { 'Content-Type' => 'application/tar',
|
113
|
+
'Transfer-Encoding' => 'chunked' },
|
104
114
|
:request_block => proc { tar.read(Excon.defaults[:chunk_size]).to_s },
|
105
|
-
:expects
|
115
|
+
:expects => (200..204),
|
106
116
|
).body
|
107
117
|
new(:id => extract_id(body), :connection => connection)
|
108
118
|
ensure
|
109
119
|
tar.close
|
110
|
-
FileUtils.cd(cwd)
|
111
120
|
end
|
112
121
|
|
113
122
|
private
|
114
123
|
def extract_id(body)
|
115
|
-
|
116
|
-
|
124
|
+
line = body.lines.to_a[-1]
|
125
|
+
if (id = line.match(/^Successfully built ([a-f0-9]+)$/)) && !id[1].empty?
|
126
|
+
id[1]
|
117
127
|
else
|
118
128
|
raise UnexpectedResponseError, "Couldn't find id: #{body}"
|
119
129
|
end
|
@@ -129,16 +139,20 @@ class Docker::Image
|
|
129
139
|
file = File.new('Dockerfile', 'w')
|
130
140
|
file.write(input)
|
131
141
|
file.close
|
132
|
-
Archive::Tar::Minitar.pack_file("
|
142
|
+
Archive::Tar::Minitar.pack_file("Dockerfile", tar)
|
133
143
|
FileUtils.cd(cwd)
|
134
144
|
FileUtils.rm_rf(path)
|
135
145
|
string.tap(&:rewind)
|
136
146
|
end
|
137
147
|
|
138
148
|
def create_dir_tar(directory)
|
149
|
+
cwd = FileUtils.pwd
|
139
150
|
tempfile = File.new('/tmp/out', 'w')
|
140
|
-
|
151
|
+
FileUtils.cd(directory)
|
152
|
+
Archive::Tar::Minitar.pack('.', tempfile)
|
141
153
|
File.new('/tmp/out', 'r')
|
154
|
+
ensure
|
155
|
+
FileUtils.cd(cwd)
|
142
156
|
end
|
143
157
|
end
|
144
158
|
end
|
data/lib/docker/model.rb
CHANGED
@@ -1,10 +1,16 @@
|
|
1
1
|
# This module is intended to be used as a Mixin for all objects exposed by the
|
2
2
|
# Remote API. Currently, these are limited to Containers and Images.
|
3
3
|
module Docker::Model
|
4
|
+
include Docker::Error
|
5
|
+
|
4
6
|
attr_reader :id, :connection
|
5
7
|
|
6
8
|
def self.included(base)
|
7
|
-
base.
|
9
|
+
base.class_eval do
|
10
|
+
extend ClassMethods
|
11
|
+
private_class_method :new, :request, :get, :put, :post, :delete,
|
12
|
+
:create_request, :resource_prefix
|
13
|
+
end
|
8
14
|
end
|
9
15
|
|
10
16
|
# Creates a new Model with the specified id and Connection. If a Connection
|
@@ -12,39 +18,22 @@ module Docker::Model
|
|
12
18
|
# Docker::Error::ArgumentError is raised.
|
13
19
|
def initialize(options = {})
|
14
20
|
options[:connection] ||= Docker.connection
|
15
|
-
|
16
|
-
raise
|
17
|
-
end
|
18
|
-
self.id = options[:id]
|
19
|
-
self.connection = options[:connection]
|
20
|
-
end
|
21
|
-
|
22
|
-
# Create a Model with the specified body. Raises A Docker::Error::StateError
|
23
|
-
# if the model already exists, and a Docker::Error::ArgumentError if the
|
24
|
-
# argument is not a Hash. Otherwise, instances exec the Class's
|
25
|
-
# #create_request method with the single argument.
|
26
|
-
def create!(options = {}, excon_options = {})
|
27
|
-
case
|
28
|
-
when self.created?
|
29
|
-
raise Docker::Error::StateError, "This #{self.class.name} already exists!"
|
30
|
-
when !options.is_a?(Hash)
|
31
|
-
raise Docker::Error::ArgumentError, 'Expected a Hash'
|
21
|
+
if !options[:connection].is_a?(Docker::Connection)
|
22
|
+
raise ArgumentError, 'Expected a Docker::Connection.'
|
32
23
|
else
|
33
|
-
|
24
|
+
@id = options[:id]
|
25
|
+
@connection = options[:connection]
|
34
26
|
end
|
35
27
|
end
|
36
28
|
|
37
|
-
# Returns true if the Container has been created, false otherwise.
|
38
|
-
def created?
|
39
|
-
!!self.id
|
40
|
-
end
|
41
|
-
|
42
29
|
def to_s
|
43
30
|
"#{self.class.name} { :id => #{id}, :connection => #{connection} }"
|
44
31
|
end
|
45
32
|
|
46
33
|
# This defines the DSL for the including Classes.
|
47
34
|
module ClassMethods
|
35
|
+
include Docker::Error
|
36
|
+
|
48
37
|
# Define the Model's prefix for all requests.
|
49
38
|
def resource_prefix(val = nil)
|
50
39
|
val.nil? ? @resource_prefix : (@resource_prefix = val)
|
@@ -57,32 +46,33 @@ module Docker::Model
|
|
57
46
|
|
58
47
|
# Define a method named `action` that sends an http `method` request to the
|
59
48
|
# Docker Server.
|
60
|
-
def
|
49
|
+
def request(method, action, opts = {}, &outer_block)
|
61
50
|
define_method(action) do |query = nil, &block|
|
62
|
-
|
63
|
-
path
|
51
|
+
path = opts[:path]
|
52
|
+
path ||= "#{self.class.send(:resource_prefix)}/#{self.id}/#{action}"
|
64
53
|
body = self.connection.json_request(method, path, query, &block)
|
65
54
|
outer_block.nil? ? body : instance_exec(body, &outer_block)
|
66
55
|
end
|
67
56
|
end
|
68
57
|
|
58
|
+
[:get, :put, :post, :delete].each do |method|
|
59
|
+
define_method(method) { |*args, &block| request(method, *args, &block) }
|
60
|
+
end
|
61
|
+
|
62
|
+
# Create a Model with the specified body. Raises a
|
63
|
+
# Docker::Error::ArgumentError if the argument is not a Hash. Otherwise,
|
64
|
+
# instances execs the Class's #create_request method with the single
|
65
|
+
# argument.
|
66
|
+
def create(opts = {}, conn = Docker.connection)
|
67
|
+
raise Docker::Error::ArgumentError, 'Expected a Hash' if !opts.is_a?(Hash)
|
68
|
+
new(:connection => conn).instance_exec(opts, &create_request)
|
69
|
+
end
|
70
|
+
|
69
71
|
# Retrieve every Instance of a model for the given server.
|
70
72
|
def all(options = {}, connection = Docker.connection)
|
71
|
-
path = "#{
|
73
|
+
path = "#{resource_prefix}/json"
|
72
74
|
hashes = connection.json_request(:get, path, options) || []
|
73
75
|
hashes.map { |hash| new(:id => hash['Id'], :connection => connection) }
|
74
76
|
end
|
75
|
-
|
76
|
-
private
|
77
|
-
end
|
78
|
-
|
79
|
-
private
|
80
|
-
attr_writer :id, :connection
|
81
|
-
|
82
|
-
# Raises an error unless the Model is created.
|
83
|
-
def ensure_created!
|
84
|
-
unless created?
|
85
|
-
raise Docker::Error::StateError, "This #{self.class.name} is not created."
|
86
|
-
end
|
87
77
|
end
|
88
78
|
end
|