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/spec/docker/event_spec.rb
CHANGED
@@ -6,7 +6,7 @@ describe Docker::Event do
|
|
6
6
|
|
7
7
|
let(:status) { "start" }
|
8
8
|
let(:id) { "398c9f77b5d2" }
|
9
|
-
let(:from) { "
|
9
|
+
let(:from) { "debian:wheezy" }
|
10
10
|
let(:time) { 1381956164 }
|
11
11
|
|
12
12
|
let(:expected_string) {
|
@@ -26,7 +26,7 @@ describe Docker::Event do
|
|
26
26
|
.and_call_original
|
27
27
|
fork do
|
28
28
|
sleep 1
|
29
|
-
Docker::Image.create('fromImage' => '
|
29
|
+
Docker::Image.create('fromImage' => 'debian:wheezy').run('bash')
|
30
30
|
end
|
31
31
|
Docker::Event.stream do |event|
|
32
32
|
puts "#{event}"
|
@@ -46,7 +46,7 @@ describe Docker::Event do
|
|
46
46
|
.and_call_original
|
47
47
|
fork do
|
48
48
|
sleep 1
|
49
|
-
Docker::Image.create('fromImage' => '
|
49
|
+
Docker::Image.create('fromImage' => 'debian:wheezy').run('bash')
|
50
50
|
end
|
51
51
|
Docker::Event.since(time) do |event|
|
52
52
|
puts "#{event}"
|
@@ -61,7 +61,7 @@ describe Docker::Event do
|
|
61
61
|
subject { Docker::Event.new_event(response_body, nil, nil) }
|
62
62
|
let(:status) { "start" }
|
63
63
|
let(:id) { "398c9f77b5d2" }
|
64
|
-
let(:from) { "
|
64
|
+
let(:from) { "debian:wheezy" }
|
65
65
|
let(:time) { 1381956164 }
|
66
66
|
let(:response_body) {
|
67
67
|
"{\"status\":\"#{status}\",\"id\":\"#{id}\""\
|
@@ -0,0 +1,197 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Docker::Exec do
|
4
|
+
|
5
|
+
describe '#to_s' do
|
6
|
+
subject {
|
7
|
+
described_class.send(:new, Docker.connection, 'id' => rand(10000).to_s)
|
8
|
+
}
|
9
|
+
|
10
|
+
let(:id) { 'bf119e2' }
|
11
|
+
let(:connection) { Docker.connection }
|
12
|
+
let(:expected_string) {
|
13
|
+
"Docker::Exec { :id => #{id}, :connection => #{connection} }"
|
14
|
+
}
|
15
|
+
before do
|
16
|
+
{
|
17
|
+
:@id => id,
|
18
|
+
:@connection => connection
|
19
|
+
}.each { |k, v| subject.instance_variable_set(k, v) }
|
20
|
+
end
|
21
|
+
|
22
|
+
its(:to_s) { should == expected_string }
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '.create' do
|
26
|
+
subject { described_class }
|
27
|
+
|
28
|
+
context 'when the HTTP request returns a 201' do
|
29
|
+
let(:container) {
|
30
|
+
Docker::Container.create(
|
31
|
+
'Cmd' => %w[sleep 5],
|
32
|
+
'Image' => 'debian:wheezy'
|
33
|
+
).start!
|
34
|
+
}
|
35
|
+
let(:options) do
|
36
|
+
{
|
37
|
+
'AttachStdin' => false,
|
38
|
+
'AttachStdout' => false,
|
39
|
+
'AttachStderr' => false,
|
40
|
+
'Tty' => false,
|
41
|
+
'Cmd' => [
|
42
|
+
'date'
|
43
|
+
],
|
44
|
+
'Container' => container.id
|
45
|
+
}
|
46
|
+
end
|
47
|
+
let(:process) { subject.create(options) }
|
48
|
+
after { container.kill!.remove }
|
49
|
+
|
50
|
+
it 'sets the id', :vcr do
|
51
|
+
expect(process).to be_a Docker::Exec
|
52
|
+
expect(process.id).to_not be_nil
|
53
|
+
expect(process.connection).to_not be_nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when the parent container does not exist' do
|
58
|
+
before do
|
59
|
+
Docker.options = { :mock => true }
|
60
|
+
Excon.stub({ :method => :post }, { :status => 404 })
|
61
|
+
end
|
62
|
+
after do
|
63
|
+
Excon.stubs.shift
|
64
|
+
Docker.options = {}
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'raises an error' do
|
68
|
+
expect { subject.create }.to raise_error(Docker::Error::NotFoundError)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#start!' do
|
74
|
+
let(:container) {
|
75
|
+
Docker::Container.create(
|
76
|
+
'Cmd' => %w[sleep 10],
|
77
|
+
'Image' => 'debian:wheezy'
|
78
|
+
).start!
|
79
|
+
}
|
80
|
+
|
81
|
+
context 'when the exec instance does not exist' do
|
82
|
+
subject do
|
83
|
+
described_class.send(:new, Docker.connection, 'id' => rand(10000).to_s)
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'raises an error', :vcr do
|
87
|
+
skip 'The Docker API returns a 200 (docker/docker#9341)'
|
88
|
+
expect { subject.start! }.to raise_error(Docker::Error::NotFoundError)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'when :detach is set to false' do
|
93
|
+
subject {
|
94
|
+
described_class.create(
|
95
|
+
'Container' => container.id,
|
96
|
+
'AttachStdout' => true,
|
97
|
+
'Cmd' => ['bash','-c','sleep 2; echo hello']
|
98
|
+
)
|
99
|
+
}
|
100
|
+
after { container.kill!.remove }
|
101
|
+
|
102
|
+
it 'returns the stdout and stderr messages', :vcr do
|
103
|
+
expect(subject.start!).to eq([["hello\n"],[]])
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'block is passed' do
|
107
|
+
it 'attaches to the stream', :vcr do
|
108
|
+
chunk = nil
|
109
|
+
subject.start! do |stream, c|
|
110
|
+
chunk ||= c
|
111
|
+
end
|
112
|
+
expect(chunk).to eq("hello\n")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'when :detach is set to true' do
|
118
|
+
subject {
|
119
|
+
described_class.create('Container' => container.id, 'Cmd' => %w[date])
|
120
|
+
}
|
121
|
+
after { container.kill!.remove }
|
122
|
+
|
123
|
+
it 'returns empty stdout and stderr messages', :vcr do
|
124
|
+
expect(subject.start!(:detach => true)).to eq([[],[]])
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'when the command has already run' do
|
129
|
+
subject {
|
130
|
+
described_class.create('Container' => container.id, 'Cmd' => ['date'])
|
131
|
+
}
|
132
|
+
before { subject.start! }
|
133
|
+
after { container.kill!.remove }
|
134
|
+
|
135
|
+
it 'raises an error', :vcr do
|
136
|
+
skip 'The Docker API returns a 200 (docker/docker#9341)'
|
137
|
+
expect { subject.start! }.to raise_error(Docker::Error::NotFoundError)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context 'when the HTTP request returns a 201' do
|
142
|
+
subject {
|
143
|
+
described_class.create('Container' => container.id, 'Cmd' => ['date'])
|
144
|
+
}
|
145
|
+
after { container.kill!.remove }
|
146
|
+
|
147
|
+
it 'starts the exec instance', :vcr do
|
148
|
+
expect { subject.start! }.not_to raise_error
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe '#resize' do
|
154
|
+
let(:container) {
|
155
|
+
Docker::Container.create(
|
156
|
+
'Cmd' => %w[sleep 20],
|
157
|
+
'Image' => 'debian:wheezy'
|
158
|
+
).start!
|
159
|
+
}
|
160
|
+
|
161
|
+
context 'when exec instance has TTY enabled' do
|
162
|
+
let(:instance) do
|
163
|
+
described_class.create(
|
164
|
+
'Container' => container.id,
|
165
|
+
'AttachStdin' => true,
|
166
|
+
'Tty' => true,
|
167
|
+
'Cmd' => %w[/bin/bash]
|
168
|
+
)
|
169
|
+
end
|
170
|
+
after do
|
171
|
+
container.kill!
|
172
|
+
sleep 1
|
173
|
+
container.remove
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'returns a 200', :vcr do
|
177
|
+
t = Thread.new do
|
178
|
+
instance.start!(:tty => true)
|
179
|
+
end
|
180
|
+
sleep 1
|
181
|
+
expect { instance.resize(:h => 10, :w => 30) }.not_to raise_error
|
182
|
+
t.kill
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
context 'when the exec instance does not exist' do
|
187
|
+
subject do
|
188
|
+
described_class.send(:new, Docker.connection, 'id' => rand(10000).to_s)
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'raises an error', :vcr do
|
192
|
+
skip 'The Docker API returns a 200 (docker/docker#9341)'
|
193
|
+
expect { subject.resize }.to raise_error(Docker::Error::NotFoundError)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
data/spec/docker/image_spec.rb
CHANGED
@@ -8,7 +8,7 @@ describe Docker::Image do
|
|
8
8
|
let(:connection) { Docker.connection }
|
9
9
|
|
10
10
|
let(:info) do
|
11
|
-
{"id" => "bf119e2", "Repository" => "
|
11
|
+
{"id" => "bf119e2", "Repository" => "debian", "Tag" => "wheezy",
|
12
12
|
"Created" => 1364102658, "Size" => 24653, "VirtualSize" => 180116135}
|
13
13
|
end
|
14
14
|
|
@@ -21,17 +21,30 @@ describe Docker::Image do
|
|
21
21
|
end
|
22
22
|
|
23
23
|
describe '#remove' do
|
24
|
-
let(:id) { subject.id }
|
25
|
-
subject { described_class.create('fromImage' => 'base') }
|
26
24
|
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
context 'when no name is given' do
|
26
|
+
let(:id) { subject.id }
|
27
|
+
subject { described_class.create('fromImage' => 'busybox') }
|
28
|
+
|
29
|
+
it 'removes the Image', :vcr do
|
30
|
+
subject.remove(:force => true)
|
31
|
+
expect(Docker::Image.all.map(&:id)).to_not include(id)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when a valid tag is given' do
|
36
|
+
it 'untags the Image'
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when an invalid tag is given' do
|
40
|
+
it 'raises an error'
|
30
41
|
end
|
31
42
|
end
|
32
43
|
|
33
44
|
describe '#insert_local' do
|
34
|
-
|
45
|
+
include_context "local paths"
|
46
|
+
|
47
|
+
subject { described_class.create('fromImage' => 'debian:wheezy') }
|
35
48
|
|
36
49
|
let(:rm) { false }
|
37
50
|
let(:new_image) {
|
@@ -49,23 +62,33 @@ describe Docker::Image do
|
|
49
62
|
end
|
50
63
|
|
51
64
|
context 'when the local file does exist' do
|
52
|
-
let(:file) { '
|
65
|
+
let(:file) { File.join(project_dir, 'Gemfile') }
|
53
66
|
let(:gemfile) { File.read('Gemfile') }
|
67
|
+
let(:container) { new_image.run('cat /Gemfile') }
|
68
|
+
after do
|
69
|
+
container.tap(&:wait).remove
|
70
|
+
new_image.remove
|
71
|
+
end
|
54
72
|
|
55
73
|
it 'creates a new Image that has that file', :vcr do
|
56
|
-
|
57
|
-
|
58
|
-
chunk ||= c
|
59
|
-
}
|
60
|
-
expect(chunk).to eq(gemfile)
|
74
|
+
output = container.streaming_logs(stdout: true)
|
75
|
+
expect(output).to eq(gemfile)
|
61
76
|
end
|
62
77
|
end
|
63
78
|
|
64
79
|
context 'when a direcory is passed' do
|
65
80
|
let(:new_image) {
|
66
|
-
subject.insert_local(
|
81
|
+
subject.insert_local(
|
82
|
+
'localPath' => File.join(project_dir, 'lib'),
|
83
|
+
'outputPath' => '/lib'
|
84
|
+
)
|
67
85
|
}
|
68
|
-
let(:
|
86
|
+
let(:container) { new_image.run('ls -a /lib/docker') }
|
87
|
+
let(:response) { container.streaming_logs(stdout: true) }
|
88
|
+
after do
|
89
|
+
container.tap(&:wait).remove
|
90
|
+
new_image.remove
|
91
|
+
end
|
69
92
|
|
70
93
|
it 'inserts the directory', :vcr do
|
71
94
|
expect(response.split("\n").sort).to eq(Dir.entries('lib/docker').sort)
|
@@ -73,21 +96,29 @@ describe Docker::Image do
|
|
73
96
|
end
|
74
97
|
|
75
98
|
context 'when there are multiple files passed' do
|
76
|
-
let(:file) {
|
99
|
+
let(:file) {
|
100
|
+
[File.join(project_dir, 'Gemfile'), File.join(project_dir, 'LICENSE')]
|
101
|
+
}
|
77
102
|
let(:gemfile) { File.read('Gemfile') }
|
78
|
-
let(:
|
103
|
+
let(:license) { File.read('LICENSE') }
|
104
|
+
let(:container) { new_image.run('cat /Gemfile /LICENSE') }
|
79
105
|
let(:response) {
|
80
|
-
|
106
|
+
container.streaming_logs(stdout: true)
|
81
107
|
}
|
108
|
+
after do
|
109
|
+
container.tap(&:wait).remove
|
110
|
+
new_image.remove
|
111
|
+
end
|
82
112
|
|
83
113
|
it 'creates a new Image that has each file', :vcr do
|
84
|
-
expect(response).to eq(
|
114
|
+
expect(response).to eq("#{gemfile}#{license}")
|
85
115
|
end
|
86
116
|
end
|
87
117
|
|
88
118
|
context 'when removing intermediate containers' do
|
89
119
|
let(:rm) { true }
|
90
|
-
let(:file) { '
|
120
|
+
let(:file) { File.join(project_dir, 'Gemfile') }
|
121
|
+
after(:each) { new_image.remove }
|
91
122
|
|
92
123
|
it 'leave no intermediate containers', :vcr do
|
93
124
|
expect { new_image }.to change {
|
@@ -104,47 +135,29 @@ describe Docker::Image do
|
|
104
135
|
describe '#push' do
|
105
136
|
let(:credentials) {
|
106
137
|
{
|
107
|
-
'username' => '
|
108
|
-
'password' => '
|
138
|
+
'username' => ENV['DOCKER_API_USER'],
|
139
|
+
'password' => ENV['DOCKER_API_PASS'],
|
109
140
|
'serveraddress' => 'https://index.docker.io/v1',
|
110
|
-
'email' => '
|
141
|
+
'email' => ENV['DOCKER_API_EMAIL']
|
111
142
|
}
|
112
143
|
}
|
113
|
-
let(:
|
114
|
-
|
115
|
-
|
116
|
-
let(:container) {
|
117
|
-
base_image.run('true')
|
118
|
-
}
|
119
|
-
let(:new_image) {
|
120
|
-
container.commit('repo' => 'nahiluhmot/base2')
|
121
|
-
Docker::Image.all(:all => true).select { |image|
|
122
|
-
image.info['RepoTags'].include?('nahiluhmot/base2:latest')
|
123
|
-
}.first
|
144
|
+
let(:repo_tag) { "#{ENV['DOCKER_API_USER']}/true" }
|
145
|
+
let(:image) {
|
146
|
+
described_class.build("FROM tianon/true\n", "t" => repo_tag).refresh!
|
124
147
|
}
|
148
|
+
after { image.remove(:name => repo_tag, :noprune => true) }
|
125
149
|
|
126
150
|
it 'pushes the Image', :vcr do
|
127
|
-
|
151
|
+
image.push(credentials)
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'when a tag is specified' do
|
155
|
+
it 'pushes that specific tag'
|
128
156
|
end
|
129
157
|
|
130
158
|
context 'when there are no credentials' do
|
131
159
|
let(:credentials) { nil }
|
132
|
-
let(:
|
133
|
-
Docker::Image.create('fromImage' => 'registry', 'tag' => 'latest')
|
134
|
-
}
|
135
|
-
|
136
|
-
let(:container) { Docker::Container.create('Image' => image.id) }
|
137
|
-
|
138
|
-
before do
|
139
|
-
opts = {
|
140
|
-
"PortBindings" => {
|
141
|
-
"5000/tcp" => [{"HostPort" => "5000"}]
|
142
|
-
}
|
143
|
-
}
|
144
|
-
container.start!(opts)
|
145
|
-
sleep 10 # for some reason the registry isn't ready right away
|
146
|
-
image.tag('repo' => 'localhost:5000/registry', 'tag' => 'test')
|
147
|
-
end
|
160
|
+
let(:repo_tag) { "localhost:5000/true" }
|
148
161
|
|
149
162
|
it 'still pushes', :vcr do
|
150
163
|
expect { image.push }.to_not raise_error
|
@@ -153,16 +166,17 @@ describe Docker::Image do
|
|
153
166
|
end
|
154
167
|
|
155
168
|
describe '#tag' do
|
156
|
-
subject { described_class.create('fromImage' => '
|
169
|
+
subject { described_class.create('fromImage' => 'debian:wheezy') }
|
170
|
+
after { subject.remove(:name => 'teh:latest', :noprune => true) }
|
157
171
|
|
158
172
|
it 'tags the image with the repo name', :vcr do
|
159
|
-
subject.tag(:repo => :
|
160
|
-
expect(subject.info['RepoTags']).to include '
|
173
|
+
subject.tag(:repo => :teh, :force => true)
|
174
|
+
expect(subject.info['RepoTags']).to include 'teh:latest'
|
161
175
|
end
|
162
176
|
end
|
163
177
|
|
164
178
|
describe '#json' do
|
165
|
-
subject { described_class.create('fromImage' => '
|
179
|
+
subject { described_class.create('fromImage' => 'debian:wheezy') }
|
166
180
|
let(:json) { subject.json }
|
167
181
|
|
168
182
|
it 'returns additional information about image image', :vcr do
|
@@ -172,7 +186,7 @@ describe Docker::Image do
|
|
172
186
|
end
|
173
187
|
|
174
188
|
describe '#history' do
|
175
|
-
subject { described_class.create('fromImage' => '
|
189
|
+
subject { described_class.create('fromImage' => 'debian:wheezy') }
|
176
190
|
let(:history) { subject.history }
|
177
191
|
|
178
192
|
it 'returns the history of the Image', :vcr do
|
@@ -183,48 +197,51 @@ describe Docker::Image do
|
|
183
197
|
end
|
184
198
|
|
185
199
|
describe '#run' do
|
186
|
-
subject { described_class.create('fromImage' => '
|
187
|
-
let(:
|
200
|
+
subject { described_class.create('fromImage' => 'debian:wheezy') }
|
201
|
+
let(:container) { subject.run(cmd) }
|
202
|
+
let(:output) { container.streaming_logs(stdout: true) }
|
188
203
|
|
189
204
|
context 'when the argument is a String', :vcr do
|
190
205
|
let(:cmd) { 'ls /lib64/' }
|
206
|
+
after { container.tap(&:wait).remove }
|
207
|
+
|
191
208
|
it 'splits the String by spaces and creates a new Container' do
|
192
|
-
expect(output).to eq(
|
209
|
+
expect(output).to eq("ld-linux-x86-64.so.2\n")
|
193
210
|
end
|
194
211
|
end
|
195
212
|
|
196
213
|
context 'when the argument is an Array' do
|
197
214
|
let(:cmd) { %w[which pwd] }
|
215
|
+
after { container.tap(&:wait).remove }
|
198
216
|
|
199
217
|
it 'creates a new Container', :vcr do
|
200
|
-
expect(output).to eq(
|
218
|
+
expect(output).to eq("/bin/pwd\n")
|
201
219
|
end
|
202
220
|
end
|
203
221
|
|
204
222
|
context 'when the argument is nil', :vcr do
|
205
223
|
let(:cmd) { nil }
|
206
|
-
context 'no command configured in image'do
|
224
|
+
context 'no command configured in image' do
|
225
|
+
subject { described_class.create('fromImage' => 'scratch') }
|
207
226
|
it 'should raise an error if no command is specified' do
|
208
|
-
expect {
|
227
|
+
expect {container}.to raise_error(Docker::Error::ServerError,
|
209
228
|
"No command specified.")
|
210
229
|
end
|
211
230
|
end
|
212
231
|
|
213
232
|
context "command configured in image" do
|
214
|
-
let(:
|
215
|
-
|
216
|
-
subject { container.commit('run' => {"Cmd" => %w[pwd]}) }
|
233
|
+
let(:cmd) { 'pwd' }
|
234
|
+
after { container.tap(&:wait).remove }
|
217
235
|
|
218
236
|
it 'should normally show result if image has Cmd configured' do
|
219
|
-
|
220
|
-
expect(output).to eql [["/\n"],[]]
|
237
|
+
expect(output).to eql "/\n"
|
221
238
|
end
|
222
239
|
end
|
223
240
|
end
|
224
241
|
end
|
225
242
|
|
226
243
|
describe '#refresh!' do
|
227
|
-
let(:image) { Docker::Image.create('fromImage' => '
|
244
|
+
let(:image) { Docker::Image.create('fromImage' => 'debian:wheezy') }
|
228
245
|
|
229
246
|
it 'updates the @info hash', :vcr do
|
230
247
|
size = image.info.size
|
@@ -237,16 +254,17 @@ describe Docker::Image do
|
|
237
254
|
subject { described_class }
|
238
255
|
|
239
256
|
context 'when the Image does not yet exist and the body is a Hash' do
|
240
|
-
let(:image) { subject.create('fromImage' => '
|
257
|
+
let(:image) { subject.create('fromImage' => 'swipely/scratch') }
|
241
258
|
let(:creds) {
|
242
259
|
{
|
243
|
-
:username => '
|
244
|
-
:password => '
|
245
|
-
:email => '
|
260
|
+
:username => ENV['DOCKER_API_USER'],
|
261
|
+
:password => ENV['DOCKER_API_PASS'],
|
262
|
+
:email => ENV['DOCKER_API_EMAIL']
|
246
263
|
}
|
247
264
|
}
|
248
265
|
|
249
266
|
before { Docker.creds = creds }
|
267
|
+
after { image.remove(:name => 'swipely/scratch', :noprune => true) }
|
250
268
|
|
251
269
|
it 'sets the id and sends Docker.creds', :vcr do
|
252
270
|
expect(image).to be_a Docker::Image
|
@@ -264,7 +282,7 @@ describe Docker::Image do
|
|
264
282
|
let(:image) { subject.get(image_name) }
|
265
283
|
|
266
284
|
context 'when the image does exist' do
|
267
|
-
let(:image_name) { '
|
285
|
+
let(:image_name) { 'debian:wheezy' }
|
268
286
|
|
269
287
|
it 'returns the new image', :vcr do
|
270
288
|
expect(image).to be_a Docker::Image
|
@@ -295,7 +313,7 @@ describe Docker::Image do
|
|
295
313
|
let(:exists) { subject.exist?(image_name) }
|
296
314
|
|
297
315
|
context 'when the image does exist' do
|
298
|
-
let(:image_name) { '
|
316
|
+
let(:image_name) { 'debian:wheezy' }
|
299
317
|
|
300
318
|
it 'returns true', :vcr do
|
301
319
|
expect(exists).to eq(true)
|
@@ -322,6 +340,8 @@ describe Docker::Image do
|
|
322
340
|
end
|
323
341
|
|
324
342
|
describe '.import' do
|
343
|
+
include_context "local paths"
|
344
|
+
|
325
345
|
subject { described_class }
|
326
346
|
|
327
347
|
context 'when the file does not exist' do
|
@@ -334,15 +354,11 @@ describe Docker::Image do
|
|
334
354
|
end
|
335
355
|
|
336
356
|
context 'when the file does exist' do
|
337
|
-
let(:file) { 'spec
|
338
|
-
let(:
|
339
|
-
|
340
|
-
before do
|
341
|
-
allow(Docker::Image).to receive(:open).with(file).and_yield(body)
|
342
|
-
end
|
357
|
+
let(:file) { File.join(project_dir, 'spec', 'fixtures', 'export.tar') }
|
358
|
+
let(:import) { subject.import(file) }
|
359
|
+
after { import.remove(:noprune => true) }
|
343
360
|
|
344
361
|
it 'creates the Image', :vcr do
|
345
|
-
import = subject.import(file)
|
346
362
|
expect(import).to be_a Docker::Image
|
347
363
|
expect(import.id).to_not be_nil
|
348
364
|
end
|
@@ -357,12 +373,13 @@ describe Docker::Image do
|
|
357
373
|
end
|
358
374
|
|
359
375
|
context 'when the URI is valid' do
|
360
|
-
let(:uri) { 'http://swipely-pub.s3.amazonaws.com/
|
376
|
+
let(:uri) { 'http://swipely-pub.s3.amazonaws.com/tianon_true.tar' }
|
377
|
+
let(:import) { subject.import(uri) }
|
378
|
+
after { import.remove(:noprune => true) }
|
361
379
|
|
362
380
|
it 'returns an Image', :vcr do
|
363
|
-
|
364
|
-
expect(
|
365
|
-
expect(image.id).to_not be_nil
|
381
|
+
expect(import).to be_a Docker::Image
|
382
|
+
expect(import.id).to_not be_nil
|
366
383
|
end
|
367
384
|
end
|
368
385
|
end
|
@@ -372,7 +389,7 @@ describe Docker::Image do
|
|
372
389
|
subject { described_class }
|
373
390
|
|
374
391
|
let(:images) { subject.all(:all => true) }
|
375
|
-
before { subject.create('fromImage' => '
|
392
|
+
before { subject.create('fromImage' => 'debian:wheezy') }
|
376
393
|
|
377
394
|
it 'materializes each Image into a Docker::Image', :vcr do
|
378
395
|
images.each do |image|
|
@@ -412,7 +429,7 @@ describe Docker::Image do
|
|
412
429
|
|
413
430
|
context 'with a valid Dockerfile' do
|
414
431
|
context 'without query parameters' do
|
415
|
-
let(:image) { subject.build("
|
432
|
+
let(:image) { subject.build("FROM debian:wheezy\n") }
|
416
433
|
|
417
434
|
it 'builds an image', :vcr do
|
418
435
|
expect(image).to be_a Docker::Image
|
@@ -423,25 +440,31 @@ describe Docker::Image do
|
|
423
440
|
|
424
441
|
context 'with specifying a repo in the query parameters' do
|
425
442
|
let(:image) {
|
426
|
-
subject.build(
|
443
|
+
subject.build(
|
444
|
+
"FROM debian:wheezy\nRUN true\n",
|
445
|
+
"t" => "#{ENV['DOCKER_API_USER']}/debian:true"
|
446
|
+
)
|
427
447
|
}
|
428
|
-
|
448
|
+
after { image.remove(:noprune => true) }
|
429
449
|
|
430
450
|
it 'builds an image and tags it', :vcr do
|
431
451
|
expect(image).to be_a Docker::Image
|
432
452
|
expect(image.id).to_not be_nil
|
433
453
|
expect(image.connection).to be_a Docker::Connection
|
434
|
-
|
454
|
+
image.refresh!
|
455
|
+
expect(image.info["RepoTags"]).to eq(
|
456
|
+
["#{ENV['DOCKER_API_USER']}/debian:true"]
|
457
|
+
)
|
435
458
|
end
|
436
459
|
end
|
437
460
|
|
438
461
|
context 'with a block capturing build output' do
|
439
462
|
let(:build_output) { "" }
|
440
463
|
let(:block) { Proc.new { |chunk| build_output << chunk } }
|
441
|
-
let!(:image) { subject.build("FROM
|
464
|
+
let!(:image) { subject.build("FROM debian:wheezy\n", &block) }
|
442
465
|
|
443
466
|
it 'calls the block and passes build output', :vcr do
|
444
|
-
expect(build_output).to match(/Step 0 : FROM
|
467
|
+
expect(build_output).to match(/Step 0 : FROM debian:wheezy/)
|
445
468
|
end
|
446
469
|
end
|
447
470
|
end
|
@@ -463,20 +486,26 @@ describe Docker::Image do
|
|
463
486
|
'Cmd' => %w[cat /Dockerfile])
|
464
487
|
end
|
465
488
|
let(:output) { container.tap(&:start)
|
466
|
-
.
|
467
|
-
|
489
|
+
.streaming_logs(stdout: true) }
|
490
|
+
after(:each) do
|
491
|
+
container.tap(&:wait).remove
|
492
|
+
image.remove(:noprune => true)
|
493
|
+
end
|
468
494
|
|
469
495
|
context 'with no query parameters' do
|
470
496
|
it 'builds the image', :vcr do
|
471
|
-
expect(output).to eq(
|
497
|
+
expect(output).to eq(docker_file.read)
|
472
498
|
end
|
473
499
|
end
|
474
500
|
|
475
501
|
context 'with specifying a repo in the query parameters' do
|
476
|
-
let(:opts) { { "t" => "
|
502
|
+
let(:opts) { { "t" => "#{ENV['DOCKER_API_USER']}/debian:from_dir" } }
|
477
503
|
it 'builds the image and tags it', :vcr do
|
478
|
-
expect(output).to eq(
|
479
|
-
|
504
|
+
expect(output).to eq(docker_file.read)
|
505
|
+
image.refresh!
|
506
|
+
expect(image.info["RepoTags"]).to eq(
|
507
|
+
["#{ENV['DOCKER_API_USER']}/debian:from_dir"]
|
508
|
+
)
|
480
509
|
end
|
481
510
|
end
|
482
511
|
|
@@ -486,16 +515,16 @@ describe Docker::Image do
|
|
486
515
|
|
487
516
|
it 'calls the block and passes build output', :vcr do
|
488
517
|
image # Create the image variable, which is lazy-loaded by Rspec
|
489
|
-
expect(build_output).to match(/Step 0 :
|
518
|
+
expect(build_output).to match(/Step 0 : FROM debian:wheezy/)
|
490
519
|
end
|
491
520
|
end
|
492
521
|
|
493
522
|
context 'with credentials passed' do
|
494
523
|
let(:creds) {
|
495
524
|
{
|
496
|
-
:username => '
|
497
|
-
:password => '
|
498
|
-
:email => '
|
525
|
+
:username => ENV['DOCKER_API_USER'],
|
526
|
+
:password => ENV['DOCKER_API_PASS'],
|
527
|
+
:email => ENV['DOCKER_API_EMAIL'],
|
499
528
|
:serveraddress => 'https://index.docker.io/v1'
|
500
529
|
}
|
501
530
|
}
|