docker_helper 0.0.1 → 0.0.2
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/ChangeLog +6 -0
- data/README +1 -1
- data/lib/docker_helper.rb +65 -4
- data/lib/docker_helper/pool.rb +103 -0
- data/lib/docker_helper/proxy.rb +8 -2
- data/lib/docker_helper/version.rb +1 -1
- data/spec/docker_helper_spec.rb +131 -0
- metadata +8 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 281e717d31b942b1d9948fed9d4f652df44dac9b
|
4
|
+
data.tar.gz: e1a79e7764f8cc227f76b70543b0d09c211777c2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0e1367bc8d01661f373f7dafbec395e1790ce1c3860d19106b6aa1fcf4900120c2ca69574d34bcfea733dc12a3152976c2ff7238a9df85116edb63d4459505c7
|
7
|
+
data.tar.gz: 86f1aabfa46d791af0462604572a9d4301681842a76dfe91b177750f96e5e445a892de409635f83376bd0693da6913d61dd6f1919307715758165774b5517443
|
data/ChangeLog
CHANGED
data/README
CHANGED
data/lib/docker_helper.rb
CHANGED
@@ -24,6 +24,8 @@
|
|
24
24
|
###############################################################################
|
25
25
|
#++
|
26
26
|
|
27
|
+
require 'net/http'
|
28
|
+
|
27
29
|
# Various helper methods to control the Docker command-line client. Main
|
28
30
|
# entrance point is the #docker helper. Use ::proxy for a self-contained
|
29
31
|
# controller object to call these methods on.
|
@@ -208,17 +210,45 @@ module DockerHelper
|
|
208
210
|
end
|
209
211
|
|
210
212
|
# call-seq:
|
211
|
-
#
|
213
|
+
# docker_port(port, name) -> aString
|
212
214
|
#
|
213
|
-
# Returns the
|
215
|
+
# Returns the host and port for container +name+ on port +port+. Fails
|
214
216
|
# if container is not running or the specified port is not exposed.
|
215
217
|
#
|
216
218
|
# Command reference: {docker port
|
217
219
|
# }[https://docs.docker.com/reference/commandline/cli/#port]
|
218
|
-
def
|
220
|
+
def docker_port(port, name = nil)
|
219
221
|
name ||= docker_container_name
|
220
222
|
|
221
|
-
|
223
|
+
docker :port, name, port
|
224
|
+
end
|
225
|
+
|
226
|
+
# call-seq:
|
227
|
+
# docker_url(port, name) -> aString
|
228
|
+
#
|
229
|
+
# Returns the HTTP URL for container +name+ on port +port+ (see
|
230
|
+
# #docker_port).
|
231
|
+
def docker_url(port, name = nil)
|
232
|
+
"http://#{docker_port(port, name)}"
|
233
|
+
end
|
234
|
+
|
235
|
+
# call-seq:
|
236
|
+
# docker_ready(host_with_port[, path]) -> true or false
|
237
|
+
#
|
238
|
+
# Argument +host_with_port+ must be of the form <tt>host:port</tt>, as
|
239
|
+
# returned by #docker_port, or an array of host and port.
|
240
|
+
#
|
241
|
+
# Returns +true+ if and when the TCP port is available on the host and,
|
242
|
+
# if +path+ is given, a HTTP request for +path+ is successful.
|
243
|
+
#
|
244
|
+
# Returns +false+ if the port and the path haven't become available after
|
245
|
+
# 30 attempts each. Sleeps for 0.1 seconds inbetween attempts.
|
246
|
+
def docker_ready(host_with_port, path = nil, attempts = 30, sleep = 0.1)
|
247
|
+
host, port = host_with_port.is_a?(Array) ?
|
248
|
+
host_with_port : host_with_port.split(':')
|
249
|
+
|
250
|
+
docker_socket_ready(host, port, attempts, sleep) &&
|
251
|
+
(!path || docker_http_ready(host, port, path, attempts, sleep))
|
222
252
|
end
|
223
253
|
|
224
254
|
# call-seq:
|
@@ -355,7 +385,38 @@ module DockerHelper
|
|
355
385
|
abort
|
356
386
|
end
|
357
387
|
|
388
|
+
# Checks TCP connection.
|
389
|
+
def docker_socket_ready(host, port, attempts, sleep)
|
390
|
+
TCPSocket.new(host, port).close
|
391
|
+
true
|
392
|
+
rescue Errno::ECONNREFUSED
|
393
|
+
return false unless docker_ready_sleep(sleep, attempts -= 1)
|
394
|
+
retry
|
395
|
+
end
|
396
|
+
|
397
|
+
# Checks HTTP connection.
|
398
|
+
def docker_http_ready(host, port, path, attempts, sleep)
|
399
|
+
loop {
|
400
|
+
begin
|
401
|
+
break if Net::HTTP.get_response(host, path, port).is_a?(Net::HTTPSuccess)
|
402
|
+
rescue Errno::ECONNRESET, EOFError => err
|
403
|
+
return false unless docker_ready_sleep(sleep, attempts -= 1)
|
404
|
+
retry
|
405
|
+
end
|
406
|
+
|
407
|
+
return false unless docker_ready_sleep(sleep, attempts -= 1)
|
408
|
+
}
|
409
|
+
|
410
|
+
true
|
411
|
+
end
|
412
|
+
|
413
|
+
# Sleeps unless out of attempts.
|
414
|
+
def docker_ready_sleep(sleep, attempts)
|
415
|
+
sleep(sleep) unless attempts.zero?
|
416
|
+
end
|
417
|
+
|
358
418
|
end
|
359
419
|
|
360
420
|
require_relative 'docker_helper/version'
|
361
421
|
require_relative 'docker_helper/proxy'
|
422
|
+
require_relative 'docker_helper/pool'
|
@@ -0,0 +1,103 @@
|
|
1
|
+
#--
|
2
|
+
###############################################################################
|
3
|
+
# #
|
4
|
+
# docker_helper -- Helper methods to interact with Docker #
|
5
|
+
# #
|
6
|
+
# Copyright (C) 2014 Jens Wille #
|
7
|
+
# #
|
8
|
+
# Authors: #
|
9
|
+
# Jens Wille <jens.wille@gmail.com> #
|
10
|
+
# #
|
11
|
+
# docker_helper is free software; you can redistribute it and/or modify it #
|
12
|
+
# under the terms of the GNU Affero General Public License as published by #
|
13
|
+
# the Free Software Foundation; either version 3 of the License, or (at your #
|
14
|
+
# option) any later version. #
|
15
|
+
# #
|
16
|
+
# docker_helper is distributed in the hope that it will be useful, but #
|
17
|
+
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY #
|
18
|
+
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public #
|
19
|
+
# License for more details. #
|
20
|
+
# #
|
21
|
+
# You should have received a copy of the GNU Affero General Public License #
|
22
|
+
# along with docker_helper. If not, see <http://www.gnu.org/licenses/>. #
|
23
|
+
# #
|
24
|
+
###############################################################################
|
25
|
+
#++
|
26
|
+
|
27
|
+
module DockerHelper
|
28
|
+
|
29
|
+
class Pool
|
30
|
+
|
31
|
+
DEFAULT_SIZE = 2
|
32
|
+
|
33
|
+
DEFAULT_BASENAME = 'docker_helper'
|
34
|
+
|
35
|
+
def initialize(size = nil, basename = nil, docker = nil)
|
36
|
+
@docker, @previous_name, @basename =
|
37
|
+
docker ||= DockerHelper.proxy, nil,
|
38
|
+
basename ||= self.class::DEFAULT_BASENAME
|
39
|
+
|
40
|
+
yield self if block_given?
|
41
|
+
|
42
|
+
@pool = Array.new(size ||= self.class::DEFAULT_SIZE) { |i|
|
43
|
+
spawn_thread("#{basename}-#{$$}-#{i}")
|
44
|
+
}
|
45
|
+
|
46
|
+
extend(SinglePool) if size == 1
|
47
|
+
end
|
48
|
+
|
49
|
+
attr_accessor :image, :port, :path
|
50
|
+
|
51
|
+
def fetch_url(name = @previous_name)
|
52
|
+
docker.url(port, @previous_name = fetch(name)) + path.to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
def fetch(name = @previous_name)
|
56
|
+
pool.shift.tap { reclaim(name) }.value
|
57
|
+
end
|
58
|
+
|
59
|
+
def clean(name = @previous_name)
|
60
|
+
pool.map { |t| clean_thread(t.value) }.tap { |clean|
|
61
|
+
clean << clean_thread(name) if name
|
62
|
+
}.each(&:join)
|
63
|
+
end
|
64
|
+
|
65
|
+
def inspect
|
66
|
+
'#<%s:0x%x %s@%d>' % [self.class, object_id, basename, pool.size]
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
attr_reader :docker, :basename, :pool
|
72
|
+
|
73
|
+
def spawn_thread(name, clean = false)
|
74
|
+
Thread.new {
|
75
|
+
docker.clean(name) if clean
|
76
|
+
docker.start(name, image) if image
|
77
|
+
docker.ready(docker.port(port, name), path) if port
|
78
|
+
|
79
|
+
name
|
80
|
+
}
|
81
|
+
end
|
82
|
+
|
83
|
+
def clean_thread(name)
|
84
|
+
Thread.new { docker.clean(name) }
|
85
|
+
end
|
86
|
+
|
87
|
+
def reclaim(name)
|
88
|
+
pool << spawn_thread(name, true) if name
|
89
|
+
end
|
90
|
+
|
91
|
+
module SinglePool
|
92
|
+
|
93
|
+
def fetch(name = @previous_name)
|
94
|
+
name || !block_given? ? super : yield(new_name = super)
|
95
|
+
ensure
|
96
|
+
reclaim(new_name)
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
data/lib/docker_helper/proxy.rb
CHANGED
@@ -31,8 +31,10 @@ module DockerHelper
|
|
31
31
|
|
32
32
|
class Proxy
|
33
33
|
|
34
|
-
|
35
|
-
|
34
|
+
DEFAULT_PREFIX = 'docker'
|
35
|
+
|
36
|
+
def initialize(prefix = nil)
|
37
|
+
self.proxy_prefix = prefix || self.class::DEFAULT_PREFIX
|
36
38
|
end
|
37
39
|
|
38
40
|
attr_accessor :proxy_prefix
|
@@ -46,6 +48,10 @@ module DockerHelper
|
|
46
48
|
respond_to?(prefix_method(method))
|
47
49
|
end
|
48
50
|
|
51
|
+
def pool(size = nil, basename = nil, &block)
|
52
|
+
Pool.new(size, basename, self, &block)
|
53
|
+
end
|
54
|
+
|
49
55
|
private
|
50
56
|
|
51
57
|
def prefix_method(method)
|
data/spec/docker_helper_spec.rb
CHANGED
@@ -44,6 +44,15 @@ quix 1.0 789 a week
|
|
44
44
|
|
45
45
|
end
|
46
46
|
|
47
|
+
describe '#port' do
|
48
|
+
|
49
|
+
it 'should return the port' do
|
50
|
+
expect_pipe('0.0.0.0:42', 'port', 'foo', '23', {})
|
51
|
+
expect(subject.docker_port(23, 'foo')).to eq('0.0.0.0:42')
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
47
56
|
describe '#url' do
|
48
57
|
|
49
58
|
it 'should return the URL' do
|
@@ -53,6 +62,128 @@ quix 1.0 789 a week
|
|
53
62
|
|
54
63
|
end
|
55
64
|
|
65
|
+
describe '#ready' do
|
66
|
+
|
67
|
+
def expect_socket(result)
|
68
|
+
expect(subject).to receive(:docker_socket_ready).with(
|
69
|
+
*@host_with_port_ary, a_kind_of(Integer), a_kind_of(Float)
|
70
|
+
).and_return(result)
|
71
|
+
end
|
72
|
+
|
73
|
+
def expect_http(result)
|
74
|
+
expect(subject).to receive(:docker_http_ready).with(
|
75
|
+
*@host_with_port_ary, @path, a_kind_of(Integer), a_kind_of(Float)
|
76
|
+
).and_return(result)
|
77
|
+
end
|
78
|
+
|
79
|
+
before do
|
80
|
+
@host_with_port_str = '0.0.0.0:42'
|
81
|
+
@host_with_port_ary = @host_with_port_str.split(':')
|
82
|
+
end
|
83
|
+
|
84
|
+
describe 'when socket ready' do
|
85
|
+
|
86
|
+
before do
|
87
|
+
expect_socket(true)
|
88
|
+
end
|
89
|
+
|
90
|
+
describe 'without path' do
|
91
|
+
|
92
|
+
before do
|
93
|
+
expect(subject).not_to receive(:docker_http_ready)
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should return true with string' do
|
97
|
+
expect(subject.docker_ready(@host_with_port_str)).to eq(true)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should return true with array' do
|
101
|
+
expect(subject.docker_ready(@host_with_port_ary)).to eq(true)
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
describe 'with path' do
|
107
|
+
|
108
|
+
before do
|
109
|
+
@path = '/path'
|
110
|
+
end
|
111
|
+
|
112
|
+
describe 'when HTTP ready' do
|
113
|
+
|
114
|
+
before do
|
115
|
+
expect_http(true)
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should return true with string' do
|
119
|
+
expect(subject.docker_ready(@host_with_port_str, @path)).to eq(true)
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should return true with array' do
|
123
|
+
expect(subject.docker_ready(@host_with_port_ary, @path)).to eq(true)
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
describe 'when HTTP not ready' do
|
129
|
+
|
130
|
+
before do
|
131
|
+
expect_http(false)
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should return false with string' do
|
135
|
+
expect(subject.docker_ready(@host_with_port_str, @path)).to eq(false)
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'should return false with array' do
|
139
|
+
expect(subject.docker_ready(@host_with_port_ary, @path)).to eq(false)
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
describe 'when socket ready' do
|
149
|
+
|
150
|
+
before do
|
151
|
+
expect_socket(false)
|
152
|
+
expect(subject).not_to receive(:docker_http_ready)
|
153
|
+
end
|
154
|
+
|
155
|
+
describe 'without path' do
|
156
|
+
|
157
|
+
it 'should return false with string' do
|
158
|
+
expect(subject.docker_ready(@host_with_port_str)).to eq(false)
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'should return false with array' do
|
162
|
+
expect(subject.docker_ready(@host_with_port_ary)).to eq(false)
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
describe 'with path' do
|
168
|
+
|
169
|
+
before do
|
170
|
+
@path = '/path'
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'should return false with string' do
|
174
|
+
expect(subject.docker_ready(@host_with_port_str, @path)).to eq(false)
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'should return false with array' do
|
178
|
+
expect(subject.docker_ready(@host_with_port_ary, @path)).to eq(false)
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
56
187
|
describe '#start' do
|
57
188
|
|
58
189
|
it 'should start the container' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: docker_helper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jens Wille
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-09-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hen
|
@@ -66,6 +66,7 @@ files:
|
|
66
66
|
- README
|
67
67
|
- Rakefile
|
68
68
|
- lib/docker_helper.rb
|
69
|
+
- lib/docker_helper/pool.rb
|
69
70
|
- lib/docker_helper/proxy.rb
|
70
71
|
- lib/docker_helper/version.rb
|
71
72
|
- spec/docker_helper_spec.rb
|
@@ -76,13 +77,15 @@ licenses:
|
|
76
77
|
metadata: {}
|
77
78
|
post_install_message: |2+
|
78
79
|
|
79
|
-
docker_helper-0.0.
|
80
|
+
docker_helper-0.0.2 [2014-09-26]:
|
80
81
|
|
81
|
-
*
|
82
|
+
* Added DockerHelper#docker_ready.
|
83
|
+
* Added DockerHelper#docker_port.
|
84
|
+
* Added DockerHelper::Pool.
|
82
85
|
|
83
86
|
rdoc_options:
|
84
87
|
- "--title"
|
85
|
-
- docker_helper Application documentation (v0.0.
|
88
|
+
- docker_helper Application documentation (v0.0.2)
|
86
89
|
- "--charset"
|
87
90
|
- UTF-8
|
88
91
|
- "--line-numbers"
|