docker-api 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.cane +0 -0
- data/.gitignore +3 -0
- data/Gemfile +3 -0
- data/README.md +215 -0
- data/Rakefile +16 -0
- data/docker-api.gemspec +27 -0
- data/lib/docker.rb +60 -0
- data/lib/docker/connection.rb +65 -0
- data/lib/docker/container.rb +54 -0
- data/lib/docker/error.rb +23 -0
- data/lib/docker/image.rb +73 -0
- data/lib/docker/model.rb +88 -0
- data/lib/docker/multipart.rb +30 -0
- data/lib/docker/version.rb +3 -0
- data/spec/docker/connection_spec.rb +67 -0
- data/spec/docker/container_spec.rb +529 -0
- data/spec/docker/image_spec.rb +379 -0
- data/spec/docker_spec.rb +58 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/support/vcr.rb +11 -0
- data/spec/vcr/Docker/_info/returns_the_info_as_a_Hash.yml +31 -0
- data/spec/vcr/Docker/_version/returns_the_version_as_a_Hash.yml +31 -0
- data/spec/vcr/Docker_Container/_all/when_the_HTTP_response_is_a_200/materializes_each_Container_into_a_Docker_Container.yml +333 -0
- data/spec/vcr/Docker_Container/_attach/when_the_Container_has_been_created/when_the_HTTP_response_status_is_200/yields_each_chunk.yml +81 -0
- data/spec/vcr/Docker_Container/_changes/when_the_Container_has_been_created/when_the_HTTP_response_status_is_200/returns_the_changes_as_an_array.yml +115 -0
- data/spec/vcr/Docker_Container/_commit/when_the_Container_has_been_created/when_the_HTTP_response_status_is_200/creates_a_new_Image_from_the_Container_s_changes.yml +87 -0
- data/spec/vcr/Docker_Container/_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 +31 -0
- data/spec/vcr/Docker_Container/_export/when_the_Container_has_been_created/when_the_HTTP_response_status_is_200/yields_each_chunk.yml +97 -0
- 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 +59 -0
- data/spec/vcr/Docker_Container/_kill/when_the_Container_has_been_created/when_the_HTTP_response_status_is_204/kills_the_container.yml +232 -0
- data/spec/vcr/Docker_Container/_restart/when_the_Container_has_been_created/when_the_HTTP_response_status_is_204/restarts_the_container.yml +201 -0
- data/spec/vcr/Docker_Container/_start/when_the_Container_has_been_created/when_the_HTTP_response_status_is_200/starts_the_container.yml +89 -0
- data/spec/vcr/Docker_Container/_stop/when_the_Container_has_been_created/when_the_HTTP_response_status_is_204/stops_the_container.yml +259 -0
- data/spec/vcr/Docker_Container/_wait/when_the_Container_has_been_created/when_the_HTTP_response_status_is_200/waits_for_the_command_to_finish.yml +87 -0
- data/spec/vcr/Docker_Image/_all/when_the_HTTP_response_is_a_200/materializes_each_Container_into_a_Docker_Container.yml +59 -0
- data/spec/vcr/Docker_Image/_build/with_a_valid_Dockerfile/builds_an_image.yml +45 -0
- data/spec/vcr/Docker_Image/_build/with_an_invalid_Dockerfile/throws_a_UnexpectedResponseError.yml +38 -0
- 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 +31 -0
- data/spec/vcr/Docker_Image/_history/when_the_Image_has_been_created/when_the_HTTP_response_status_is_200/returns_the_history_of_the_Image.yml +59 -0
- data/spec/vcr/Docker_Image/_insert/when_the_Image_has_been_created/when_the_HTTP_response_status_is_200/inserts_the_file.yml +59 -0
- data/spec/vcr/Docker_Image/_json/when_the_Image_has_been_created/when_the_HTTP_response_status_is_200/returns_additional_information_about_image_image.yml +60 -0
- data/spec/vcr/Docker_Image/_remove/when_the_Image_has_been_created/when_the_HTTP_response_status_is_204/nils_out_the_id.yml +59 -0
- data/spec/vcr/Docker_Image/_search/when_the_HTTP_response_is_a_200/materializes_each_Container_into_a_Docker_Container.yml +64 -0
- data/spec/vcr/Docker_Image/_tag/when_the_Image_has_been_created/when_the_HTTP_response_status_is_200/tags_the_image_with_the_repo_name.yml +59 -0
- metadata +281 -0
data/.cane
ADDED
File without changes
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,215 @@
|
|
1
|
+
docker-api
|
2
|
+
==========
|
3
|
+
|
4
|
+
This gem provides an object-oriented interface to the [Docker Remote API](http://docs.docker.io/en/latest/api/docker_remote_api_v1.2/). Every method listed there is implemented, with the exception of attaching to the STDIN of a Container. At the time of this writing, docker-api is meant to interface with Docker version 0.4.0.
|
5
|
+
|
6
|
+
Installation
|
7
|
+
------------
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'docker-api'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then run:
|
16
|
+
|
17
|
+
```shell
|
18
|
+
$ bundle install
|
19
|
+
```
|
20
|
+
|
21
|
+
Alternatively, if you wish to just use the gem in a script, you can run:
|
22
|
+
|
23
|
+
```shell
|
24
|
+
$ gem install docker-api
|
25
|
+
```
|
26
|
+
|
27
|
+
Finally, just add `require 'docker'` to the top of the file using this gem.
|
28
|
+
|
29
|
+
Usage
|
30
|
+
-----
|
31
|
+
|
32
|
+
docker-api is designed to be very lightweight. Almost no state is cached (aside from id's which are immutable) to ensure that each method call's information is up to date. As such, just about every extrenal method represents an API call.
|
33
|
+
|
34
|
+
## Starting up
|
35
|
+
|
36
|
+
Follow the [installation instructions](http://www.docker.io/gettingstarted/), and then run:
|
37
|
+
|
38
|
+
```shell
|
39
|
+
$ sudo docker -d
|
40
|
+
```
|
41
|
+
|
42
|
+
This will daemonize Docker so that it can be used for the remote API calls.
|
43
|
+
|
44
|
+
If you're running Docker locally, there is no setup to do in Ruby. If you're not, you'll have to point the gem to your server. For example:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
Docker.url = 'http://example.com'
|
48
|
+
Docker.options = { :port => 5422 }
|
49
|
+
```
|
50
|
+
|
51
|
+
Two things to note here. The first is that this gem uses [excon](http://www.github.com/geemus/excon), so any of the options that are valid for `Excon.new` are alse valid for `Docker.options`. Second, by default Docker runs on port 4243. The gem will assume you want to connnect to port 4243 unless you specify otherwise.
|
52
|
+
|
53
|
+
## Global calls
|
54
|
+
|
55
|
+
All of the following examples require a connection to a Docker server. See the <a href="#starting-up">Starting up</a> section above for more information.
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
require 'docker'
|
59
|
+
# => true
|
60
|
+
|
61
|
+
Docker.version
|
62
|
+
# => { 'Version' => '0.4.0', 'GoVersion' => 'go1.0.3' }
|
63
|
+
|
64
|
+
Docker.info
|
65
|
+
# => { "Debug" => false, "Containers" => 187, "Images" => 196, "NFd" => 10, "NGoroutines" => 9, "MemoryLimit" => true }
|
66
|
+
|
67
|
+
Docker.authenticate!('username' => 'docker-fan-boi', 'password' => 'i<3docker', 'email' => 'dockerboy22@aol.com')
|
68
|
+
# => true
|
69
|
+
```
|
70
|
+
|
71
|
+
## Images
|
72
|
+
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
|
+
|
74
|
+
```ruby
|
75
|
+
require 'docker'
|
76
|
+
# => true
|
77
|
+
|
78
|
+
# Instantiate a new Image. Note that this does NOT create the Image.
|
79
|
+
image = Docker::Image.new
|
80
|
+
# => Docker::Image { :id => , :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }
|
81
|
+
|
82
|
+
# Test if the Image is created.
|
83
|
+
image.created?
|
84
|
+
# => false
|
85
|
+
|
86
|
+
# Create the Image.
|
87
|
+
image.create!('fromRepo' => 'base', 'fromSrc' => '-')
|
88
|
+
# => Docker::Image { :id => ae7ffbcd1, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }
|
89
|
+
|
90
|
+
image.created?
|
91
|
+
# => true
|
92
|
+
|
93
|
+
# Insert a file into an Image.
|
94
|
+
image.insert('path' => '/usr', 'url' => '/home/user/.vimrc')
|
95
|
+
# => { 'Id' => '' }
|
96
|
+
|
97
|
+
# Tag an Image.
|
98
|
+
image.tag('repo' => 'base2', 'force' => true)
|
99
|
+
# => nil
|
100
|
+
|
101
|
+
# Get more information about the Image.
|
102
|
+
image.json
|
103
|
+
# => {"id"=>"67859327bf22ef8b5b9b4a6781f72b2015acd894fa03ce07e0db7af170ba468c", "comment"=>"Imported from -", "created"=>"2013-06-19T18:42:58.287944526-04:00", "container_config"=>{"Hostname"=>"", "User"=>"", "Memory"=>0, "MemorySwap"=>0, "CpuShares"=>0, "AttachStdin"=>false, "AttachStdout"=>false, "AttachStderr"=>false, "PortSpecs"=>nil, "Tty"=>false, "OpenStdin"=>false, "StdinOnce"=>false, "Env"=>nil, "Cmd"=>nil, "Dns"=>nil, "Image"=>"", "Volumes"=>nil, "VolumesFrom"=>""}, "docker_version"=>"0.4.0", "architecture"=>"x86_64"}
|
104
|
+
|
105
|
+
# View the history of the Image.
|
106
|
+
image.history
|
107
|
+
# => [{"Id"=>"67859327bf22", "Created"=>1371681778}]
|
108
|
+
|
109
|
+
# Remove the Image from the server.
|
110
|
+
image.remove
|
111
|
+
# => true
|
112
|
+
|
113
|
+
image.created?
|
114
|
+
# => false
|
115
|
+
|
116
|
+
# Load all Images on your Docker server.
|
117
|
+
Docker::Image.all
|
118
|
+
# => [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} } }]
|
119
|
+
|
120
|
+
# Search the Docker registry.
|
121
|
+
Docker::Image.search('term' => 'sshd')
|
122
|
+
# => [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} } }]
|
123
|
+
|
124
|
+
# Create an Image from a Dockerfile.
|
125
|
+
Docker::Image.build("from base\nrun touch /test")
|
126
|
+
# => Docker::Image { :id => b750fe79269d2ec9a3c593ef05b4332b1d1a02a62b4accb2c21d589ff2f5f2dc, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }
|
127
|
+
```
|
128
|
+
|
129
|
+
## Containers
|
130
|
+
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.
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
require 'docker'
|
134
|
+
|
135
|
+
# Instantiate a new Container.
|
136
|
+
container = Docker::Container.new
|
137
|
+
# => Docker::Container { :id => , :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }
|
138
|
+
|
139
|
+
# Test if the has been created.
|
140
|
+
container.created?
|
141
|
+
# => false
|
142
|
+
|
143
|
+
# Create the Container.
|
144
|
+
container.create!('Cmd' => ['ls'], 'Image' => 'base')
|
145
|
+
# => Docker::Container { :id => 492510dd38e4, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }
|
146
|
+
|
147
|
+
container.created?
|
148
|
+
# => true
|
149
|
+
|
150
|
+
# Get more information about the Container.
|
151
|
+
container.json
|
152
|
+
# => {"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}
|
153
|
+
|
154
|
+
# Start running the Container.
|
155
|
+
container.start
|
156
|
+
# => nil
|
157
|
+
|
158
|
+
# Stop running the Container.
|
159
|
+
container.stop
|
160
|
+
# => nil
|
161
|
+
|
162
|
+
# Restart the Container.
|
163
|
+
container.restart
|
164
|
+
# => nil
|
165
|
+
|
166
|
+
# Kill the command running in the Container.
|
167
|
+
container.kill
|
168
|
+
# => nil
|
169
|
+
|
170
|
+
# Export a Container. Since an export is typically at least 300M, chunks of the
|
171
|
+
# export are yielded instead of just returning the whole thing.
|
172
|
+
File.open('export.tar.gz', 'w') do |f|
|
173
|
+
container.export { |chunk| file.write(chunk) }
|
174
|
+
end
|
175
|
+
# => nil
|
176
|
+
|
177
|
+
# Inspect a Container's changes to the file system.
|
178
|
+
container.changes
|
179
|
+
# => [{'Path'=>'/dev', 'Kind'=>0}, {'Path'=>'/dev/kmsg', 'Kind'=>1}]
|
180
|
+
|
181
|
+
# Wait for the current command to finish executing.
|
182
|
+
container.wait
|
183
|
+
# => {'StatusCode'=>0}
|
184
|
+
|
185
|
+
# Attach to the Container. Currently, the below options are the only valid ones.
|
186
|
+
container.attach(:stream => true, :stdout => true, :stderr => true, :logs => true)
|
187
|
+
# => "bin\nboot\ndev\netc\nhome\nlib\nlib64\nmedia\nmnt\nopt\nproc\nroot\nrun\nsbin\nselinux\nsrv\nsys\ntmp\nusr\nvar"
|
188
|
+
|
189
|
+
# Create an Image from a Container's changes.
|
190
|
+
container.commit
|
191
|
+
# => Docker::Image { :id => eaeb8d00efdf, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }
|
192
|
+
|
193
|
+
# Request all of the Containers. By default, will only return the running Containers.
|
194
|
+
Docker::Container.all(:all => true)
|
195
|
+
# => [Docker::Container { :id => , :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }]
|
196
|
+
```
|
197
|
+
|
198
|
+
## Connecting to Multiple Servers
|
199
|
+
|
200
|
+
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. Examples:
|
201
|
+
|
202
|
+
```ruby
|
203
|
+
require 'docker'
|
204
|
+
|
205
|
+
Docker::Container.new(:connection => Docker::Connection.new(:url => 'http://example.com'))
|
206
|
+
Docker::Container.all({}, Docker::Connection.new(:url => 'http://example.com'))
|
207
|
+
|
208
|
+
Docker::Image.new(:connection => Docker::Connection.new(:url => 'http://example.com'))
|
209
|
+
Docker::Image.all({}, Docker::Connection.new(:url => 'http://example.com'))
|
210
|
+
Docker::Image.build('from base', Docker::Connection.new(:url => 'http://example.com'))
|
211
|
+
Docker::Image.build({ :term => 'sshd' }, Docker::Connection.new(:url => 'http://example.com'))
|
212
|
+
```
|
213
|
+
|
214
|
+
## Known Issues
|
215
|
+
- `Docker::Container#attach` cannot attach to STDIN
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
2
|
+
|
3
|
+
require 'rake'
|
4
|
+
require 'docker'
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
require 'cane/rake_task'
|
7
|
+
|
8
|
+
task :default => [:spec, :quality]
|
9
|
+
|
10
|
+
RSpec::Core::RakeTask.new do |t|
|
11
|
+
t.pattern = 'spec/**/*_spec.rb'
|
12
|
+
end
|
13
|
+
|
14
|
+
Cane::RakeTask.new(:quality) do |cane|
|
15
|
+
cane.canefile = '.cane'
|
16
|
+
end
|
data/docker-api.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/docker/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Swipely, Inc."]
|
6
|
+
gem.email = %w{tomhulihan@swipely.com bright@swipely.com}
|
7
|
+
gem.description = %q{A simple REST client for the Docker Remote API}
|
8
|
+
gem.summary = %q{A simple REST client for the Docker Remote API}
|
9
|
+
gem.homepage = 'https://github.com/swipely/docker-api'
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "docker-api"
|
15
|
+
gem.require_paths = %w{lib}
|
16
|
+
gem.version = Docker::VERSION
|
17
|
+
gem.add_dependency 'excon', '>= 0.22.0'
|
18
|
+
gem.add_dependency 'json'
|
19
|
+
gem.add_dependency 'i18n'
|
20
|
+
gem.add_dependency 'multipart-post'
|
21
|
+
gem.add_development_dependency 'rake'
|
22
|
+
gem.add_development_dependency 'rspec'
|
23
|
+
gem.add_development_dependency 'cane'
|
24
|
+
gem.add_development_dependency 'pry'
|
25
|
+
gem.add_development_dependency 'webmock', '>= 1.11.0'
|
26
|
+
gem.add_development_dependency 'vcr', '>= 2.4.0'
|
27
|
+
end
|
data/lib/docker.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'json'
|
3
|
+
require 'excon'
|
4
|
+
require 'net/http/post/multipart'
|
5
|
+
|
6
|
+
# The top-level module for this gem. It's purpose is to hold global
|
7
|
+
# configuration variables that are used as defaults in other classes.
|
8
|
+
module Docker
|
9
|
+
class << self
|
10
|
+
def url
|
11
|
+
@url ||= 'http://localhost'
|
12
|
+
end
|
13
|
+
|
14
|
+
def options
|
15
|
+
@options ||= { :port => 4243 }
|
16
|
+
end
|
17
|
+
|
18
|
+
def url=(new_url)
|
19
|
+
@url = new_url
|
20
|
+
reset_connection!
|
21
|
+
end
|
22
|
+
|
23
|
+
def options=(new_options)
|
24
|
+
@options = { :port => 4243 }.merge(new_options)
|
25
|
+
reset_connection!
|
26
|
+
end
|
27
|
+
|
28
|
+
def connection
|
29
|
+
@connection ||= Connection.new(url, options)
|
30
|
+
end
|
31
|
+
|
32
|
+
def reset_connection!
|
33
|
+
@connection = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
# Get the version of Go, Docker, and optionally the Git commit.
|
37
|
+
def version
|
38
|
+
connection.json_request(:get, '/version')
|
39
|
+
end
|
40
|
+
|
41
|
+
# Get more information about the Docker server.
|
42
|
+
def info
|
43
|
+
connection.json_request(:get, '/info')
|
44
|
+
end
|
45
|
+
|
46
|
+
# Login to the Docker registry.
|
47
|
+
def authenticate!(options = {})
|
48
|
+
connection.post(:path => '/auth', :body => options)
|
49
|
+
true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
require 'docker/version'
|
55
|
+
require 'docker/error'
|
56
|
+
require 'docker/connection'
|
57
|
+
require 'docker/model'
|
58
|
+
require 'docker/multipart'
|
59
|
+
require 'docker/container'
|
60
|
+
require 'docker/image'
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# This class represents a Connection to a Docker server. The Connection is
|
2
|
+
# immutable in that once the url and options is set they cannot be changed.
|
3
|
+
class Docker::Connection
|
4
|
+
include Docker::Error
|
5
|
+
|
6
|
+
attr_reader :url, :options
|
7
|
+
|
8
|
+
# Create a new Connection. By default, the Connection points to localhost at
|
9
|
+
# port 4243, but this can be changed via an options Hash.
|
10
|
+
def initialize(url = 'http://localhost', options = {})
|
11
|
+
unless options.is_a?(Hash)
|
12
|
+
raise Docker::Error::ArgumentError, "Expected a Hash, got: #{options}"
|
13
|
+
end
|
14
|
+
self.url = url
|
15
|
+
self.options = { :port => 4243 }.merge(options)
|
16
|
+
end
|
17
|
+
|
18
|
+
# The actual client that sends HTTP methods to the docker server.
|
19
|
+
def resource
|
20
|
+
@resource ||= Excon.new(self.url, self.options)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Delegate all HTTP methods to the resource.
|
24
|
+
[:get, :put, :post, :delete, :request].each do |method|
|
25
|
+
define_method(method) do |*args, &block|
|
26
|
+
begin
|
27
|
+
self.resource.public_send(method, *args, &block)
|
28
|
+
rescue Excon::Errors::BadRequest => ex
|
29
|
+
raise ClientError, ex.message
|
30
|
+
rescue Excon::Errors::InternalServerError => ex
|
31
|
+
raise ServerError, ex.message
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Send a request to the server and then parse it into a Hash.
|
37
|
+
def json_request(method, path, query = {}, &block)
|
38
|
+
params = compile_request_params(method, path, query, &block)
|
39
|
+
body = self.request(params).body
|
40
|
+
JSON.parse(body) unless (body.nil? || body.empty? || (body == 'null'))
|
41
|
+
rescue JSON::ParserError => ex
|
42
|
+
raise UnexpectedResponseError, ex.message
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
"Docker::Connection { :url => #{self.url}, :options => #{self.options} }"
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
attr_writer :url, :options
|
51
|
+
|
52
|
+
# Given an http_method, path, query, and optional block, returns the
|
53
|
+
# corresponding request parameters.
|
54
|
+
def compile_request_params(http_method, path, query, &block)
|
55
|
+
{
|
56
|
+
:method => http_method,
|
57
|
+
:path => path,
|
58
|
+
:query => query,
|
59
|
+
:headers => { 'Content-Type' => 'application/json' },
|
60
|
+
:expects => (200..204),
|
61
|
+
:idempotent => http_method == :get,
|
62
|
+
:response_block => block
|
63
|
+
}.reject { |_, v| v.nil? }
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# This class represents a Docker Container. It's important to note that nothing
|
2
|
+
# is cached so that the information is always up to date.
|
3
|
+
class Docker::Container
|
4
|
+
include Docker::Model
|
5
|
+
|
6
|
+
resource_prefix '/containers'
|
7
|
+
|
8
|
+
create_request do |body|
|
9
|
+
response = self.connection.post(
|
10
|
+
:path => '/containers/create',
|
11
|
+
:headers => { 'Content-Type' => 'application/json' },
|
12
|
+
:body => body.to_json,
|
13
|
+
:expects => (200..204)
|
14
|
+
)
|
15
|
+
self.id = JSON.parse(response.body)['Id']
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
# Export the Container as a .tgz.
|
20
|
+
docker_request :export, :get
|
21
|
+
# Get more information about the Container.
|
22
|
+
docker_request :json, :get
|
23
|
+
# Wait for the current command to finish executing.
|
24
|
+
docker_request :wait, :post
|
25
|
+
# Start the Container.
|
26
|
+
docker_request :start, :post
|
27
|
+
# Inspect the Container's changes to the filesysetem
|
28
|
+
docker_request :changes, :get
|
29
|
+
# Stop the Container.
|
30
|
+
docker_request :stop, :post
|
31
|
+
# Kill the Container.
|
32
|
+
docker_request :kill, :post
|
33
|
+
# Restart the Container
|
34
|
+
docker_request :restart, :post
|
35
|
+
|
36
|
+
# Attach to a container's standard streams / logs.
|
37
|
+
def attach(options = {})
|
38
|
+
ensure_created!
|
39
|
+
self.connection.request(
|
40
|
+
:method => :post,
|
41
|
+
:path => "/containers/#{self.id}/attach",
|
42
|
+
:query => options,
|
43
|
+
:expects => (200..204)
|
44
|
+
).body
|
45
|
+
end
|
46
|
+
|
47
|
+
# Create an Image from a Container's change.s
|
48
|
+
def commit(options = {})
|
49
|
+
ensure_created!
|
50
|
+
options.merge!('container' => self.id[0..7])
|
51
|
+
hash = self.connection.json_request(:post, '/commit', options)
|
52
|
+
Docker::Image.new(:id => hash['Id'], :connection => self.connection)
|
53
|
+
end
|
54
|
+
end
|