synapse 0.15.1 → 0.16.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/README.md +4 -2
- data/bin/synapse +7 -1
- data/config/synapse.conf.json +12 -1
- data/lib/synapse.rb +60 -20
- data/lib/synapse/config_generator/file_output.rb +10 -2
- data/lib/synapse/config_generator/haproxy.rb +42 -7
- data/lib/synapse/service_watcher/base.rb +2 -0
- data/lib/synapse/service_watcher/dns.rb +7 -1
- data/lib/synapse/service_watcher/zookeeper.rb +123 -72
- data/lib/synapse/statsd.rb +47 -0
- data/lib/synapse/version.rb +1 -1
- data/spec/bin/synapse_spec.rb +56 -0
- data/spec/lib/synapse/file_output_spec.rb +9 -2
- data/spec/lib/synapse/haproxy_spec.rb +158 -1
- data/spec/lib/synapse/service_watcher_dns_spec.rb +51 -0
- data/spec/lib/synapse/service_watcher_zookeeper_spec.rb +45 -0
- data/spec/support/configuration.rb +3 -1
- data/spec/support/minimum.conf.yaml +2 -0
- data/synapse.gemspec +1 -0
- metadata +52 -33
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'datadog/statsd'
|
2
|
+
require 'synapse/log'
|
3
|
+
|
4
|
+
module Synapse
|
5
|
+
module StatsD
|
6
|
+
def statsd
|
7
|
+
@@STATSD ||= StatsD.statsd_for(self.class.name)
|
8
|
+
end
|
9
|
+
|
10
|
+
def statsd_increment(key, tags = [])
|
11
|
+
statsd.increment(key, tags: tags, sample_rate: sample_rate_for(key))
|
12
|
+
end
|
13
|
+
|
14
|
+
def statsd_time(key, tags = [])
|
15
|
+
statsd.time(key, tags: tags, sample_rate: sample_rate_for(key)) do
|
16
|
+
yield
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class << self
|
21
|
+
include Logging
|
22
|
+
|
23
|
+
@@STATSD_HOST = "localhost"
|
24
|
+
@@STATSD_PORT = 8125
|
25
|
+
@@STATSD_SAMPLE_RATE = {}
|
26
|
+
|
27
|
+
def statsd_for(classname)
|
28
|
+
log.debug "synapse: creating statsd client for class '#{classname}' on host '#{@@STATSD_HOST}' port #{@@STATSD_PORT}"
|
29
|
+
Datadog::Statsd.new(@@STATSD_HOST, @@STATSD_PORT)
|
30
|
+
end
|
31
|
+
|
32
|
+
def configure_statsd(opts)
|
33
|
+
@@STATSD_HOST = opts['host'] || @@STATSD_HOST
|
34
|
+
@@STATSD_PORT = (opts['port'] || @@STATSD_PORT).to_i
|
35
|
+
@@STATSD_SAMPLE_RATE = opts['sample_rate'] || {}
|
36
|
+
log.info "synapse: configuring statsd on host '#{@@STATSD_HOST}' port #{@@STATSD_PORT}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def sample_rate_for(key)
|
43
|
+
rate = @@STATSD_SAMPLE_RATE[key]
|
44
|
+
rate.nil? ? 1 : rate
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/synapse/version.rb
CHANGED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'tempfile'
|
3
|
+
|
4
|
+
describe 'parseconfig' do
|
5
|
+
it 'parses a templated config' do
|
6
|
+
allow_any_instance_of(Synapse::Synapse).to receive(:run)
|
7
|
+
expect(Synapse::Synapse).to receive(:new).
|
8
|
+
with(hash_including(
|
9
|
+
{"services" =>
|
10
|
+
{"test" =>
|
11
|
+
{"default_servers" =>
|
12
|
+
[{"name" => "default1", "host" => "localhost", "port" => 8080}],
|
13
|
+
"discovery" =>
|
14
|
+
{"method" => "zookeeper",
|
15
|
+
"path" => "/airbnb/service/logging/event_collector",
|
16
|
+
"hosts" => ["localhost:2181"],
|
17
|
+
"label_filters" =>
|
18
|
+
[{"label" => "tag", "value" => "config value", "condition" => "equals"}]},
|
19
|
+
"haproxy" =>
|
20
|
+
{"port" => 3219,
|
21
|
+
"bind_address" => "localhost",
|
22
|
+
"server_options" => ["some_haproxy_server_option"],
|
23
|
+
"listen" => ["some_haproxy_listen_option"]}}},
|
24
|
+
"haproxy" =>
|
25
|
+
{"reload_command" => "sudo service haproxy reload",
|
26
|
+
"config_file_path" => "/etc/haproxy/haproxy.cfg",
|
27
|
+
"do_writes" => false,
|
28
|
+
"do_reloads" => false,
|
29
|
+
"do_socket" => false,
|
30
|
+
"global" => ["global_test_option"],
|
31
|
+
"defaults" => ["default_test_option"]},
|
32
|
+
"file_output" => {"output_directory" => "/tmp/synapse_file_output_test"}}
|
33
|
+
)).and_call_original
|
34
|
+
stub_const 'ENV', ENV.to_hash.merge(
|
35
|
+
{"SYNAPSE_CONFIG" => "#{File.dirname(__FILE__)}/../support/minimum.conf.yaml",
|
36
|
+
"SYNAPSE_CONFIG_VALUE" => "config value"}
|
37
|
+
)
|
38
|
+
stub_const 'ARGV', []
|
39
|
+
load "#{File.dirname(__FILE__)}/../../bin/synapse"
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'fails if templated config is invalid' do
|
43
|
+
allow_any_instance_of(Synapse::Synapse).to receive(:run)
|
44
|
+
tmpcfg = Tempfile.new 'synapse.conf.yaml'
|
45
|
+
tmpcfg.write '{:a => "<% if %>"}'
|
46
|
+
tmpcfg.flush
|
47
|
+
stub_const 'ENV', ENV.to_hash.merge(
|
48
|
+
{"SYNAPSE_CONFIG" => tmpcfg.to_path,
|
49
|
+
"SYNAPSE_CONFIG_VALUE" => "config value"}
|
50
|
+
)
|
51
|
+
stub_const 'ARGV', []
|
52
|
+
expect {
|
53
|
+
load "#{File.dirname(__FILE__)}/../../bin/synapse"
|
54
|
+
}.to raise_error(SyntaxError)
|
55
|
+
end
|
56
|
+
end
|
@@ -36,6 +36,13 @@ describe Synapse::ConfigGenerator::FileOutput do
|
|
36
36
|
mockWatcher
|
37
37
|
end
|
38
38
|
|
39
|
+
let(:mockwatcher_with_no_name) do
|
40
|
+
mockWatcher = double(Synapse::ServiceWatcher)
|
41
|
+
allow(mockWatcher).to receive(:name).and_return('no_name_service')
|
42
|
+
allow(mockWatcher).to receive(:config_for_generator).and_return({})
|
43
|
+
mockWatcher
|
44
|
+
end
|
45
|
+
|
39
46
|
let(:mockwatcher_disabled) do
|
40
47
|
mockWatcher = double(Synapse::ServiceWatcher)
|
41
48
|
allow(mockWatcher).to receive(:name).and_return('disabled_service')
|
@@ -60,14 +67,14 @@ describe Synapse::ConfigGenerator::FileOutput do
|
|
60
67
|
end
|
61
68
|
|
62
69
|
it 'manages correct files' do
|
63
|
-
subject.update_config([mockwatcher_1, mockwatcher_2, mockwatcher_disabled])
|
70
|
+
subject.update_config([mockwatcher_1, mockwatcher_2, mockwatcher_disabled, mockwatcher_with_no_name])
|
64
71
|
FileUtils.cd(config['file_output']['output_directory']) do
|
65
72
|
expect(Dir.glob('*.json').sort).to eql(['example_service.json', 'foobar_service.json'])
|
66
73
|
end
|
67
74
|
# Should clean up after itself
|
68
75
|
FileUtils.cd(config['file_output']['output_directory']) do
|
69
76
|
FileUtils.touch('disabled_service.json')
|
70
|
-
subject.update_config([mockwatcher_1, mockwatcher_disabled])
|
77
|
+
subject.update_config([mockwatcher_1, mockwatcher_disabled, mockwatcher_with_no_name])
|
71
78
|
expect(Dir.glob('*.json')).to eql(['example_service.json'])
|
72
79
|
end
|
73
80
|
# Should clean up after itself
|
@@ -6,6 +6,12 @@ class MockWatcher; end;
|
|
6
6
|
describe Synapse::ConfigGenerator::Haproxy do
|
7
7
|
subject { Synapse::ConfigGenerator::Haproxy.new(config['haproxy']) }
|
8
8
|
|
9
|
+
let (:nerve_weights_subject) {
|
10
|
+
nerve_weights_subject = subject.clone
|
11
|
+
nerve_weights_subject.opts['use_nerve_weights'] = true
|
12
|
+
nerve_weights_subject
|
13
|
+
}
|
14
|
+
|
9
15
|
let(:maxid) do
|
10
16
|
Synapse::ConfigGenerator::Haproxy::MAX_SERVER_ID
|
11
17
|
end
|
@@ -22,6 +28,29 @@ describe Synapse::ConfigGenerator::Haproxy do
|
|
22
28
|
mockWatcher
|
23
29
|
end
|
24
30
|
|
31
|
+
let(:mockwatcher_with_hashed_haproxy_server_options) do
|
32
|
+
mockWatcher = double(Synapse::ServiceWatcher)
|
33
|
+
allow(mockWatcher).to receive(:name).and_return('example_service')
|
34
|
+
backends = [{ 'host' => 'somehost', 'port' => 5555, 'haproxy_server_options' => {'option_key' => 'option_value'}}]
|
35
|
+
allow(mockWatcher).to receive(:backends).and_return(backends)
|
36
|
+
allow(mockWatcher).to receive(:config_for_generator).and_return({
|
37
|
+
'haproxy' => {'server_options' => "check inter 2000 rise 3 fall 2"}
|
38
|
+
})
|
39
|
+
allow(mockWatcher).to receive(:revision).and_return(1)
|
40
|
+
mockWatcher
|
41
|
+
end
|
42
|
+
|
43
|
+
let(:mockwatcher_with_hashed_server_options) do
|
44
|
+
mockWatcher = double(Synapse::ServiceWatcher)
|
45
|
+
allow(mockWatcher).to receive(:name).and_return('example_service2')
|
46
|
+
backends = [{ 'host' => 'somehost', 'port' => 5555, 'haproxy_server_options' => 'id 12 backup'}]
|
47
|
+
allow(mockWatcher).to receive(:backends).and_return(backends)
|
48
|
+
allow(mockWatcher).to receive(:config_for_generator).and_return({
|
49
|
+
'haproxy' => {'server_options' => {'hash_key' => 'check inter 2000 rise 3 fall 2'}}
|
50
|
+
})
|
51
|
+
mockWatcher
|
52
|
+
end
|
53
|
+
|
25
54
|
let(:mockwatcher_with_server_options) do
|
26
55
|
mockWatcher = double(Synapse::ServiceWatcher)
|
27
56
|
allow(mockWatcher).to receive(:name).and_return('example_service2')
|
@@ -84,6 +113,54 @@ describe Synapse::ConfigGenerator::Haproxy do
|
|
84
113
|
mockWatcher
|
85
114
|
end
|
86
115
|
|
116
|
+
let(:mockwatcher_with_weight) do
|
117
|
+
mockWatcher = double(Synapse::ServiceWatcher)
|
118
|
+
allow(mockWatcher).to receive(:name).and_return('example_weighted_service')
|
119
|
+
backends = [{ 'host' => 'somehost', 'port' => 5555, 'weight' => 1}]
|
120
|
+
allow(mockWatcher).to receive(:backends).and_return(backends)
|
121
|
+
allow(mockWatcher).to receive(:config_for_generator).and_return({
|
122
|
+
'haproxy' => {
|
123
|
+
}
|
124
|
+
})
|
125
|
+
mockWatcher
|
126
|
+
end
|
127
|
+
|
128
|
+
let(:mockwatcher_with_weight_as_string) do
|
129
|
+
mockWatcher = double(Synapse::ServiceWatcher)
|
130
|
+
allow(mockWatcher).to receive(:name).and_return('example_weighted_service')
|
131
|
+
backends = [{ 'host' => 'somehost', 'port' => 5555, 'weight' => '1'}]
|
132
|
+
allow(mockWatcher).to receive(:backends).and_return(backends)
|
133
|
+
allow(mockWatcher).to receive(:config_for_generator).and_return({
|
134
|
+
'haproxy' => {
|
135
|
+
}
|
136
|
+
})
|
137
|
+
mockWatcher
|
138
|
+
end
|
139
|
+
|
140
|
+
let(:mockwatcher_with_weight_as_hash) do
|
141
|
+
mockWatcher = double(Synapse::ServiceWatcher)
|
142
|
+
allow(mockWatcher).to receive(:name).and_return('example_weighted_service')
|
143
|
+
backends = [{ 'host' => 'somehost', 'port' => 5555, 'weight' => {}}]
|
144
|
+
allow(mockWatcher).to receive(:backends).and_return(backends)
|
145
|
+
allow(mockWatcher).to receive(:config_for_generator).and_return({
|
146
|
+
'haproxy' => {
|
147
|
+
}
|
148
|
+
})
|
149
|
+
mockWatcher
|
150
|
+
end
|
151
|
+
|
152
|
+
let(:mockwatcher_with_haproxy_weight_and_nerve_weight) do
|
153
|
+
mockWatcher = double(Synapse::ServiceWatcher)
|
154
|
+
allow(mockWatcher).to receive(:name).and_return('example_weighted_service')
|
155
|
+
backends = [{ 'host' => 'somehost', 'port' => 5555, 'weight' => 99, 'haproxy_server_options' => 'weight 50'}]
|
156
|
+
allow(mockWatcher).to receive(:backends).and_return(backends)
|
157
|
+
allow(mockWatcher).to receive(:config_for_generator).and_return({
|
158
|
+
'haproxy' => {
|
159
|
+
}
|
160
|
+
})
|
161
|
+
mockWatcher
|
162
|
+
end
|
163
|
+
|
87
164
|
let(:mockwatcher_frontend) do
|
88
165
|
mockWatcher = double(Synapse::ServiceWatcher)
|
89
166
|
allow(mockWatcher).to receive(:name).and_return('example_service4')
|
@@ -135,6 +212,17 @@ describe Synapse::ConfigGenerator::Haproxy do
|
|
135
212
|
mockWatcher
|
136
213
|
end
|
137
214
|
|
215
|
+
let(:mockwatcher_with_server_option_templates) do
|
216
|
+
mockWatcher = double(Synapse::ServiceWatcher)
|
217
|
+
allow(mockWatcher).to receive(:name).and_return('example_service7')
|
218
|
+
backends = [{ 'host' => 'somehost', 'port' => 5555, 'haproxy_server_options' => 'id 12 backup'}]
|
219
|
+
allow(mockWatcher).to receive(:backends).and_return(backends)
|
220
|
+
allow(mockWatcher).to receive(:config_for_generator).and_return({
|
221
|
+
'haproxy' => {'server_options' => "check port %{port} inter 2000 rise 3 fall 2"}
|
222
|
+
})
|
223
|
+
mockWatcher
|
224
|
+
end
|
225
|
+
|
138
226
|
describe '#initialize' do
|
139
227
|
it 'succeeds on minimal config' do
|
140
228
|
conf = {
|
@@ -148,6 +236,20 @@ describe Synapse::ConfigGenerator::Haproxy do
|
|
148
236
|
expect{Synapse::ConfigGenerator::Haproxy.new(conf)}.not_to raise_error
|
149
237
|
end
|
150
238
|
|
239
|
+
it 'reads use_nerve_weights in config' do
|
240
|
+
conf = {
|
241
|
+
'global' => [],
|
242
|
+
'defaults' => [],
|
243
|
+
'do_writes' => false,
|
244
|
+
'do_reloads' => false,
|
245
|
+
'do_socket' => false,
|
246
|
+
'use_nerve_weights' => true
|
247
|
+
}
|
248
|
+
expect{Synapse::ConfigGenerator::Haproxy.new(conf)}.not_to raise_error
|
249
|
+
haproxy = Synapse::ConfigGenerator::Haproxy.new(conf)
|
250
|
+
expect(haproxy.opts['use_nerve_weights']).to eql(true)
|
251
|
+
end
|
252
|
+
|
151
253
|
it 'validates req_pairs' do
|
152
254
|
req_pairs = {
|
153
255
|
'do_writes' => 'config_file_path',
|
@@ -171,7 +273,7 @@ describe Synapse::ConfigGenerator::Haproxy do
|
|
171
273
|
|
172
274
|
end
|
173
275
|
|
174
|
-
it 'properly defaults do_writes, do_socket, do_reloads' do
|
276
|
+
it 'properly defaults do_writes, do_socket, do_reloads, use_nerve_weights' do
|
175
277
|
conf = {
|
176
278
|
'global' => [],
|
177
279
|
'defaults' => [],
|
@@ -185,6 +287,7 @@ describe Synapse::ConfigGenerator::Haproxy do
|
|
185
287
|
expect(haproxy.opts['do_writes']).to eql(true)
|
186
288
|
expect(haproxy.opts['do_socket']).to eql(true)
|
187
289
|
expect(haproxy.opts['do_reloads']).to eql(true)
|
290
|
+
expect(haproxy.opts['use_nerve_weights']).to eql(nil)
|
188
291
|
end
|
189
292
|
|
190
293
|
it 'complains when req_pairs are not passed at all' do
|
@@ -311,6 +414,13 @@ describe Synapse::ConfigGenerator::Haproxy do
|
|
311
414
|
expect(subject).to receive(:write_config).with(new_config)
|
312
415
|
subject.update_config(watchers)
|
313
416
|
end
|
417
|
+
|
418
|
+
it 'writes the new config to the file system' do
|
419
|
+
expect(File).to receive(:read).and_return(nil)
|
420
|
+
expect(File).to receive(:write)
|
421
|
+
expect(FileUtils).to receive(:mv)
|
422
|
+
subject.update_config(watchers)
|
423
|
+
end
|
314
424
|
end
|
315
425
|
|
316
426
|
context 'if we do not support config writes' do
|
@@ -481,6 +591,16 @@ describe Synapse::ConfigGenerator::Haproxy do
|
|
481
591
|
expect(subject.generate_backend_stanza(mockwatcher, mockConfig)).to eql(["\nbackend example_service", [], ["\tserver somehost:5555 somehost:5555 id 1 cookie somehost:5555 check inter 2000 rise 3 fall 2"]])
|
482
592
|
end
|
483
593
|
|
594
|
+
it 'ignores non-strings of haproxy_server_options' do
|
595
|
+
mockConfig = []
|
596
|
+
expect(subject.generate_backend_stanza(mockwatcher_with_hashed_haproxy_server_options, mockConfig)).to eql(["\nbackend example_service", [], ["\tserver somehost:5555 somehost:5555 id 1 cookie somehost:5555 check inter 2000 rise 3 fall 2"]])
|
597
|
+
end
|
598
|
+
|
599
|
+
it 'ignores non-strings of server_options' do
|
600
|
+
mockConfig = []
|
601
|
+
expect(subject.generate_backend_stanza(mockwatcher_with_hashed_server_options, mockConfig)).to eql(["\nbackend example_service2", [], ["\tserver somehost:5555 somehost:5555 cookie somehost:5555 id 12 backup"]])
|
602
|
+
end
|
603
|
+
|
484
604
|
describe 'when known backend gets offline' do
|
485
605
|
let(:mockStateCache) do
|
486
606
|
mockCache = double(Synapse::ConfigGenerator::Haproxy::HaproxyState)
|
@@ -610,6 +730,11 @@ describe Synapse::ConfigGenerator::Haproxy do
|
|
610
730
|
expect(subject.generate_backend_stanza(mockwatcher_with_server_options, mockConfig)).to eql(["\nbackend example_service2", [], ["\tserver somehost:5555 somehost:5555 cookie somehost:5555 check inter 2000 rise 3 fall 2 id 12 backup"]])
|
611
731
|
end
|
612
732
|
|
733
|
+
it 'templates haproxy backend options' do
|
734
|
+
mockConfig = []
|
735
|
+
expect(subject.generate_backend_stanza(mockwatcher_with_server_option_templates, mockConfig)).to eql(["\nbackend example_service7", [], ["\tserver somehost:5555 somehost:5555 cookie somehost:5555 check port 5555 inter 2000 rise 3 fall 2 id 12 backup"]])
|
736
|
+
end
|
737
|
+
|
613
738
|
it 'respects haproxy_server_id' do
|
614
739
|
mockConfig = []
|
615
740
|
expect(subject.generate_backend_stanza(mockwatcher_with_server_id, mockConfig)).to eql(
|
@@ -623,6 +748,38 @@ describe Synapse::ConfigGenerator::Haproxy do
|
|
623
748
|
)
|
624
749
|
end
|
625
750
|
|
751
|
+
describe '#use_nerve_weights' do
|
752
|
+
it 'respects weight as integer' do
|
753
|
+
mockConfig = []
|
754
|
+
expect(nerve_weights_subject.generate_backend_stanza(mockwatcher_with_weight, mockConfig)).to eql(
|
755
|
+
["\nbackend example_weighted_service", [], ["\tserver somehost:5555 somehost:5555 id 1 cookie somehost:5555 weight 1"]]
|
756
|
+
)
|
757
|
+
end
|
758
|
+
|
759
|
+
it 'ignores weight if not valid' do
|
760
|
+
mockConfig = []
|
761
|
+
expect(nerve_weights_subject.generate_backend_stanza(mockwatcher_with_weight_as_hash, mockConfig)).to eql(
|
762
|
+
["\nbackend example_weighted_service", [], ["\tserver somehost:5555 somehost:5555 id 1 cookie somehost:5555"]]
|
763
|
+
)
|
764
|
+
end
|
765
|
+
|
766
|
+
it 'ignores haproxy_server_options weight with use_nerve_weights true' do
|
767
|
+
mockConfig = []
|
768
|
+
expect(nerve_weights_subject.generate_backend_stanza(mockwatcher_with_haproxy_weight_and_nerve_weight, mockConfig)).to eql(
|
769
|
+
["\nbackend example_weighted_service", [], ["\tserver somehost:5555 somehost:5555 id 1 cookie somehost:5555 weight 99"]]
|
770
|
+
)
|
771
|
+
end
|
772
|
+
|
773
|
+
it 'ignores nerve weight with use_nerve_weights false' do
|
774
|
+
mockConfig = []
|
775
|
+
expect(subject.generate_backend_stanza(mockwatcher_with_haproxy_weight_and_nerve_weight, mockConfig)).to eql(
|
776
|
+
["\nbackend example_weighted_service", [], ["\tserver somehost:5555 somehost:5555 id 1 cookie somehost:5555 weight 50"]]
|
777
|
+
)
|
778
|
+
end
|
779
|
+
end
|
780
|
+
|
781
|
+
|
782
|
+
|
626
783
|
it 'generates frontend stanza ' do
|
627
784
|
mockConfig = []
|
628
785
|
expect(subject.generate_frontend_stanza(mockwatcher_frontend, mockConfig)).to eql(["\nfrontend example_service4", [], "\tbind localhost:2200", "\tdefault_backend example_service4"])
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'synapse/service_watcher/dns'
|
3
|
+
|
4
|
+
describe Synapse::ServiceWatcher::DnsWatcher do
|
5
|
+
let(:mock_synapse) do
|
6
|
+
mock_synapse = instance_double(Synapse::Synapse)
|
7
|
+
mockgenerator = Synapse::ConfigGenerator::BaseGenerator.new()
|
8
|
+
allow(mock_synapse).to receive(:available_generators).and_return({
|
9
|
+
'haproxy' => mockgenerator
|
10
|
+
})
|
11
|
+
mock_synapse
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:discovery) do
|
15
|
+
{
|
16
|
+
'method' => 'dns',
|
17
|
+
'servers' => servers,
|
18
|
+
'generator_config_path' => 'disabled',
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:config) do
|
23
|
+
{
|
24
|
+
'name' => 'test',
|
25
|
+
'haproxy' => {},
|
26
|
+
'discovery' => discovery,
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
let (:servers) do
|
31
|
+
[
|
32
|
+
{'name' => 'test1', 'host' => 'localhost'},
|
33
|
+
{'name' => 'test2', 'host' => '127.0.0.1'},
|
34
|
+
{'name' => 'test3', 'host' => '::1'},
|
35
|
+
]
|
36
|
+
end
|
37
|
+
|
38
|
+
subject { Synapse::ServiceWatcher::DnsWatcher.new(config, mock_synapse) }
|
39
|
+
|
40
|
+
it 'only resolves hostnames' do
|
41
|
+
resolver = instance_double("Resolv::DNS")
|
42
|
+
allow(subject).to receive(:resolver).and_return(resolver)
|
43
|
+
expect(resolver).to receive(:getaddresses).with('localhost').
|
44
|
+
and_return([Resolv::IPv4.create('127.0.0.2')])
|
45
|
+
expect(subject.send(:resolve_servers)).to eql([
|
46
|
+
[{'name' => 'test1', 'host' => 'localhost'}, ['127.0.0.2']],
|
47
|
+
[{'name' => 'test2', 'host' => '127.0.0.1'}, ['127.0.0.1']],
|
48
|
+
[{'name' => 'test3', 'host' => '::1'}, ['::1']],
|
49
|
+
])
|
50
|
+
end
|
51
|
+
end
|
@@ -124,6 +124,51 @@ describe Synapse::ServiceWatcher::ZookeeperWatcher do
|
|
124
124
|
expect(subject).to receive(:set_backends).with([],{})
|
125
125
|
subject.send(:watcher_callback).call
|
126
126
|
end
|
127
|
+
|
128
|
+
it 'responds fail to ping? when the client is not in any of the connected/connecting/associatin state' do
|
129
|
+
expect(mock_zk).to receive(:associating?).and_return(false)
|
130
|
+
expect(mock_zk).to receive(:connecting?).and_return(false)
|
131
|
+
expect(mock_zk).to receive(:connected?).and_return(false)
|
132
|
+
|
133
|
+
subject.instance_variable_set('@zk', mock_zk)
|
134
|
+
expect(subject.ping?).to be false
|
135
|
+
end
|
136
|
+
|
137
|
+
context "generator_config_path" do
|
138
|
+
let(:discovery) { { 'method' => 'zookeeper', 'hosts' => 'somehost', 'path' => 'some/path', 'generator_config_path' => generator_config_path } }
|
139
|
+
before :each do
|
140
|
+
expect(subject).to receive(:watch)
|
141
|
+
expect(subject).to receive(:discover).and_call_original
|
142
|
+
expect(mock_zk).to receive(:children).with('some/path', {:watch=>true}).and_return(
|
143
|
+
["test_child_1"]
|
144
|
+
)
|
145
|
+
expect(mock_zk).to receive(:get).with('some/path/test_child_1').and_raise(ZK::Exceptions::NoNode)
|
146
|
+
|
147
|
+
subject.instance_variable_set('@zk', mock_zk)
|
148
|
+
expect(subject).to receive(:set_backends).with([],{})
|
149
|
+
end
|
150
|
+
|
151
|
+
context 'when generator_config_path is defined' do
|
152
|
+
let(:generator_config_path) { 'some/other/path' }
|
153
|
+
it 'reads from generator_config_path znode' do
|
154
|
+
expect(mock_zk).to receive(:get).with(generator_config_path, {:watch=>true}).and_return("")
|
155
|
+
|
156
|
+
subject.send(:watcher_callback).call
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'does not crash if there is no zk node' do
|
160
|
+
expect(mock_zk).to receive(:get).with(generator_config_path, {:watch=>true}).and_raise(ZK::Exceptions::NoNode)
|
161
|
+
|
162
|
+
subject.send(:watcher_callback).call
|
163
|
+
end
|
164
|
+
end
|
165
|
+
context 'when generator_config_path is disabled' do
|
166
|
+
let(:generator_config_path) { 'disabled' }
|
167
|
+
it 'does not read from any znode' do
|
168
|
+
subject.send(:watcher_callback).call
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
127
172
|
end
|
128
173
|
|
129
174
|
context 'ZookeeperDnsWatcher' do
|