synapse-aurora 0.11.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/.gitignore +23 -0
  2. data/.mailmap +3 -0
  3. data/.nix/Gemfile.nix +141 -0
  4. data/.nix/rubylibs.nix +42 -0
  5. data/.rspec +2 -0
  6. data/.travis.yml +5 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE.txt +22 -0
  9. data/Makefile +6 -0
  10. data/README.md +339 -0
  11. data/Rakefile +8 -0
  12. data/bin/synapse +62 -0
  13. data/config/hostheader_test.json +71 -0
  14. data/config/svcdir_test.json +46 -0
  15. data/config/synapse.conf.json +90 -0
  16. data/config/synapse_services/service1.json +24 -0
  17. data/config/synapse_services/service2.json +24 -0
  18. data/default.nix +66 -0
  19. data/lib/synapse.rb +85 -0
  20. data/lib/synapse/base.rb +5 -0
  21. data/lib/synapse/haproxy.rb +797 -0
  22. data/lib/synapse/log.rb +24 -0
  23. data/lib/synapse/service_watcher.rb +36 -0
  24. data/lib/synapse/service_watcher/base.rb +109 -0
  25. data/lib/synapse/service_watcher/dns.rb +109 -0
  26. data/lib/synapse/service_watcher/docker.rb +120 -0
  27. data/lib/synapse/service_watcher/ec2tag.rb +133 -0
  28. data/lib/synapse/service_watcher/zookeeper.rb +153 -0
  29. data/lib/synapse/service_watcher/zookeeper_aurora.rb +76 -0
  30. data/lib/synapse/service_watcher/zookeeper_dns.rb +232 -0
  31. data/lib/synapse/version.rb +3 -0
  32. data/spec/lib/synapse/haproxy_spec.rb +32 -0
  33. data/spec/lib/synapse/service_watcher_base_spec.rb +55 -0
  34. data/spec/lib/synapse/service_watcher_docker_spec.rb +152 -0
  35. data/spec/lib/synapse/service_watcher_ec2tags_spec.rb +220 -0
  36. data/spec/spec_helper.rb +22 -0
  37. data/spec/support/configuration.rb +9 -0
  38. data/spec/support/minimum.conf.yaml +27 -0
  39. data/synapse.gemspec +33 -0
  40. metadata +227 -0
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :test => :spec
7
+ task :default => :spec
8
+
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