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