docker-api 1.6.0 → 1.7.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/.cane +0 -1
- data/README.md +6 -7
- data/docker-api.gemspec +3 -4
- data/lib/docker.rb +10 -5
- data/lib/docker/connection.rb +2 -0
- data/lib/docker/container.rb +39 -4
- data/lib/docker/error.rb +6 -0
- data/lib/docker/event.rb +40 -0
- data/lib/docker/image.rb +37 -13
- data/lib/docker/util.rb +25 -1
- data/lib/docker/version.rb +2 -2
- data/spec/docker/container_spec.rb +37 -19
- data/spec/docker/event_spec.rb +79 -0
- data/spec/docker/image_spec.rb +89 -30
- data/spec/docker/util_spec.rb +83 -0
- data/spec/docker_spec.rb +47 -2
- data/spec/fixtures/{Dockerfile → build_from_dir/Dockerfile} +0 -0
- data/spec/fixtures/top/Dockerfile +2 -0
- data/spec/support/vcr.rb +1 -4
- data/spec/vcr/Docker/_authenticate_/with_valid_credentials/logs_in_and_sets_the_creds.yml +33 -0
- data/spec/vcr/Docker/_info/returns_the_info_as_a_Hash.yml +7 -7
- data/spec/vcr/Docker/_validate_version/when_nothing_is_raised/validate_version_/.yml +6 -6
- data/spec/vcr/Docker/_version/returns_the_version_as_a_Hash.yml +6 -6
- data/spec/vcr/Docker_Container/_all/when_the_HTTP_response_is_a_200/materializes_each_Container_into_a_Docker_Container.yml +27 -97
- data/spec/vcr/Docker_Container/_attach/yields_each_chunk.yml +18 -19
- data/spec/vcr/Docker_Container/_changes/returns_the_changes_as_an_array.yml +22 -22
- data/spec/vcr/Docker_Container/_commit/creates_a_new_Image_from_the_Container_s_changes.yml +18 -18
- data/spec/vcr/Docker_Container/_commit/if_run_is_passed_it_saves_the_command_in_the_image/saves_the_command.yml +178 -0
- data/spec/vcr/Docker_Container/_copy/when_the_file_does_not_exist/raises_an_error.yml +54 -24
- data/spec/vcr/Docker_Container/_copy/when_the_input_is_a_directory/yields_each_chunk_of_the_tarred_directory.yml +27 -60
- data/spec/vcr/Docker_Container/_copy/when_the_input_is_a_file/yields_each_chunk_of_the_tarred_file.yml +27 -60
- data/spec/vcr/Docker_Container/_create/when_the_Container_does_not_yet_exist/when_the_HTTP_request_returns_a_200/sets_the_id.yml +7 -7
- data/spec/vcr/Docker_Container/_delete/deletes_the_container.yml +16 -46
- data/spec/vcr/Docker_Container/_export/yields_each_chunk.yml +24 -17
- data/spec/vcr/Docker_Container/_json/returns_the_description_as_a_Hash.yml +14 -14
- data/spec/vcr/Docker_Container/_kill/kills_the_container.yml +36 -49
- data/spec/vcr/Docker_Container/_restart/restarts_the_container.yml +43 -43
- data/spec/vcr/Docker_Container/_run/when_the_Container_s_command_does_not_return_status_code_of_0/raises_an_error.yml +17 -17
- data/spec/vcr/Docker_Container/_run/when_the_Container_s_command_returns_a_status_code_of_0/creates_a_new_container_to_run_the_specified_command.yml +47 -47
- data/spec/vcr/Docker_Container/_start/starts_the_container.yml +25 -25
- data/spec/vcr/Docker_Container/_stop/stops_the_container.yml +40 -53
- data/spec/vcr/Docker_Container/_top/returns_the_top_commands_as_an_Array.yml +89 -25
- data/spec/vcr/Docker_Container/_wait/waits_for_the_command_to_finish.yml +17 -17
- data/spec/vcr/Docker_Container/_wait/when_an_argument_is_given/and_a_command_runs_for_too_long/raises_a_ServerError.yml +12 -12
- data/spec/vcr/Docker_Container/_wait/when_an_argument_is_given/sets_the_read_timeout_to_that_amount_of_time.yml +17 -17
- data/spec/vcr/Docker_Image/_all/materializes_each_Image_into_a_Docker_Image.yml +12 -12
- data/spec/vcr/Docker_Image/_build/with_a_valid_Dockerfile/with_specifying_a_repo_in_the_query_parameters/builds_an_image_and_tags_it.yml +110 -0
- data/spec/vcr/Docker_Image/_build/with_a_valid_Dockerfile/{builds_an_image.yml → without_query_parameters/builds_an_image.yml} +5 -5
- data/spec/vcr/Docker_Image/_build/with_an_invalid_Dockerfile/throws_a_UnexpectedResponseError.yml +7 -9
- data/spec/vcr/Docker_Image/_build_from_dir/with_a_valid_Dockerfile/with_no_query_parameters/builds_the_image.yml +121 -0
- data/spec/vcr/Docker_Image/_build_from_dir/with_a_valid_Dockerfile/with_specifying_a_repo_in_the_query_parameters/builds_the_image_and_tags_it.yml +151 -0
- data/spec/vcr/Docker_Image/_create/when_the_Image_does_not_yet_exist_and_the_body_is_a_Hash/sets_the_id.yml +5 -5
- data/spec/vcr/Docker_Image/_history/returns_the_history_of_the_Image.yml +10 -10
- data/spec/vcr/Docker_Image/_insert/inserts_the_url_s_file_into_a_new_Image.yml +53 -109
- data/spec/vcr/Docker_Image/_insert_local/when_the_local_file_does_exist/creates_a_new_Image_that_has_that_file.yml +32 -68
- data/spec/vcr/Docker_Image/_insert_local/when_the_local_file_does_not_exist/raises_an_error.yml +5 -5
- data/spec/vcr/Docker_Image/_insert_local/when_there_are_multiple_files_passed/creates_a_new_Image_that_has_each_file.yml +40 -68
- data/spec/vcr/Docker_Image/_json/returns_additional_information_about_image_image.yml +10 -10
- data/spec/vcr/Docker_Image/_push/pushes_the_Image.yml +161 -0
- data/spec/vcr/Docker_Image/_remove/removes_the_Image.yml +17 -17
- data/spec/vcr/Docker_Image/_run/when_the_argument_is_a_String/splits_the_String_by_spaces_and_creates_a_new_Container.yml +23 -24
- data/spec/vcr/Docker_Image/_run/when_the_argument_is_an_Array/creates_a_new_Container.yml +23 -24
- data/spec/vcr/Docker_Image/_run/when_the_argument_is_nil/command_configured_in_image/should_normally_show_result_if_image_has_Cmd_configured.yml +148 -0
- data/spec/vcr/Docker_Image/_run/when_the_argument_is_nil/no_command_configured_in_image/should_raise_an_error_if_no_command_is_specified.yml +68 -0
- data/spec/vcr/Docker_Image/_search/materializes_each_Image_into_a_Docker_Image.yml +13 -11
- data/spec/vcr/Docker_Image/_tag/tags_the_image_with_the_repo_name.yml +10 -10
- metadata +32 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a4a13f5948a8df770804ade2a22dc3c31e7fc1b1
|
4
|
+
data.tar.gz: c3ac3bb3d1219fb34fbb1e91b4ee63e7fc4486b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff874b82925ea1dd68a05be8bdad589108967abc86d6a649efaf07606b35266284c4d596e0bdf603f56d7a5d8268a6f327a9e90311b0b7240cd9b517b909ac1f
|
7
|
+
data.tar.gz: abd742b0ee713c369d1034b90c96ed6e8c6ba48ccac6fa36129ecd36c5a8c6340860cf89486d90feaacebf105a30f6df8ec17e5954dd63c85cc73dcd0cf19953
|
data/.cane
CHANGED
@@ -1 +0,0 @@
|
|
1
|
-
--abc-max 13
|
data/README.md
CHANGED
@@ -219,22 +219,21 @@ ff02::1 ip6-allnodes
|
|
219
219
|
ff02::2 ip6-allrouters
|
220
220
|
# => Docker::Container { :id => a1759f3e2873, :connection => Docker::Connection { :url => http://localhost, :options => {:port=>4243} } }
|
221
221
|
|
222
|
-
|
223
|
-
|
224
222
|
# Wait for the current command to finish executing. If an argument is given,
|
225
223
|
# will timeout after that number of seconds. The default is one minute.
|
226
224
|
container.wait(15)
|
227
225
|
# => {'StatusCode'=>0}
|
228
226
|
|
229
227
|
# Attach to the Container. Currently, the below options are the only valid ones.
|
230
|
-
# By default, :stream and :
|
228
|
+
# By default, :stream, :stdout, and :stderr are set.
|
231
229
|
container.attach(:stream => true, :stdout => true, :stderr => true, :logs => true)
|
232
|
-
# => "bin\nboot\ndev\netc\nhome\nlib\nlib64\nmedia\nmnt\nopt\nproc\nroot\nrun\nsbin\nselinux\nsrv\nsys\ntmp\nusr\nvar"
|
230
|
+
# => [["bin\nboot\ndev\netc\nhome\nlib\nlib64\nmedia\nmnt\nopt\nproc\nroot\nrun\nsbin\nselinux\nsrv\nsys\ntmp\nusr\nvar", []]
|
233
231
|
|
234
232
|
# If you wish to stream the attach method, a block may be supplied.
|
235
|
-
container = Docker::Container.create('Image' => 'base', 'Cmd' =>
|
236
|
-
container.tap(&:start).attach { |chunk| puts chunk }
|
237
|
-
|
233
|
+
container = Docker::Container.create('Image' => 'base', 'Cmd' => ['find / -name *'])
|
234
|
+
container.tap(&:start).attach { |stream, chunk| puts "#{stream}: #{chunk}" }
|
235
|
+
stderr: 2013/10/30 17:16:24 Unable to locate find / -name *
|
236
|
+
# => [[], ["2013/10/30 17:16:24 Unable to locate find / -name *\n"]]
|
238
237
|
|
239
238
|
# Create an Image from a Container's changes.
|
240
239
|
container.commit
|
data/docker-api.gemspec
CHANGED
@@ -3,7 +3,7 @@ require File.expand_path('../lib/docker/version', __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ["Swipely, Inc."]
|
6
|
-
gem.email = %w{tomhulihan@swipely.com bright@swipely.com}
|
6
|
+
gem.email = %w{tomhulihan@swipely.com bright@swipely.com toddlunter@swipely.com}
|
7
7
|
gem.description = %q{A simple REST client for the Docker Remote API}
|
8
8
|
gem.summary = %q{A simple REST client for the Docker Remote API}
|
9
9
|
gem.homepage = 'https://github.com/swipely/docker-api'
|
@@ -14,14 +14,13 @@ Gem::Specification.new do |gem|
|
|
14
14
|
gem.name = "docker-api"
|
15
15
|
gem.require_paths = %w{lib}
|
16
16
|
gem.version = Docker::VERSION
|
17
|
-
gem.add_dependency 'excon', '>= 0.
|
17
|
+
gem.add_dependency 'excon', '>= 0.28'
|
18
18
|
gem.add_dependency 'json'
|
19
19
|
gem.add_dependency 'archive-tar-minitar'
|
20
20
|
gem.add_development_dependency 'rake'
|
21
21
|
gem.add_development_dependency 'rspec'
|
22
22
|
gem.add_development_dependency 'cane'
|
23
23
|
gem.add_development_dependency 'pry'
|
24
|
-
gem.add_development_dependency '
|
25
|
-
gem.add_development_dependency 'vcr', '>= 2.4.0'
|
24
|
+
gem.add_development_dependency 'vcr', '>= 2.7.0'
|
26
25
|
gem.add_development_dependency 'simplecov'
|
27
26
|
end
|
data/lib/docker.rb
CHANGED
@@ -2,13 +2,14 @@ require 'cgi'
|
|
2
2
|
require 'json'
|
3
3
|
require 'excon'
|
4
4
|
require 'tempfile'
|
5
|
+
require 'base64'
|
5
6
|
require 'rubygems/package'
|
6
7
|
require 'archive/tar/minitar'
|
7
8
|
|
8
9
|
# The top-level module for this gem. It's purpose is to hold global
|
9
10
|
# configuration variables that are used as defaults in other classes.
|
10
11
|
module Docker
|
11
|
-
|
12
|
+
attr_accessor :creds
|
12
13
|
|
13
14
|
def default_socket_url
|
14
15
|
'unix:///var/run/docker.sock'
|
@@ -56,9 +57,12 @@ module Docker
|
|
56
57
|
|
57
58
|
# Login to the Docker registry.
|
58
59
|
def authenticate!(options = {})
|
59
|
-
|
60
|
-
connection.post(
|
60
|
+
creds = options.to_json
|
61
|
+
connection.post('/auth', {}, :body => creds)
|
62
|
+
@creds = creds
|
61
63
|
true
|
64
|
+
rescue Docker::Error::ServerError, Docker::Error::UnauthorizedError
|
65
|
+
raise Docker::Error::AuthenticationError
|
62
66
|
end
|
63
67
|
|
64
68
|
# When the correct version of Docker is installed, returns true. Otherwise,
|
@@ -71,8 +75,8 @@ module Docker
|
|
71
75
|
end
|
72
76
|
|
73
77
|
module_function :default_socket_url, :env_url, :url, :url=, :options,
|
74
|
-
:options=, :connection, :reset_connection!,
|
75
|
-
:info, :authenticate!, :validate_version!
|
78
|
+
:options=, :creds, :creds=, :connection, :reset_connection!,
|
79
|
+
:version, :info, :authenticate!, :validate_version!
|
76
80
|
end
|
77
81
|
|
78
82
|
require 'docker/version'
|
@@ -81,3 +85,4 @@ require 'docker/util'
|
|
81
85
|
require 'docker/connection'
|
82
86
|
require 'docker/container'
|
83
87
|
require 'docker/image'
|
88
|
+
require 'docker/event'
|
data/lib/docker/connection.rb
CHANGED
@@ -36,6 +36,8 @@ class Docker::Connection
|
|
36
36
|
resource.request(compile_request_params(*args, &block)).body
|
37
37
|
rescue Excon::Errors::BadRequest => ex
|
38
38
|
raise ClientError, ex.message
|
39
|
+
rescue Excon::Errors::Unauthorized => ex
|
40
|
+
raise UnauthorizedError, ex.message
|
39
41
|
rescue Excon::Errors::InternalServerError => ex
|
40
42
|
raise ServerError, ex.message
|
41
43
|
rescue Excon::Errors::Timeout => ex
|
data/lib/docker/container.rb
CHANGED
@@ -50,14 +50,31 @@ class Docker::Container
|
|
50
50
|
|
51
51
|
# Attach to a container's standard streams / logs.
|
52
52
|
def attach(options = {}, &block)
|
53
|
-
opts = {
|
54
|
-
|
53
|
+
opts = {
|
54
|
+
:stream => true, :stdout => true, :stderr => true
|
55
|
+
}.merge(options)
|
56
|
+
# Creates list to store stdout and stderr messages
|
57
|
+
msgs = [[],[]]
|
58
|
+
connection.post(
|
59
|
+
path_for(:attach),
|
60
|
+
opts,
|
61
|
+
:response_block => attach_for(block, msgs)
|
62
|
+
)
|
63
|
+
msgs
|
55
64
|
end
|
56
65
|
|
57
66
|
# Create an Image from a Container's change.s
|
58
67
|
def commit(options = {})
|
59
68
|
options.merge!('container' => self.id[0..7])
|
60
|
-
|
69
|
+
# [code](https://github.com/dotcloud/docker/blob/v0.6.3/commands.go#L1115)
|
70
|
+
# Based on the link, the config passed as run, needs to be passed as the
|
71
|
+
# body of the post so capture it, remove from the options, and pass it via
|
72
|
+
# the post body
|
73
|
+
config = options.delete('run')
|
74
|
+
hash = Docker::Util.parse_json(connection.post('/commit',
|
75
|
+
options,
|
76
|
+
:body => config.to_json)
|
77
|
+
)
|
61
78
|
Docker::Image.send(:new, self.connection, hash['Id'])
|
62
79
|
end
|
63
80
|
|
@@ -124,6 +141,24 @@ class Docker::Container
|
|
124
141
|
"/containers/#{self.id}/#{resource}"
|
125
142
|
end
|
126
143
|
|
127
|
-
|
144
|
+
# Method that takes chunks and calls the attached block for each mux'd message
|
145
|
+
def attach_for(block, msg_stack)
|
146
|
+
lambda do |c,r,t|
|
147
|
+
stdout_msgs, stderr_msgs = Docker::Util.decipher_messages(c)
|
148
|
+
msg_stack[0] += stdout_msgs
|
149
|
+
msg_stack[1] += stderr_msgs
|
150
|
+
|
151
|
+
unless block.nil?
|
152
|
+
stdout_msgs.each do |msg|
|
153
|
+
block.call(:stdout, msg)
|
154
|
+
end
|
155
|
+
stderr_msgs.each do |msg|
|
156
|
+
block.call(:stderr, msg)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
private :path_for, :attach_for
|
128
163
|
private_class_method :new
|
129
164
|
end
|
data/lib/docker/error.rb
CHANGED
@@ -11,6 +11,9 @@ module Docker::Error
|
|
11
11
|
# Raised when a request returns a 400.
|
12
12
|
class ClientError < DockerError; end
|
13
13
|
|
14
|
+
# Raised when a request returns a 401.
|
15
|
+
class UnauthorizedError < DockerError; end
|
16
|
+
|
14
17
|
# Raised when a request returns a 500.
|
15
18
|
class ServerError < DockerError; end
|
16
19
|
|
@@ -22,4 +25,7 @@ module Docker::Error
|
|
22
25
|
|
23
26
|
# Raised when a request times out.
|
24
27
|
class TimeoutError < DockerError; end
|
28
|
+
|
29
|
+
# Raised when login fails.
|
30
|
+
class AuthenticationError < DockerError; end
|
25
31
|
end
|
data/lib/docker/event.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# This class represents a Docker Image.
|
2
|
+
class Docker::Event
|
3
|
+
include Docker::Error
|
4
|
+
|
5
|
+
attr_accessor :status, :id, :from, :time
|
6
|
+
|
7
|
+
def initialize(status, id, from, time)
|
8
|
+
@status, @id, @from, @time = status, id, from, time
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
"Docker::Event { :status => #{self.status}, :id => #{self.id}, "\
|
13
|
+
":from => #{self.from}, :time => #{self.time} }"
|
14
|
+
end
|
15
|
+
|
16
|
+
class << self
|
17
|
+
include Docker::Error
|
18
|
+
|
19
|
+
def stream(opts = {}, conn = Docker.connection, &block)
|
20
|
+
conn.get('/events', opts, :response_block => lambda { |b, r, t|
|
21
|
+
block.call(new_event(b, r, t))
|
22
|
+
})
|
23
|
+
end
|
24
|
+
|
25
|
+
def since(since, opts = {}, conn = Docker.connection, &block)
|
26
|
+
stream(opts.merge(:since => since), conn, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def new_event(body, remaining, total)
|
30
|
+
return if body.nil? || body.empty?
|
31
|
+
json = Docker::Util.parse_json(body)
|
32
|
+
Docker::Event.new(
|
33
|
+
json['status'],
|
34
|
+
json['id'],
|
35
|
+
json['from'],
|
36
|
+
json['time']
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/docker/image.rb
CHANGED
@@ -15,16 +15,32 @@ class Docker::Image
|
|
15
15
|
|
16
16
|
# Given a command and optional list of streams to attach to, run a command on
|
17
17
|
# an Image. This will not modify the Image, but rather create a new Container
|
18
|
-
# to run the Image.
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
# to run the Image. If the image has an embedded config, no command is
|
19
|
+
# necessary, but it will fail with 500 if no config is saved with the image
|
20
|
+
def run(cmd=nil)
|
21
|
+
opts = { 'Image' => self.id }
|
22
|
+
opts["Cmd"] = cmd.split(/\s+/) if cmd.is_a?(String)
|
23
|
+
begin
|
24
|
+
Docker::Container.create(opts, connection)
|
25
|
+
.tap(&:start!)
|
26
|
+
rescue ServerError
|
27
|
+
if cmd
|
28
|
+
raise ServerError, "Docker Server Error."
|
29
|
+
else
|
30
|
+
raise ServerError, "No command specified."
|
31
|
+
end
|
32
|
+
end
|
23
33
|
end
|
24
34
|
|
25
35
|
# Push the Image to the Docker registry.
|
26
|
-
def push(options = {})
|
27
|
-
|
36
|
+
def push(creds = nil, options = {})
|
37
|
+
credentials = (creds.nil?) ? Docker.creds : creds.to_json
|
38
|
+
headers = Docker::Util.build_auth_header(credentials)
|
39
|
+
connection.post(
|
40
|
+
path_for(:push),
|
41
|
+
options,
|
42
|
+
:headers => headers
|
43
|
+
)
|
28
44
|
self
|
29
45
|
end
|
30
46
|
|
@@ -83,8 +99,14 @@ class Docker::Image
|
|
83
99
|
include Docker::Error
|
84
100
|
|
85
101
|
# Create a new Image.
|
86
|
-
def create(opts = {}, conn = Docker.connection)
|
87
|
-
|
102
|
+
def create(opts = {}, creds = nil, conn = Docker.connection)
|
103
|
+
credentials = (creds.nil?) ? creds.to_json : Docker.creds
|
104
|
+
headers = if credentials.nil?
|
105
|
+
Docker::Util.build_auth_header(credentials)
|
106
|
+
else
|
107
|
+
{}
|
108
|
+
end
|
109
|
+
instance = new(conn, {}, :headers => headers)
|
88
110
|
conn.post('/images/create', opts)
|
89
111
|
id = opts['repo'] ? "#{opts['repo']}/#{opts['tag']}" : opts['fromImage']
|
90
112
|
if (instance.id = id).nil?
|
@@ -122,19 +144,21 @@ class Docker::Image
|
|
122
144
|
end
|
123
145
|
|
124
146
|
# Given a Dockerfile as a string, builds an Image.
|
125
|
-
def build(commands, connection = Docker.connection)
|
147
|
+
def build(commands, opts = {}, connection = Docker.connection)
|
126
148
|
body = connection.post(
|
127
|
-
'/build',
|
149
|
+
'/build', opts,
|
128
150
|
:body => Docker::Util.create_tar('Dockerfile' => commands)
|
129
151
|
)
|
130
152
|
new(connection, Docker::Util.extract_id(body))
|
153
|
+
rescue Docker::Error::ServerError
|
154
|
+
raise Docker::Error::UnexpectedResponseError
|
131
155
|
end
|
132
156
|
|
133
157
|
# Given a directory that contains a Dockerfile, builds an Image.
|
134
|
-
def build_from_dir(dir, connection = Docker.connection)
|
158
|
+
def build_from_dir(dir, opts = {}, connection = Docker.connection)
|
135
159
|
tar = Docker::Util.create_dir_tar(dir)
|
136
160
|
body = connection.post(
|
137
|
-
'/build',
|
161
|
+
'/build', opts,
|
138
162
|
:headers => { 'Content-Type' => 'application/tar',
|
139
163
|
'Transfer-Encoding' => 'chunked' }
|
140
164
|
) { tar.read(Excon.defaults[:chunk_size]).to_s }
|
data/lib/docker/util.rb
CHANGED
@@ -18,7 +18,7 @@ module Docker::Util
|
|
18
18
|
tar.add_file(file_name, 0640) { |tar_file| tar_file.write(input) }
|
19
19
|
end
|
20
20
|
end
|
21
|
-
output.tap(&:rewind)
|
21
|
+
output.tap(&:rewind).string
|
22
22
|
end
|
23
23
|
|
24
24
|
def create_dir_tar(directory)
|
@@ -57,4 +57,28 @@ module Docker::Util
|
|
57
57
|
|
58
58
|
file_hash
|
59
59
|
end
|
60
|
+
|
61
|
+
def build_auth_header(credentials)
|
62
|
+
credentials = credentials.to_json if credentials.is_a?(Hash)
|
63
|
+
{ 'X-Registry-Auth' => Base64.encode64(credentials).gsub(/\n/, '') }
|
64
|
+
end
|
65
|
+
|
66
|
+
# Method to break apart application/vnd.docker.raw-stream headers
|
67
|
+
def decipher_messages(body)
|
68
|
+
raw_text = body.dup
|
69
|
+
stdout_messages = []
|
70
|
+
stderr_messages = []
|
71
|
+
while !raw_text.empty?
|
72
|
+
header = raw_text.slice!(0,8)
|
73
|
+
next if header.nil?
|
74
|
+
length = header[4..7].chars
|
75
|
+
.map { |c| c.getbyte(0) }
|
76
|
+
.inject(0) { |total, curr| (total << 8) + curr }
|
77
|
+
message = raw_text.slice!(0,length)
|
78
|
+
stdout_messages << message if header.getbyte(0) == 1
|
79
|
+
stderr_messages << message if header.getbyte(0) == 2
|
80
|
+
end
|
81
|
+
|
82
|
+
[stdout_messages, stderr_messages]
|
83
|
+
end
|
60
84
|
end
|
data/lib/docker/version.rb
CHANGED
@@ -58,16 +58,14 @@ describe Docker::Container do
|
|
58
58
|
end
|
59
59
|
|
60
60
|
describe '#top' do
|
61
|
-
|
62
|
-
|
63
|
-
'Cmd' => %w[while true; do; done;],
|
64
|
-
'Image' => 'base'
|
65
|
-
)
|
61
|
+
let(:dir) {
|
62
|
+
File.join(File.dirname(__FILE__), '..', 'fixtures', 'top')
|
66
63
|
}
|
67
|
-
let(:
|
64
|
+
let(:image) { Docker::Image.build_from_dir(dir) }
|
65
|
+
let(:top) { sleep 1; container.top }
|
66
|
+
let!(:container) { image.run('/while') }
|
68
67
|
|
69
|
-
|
70
|
-
after { subject.kill }
|
68
|
+
after { container.kill; image.remove }
|
71
69
|
|
72
70
|
it 'returns the top commands as an Array', :vcr do
|
73
71
|
top.should be_a Array
|
@@ -80,7 +78,7 @@ describe Docker::Container do
|
|
80
78
|
subject {
|
81
79
|
Docker::Image.create(
|
82
80
|
'fromImage' => 'base'
|
83
|
-
).run('touch /test').tap { |c| c.
|
81
|
+
).run('touch /test').tap { |c| c.wait }
|
84
82
|
}
|
85
83
|
|
86
84
|
context 'when the file does not exist' do
|
@@ -120,8 +118,7 @@ describe Docker::Container do
|
|
120
118
|
it 'yields each chunk', :vcr do
|
121
119
|
first = nil
|
122
120
|
subject.export do |chunk|
|
123
|
-
first
|
124
|
-
break
|
121
|
+
first ||= chunk
|
125
122
|
end
|
126
123
|
first[257..261].should == "ustar" # Make sure the export is a tar.
|
127
124
|
end
|
@@ -133,10 +130,11 @@ describe Docker::Container do
|
|
133
130
|
before { subject.start }
|
134
131
|
|
135
132
|
it 'yields each chunk', :vcr do
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
133
|
+
chunk = nil
|
134
|
+
subject.attach do |stream, c|
|
135
|
+
chunk ||= c
|
136
|
+
end
|
137
|
+
expect(chunk).to eq("/\n")
|
140
138
|
end
|
141
139
|
end
|
142
140
|
|
@@ -277,6 +275,14 @@ describe Docker::Container do
|
|
277
275
|
image.should be_a Docker::Image
|
278
276
|
image.id.should_not be_nil
|
279
277
|
end
|
278
|
+
|
279
|
+
context 'if run is passed, it saves the command in the image', :vcr do
|
280
|
+
let(:image) { subject.commit('run' => {"Cmd" => %w[pwd]}) }
|
281
|
+
it 'saves the command' do
|
282
|
+
expect(image.run.attach).to eql [["/\n"],[]]
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
280
286
|
end
|
281
287
|
|
282
288
|
describe '.create' do
|
@@ -284,8 +290,14 @@ describe Docker::Container do
|
|
284
290
|
|
285
291
|
context 'when the Container does not yet exist' do
|
286
292
|
context 'when the HTTP request does not return a 200' do
|
287
|
-
before
|
288
|
-
|
293
|
+
before do
|
294
|
+
Docker.options = { :mock => true }
|
295
|
+
Excon.stub({ :method => :post }, { :status => 400 })
|
296
|
+
end
|
297
|
+
after do
|
298
|
+
Excon.stubs.shift
|
299
|
+
Docker.options = {}
|
300
|
+
end
|
289
301
|
|
290
302
|
it 'raises an error' do
|
291
303
|
expect { subject.create }.to raise_error(Docker::Error::ClientError)
|
@@ -329,8 +341,14 @@ describe Docker::Container do
|
|
329
341
|
subject { described_class }
|
330
342
|
|
331
343
|
context 'when the HTTP response is not a 200' do
|
332
|
-
before
|
333
|
-
|
344
|
+
before do
|
345
|
+
Docker.options = { :mock => true }
|
346
|
+
Excon.stub({ :method => :get }, { :status => 500 })
|
347
|
+
end
|
348
|
+
after do
|
349
|
+
Excon.stubs.shift
|
350
|
+
Docker.options = {}
|
351
|
+
end
|
334
352
|
|
335
353
|
it 'raises an error' do
|
336
354
|
expect { subject.all }
|