marathon-api 2.0.0 → 2.0.1
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/.travis.yml +1 -0
- data/bin/marathon +1 -1
- data/lib/marathon.rb +4 -6
- data/lib/marathon/app.rb +27 -21
- data/lib/marathon/connection.rb +11 -11
- data/lib/marathon/constraint.rb +1 -1
- data/lib/marathon/container.rb +2 -2
- data/lib/marathon/container_docker.rb +2 -2
- data/lib/marathon/container_docker_port_mapping.rb +2 -2
- data/lib/marathon/container_volume.rb +1 -1
- data/lib/marathon/deployment.rb +4 -1
- data/lib/marathon/deployment_action.rb +1 -0
- data/lib/marathon/deployment_info.rb +3 -2
- data/lib/marathon/deployment_step.rb +1 -1
- data/lib/marathon/error.rb +24 -16
- data/lib/marathon/event_subscriptions.rb +1 -1
- data/lib/marathon/group.rb +2 -1
- data/lib/marathon/health_check.rb +7 -7
- data/lib/marathon/leader.rb +1 -1
- data/lib/marathon/queue.rb +2 -1
- data/lib/marathon/task.rb +7 -3
- data/lib/marathon/util.rb +7 -7
- data/lib/marathon/version.rb +1 -1
- data/spec/marathon/app_spec.rb +58 -54
- data/spec/marathon/base_spec.rb +10 -10
- data/spec/marathon/container_docker_port_mapping_spec.rb +7 -7
- data/spec/marathon/container_docker_spec.rb +13 -13
- data/spec/marathon/container_spec.rb +9 -9
- data/spec/marathon/container_volume_spec.rb +4 -4
- data/spec/marathon/deployment_action_spec.rb +1 -1
- data/spec/marathon/deployment_info_spec.rb +2 -2
- data/spec/marathon/deployment_spec.rb +19 -19
- data/spec/marathon/deployment_step_spec.rb +4 -4
- data/spec/marathon/error_spec.rb +7 -7
- data/spec/marathon/group_spec.rb +47 -47
- data/spec/marathon/marathon_spec.rb +1 -1
- data/spec/marathon/queue_spec.rb +9 -9
- data/spec/marathon/task_spec.rb +12 -12
- data/spec/marathon/util_spec.rb +17 -17
- metadata +2 -2
data/lib/marathon/leader.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# See https://mesosphere.github.io/marathon/docs/rest-api.html#get-/v2/leader for full list of API's methods.
|
3
3
|
class Marathon::Leader
|
4
4
|
|
5
|
-
def initialize(marathon_instance)
|
5
|
+
def initialize(marathon_instance = Marathon.singleton)
|
6
6
|
@connection = marathon_instance.connection
|
7
7
|
end
|
8
8
|
|
data/lib/marathon/queue.rb
CHANGED
@@ -6,7 +6,8 @@ class Marathon::Queue < Marathon::Base
|
|
6
6
|
|
7
7
|
# Create a new queue element object.
|
8
8
|
# ++hash++: Hash returned by API, including 'app' and 'delay'
|
9
|
-
|
9
|
+
# ++marathon_instance++: MarathonInstance holding a connection to marathon
|
10
|
+
def initialize(hash, marathon_instance = Marathon.singleton)
|
10
11
|
super(hash, %w[delay])
|
11
12
|
@app = Marathon::App.new(info[:app], marathon_instance, true)
|
12
13
|
@marathon_instance = marathon_instance
|
data/lib/marathon/task.rb
CHANGED
@@ -6,7 +6,8 @@ class Marathon::Task < Marathon::Base
|
|
6
6
|
|
7
7
|
# Create a new task object.
|
8
8
|
# ++hash++: Hash including all attributes
|
9
|
-
|
9
|
+
# ++marathon_instance++: MarathonInstance holding a connection to marathon
|
10
|
+
def initialize(hash, marathon_instance = Marathon.singleton)
|
10
11
|
super(hash, ACCESSORS)
|
11
12
|
@marathon_instance = marathon_instance
|
12
13
|
end
|
@@ -17,6 +18,7 @@ class Marathon::Task < Marathon::Base
|
|
17
18
|
def delete!(scale = false)
|
18
19
|
new_task = self.class.delete(id, scale)
|
19
20
|
end
|
21
|
+
|
20
22
|
alias :kill! :delete!
|
21
23
|
|
22
24
|
def to_s
|
@@ -56,8 +58,9 @@ Version: #{version}
|
|
56
58
|
# ++scale++: Scale the app down (i.e. decrement its instances setting by the number of tasks killed)
|
57
59
|
# after killing the specified tasks.
|
58
60
|
def delete(ids, scale = false)
|
59
|
-
Marathon.singleton.tasks.delete(ids,scale)
|
61
|
+
Marathon.singleton.tasks.delete(ids, scale)
|
60
62
|
end
|
63
|
+
|
61
64
|
alias :remove :delete
|
62
65
|
alias :kill :delete
|
63
66
|
|
@@ -67,8 +70,9 @@ Version: #{version}
|
|
67
70
|
# ++scale++: Scale the app down (i.e. decrement its instances setting by the number of tasks killed)
|
68
71
|
# after killing the specified tasks.
|
69
72
|
def delete_all(appId, host = nil, scale = false)
|
70
|
-
Marathon.singleton.tasks.delete_all(appId,host,scale)
|
73
|
+
Marathon.singleton.tasks.delete_all(appId, host, scale)
|
71
74
|
end
|
75
|
+
|
72
76
|
alias :remove_all :delete_all
|
73
77
|
alias :kill_all :delete_all
|
74
78
|
end
|
data/lib/marathon/util.rb
CHANGED
@@ -18,10 +18,10 @@ class Marathon::Util
|
|
18
18
|
unless allowed.include?(value)
|
19
19
|
if nil_allowed
|
20
20
|
raise Marathon::Error::ArgumentError,
|
21
|
-
|
21
|
+
"#{name} must be one of #{allowed.join(', ')} or nil, but is '#{value}'"
|
22
22
|
else
|
23
23
|
raise Marathon::Error::ArgumentError,
|
24
|
-
|
24
|
+
"#{name} must be one of #{allowed.join(', ')} or nil, but is '#{value}'"
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
@@ -43,12 +43,12 @@ class Marathon::Util
|
|
43
43
|
# ++ignore_keys++: don't keywordize hashes under theses keys
|
44
44
|
def keywordize_hash!(hash, ignore_keys = [:env])
|
45
45
|
if hash.is_a?(Hash)
|
46
|
-
hmap!(hash) do |k,v|
|
46
|
+
hmap!(hash) do |k, v|
|
47
47
|
key = k.to_sym
|
48
48
|
if ignore_keys.include?(key) and v.is_a?(Hash)
|
49
|
-
{
|
49
|
+
{key => v}
|
50
50
|
else
|
51
|
-
{
|
51
|
+
{key => keywordize_hash!(v)}
|
52
52
|
end
|
53
53
|
end
|
54
54
|
elsif hash.is_a?(Array)
|
@@ -63,7 +63,7 @@ class Marathon::Util
|
|
63
63
|
def remove_keys(hash, keys)
|
64
64
|
if hash.is_a?(Hash)
|
65
65
|
new_hash = {}
|
66
|
-
hash.each { |k,v| new_hash[k] = remove_keys(v, keys) unless keys.include?(k) }
|
66
|
+
hash.each { |k, v| new_hash[k] = remove_keys(v, keys) unless keys.include?(k) }
|
67
67
|
new_hash
|
68
68
|
elsif hash.is_a?(Array)
|
69
69
|
hash.map { |e| remove_keys(e, keys) }
|
@@ -82,7 +82,7 @@ class Marathon::Util
|
|
82
82
|
if item.nil?
|
83
83
|
nil
|
84
84
|
elsif item.is_a?(Array)
|
85
|
-
item.map {|e| e.to_pretty_s}.join(',')
|
85
|
+
item.map { |e| e.to_pretty_s }.join(',')
|
86
86
|
else
|
87
87
|
item.to_pretty_s
|
88
88
|
end
|
data/lib/marathon/version.rb
CHANGED
data/spec/marathon/app_spec.rb
CHANGED
@@ -4,18 +4,18 @@ describe Marathon::App do
|
|
4
4
|
|
5
5
|
describe '#to_s' do
|
6
6
|
subject { described_class.new({
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
7
|
+
'id' => '/app/foo',
|
8
|
+
'instances' => 1,
|
9
|
+
'tasks' => [],
|
10
|
+
'container' => {
|
11
|
+
:type => 'DOCKER', 'docker' => {'image' => 'foo/bar:latest'},
|
12
|
+
},
|
13
|
+
'env' => {'FOO' => 'BAR', 'blubb' => 'blah'},
|
14
|
+
'constraints' => [['hostname', 'UNIQUE']],
|
15
|
+
'uris' => ['http://example.com/big.tar'],
|
16
|
+
'labels' => {'abc' => '123'},
|
17
|
+
'version' => 'foo-version'
|
18
|
+
}, double(Marathon::MarathonInstance)) }
|
19
19
|
|
20
20
|
let(:expected_string) do
|
21
21
|
"Marathon::App { :id => /app/foo }"
|
@@ -40,7 +40,7 @@ describe Marathon::App do
|
|
40
40
|
end
|
41
41
|
|
42
42
|
describe '#to_json' do
|
43
|
-
subject { described_class.new({
|
43
|
+
subject { described_class.new({'id' => '/app/foo'}, double(Marathon::MarathonInstance)) }
|
44
44
|
|
45
45
|
let(:expected_string) do
|
46
46
|
'{"env":{},"labels":{},"ports":[],"uris":[],"id":"/app/foo"}'
|
@@ -50,7 +50,7 @@ describe Marathon::App do
|
|
50
50
|
end
|
51
51
|
|
52
52
|
describe '#check_read_only' do
|
53
|
-
subject { described_class.new({
|
53
|
+
subject { described_class.new({'id' => '/ubuntu2'}, double(Marathon::MarathonInstance), true) }
|
54
54
|
|
55
55
|
it 'does not allow changing the app' do
|
56
56
|
expect { subject.change!({}) }.to raise_error(Marathon::Error::ArgumentError)
|
@@ -59,8 +59,12 @@ describe Marathon::App do
|
|
59
59
|
|
60
60
|
describe '#container' do
|
61
61
|
subject { described_class.new({
|
62
|
-
|
63
|
-
|
62
|
+
'id' => '/ubuntu2',
|
63
|
+
'container' => {
|
64
|
+
'type' => 'DOCKER',
|
65
|
+
'docker' => {'image' => 'felixb/yocto-httpd'}
|
66
|
+
}
|
67
|
+
}, double(Marathon::MarathonInstance)) }
|
64
68
|
|
65
69
|
it 'has container' do
|
66
70
|
expect(subject.container).to be_instance_of(Marathon::Container)
|
@@ -69,7 +73,7 @@ describe Marathon::App do
|
|
69
73
|
end
|
70
74
|
|
71
75
|
describe '#constraints' do
|
72
|
-
subject { described_class.new({
|
76
|
+
subject { described_class.new({'id' => '/ubuntu2', 'constraints' => [['hostname', 'UNIQUE']]},
|
73
77
|
double(Marathon::MarathonInstance)) }
|
74
78
|
|
75
79
|
it 'has constraints' do
|
@@ -99,7 +103,7 @@ describe Marathon::App do
|
|
99
103
|
end
|
100
104
|
|
101
105
|
describe '#constraints' do
|
102
|
-
subject { described_class.new({
|
106
|
+
subject { described_class.new({'id' => '/ubuntu2', 'healthChecks' => [{'path' => '/ping'}]},
|
103
107
|
double(Marathon::MarathonInstance)) }
|
104
108
|
|
105
109
|
it 'has healthChecks' do
|
@@ -109,7 +113,7 @@ describe Marathon::App do
|
|
109
113
|
end
|
110
114
|
|
111
115
|
describe '#tasks' do
|
112
|
-
subject { described_class.new({
|
116
|
+
subject { described_class.new({'id' => '/ubuntu2'}, double(Marathon::MarathonInstance)) }
|
113
117
|
|
114
118
|
it 'shows already loaded tasks w/o API call' do
|
115
119
|
subject.info[:tasks] = []
|
@@ -142,26 +146,26 @@ describe Marathon::App do
|
|
142
146
|
before(:each) do
|
143
147
|
@apps = double(Marathon::Apps)
|
144
148
|
@marathon_instance = double(Marathon::MarathonInstance, :apps => @apps)
|
145
|
-
@subject = described_class.new({
|
149
|
+
@subject = described_class.new({'id' => '/app/foo'}, @marathon_instance)
|
146
150
|
end
|
147
151
|
|
148
152
|
it 'checks for read only' do
|
149
153
|
expect(@subject).to receive(:check_read_only)
|
150
154
|
expect(@apps).to receive(:change).with(
|
151
155
|
'/app/foo',
|
152
|
-
{:env=>{}, :labels=>{}, :ports=>[], :uris=>[], :id=>"/app/foo"},
|
156
|
+
{:env => {}, :labels => {}, :ports => [], :uris => [], :id => "/app/foo"},
|
153
157
|
false
|
154
|
-
|
158
|
+
)
|
155
159
|
@subject.start!
|
156
160
|
end
|
157
161
|
|
158
162
|
it 'starts the app' do
|
159
163
|
expect(@apps).to receive(:change)
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
164
|
+
.with(
|
165
|
+
'/app/foo',
|
166
|
+
{:env => {}, :labels => {}, :ports => [], :uris => [], :id => "/app/foo"},
|
167
|
+
false
|
168
|
+
)
|
165
169
|
@subject.start!
|
166
170
|
end
|
167
171
|
end
|
@@ -170,7 +174,7 @@ describe Marathon::App do
|
|
170
174
|
before(:each) do
|
171
175
|
@apps = double(Marathon::Apps)
|
172
176
|
@marathon_instance = double(Marathon::MarathonInstance, :apps => @apps)
|
173
|
-
@subject = described_class.new({
|
177
|
+
@subject = described_class.new({'id' => '/app/foo'}, @marathon_instance)
|
174
178
|
end
|
175
179
|
|
176
180
|
it 'checks for read only' do
|
@@ -181,7 +185,7 @@ describe Marathon::App do
|
|
181
185
|
|
182
186
|
it 'refreshs the app' do
|
183
187
|
expect(@apps).to receive(:get).with('/app/foo') do
|
184
|
-
described_class.new({
|
188
|
+
described_class.new({'id' => '/app/foo', 'refreshed' => true}, double(Marathon::MarathonInstance))
|
185
189
|
end
|
186
190
|
@subject.refresh
|
187
191
|
expect(@subject.info[:refreshed]).to be(true)
|
@@ -189,7 +193,7 @@ describe Marathon::App do
|
|
189
193
|
|
190
194
|
it 'returns the app' do
|
191
195
|
expect(@apps).to receive(:get).with('/app/foo') do
|
192
|
-
described_class.new({
|
196
|
+
described_class.new({'id' => '/app/foo'}, double(Marathon::MarathonInstance))
|
193
197
|
end
|
194
198
|
expect(@subject.refresh).to be @subject
|
195
199
|
end
|
@@ -211,13 +215,13 @@ describe Marathon::App do
|
|
211
215
|
|
212
216
|
it 'restarts the app' do
|
213
217
|
expect(@apps).to receive(:restart)
|
214
|
-
|
218
|
+
.with('/app/foo', false)
|
215
219
|
@subject.restart!
|
216
220
|
end
|
217
221
|
|
218
222
|
it 'restarts the app, force' do
|
219
223
|
expect(@apps).to receive(:restart)
|
220
|
-
|
224
|
+
.with('/app/foo', true)
|
221
225
|
@subject.restart!(true)
|
222
226
|
end
|
223
227
|
end
|
@@ -236,7 +240,7 @@ describe Marathon::App do
|
|
236
240
|
end
|
237
241
|
|
238
242
|
it 'changes the app' do
|
239
|
-
expect(@apps).to receive(:change).with('/app/foo', {:instances => 9000
|
243
|
+
expect(@apps).to receive(:change).with('/app/foo', {:instances => 9000}, false)
|
240
244
|
@subject.change!('instances' => 9000, 'version' => 'old-version')
|
241
245
|
end
|
242
246
|
end
|
@@ -256,12 +260,12 @@ describe Marathon::App do
|
|
256
260
|
end
|
257
261
|
|
258
262
|
it 'changes the app' do
|
259
|
-
expect(@subject).to receive(:change!).with({:version => 'old_version'
|
263
|
+
expect(@subject).to receive(:change!).with({:version => 'old_version'}, false)
|
260
264
|
@subject.roll_back!('old_version')
|
261
265
|
end
|
262
266
|
|
263
267
|
it 'changes the app with force' do
|
264
|
-
expect(@subject).to receive(:change!).with({:version => 'old_version'
|
268
|
+
expect(@subject).to receive(:change!).with({:version => 'old_version'}, true)
|
265
269
|
@subject.roll_back!('old_version', true)
|
266
270
|
end
|
267
271
|
end
|
@@ -320,23 +324,23 @@ describe Marathon::App do
|
|
320
324
|
|
321
325
|
it 'passes arguments to api call' do
|
322
326
|
expect(Marathon.connection).to receive(:get)
|
323
|
-
|
324
|
-
|
327
|
+
.with('/v2/apps', {:cmd => 'foo', :embed => 'apps.tasks'})
|
328
|
+
.and_return({'apps' => []})
|
325
329
|
subject.list('foo', 'apps.tasks')
|
326
330
|
end
|
327
331
|
|
328
332
|
it 'passing id argument to api call' do
|
329
333
|
expect(Marathon.connection).to receive(:get)
|
330
|
-
|
331
|
-
|
334
|
+
.with('/v2/apps', {:id => '/app/foo'})
|
335
|
+
.and_return({'apps' => []})
|
332
336
|
subject.list(nil, nil, '/app/foo')
|
333
337
|
end
|
334
338
|
|
335
339
|
it 'passing label argument to api call' do
|
336
340
|
expect(Marathon.connection).to receive(:get)
|
337
|
-
|
338
|
-
|
339
|
-
subject.list(nil, nil
|
341
|
+
.with('/v2/apps', {:label => 'abc'})
|
342
|
+
.and_return({'apps' => []})
|
343
|
+
subject.list(nil, nil, nil, 'abc')
|
340
344
|
end
|
341
345
|
|
342
346
|
it 'raises error when run with strange embed' do
|
@@ -358,12 +362,12 @@ describe Marathon::App do
|
|
358
362
|
|
359
363
|
it 'starts the app', :vcr do
|
360
364
|
app = subject.start({
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
365
|
+
:id => '/test-app',
|
366
|
+
:cmd => 'sleep 10',
|
367
|
+
:instances => 1,
|
368
|
+
:cpus => 0.1,
|
369
|
+
:mem => 32
|
370
|
+
})
|
367
371
|
expect(app).to be_instance_of(described_class)
|
368
372
|
expect(app.id).to eq('/test-app')
|
369
373
|
expect(app.instances).to eq(1)
|
@@ -402,7 +406,7 @@ describe Marathon::App do
|
|
402
406
|
|
403
407
|
it 'deletes the app', :vcr do
|
404
408
|
expect(subject.delete('/test-app'))
|
405
|
-
|
409
|
+
.to be_instance_of(Marathon::DeploymentInfo)
|
406
410
|
end
|
407
411
|
|
408
412
|
it 'fails deleting not existing app', :vcr do
|
@@ -430,15 +434,15 @@ describe Marathon::App do
|
|
430
434
|
subject { described_class }
|
431
435
|
|
432
436
|
it 'changes the app', :vcr do
|
433
|
-
expect(subject.change('/ubuntu2', {
|
434
|
-
|
435
|
-
expect(subject.change('/ubuntu2', {
|
436
|
-
|
437
|
+
expect(subject.change('/ubuntu2', {'instances' => 2}, true))
|
438
|
+
.to be_instance_of(Marathon::DeploymentInfo)
|
439
|
+
expect(subject.change('/ubuntu2', {'instances' => 1}, true))
|
440
|
+
.to be_instance_of(Marathon::DeploymentInfo)
|
437
441
|
end
|
438
442
|
|
439
443
|
it 'fails with stange attributes', :vcr do
|
440
444
|
expect {
|
441
|
-
subject.change('/ubuntu2', {
|
445
|
+
subject.change('/ubuntu2', {'instances' => 'foo'})
|
442
446
|
}.to raise_error(Marathon::Error::ClientError)
|
443
447
|
end
|
444
448
|
end
|
data/spec/marathon/base_spec.rb
CHANGED
@@ -16,10 +16,10 @@ describe Marathon::Base do
|
|
16
16
|
|
17
17
|
describe '#to_json' do
|
18
18
|
subject { described_class.new({
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
'app' => {'id' => '/app/foo'},
|
20
|
+
:foo => 'blubb',
|
21
|
+
:bar => 1
|
22
|
+
}) }
|
23
23
|
|
24
24
|
let(:expected_string) do
|
25
25
|
'{"foo":"blubb","bar":1,"app":{"id":"/app/foo"}}'
|
@@ -30,9 +30,9 @@ describe Marathon::Base do
|
|
30
30
|
|
31
31
|
describe '#attr_readers' do
|
32
32
|
subject { described_class.new({
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
'foo' => 'blubb',
|
34
|
+
:bar => 1
|
35
|
+
}, [:foo, 'bar']) }
|
36
36
|
|
37
37
|
its(:info) { should == {:foo => 'blubb', :bar => 1} }
|
38
38
|
its(:foo) { should == 'blubb' }
|
@@ -41,9 +41,9 @@ describe Marathon::Base do
|
|
41
41
|
|
42
42
|
describe '#attr_readers, from string array' do
|
43
43
|
subject { described_class.new({
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
'foo' => 'blubb',
|
45
|
+
:bar => 1
|
46
|
+
}, %w[foo bar]) }
|
47
47
|
|
48
48
|
its(:info) { should == {:foo => 'blubb', :bar => 1} }
|
49
49
|
its(:foo) { should == 'blubb' }
|
@@ -4,7 +4,7 @@ CONTAINER_DOCKER_PORT_MAPPING_EXAMPLE = {
|
|
4
4
|
:protocol => 'tcp',
|
5
5
|
:hostPort => 0,
|
6
6
|
:containerPort => 8080
|
7
|
-
|
7
|
+
}
|
8
8
|
|
9
9
|
describe Marathon::ContainerDockerPortMapping do
|
10
10
|
|
@@ -13,23 +13,23 @@ describe Marathon::ContainerDockerPortMapping do
|
|
13
13
|
|
14
14
|
it 'should fail with invalid protocol' do
|
15
15
|
expect { subject.new(:protocol => 'foo', :containerPort => 8080) }
|
16
|
-
|
16
|
+
.to raise_error(Marathon::Error::ArgumentError, /protocol must be one of /)
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'should fail with invalid containerPort' do
|
20
20
|
expect { subject.new(:containerPort => 'foo') }
|
21
|
-
|
21
|
+
.to raise_error(Marathon::Error::ArgumentError, /containerPort must be/)
|
22
22
|
expect { subject.new(:containerPort => 0) }
|
23
|
-
|
23
|
+
.not_to raise_error
|
24
24
|
expect { subject.new(:containerPort => -1) }
|
25
|
-
|
25
|
+
.to raise_error(Marathon::Error::ArgumentError, /containerPort must be/)
|
26
26
|
end
|
27
27
|
|
28
28
|
it 'should fail with invalid hostPort' do
|
29
29
|
expect { subject.new(:hostPort => 'foo', :containerPort => 8080) }
|
30
|
-
|
30
|
+
.to raise_error(Marathon::Error::ArgumentError, /hostPort must be/)
|
31
31
|
expect { subject.new(:hostPort => -1, :containerPort => 8080) }
|
32
|
-
|
32
|
+
.to raise_error(Marathon::Error::ArgumentError, /hostPort must be/)
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|