synapse 0.12.2 → 0.13.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 +7 -0
- data/README.md +37 -11
- data/lib/synapse/haproxy.rb +12 -2
- data/lib/synapse/service_watcher/base.rb +14 -0
- data/lib/synapse/service_watcher/zookeeper.rb +79 -7
- data/lib/synapse/version.rb +1 -1
- data/spec/lib/synapse/haproxy_spec.rb +54 -0
- data/spec/lib/synapse/service_watcher_base_spec.rb +26 -0
- data/spec/lib/synapse/service_watcher_zookeeper_spec.rb +47 -0
- data/synapse.gemspec +2 -1
- metadata +47 -49
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 34b7877f7f8196407e10fafab1a72354e861121c
|
4
|
+
data.tar.gz: 154d642f85c7a1d1ab13078a8adb1a75d295d993
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 06e858b8cd8a0c316baad80264754206ee64615f7ca0f7958ebf7d38a5b07d67968d949d09367dd127b525e1f6710611d48813af224fe3371bd1e2c78c4da343
|
7
|
+
data.tar.gz: 41be259d76cd50f950b4d6e2e217f4c68134a8f71cfcc75bf69842f7d5edee95bac61996412ba8b9a00057ceb52e651aa4837e2146c3c57432929fbbbfb1f641
|
data/README.md
CHANGED
@@ -97,6 +97,11 @@ install synapse with:
|
|
97
97
|
|
98
98
|
```bash
|
99
99
|
$ mkdir -p /opt/smartstack/synapse
|
100
|
+
|
101
|
+
# If you want to install specific versions of dependencies such as an older
|
102
|
+
# version of the aws-sdk, the docker-api, etc, gem install that here *before*
|
103
|
+
# gem installing synapse
|
104
|
+
|
100
105
|
# If you are on Ruby 2.X use --no-document instead of --no-ri --no-rdoc
|
101
106
|
$ gem install synapse --install-dir /opt/smartstack/synapse --no-ri --no-rdoc
|
102
107
|
```
|
@@ -141,25 +146,39 @@ Each value in the services hash is also a hash, and should contain the following
|
|
141
146
|
We've included a number of `watchers` which provide service discovery.
|
142
147
|
Put these into the `discovery` section of the service hash, with these options:
|
143
148
|
|
144
|
-
#####
|
149
|
+
##### Base #####
|
145
150
|
|
146
|
-
The
|
151
|
+
The base watcher is useful in situations where you only want to use the servers in the `default_servers` list.
|
147
152
|
It has only one option:
|
148
153
|
|
149
|
-
* `method`:
|
154
|
+
* `method`: base
|
150
155
|
|
151
156
|
##### Zookeeper #####
|
152
157
|
|
153
158
|
This watcher retrieves a list of servers from zookeeper.
|
154
|
-
It takes the following
|
159
|
+
It takes the following mandatory arguments:
|
155
160
|
|
156
161
|
* `method`: zookeeper
|
157
162
|
* `path`: the zookeeper path where ephemeral nodes will be created for each available service server
|
158
163
|
* `hosts`: the list of zookeeper servers to query
|
159
164
|
|
160
165
|
The watcher assumes that each node under `path` represents a service server.
|
161
|
-
|
162
|
-
|
166
|
+
|
167
|
+
The following arguments are optional:
|
168
|
+
|
169
|
+
* `decode`: A hash containing configuration for how to decode the data found in zookeeper.
|
170
|
+
|
171
|
+
###### Decoding service nodes ######
|
172
|
+
Synapse attempts to decode the data in each of these nodes using JSON and you can control how it is decoded with the `decode` argument. If provided, the `decode` hash should contain the following:
|
173
|
+
|
174
|
+
* `method` (one of ['`nerve`', '`serverset`'], default: '`nerve`'): The kind of data to expect to find in zookeeper nodes
|
175
|
+
* `endpoint_name` (default: nil): If using the `serverset` method, this controls which of the `additionalEndpoints` is chosen instead of the `serviceEndpoint` data. If not supplied the `serverset` method will use the host/port from the `serviceEndpoint` data.
|
176
|
+
|
177
|
+
If the `method` is `nerve`, then we expect to find nerve registrations with a `host` and a `port`.
|
178
|
+
|
179
|
+
If the `method` is `serverset` then we expect to find Finagle ServerSet
|
180
|
+
(also used by [Aurora](https://github.com/apache/aurora/blob/master/docs/user-guide.md#service-discovery)) registrations with a `serviceEndpoint` and optionally one or more `additionalEndpoints`.
|
181
|
+
The Synapse `name` will be automatically deduced from `shard` if present.
|
163
182
|
|
164
183
|
##### Docker #####
|
165
184
|
|
@@ -232,6 +251,7 @@ by unsetting `use_previous_backends`.
|
|
232
251
|
This section is its own hash, which should contain the following keys:
|
233
252
|
|
234
253
|
* `port`: the port (on localhost) where HAProxy will listen for connections to the service. If this is omitted, only a backend stanza (and no frontend stanza) will be generated for this service; you'll need to get traffic to your service yourself via the `shared_frontend` or manual frontends in `extra_sections`
|
254
|
+
* `bind_address`: force HAProxy to listen on this address ( default is localhost ). Setting `bind_address` on a per service basis overrides the global `bind_address` in the top level `haproxy`. Having HAProxy listen for connections on different addresses ( example: service1 listen on 127.0.0.2:443 and service2 listen on 127.0.0.3:443) allows /etc/hosts entries to point to services.
|
235
255
|
* `server_port_override`: the port that discovered servers listen on; you should specify this if your discovery mechanism only discovers names or addresses (like the DNS watcher). If the discovery method discovers a port along with hostnames (like the zookeeper watcher) this option may be left out, but will be used in preference if given.
|
236
256
|
* `server_options`: the haproxy options for each `server` line of the service in HAProxy config; it may be left out.
|
237
257
|
* `frontend`: additional lines passed to the HAProxy config in the `frontend` stanza of this service
|
@@ -239,6 +259,7 @@ This section is its own hash, which should contain the following keys:
|
|
239
259
|
* `backend_name`: The name of the generated HAProxy backend for this service
|
240
260
|
(defaults to the service's key in the `services` section)
|
241
261
|
* `listen`: these lines will be parsed and placed in the correct `frontend`/`backend` section as applicable; you can put lines which are the same for the frontend and backend here.
|
262
|
+
* `backend_order`: optional: how backends should be ordered in the `backend` stanza. (default is shuffling). Setting to `asc` means sorting backends in ascending alphabetical order before generating stanza. `desc` means descending alphabetical order. `no_shuffle` means no shuffling or sorting.
|
242
263
|
* `shared_frontend`: optional: haproxy configuration directives for a shared http frontend (see below)
|
243
264
|
|
244
265
|
<a name="haproxy"/>
|
@@ -259,11 +280,16 @@ The top level `haproxy` section of the config file has the following options:
|
|
259
280
|
* `restart_interval`: number of seconds to wait between restarts of haproxy (default: 2)
|
260
281
|
* `restart_jitter`: percentage, expressed as a float, of jitter to multiply the `restart_interval` by when determining the next
|
261
282
|
restart time. Use this to help prevent healthcheck storms when HAProxy restarts. (default: 0.0)
|
262
|
-
* `state_file_path`: full path on disk (e.g. /tmp/synapse/state.json) for
|
263
|
-
If provided, synapse will store
|
264
|
-
|
265
|
-
|
266
|
-
|
283
|
+
* `state_file_path`: full path on disk (e.g. /tmp/synapse/state.json) for
|
284
|
+
caching haproxy state between reloads. If provided, synapse will store
|
285
|
+
recently seen backends at this location and can "remember" backends across
|
286
|
+
both synapse and HAProxy restarts. Any backends that are "down" in the
|
287
|
+
reporter but listed in the cache will be put into HAProxy disabled. Synapse
|
288
|
+
writes the state file every sixty seconds, so the file's age can be used to
|
289
|
+
monitor that Synapse is alive and making progress. (default: nil)
|
290
|
+
* `state_file_ttl`: the number of seconds that backends should be kept in the
|
291
|
+
state file cache. This only applies if `state_file_path` is provided.
|
292
|
+
(default: 86400)
|
267
293
|
|
268
294
|
Note that a non-default `bind_address` can be dangerous.
|
269
295
|
If you configure an `address:port` combination that is already in use on the system, haproxy will fail to start.
|
data/lib/synapse/haproxy.rb
CHANGED
@@ -686,7 +686,7 @@ module Synapse
|
|
686
686
|
stanza = [
|
687
687
|
"\nfrontend #{watcher.name}",
|
688
688
|
config.map {|c| "\t#{c}"},
|
689
|
-
"\tbind #{@opts['bind_address'] || 'localhost'}:#{watcher.haproxy['port']}",
|
689
|
+
"\tbind #{ watcher.haproxy['bind_address'] || @opts['bind_address'] || 'localhost'}:#{watcher.haproxy['port']}",
|
690
690
|
"\tdefault_backend #{watcher.haproxy.fetch('backend_name', watcher.name)}"
|
691
691
|
]
|
692
692
|
end
|
@@ -721,10 +721,20 @@ module Synapse
|
|
721
721
|
log.debug "synapse: no backends found for watcher #{watcher.name}"
|
722
722
|
end
|
723
723
|
|
724
|
+
keys = case watcher.haproxy['backend_order']
|
725
|
+
when 'asc'
|
726
|
+
backends.keys.sort
|
727
|
+
when 'desc'
|
728
|
+
backends.keys.sort.reverse
|
729
|
+
when 'no_shuffle'
|
730
|
+
backends.keys
|
731
|
+
else
|
732
|
+
backends.keys.shuffle
|
733
|
+
end
|
724
734
|
stanza = [
|
725
735
|
"\nbackend #{watcher.haproxy.fetch('backend_name', watcher.name)}",
|
726
736
|
config.map {|c| "\t#{c}"},
|
727
|
-
|
737
|
+
keys.map {|backend_name|
|
728
738
|
backend = backends[backend_name]
|
729
739
|
b = "\tserver #{backend_name} #{backend['host']}:#{backend['port']}"
|
730
740
|
b = "#{b} cookie #{backend_name}" unless config.include?('mode tcp')
|
@@ -21,6 +21,7 @@ class Synapse::ServiceWatcher
|
|
21
21
|
|
22
22
|
@name = opts['name']
|
23
23
|
@discovery = opts['discovery']
|
24
|
+
@label_filter = @discovery['label_filter'] || false
|
24
25
|
|
25
26
|
@leader_election = opts['leader_election'] || false
|
26
27
|
@leader_last_warn = Time.now - LEADER_WARN_INTERVAL
|
@@ -86,6 +87,8 @@ class Synapse::ServiceWatcher
|
|
86
87
|
|
87
88
|
# if leader election fails, return no backends
|
88
89
|
return []
|
90
|
+
elsif @label_filter
|
91
|
+
return filter_backends_by_label(@backends, @label_filter)
|
89
92
|
end
|
90
93
|
|
91
94
|
return @backends
|
@@ -99,6 +102,17 @@ class Synapse::ServiceWatcher
|
|
99
102
|
log.warn "synapse: warning: a stub watcher with no default servers is pretty useless" if @default_servers.empty?
|
100
103
|
end
|
101
104
|
|
105
|
+
def filter_backends_by_label(backends, label_filter)
|
106
|
+
filtered_backends = []
|
107
|
+
backends.each do |backend|
|
108
|
+
backend_labels = backend['labels'] || {}
|
109
|
+
if label_filter['condition'] == 'equals' and backend_labels[label_filter['label']] == label_filter['value']
|
110
|
+
filtered_backends << backend
|
111
|
+
end
|
112
|
+
end
|
113
|
+
return filtered_backends
|
114
|
+
end
|
115
|
+
|
102
116
|
def set_backends(new_backends)
|
103
117
|
# Aggregate and deduplicate all potential backend service instances.
|
104
118
|
new_backends = (new_backends + @default_servers) if @keep_default_servers
|
@@ -11,6 +11,24 @@ class Synapse::ServiceWatcher
|
|
11
11
|
@@zk_pool_count = {}
|
12
12
|
@@zk_pool_lock = Mutex.new
|
13
13
|
|
14
|
+
def initialize(opts={}, synapse)
|
15
|
+
super(opts, synapse)
|
16
|
+
|
17
|
+
# Alternative deserialization support. By default we use nerve
|
18
|
+
# deserialization, but we also support serverset registries
|
19
|
+
@decode_method = self.method(:nerve_decode)
|
20
|
+
if @discovery['decode']
|
21
|
+
valid_methods = ['nerve', 'serverset']
|
22
|
+
decode_method = @discovery['decode']['method']
|
23
|
+
unless decode_method && valid_methods.include?(decode_method)
|
24
|
+
raise ArgumentError, "missing or invalid decode method #{decode_method}"
|
25
|
+
end
|
26
|
+
if decode_method == 'serverset'
|
27
|
+
@decode_method = self.method(:serverset_decode)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
14
32
|
def start
|
15
33
|
@zk_hosts = @discovery['hosts'].sort.join(',')
|
16
34
|
|
@@ -43,6 +61,57 @@ class Synapse::ServiceWatcher
|
|
43
61
|
unless @discovery['path']
|
44
62
|
end
|
45
63
|
|
64
|
+
# Supported decode methods
|
65
|
+
|
66
|
+
# Airbnb nerve ZK node data looks like this:
|
67
|
+
#
|
68
|
+
# {
|
69
|
+
# "host": "somehostname",
|
70
|
+
# "port": 1234,
|
71
|
+
# }
|
72
|
+
def nerve_decode(data)
|
73
|
+
JSON.parse(data)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Twitter serverset ZK node data looks like this:
|
77
|
+
#
|
78
|
+
# {
|
79
|
+
# "additionalEndpoints": {
|
80
|
+
# "serverset": {
|
81
|
+
# "host": "somehostname",
|
82
|
+
# "port": 31943
|
83
|
+
# },
|
84
|
+
# "http": {
|
85
|
+
# "host": "somehostname",
|
86
|
+
# "port": 31943
|
87
|
+
# },
|
88
|
+
# "otherport": {
|
89
|
+
# "host": "somehostname",
|
90
|
+
# "port": 31944
|
91
|
+
# }
|
92
|
+
# },
|
93
|
+
# "serviceEndpoint": {
|
94
|
+
# "host": "somehostname",
|
95
|
+
# "port": 31943
|
96
|
+
# },
|
97
|
+
# "shard": 0,
|
98
|
+
# "status": "ALIVE"
|
99
|
+
# }
|
100
|
+
def serverset_decode(data)
|
101
|
+
decoded = JSON.parse(data)
|
102
|
+
if @discovery['decode']['endpoint_name']
|
103
|
+
endpoint_name = @discovery['decode']['endpoint_name']
|
104
|
+
raise KeyError, "json data has no additionalEndpoint called #{endpoint_name}" \
|
105
|
+
unless decoded['additionalEndpoints'] && decoded['additionalEndpoints'][endpoint_name]
|
106
|
+
result = decoded['additionalEndpoints'][endpoint_name]
|
107
|
+
else
|
108
|
+
result = decoded['serviceEndpoint']
|
109
|
+
end
|
110
|
+
result['name'] = decoded['shard'] || nil
|
111
|
+
result['name'] = result['name'].to_s unless result['name'].nil?
|
112
|
+
result
|
113
|
+
end
|
114
|
+
|
46
115
|
# helper method that ensures that the discovery path exists
|
47
116
|
def create(path)
|
48
117
|
log.debug "synapse: creating ZK path: #{path}"
|
@@ -62,11 +131,11 @@ class Synapse::ServiceWatcher
|
|
62
131
|
|
63
132
|
begin
|
64
133
|
# TODO: Do less munging, or refactor out this processing
|
65
|
-
host, port, name, weight, haproxy_server_options = deserialize_service_instance(node.first)
|
134
|
+
host, port, name, weight, haproxy_server_options, labels = deserialize_service_instance(node.first)
|
66
135
|
rescue StandardError => e
|
67
136
|
log.error "synapse: invalid data in ZK node #{id} at #{@discovery['path']}: #{e}"
|
68
137
|
else
|
69
|
-
server_port = @server_port_override ? @server_port_override : port
|
138
|
+
server_port = @haproxy['server_port_override'] ? @haproxy['server_port_override'] : port
|
70
139
|
|
71
140
|
# find the numberic id in the node name; used for leader elections if enabled
|
72
141
|
numeric_id = id.split('_').last
|
@@ -76,7 +145,8 @@ class Synapse::ServiceWatcher
|
|
76
145
|
new_backends << {
|
77
146
|
'name' => name, 'host' => host, 'port' => server_port,
|
78
147
|
'id' => numeric_id, 'weight' => weight,
|
79
|
-
'haproxy_server_options' => haproxy_server_options
|
148
|
+
'haproxy_server_options' => haproxy_server_options,
|
149
|
+
'labels' => labels
|
80
150
|
}
|
81
151
|
end
|
82
152
|
end
|
@@ -173,15 +243,17 @@ class Synapse::ServiceWatcher
|
|
173
243
|
# decode the data at a zookeeper endpoint
|
174
244
|
def deserialize_service_instance(data)
|
175
245
|
log.debug "synapse: deserializing process data"
|
176
|
-
decoded =
|
246
|
+
decoded = @decode_method.call(data)
|
177
247
|
|
178
|
-
host = decoded['host'] || (raise
|
179
|
-
port = decoded['port'] || (raise
|
248
|
+
host = decoded['host'] || (raise KeyError, 'instance json data does not have host key')
|
249
|
+
port = decoded['port'] || (raise KeyError, 'instance json data does not have port key')
|
180
250
|
name = decoded['name'] || nil
|
181
251
|
weight = decoded['weight'] || nil
|
182
252
|
haproxy_server_options = decoded['haproxy_server_options'] || nil
|
253
|
+
labels = decoded['labels'] || nil
|
183
254
|
|
184
|
-
return host, port, name, weight, haproxy_server_options
|
255
|
+
return host, port, name, weight, haproxy_server_options, labels
|
185
256
|
end
|
186
257
|
end
|
187
258
|
end
|
259
|
+
|
data/lib/synapse/version.rb
CHANGED
@@ -23,6 +23,21 @@ describe Synapse::Haproxy do
|
|
23
23
|
mockWatcher
|
24
24
|
end
|
25
25
|
|
26
|
+
let(:mockwatcher_frontend) do
|
27
|
+
mockWatcher = double(Synapse::ServiceWatcher)
|
28
|
+
allow(mockWatcher).to receive(:name).and_return('example_service')
|
29
|
+
allow(mockWatcher).to receive(:haproxy).and_return('port' => 2200)
|
30
|
+
mockWatcher
|
31
|
+
end
|
32
|
+
|
33
|
+
let(:mockwatcher_frontend_with_bind_address) do
|
34
|
+
mockWatcher = double(Synapse::ServiceWatcher)
|
35
|
+
allow(mockWatcher).to receive(:name).and_return('example_service')
|
36
|
+
allow(mockWatcher).to receive(:haproxy).and_return('port' => 2200, 'bind_address' => "127.0.0.3")
|
37
|
+
mockWatcher
|
38
|
+
end
|
39
|
+
|
40
|
+
|
26
41
|
it 'updating the config' do
|
27
42
|
expect(subject).to receive(:generate_config)
|
28
43
|
subject.update_config([mockwatcher])
|
@@ -33,6 +48,34 @@ describe Synapse::Haproxy do
|
|
33
48
|
expect(subject.generate_backend_stanza(mockwatcher, mockConfig)).to eql(["\nbackend example_service", [], ["\tserver somehost:5555 somehost:5555 cookie somehost:5555 check inter 2000 rise 3 fall 2"]])
|
34
49
|
end
|
35
50
|
|
51
|
+
describe 'generate backend stanza in correct order' do
|
52
|
+
let(:multiple_backends_stanza_map) do
|
53
|
+
{
|
54
|
+
'asc' => ["\nbackend example_service", [], ["\tserver somehost1:5555 somehost1:5555 cookie somehost1:5555 check inter 2000 rise 3 fall 2", "\tserver somehost2:5555 somehost2:5555 cookie somehost2:5555 check inter 2000 rise 3 fall 2", "\tserver somehost3:5555 somehost3:5555 cookie somehost3:5555 check inter 2000 rise 3 fall 2"]],
|
55
|
+
'desc' => ["\nbackend example_service", [], ["\tserver somehost3:5555 somehost3:5555 cookie somehost3:5555 check inter 2000 rise 3 fall 2", "\tserver somehost2:5555 somehost2:5555 cookie somehost2:5555 check inter 2000 rise 3 fall 2", "\tserver somehost1:5555 somehost1:5555 cookie somehost1:5555 check inter 2000 rise 3 fall 2"]],
|
56
|
+
'no_shuffle' => ["\nbackend example_service", [], ["\tserver somehost1:5555 somehost1:5555 cookie somehost1:5555 check inter 2000 rise 3 fall 2", "\tserver somehost3:5555 somehost3:5555 cookie somehost3:5555 check inter 2000 rise 3 fall 2", "\tserver somehost2:5555 somehost2:5555 cookie somehost2:5555 check inter 2000 rise 3 fall 2"]]
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
let(:mockwatcher_with_multiple_backends) do
|
61
|
+
mockWatcher = double(Synapse::ServiceWatcher)
|
62
|
+
allow(mockWatcher).to receive(:name).and_return('example_service')
|
63
|
+
backends = [{ 'host' => 'somehost1', 'port' => 5555}, {'host' => 'somehost3', 'port' => 5555}, { 'host' => 'somehost2', 'port' => 5555}]
|
64
|
+
allow(mockWatcher).to receive(:backends).and_return(backends)
|
65
|
+
mockWatcher
|
66
|
+
end
|
67
|
+
|
68
|
+
['asc', 'desc', 'no_shuffle'].each do |order_option|
|
69
|
+
context "when #{order_option} is specified for backend_order" do
|
70
|
+
it 'generates backend stanza in correct order' do
|
71
|
+
mockConfig = []
|
72
|
+
allow(mockwatcher_with_multiple_backends).to receive(:haproxy).and_return({'server_options' => "check inter 2000 rise 3 fall 2", 'backend_order' => order_option})
|
73
|
+
expect(subject.generate_backend_stanza(mockwatcher_with_multiple_backends, mockConfig)).to eql(multiple_backends_stanza_map[order_option])
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
36
79
|
it 'generates backend stanza without cookies for tcp mode' do
|
37
80
|
mockConfig = ['mode tcp']
|
38
81
|
expect(subject.generate_backend_stanza(mockwatcher, mockConfig)).to eql(["\nbackend example_service", ["\tmode tcp"], ["\tserver somehost:5555 somehost:5555 check inter 2000 rise 3 fall 2"]])
|
@@ -42,4 +85,15 @@ describe Synapse::Haproxy do
|
|
42
85
|
mockConfig = []
|
43
86
|
expect(subject.generate_backend_stanza(mockwatcher_with_server_options, mockConfig)).to eql(["\nbackend example_service", [], ["\tserver somehost:5555 somehost:5555 cookie somehost:5555 check inter 2000 rise 3 fall 2 backup"]])
|
44
87
|
end
|
88
|
+
|
89
|
+
it 'generates frontend stanza ' do
|
90
|
+
mockConfig = []
|
91
|
+
expect(subject.generate_frontend_stanza(mockwatcher_frontend, mockConfig)).to eql(["\nfrontend example_service", [], "\tbind localhost:2200", "\tdefault_backend example_service"])
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'respects frontend bind_address ' do
|
95
|
+
mockConfig = []
|
96
|
+
expect(subject.generate_frontend_stanza(mockwatcher_frontend_with_bind_address, mockConfig)).to eql(["\nfrontend example_service", [], "\tbind 127.0.0.3:2200", "\tdefault_backend example_service"])
|
97
|
+
end
|
98
|
+
|
45
99
|
end
|
@@ -109,5 +109,31 @@ describe Synapse::ServiceWatcher::BaseWatcher do
|
|
109
109
|
expect(subject.backends).to eq(backends + default_servers)
|
110
110
|
end
|
111
111
|
end
|
112
|
+
|
113
|
+
context 'with label_filter set' do
|
114
|
+
let(:matching_labeled_backends) { [
|
115
|
+
{ 'name' => 'server1', 'host' => 'server1', 'port' => 1111, 'labels' => { 'az' => 'us-east-1a' } },
|
116
|
+
{ 'name' => 'server2', 'host' => 'server2', 'port' => 2222, 'labels' => { 'az' => 'us-east-1a' } },
|
117
|
+
] }
|
118
|
+
let(:non_matching_labeled_backends) { [
|
119
|
+
{ 'name' => 'server3', 'host' => 'server3', 'port' => 3333, 'labels' => { 'az' => 'us-west-1c' } },
|
120
|
+
{ 'name' => 'server4', 'host' => 'server4', 'port' => 4444, 'labels' => { 'az' => 'us-west-2a' } },
|
121
|
+
] }
|
122
|
+
let(:non_labeled_backends) { [
|
123
|
+
{ 'name' => 'server5', 'host' => 'server5', 'port' => 5555 },
|
124
|
+
] }
|
125
|
+
let(:args) {
|
126
|
+
testargs.merge({ 'discovery' => {
|
127
|
+
'method' => 'base',
|
128
|
+
'label_filter' => { 'condition' => 'equals', 'label' => 'az', 'value' => 'us-east-1a' } }
|
129
|
+
})
|
130
|
+
}
|
131
|
+
it 'removes all backends that do not match the label_filter' do
|
132
|
+
expect(subject).to receive(:'reconfigure!').exactly(:once)
|
133
|
+
subject.send(:set_backends, matching_labeled_backends + non_matching_labeled_backends +
|
134
|
+
non_labeled_backends)
|
135
|
+
expect(subject.backends).to eq(matching_labeled_backends)
|
136
|
+
end
|
137
|
+
end
|
112
138
|
end
|
113
139
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'synapse/service_watcher/zookeeper'
|
3
|
+
require 'synapse/service_watcher/zookeeper_dns'
|
4
|
+
|
5
|
+
describe Synapse::ServiceWatcher::ZookeeperWatcher do
|
6
|
+
let(:mock_synapse) { double }
|
7
|
+
let(:config) do
|
8
|
+
{
|
9
|
+
'name' => 'test',
|
10
|
+
'haproxy' => {},
|
11
|
+
'discovery' => discovery,
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:service_data) do
|
16
|
+
{
|
17
|
+
'host' => 'server',
|
18
|
+
'port' => '8888',
|
19
|
+
'name' => 'server',
|
20
|
+
'weight' => '1',
|
21
|
+
'haproxy_server_options' => 'backup',
|
22
|
+
'labels' => { 'az' => 'us-east-1a' }
|
23
|
+
}
|
24
|
+
end
|
25
|
+
let(:service_data_string) { service_data.to_json }
|
26
|
+
let(:deserialized_service_data) {
|
27
|
+
[ service_data['host'], service_data['port'], service_data['name'], service_data['weight'],
|
28
|
+
service_data['haproxy_server_options'], service_data['labels'] ]
|
29
|
+
}
|
30
|
+
|
31
|
+
context 'ZookeeperWatcher' do
|
32
|
+
let(:discovery) { { 'method' => 'zookeeper', 'hosts' => 'somehost','path' => 'some/path' } }
|
33
|
+
subject { Synapse::ServiceWatcher::ZookeeperWatcher.new(config, mock_synapse) }
|
34
|
+
it 'decodes data correctly' do
|
35
|
+
expect(subject.send(:deserialize_service_instance, service_data_string)).to eql(deserialized_service_data)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'ZookeeperDnsWatcher' do
|
40
|
+
let(:discovery) { { 'method' => 'zookeeper_dns', 'hosts' => 'somehost','path' => 'some/path' } }
|
41
|
+
let(:message_queue) { [] }
|
42
|
+
subject { Synapse::ServiceWatcher::ZookeeperDnsWatcher::Zookeeper.new(config, mock_synapse, message_queue) }
|
43
|
+
it 'decodes data correctly' do
|
44
|
+
expect(subject.send(:deserialize_service_instance, service_data_string)).to eql(deserialized_service_data)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/synapse.gemspec
CHANGED
@@ -17,8 +17,9 @@ Gem::Specification.new do |gem|
|
|
17
17
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
18
|
|
19
19
|
gem.add_runtime_dependency "aws-sdk", "~> 1.39"
|
20
|
-
gem.add_runtime_dependency "docker-api", "~> 1.7
|
20
|
+
gem.add_runtime_dependency "docker-api", "~> 1.7"
|
21
21
|
gem.add_runtime_dependency "zk", "~> 1.9.4"
|
22
|
+
gem.add_runtime_dependency "logging", "~> 1.8"
|
22
23
|
|
23
24
|
gem.add_development_dependency "rake"
|
24
25
|
gem.add_development_dependency "rspec", "~> 3.1.0"
|
metadata
CHANGED
@@ -1,145 +1,142 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: synapse
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.13.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Martin Rhoads
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2016-02-18 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: aws-sdk
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- - ~>
|
17
|
+
- - "~>"
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '1.39'
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- - ~>
|
24
|
+
- - "~>"
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '1.39'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: docker-api
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- - ~>
|
31
|
+
- - "~>"
|
36
32
|
- !ruby/object:Gem::Version
|
37
|
-
version: 1.7
|
33
|
+
version: '1.7'
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- - ~>
|
38
|
+
- - "~>"
|
44
39
|
- !ruby/object:Gem::Version
|
45
|
-
version: 1.7
|
40
|
+
version: '1.7'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: zk
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- - ~>
|
45
|
+
- - "~>"
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: 1.9.4
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- - ~>
|
52
|
+
- - "~>"
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: 1.9.4
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: logging
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.8'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.8'
|
62
69
|
- !ruby/object:Gem::Dependency
|
63
70
|
name: rake
|
64
71
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
72
|
requirements:
|
67
|
-
- -
|
73
|
+
- - ">="
|
68
74
|
- !ruby/object:Gem::Version
|
69
75
|
version: '0'
|
70
76
|
type: :development
|
71
77
|
prerelease: false
|
72
78
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
79
|
requirements:
|
75
|
-
- -
|
80
|
+
- - ">="
|
76
81
|
- !ruby/object:Gem::Version
|
77
82
|
version: '0'
|
78
83
|
- !ruby/object:Gem::Dependency
|
79
84
|
name: rspec
|
80
85
|
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
86
|
requirements:
|
83
|
-
- - ~>
|
87
|
+
- - "~>"
|
84
88
|
- !ruby/object:Gem::Version
|
85
89
|
version: 3.1.0
|
86
90
|
type: :development
|
87
91
|
prerelease: false
|
88
92
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
93
|
requirements:
|
91
|
-
- - ~>
|
94
|
+
- - "~>"
|
92
95
|
- !ruby/object:Gem::Version
|
93
96
|
version: 3.1.0
|
94
97
|
- !ruby/object:Gem::Dependency
|
95
98
|
name: pry
|
96
99
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
100
|
requirements:
|
99
|
-
- -
|
101
|
+
- - ">="
|
100
102
|
- !ruby/object:Gem::Version
|
101
103
|
version: '0'
|
102
104
|
type: :development
|
103
105
|
prerelease: false
|
104
106
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
107
|
requirements:
|
107
|
-
- -
|
108
|
+
- - ">="
|
108
109
|
- !ruby/object:Gem::Version
|
109
110
|
version: '0'
|
110
111
|
- !ruby/object:Gem::Dependency
|
111
112
|
name: pry-nav
|
112
113
|
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
114
|
requirements:
|
115
|
-
- -
|
115
|
+
- - ">="
|
116
116
|
- !ruby/object:Gem::Version
|
117
117
|
version: '0'
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
121
|
requirements:
|
123
|
-
- -
|
122
|
+
- - ">="
|
124
123
|
- !ruby/object:Gem::Version
|
125
124
|
version: '0'
|
126
125
|
- !ruby/object:Gem::Dependency
|
127
126
|
name: webmock
|
128
127
|
requirement: !ruby/object:Gem::Requirement
|
129
|
-
none: false
|
130
128
|
requirements:
|
131
|
-
- -
|
129
|
+
- - ">="
|
132
130
|
- !ruby/object:Gem::Version
|
133
131
|
version: '0'
|
134
132
|
type: :development
|
135
133
|
prerelease: false
|
136
134
|
version_requirements: !ruby/object:Gem::Requirement
|
137
|
-
none: false
|
138
135
|
requirements:
|
139
|
-
- -
|
136
|
+
- - ">="
|
140
137
|
- !ruby/object:Gem::Version
|
141
138
|
version: '0'
|
142
|
-
description:
|
139
|
+
description: ": Write a gem description"
|
143
140
|
email:
|
144
141
|
- martin.rhoads@airbnb.com
|
145
142
|
executables:
|
@@ -147,10 +144,10 @@ executables:
|
|
147
144
|
extensions: []
|
148
145
|
extra_rdoc_files: []
|
149
146
|
files:
|
150
|
-
- .gitignore
|
151
|
-
- .mailmap
|
152
|
-
- .rspec
|
153
|
-
- .travis.yml
|
147
|
+
- ".gitignore"
|
148
|
+
- ".mailmap"
|
149
|
+
- ".rspec"
|
150
|
+
- ".travis.yml"
|
154
151
|
- Gemfile
|
155
152
|
- Gemfile.lock
|
156
153
|
- LICENSE.txt
|
@@ -185,34 +182,34 @@ files:
|
|
185
182
|
- spec/lib/synapse/service_watcher_ec2tags_spec.rb
|
186
183
|
- spec/lib/synapse/service_watcher_marathon_spec.rb
|
187
184
|
- spec/lib/synapse/service_watcher_spec.rb
|
185
|
+
- spec/lib/synapse/service_watcher_zookeeper_spec.rb
|
188
186
|
- spec/spec_helper.rb
|
189
187
|
- spec/support/configuration.rb
|
190
188
|
- spec/support/minimum.conf.yaml
|
191
189
|
- synapse.gemspec
|
192
190
|
homepage: ''
|
193
191
|
licenses: []
|
192
|
+
metadata: {}
|
194
193
|
post_install_message:
|
195
194
|
rdoc_options: []
|
196
195
|
require_paths:
|
197
196
|
- lib
|
198
197
|
required_ruby_version: !ruby/object:Gem::Requirement
|
199
|
-
none: false
|
200
198
|
requirements:
|
201
|
-
- -
|
199
|
+
- - ">="
|
202
200
|
- !ruby/object:Gem::Version
|
203
201
|
version: '0'
|
204
202
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
205
|
-
none: false
|
206
203
|
requirements:
|
207
|
-
- -
|
204
|
+
- - ">="
|
208
205
|
- !ruby/object:Gem::Version
|
209
206
|
version: '0'
|
210
207
|
requirements: []
|
211
208
|
rubyforge_project:
|
212
|
-
rubygems_version:
|
209
|
+
rubygems_version: 2.5.1
|
213
210
|
signing_key:
|
214
|
-
specification_version:
|
215
|
-
summary:
|
211
|
+
specification_version: 4
|
212
|
+
summary: ": Write a gem summary"
|
216
213
|
test_files:
|
217
214
|
- spec/lib/synapse/file_output_spec.rb
|
218
215
|
- spec/lib/synapse/haproxy_spec.rb
|
@@ -221,6 +218,7 @@ test_files:
|
|
221
218
|
- spec/lib/synapse/service_watcher_ec2tags_spec.rb
|
222
219
|
- spec/lib/synapse/service_watcher_marathon_spec.rb
|
223
220
|
- spec/lib/synapse/service_watcher_spec.rb
|
221
|
+
- spec/lib/synapse/service_watcher_zookeeper_spec.rb
|
224
222
|
- spec/spec_helper.rb
|
225
223
|
- spec/support/configuration.rb
|
226
224
|
- spec/support/minimum.conf.yaml
|