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.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +26 -1
  3. data/Rakefile +37 -0
  4. data/TESTING.md +61 -0
  5. data/lib/docker.rb +8 -1
  6. data/lib/docker/container.rb +44 -80
  7. data/lib/docker/exec.rb +98 -0
  8. data/lib/docker/image.rb +4 -3
  9. data/lib/docker/util.rb +79 -0
  10. data/lib/docker/version.rb +2 -2
  11. data/spec/docker/container_spec.rb +192 -56
  12. data/spec/docker/event_spec.rb +4 -4
  13. data/spec/docker/exec_spec.rb +197 -0
  14. data/spec/docker/image_spec.rb +131 -102
  15. data/spec/docker_spec.rb +37 -27
  16. data/spec/fixtures/build_from_dir/Dockerfile +2 -2
  17. data/spec/fixtures/export.tar +0 -0
  18. data/spec/fixtures/top/Dockerfile +2 -2
  19. data/spec/spec_helper.rb +10 -0
  20. data/spec/support/vcr.rb +5 -0
  21. data/spec/vcr/Docker/_authenticate_/with_valid_credentials/logs_in_and_sets_the_creds.yml +6 -8
  22. data/spec/vcr/Docker/_info/returns_the_info_as_a_Hash.yml +7 -9
  23. data/spec/vcr/Docker/_validate_version/when_nothing_is_raised/validate_version_/.yml +7 -9
  24. data/spec/vcr/Docker/_version/returns_the_version_as_a_Hash.yml +7 -9
  25. data/spec/vcr/Docker_Container/_all/when_the_HTTP_response_is_a_200/materializes_each_Container_into_a_Docker_Container.yml +46 -139
  26. data/spec/vcr/Docker_Container/_attach/with_normal_sized_chunks/yields_each_chunk.yml +62 -20
  27. data/spec/vcr/Docker_Container/_attach/with_very_small_chunks/yields_each_chunk.yml +62 -20
  28. data/spec/vcr/Docker_Container/_changes/returns_the_changes_as_an_array.yml +71 -28
  29. data/spec/vcr/Docker_Container/_commit/creates_a_new_Image_from_the_Container_s_changes.yml +69 -23
  30. data/spec/vcr/Docker_Container/_copy/when_the_file_does_not_exist/raises_an_error.yml +134 -0
  31. data/spec/vcr/Docker_Container/_copy/when_the_input_is_a_directory/yields_each_chunk_of_the_tarred_directory.yml +73 -290
  32. data/spec/vcr/Docker_Container/_copy/when_the_input_is_a_file/yields_each_chunk_of_the_tarred_file.yml +51 -211
  33. data/spec/vcr/Docker_Container/_create/when_creating_a_container_named_bob/should_have_name_set_to_bob.yml +36 -17
  34. 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
  35. data/spec/vcr/Docker_Container/_delete/deletes_the_container.yml +17 -23
  36. data/spec/vcr/Docker_Container/_exec/when_detach_is_true/returns_the_Docker_Exec_object.yml +151 -0
  37. data/spec/vcr/Docker_Container/_exec/when_passed_a_block/streams_the_stdout/stderr_messages.yml +153 -0
  38. data/spec/vcr/Docker_Container/_exec/when_passed_only_a_command/returns_the_stdout/stderr_messages.yml +153 -0
  39. data/spec/vcr/Docker_Container/_exec/when_stdin_object_is_passed/returns_the_stdout/stderr_messages.yml +100 -0
  40. data/spec/vcr/Docker_Container/_exec/when_tty_is_true/returns_the_raw_stdout/stderr_output.yml +152 -0
  41. data/spec/vcr/Docker_Container/_export/yields_each_chunk.yml +263 -28
  42. data/spec/vcr/Docker_Container/_get/when_the_HTTP_response_is_a_200/materializes_the_Container_into_a_Docker_Container.yml +36 -17
  43. data/spec/vcr/Docker_Container/_json/returns_the_description_as_a_Hash.yml +36 -17
  44. data/spec/vcr/Docker_Container/_kill/kills_the_container.yml +55 -53
  45. data/spec/vcr/Docker_Container/_kill/with_a_kill_signal/kills_the_container.yml +74 -96
  46. data/spec/vcr/Docker_Container/_logs/when_not_selecting_any_stream/raises_a_client_error.yml +84 -81
  47. data/spec/vcr/Docker_Container/_logs/when_selecting_stdout/returns_blank_logs.yml +34 -15
  48. data/spec/vcr/Docker_Container/_pause/pauses_the_container.yml +98 -45
  49. data/spec/vcr/Docker_Container/_restart/restarts_the_container.yml +88 -56
  50. data/spec/vcr/Docker_Container/_run/when_the_Container_s_command_does_not_return_status_code_of_0/raises_an_error.yml +39 -22
  51. 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
  52. data/spec/vcr/Docker_Container/_start/starts_the_container.yml +45 -30
  53. data/spec/vcr/Docker_Container/_stop/stops_the_container.yml +54 -83
  54. data/spec/vcr/Docker_Container/_streaming_logs/when_not_selecting_any_stream/raises_a_client_error.yml +84 -81
  55. data/spec/vcr/Docker_Container/_streaming_logs/when_selecting_stdout/returns_blank_logs.yml +46 -30
  56. data/spec/vcr/Docker_Container/_top/returns_the_top_commands_as_an_Array.yml +103 -40
  57. data/spec/vcr/Docker_Container/_unpause/unpauses_the_container.yml +81 -57
  58. data/spec/vcr/Docker_Container/_wait/waits_for_the_command_to_finish.yml +39 -22
  59. data/spec/vcr/Docker_Container/_wait/when_an_argument_is_given/sets_the_read_timeout_to_that_amount_of_time.yml +39 -22
  60. data/spec/vcr/Docker_Exec/_create/when_the_HTTP_request_returns_a_201/sets_the_id.yml +128 -0
  61. data/spec/vcr/Docker_Exec/_resize/when_exec_instance_has_TTY_enabled/returns_a_200.yml +155 -0
  62. data/spec/vcr/Docker_Exec/_start_/when_detach_is_set_to_false/block_is_passed/attaches_to_the_stream.yml +152 -0
  63. data/spec/vcr/Docker_Exec/_start_/when_detach_is_set_to_false/returns_the_stdout_and_stderr_messages.yml +152 -0
  64. data/spec/vcr/Docker_Exec/_start_/when_detach_is_set_to_true/returns_empty_stdout_and_stderr_messages.yml +151 -0
  65. data/spec/vcr/Docker_Exec/_start_/when_the_HTTP_request_returns_a_201/starts_the_exec_instance.yml +151 -0
  66. data/spec/vcr/Docker_Exec/_start_/when_the_command_has_already_run/raises_an_error.yml +151 -0
  67. data/spec/vcr/Docker_Image/_all/materializes_each_Image_into_a_Docker_Image.yml +86 -200
  68. 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
  69. 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
  70. data/spec/vcr/Docker_Image/_build/with_a_valid_Dockerfile/without_query_parameters/builds_an_image.yml +10 -14
  71. data/spec/vcr/Docker_Image/_build/with_an_invalid_Dockerfile/throws_a_UnexpectedResponseError.yml +12 -14
  72. 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
  73. data/spec/vcr/Docker_Image/_build_from_dir/with_a_valid_Dockerfile/with_credentials_passed/sends_X-Registry-Config_header.yml +118 -14
  74. data/spec/vcr/Docker_Image/_build_from_dir/with_a_valid_Dockerfile/with_no_query_parameters/builds_the_image.yml +109 -37
  75. 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
  76. 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
  77. data/spec/vcr/Docker_Image/_exist_/when_the_image_does_exist/returns_true.yml +12 -19
  78. data/spec/vcr/Docker_Image/_get/when_the_image_does_exist/returns_the_new_image.yml +7 -9
  79. data/spec/vcr/Docker_Image/_history/returns_the_history_of_the_Image.yml +17 -198
  80. data/spec/vcr/Docker_Image/_import/when_the_argument_is_a_URI/when_the_URI_is_invalid/raises_an_error.yml +26 -30
  81. data/spec/vcr/Docker_Image/_import/when_the_argument_is_a_URI/when_the_URI_is_valid/returns_an_Image.yml +246 -22
  82. data/spec/vcr/Docker_Image/_import/when_the_file_does_exist/creates_the_Image.yml +35 -10
  83. data/spec/vcr/Docker_Image/_insert_local/when_a_direcory_is_passed/inserts_the_directory.yml +1249 -74
  84. data/spec/vcr/Docker_Image/_insert_local/when_removing_intermediate_containers/creates_a_new_image.yml +84 -94
  85. data/spec/vcr/Docker_Image/_insert_local/when_removing_intermediate_containers/leave_no_intermediate_containers.yml +70 -92
  86. data/spec/vcr/Docker_Image/_insert_local/when_the_local_file_does_exist/creates_a_new_Image_that_has_that_file.yml +125 -98
  87. data/spec/vcr/Docker_Image/_insert_local/when_the_local_file_does_not_exist/raises_an_error.yml +13 -60
  88. data/spec/vcr/Docker_Image/_insert_local/when_there_are_multiple_files_passed/creates_a_new_Image_that_has_each_file.yml +190 -135
  89. data/spec/vcr/Docker_Image/_json/returns_additional_information_about_image_image.yml +15 -198
  90. data/spec/vcr/Docker_Image/_push/pushes_the_Image.yml +169 -264
  91. data/spec/vcr/Docker_Image/_push/when_there_are_no_credentials/still_pushes.yml +175 -4543
  92. data/spec/vcr/Docker_Image/_refresh_/updates_the_info_hash.yml +90 -206
  93. data/spec/vcr/Docker_Image/_remove/when_no_name_is_given/removes_the_Image.yml +300 -0
  94. 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
  95. data/spec/vcr/Docker_Image/_run/when_the_argument_is_an_Array/creates_a_new_Container.yml +77 -207
  96. 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
  97. 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
  98. data/spec/vcr/Docker_Image/_search/materializes_each_Image_into_a_Docker_Image.yml +151 -73
  99. data/spec/vcr/Docker_Image/_tag/tags_the_image_with_the_repo_name.yml +42 -196
  100. metadata +67 -41
  101. data/spec/vcr/Docker_Container/_commit/if_run_is_passed_it_saves_the_command_in_the_image/saves_the_command.yml +0 -58
  102. data/spec/vcr/Docker_Container/_streaming_logs/when_not_selecting_any_stream/returns_the_error_message.yml +0 -163
  103. data/spec/vcr/Docker_Container/_wait/when_an_argument_is_given/and_a_command_runs_for_too_long/raises_a_ServerError.yml +0 -58
  104. data/spec/vcr/Docker_Image/_build_from_dir/with_a_valid_Dockerfile/with_credentials_passed/sends_Docker_creds.yml +0 -41
  105. 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: 026147324341d46ecc633b106fa941316435e612
4
- data.tar.gz: c9022722fa623436a9a7f5b5ece2383c946eb21d
3
+ metadata.gz: d13e05e91b0dbfbae522e12e17e7a6785347f5b7
4
+ data.tar.gz: 83e0f7511f3e284747d4cabbbb3a69cf701ed5d4
5
5
  SHA512:
6
- metadata.gz: 0361890e0d8bd23b86c4b1cc362a4f7d5f327222ea0261c8a1159daaa331f5b7b90d5a93e8142558fd2e514b5d22ff7481fa80b60fc6fb64a55c6868e6bff1b6
7
- data.tar.gz: 4d22cb2d2fb45120b9a7485e4be4e8a35b56085287c397ae624be1d6c6036acfe4cbb57879afa096fa8089d3e03524f54542841c9ae626087611086fee07a57f
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"
@@ -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.
@@ -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
@@ -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, msgs, tty)
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 = { response_block: attach_for(block, msgs, false) }
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("\n")
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
- def hijack_for(stdin, block, msg_stack, tty)
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
@@ -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
@@ -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
- connection.delete("/images/#{self.id}", opts)
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