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
data/lib/docker/util.rb
CHANGED
@@ -5,6 +5,85 @@ module Docker::Util
|
|
5
5
|
|
6
6
|
module_function
|
7
7
|
|
8
|
+
# Attaches to a HTTP stream
|
9
|
+
#
|
10
|
+
# @param block
|
11
|
+
# @param msg_stack [Docker::Messages]
|
12
|
+
# @param tty [boolean]
|
13
|
+
def attach_for(block, msg_stack, tty = false)
|
14
|
+
# If TTY is enabled expect raw data and append to stdout
|
15
|
+
if tty
|
16
|
+
attach_for_tty(block, msg_stack)
|
17
|
+
else
|
18
|
+
attach_for_multiplex(block, msg_stack)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def attach_for_tty(block, msg_stack)
|
23
|
+
return lambda do |c,r,t|
|
24
|
+
msg_stack.stdout_messages << c
|
25
|
+
msg_stack.all_messages << c
|
26
|
+
block.call c if block
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def attach_for_multiplex(block, msg_stack)
|
31
|
+
messages = Docker::Messages.new
|
32
|
+
lambda do |c,r,t|
|
33
|
+
messages = messages.decipher_messages(c)
|
34
|
+
msg_stack.append(messages)
|
35
|
+
|
36
|
+
unless block.nil?
|
37
|
+
messages.stdout_messages.each do |msg|
|
38
|
+
block.call(:stdout, msg)
|
39
|
+
end
|
40
|
+
messages.stderr_messages.each do |msg|
|
41
|
+
block.call(:stderr, msg)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def debug(msg)
|
48
|
+
Docker.logger.debug(msg) if Docker.logger
|
49
|
+
end
|
50
|
+
|
51
|
+
def hijack_for(stdin, block, msg_stack, tty)
|
52
|
+
attach_block = attach_for(block, msg_stack, tty)
|
53
|
+
|
54
|
+
lambda do |socket|
|
55
|
+
debug "hijack: hijacking the HTTP socket"
|
56
|
+
threads = []
|
57
|
+
|
58
|
+
debug "hijack: starting stdin copy thread"
|
59
|
+
threads << Thread.start do
|
60
|
+
debug "hijack: copying stdin => socket"
|
61
|
+
IO.copy_stream stdin, socket
|
62
|
+
|
63
|
+
debug "hijack: closing write end of hijacked socket"
|
64
|
+
socket.close_write
|
65
|
+
end
|
66
|
+
|
67
|
+
debug "hijack: starting hijacked socket read thread"
|
68
|
+
threads << Thread.start do
|
69
|
+
debug "hijack: reading from hijacked socket"
|
70
|
+
|
71
|
+
begin
|
72
|
+
while chunk = socket.readpartial(512)
|
73
|
+
debug "hijack: got #{chunk.bytesize} bytes from hijacked socket"
|
74
|
+
attach_block.call chunk, nil, nil
|
75
|
+
end
|
76
|
+
rescue EOFError
|
77
|
+
end
|
78
|
+
|
79
|
+
debug "hijack: killing stdin copy thread"
|
80
|
+
threads.first.kill
|
81
|
+
end
|
82
|
+
|
83
|
+
threads.each(&:join)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
8
87
|
def parse_json(body)
|
9
88
|
JSON.parse(body) unless body.nil? || body.empty? || (body == 'null')
|
10
89
|
rescue JSON::ParserError => ex
|
data/lib/docker/version.rb
CHANGED
@@ -24,8 +24,11 @@ describe Docker::Container do
|
|
24
24
|
end
|
25
25
|
|
26
26
|
describe '#json' do
|
27
|
-
subject {
|
27
|
+
subject {
|
28
|
+
described_class.create('Cmd' => %w[true], 'Image' => 'debian:wheezy')
|
29
|
+
}
|
28
30
|
let(:description) { subject.json }
|
31
|
+
after(:each) { subject.remove }
|
29
32
|
|
30
33
|
it 'returns the description as a Hash', :vcr do
|
31
34
|
expect(description).to be_a Hash
|
@@ -34,7 +37,10 @@ describe Docker::Container do
|
|
34
37
|
end
|
35
38
|
|
36
39
|
describe '#streaming_logs' do
|
37
|
-
subject {
|
40
|
+
subject {
|
41
|
+
described_class.create('Cmd' => "echo hello", 'Image' => 'debian:wheezy')
|
42
|
+
}
|
43
|
+
after(:each) { subject.remove }
|
38
44
|
|
39
45
|
context "when not selecting any stream" do
|
40
46
|
let(:non_destination) { subject.logs }
|
@@ -53,7 +59,10 @@ describe Docker::Container do
|
|
53
59
|
end
|
54
60
|
|
55
61
|
describe '#logs' do
|
56
|
-
subject {
|
62
|
+
subject {
|
63
|
+
described_class.create('Cmd' => "echo hello", 'Image' => 'debian:wheezy')
|
64
|
+
}
|
65
|
+
after(:each) { subject.remove }
|
57
66
|
|
58
67
|
context "when not selecting any stream" do
|
59
68
|
let(:non_destination) { subject.logs }
|
@@ -73,11 +82,15 @@ describe Docker::Container do
|
|
73
82
|
|
74
83
|
describe '#create' do
|
75
84
|
subject {
|
76
|
-
described_class.create({
|
85
|
+
described_class.create({
|
86
|
+
'Cmd' => %w[true],
|
87
|
+
'Image' => 'debian:wheezy'
|
88
|
+
}.merge(opts))
|
77
89
|
}
|
78
90
|
|
79
91
|
context 'when creating a container named bob' do
|
80
92
|
let(:opts) { {"name" => "bob"} }
|
93
|
+
after(:each) { subject.remove }
|
81
94
|
|
82
95
|
it 'should have name set to bob', :vcr do
|
83
96
|
expect(subject.json["Name"]).to eq "/bob"
|
@@ -87,11 +100,15 @@ describe Docker::Container do
|
|
87
100
|
|
88
101
|
describe '#changes' do
|
89
102
|
subject {
|
90
|
-
described_class.create(
|
103
|
+
described_class.create(
|
104
|
+
'Cmd' => %w[rm -rf /root],
|
105
|
+
'Image' => 'debian:wheezy'
|
106
|
+
)
|
91
107
|
}
|
92
108
|
let(:changes) { subject.changes }
|
93
109
|
|
94
110
|
before { subject.tap(&:start).tap(&:wait) }
|
111
|
+
after(:each) { subject.tap(&:wait).remove }
|
95
112
|
|
96
113
|
it 'returns the changes as an array', :vcr do
|
97
114
|
expect(changes).to eq [
|
@@ -110,26 +127,29 @@ describe Docker::Container do
|
|
110
127
|
let(:image) { Docker::Image.build_from_dir(dir) }
|
111
128
|
let(:top) { sleep 1; container.top }
|
112
129
|
let!(:container) { image.run('/while') }
|
130
|
+
after do
|
131
|
+
container.kill!.remove
|
132
|
+
image.remove
|
133
|
+
end
|
113
134
|
|
114
135
|
it 'returns the top commands as an Array', :vcr do
|
115
136
|
expect(top).to be_a Array
|
116
137
|
expect(top).to_not be_empty
|
117
|
-
expect(top.first.keys).to
|
138
|
+
expect(top.first.keys).to include('PID')
|
118
139
|
end
|
119
140
|
end
|
120
141
|
|
121
142
|
describe '#copy' do
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
}
|
143
|
+
let(:image) { Docker::Image.create('fromImage' => 'debian:wheezy') }
|
144
|
+
subject { image.run('touch /test').tap { |c| c.wait } }
|
145
|
+
|
146
|
+
after(:each) { subject.remove }
|
127
147
|
|
128
148
|
context 'when the file does not exist' do
|
129
149
|
it 'raises an error', :vcr do
|
130
150
|
skip 'Docker no longer returns a 500 when the file does not exist'
|
131
|
-
expect { subject.copy('/lol/not/a/real/file') { |chunk| puts chunk } }
|
132
|
-
|
151
|
+
# expect { subject.copy('/lol/not/a/real/file') { |chunk| puts chunk } }
|
152
|
+
# .to raise_error
|
133
153
|
end
|
134
154
|
end
|
135
155
|
|
@@ -145,21 +165,19 @@ describe Docker::Container do
|
|
145
165
|
context 'when the input is a directory' do
|
146
166
|
it 'yields each chunk of the tarred directory', :vcr do
|
147
167
|
chunks = []
|
148
|
-
subject.copy('/etc/
|
168
|
+
subject.copy('/etc/logrotate.d') { |chunk| chunks << chunk }
|
149
169
|
chunks = chunks.join("\n")
|
150
|
-
expect(%w[
|
170
|
+
expect(%w[apt dpkg]).to be_all { |file| chunks.include?(file) }
|
151
171
|
end
|
152
172
|
end
|
153
173
|
end
|
154
174
|
|
155
175
|
describe '#export' do
|
156
176
|
subject { described_class.create('Cmd' => %w[rm -rf / --no-preserve-root],
|
157
|
-
'Image' => '
|
177
|
+
'Image' => 'tianon/true') }
|
158
178
|
before { subject.start }
|
179
|
+
after { subject.tap(&:wait).remove }
|
159
180
|
|
160
|
-
# If you have to re-record this VCR, PLEASE edit it so that it's only ~200
|
161
|
-
# lines. This is only because we don't want our gem to be a few hundred
|
162
|
-
# megabytes.
|
163
181
|
it 'yields each chunk', :vcr do
|
164
182
|
first = nil
|
165
183
|
subject.export do |chunk|
|
@@ -170,9 +188,15 @@ describe Docker::Container do
|
|
170
188
|
end
|
171
189
|
|
172
190
|
describe '#attach' do
|
173
|
-
subject {
|
191
|
+
subject {
|
192
|
+
described_class.create(
|
193
|
+
'Cmd' => ['bash','-c','sleep 2; echo hello'],
|
194
|
+
'Image' => 'debian:wheezy'
|
195
|
+
)
|
196
|
+
}
|
174
197
|
|
175
198
|
before { subject.start }
|
199
|
+
after(:each) { subject.stop.remove }
|
176
200
|
|
177
201
|
context 'with normal sized chunks' do
|
178
202
|
it 'yields each chunk', :vcr do
|
@@ -180,7 +204,7 @@ describe Docker::Container do
|
|
180
204
|
subject.attach do |stream, c|
|
181
205
|
chunk ||= c
|
182
206
|
end
|
183
|
-
expect(chunk).to eq("
|
207
|
+
expect(chunk).to eq("hello\n")
|
184
208
|
end
|
185
209
|
end
|
186
210
|
|
@@ -198,7 +222,7 @@ describe Docker::Container do
|
|
198
222
|
subject.attach do |stream, c|
|
199
223
|
chunk ||= c
|
200
224
|
end
|
201
|
-
expect(chunk).to eq("
|
225
|
+
expect(chunk).to eq("hello\n")
|
202
226
|
end
|
203
227
|
end
|
204
228
|
end
|
@@ -211,7 +235,7 @@ describe Docker::Container do
|
|
211
235
|
skip 'HTTP socket hijacking not compatible with VCR'
|
212
236
|
container = described_class.create(
|
213
237
|
'Cmd' => %w[cat],
|
214
|
-
'Image' => '
|
238
|
+
'Image' => 'debian:wheezy',
|
215
239
|
'OpenStdin' => true,
|
216
240
|
'StdinOnce' => true
|
217
241
|
)
|
@@ -227,13 +251,14 @@ describe Docker::Container do
|
|
227
251
|
subject {
|
228
252
|
described_class.create(
|
229
253
|
'Cmd' => %w[test -d /foo],
|
230
|
-
'Image' => '
|
254
|
+
'Image' => 'debian:wheezy',
|
231
255
|
'Volumes' => {'/foo' => {}}
|
232
256
|
)
|
233
257
|
}
|
234
258
|
let(:all) { Docker::Container.all }
|
235
259
|
|
236
260
|
before { subject.start('Binds' => ["/tmp:/foo"]) }
|
261
|
+
after(:each) { subject.remove }
|
237
262
|
|
238
263
|
it 'starts the container', :vcr do
|
239
264
|
expect(all.map(&:id)).to be_any { |id| id.start_with?(subject.id) }
|
@@ -242,9 +267,12 @@ describe Docker::Container do
|
|
242
267
|
end
|
243
268
|
|
244
269
|
describe '#stop' do
|
245
|
-
subject {
|
270
|
+
subject {
|
271
|
+
described_class.create('Cmd' => %w[true], 'Image' => 'debian:wheezy')
|
272
|
+
}
|
246
273
|
|
247
274
|
before { subject.tap(&:start).stop('timeout' => '10') }
|
275
|
+
after { subject.remove }
|
248
276
|
|
249
277
|
it 'stops the container', :vcr do
|
250
278
|
expect(described_class.all(:all => true).map(&:id)).to be_any { |id|
|
@@ -256,13 +284,72 @@ describe Docker::Container do
|
|
256
284
|
end
|
257
285
|
end
|
258
286
|
|
287
|
+
describe '#exec' do
|
288
|
+
subject {
|
289
|
+
described_class.create(
|
290
|
+
'Cmd' => %w[sleep 20],
|
291
|
+
'Image' => 'debian:wheezy'
|
292
|
+
).start
|
293
|
+
}
|
294
|
+
after { subject.kill!.remove }
|
295
|
+
|
296
|
+
context 'when passed only a command' do
|
297
|
+
let(:output) { subject.exec(['bash','-c','sleep 2; echo hello']) }
|
298
|
+
|
299
|
+
it 'returns the stdout/stderr messages', :vcr do
|
300
|
+
expect(output).to eq([["hello\n"], []])
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
context 'when detach is true' do
|
305
|
+
let(:output) { subject.exec('date', detach: true) }
|
306
|
+
|
307
|
+
it 'returns the Docker::Exec object', :vcr do
|
308
|
+
expect(output).to be_a Docker::Exec
|
309
|
+
expect(output.id).to_not be_nil
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
context 'when passed a block' do
|
314
|
+
it 'streams the stdout/stderr messages', :vcr do
|
315
|
+
chunk = nil
|
316
|
+
subject.exec(['bash','-c','sleep 2; echo hello']) do |stream, c|
|
317
|
+
chunk ||= c
|
318
|
+
end
|
319
|
+
expect(chunk).to eq("hello\n")
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
context 'when stdin object is passed' do
|
324
|
+
let(:output) { subject.exec('cat', stdin: StringIO.new("hello")) }
|
325
|
+
|
326
|
+
it 'returns the stdout/stderr messages', :vcr do
|
327
|
+
skip 'HTTP socket hijacking not compatible with VCR'
|
328
|
+
expect(output).to eq([["hello"],[]])
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
context 'when tty is true' do
|
333
|
+
let(:command) { [
|
334
|
+
"bash", "-c",
|
335
|
+
"if [ -t 1 ]; then echo -n \"I'm a TTY!\"; fi"
|
336
|
+
] }
|
337
|
+
let(:output) { subject.exec(command, tty: true) }
|
338
|
+
|
339
|
+
it 'returns the raw stdout/stderr output', :vcr do
|
340
|
+
expect(output).to eq([["I'm a TTY!"], []])
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
259
345
|
describe '#kill' do
|
260
346
|
let(:command) { ['/bin/bash', '-c', 'while [ 1 ]; do echo hello; done'] }
|
261
|
-
subject {
|
347
|
+
subject {
|
348
|
+
described_class.create('Cmd' => command, 'Image' => 'debian:wheezy')
|
349
|
+
}
|
262
350
|
|
263
|
-
before
|
264
|
-
|
265
|
-
end
|
351
|
+
before { subject.start }
|
352
|
+
after(:each) {subject.remove }
|
266
353
|
|
267
354
|
it 'kills the container', :vcr do
|
268
355
|
subject.kill
|
@@ -303,7 +390,9 @@ describe Docker::Container do
|
|
303
390
|
end
|
304
391
|
|
305
392
|
describe '#delete' do
|
306
|
-
subject {
|
393
|
+
subject {
|
394
|
+
described_class.create('Cmd' => ['ls'], 'Image' => 'debian:wheezy')
|
395
|
+
}
|
307
396
|
|
308
397
|
it 'deletes the container', :vcr do
|
309
398
|
subject.delete(:force => true)
|
@@ -314,9 +403,12 @@ describe Docker::Container do
|
|
314
403
|
end
|
315
404
|
|
316
405
|
describe '#restart' do
|
317
|
-
subject {
|
406
|
+
subject {
|
407
|
+
described_class.create('Cmd' => %w[sleep 10], 'Image' => 'debian:wheezy')
|
408
|
+
}
|
318
409
|
|
319
410
|
before { subject.start }
|
411
|
+
after { subject.kill!.remove }
|
320
412
|
|
321
413
|
it 'restarts the container', :vcr do
|
322
414
|
expect(described_class.all.map(&:id)).to be_any { |id|
|
@@ -335,8 +427,12 @@ describe Docker::Container do
|
|
335
427
|
|
336
428
|
describe '#pause' do
|
337
429
|
subject {
|
338
|
-
described_class.create(
|
430
|
+
described_class.create(
|
431
|
+
'Cmd' => %w[sleep 50],
|
432
|
+
'Image' => 'debian:wheezy'
|
433
|
+
).start
|
339
434
|
}
|
435
|
+
after { subject.unpause.kill!.remove }
|
340
436
|
|
341
437
|
it 'pauses the container', :vcr do
|
342
438
|
subject.pause
|
@@ -346,9 +442,13 @@ describe Docker::Container do
|
|
346
442
|
|
347
443
|
describe '#unpause' do
|
348
444
|
subject {
|
349
|
-
described_class.create(
|
445
|
+
described_class.create(
|
446
|
+
'Cmd' => %w[sleep 50],
|
447
|
+
'Image' => 'debian:wheezy'
|
448
|
+
).start
|
350
449
|
}
|
351
450
|
before { subject.pause }
|
451
|
+
after { subject.kill!.remove }
|
352
452
|
|
353
453
|
it 'unpauses the container', :vcr do
|
354
454
|
subject.unpause
|
@@ -359,10 +459,15 @@ describe Docker::Container do
|
|
359
459
|
end
|
360
460
|
|
361
461
|
describe '#wait' do
|
362
|
-
subject {
|
363
|
-
|
462
|
+
subject {
|
463
|
+
described_class.create(
|
464
|
+
'Cmd' => %w[tar nonsense],
|
465
|
+
'Image' => 'debian:wheezy'
|
466
|
+
)
|
467
|
+
}
|
364
468
|
|
365
469
|
before { subject.start }
|
470
|
+
after(:each) { subject.remove }
|
366
471
|
|
367
472
|
it 'waits for the command to finish', :vcr do
|
368
473
|
expect(subject.wait['StatusCode']).to_not be_zero
|
@@ -370,26 +475,33 @@ describe Docker::Container do
|
|
370
475
|
|
371
476
|
context 'when an argument is given' do
|
372
477
|
subject { described_class.create('Cmd' => %w[sleep 5],
|
373
|
-
'Image' => '
|
478
|
+
'Image' => 'debian:wheezy') }
|
374
479
|
|
375
480
|
it 'sets the :read_timeout to that amount of time', :vcr do
|
376
481
|
expect(subject.wait(6)['StatusCode']).to be_zero
|
377
482
|
end
|
378
483
|
|
379
|
-
context 'and a command runs for too long' do
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
484
|
+
# context 'and a command runs for too long' do
|
485
|
+
# after(:each) { subject.remove }
|
486
|
+
#
|
487
|
+
# it 'raises a ServerError', :vcr do
|
488
|
+
# skip "VCR doesn't like to record errors"
|
489
|
+
# expect{subject.wait(4)}.to raise_error(Docker::Error::TimeoutError)
|
490
|
+
# end
|
491
|
+
# end
|
385
492
|
end
|
386
493
|
end
|
387
494
|
|
388
495
|
describe '#run' do
|
389
496
|
let(:run_command) { subject.run('ls') }
|
497
|
+
|
390
498
|
context 'when the Container\'s command does not return status code of 0' do
|
391
|
-
subject { described_class.create('Cmd' => %w[
|
392
|
-
'Image' => '
|
499
|
+
subject { described_class.create('Cmd' => %w[false],
|
500
|
+
'Image' => 'debian:wheezy') }
|
501
|
+
|
502
|
+
after do
|
503
|
+
subject.remove
|
504
|
+
end
|
393
505
|
|
394
506
|
it 'raises an error', :vcr do
|
395
507
|
expect { run_command }
|
@@ -399,7 +511,16 @@ describe Docker::Container do
|
|
399
511
|
|
400
512
|
context 'when the Container\'s command returns a status code of 0' do
|
401
513
|
subject { described_class.create('Cmd' => %w[pwd],
|
402
|
-
'Image' => '
|
514
|
+
'Image' => 'debian:wheezy') }
|
515
|
+
after do
|
516
|
+
subject.remove
|
517
|
+
image = run_command.json['Image']
|
518
|
+
run_command.remove
|
519
|
+
Docker::Image.get(image).history.each do |layer|
|
520
|
+
next unless layer['CreatedBy'] == 'pwd'
|
521
|
+
Docker::Image.get(layer['Id']).remove(:noprune => true)
|
522
|
+
end
|
523
|
+
end
|
403
524
|
|
404
525
|
it 'creates a new container to run the specified command', :vcr do
|
405
526
|
expect(run_command.wait['StatusCode']).to be_zero
|
@@ -408,23 +529,30 @@ describe Docker::Container do
|
|
408
529
|
end
|
409
530
|
|
410
531
|
describe '#commit' do
|
411
|
-
subject {
|
532
|
+
subject {
|
533
|
+
described_class.create('Cmd' => %w[true], 'Image' => 'debian:wheezy')
|
534
|
+
}
|
412
535
|
let(:image) { subject.commit }
|
413
536
|
|
414
537
|
before { subject.start }
|
538
|
+
after(:each) do
|
539
|
+
subject.remove
|
540
|
+
image.remove
|
541
|
+
end
|
415
542
|
|
416
543
|
it 'creates a new Image from the Container\'s changes', :vcr do
|
417
544
|
expect(image).to be_a Docker::Image
|
418
545
|
expect(image.id).to_not be_nil
|
419
546
|
end
|
420
547
|
|
421
|
-
context 'if run is passed, it saves the command in the image', :vcr do
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
end
|
548
|
+
# context 'if run is passed, it saves the command in the image', :vcr do
|
549
|
+
# let(:image) { subject.commit }
|
550
|
+
#
|
551
|
+
# it 'saves the command' do
|
552
|
+
# skip 'This is no longer working in v0.8'
|
553
|
+
# expect(image.run('pwd').attach).to eql [["/\n"],[]]
|
554
|
+
# end
|
555
|
+
# end
|
428
556
|
|
429
557
|
end
|
430
558
|
|
@@ -464,12 +592,13 @@ describe Docker::Container do
|
|
464
592
|
"Env" => nil,
|
465
593
|
"Cmd" => ["date"],
|
466
594
|
"Dns" => nil,
|
467
|
-
"Image" => "
|
595
|
+
"Image" => "debian:wheezy",
|
468
596
|
"Volumes" => {},
|
469
597
|
"VolumesFrom" => ""
|
470
598
|
}
|
471
599
|
end
|
472
600
|
let(:container) { subject.create(options) }
|
601
|
+
after { container.remove }
|
473
602
|
|
474
603
|
it 'sets the id', :vcr do
|
475
604
|
expect(container).to be_a Docker::Container
|
@@ -500,7 +629,10 @@ describe Docker::Container do
|
|
500
629
|
end
|
501
630
|
|
502
631
|
context 'when the HTTP response is a 200' do
|
503
|
-
let(:container) {
|
632
|
+
let(:container) {
|
633
|
+
subject.create('Cmd' => ['ls'], 'Image' => 'debian:wheezy')
|
634
|
+
}
|
635
|
+
after { container.remove }
|
504
636
|
|
505
637
|
it 'materializes the Container into a Docker::Container', :vcr do
|
506
638
|
expect(subject.get(container.id)).to be_a Docker::Container
|
@@ -529,7 +661,11 @@ describe Docker::Container do
|
|
529
661
|
end
|
530
662
|
|
531
663
|
context 'when the HTTP response is a 200' do
|
532
|
-
|
664
|
+
let(:container) {
|
665
|
+
subject.create('Cmd' => ['ls'], 'Image' => 'debian:wheezy')
|
666
|
+
}
|
667
|
+
before { container }
|
668
|
+
after { container.remove }
|
533
669
|
|
534
670
|
it 'materializes each Container into a Docker::Container', :vcr do
|
535
671
|
expect(subject.all(:all => true)).to be_all { |container|
|