docker-api 1.15.0 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +26 -1
- data/Rakefile +37 -0
- data/TESTING.md +61 -0
- data/lib/docker.rb +8 -1
- data/lib/docker/container.rb +44 -80
- data/lib/docker/exec.rb +98 -0
- data/lib/docker/image.rb +4 -3
- data/lib/docker/util.rb +79 -0
- data/lib/docker/version.rb +2 -2
- data/spec/docker/container_spec.rb +192 -56
- data/spec/docker/event_spec.rb +4 -4
- data/spec/docker/exec_spec.rb +197 -0
- data/spec/docker/image_spec.rb +131 -102
- data/spec/docker_spec.rb +37 -27
- data/spec/fixtures/build_from_dir/Dockerfile +2 -2
- data/spec/fixtures/export.tar +0 -0
- data/spec/fixtures/top/Dockerfile +2 -2
- data/spec/spec_helper.rb +10 -0
- data/spec/support/vcr.rb +5 -0
- data/spec/vcr/Docker/_authenticate_/with_valid_credentials/logs_in_and_sets_the_creds.yml +6 -8
- data/spec/vcr/Docker/_info/returns_the_info_as_a_Hash.yml +7 -9
- data/spec/vcr/Docker/_validate_version/when_nothing_is_raised/validate_version_/.yml +7 -9
- data/spec/vcr/Docker/_version/returns_the_version_as_a_Hash.yml +7 -9
- data/spec/vcr/Docker_Container/_all/when_the_HTTP_response_is_a_200/materializes_each_Container_into_a_Docker_Container.yml +46 -139
- data/spec/vcr/Docker_Container/_attach/with_normal_sized_chunks/yields_each_chunk.yml +62 -20
- data/spec/vcr/Docker_Container/_attach/with_very_small_chunks/yields_each_chunk.yml +62 -20
- data/spec/vcr/Docker_Container/_changes/returns_the_changes_as_an_array.yml +71 -28
- data/spec/vcr/Docker_Container/_commit/creates_a_new_Image_from_the_Container_s_changes.yml +69 -23
- data/spec/vcr/Docker_Container/_copy/when_the_file_does_not_exist/raises_an_error.yml +134 -0
- data/spec/vcr/Docker_Container/_copy/when_the_input_is_a_directory/yields_each_chunk_of_the_tarred_directory.yml +73 -290
- data/spec/vcr/Docker_Container/_copy/when_the_input_is_a_file/yields_each_chunk_of_the_tarred_file.yml +51 -211
- data/spec/vcr/Docker_Container/_create/when_creating_a_container_named_bob/should_have_name_set_to_bob.yml +36 -17
- data/spec/vcr/Docker_Container/_create/when_the_Container_does_not_yet_exist/when_the_HTTP_request_returns_a_200/sets_the_id.yml +30 -9
- data/spec/vcr/Docker_Container/_delete/deletes_the_container.yml +17 -23
- data/spec/vcr/Docker_Container/_exec/when_detach_is_true/returns_the_Docker_Exec_object.yml +151 -0
- data/spec/vcr/Docker_Container/_exec/when_passed_a_block/streams_the_stdout/stderr_messages.yml +153 -0
- data/spec/vcr/Docker_Container/_exec/when_passed_only_a_command/returns_the_stdout/stderr_messages.yml +153 -0
- data/spec/vcr/Docker_Container/_exec/when_stdin_object_is_passed/returns_the_stdout/stderr_messages.yml +100 -0
- data/spec/vcr/Docker_Container/_exec/when_tty_is_true/returns_the_raw_stdout/stderr_output.yml +152 -0
- data/spec/vcr/Docker_Container/_export/yields_each_chunk.yml +263 -28
- data/spec/vcr/Docker_Container/_get/when_the_HTTP_response_is_a_200/materializes_the_Container_into_a_Docker_Container.yml +36 -17
- data/spec/vcr/Docker_Container/_json/returns_the_description_as_a_Hash.yml +36 -17
- data/spec/vcr/Docker_Container/_kill/kills_the_container.yml +55 -53
- data/spec/vcr/Docker_Container/_kill/with_a_kill_signal/kills_the_container.yml +74 -96
- data/spec/vcr/Docker_Container/_logs/when_not_selecting_any_stream/raises_a_client_error.yml +84 -81
- data/spec/vcr/Docker_Container/_logs/when_selecting_stdout/returns_blank_logs.yml +34 -15
- data/spec/vcr/Docker_Container/_pause/pauses_the_container.yml +98 -45
- data/spec/vcr/Docker_Container/_restart/restarts_the_container.yml +88 -56
- data/spec/vcr/Docker_Container/_run/when_the_Container_s_command_does_not_return_status_code_of_0/raises_an_error.yml +39 -22
- 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 +212 -60
- data/spec/vcr/Docker_Container/_start/starts_the_container.yml +45 -30
- data/spec/vcr/Docker_Container/_stop/stops_the_container.yml +54 -83
- data/spec/vcr/Docker_Container/_streaming_logs/when_not_selecting_any_stream/raises_a_client_error.yml +84 -81
- data/spec/vcr/Docker_Container/_streaming_logs/when_selecting_stdout/returns_blank_logs.yml +46 -30
- data/spec/vcr/Docker_Container/_top/returns_the_top_commands_as_an_Array.yml +103 -40
- data/spec/vcr/Docker_Container/_unpause/unpauses_the_container.yml +81 -57
- data/spec/vcr/Docker_Container/_wait/waits_for_the_command_to_finish.yml +39 -22
- data/spec/vcr/Docker_Container/_wait/when_an_argument_is_given/sets_the_read_timeout_to_that_amount_of_time.yml +39 -22
- data/spec/vcr/Docker_Exec/_create/when_the_HTTP_request_returns_a_201/sets_the_id.yml +128 -0
- data/spec/vcr/Docker_Exec/_resize/when_exec_instance_has_TTY_enabled/returns_a_200.yml +155 -0
- data/spec/vcr/Docker_Exec/_start_/when_detach_is_set_to_false/block_is_passed/attaches_to_the_stream.yml +152 -0
- data/spec/vcr/Docker_Exec/_start_/when_detach_is_set_to_false/returns_the_stdout_and_stderr_messages.yml +152 -0
- data/spec/vcr/Docker_Exec/_start_/when_detach_is_set_to_true/returns_empty_stdout_and_stderr_messages.yml +151 -0
- data/spec/vcr/Docker_Exec/_start_/when_the_HTTP_request_returns_a_201/starts_the_exec_instance.yml +151 -0
- data/spec/vcr/Docker_Exec/_start_/when_the_command_has_already_run/raises_an_error.yml +151 -0
- data/spec/vcr/Docker_Image/_all/materializes_each_Image_into_a_Docker_Image.yml +86 -200
- data/spec/vcr/Docker_Image/_build/with_a_valid_Dockerfile/with_a_block_capturing_build_output/calls_the_block_and_passes_build_output.yml +10 -14
- 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 +147 -39
- data/spec/vcr/Docker_Image/_build/with_a_valid_Dockerfile/without_query_parameters/builds_an_image.yml +10 -14
- data/spec/vcr/Docker_Image/_build/with_an_invalid_Dockerfile/throws_a_UnexpectedResponseError.yml +12 -14
- data/spec/vcr/Docker_Image/_build_from_dir/with_a_valid_Dockerfile/with_a_block_capturing_build_output/calls_the_block_and_passes_build_output.yml +118 -16
- data/spec/vcr/Docker_Image/_build_from_dir/with_a_valid_Dockerfile/with_credentials_passed/sends_X-Registry-Config_header.yml +118 -14
- data/spec/vcr/Docker_Image/_build_from_dir/with_a_valid_Dockerfile/with_no_query_parameters/builds_the_image.yml +109 -37
- 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 +214 -60
- data/spec/vcr/Docker_Image/_create/when_the_Image_does_not_yet_exist_and_the_body_is_a_Hash/sets_the_id_and_sends_Docker_creds.yml +41 -2631
- data/spec/vcr/Docker_Image/_exist_/when_the_image_does_exist/returns_true.yml +12 -19
- data/spec/vcr/Docker_Image/_get/when_the_image_does_exist/returns_the_new_image.yml +7 -9
- data/spec/vcr/Docker_Image/_history/returns_the_history_of_the_Image.yml +17 -198
- data/spec/vcr/Docker_Image/_import/when_the_argument_is_a_URI/when_the_URI_is_invalid/raises_an_error.yml +26 -30
- data/spec/vcr/Docker_Image/_import/when_the_argument_is_a_URI/when_the_URI_is_valid/returns_an_Image.yml +246 -22
- data/spec/vcr/Docker_Image/_import/when_the_file_does_exist/creates_the_Image.yml +35 -10
- data/spec/vcr/Docker_Image/_insert_local/when_a_direcory_is_passed/inserts_the_directory.yml +1249 -74
- data/spec/vcr/Docker_Image/_insert_local/when_removing_intermediate_containers/creates_a_new_image.yml +84 -94
- data/spec/vcr/Docker_Image/_insert_local/when_removing_intermediate_containers/leave_no_intermediate_containers.yml +70 -92
- data/spec/vcr/Docker_Image/_insert_local/when_the_local_file_does_exist/creates_a_new_Image_that_has_that_file.yml +125 -98
- data/spec/vcr/Docker_Image/_insert_local/when_the_local_file_does_not_exist/raises_an_error.yml +13 -60
- data/spec/vcr/Docker_Image/_insert_local/when_there_are_multiple_files_passed/creates_a_new_Image_that_has_each_file.yml +190 -135
- data/spec/vcr/Docker_Image/_json/returns_additional_information_about_image_image.yml +15 -198
- data/spec/vcr/Docker_Image/_push/pushes_the_Image.yml +169 -264
- data/spec/vcr/Docker_Image/_push/when_there_are_no_credentials/still_pushes.yml +175 -4543
- data/spec/vcr/Docker_Image/_refresh_/updates_the_info_hash.yml +90 -206
- data/spec/vcr/Docker_Image/_remove/when_no_name_is_given/removes_the_Image.yml +300 -0
- data/spec/vcr/Docker_Image/_run/when_the_argument_is_a_String/splits_the_String_by_spaces_and_creates_a_new_Container.yml +77 -207
- data/spec/vcr/Docker_Image/_run/when_the_argument_is_an_Array/creates_a_new_Container.yml +77 -207
- 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 +160 -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 +16 -197
- data/spec/vcr/Docker_Image/_search/materializes_each_Image_into_a_Docker_Image.yml +151 -73
- data/spec/vcr/Docker_Image/_tag/tags_the_image_with_the_repo_name.yml +42 -196
- metadata +67 -41
- data/spec/vcr/Docker_Container/_commit/if_run_is_passed_it_saves_the_command_in_the_image/saves_the_command.yml +0 -58
- data/spec/vcr/Docker_Container/_streaming_logs/when_not_selecting_any_stream/returns_the_error_message.yml +0 -163
- data/spec/vcr/Docker_Container/_wait/when_an_argument_is_given/and_a_command_runs_for_too_long/raises_a_ServerError.yml +0 -58
- data/spec/vcr/Docker_Image/_build_from_dir/with_a_valid_Dockerfile/with_credentials_passed/sends_Docker_creds.yml +0 -41
- data/spec/vcr/Docker_Image/_remove/removes_the_Image.yml +0 -276
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d13e05e91b0dbfbae522e12e17e7a6785347f5b7
|
4
|
+
data.tar.gz: 83e0f7511f3e284747d4cabbbb3a69cf701ed5d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a8f18cbb168d6808180a9adac203a94b37bf82d9bbb43bf9fe9c63fd9dba4b7baab4756cee3a3d9eb30e9cbf0c9a178d6d8506faca9d32656620f162bb5f6571
|
7
|
+
data.tar.gz: dd860931831eceadb0bae490710edbc6f52189c918999b0edb41b2d3c88961a53359bf597eee953869745730279e8d68ec6fa146a3eca06f1395e8e58d26ccda
|
data/README.md
CHANGED
@@ -286,6 +286,32 @@ container.commit
|
|
286
286
|
container.run('pwd', 10)
|
287
287
|
# => Docker::Image { :id => 4427be4199ac, :connection => Docker::Connection { :url => tcp://localhost, :options => {:port=>2375} } }
|
288
288
|
|
289
|
+
# Run an Exec instance inside the container and capture its output
|
290
|
+
container.exec('date')
|
291
|
+
# => [["Wed Nov 26 11:10:30 CST 2014\n"], []]
|
292
|
+
|
293
|
+
# Launch an Exec instance without capturing its output
|
294
|
+
container.exec('./my_service', detach: true)
|
295
|
+
# => Docker::Exec { :id => be4eaeb8d28a, :connection => Docker::Connection { :url => tcp://localhost, :options => {:port=>2375} } }
|
296
|
+
|
297
|
+
# Parse the output of an Exec instance
|
298
|
+
container.exec('find / -name *') { |stream, chunk| puts "#{stream}: #{chunk}" }
|
299
|
+
stderr: 2013/10/30 17:16:24 Unable to locate find / -name *
|
300
|
+
# => [[], ["2013/10/30 17:16:24 Unable to locate find / -name *\n"]]
|
301
|
+
|
302
|
+
# Run an Exec instance by grab only the STDOUT output
|
303
|
+
container.exec('date', stderr: false)
|
304
|
+
# => [["Wed Nov 26 11:10:30 CST 2014\n"], []]
|
305
|
+
|
306
|
+
# Pass input to an Exec instance command via Stdin
|
307
|
+
container.exec('cat', stdin: StringIO.new("foo\nbar\n"))
|
308
|
+
# => [["foo\nbar\n"], []]
|
309
|
+
|
310
|
+
# Get the raw stream of data from an Exec instance
|
311
|
+
command = ["bash", "-c", "if [ -t 1 ]; then echo -n \"I'm a TTY!\"; fi"]
|
312
|
+
container.exec(command, tty: true)
|
313
|
+
# => [["I'm a TTY!"], []]
|
314
|
+
|
289
315
|
# Delete a Container.
|
290
316
|
container.delete(:force => true)
|
291
317
|
# => nil
|
@@ -340,4 +366,3 @@ License
|
|
340
366
|
-----
|
341
367
|
|
342
368
|
This program is licensed under the MIT license. See LICENSE for details.
|
343
|
-
|
data/Rakefile
CHANGED
@@ -15,6 +15,43 @@ Cane::RakeTask.new(:quality) do |cane|
|
|
15
15
|
cane.canefile = '.cane'
|
16
16
|
end
|
17
17
|
|
18
|
+
dir = File.expand_path(File.dirname(__FILE__))
|
19
|
+
namespace :vcr do
|
20
|
+
desc 'Run the full test suite from scratch'
|
21
|
+
task :spec => [:unpack, :record]
|
22
|
+
|
23
|
+
desc 'Download the necessary base images'
|
24
|
+
task :unpack do
|
25
|
+
%w( registry busybox tianon/true scratch ).each do |image|
|
26
|
+
system "docker pull #{image}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
desc 'Run spec tests and record VCR cassettes'
|
31
|
+
task :record do
|
32
|
+
begin
|
33
|
+
FileUtils.remove_dir("#{dir}/spec/vcr", true)
|
34
|
+
registry = Docker::Container.create(
|
35
|
+
'name' => 'registry',
|
36
|
+
'Image' => 'registry',
|
37
|
+
'Env' => ["GUNICORN_OPTS=[--preload]"],
|
38
|
+
'ExposedPorts' => {
|
39
|
+
'5000/tcp' => {}
|
40
|
+
},
|
41
|
+
'HostConfig' => {
|
42
|
+
'PortBindings' => { '5000/tcp' => [{ 'HostPort' => '5000' }] }
|
43
|
+
}
|
44
|
+
)
|
45
|
+
registry.start
|
46
|
+
Rake::Task["spec"].invoke
|
47
|
+
rescue
|
48
|
+
# nothing
|
49
|
+
ensure
|
50
|
+
registry.kill!.remove
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
18
55
|
desc 'Pull an Ubuntu image'
|
19
56
|
image 'ubuntu:13.10' do
|
20
57
|
puts "Pulling ubuntu:13.10"
|
data/TESTING.md
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# Prerequisites
|
2
|
+
To develop on this gem, you must the following installed:
|
3
|
+
* a sane Ruby 1.9+ environment with `bundler`
|
4
|
+
```shell
|
5
|
+
$ gem install bundler
|
6
|
+
```
|
7
|
+
* Docker v1.3.1 or greater
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
# Getting Started
|
12
|
+
1. Clone the git repository from Github:
|
13
|
+
```shell
|
14
|
+
$ git clone git@github.com:swipely/docker-api.git
|
15
|
+
```
|
16
|
+
2. Install the dependencies using Bundler
|
17
|
+
```shell
|
18
|
+
$ bundle install
|
19
|
+
```
|
20
|
+
3. Create a branch for your changes
|
21
|
+
```shell
|
22
|
+
$ git checkout -b my_bug_fix
|
23
|
+
```
|
24
|
+
4. Make any changes
|
25
|
+
5. Write tests to support those changes.
|
26
|
+
6. Run the tests:
|
27
|
+
* `bundle exec rake vcr:test`
|
28
|
+
7. Assuming the tests pass, open a Pull Request on Github.
|
29
|
+
|
30
|
+
# Using Rakefile Commands
|
31
|
+
This repository comes with five Rake commands to assist in your testing of the code.
|
32
|
+
|
33
|
+
## `rake spec`
|
34
|
+
This command will run Rspec tests normally on your local system. Be careful that VCR will behave "weirdly" if you currently have the Docker daemon running.
|
35
|
+
|
36
|
+
## `rake quality`
|
37
|
+
This command runs a code quality threshold checker to hinder bad code.
|
38
|
+
|
39
|
+
## `rake vcr`
|
40
|
+
This gem uses [VCR](https://relishapp.com/vcr/vcr) to record and replay HTTP requests made to the Docker API. The `vcr` namespace is used to record and replay spec tests inside of a Docker container. This will allow each developer to run and rerecord VCR cassettes in a consistent environment.
|
41
|
+
|
42
|
+
### Setting Up Environment Variables
|
43
|
+
Certain Rspec tests will require your credentials to the Docker Hub. If you do not have a Docker Hub account, you can sign up for one [here](https://hub.docker.com/account/signup/). To avoid hard-coding credentials into the code the test suite leverages three Environment Variables: `DOCKER_API_USER`, `DOCKER_API_PASS`, and `DOCKER_API_EMAIL`. You will need to configure your work environment (shell profile, IDE, etc) with these values in order to successfully re-record VCR cassettes.
|
44
|
+
|
45
|
+
```shell
|
46
|
+
export DOCKER_API_USER='your_docker_hub_user'
|
47
|
+
export DOCKER_API_PASS='your_docker_hub_password'
|
48
|
+
export DOCKER_API_EMAIL='your_docker_hub_email_address'
|
49
|
+
```
|
50
|
+
|
51
|
+
### `rake vcr:spec`
|
52
|
+
This command will download the necessary Docker images and then run the Rspec tests while recording your VCR cassettes.
|
53
|
+
|
54
|
+
### `rake vcr:unpack`
|
55
|
+
This command will download the necessary Docker image.
|
56
|
+
|
57
|
+
### `rake vcr:record`
|
58
|
+
This is the command you will use to record a new set of VCR cassettes. This command runs the following procedures:
|
59
|
+
1. Delete the existing `spec/vcr` directory.
|
60
|
+
2. Launch a temporary local Docker registry
|
61
|
+
3. Record new VCR cassettes by running the Rspec test suite against a live Docker daemon.
|
data/lib/docker.rb
CHANGED
@@ -24,6 +24,7 @@ module Docker
|
|
24
24
|
require 'docker/base'
|
25
25
|
require 'docker/container'
|
26
26
|
require 'docker/event'
|
27
|
+
require 'docker/exec'
|
27
28
|
require 'docker/image'
|
28
29
|
require 'docker/messages'
|
29
30
|
require 'docker/util'
|
@@ -78,6 +79,12 @@ module Docker
|
|
78
79
|
@connection ||= Connection.new(url, options)
|
79
80
|
end
|
80
81
|
|
82
|
+
def reset!
|
83
|
+
@url = nil
|
84
|
+
@options = nil
|
85
|
+
reset_connection!
|
86
|
+
end
|
87
|
+
|
81
88
|
def reset_connection!
|
82
89
|
@connection = nil
|
83
90
|
end
|
@@ -113,6 +120,6 @@ module Docker
|
|
113
120
|
|
114
121
|
module_function :default_socket_url, :env_url, :url, :url=, :env_options,
|
115
122
|
:options, :options=, :creds, :creds=, :logger, :logger=,
|
116
|
-
:connection, :reset_connection!, :version, :info,
|
123
|
+
:connection, :reset!, :reset_connection!, :version, :info,
|
117
124
|
:authenticate!, :validate_version!
|
118
125
|
end
|
data/lib/docker/container.rb
CHANGED
@@ -32,6 +32,44 @@ class Docker::Container
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
# Create an Exec instance inside the container
|
36
|
+
#
|
37
|
+
# @param command [String, Array] The command to run inside the Exec instance
|
38
|
+
# @param options [Hash] The options to pass to Docker::Exec
|
39
|
+
#
|
40
|
+
# @return [Docker::Exec] The Exec instance
|
41
|
+
def exec(command, opts = {}, &block)
|
42
|
+
# Establish values
|
43
|
+
tty = opts.delete(:tty) || false
|
44
|
+
detach = opts.delete(:detach) || false
|
45
|
+
stdin = opts.delete(:stdin)
|
46
|
+
stdout = opts.delete(:stdout) || !detach
|
47
|
+
stderr = opts.delete(:stderr) || !detach
|
48
|
+
|
49
|
+
# Create Exec Instance
|
50
|
+
instance = Docker::Exec.create(
|
51
|
+
'Container' => self.id,
|
52
|
+
'AttachStdin' => !!stdin,
|
53
|
+
'AttachStdout' => stdout,
|
54
|
+
'AttachStderr' => stderr,
|
55
|
+
'Tty' => tty,
|
56
|
+
'Cmd' => command
|
57
|
+
)
|
58
|
+
|
59
|
+
start_opts = {
|
60
|
+
:tty => tty,
|
61
|
+
:stdin => stdin,
|
62
|
+
:detach => detach
|
63
|
+
}
|
64
|
+
|
65
|
+
if detach
|
66
|
+
instance.start!(start_opts)
|
67
|
+
return instance
|
68
|
+
else
|
69
|
+
instance.start!(start_opts, &block)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
35
73
|
# Export the Container as a tar.
|
36
74
|
def export(&block)
|
37
75
|
connection.get(path_for(:export), {}, :response_block => block)
|
@@ -55,9 +93,10 @@ class Docker::Container
|
|
55
93
|
# If attaching to stdin, we must hijack the underlying TCP connection
|
56
94
|
# so we can stream stdin to the remote Docker process
|
57
95
|
opts[:stdin] = true
|
58
|
-
excon_params[:hijack_block] = hijack_for(stdin, block,
|
96
|
+
excon_params[:hijack_block] = Docker::Util.hijack_for(stdin, block,
|
97
|
+
msgs, tty)
|
59
98
|
else
|
60
|
-
excon_params[:response_block] = attach_for(block, msgs, tty)
|
99
|
+
excon_params[:response_block] = Docker::Util.attach_for(block, msgs, tty)
|
61
100
|
end
|
62
101
|
|
63
102
|
connection.post(
|
@@ -101,10 +140,10 @@ class Docker::Container
|
|
101
140
|
|
102
141
|
def streaming_logs(opts = {}, &block)
|
103
142
|
msgs = Docker::Messages.new
|
104
|
-
excon_params = {
|
143
|
+
excon_params = {response_block: Docker::Util.attach_for(block, msgs, false)}
|
105
144
|
|
106
145
|
connection.get(path_for(:logs), opts, excon_params)
|
107
|
-
msgs.all_messages.join
|
146
|
+
msgs.all_messages.join
|
108
147
|
end
|
109
148
|
|
110
149
|
def start!(opts = {})
|
@@ -201,81 +240,6 @@ class Docker::Container
|
|
201
240
|
"/containers/#{self.id}/#{resource}"
|
202
241
|
end
|
203
242
|
|
204
|
-
|
205
|
-
attach_block = attach_for(block, msg_stack, tty)
|
206
|
-
|
207
|
-
lambda do |socket|
|
208
|
-
debug "hijack: hijacking the HTTP socket"
|
209
|
-
threads = []
|
210
|
-
|
211
|
-
debug "hijack: starting stdin copy thread"
|
212
|
-
threads << Thread.start do
|
213
|
-
debug "hijack: copying stdin => socket"
|
214
|
-
IO.copy_stream stdin, socket
|
215
|
-
|
216
|
-
debug "hijack: closing write end of hijacked socket"
|
217
|
-
socket.close_write
|
218
|
-
end
|
219
|
-
|
220
|
-
debug "hijack: starting hijacked socket read thread"
|
221
|
-
threads << Thread.start do
|
222
|
-
debug "hijack: reading from hijacked socket"
|
223
|
-
|
224
|
-
begin
|
225
|
-
while chunk = socket.readpartial(512)
|
226
|
-
debug "hijack: got #{chunk.bytesize} bytes from hijacked socket"
|
227
|
-
attach_block.call chunk, nil, nil
|
228
|
-
end
|
229
|
-
rescue EOFError
|
230
|
-
end
|
231
|
-
|
232
|
-
debug "hijack: killing stdin copy thread"
|
233
|
-
threads.first.kill
|
234
|
-
end
|
235
|
-
|
236
|
-
threads.each(&:join)
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
# Method that takes chunks and calls the attached block for each mux'd message
|
241
|
-
def attach_for(block, msg_stack, tty)
|
242
|
-
# If TTY is enabled expect raw data and append to stdout
|
243
|
-
if tty
|
244
|
-
attach_for_tty(block, msg_stack)
|
245
|
-
else
|
246
|
-
attach_for_multiplex(block, msg_stack)
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
def attach_for_tty(block, msg_stack)
|
251
|
-
return lambda do |c,r,t|
|
252
|
-
msg_stack.stdout_messages << c
|
253
|
-
msg_stack.all_messages << c
|
254
|
-
block.call c if block
|
255
|
-
end
|
256
|
-
end
|
257
|
-
|
258
|
-
def attach_for_multiplex(block, msg_stack)
|
259
|
-
messages = Docker::Messages.new
|
260
|
-
lambda do |c,r,t|
|
261
|
-
messages = messages.decipher_messages(c)
|
262
|
-
msg_stack.append(messages)
|
263
|
-
|
264
|
-
unless block.nil?
|
265
|
-
messages.stdout_messages.each do |msg|
|
266
|
-
block.call(:stdout, msg)
|
267
|
-
end
|
268
|
-
messages.stderr_messages.each do |msg|
|
269
|
-
block.call(:stderr, msg)
|
270
|
-
end
|
271
|
-
end
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
|
-
def debug(msg)
|
276
|
-
Docker.logger.debug(msg) if Docker.logger
|
277
|
-
end
|
278
|
-
|
279
|
-
private :path_for, :attach_for, :attach_for_tty, :attach_for_multiplex, :debug
|
243
|
+
private :path_for
|
280
244
|
private_class_method :new
|
281
245
|
end
|
data/lib/docker/exec.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# This class represents a Docker Exec Instance.
|
2
|
+
class Docker::Exec
|
3
|
+
include Docker::Base
|
4
|
+
|
5
|
+
# Convert details about the object into a string
|
6
|
+
#
|
7
|
+
# @return [String] String representation of the Exec instance object
|
8
|
+
def to_s
|
9
|
+
"Docker::Exec { :id => #{self.id}, :connection => #{self.connection} }"
|
10
|
+
end
|
11
|
+
|
12
|
+
# Create a new Exec instance in a running container. Please note, this does
|
13
|
+
# NOT execute the instance - you must run #start. Also, each instance is
|
14
|
+
# one-time use only.
|
15
|
+
#
|
16
|
+
# @param options [Hash] Parameters to pass in to the API.
|
17
|
+
# @param conn [Docker::Connection] Connection to Docker Remote API
|
18
|
+
#
|
19
|
+
# @return [Docker::Exec] self
|
20
|
+
def self.create(options = {}, conn = Docker.connection)
|
21
|
+
container = options.delete('Container')
|
22
|
+
resp = conn.post("/containers/#{container}/exec", {},
|
23
|
+
:body => options.to_json)
|
24
|
+
hash = Docker::Util.parse_json(resp) || {}
|
25
|
+
new(conn, hash)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Start the Exec instance. The Exec instance is deleted after this so this
|
29
|
+
# command can only be run once.
|
30
|
+
#
|
31
|
+
# @param options [Hash] Options to dictate behavior of the instance
|
32
|
+
# @option options [Object] :stdin (nil) The object to pass to STDIN.
|
33
|
+
# @option options [TrueClass, FalseClass] :detach (false) Whether to attach
|
34
|
+
# to STDOUT/STDERR.
|
35
|
+
# @option options [TrueClass, FalseClass] :tty (false) Whether to attach using
|
36
|
+
# a pseudo-TTY.
|
37
|
+
#
|
38
|
+
# @return [Array, Array] The STDOUT and STDERR responses
|
39
|
+
def start!(options = {}, &block)
|
40
|
+
|
41
|
+
# Parse the Options
|
42
|
+
tty = !!options.delete(:tty)
|
43
|
+
detached = !!options.delete(:detach)
|
44
|
+
stdin = options[:stdin]
|
45
|
+
|
46
|
+
# Create API Request Body
|
47
|
+
body = {
|
48
|
+
"Tty" => tty,
|
49
|
+
"Detach" => detached
|
50
|
+
}
|
51
|
+
excon_params = { :body => body.to_json }
|
52
|
+
|
53
|
+
msgs = Docker::Messages.new
|
54
|
+
unless detached
|
55
|
+
if stdin
|
56
|
+
excon_params[:hijack_block] = Docker::Util.hijack_for(stdin, block,
|
57
|
+
msgs, tty)
|
58
|
+
else
|
59
|
+
excon_params[:response_block] = Docker::Util.attach_for(block,
|
60
|
+
msgs, tty)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
connection.post(path_for(:start), nil, excon_params)
|
65
|
+
[msgs.stdout_messages, msgs.stderr_messages]
|
66
|
+
end
|
67
|
+
|
68
|
+
# #start! performs the associated action and returns the output.
|
69
|
+
# #start does the same, but rescues from ServerErrors.
|
70
|
+
[:start].each do |method|
|
71
|
+
define_method(method) do |*args|
|
72
|
+
begin; public_send(:"#{method}!", *args); rescue ServerError; self end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Resize the TTY associated with the Exec instance
|
77
|
+
#
|
78
|
+
# @param query [Hash] API query parameters
|
79
|
+
# @option query [Fixnum] h Height of the TTY
|
80
|
+
# @option query [Fixnum] w Width of the TTY
|
81
|
+
#
|
82
|
+
# @return [Docker::Exec] self
|
83
|
+
def resize(query = {})
|
84
|
+
connection.post(path_for(:resize), query)
|
85
|
+
self
|
86
|
+
end
|
87
|
+
|
88
|
+
# Get the request URI for the given endpoint
|
89
|
+
#
|
90
|
+
# @param endpoint [Symbol] The endpoint to grab
|
91
|
+
# @return [String] The full Remote API endpoint with ID
|
92
|
+
def path_for(endpoint)
|
93
|
+
"/exec/#{self.id}/#{endpoint}"
|
94
|
+
end
|
95
|
+
|
96
|
+
private :path_for
|
97
|
+
private_class_method :new
|
98
|
+
end
|
data/lib/docker/image.rb
CHANGED
@@ -23,7 +23,7 @@ class Docker::Image
|
|
23
23
|
|
24
24
|
# Push the Image to the Docker registry.
|
25
25
|
def push(creds = nil, options = {})
|
26
|
-
repo_tag = info['RepoTags'].first
|
26
|
+
repo_tag = options.delete(:repo_tag) || info['RepoTags'].first
|
27
27
|
raise ArgumentError "Image is untagged" if repo_tag.nil?
|
28
28
|
repo, tag = Docker::Util.parse_repo_tag(repo_tag)
|
29
29
|
raise ArgumentError, "Image does not have a name to push." if repo.nil?
|
@@ -63,7 +63,8 @@ class Docker::Image
|
|
63
63
|
|
64
64
|
# Remove the Image from the server.
|
65
65
|
def remove(opts = {})
|
66
|
-
|
66
|
+
name = opts.delete(:name) || self.id
|
67
|
+
connection.delete("/images/#{name}", opts)
|
67
68
|
end
|
68
69
|
alias_method :delete, :remove
|
69
70
|
|
@@ -211,7 +212,7 @@ end
|
|
211
212
|
|
212
213
|
# A method to build the config header and merge it into the
|
213
214
|
# headers sent by build_from_dir.
|
214
|
-
def self.build_headers(creds)
|
215
|
+
def self.build_headers(creds=nil)
|
215
216
|
credentials = creds || Docker.creds || {}
|
216
217
|
config_header = Docker::Util.build_config_header(credentials)
|
217
218
|
|