synapse-aurora 0.11.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/.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
|