synapse 0.12.1 → 0.12.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.
- 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
@@ -1,7 +1,7 @@
|
|
1
1
|
require "synapse/service_watcher/base"
|
2
2
|
require 'docker'
|
3
3
|
|
4
|
-
|
4
|
+
class Synapse::ServiceWatcher
|
5
5
|
class DockerWatcher < BaseWatcher
|
6
6
|
def start
|
7
7
|
@check_interval = @discovery['check_interval'] || 15.0
|
@@ -74,10 +74,11 @@ module Synapse
|
|
74
74
|
cnts.each do |cnt|
|
75
75
|
cnt['Ports'] = rewrite_container_ports cnt['Ports']
|
76
76
|
end
|
77
|
-
# Discover containers that match the image/port we're interested in
|
77
|
+
# Discover containers that match the image/port we're interested in and have the port mapped to the host
|
78
78
|
cnts = cnts.find_all do |cnt|
|
79
79
|
cnt["Image"].rpartition(":").first == @discovery["image_name"] \
|
80
|
-
and cnt["Ports"].has_key?(@discovery["container_port"].to_s())
|
80
|
+
and cnt["Ports"].has_key?(@discovery["container_port"].to_s()) \
|
81
|
+
and cnt["Ports"][@discovery["container_port"].to_s()].length > 0
|
81
82
|
end
|
82
83
|
cnts.map do |cnt|
|
83
84
|
{
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'synapse/service_watcher/base'
|
2
2
|
require 'aws-sdk'
|
3
3
|
|
4
|
-
|
5
|
-
class
|
4
|
+
class Synapse::ServiceWatcher
|
5
|
+
class Ec2tagWatcher < BaseWatcher
|
6
6
|
|
7
7
|
attr_reader :check_interval
|
8
8
|
|
@@ -41,15 +41,18 @@ module Synapse
|
|
41
41
|
"Missing server_port_override for service #{@name} - which port are backends listening on?"
|
42
42
|
end
|
43
43
|
|
44
|
-
unless @haproxy['server_port_override'].match(/^\d+$/)
|
44
|
+
unless @haproxy['server_port_override'].to_s.match(/^\d+$/)
|
45
45
|
raise ArgumentError, "Invalid server_port_override value"
|
46
46
|
end
|
47
47
|
|
48
|
-
#
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
48
|
+
# aws region is optional in the SDK, aws will use a default value if not provided
|
49
|
+
unless @discovery['aws_region'] || ENV['AWS_REGION']
|
50
|
+
log.info "aws region is missing, will use default"
|
51
|
+
end
|
52
|
+
# access key id & secret are optional, might be using IAM instance profile for credentials
|
53
|
+
unless ((@discovery['aws_access_key_id'] || ENV['aws_access_key_id']) \
|
54
|
+
&& (@discovery['aws_secret_access_key'] || ENV['aws_secret_access_key'] ))
|
55
|
+
log.info "aws access key id & secret not set in config or env variables for service #{name}, will attempt to use IAM instance profile"
|
53
56
|
end
|
54
57
|
end
|
55
58
|
|
@@ -60,10 +63,11 @@ module Synapse
|
|
60
63
|
if set_backends(discover_instances)
|
61
64
|
log.info "synapse: ec2tag watcher backends have changed."
|
62
65
|
end
|
63
|
-
sleep_until_next_check(start)
|
64
66
|
rescue Exception => e
|
65
67
|
log.warn "synapse: error in ec2tag watcher thread: #{e.inspect}"
|
66
68
|
log.warn e.backtrace
|
69
|
+
ensure
|
70
|
+
sleep_until_next_check(start)
|
67
71
|
end
|
68
72
|
end
|
69
73
|
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'synapse/service_watcher/base'
|
2
|
+
require 'json'
|
3
|
+
require 'net/http'
|
4
|
+
require 'resolv'
|
5
|
+
|
6
|
+
class Synapse::ServiceWatcher
|
7
|
+
class MarathonWatcher < BaseWatcher
|
8
|
+
def start
|
9
|
+
@check_interval = @discovery['check_interval'] || 10.0
|
10
|
+
@connection = nil
|
11
|
+
@watcher = Thread.new { sleep splay; watch }
|
12
|
+
end
|
13
|
+
|
14
|
+
def stop
|
15
|
+
@connection.finish
|
16
|
+
rescue
|
17
|
+
# pass
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def validate_discovery_opts
|
23
|
+
required_opts = %w[marathon_api_url application_name]
|
24
|
+
|
25
|
+
required_opts.each do |opt|
|
26
|
+
if @discovery.fetch(opt, '').empty?
|
27
|
+
raise ArgumentError,
|
28
|
+
"a value for services.#{@name}.discovery.#{opt} must be specified"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def attempt_marathon_connection
|
34
|
+
marathon_api_path = @discovery.fetch('marathon_api_path', '/v2/apps/%{app}/tasks')
|
35
|
+
marathon_api_path = marathon_api_path % { app: @discovery['application_name'] }
|
36
|
+
|
37
|
+
@marathon_api = URI.join(@discovery['marathon_api_url'], marathon_api_path)
|
38
|
+
|
39
|
+
begin
|
40
|
+
@connection = Net::HTTP.new(@marathon_api.host, @marathon_api.port)
|
41
|
+
@connection.open_timeout = 5
|
42
|
+
@connection.start
|
43
|
+
rescue => ex
|
44
|
+
@connection = nil
|
45
|
+
log.error "synapse: could not connect to marathon at #{@marathon_api}: #{ex}"
|
46
|
+
|
47
|
+
raise ex
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def watch
|
52
|
+
until @should_exit
|
53
|
+
retry_count = 0
|
54
|
+
start = Time.now
|
55
|
+
|
56
|
+
begin
|
57
|
+
if @connection.nil?
|
58
|
+
attempt_marathon_connection
|
59
|
+
end
|
60
|
+
|
61
|
+
req = Net::HTTP::Get.new(@marathon_api.request_uri)
|
62
|
+
req['Accept'] = 'application/json'
|
63
|
+
response = @connection.request(req)
|
64
|
+
|
65
|
+
tasks = JSON.parse(response.body).fetch('tasks', [])
|
66
|
+
port_index = @discovery['port_index'] || 0
|
67
|
+
backends = tasks.keep_if { |task| task['startedAt'] }.map do |task|
|
68
|
+
{
|
69
|
+
'name' => task['host'],
|
70
|
+
'host' => task['host'],
|
71
|
+
'port' => task['ports'][port_index],
|
72
|
+
}
|
73
|
+
end.sort_by { |task| task['name'] }
|
74
|
+
|
75
|
+
invalid_backends = backends.find_all { |b| b['port'].nil? }
|
76
|
+
if invalid_backends.any?
|
77
|
+
backends = backends - invalid_backends
|
78
|
+
|
79
|
+
invalid_backends.each do |backend|
|
80
|
+
log.error "synapse: port index #{port_index} not found in task's port array!"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
set_backends(backends)
|
85
|
+
rescue EOFError
|
86
|
+
# If the persistent HTTP connection is severed, we can automatically
|
87
|
+
# retry
|
88
|
+
log.info "synapse: marathon HTTP API disappeared, reconnecting..."
|
89
|
+
|
90
|
+
retry if (retry_count += 1) == 1
|
91
|
+
rescue => e
|
92
|
+
log.warn "synapse: error in watcher thread: #{e.inspect}"
|
93
|
+
log.warn e.backtrace.join("\n")
|
94
|
+
@connection = nil
|
95
|
+
ensure
|
96
|
+
elapsed_time = Time.now - start
|
97
|
+
sleep (@check_interval - elapsed_time) if elapsed_time < @check_interval
|
98
|
+
end
|
99
|
+
|
100
|
+
@should_exit = true if only_run_once? # for testability
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def splay
|
105
|
+
Random.rand(@check_interval)
|
106
|
+
end
|
107
|
+
|
108
|
+
def only_run_once?
|
109
|
+
false
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -3,7 +3,7 @@ require "synapse/service_watcher/base"
|
|
3
3
|
require 'thread'
|
4
4
|
require 'zk'
|
5
5
|
|
6
|
-
|
6
|
+
class Synapse::ServiceWatcher
|
7
7
|
class ZookeeperWatcher < BaseWatcher
|
8
8
|
NUMBERS_RE = /^\d+$/
|
9
9
|
|
@@ -61,7 +61,8 @@ module Synapse
|
|
61
61
|
node = @zk.get("#{@discovery['path']}/#{id}")
|
62
62
|
|
63
63
|
begin
|
64
|
-
|
64
|
+
# TODO: Do less munging, or refactor out this processing
|
65
|
+
host, port, name, weight, haproxy_server_options = deserialize_service_instance(node.first)
|
65
66
|
rescue StandardError => e
|
66
67
|
log.error "synapse: invalid data in ZK node #{id} at #{@discovery['path']}: #{e}"
|
67
68
|
else
|
@@ -72,7 +73,11 @@ module Synapse
|
|
72
73
|
numeric_id = NUMBERS_RE =~ numeric_id ? numeric_id.to_i : nil
|
73
74
|
|
74
75
|
log.debug "synapse: discovered backend #{name} at #{host}:#{server_port} for service #{@name}"
|
75
|
-
new_backends << {
|
76
|
+
new_backends << {
|
77
|
+
'name' => name, 'host' => host, 'port' => server_port,
|
78
|
+
'id' => numeric_id, 'weight' => weight,
|
79
|
+
'haproxy_server_options' => haproxy_server_options
|
80
|
+
}
|
76
81
|
end
|
77
82
|
end
|
78
83
|
|
@@ -84,13 +89,12 @@ module Synapse
|
|
84
89
|
return if @zk.nil?
|
85
90
|
log.debug "synapse: setting watch at #{@discovery['path']}"
|
86
91
|
|
87
|
-
@watcher.
|
88
|
-
@watcher = @zk.register(@discovery['path'], &watcher_callback)
|
92
|
+
@watcher = @zk.register(@discovery['path'], &watcher_callback) unless @watcher
|
89
93
|
|
90
94
|
# Verify that we actually set up the watcher.
|
91
95
|
unless @zk.exists?(@discovery['path'], :watch => true)
|
92
96
|
log.error "synapse: zookeeper watcher path #{@discovery['path']} does not exist!"
|
93
|
-
|
97
|
+
zk_cleanup
|
94
98
|
end
|
95
99
|
log.debug "synapse: set watch at #{@discovery['path']}"
|
96
100
|
end
|
@@ -175,8 +179,9 @@ module Synapse
|
|
175
179
|
port = decoded['port'] || (raise ValueError, 'instance json data does not have port key')
|
176
180
|
name = decoded['name'] || nil
|
177
181
|
weight = decoded['weight'] || nil
|
182
|
+
haproxy_server_options = decoded['haproxy_server_options'] || nil
|
178
183
|
|
179
|
-
return host, port, name, weight
|
184
|
+
return host, port, name, weight, haproxy_server_options
|
180
185
|
end
|
181
186
|
end
|
182
187
|
end
|
@@ -19,7 +19,7 @@ require 'thread'
|
|
19
19
|
# for messages indicating that new servers are available, the check interval
|
20
20
|
# has passed (triggering a re-resolve), or that the watcher should shut down.
|
21
21
|
# The DNS watcher is responsible for the actual reconfiguring of backends.
|
22
|
-
|
22
|
+
class Synapse::ServiceWatcher
|
23
23
|
class ZookeeperDnsWatcher < BaseWatcher
|
24
24
|
|
25
25
|
# Valid messages that can be passed through the internal message queue
|
@@ -46,7 +46,7 @@ module Synapse
|
|
46
46
|
CHECK_INTERVAL_MESSAGE = CheckInterval.new
|
47
47
|
end
|
48
48
|
|
49
|
-
class Dns < Synapse::DnsWatcher
|
49
|
+
class Dns < Synapse::ServiceWatcher::DnsWatcher
|
50
50
|
|
51
51
|
# Overrides the discovery_servers method on the parent class
|
52
52
|
attr_accessor :discovery_servers
|
@@ -106,7 +106,7 @@ module Synapse
|
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
109
|
-
class Zookeeper < Synapse::ZookeeperWatcher
|
109
|
+
class Zookeeper < Synapse::ServiceWatcher::ZookeeperWatcher
|
110
110
|
def initialize(opts={}, synapse, message_queue)
|
111
111
|
super(opts, synapse)
|
112
112
|
|
data/lib/synapse/version.rb
CHANGED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
describe Synapse::FileOutput do
|
5
|
+
subject { Synapse::FileOutput.new(config['file_output']) }
|
6
|
+
|
7
|
+
before(:example) do
|
8
|
+
FileUtils.mkdir_p(config['file_output']['output_directory'])
|
9
|
+
end
|
10
|
+
|
11
|
+
after(:example) do
|
12
|
+
FileUtils.rm_r(config['file_output']['output_directory'])
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:mockwatcher_1) do
|
16
|
+
mockWatcher = double(Synapse::ServiceWatcher)
|
17
|
+
allow(mockWatcher).to receive(:name).and_return('example_service')
|
18
|
+
backends = [{ 'host' => 'somehost', 'port' => 5555}]
|
19
|
+
allow(mockWatcher).to receive(:backends).and_return(backends)
|
20
|
+
mockWatcher
|
21
|
+
end
|
22
|
+
let(:mockwatcher_2) do
|
23
|
+
mockWatcher = double(Synapse::ServiceWatcher)
|
24
|
+
allow(mockWatcher).to receive(:name).and_return('foobar_service')
|
25
|
+
backends = [{ 'host' => 'somehost', 'port' => 1234}]
|
26
|
+
allow(mockWatcher).to receive(:backends).and_return(backends)
|
27
|
+
mockWatcher
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'updates the config' do
|
31
|
+
expect(subject).to receive(:write_backends_to_file)
|
32
|
+
subject.update_config([mockwatcher_1])
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'manages correct files' do
|
36
|
+
subject.update_config([mockwatcher_1, mockwatcher_2])
|
37
|
+
FileUtils.cd(config['file_output']['output_directory']) do
|
38
|
+
expect(Dir.glob('*.json')).to eql(['example_service.json', 'foobar_service.json'])
|
39
|
+
end
|
40
|
+
# Should clean up after itself
|
41
|
+
subject.update_config([mockwatcher_1])
|
42
|
+
FileUtils.cd(config['file_output']['output_directory']) do
|
43
|
+
expect(Dir.glob('*.json')).to eql(['example_service.json'])
|
44
|
+
end
|
45
|
+
# Should clean up after itself
|
46
|
+
subject.update_config([])
|
47
|
+
FileUtils.cd(config['file_output']['output_directory']) do
|
48
|
+
expect(Dir.glob('*.json')).to eql([])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'writes correct content' do
|
53
|
+
subject.update_config([mockwatcher_1])
|
54
|
+
data_path = File.join(config['file_output']['output_directory'],
|
55
|
+
"example_service.json")
|
56
|
+
old_backends = JSON.load(File.read(data_path))
|
57
|
+
expect(old_backends.length).to eql(1)
|
58
|
+
expect(old_backends.first['host']).to eql('somehost')
|
59
|
+
expect(old_backends.first['port']).to eql(5555)
|
60
|
+
end
|
61
|
+
end
|
@@ -8,7 +8,16 @@ describe Synapse::Haproxy do
|
|
8
8
|
let(:mockwatcher) do
|
9
9
|
mockWatcher = double(Synapse::ServiceWatcher)
|
10
10
|
allow(mockWatcher).to receive(:name).and_return('example_service')
|
11
|
-
backends = [{ 'host' => 'somehost', 'port' =>
|
11
|
+
backends = [{ 'host' => 'somehost', 'port' => 5555}]
|
12
|
+
allow(mockWatcher).to receive(:backends).and_return(backends)
|
13
|
+
allow(mockWatcher).to receive(:haproxy).and_return({'server_options' => "check inter 2000 rise 3 fall 2"})
|
14
|
+
mockWatcher
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:mockwatcher_with_server_options) do
|
18
|
+
mockWatcher = double(Synapse::ServiceWatcher)
|
19
|
+
allow(mockWatcher).to receive(:name).and_return('example_service')
|
20
|
+
backends = [{ 'host' => 'somehost', 'port' => 5555, 'haproxy_server_options' => 'backup'}]
|
12
21
|
allow(mockWatcher).to receive(:backends).and_return(backends)
|
13
22
|
allow(mockWatcher).to receive(:haproxy).and_return({'server_options' => "check inter 2000 rise 3 fall 2"})
|
14
23
|
mockWatcher
|
@@ -29,4 +38,8 @@ describe Synapse::Haproxy do
|
|
29
38
|
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"]])
|
30
39
|
end
|
31
40
|
|
41
|
+
it 'respects haproxy_server_options' do
|
42
|
+
mockConfig = []
|
43
|
+
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
|
+
end
|
32
45
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
class Synapse::BaseWatcher
|
3
|
+
class Synapse::ServiceWatcher::BaseWatcher
|
4
4
|
attr_reader :should_exit, :default_servers
|
5
5
|
end
|
6
6
|
|
7
|
-
describe Synapse::BaseWatcher do
|
7
|
+
describe Synapse::ServiceWatcher::BaseWatcher do
|
8
8
|
let(:mocksynapse) { double() }
|
9
|
-
subject { Synapse::BaseWatcher.new(args, mocksynapse) }
|
9
|
+
subject { Synapse::ServiceWatcher::BaseWatcher.new(args, mocksynapse) }
|
10
10
|
let(:testargs) { { 'name' => 'foo', 'discovery' => { 'method' => 'base' }, 'haproxy' => {} }}
|
11
11
|
|
12
12
|
def remove_arg(name)
|
@@ -1,13 +1,14 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'synapse/service_watcher/docker'
|
2
3
|
|
3
|
-
class Synapse::DockerWatcher
|
4
|
+
class Synapse::ServiceWatcher::DockerWatcher
|
4
5
|
attr_reader :check_interval, :watcher, :synapse
|
5
6
|
attr_accessor :default_servers
|
6
7
|
end
|
7
8
|
|
8
|
-
describe Synapse::DockerWatcher do
|
9
|
+
describe Synapse::ServiceWatcher::DockerWatcher do
|
9
10
|
let(:mocksynapse) { double() }
|
10
|
-
subject { Synapse::DockerWatcher.new(testargs, mocksynapse) }
|
11
|
+
subject { Synapse::ServiceWatcher::DockerWatcher.new(testargs, mocksynapse) }
|
11
12
|
let(:testargs) { { 'name' => 'foo', 'discovery' => { 'method' => 'docker', 'servers' => [{'host' => 'server1.local', 'name' => 'mainserver'}], 'image_name' => 'mycool/image', 'container_port' => 6379 }, 'haproxy' => {} }}
|
12
13
|
before(:each) do
|
13
14
|
allow(subject.log).to receive(:warn)
|
@@ -84,9 +85,9 @@ describe Synapse::DockerWatcher do
|
|
84
85
|
it('has a sane uri') { subject.send(:containers); expect(Docker.url).to eql('http://server1.local:4243') }
|
85
86
|
|
86
87
|
context 'old style port mappings' do
|
88
|
+
let(:docker_data) { [{"Ports" => "0.0.0.0:49153->6379/tcp, 0.0.0.0:49154->6390/tcp", "Image" => "mycool/image:tagname"}] }
|
87
89
|
context 'works for one container' do
|
88
|
-
|
89
|
-
it do
|
90
|
+
it do
|
90
91
|
expect(Docker::Util).to receive(:parse_json).and_return(docker_data)
|
91
92
|
expect(subject.send(:containers)).to eql([{"name"=>"mainserver", "host"=>"server1.local", "port"=>"49153"}])
|
92
93
|
end
|
@@ -106,6 +107,12 @@ describe Synapse::DockerWatcher do
|
|
106
107
|
expect(Docker::Util).to receive(:parse_json).and_return(docker_data)
|
107
108
|
expect(subject.send(:containers)).to eql([{"name"=>"mainserver", "host"=>"server1.local", "port"=>"49153"}])
|
108
109
|
end
|
110
|
+
|
111
|
+
it 'filters out containers with unmapped ports' do
|
112
|
+
test_docker_data = docker_data + [{"Ports" => [{'PrivatePort' => 6379}], "Image" => "mycool/image:unmapped"}]
|
113
|
+
expect(Docker::Util).to receive(:parse_json).and_return(test_docker_data)
|
114
|
+
expect(subject.send(:containers)).to eql([{"name"=>"mainserver", "host"=>"server1.local", "port"=>"49153"}])
|
115
|
+
end
|
109
116
|
end
|
110
117
|
|
111
118
|
context 'filters out wrong images' do
|
@@ -117,4 +124,3 @@ describe Synapse::DockerWatcher do
|
|
117
124
|
end
|
118
125
|
end
|
119
126
|
end
|
120
|
-
|
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'synapse/service_watcher/ec2tag'
|
2
3
|
require 'logging'
|
3
4
|
|
4
|
-
class Synapse::
|
5
|
+
class Synapse::ServiceWatcher::Ec2tagWatcher
|
5
6
|
attr_reader :synapse
|
6
7
|
attr_accessor :default_servers, :ec2
|
7
8
|
end
|
@@ -28,9 +29,9 @@ class FakeAWSInstance
|
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
31
|
-
describe Synapse::
|
32
|
+
describe Synapse::ServiceWatcher::Ec2tagWatcher do
|
32
33
|
let(:mock_synapse) { double }
|
33
|
-
subject { Synapse::
|
34
|
+
subject { Synapse::ServiceWatcher::Ec2tagWatcher.new(basic_config, mock_synapse) }
|
34
35
|
|
35
36
|
let(:basic_config) do
|
36
37
|
{ 'name' => 'ec2tagtest',
|
@@ -86,24 +87,24 @@ describe Synapse::EC2Watcher do
|
|
86
87
|
end
|
87
88
|
|
88
89
|
context 'when missing arguments' do
|
89
|
-
it '
|
90
|
+
it 'does not break if aws_region is missing' do
|
90
91
|
expect {
|
91
|
-
Synapse::
|
92
|
-
}.
|
92
|
+
Synapse::ServiceWatcher::Ec2tagWatcher.new(remove_discovery_arg('aws_region'), mock_synapse)
|
93
|
+
}.not_to raise_error
|
93
94
|
end
|
94
|
-
it '
|
95
|
+
it 'does not break if aws_access_key_id is missing' do
|
95
96
|
expect {
|
96
|
-
Synapse::
|
97
|
-
}.
|
97
|
+
Synapse::ServiceWatcher::Ec2tagWatcher.new(remove_discovery_arg('aws_access_key_id'), mock_synapse)
|
98
|
+
}.not_to raise_error
|
98
99
|
end
|
99
|
-
it '
|
100
|
+
it 'does not break if aws_secret_access_key is missing' do
|
100
101
|
expect {
|
101
|
-
Synapse::
|
102
|
-
}.
|
102
|
+
Synapse::ServiceWatcher::Ec2tagWatcher.new(remove_discovery_arg('aws_secret_access_key'), mock_synapse)
|
103
|
+
}.not_to raise_error
|
103
104
|
end
|
104
105
|
it 'complains if server_port_override is missing' do
|
105
106
|
expect {
|
106
|
-
Synapse::
|
107
|
+
Synapse::ServiceWatcher::Ec2tagWatcher.new(remove_haproxy_arg('server_port_override'), mock_synapse)
|
107
108
|
}.to raise_error(ArgumentError, /Missing server_port_override/)
|
108
109
|
end
|
109
110
|
end
|
@@ -111,7 +112,7 @@ describe Synapse::EC2Watcher do
|
|
111
112
|
context 'invalid data' do
|
112
113
|
it 'complains if the haproxy server_port_override is not a number' do
|
113
114
|
expect {
|
114
|
-
Synapse::
|
115
|
+
Synapse::ServiceWatcher::Ec2tagWatcher.new(munge_haproxy_arg('server_port_override', '80deadbeef'), mock_synapse)
|
115
116
|
}.to raise_error(ArgumentError, /Invalid server_port_override/)
|
116
117
|
end
|
117
118
|
end
|
@@ -121,6 +122,27 @@ describe Synapse::EC2Watcher do
|
|
121
122
|
let(:instance1) { FakeAWSInstance.new }
|
122
123
|
let(:instance2) { FakeAWSInstance.new }
|
123
124
|
|
125
|
+
context 'watch' do
|
126
|
+
|
127
|
+
it 'discovers instances, configures backends, then sleeps' do
|
128
|
+
fake_backends = [1,2,3]
|
129
|
+
expect(subject).to receive(:discover_instances).and_return(fake_backends)
|
130
|
+
expect(subject).to receive(:set_backends).with(fake_backends) { subject.stop }
|
131
|
+
expect(subject).to receive(:sleep_until_next_check)
|
132
|
+
subject.send(:watch)
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'sleeps until next check if discover_instances fails' do
|
136
|
+
expect(subject).to receive(:discover_instances) do
|
137
|
+
subject.stop
|
138
|
+
raise "discover failed"
|
139
|
+
end
|
140
|
+
expect(subject).to receive(:sleep_until_next_check)
|
141
|
+
subject.send(:watch)
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
124
146
|
context 'using the AWS API' do
|
125
147
|
let(:ec2_client) { double('AWS::EC2') }
|
126
148
|
let(:instance_collection) { double('AWS::EC2::InstanceCollection') }
|