docker-api 0.1.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|