synapse 0.8.0 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|