synapse 0.12.1 → 0.12.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +1 -0
- data/README.md +64 -55
- data/lib/synapse.rb +6 -6
- data/lib/synapse/file_output.rb +12 -1
- data/lib/synapse/haproxy.rb +14 -4
- data/lib/synapse/service_watcher.rb +11 -19
- data/lib/synapse/service_watcher/README.md +84 -0
- data/lib/synapse/service_watcher/base.rb +3 -3
- data/lib/synapse/service_watcher/dns.rb +1 -1
- data/lib/synapse/service_watcher/docker.rb +4 -3
- data/lib/synapse/service_watcher/ec2tag.rb +13 -9
- data/lib/synapse/service_watcher/marathon.rb +112 -0
- data/lib/synapse/service_watcher/zookeeper.rb +12 -7
- data/lib/synapse/service_watcher/zookeeper_dns.rb +3 -3
- data/lib/synapse/version.rb +1 -1
- data/spec/lib/synapse/file_output_spec.rb +61 -0
- data/spec/lib/synapse/haproxy_spec.rb +14 -1
- data/spec/lib/synapse/service_watcher_base_spec.rb +3 -3
- data/spec/lib/synapse/service_watcher_docker_spec.rb +12 -6
- data/spec/lib/synapse/service_watcher_ec2tags_spec.rb +36 -14
- data/spec/lib/synapse/service_watcher_marathon_spec.rb +191 -0
- data/spec/lib/synapse/service_watcher_spec.rb +102 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/support/minimum.conf.yaml +6 -1
- data/synapse.gemspec +1 -0
- metadata +26 -2
@@ -0,0 +1,191 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'synapse/service_watcher/marathon'
|
3
|
+
|
4
|
+
describe Synapse::ServiceWatcher::MarathonWatcher do
|
5
|
+
let(:mocksynapse) { double() }
|
6
|
+
let(:marathon_host) { '127.0.0.1' }
|
7
|
+
let(:marathon_port) { '8080' }
|
8
|
+
let(:app_name) { 'foo' }
|
9
|
+
let(:check_interval) { 11 }
|
10
|
+
let(:marathon_request_uri) { "#{marathon_host}:#{marathon_port}/v2/apps/#{app_name}/tasks" }
|
11
|
+
let(:config) do
|
12
|
+
{
|
13
|
+
'name' => 'foo',
|
14
|
+
'discovery' => {
|
15
|
+
'method' => 'marathon',
|
16
|
+
'marathon_api_url' => "http://#{marathon_host}:#{marathon_port}",
|
17
|
+
'application_name' => app_name,
|
18
|
+
'check_interval' => check_interval,
|
19
|
+
},
|
20
|
+
'haproxy' => {},
|
21
|
+
}
|
22
|
+
end
|
23
|
+
let(:marathon_response) { { 'tasks' => [] } }
|
24
|
+
|
25
|
+
subject { described_class.new(config, mocksynapse) }
|
26
|
+
|
27
|
+
before do
|
28
|
+
allow(subject.log).to receive(:warn)
|
29
|
+
allow(subject.log).to receive(:info)
|
30
|
+
|
31
|
+
allow(Thread).to receive(:new).and_yield
|
32
|
+
allow(subject).to receive(:sleep)
|
33
|
+
allow(subject).to receive(:only_run_once?).and_return(true)
|
34
|
+
allow(subject).to receive(:splay).and_return(0)
|
35
|
+
|
36
|
+
stub_request(:get, marathon_request_uri).
|
37
|
+
with(:headers => { 'Accept' => 'application/json' }).
|
38
|
+
to_return(:body => JSON.generate(marathon_response))
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'with a valid argument hash' do
|
42
|
+
it 'instantiates' do
|
43
|
+
expect(subject).to be_a(Synapse::ServiceWatcher::MarathonWatcher)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#watch' do
|
48
|
+
context 'when synapse cannot connect to marathon' do
|
49
|
+
before do
|
50
|
+
allow(Net::HTTP).to receive(:new).
|
51
|
+
with(marathon_host, marathon_port.to_i).
|
52
|
+
and_raise(Errno::ECONNREFUSED)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'does not crash' do
|
56
|
+
expect { subject.start }.not_to raise_error
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'requests the proper API endpoint one time' do
|
61
|
+
subject.start
|
62
|
+
expect(a_request(:get, marathon_request_uri)).to have_been_made.times(1)
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'when the API path (marathon_api_path) is customized' do
|
66
|
+
let(:config) do
|
67
|
+
super().tap do |c|
|
68
|
+
c['discovery']['marathon_api_path'] = '/v3/tasks/%{app}'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
let(:marathon_request_uri) { "#{marathon_host}:#{marathon_port}/v3/tasks/#{app_name}" }
|
73
|
+
|
74
|
+
it 'calls the customized path' do
|
75
|
+
subject.start
|
76
|
+
expect(a_request(:get, marathon_request_uri)).to have_been_made.times(1)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'with tasks returned from marathon' do
|
81
|
+
let(:marathon_response) do
|
82
|
+
{
|
83
|
+
'tasks' => [
|
84
|
+
{
|
85
|
+
'host' => 'agouti.local',
|
86
|
+
'id' => 'my-app_1-1396592790353',
|
87
|
+
'ports' => [
|
88
|
+
31336,
|
89
|
+
31337
|
90
|
+
],
|
91
|
+
'stagedAt' => '2014-04-04T06:26:30.355Z',
|
92
|
+
'startedAt' => '2014-04-04T06:26:30.860Z',
|
93
|
+
'version' => '2014-04-04T06:26:23.051Z'
|
94
|
+
},
|
95
|
+
]
|
96
|
+
}
|
97
|
+
end
|
98
|
+
let(:expected_backend_hash) do
|
99
|
+
{
|
100
|
+
'name' => 'agouti.local', 'host' => 'agouti.local', 'port' => 31336
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'adds the task as a backend' do
|
105
|
+
expect(subject).to receive(:set_backends).with([expected_backend_hash])
|
106
|
+
subject.start
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'with a custom port_index' do
|
110
|
+
let(:config) do
|
111
|
+
super().tap do |c|
|
112
|
+
c['discovery']['port_index'] = 1
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
let(:expected_backend_hash) do
|
117
|
+
{
|
118
|
+
'name' => 'agouti.local', 'host' => 'agouti.local', 'port' => 31337
|
119
|
+
}
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'adds the task as a backend' do
|
123
|
+
expect(subject).to receive(:set_backends).with([expected_backend_hash])
|
124
|
+
subject.start
|
125
|
+
end
|
126
|
+
|
127
|
+
context 'when that port_index does not exist' do
|
128
|
+
let(:config) do
|
129
|
+
super().tap { |c| c['discovery']['port_index'] = 999 }
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'does not include the backend' do
|
133
|
+
expect(subject).to receive(:set_backends).with([])
|
134
|
+
subject.start
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'with a task that has not started yet' do
|
140
|
+
let(:marathon_response) do
|
141
|
+
super().tap do |resp|
|
142
|
+
resp['tasks'] << {
|
143
|
+
'host' => 'agouti.local',
|
144
|
+
'id' => 'my-app_2-1396592790353',
|
145
|
+
'ports' => [
|
146
|
+
31336,
|
147
|
+
31337
|
148
|
+
],
|
149
|
+
'stagedAt' => '2014-04-04T06:26:30.355Z',
|
150
|
+
'startedAt' => nil,
|
151
|
+
'version' => '2014-04-04T06:26:23.051Z'
|
152
|
+
}
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'filters tasks that have no startedAt value' do
|
157
|
+
expect(subject).to receive(:set_backends).with([expected_backend_hash])
|
158
|
+
subject.start
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context 'when marathon returns invalid response' do
|
163
|
+
let(:marathon_response) { [] }
|
164
|
+
it 'does not blow up' do
|
165
|
+
expect { subject.start }.to_not raise_error
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
context 'when the job takes a long time for some reason' do
|
170
|
+
let(:job_duration) { 10 } # seconds
|
171
|
+
|
172
|
+
before do
|
173
|
+
actual_time = Time.now
|
174
|
+
time_offset = -1 * job_duration
|
175
|
+
allow(Time).to receive(:now) do
|
176
|
+
# on first run, return the right time
|
177
|
+
# subsequently, add in our job_duration offset
|
178
|
+
actual_time + (time_offset += job_duration)
|
179
|
+
end
|
180
|
+
allow(subject).to receive(:set_backends)
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'only sleeps for the difference' do
|
184
|
+
expect(subject).to receive(:sleep).with(check_interval - job_duration)
|
185
|
+
subject.start
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'synapse/service_watcher'
|
3
|
+
|
4
|
+
describe Synapse::ServiceWatcher do
|
5
|
+
let(:mock_synapse) { double }
|
6
|
+
subject { Synapse::ServiceWatcher }
|
7
|
+
let(:config) do
|
8
|
+
{
|
9
|
+
'haproxy' => {
|
10
|
+
'port' => '8080',
|
11
|
+
'server_port_override' => '8081',
|
12
|
+
},
|
13
|
+
'discovery' => {
|
14
|
+
'method' => 'test'
|
15
|
+
}
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def replace_discovery(new_value)
|
20
|
+
args = config.clone
|
21
|
+
args['discovery'] = new_value
|
22
|
+
args
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'bogus arguments' do
|
26
|
+
it 'complains if discovery method is bogus' do
|
27
|
+
expect {
|
28
|
+
subject.create('test', config, mock_synapse)
|
29
|
+
}.to raise_error(ArgumentError)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'service watcher dispatch' do
|
34
|
+
let (:zookeeper_config) {{
|
35
|
+
'method' => 'zookeeper',
|
36
|
+
'hosts' => 'localhost:2181',
|
37
|
+
'path' => '/smartstack',
|
38
|
+
}}
|
39
|
+
let (:dns_config) {{
|
40
|
+
'method' => 'dns',
|
41
|
+
'servers' => ['localhost'],
|
42
|
+
}}
|
43
|
+
let (:docker_config) {{
|
44
|
+
'method' => 'docker',
|
45
|
+
'servers' => 'localhost',
|
46
|
+
'image_name' => 'servicefoo',
|
47
|
+
'container_port' => 1234,
|
48
|
+
}}
|
49
|
+
let (:ec2_config) {{
|
50
|
+
'method' => 'ec2tag',
|
51
|
+
'tag_name' => 'footag',
|
52
|
+
'tag_value' => 'barvalue',
|
53
|
+
'aws_access_key_id' => 'bogus',
|
54
|
+
'aws_secret_access_key' => 'morebogus',
|
55
|
+
'aws_region' => 'evenmorebogus',
|
56
|
+
}}
|
57
|
+
let (:zookeeper_dns_config) {{
|
58
|
+
'method' => 'zookeeper_dns',
|
59
|
+
'hosts' => 'localhost:2181',
|
60
|
+
'path' => '/smartstack',
|
61
|
+
}}
|
62
|
+
let (:marathon_config) {{
|
63
|
+
'method' => 'marathon',
|
64
|
+
'marathon_api_url' => 'localhost:12345',
|
65
|
+
'application_name' => 'foobar',
|
66
|
+
}}
|
67
|
+
|
68
|
+
it 'creates zookeeper correctly' do
|
69
|
+
expect {
|
70
|
+
subject.create('test', replace_discovery(zookeeper_config), mock_synapse)
|
71
|
+
}.not_to raise_error
|
72
|
+
end
|
73
|
+
it 'creates dns correctly' do
|
74
|
+
expect {
|
75
|
+
subject.create('test', replace_discovery(dns_config), mock_synapse)
|
76
|
+
}.not_to raise_error
|
77
|
+
end
|
78
|
+
it 'creates docker correctly' do
|
79
|
+
expect {
|
80
|
+
subject.create('test', replace_discovery(docker_config), mock_synapse)
|
81
|
+
}.not_to raise_error
|
82
|
+
end
|
83
|
+
it 'creates ec2tag correctly' do
|
84
|
+
expect {
|
85
|
+
subject.create('test', replace_discovery(ec2_config), mock_synapse)
|
86
|
+
}.not_to raise_error
|
87
|
+
end
|
88
|
+
it 'creates zookeeper_dns correctly' do
|
89
|
+
expect {
|
90
|
+
subject.create('test', replace_discovery(zookeeper_dns_config), mock_synapse)
|
91
|
+
}.not_to raise_error
|
92
|
+
end
|
93
|
+
it 'creates marathon correctly' do
|
94
|
+
expect {
|
95
|
+
subject.create('test', replace_discovery(marathon_config), mock_synapse)
|
96
|
+
}.not_to raise_error
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
|
data/spec/spec_helper.rb
CHANGED
data/synapse.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: synapse
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.12.
|
4
|
+
version: 0.12.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-07
|
12
|
+
date: 2015-12-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: aws-sdk
|
@@ -123,6 +123,22 @@ dependencies:
|
|
123
123
|
- - ! '>='
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: webmock
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
126
142
|
description: ': Write a gem description'
|
127
143
|
email:
|
128
144
|
- martin.rhoads@airbnb.com
|
@@ -153,17 +169,22 @@ files:
|
|
153
169
|
- lib/synapse/haproxy.rb
|
154
170
|
- lib/synapse/log.rb
|
155
171
|
- lib/synapse/service_watcher.rb
|
172
|
+
- lib/synapse/service_watcher/README.md
|
156
173
|
- lib/synapse/service_watcher/base.rb
|
157
174
|
- lib/synapse/service_watcher/dns.rb
|
158
175
|
- lib/synapse/service_watcher/docker.rb
|
159
176
|
- lib/synapse/service_watcher/ec2tag.rb
|
177
|
+
- lib/synapse/service_watcher/marathon.rb
|
160
178
|
- lib/synapse/service_watcher/zookeeper.rb
|
161
179
|
- lib/synapse/service_watcher/zookeeper_dns.rb
|
162
180
|
- lib/synapse/version.rb
|
181
|
+
- spec/lib/synapse/file_output_spec.rb
|
163
182
|
- spec/lib/synapse/haproxy_spec.rb
|
164
183
|
- spec/lib/synapse/service_watcher_base_spec.rb
|
165
184
|
- spec/lib/synapse/service_watcher_docker_spec.rb
|
166
185
|
- spec/lib/synapse/service_watcher_ec2tags_spec.rb
|
186
|
+
- spec/lib/synapse/service_watcher_marathon_spec.rb
|
187
|
+
- spec/lib/synapse/service_watcher_spec.rb
|
167
188
|
- spec/spec_helper.rb
|
168
189
|
- spec/support/configuration.rb
|
169
190
|
- spec/support/minimum.conf.yaml
|
@@ -193,10 +214,13 @@ signing_key:
|
|
193
214
|
specification_version: 3
|
194
215
|
summary: ': Write a gem summary'
|
195
216
|
test_files:
|
217
|
+
- spec/lib/synapse/file_output_spec.rb
|
196
218
|
- spec/lib/synapse/haproxy_spec.rb
|
197
219
|
- spec/lib/synapse/service_watcher_base_spec.rb
|
198
220
|
- spec/lib/synapse/service_watcher_docker_spec.rb
|
199
221
|
- spec/lib/synapse/service_watcher_ec2tags_spec.rb
|
222
|
+
- spec/lib/synapse/service_watcher_marathon_spec.rb
|
223
|
+
- spec/lib/synapse/service_watcher_spec.rb
|
200
224
|
- spec/spec_helper.rb
|
201
225
|
- spec/support/configuration.rb
|
202
226
|
- spec/support/minimum.conf.yaml
|