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
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|
|