synapse 0.8.0 → 0.9.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.
- data/.travis.yml +5 -0
- data/Gemfile.lock +5 -3
- data/README.md +2 -0
- data/Rakefile +7 -0
- data/bin/synapse +7 -7
- data/lib/synapse/haproxy.rb +6 -4
- data/lib/synapse/service_watcher/base.rb +30 -1
- data/lib/synapse/service_watcher/dns.rb +0 -3
- data/lib/synapse/service_watcher/docker.rb +20 -8
- data/lib/synapse/service_watcher/zookeeper.rb +17 -25
- data/lib/synapse/version.rb +1 -1
- data/spec/lib/synapse/haproxy_spec.rb +1 -2
- data/spec/lib/synapse/service_watcher_base_spec.rb +46 -0
- data/spec/lib/synapse/service_watcher_docker_spec.rb +152 -0
- data/spec/spec_helper.rb +1 -1
- data/synapse.gemspec +1 -0
- metadata +29 -2
data/.travis.yml
ADDED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
synapse (0.
|
4
|
+
synapse (0.9.1)
|
5
5
|
docker-api (~> 1.7.2)
|
6
6
|
zk (~> 1.9.2)
|
7
7
|
|
@@ -27,6 +27,7 @@ GEM
|
|
27
27
|
slop (~> 3.4)
|
28
28
|
pry-nav (0.2.3)
|
29
29
|
pry (~> 0.9.10)
|
30
|
+
rake (10.1.1)
|
30
31
|
rspec (2.14.1)
|
31
32
|
rspec-core (~> 2.14.0)
|
32
33
|
rspec-expectations (~> 2.14.0)
|
@@ -36,10 +37,10 @@ GEM
|
|
36
37
|
diff-lcs (>= 1.1.3, < 2.0)
|
37
38
|
rspec-mocks (2.14.3)
|
38
39
|
slop (3.4.6)
|
39
|
-
zk (1.9.
|
40
|
+
zk (1.9.3)
|
40
41
|
logging (~> 1.7.2)
|
41
42
|
zookeeper (~> 1.4.0)
|
42
|
-
zookeeper (1.4.
|
43
|
+
zookeeper (1.4.8)
|
43
44
|
|
44
45
|
PLATFORMS
|
45
46
|
ruby
|
@@ -47,5 +48,6 @@ PLATFORMS
|
|
47
48
|
DEPENDENCIES
|
48
49
|
pry
|
49
50
|
pry-nav
|
51
|
+
rake
|
50
52
|
rspec
|
51
53
|
synapse!
|
data/README.md
CHANGED
data/Rakefile
CHANGED
data/bin/synapse
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'yaml'
|
4
4
|
require 'optparse'
|
5
5
|
|
6
6
|
require 'synapse'
|
@@ -32,15 +32,15 @@ optparse.parse!
|
|
32
32
|
def parseconfig(filename)
|
33
33
|
# parse synapse config file
|
34
34
|
begin
|
35
|
-
c =
|
35
|
+
c = YAML::parse(File.read(filename))
|
36
36
|
rescue Errno::ENOENT => e
|
37
37
|
raise ArgumentError, "config file does not exist:\n#{e.inspect}"
|
38
38
|
rescue Errno::EACCES => e
|
39
39
|
raise ArgumentError, "could not open config file:\n#{e.inspect}"
|
40
|
-
rescue
|
41
|
-
raise "config file #{filename} is not
|
40
|
+
rescue YAML::ParseError => e
|
41
|
+
raise "config file #{filename} is not yaml:\n#{e.inspect}"
|
42
42
|
end
|
43
|
-
return c
|
43
|
+
return c.to_ruby
|
44
44
|
end
|
45
45
|
|
46
46
|
config = parseconfig(options[:config])
|
@@ -51,8 +51,8 @@ if config.has_key?('service_conf_dir')
|
|
51
51
|
if ! Dir.exists?(cdir)
|
52
52
|
raise "service conf dir does not exist:#{cdir}"
|
53
53
|
end
|
54
|
-
cfiles = Dir.glob(File.join(cdir, '*.json'))
|
55
|
-
cfiles.each { |x| config['services'][File.basename(x[/(.*)\.json$/, 1])] = parseconfig(x) }
|
54
|
+
cfiles = Dir.glob(File.join(cdir, '*.{json,yaml}'))
|
55
|
+
cfiles.each { |x| config['services'][File.basename(x[/(.*)\.(json|yaml)$/, 1])] = parseconfig(x) }
|
56
56
|
end
|
57
57
|
|
58
58
|
# run synapse
|
data/lib/synapse/haproxy.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
require 'synapse/log'
|
2
|
-
|
3
2
|
require 'socket'
|
4
|
-
require 'digest'
|
5
3
|
|
6
4
|
module Synapse
|
7
5
|
class Haproxy
|
@@ -750,8 +748,12 @@ module Synapse
|
|
750
748
|
|
751
749
|
# used to build unique, consistent haproxy names for backends
|
752
750
|
def construct_name(backend)
|
753
|
-
|
754
|
-
|
751
|
+
name = "#{backend['host']}:#{backend['port']}"
|
752
|
+
if backend['name'] && !backend['name'].empty?
|
753
|
+
name = "#{name}_#{backend['name']}"
|
754
|
+
end
|
755
|
+
|
756
|
+
return name
|
755
757
|
end
|
756
758
|
end
|
757
759
|
end
|
@@ -1,6 +1,12 @@
|
|
1
|
+
require 'synapse/log'
|
2
|
+
|
1
3
|
module Synapse
|
2
4
|
class BaseWatcher
|
3
|
-
|
5
|
+
include Logging
|
6
|
+
|
7
|
+
LEADER_WARN_INTERVAL = 30
|
8
|
+
|
9
|
+
attr_reader :name, :haproxy
|
4
10
|
|
5
11
|
def initialize(opts={}, synapse)
|
6
12
|
super()
|
@@ -15,6 +21,9 @@ module Synapse
|
|
15
21
|
@name = opts['name']
|
16
22
|
@discovery = opts['discovery']
|
17
23
|
|
24
|
+
@leader_election = opts['leader_election'] || false
|
25
|
+
@leader_last_warn = Time.now - LEADER_WARN_INTERVAL
|
26
|
+
|
18
27
|
# the haproxy config
|
19
28
|
@haproxy = opts['haproxy']
|
20
29
|
@haproxy['server_options'] ||= ""
|
@@ -55,6 +64,26 @@ module Synapse
|
|
55
64
|
true
|
56
65
|
end
|
57
66
|
|
67
|
+
def backends
|
68
|
+
if @leader_election
|
69
|
+
if @backends.all?{|b| b.key?('id') && b['id']}
|
70
|
+
smallest = @backends.sort_by{ |b| b['id']}.first
|
71
|
+
log.debug "synapse: leader election chose one of #{@backends.count} backends " \
|
72
|
+
"(#{smallest['host']}:#{smallest['port']} with id #{smallest['id']})"
|
73
|
+
|
74
|
+
return [smallest]
|
75
|
+
elsif (Time.now - @leader_last_warn) > LEADER_WARN_INTERVAL
|
76
|
+
log.warn "synapse: service #{@name}: leader election failed; not all backends include an id"
|
77
|
+
@leader_last_warn = Time.now
|
78
|
+
end
|
79
|
+
|
80
|
+
# if leader election fails, return no backends
|
81
|
+
return []
|
82
|
+
end
|
83
|
+
|
84
|
+
return @backends
|
85
|
+
end
|
86
|
+
|
58
87
|
private
|
59
88
|
def validate_discovery_opts
|
60
89
|
raise ArgumentError, "invalid discovery method '#{@discovery['method']}' for base watcher" \
|
@@ -1,12 +1,10 @@
|
|
1
1
|
require "synapse/service_watcher/base"
|
2
|
-
require "synapse/log"
|
3
2
|
|
4
3
|
require 'thread'
|
5
4
|
require 'resolv'
|
6
5
|
|
7
6
|
module Synapse
|
8
7
|
class DnsWatcher < BaseWatcher
|
9
|
-
include Logging
|
10
8
|
def start
|
11
9
|
@check_interval = @discovery['check_interval'] || 30.0
|
12
10
|
@nameserver = @discovery['nameserver']
|
@@ -80,7 +78,6 @@ module Synapse
|
|
80
78
|
new_backends = servers.flat_map do |(server, addresses)|
|
81
79
|
addresses.map do |address|
|
82
80
|
{
|
83
|
-
'name' => server['name'],
|
84
81
|
'host' => address,
|
85
82
|
'port' => server['port']
|
86
83
|
}
|
@@ -34,7 +34,7 @@ module Synapse
|
|
34
34
|
end
|
35
35
|
|
36
36
|
sleep_until_next_check(start)
|
37
|
-
rescue => e
|
37
|
+
rescue Exception => e
|
38
38
|
log.warn "synapse: error in watcher thread: #{e.inspect}"
|
39
39
|
log.warn e.backtrace
|
40
40
|
end
|
@@ -50,6 +50,24 @@ module Synapse
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
+
def rewrite_container_ports(ports)
|
54
|
+
pairs = []
|
55
|
+
if ports.is_a?(String)
|
56
|
+
# "Ports" comes through (as of 0.6.5) as a string like "0.0.0.0:49153->6379/tcp, 0.0.0.0:49153->6379/tcp"
|
57
|
+
# Convert string to a map of container port to host port: {"7000"->"49158", "6379": "49159"}
|
58
|
+
pairs = ports.split(", ").collect do |v|
|
59
|
+
pair = v.split('->')
|
60
|
+
[ pair[1].rpartition("/").first, pair[0].rpartition(":").last ]
|
61
|
+
end
|
62
|
+
elsif ports.is_a?(Array)
|
63
|
+
# New style API, ports is an array of hashes, with numeric values (or nil if no ports forwarded)
|
64
|
+
pairs = ports.collect do |v|
|
65
|
+
[v['PrivatePort'].to_s, v['PublicPort'].to_s]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
Hash[pairs]
|
69
|
+
end
|
70
|
+
|
53
71
|
def containers
|
54
72
|
backends = @discovery['servers'].map do |server|
|
55
73
|
Docker.url = "http://#{server['host']}:#{server['port'] || 4243}"
|
@@ -59,14 +77,8 @@ module Synapse
|
|
59
77
|
log.warn "synapse: error polling docker host #{Docker.url}: #{e.inspect}"
|
60
78
|
next []
|
61
79
|
end
|
62
|
-
# "Ports" comes through (as of 0.6.5) as a string like "0.0.0.0:49153->6379/tcp, 0.0.0.0:49153->6379/tcp"
|
63
|
-
# Convert string to a map of container port to host port: {"7000"->"49158", "6379": "49159"}
|
64
80
|
cnts.each do |cnt|
|
65
|
-
|
66
|
-
pair = v.split('->')
|
67
|
-
[ pair[1].rpartition("/").first, pair[0].rpartition(":").last ]
|
68
|
-
end
|
69
|
-
cnt["Ports"] = Hash[pairs]
|
81
|
+
cnt['Ports'] = rewrite_container_ports cnt['Ports']
|
70
82
|
end
|
71
83
|
# Discover containers that match the image/port we're interested in
|
72
84
|
cnts = cnts.find_all do |cnt|
|
@@ -1,11 +1,11 @@
|
|
1
1
|
require "synapse/service_watcher/base"
|
2
|
-
require "synapse/log"
|
3
2
|
|
4
3
|
require 'zk'
|
5
4
|
|
6
5
|
module Synapse
|
7
6
|
class ZookeeperWatcher < BaseWatcher
|
8
|
-
|
7
|
+
NUMBERS_RE = /^\d+$/
|
8
|
+
|
9
9
|
def start
|
10
10
|
zk_hosts = @discovery['hosts'].shuffle.join(',')
|
11
11
|
|
@@ -55,18 +55,22 @@ module Synapse
|
|
55
55
|
|
56
56
|
new_backends = []
|
57
57
|
begin
|
58
|
-
@zk.children(@discovery['path'], :watch => true).
|
59
|
-
node = @zk.get("#{@discovery['path']}/#{
|
58
|
+
@zk.children(@discovery['path'], :watch => true).each do |id|
|
59
|
+
node = @zk.get("#{@discovery['path']}/#{id}")
|
60
60
|
|
61
61
|
begin
|
62
|
-
host, port = deserialize_service_instance(node.first)
|
63
|
-
rescue
|
64
|
-
log.error "synapse: invalid data in ZK node #{
|
62
|
+
host, port, name = deserialize_service_instance(node.first)
|
63
|
+
rescue StandardError => e
|
64
|
+
log.error "synapse: invalid data in ZK node #{id} at #{@discovery['path']}: #{e}"
|
65
65
|
else
|
66
66
|
server_port = @server_port_override ? @server_port_override : port
|
67
67
|
|
68
|
+
# find the numberic id in the node name; used for leader elections if enabled
|
69
|
+
numeric_id = id.split('_').last
|
70
|
+
numeric_id = NUMBERS_RE =~ numeric_id ? numeric_id.to_i : nil
|
71
|
+
|
68
72
|
log.debug "synapse: discovered backend #{name} at #{host}:#{server_port} for service #{@name}"
|
69
|
-
new_backends << { 'name' => name, 'host' => host, 'port' => server_port}
|
73
|
+
new_backends << { 'name' => name, 'host' => host, 'port' => server_port, 'id' => numeric_id}
|
70
74
|
end
|
71
75
|
end
|
72
76
|
rescue ZK::Exceptions::NoNode
|
@@ -108,28 +112,16 @@ module Synapse
|
|
108
112
|
end
|
109
113
|
end
|
110
114
|
|
111
|
-
# tries to extract host/port from a json hash
|
112
|
-
def parse_json(data)
|
113
|
-
begin
|
114
|
-
json = JSON.parse data
|
115
|
-
rescue Object => o
|
116
|
-
return false
|
117
|
-
end
|
118
|
-
raise 'instance json data does not have host key' unless json.has_key?('host')
|
119
|
-
raise 'instance json data does not have port key' unless json.has_key?('port')
|
120
|
-
return json['host'], json['port']
|
121
|
-
end
|
122
|
-
|
123
115
|
# decode the data at a zookeeper endpoint
|
124
116
|
def deserialize_service_instance(data)
|
125
117
|
log.debug "synapse: deserializing process data"
|
118
|
+
decoded = JSON.parse(data)
|
126
119
|
|
127
|
-
|
128
|
-
|
129
|
-
|
120
|
+
host = decoded['host'] || (raise ValueError, 'instance json data does not have host key')
|
121
|
+
port = decoded['port'] || (raise ValueError, 'instance json data does not have port key')
|
122
|
+
name = decoded['name'] || nil
|
130
123
|
|
131
|
-
|
132
|
-
raise "could not decode this data:\n#{data}"
|
124
|
+
return host, port, name
|
133
125
|
end
|
134
126
|
end
|
135
127
|
end
|
data/lib/synapse/version.rb
CHANGED
@@ -6,8 +6,7 @@ describe Synapse::Haproxy do
|
|
6
6
|
subject { Synapse::Haproxy.new(config['haproxy']) }
|
7
7
|
|
8
8
|
it 'updating the config' do
|
9
|
-
mockWatcher =
|
10
|
-
binding.pry
|
9
|
+
mockWatcher = double(Synapse::ServiceWatcher)
|
11
10
|
subject.should_receive(:generate_config)
|
12
11
|
subject.update_config([mockWatcher])
|
13
12
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Synapse::BaseWatcher
|
4
|
+
attr_reader :should_exit, :default_servers
|
5
|
+
end
|
6
|
+
|
7
|
+
describe Synapse::BaseWatcher do
|
8
|
+
let(:mocksynapse) { double() }
|
9
|
+
subject { Synapse::BaseWatcher.new(args, mocksynapse) }
|
10
|
+
let(:testargs) { { 'name' => 'foo', 'discovery' => { 'method' => 'base' }, 'haproxy' => {} }}
|
11
|
+
|
12
|
+
def remove_arg(name)
|
13
|
+
args = testargs.clone
|
14
|
+
args.delete name
|
15
|
+
args
|
16
|
+
end
|
17
|
+
|
18
|
+
context "can construct normally" do
|
19
|
+
let(:args) { testargs }
|
20
|
+
it('can at least construct') { expect { subject }.not_to raise_error }
|
21
|
+
end
|
22
|
+
|
23
|
+
['name', 'discovery', 'haproxy'].each do |to_remove|
|
24
|
+
context "without #{to_remove} argument" do
|
25
|
+
let(:args) { remove_arg to_remove }
|
26
|
+
it('gots bang') { expect { subject }.to raise_error(ArgumentError, "missing required option #{to_remove}") }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context "normal tests" do
|
31
|
+
let(:args) { testargs }
|
32
|
+
it('is running') { expect(subject.should_exit).to equal(false) }
|
33
|
+
it('can ping') { expect(subject.ping?).to equal(true) }
|
34
|
+
it('can be stopped') do
|
35
|
+
subject.stop
|
36
|
+
expect(subject.should_exit).to equal(true)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "with default_servers" do
|
41
|
+
default_servers = ['server1', 'server2']
|
42
|
+
let(:args) { testargs.merge({'default_servers' => default_servers}) }
|
43
|
+
it('sets default backends to default_servers') { expect(subject.backends).to equal(default_servers) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Synapse::DockerWatcher
|
4
|
+
attr_reader :check_interval, :watcher, :synapse
|
5
|
+
attr_accessor :default_servers
|
6
|
+
end
|
7
|
+
|
8
|
+
describe Synapse::DockerWatcher do
|
9
|
+
let(:mocksynapse) { double() }
|
10
|
+
subject { Synapse::DockerWatcher.new(testargs, mocksynapse) }
|
11
|
+
let(:testargs) { { 'name' => 'foo', 'discovery' => { 'method' => 'docker', 'servers' => [{'host' => 'server1.local', 'name' => 'mainserver'}], 'image_name' => 'mycool/image', 'container_port' => 6379 }, 'haproxy' => {} }}
|
12
|
+
before(:each) do
|
13
|
+
allow(subject.log).to receive(:warn)
|
14
|
+
allow(subject.log).to receive(:info)
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_arg(name, value)
|
18
|
+
args = testargs.clone
|
19
|
+
args['discovery'][name] = value
|
20
|
+
args
|
21
|
+
end
|
22
|
+
|
23
|
+
context "can construct normally" do
|
24
|
+
it('can at least construct') { expect { subject }.not_to raise_error }
|
25
|
+
end
|
26
|
+
|
27
|
+
context "normal tests" do
|
28
|
+
it('starts a watcher thread') do
|
29
|
+
watcher_mock = double()
|
30
|
+
expect(Thread).to receive(:new).and_return(watcher_mock)
|
31
|
+
subject.start
|
32
|
+
expect(subject.watcher).to equal(watcher_mock)
|
33
|
+
end
|
34
|
+
it('sets default check interval') do
|
35
|
+
expect(Thread).to receive(:new).and_return(double)
|
36
|
+
subject.start
|
37
|
+
expect(subject.check_interval).to eq(15.0)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "watch tests" do
|
42
|
+
before(:each) do
|
43
|
+
expect(subject).to receive(:sleep_until_next_check) do |arg|
|
44
|
+
subject.instance_variable_set('@should_exit', true)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
it('has a happy first run path, configuring backends') do
|
48
|
+
expect(subject).to receive(:containers).and_return(['container1'])
|
49
|
+
expect(subject).to receive(:configure_backends).with(['container1'])
|
50
|
+
subject.send(:watch)
|
51
|
+
end
|
52
|
+
it('does not call configure_backends if there is no change') do
|
53
|
+
expect(subject).to receive(:containers).and_return([])
|
54
|
+
expect(subject).to_not receive(:configure_backends)
|
55
|
+
subject.send(:watch)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
context "watch eats exceptions" do
|
59
|
+
it "blows up when finding containers" do
|
60
|
+
expect(subject).to receive(:containers) do |arg|
|
61
|
+
subject.instance_variable_set('@should_exit', true)
|
62
|
+
raise('throw exception inside watch')
|
63
|
+
end
|
64
|
+
expect { subject.send(:watch) }.not_to raise_error
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context "configure_backends tests" do
|
69
|
+
before(:each) do
|
70
|
+
expect(subject.synapse).to receive(:'reconfigure!').at_least(:once)
|
71
|
+
end
|
72
|
+
it 'runs' do
|
73
|
+
expect { subject.send(:configure_backends, []) }.not_to raise_error
|
74
|
+
end
|
75
|
+
it 'sets backends right' do
|
76
|
+
subject.send(:configure_backends, ['foo'])
|
77
|
+
expect(subject.backends).to eq(['foo'])
|
78
|
+
end
|
79
|
+
it 'resets to default backends if no container found' do
|
80
|
+
subject.default_servers = ['fallback1']
|
81
|
+
subject.send(:configure_backends, ['foo'])
|
82
|
+
expect(subject.backends).to eq(['foo'])
|
83
|
+
subject.send(:configure_backends, [])
|
84
|
+
expect(subject.backends).to eq(['fallback1'])
|
85
|
+
end
|
86
|
+
it 'does not reset to default backends if there are no default backends' do
|
87
|
+
subject.default_servers = []
|
88
|
+
subject.send(:configure_backends, ['foo'])
|
89
|
+
expect(subject.backends).to eq(['foo'])
|
90
|
+
subject.send(:configure_backends, [])
|
91
|
+
expect(subject.backends).to eq(['foo'])
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "rewrite_container_ports tests" do
|
96
|
+
it 'doesnt break if Ports => nil' do
|
97
|
+
subject.send(:rewrite_container_ports, nil)
|
98
|
+
end
|
99
|
+
it 'works for old style port mappings' do
|
100
|
+
expect(subject.send(:rewrite_container_ports, "0.0.0.0:49153->6379/tcp, 0.0.0.0:49154->6390/tcp")).to \
|
101
|
+
eql({'6379' => '49153', '6390' => '49154'})
|
102
|
+
end
|
103
|
+
it 'works for new style port mappings' do
|
104
|
+
expect(subject.send(:rewrite_container_ports, [{'PrivatePort' => 6379, 'PublicPort' => 49153}, {'PublicPort' => 49154, 'PrivatePort' => 6390}])).to \
|
105
|
+
eql({'6379' => '49153', '6390' => '49154'})
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "container discovery tests" do
|
110
|
+
before(:each) do
|
111
|
+
getter = double()
|
112
|
+
expect(getter).to receive(:get)
|
113
|
+
expect(Docker).to receive(:connection).and_return(getter)
|
114
|
+
end
|
115
|
+
|
116
|
+
it('has a sane uri') { subject.send(:containers); expect(Docker.url).to eql('http://server1.local:4243') }
|
117
|
+
|
118
|
+
context 'old style port mappings' do
|
119
|
+
context 'works for one container' do
|
120
|
+
let(:docker_data) { [{"Ports" => "0.0.0.0:49153->6379/tcp, 0.0.0.0:49154->6390/tcp", "Image" => "mycool/image:tagname"}] }
|
121
|
+
it do
|
122
|
+
expect(Docker::Util).to receive(:parse_json).and_return(docker_data)
|
123
|
+
expect(subject.send(:containers)).to eql([{"name"=>"mainserver", "host"=>"server1.local", "port"=>"49153"}])
|
124
|
+
end
|
125
|
+
end
|
126
|
+
context 'works for multiple containers' do
|
127
|
+
let(:docker_data) { [{"Ports" => "0.0.0.0:49153->6379/tcp, 0.0.0.0:49154->6390/tcp", "Image" => "mycool/image:tagname"}, {"Ports" => "0.0.0.0:49155->6379/tcp", "Image" => "mycool/image:tagname"}] }
|
128
|
+
it do
|
129
|
+
expect(Docker::Util).to receive(:parse_json).and_return(docker_data)
|
130
|
+
expect(subject.send(:containers)).to eql([{"name"=>"mainserver", "host"=>"server1.local", "port"=>"49153"},{"name"=>"mainserver", "host"=>"server1.local", "port"=>"49155"}])
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context 'new style port mappings' do
|
136
|
+
let(:docker_data) { [{"Ports" => [{'PrivatePort' => 6379, 'PublicPort' => 49153}, {'PublicPort' => 49154, 'PrivatePort' => 6390}], "Image" => "mycool/image:tagname"}] }
|
137
|
+
it do
|
138
|
+
expect(Docker::Util).to receive(:parse_json).and_return(docker_data)
|
139
|
+
expect(subject.send(:containers)).to eql([{"name"=>"mainserver", "host"=>"server1.local", "port"=>"49153"}])
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context 'filters out wrong images' do
|
144
|
+
let(:docker_data) { [{"Ports" => "0.0.0.0:49153->6379/tcp, 0.0.0.0:49154->6390/tcp", "Image" => "mycool/image:tagname"}, {"Ports" => "0.0.0.0:49155->6379/tcp", "Image" => "wrong/image:tagname"}] }
|
145
|
+
it do
|
146
|
+
expect(Docker::Util).to receive(:parse_json).and_return(docker_data)
|
147
|
+
expect(subject.send(:containers)).to eql([{"name"=>"mainserver", "host"=>"server1.local", "port"=>"49153"}])
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
data/spec/spec_helper.rb
CHANGED
data/synapse.gemspec
CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |gem|
|
|
19
19
|
gem.add_runtime_dependency "zk", "~> 1.9.2"
|
20
20
|
gem.add_runtime_dependency "docker-api", "~> 1.7.2"
|
21
21
|
|
22
|
+
gem.add_development_dependency "rake"
|
22
23
|
gem.add_development_dependency "rspec"
|
23
24
|
gem.add_development_dependency "pry"
|
24
25
|
gem.add_development_dependency "pry-nav"
|
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.
|
4
|
+
version: 0.9.1
|
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: 2014-
|
12
|
+
date: 2014-02-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: zk
|
@@ -43,6 +43,22 @@ dependencies:
|
|
43
43
|
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: 1.7.2
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
46
62
|
- !ruby/object:Gem::Dependency
|
47
63
|
name: rspec
|
48
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -102,6 +118,7 @@ files:
|
|
102
118
|
- .gitignore
|
103
119
|
- .mailmap
|
104
120
|
- .rspec
|
121
|
+
- .travis.yml
|
105
122
|
- Gemfile
|
106
123
|
- Gemfile.lock
|
107
124
|
- LICENSE.txt
|
@@ -126,6 +143,8 @@ files:
|
|
126
143
|
- lib/synapse/service_watcher/zookeeper.rb
|
127
144
|
- lib/synapse/version.rb
|
128
145
|
- spec/lib/synapse/haproxy_spec.rb
|
146
|
+
- spec/lib/synapse/service_watcher_base_spec.rb
|
147
|
+
- spec/lib/synapse/service_watcher_docker_spec.rb
|
129
148
|
- spec/spec_helper.rb
|
130
149
|
- spec/support/config.rb
|
131
150
|
- spec/support/minimum.conf.yaml
|
@@ -142,12 +161,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
142
161
|
- - ! '>='
|
143
162
|
- !ruby/object:Gem::Version
|
144
163
|
version: '0'
|
164
|
+
segments:
|
165
|
+
- 0
|
166
|
+
hash: 575568743231626432
|
145
167
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
168
|
none: false
|
147
169
|
requirements:
|
148
170
|
- - ! '>='
|
149
171
|
- !ruby/object:Gem::Version
|
150
172
|
version: '0'
|
173
|
+
segments:
|
174
|
+
- 0
|
175
|
+
hash: 575568743231626432
|
151
176
|
requirements: []
|
152
177
|
rubyforge_project:
|
153
178
|
rubygems_version: 1.8.23
|
@@ -156,6 +181,8 @@ specification_version: 3
|
|
156
181
|
summary: ': Write a gem summary'
|
157
182
|
test_files:
|
158
183
|
- spec/lib/synapse/haproxy_spec.rb
|
184
|
+
- spec/lib/synapse/service_watcher_base_spec.rb
|
185
|
+
- spec/lib/synapse/service_watcher_docker_spec.rb
|
159
186
|
- spec/spec_helper.rb
|
160
187
|
- spec/support/config.rb
|
161
188
|
- spec/support/minimum.conf.yaml
|