synapse-aurora 0.11.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +23 -0
- data/.mailmap +3 -0
- data/.nix/Gemfile.nix +141 -0
- data/.nix/rubylibs.nix +42 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/Makefile +6 -0
- data/README.md +339 -0
- data/Rakefile +8 -0
- data/bin/synapse +62 -0
- data/config/hostheader_test.json +71 -0
- data/config/svcdir_test.json +46 -0
- data/config/synapse.conf.json +90 -0
- data/config/synapse_services/service1.json +24 -0
- data/config/synapse_services/service2.json +24 -0
- data/default.nix +66 -0
- data/lib/synapse.rb +85 -0
- data/lib/synapse/base.rb +5 -0
- data/lib/synapse/haproxy.rb +797 -0
- data/lib/synapse/log.rb +24 -0
- data/lib/synapse/service_watcher.rb +36 -0
- data/lib/synapse/service_watcher/base.rb +109 -0
- data/lib/synapse/service_watcher/dns.rb +109 -0
- data/lib/synapse/service_watcher/docker.rb +120 -0
- data/lib/synapse/service_watcher/ec2tag.rb +133 -0
- data/lib/synapse/service_watcher/zookeeper.rb +153 -0
- data/lib/synapse/service_watcher/zookeeper_aurora.rb +76 -0
- data/lib/synapse/service_watcher/zookeeper_dns.rb +232 -0
- data/lib/synapse/version.rb +3 -0
- data/spec/lib/synapse/haproxy_spec.rb +32 -0
- data/spec/lib/synapse/service_watcher_base_spec.rb +55 -0
- data/spec/lib/synapse/service_watcher_docker_spec.rb +152 -0
- data/spec/lib/synapse/service_watcher_ec2tags_spec.rb +220 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/support/configuration.rb +9 -0
- data/spec/support/minimum.conf.yaml +27 -0
- data/synapse.gemspec +33 -0
- metadata +227 -0
data/Rakefile
ADDED
data/bin/synapse
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
require 'synapse'
|
7
|
+
|
8
|
+
options={}
|
9
|
+
|
10
|
+
# set command line options
|
11
|
+
optparse = OptionParser.new do |opts|
|
12
|
+
opts.banner =<<-EOB
|
13
|
+
Welcome to synapse
|
14
|
+
|
15
|
+
Usage: synapse --config /path/to/synapse/config
|
16
|
+
EOB
|
17
|
+
|
18
|
+
options[:config] = ENV['SYNAPSE_CONFIG']
|
19
|
+
opts.on('-c config','--config config', String, 'path to synapse config') do |key,value|
|
20
|
+
options[:config] = key
|
21
|
+
end
|
22
|
+
|
23
|
+
opts.on( '-h', '--help', 'Display this screen' ) do
|
24
|
+
puts opts
|
25
|
+
exit
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# parse command line arguments
|
30
|
+
optparse.parse!
|
31
|
+
|
32
|
+
def parseconfig(filename)
|
33
|
+
# parse synapse config file
|
34
|
+
begin
|
35
|
+
c = YAML::parse(File.read(filename))
|
36
|
+
rescue Errno::ENOENT => e
|
37
|
+
raise ArgumentError, "config file does not exist:\n#{e.inspect}"
|
38
|
+
rescue Errno::EACCES => e
|
39
|
+
raise ArgumentError, "could not open config file:\n#{e.inspect}"
|
40
|
+
rescue YAML::SyntaxError => e
|
41
|
+
raise "config file #{filename} is not yaml:\n#{e.inspect}"
|
42
|
+
end
|
43
|
+
return c.to_ruby
|
44
|
+
end
|
45
|
+
|
46
|
+
config = parseconfig(options[:config])
|
47
|
+
config['services'] ||= {}
|
48
|
+
|
49
|
+
if config.has_key?('service_conf_dir')
|
50
|
+
cdir = File.expand_path(config['service_conf_dir'])
|
51
|
+
if ! Dir.exists?(cdir)
|
52
|
+
raise "service conf dir does not exist:#{cdir}"
|
53
|
+
end
|
54
|
+
cfiles = Dir.glob(File.join(cdir, '*.{json,yaml}'))
|
55
|
+
cfiles.each { |x| config['services'][File.basename(x[/(.*)\.(json|yaml)$/, 1])] = parseconfig(x) }
|
56
|
+
end
|
57
|
+
|
58
|
+
# run synapse
|
59
|
+
s = Synapse::Synapse.new(config)
|
60
|
+
s.run
|
61
|
+
|
62
|
+
puts "synapse has exited"
|
@@ -0,0 +1,71 @@
|
|
1
|
+
{
|
2
|
+
"services": {
|
3
|
+
"service1": {
|
4
|
+
"default_servers": [
|
5
|
+
{ "name": "default1", "host": "localhost", "port": 8080 }
|
6
|
+
],
|
7
|
+
"discovery": {
|
8
|
+
"method": "dns",
|
9
|
+
"nameserver": "127.0.0.1",
|
10
|
+
"servers": [
|
11
|
+
"0.www.example.com",
|
12
|
+
"1.www.example.com"
|
13
|
+
]
|
14
|
+
},
|
15
|
+
"haproxy": {
|
16
|
+
"server_options": "check inter 2s rise 3 fall 2",
|
17
|
+
"listen": [
|
18
|
+
"mode http",
|
19
|
+
"option httplog"
|
20
|
+
],
|
21
|
+
"backend": [
|
22
|
+
"mode http",
|
23
|
+
"option httpchk GET /health HTTP/1.0"
|
24
|
+
]
|
25
|
+
}
|
26
|
+
}
|
27
|
+
},
|
28
|
+
"haproxy": {
|
29
|
+
"reload_command": "sudo service haproxy reload",
|
30
|
+
"config_file_path": "/etc/haproxy/haproxy.cfg",
|
31
|
+
"socket_file_path": "/var/haproxy/stats.sock",
|
32
|
+
"do_writes": true,
|
33
|
+
"do_reloads": true,
|
34
|
+
"do_socket": true,
|
35
|
+
"global": [
|
36
|
+
"daemon",
|
37
|
+
"user haproxy",
|
38
|
+
"group haproxy",
|
39
|
+
"maxconn 4096",
|
40
|
+
"log 127.0.0.1 local0",
|
41
|
+
"log 127.0.0.1 local1 notice",
|
42
|
+
"stats socket /var/haproxy/stats.sock mode 666 level admin"
|
43
|
+
],
|
44
|
+
"defaults": [
|
45
|
+
"log global",
|
46
|
+
"option dontlognull",
|
47
|
+
"maxconn 2000",
|
48
|
+
"retries 3",
|
49
|
+
"timeout connect 5s",
|
50
|
+
"timeout client 1m",
|
51
|
+
"timeout server 1m",
|
52
|
+
"option redispatch",
|
53
|
+
"balance roundrobin"
|
54
|
+
],
|
55
|
+
"extra_sections": {
|
56
|
+
"listen stats :3212": [
|
57
|
+
"mode http",
|
58
|
+
"stats enable",
|
59
|
+
"stats uri /",
|
60
|
+
"stats refresh 5s"
|
61
|
+
],
|
62
|
+
"frontend http-generic-in": [
|
63
|
+
"bind 127.0.0.1:80",
|
64
|
+
"acl is_service1 hdr_dom(host) -i service1.lb",
|
65
|
+
"acl is_cache hdr_dom(host) -i cache.lb",
|
66
|
+
"use_backend service1 if is_service1",
|
67
|
+
"use_backend cache if is_cache"
|
68
|
+
]
|
69
|
+
}
|
70
|
+
}
|
71
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
{
|
2
|
+
"service_conf_dir": "config/synapse_services",
|
3
|
+
"haproxy": {
|
4
|
+
"reload_command": "sudo service haproxy reload",
|
5
|
+
"config_file_path": "/etc/haproxy/haproxy.cfg",
|
6
|
+
"socket_file_path": "/var/haproxy/stats.sock",
|
7
|
+
"do_writes": true,
|
8
|
+
"do_reloads": true,
|
9
|
+
"do_socket": true,
|
10
|
+
"global": [
|
11
|
+
"daemon",
|
12
|
+
"user haproxy",
|
13
|
+
"group haproxy",
|
14
|
+
"maxconn 4096",
|
15
|
+
"log 127.0.0.1 local0",
|
16
|
+
"log 127.0.0.1 local1 notice",
|
17
|
+
"stats socket /var/haproxy/stats.sock mode 666 level admin"
|
18
|
+
],
|
19
|
+
"defaults": [
|
20
|
+
"log global",
|
21
|
+
"option dontlognull",
|
22
|
+
"maxconn 2000",
|
23
|
+
"retries 3",
|
24
|
+
"timeout connect 5s",
|
25
|
+
"timeout client 1m",
|
26
|
+
"timeout server 1m",
|
27
|
+
"option redispatch",
|
28
|
+
"balance roundrobin"
|
29
|
+
],
|
30
|
+
"extra_sections": {
|
31
|
+
"listen stats :3212": [
|
32
|
+
"mode http",
|
33
|
+
"stats enable",
|
34
|
+
"stats uri /",
|
35
|
+
"stats refresh 5s"
|
36
|
+
],
|
37
|
+
"frontend http-generic-in": [
|
38
|
+
"bind 127.0.0.1:80",
|
39
|
+
"acl is_service1 hdr_dom(host) -i service1.lb",
|
40
|
+
"acl is_cache hdr_dom(host) -i cache.lb",
|
41
|
+
"use_backend service1 if is_service1",
|
42
|
+
"use_backend cache if is_cache"
|
43
|
+
]
|
44
|
+
}
|
45
|
+
}
|
46
|
+
}
|
@@ -0,0 +1,90 @@
|
|
1
|
+
{
|
2
|
+
"services": {
|
3
|
+
"service1": {
|
4
|
+
"default_servers": [
|
5
|
+
{
|
6
|
+
"name": "default1",
|
7
|
+
"host": "localhost",
|
8
|
+
"port": 8423
|
9
|
+
}
|
10
|
+
],
|
11
|
+
"discovery": {
|
12
|
+
"method": "zookeeper",
|
13
|
+
"path": "/services/service1",
|
14
|
+
"hosts": [
|
15
|
+
"localhost:2181"
|
16
|
+
]
|
17
|
+
},
|
18
|
+
"haproxy": {
|
19
|
+
"port": 3213,
|
20
|
+
"server_options": "check inter 2s rise 3 fall 2",
|
21
|
+
"listen": [
|
22
|
+
"mode http",
|
23
|
+
"option httpchk /health",
|
24
|
+
"http-check expect string OK"
|
25
|
+
]
|
26
|
+
}
|
27
|
+
|
28
|
+
},
|
29
|
+
"service2": {
|
30
|
+
"default_servers": [
|
31
|
+
{
|
32
|
+
"name": "default1",
|
33
|
+
"host": "localhost",
|
34
|
+
"port": 8422
|
35
|
+
}
|
36
|
+
],
|
37
|
+
"discovery": {
|
38
|
+
"method": "zookeeper",
|
39
|
+
"path": "/services/service2",
|
40
|
+
"hosts": [
|
41
|
+
"localhost:2181"
|
42
|
+
]
|
43
|
+
},
|
44
|
+
"haproxy": {
|
45
|
+
"port": 3214,
|
46
|
+
"server_options": "check inter 2s rise 3 fall 2",
|
47
|
+
"listen": [
|
48
|
+
"mode http",
|
49
|
+
"option httpchk /health"
|
50
|
+
]
|
51
|
+
}
|
52
|
+
}
|
53
|
+
},
|
54
|
+
"haproxy": {
|
55
|
+
"reload_command": "sudo service haproxy reload",
|
56
|
+
"config_file_path": "/etc/haproxy/haproxy.cfg",
|
57
|
+
"socket_file_path": "/var/haproxy/stats.sock",
|
58
|
+
"do_writes": false,
|
59
|
+
"do_reloads": false,
|
60
|
+
"do_socket": false,
|
61
|
+
"global": [
|
62
|
+
"daemon",
|
63
|
+
"user haproxy",
|
64
|
+
"group haproxy",
|
65
|
+
"maxconn 4096",
|
66
|
+
"log 127.0.0.1 local0",
|
67
|
+
"log 127.0.0.1 local1 notice",
|
68
|
+
"stats socket /var/haproxy/stats.sock mode 666 level admin"
|
69
|
+
],
|
70
|
+
"defaults": [
|
71
|
+
"log global",
|
72
|
+
"option dontlognull",
|
73
|
+
"maxconn 2000",
|
74
|
+
"retries 3",
|
75
|
+
"timeout connect 5s",
|
76
|
+
"timeout client 1m",
|
77
|
+
"timeout server 1m",
|
78
|
+
"option redispatch",
|
79
|
+
"balance roundrobin"
|
80
|
+
],
|
81
|
+
"extra_sections": {
|
82
|
+
"listen stats :3212": [
|
83
|
+
"mode http",
|
84
|
+
"stats enable",
|
85
|
+
"stats uri /",
|
86
|
+
"stats refresh 5s"
|
87
|
+
]
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
{
|
2
|
+
"default_servers": [
|
3
|
+
{ "name": "default1", "host": "localhost", "port": 8080 }
|
4
|
+
],
|
5
|
+
"discovery": {
|
6
|
+
"method": "dns",
|
7
|
+
"nameserver": "10.10.1.13",
|
8
|
+
"servers": [
|
9
|
+
"0.www.example.com",
|
10
|
+
"1.www.example.com"
|
11
|
+
]
|
12
|
+
},
|
13
|
+
"haproxy": {
|
14
|
+
"server_options": "check inter 2s rise 3 fall 2",
|
15
|
+
"listen": [
|
16
|
+
"mode http",
|
17
|
+
"option httplog"
|
18
|
+
],
|
19
|
+
"backend": [
|
20
|
+
"mode http",
|
21
|
+
"option httpchk GET /health HTTP/1.0"
|
22
|
+
]
|
23
|
+
}
|
24
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
{
|
2
|
+
"default_servers": [
|
3
|
+
{ "name": "default1", "host": "localhost", "port": 8080 }
|
4
|
+
],
|
5
|
+
"discovery": {
|
6
|
+
"method": "dns",
|
7
|
+
"nameserver": "10.10.1.13",
|
8
|
+
"servers": [
|
9
|
+
"0.www.example.com",
|
10
|
+
"1.www.example.com"
|
11
|
+
]
|
12
|
+
},
|
13
|
+
"haproxy": {
|
14
|
+
"server_options": "check inter 2s rise 3 fall 2",
|
15
|
+
"listen": [
|
16
|
+
"mode http",
|
17
|
+
"option httplog"
|
18
|
+
],
|
19
|
+
"backend": [
|
20
|
+
"mode http",
|
21
|
+
"option httpchk GET /health HTTP/1.0"
|
22
|
+
]
|
23
|
+
}
|
24
|
+
}
|
data/default.nix
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# Build a snapshot of synapse from the current git working copy.
|
2
|
+
|
3
|
+
with import <nixpkgs> { };
|
4
|
+
|
5
|
+
let
|
6
|
+
myGems = recurseIntoAttrs (callPackage ./.nix/rubylibs.nix { });
|
7
|
+
synapse_requirements = [
|
8
|
+
rubyLibs.aws_sdk
|
9
|
+
myGems.zk
|
10
|
+
myGems.docker_api
|
11
|
+
];
|
12
|
+
in
|
13
|
+
stdenv.mkDerivation rec {
|
14
|
+
name = "synapse-git";
|
15
|
+
version = "0.11.1";
|
16
|
+
|
17
|
+
src = ./.;
|
18
|
+
|
19
|
+
meta = {
|
20
|
+
description = "Development build of synapse from git";
|
21
|
+
homepage = "https://github.com/benley/synapse";
|
22
|
+
};
|
23
|
+
|
24
|
+
buildInputs = [ ruby rubygems git makeWrapper ];
|
25
|
+
propagatedBuildInputs = synapse_requirements;
|
26
|
+
|
27
|
+
buildPhase = "gem build synapse.gemspec";
|
28
|
+
|
29
|
+
installPhase = ''
|
30
|
+
export HOME=$TMP/home; mkdir -pv "$HOME"
|
31
|
+
|
32
|
+
gem install \
|
33
|
+
--ignore-dependencies \
|
34
|
+
--install-dir "$out/${ruby.gemPath}" \
|
35
|
+
--bindir "$out/bin" \
|
36
|
+
"synapse-${version}.gem" $gemFlags -- $buildFlags
|
37
|
+
|
38
|
+
# Don't keep the .gem file in the finished package
|
39
|
+
rm -frv "$out/${ruby.gemPath}/cache"
|
40
|
+
|
41
|
+
addToSearchPath GEM_PATH "$out/${ruby.gemPath}"
|
42
|
+
|
43
|
+
for prog in $out/bin/*; do
|
44
|
+
wrapProgram "$prog" \
|
45
|
+
--prefix GEM_PATH : "$GEM_PATH" \
|
46
|
+
--prefix RUBYLIB : "${rubygems}/lib" \
|
47
|
+
--set RUBYOPT rubygems \
|
48
|
+
$extraWrapperFlags ''${extraWrapperFlagsArray[@]}
|
49
|
+
done
|
50
|
+
|
51
|
+
# Make sure all the executables are actually in the package
|
52
|
+
for prog in $out/gems/*/bin/*; do
|
53
|
+
[[ -e "$out/bin/$(basename $prog)" ]]
|
54
|
+
done
|
55
|
+
|
56
|
+
# looks like useless files which break build repeatability and consume space
|
57
|
+
rm $out/${ruby.gemPath}/doc/*/*/created.rid \
|
58
|
+
$out/${ruby.gemPath}/gems/*/ext/*/mkmf.log || true
|
59
|
+
|
60
|
+
runHook postInstall
|
61
|
+
'';
|
62
|
+
|
63
|
+
propagatedUserEnvPkgs = synapse_requirements;
|
64
|
+
|
65
|
+
passthru.isRubyGem = true;
|
66
|
+
}
|
data/lib/synapse.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require "synapse/version"
|
2
|
+
require "synapse/service_watcher/base"
|
3
|
+
require "synapse/haproxy"
|
4
|
+
require "synapse/service_watcher"
|
5
|
+
require "synapse/log"
|
6
|
+
|
7
|
+
require 'logger'
|
8
|
+
require 'json'
|
9
|
+
|
10
|
+
include Synapse
|
11
|
+
|
12
|
+
module Synapse
|
13
|
+
class Synapse
|
14
|
+
include Logging
|
15
|
+
def initialize(opts={})
|
16
|
+
# create the service watchers for all our services
|
17
|
+
raise "specify a list of services to connect in the config" unless opts.has_key?('services')
|
18
|
+
@service_watchers = create_service_watchers(opts['services'])
|
19
|
+
|
20
|
+
# create the haproxy object
|
21
|
+
raise "haproxy config section is missing" unless opts.has_key?('haproxy')
|
22
|
+
@haproxy = Haproxy.new(opts['haproxy'])
|
23
|
+
|
24
|
+
# configuration is initially enabled to configure on first loop
|
25
|
+
@config_updated = true
|
26
|
+
|
27
|
+
# Any exceptions in the watcher threads should wake the main thread so
|
28
|
+
# that we can fail fast.
|
29
|
+
Thread.abort_on_exception = true
|
30
|
+
|
31
|
+
log.debug "synapse: completed init"
|
32
|
+
end
|
33
|
+
|
34
|
+
# start all the watchers and enable haproxy configuration
|
35
|
+
def run
|
36
|
+
log.info "synapse: starting..."
|
37
|
+
|
38
|
+
# start all the watchers
|
39
|
+
@service_watchers.map { |watcher| watcher.start }
|
40
|
+
|
41
|
+
# main loop
|
42
|
+
loops = 0
|
43
|
+
loop do
|
44
|
+
@service_watchers.each do |w|
|
45
|
+
raise "synapse: service watcher #{w.name} failed ping!" unless w.ping?
|
46
|
+
end
|
47
|
+
|
48
|
+
if @config_updated
|
49
|
+
@config_updated = false
|
50
|
+
log.info "synapse: regenerating haproxy config"
|
51
|
+
@haproxy.update_config(@service_watchers)
|
52
|
+
else
|
53
|
+
sleep 1
|
54
|
+
end
|
55
|
+
|
56
|
+
loops += 1
|
57
|
+
log.debug "synapse: still running at #{Time.now}" if (loops % 60) == 0
|
58
|
+
end
|
59
|
+
|
60
|
+
rescue StandardError => e
|
61
|
+
log.error "synapse: encountered unexpected exception #{e.inspect} in main thread"
|
62
|
+
raise e
|
63
|
+
ensure
|
64
|
+
log.warn "synapse: exiting; sending stop signal to all watchers"
|
65
|
+
|
66
|
+
# stop all the watchers
|
67
|
+
@service_watchers.map(&:stop)
|
68
|
+
end
|
69
|
+
|
70
|
+
def reconfigure!
|
71
|
+
@config_updated = true
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
def create_service_watchers(services={})
|
76
|
+
service_watchers =[]
|
77
|
+
services.each do |service_name, service_config|
|
78
|
+
service_watchers << ServiceWatcher.create(service_name, service_config, self)
|
79
|
+
end
|
80
|
+
|
81
|
+
return service_watchers
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|