synapse 0.2.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/.gitignore +3 -0
  2. data/.mailmap +3 -0
  3. data/LICENSE.txt +2 -2
  4. data/Makefile +6 -0
  5. data/README.md +42 -13
  6. data/bin/synapse +29 -21
  7. data/config/hostheader_test.json +71 -0
  8. data/config/svcdir_test.json +46 -0
  9. data/config/synapse.conf.json +26 -32
  10. data/config/synapse_services/service1.json +24 -0
  11. data/config/synapse_services/service2.json +24 -0
  12. data/lib/synapse.rb +39 -24
  13. data/lib/synapse/base.rb +1 -1
  14. data/lib/synapse/haproxy.rb +579 -22
  15. data/lib/synapse/log.rb +24 -0
  16. data/lib/synapse/service_watcher.rb +10 -6
  17. data/lib/synapse/service_watcher/base.rb +33 -11
  18. data/lib/synapse/service_watcher/dns.rb +28 -20
  19. data/lib/synapse/service_watcher/docker.rb +108 -0
  20. data/lib/synapse/service_watcher/ec2tag.rb +1 -1
  21. data/lib/synapse/service_watcher/zookeeper.rb +25 -28
  22. data/lib/synapse/version.rb +1 -1
  23. data/spec/spec_helper.rb +2 -2
  24. data/synapse.gemspec +2 -3
  25. metadata +15 -25
  26. data/Vagrantfile +0 -112
  27. data/chef/converge +0 -4
  28. data/chef/cookbooks/lxc/recipes/default.rb +0 -2
  29. data/chef/cookbooks/synapse/attributes/default.rb +0 -1
  30. data/chef/cookbooks/synapse/recipes/default.rb +0 -6
  31. data/chef/run.json +0 -8
  32. data/chef/run.rb +0 -2
  33. data/client/.RData +0 -0
  34. data/client/.Rhistory +0 -294
  35. data/client/bench_rewrite_config.dat +0 -2013
  36. data/client/benchmark-client.iml +0 -20
  37. data/client/pom.xml +0 -45
  38. data/client/src/main/java/ClientArsch.java +0 -68
  39. data/client/src/main/java/META-INF/MANIFEST.MF +0 -3
  40. data/haproxy.pid +0 -1
  41. data/lib/gen-rb/endpoint_types.rb +0 -65
  42. data/lib/gen-rb/thrift.rb +0 -65
  43. data/test.sh +0 -3
data/.gitignore CHANGED
@@ -18,3 +18,6 @@ tmp
18
18
  *~
19
19
  .vagrant
20
20
  .*sw?
21
+ vendor/
22
+
23
+ synapse.jar
data/.mailmap ADDED
@@ -0,0 +1,3 @@
1
+ <igor.serebryany@airbedandbreakfast.com> <igor47@moomers.org>
2
+ <martin.rhoads@airbnb.com> <ermal14@gmail.com>
3
+ Pierre Carrier <pierre@gcarrier.fr>
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012 Martin Rhoads
1
+ Copyright (c) 2013 Airbnb, Inc.
2
2
 
3
3
  MIT License
4
4
 
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
19
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
20
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
21
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Makefile ADDED
@@ -0,0 +1,6 @@
1
+ build: synapse.jar
2
+
3
+ synapse.jar:
4
+ jruby -S warble jar
5
+
6
+ .PHONY: build push
data/README.md CHANGED
@@ -54,10 +54,7 @@ Add a hash under `services` that looks like this:
54
54
 
55
55
  ```json
56
56
  {"services":
57
- {
58
- "name": "proddb",
59
- "local_port": 3219,
60
- "server_options": "check inter 2000 rise 3 fall 2",
57
+ "proddb": {
61
58
  "default_servers": [
62
59
  {
63
60
  "name": "default-db",
@@ -70,8 +67,16 @@ Add a hash under `services` that looks like this:
70
67
  "tag": "proddb",
71
68
  "value": "true"
72
69
  },
73
- "listen": [
74
- ]
70
+ "haproxy": {
71
+ "port": 3219,
72
+ "server_options": "check inter 2000 rise 3 fall 2",
73
+ "frontend": [
74
+ "mode tcp",
75
+ ],
76
+ "backend": [
77
+ "mode tcp",
78
+ ],
79
+ },
75
80
  },
76
81
  ...
77
82
  ```
@@ -114,15 +119,13 @@ The second is the `haproxy` section, which specifies how to configure and intera
114
119
 
115
120
  ### Configuring a Service ###
116
121
 
117
- Each service hash has the following options:
122
+ The services are a hash, where the keys are the `name` of the service to be configured.
123
+ The name is just a human-readable string; it will be used in logs and notifications.
124
+ Each value in the services hash is also a hash, and should contain the following keys:
118
125
 
119
- * `name`: a human-readable name for the service, this is used in logs and notifications
120
- * `local_port`: the port (on localhost) where HAProxy will listen for connections to the serivce
121
126
  * `discovery`: how synapse will discover hosts providing this service (see below)
122
127
  * `default_servers`: the list of default servers providing this service; synapse uses these if none others can be discovered
123
- * `server_port_override`: the port that discovered servers listen on; if the discovery method discovers a port along with hostnames (like the zookeeper watcher) this option may be left out, but will be used in preference if given
124
- * `server_options`: the haproxy options for each `server` line of the service in HAProxy config; may be left out
125
- * `listen`: additional lines passed to the HAProxy config in the `listen` stanza of this service
128
+ * `haproxy`: how will the haproxy section for this service be configured
126
129
 
127
130
  #### Service Discovery ####
128
131
 
@@ -149,6 +152,17 @@ The watcher assumes that each node under `path` represents a service server.
149
152
  Synapse attempts to decode the data in each of these nodes using JSON and also using Thrift under the standard Twitter service encoding.
150
153
  We assume that the data contains a hostname and a port for service servers.
151
154
 
155
+ ##### Docker #####
156
+
157
+ This watcher retrieves a list of [docker](http://www.docker.io/) containers via docker's [HTTP API](http://docs.docker.io/en/latest/api/docker_remote_api/).
158
+ It takes the following options:
159
+
160
+ * `method`: docker
161
+ * `servers`: a list of servers running docker as a daemon. Format is `{"name":"...", "host": "..."[, port: 4243]}`
162
+ * `image_name`: find containers running this image
163
+ * `container_port`: find containers forwarding this port
164
+ * `check_interval`: how often to poll the docker API on each server. Default is 15s.
165
+
152
166
  #### Listing Default Servers ####
153
167
 
154
168
  You may list a number of default servers providing a service.
@@ -162,6 +176,17 @@ The `default_servers` list is used only when service discovery returns no server
162
176
  In that case, the service proxy will be created with the servers listed here.
163
177
  If you do not list any default servers, no proxy will be created.
164
178
 
179
+ #### The `haproxy` Section ####
180
+
181
+ This section is it's own hash, which should contain the following keys:
182
+
183
+ * `port`: the port (on localhost) where HAProxy will listen for connections to the service.
184
+ * `server_port_override`: the port that discovered servers listen on; you should specify this if your discovery mechanism only discovers names or addresses (like the DNS watcher). If the discovery method discovers a port along with hostnames (like the zookeeper watcher) this option may be left out, but will be used in preference if given.
185
+ * `server_options`: the haproxy options for each `server` line of the service in HAProxy config; it may be left out.
186
+ * `frontend`: additional lines passed to the HAProxy config in the `frontend` stanza of this service
187
+ * `backend`: additional lines passed to the HAProxy config in the `backend` stanza of this service
188
+ * `listen`: these lines will be parsed and placed in the correct `frontend`/`backend` section as applicable; you can put lines which are the same for the frontend and backend here.
189
+
165
190
  ### Configuring HAProxy ###
166
191
 
167
192
  The `haproxy` section of the config file has the following options:
@@ -172,6 +197,9 @@ The `haproxy` section of the config file has the following options:
172
197
  * `do_reloads`: whether or not Synapse will reload HAProxy (default to `true`)
173
198
  * `global`: options listed here will be written into the `global` section of the HAProxy config
174
199
  * `defaults`: options listed here will be written into the `defaults` section of the HAProxy config
200
+ * `bind_address`: force HAProxy to listen on this address (default is localhost)
201
+
202
+ Note that a non-default `bind_address` can be dangerous: it is up to you to ensure that HAProxy will not attempt to bind an address:port combination that is not already in use by one of your services.
175
203
 
176
204
  ## Contributing
177
205
 
@@ -188,7 +216,8 @@ If you'd like to create a new service watcher:
188
216
  1. Create a file for your watcher in `service_watcher` dir
189
217
  2. Use the following template:
190
218
  ```ruby
191
- require_relative "./base"
219
+ require 'synapse/service_watcher/base'
220
+
192
221
  module Synapse
193
222
  class NewWatcher < BaseWatcher
194
223
  def start
data/bin/synapse CHANGED
@@ -3,18 +3,18 @@
3
3
  require 'json'
4
4
  require 'optparse'
5
5
 
6
- require_relative "../lib/synapse"
6
+ require 'synapse'
7
7
 
8
8
  options={}
9
9
 
10
10
  # set command line options
11
11
  optparse = OptionParser.new do |opts|
12
- opts.banner =<<EOB
12
+ opts.banner =<<-EOB
13
13
  Welcome to synapse
14
14
 
15
15
  Usage: synapse --config /path/to/synapse/config
16
- EOB
17
-
16
+ EOB
17
+
18
18
  options[:config] = ENV['SYNAPSE_CONFIG']
19
19
  opts.on('-c config','--config config', String, 'path to synapse config') do |key,value|
20
20
  options[:config] = key
@@ -24,31 +24,39 @@ EOB
24
24
  puts opts
25
25
  exit
26
26
  end
27
-
28
27
  end
29
28
 
30
-
31
29
  # parse command line arguments
32
30
  optparse.parse!
33
31
 
34
-
35
- # parse synapse config file
36
- begin
37
- config = JSON::parse(File.read(options[:config]))
38
- rescue Errno::ENOENT => e
39
- raise ArgumentError, "config file does not exist:\n#{e.inspect}"
40
- rescue Errno::EACCES => e
41
- raise ArgumentError, "could not open config file:\n#{e.inspect}"
42
- rescue JSON::ParserError => e
43
- raise "config file #{options[:config]} is not json:\n#{e.inspect}"
32
+ def parseconfig(filename)
33
+ # parse synapse config file
34
+ begin
35
+ c = JSON::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 JSON::ParserError => e
41
+ raise "config file #{filename} is not json:\n#{e.inspect}"
42
+ end
43
+ return c
44
44
  end
45
45
 
46
+ config = parseconfig(options[:config])
47
+ config['services'] ||= {}
46
48
 
47
- # create synapse object
48
- s = Synapse::Synapse.new config
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'))
55
+ cfiles.each { |x| config['services'][File.basename(x[/(.*)\.json$/, 1])] = parseconfig(x) }
56
+ end
49
57
 
50
- # start synapse
58
+ # run synapse
59
+ s = Synapse::Synapse.new(config)
51
60
  s.run
52
61
 
53
-
54
- puts "exiting synapse"
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
+ }
@@ -1,9 +1,6 @@
1
1
  {
2
- "services": [
3
- {
4
- "name": "service1",
5
- "local_port": 3213,
6
- "server_options": "check inter 2s rise 3 fall 2",
2
+ "services": {
3
+ "service1": {
7
4
  "default_servers": [
8
5
  {
9
6
  "name": "default1",
@@ -13,22 +10,23 @@
13
10
  ],
14
11
  "discovery": {
15
12
  "method": "zookeeper",
16
- "path": "/airbnb/service/service1",
13
+ "path": "/services/service1",
17
14
  "hosts": [
18
- "zk0.airbnb.com:2181",
19
- "zk1.airbnb.com:2181"
15
+ "localhost:2181"
20
16
  ]
21
17
  },
22
- "listen": [
23
- "mode http",
24
- "option httpchk /health",
25
- "http-check expect string OK"
26
- ]
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
+
27
28
  },
28
- {
29
- "name": "service2",
30
- "local_port": 3214,
31
- "server_options": "check inter 2s rise 3 fall 2",
29
+ "service2": {
32
30
  "default_servers": [
33
31
  {
34
32
  "name": "default1",
@@ -38,18 +36,21 @@
38
36
  ],
39
37
  "discovery": {
40
38
  "method": "zookeeper",
41
- "path": "/airbnb/service/service2",
39
+ "path": "/services/service2",
42
40
  "hosts": [
43
- "zk0.airbnb.com:2181",
44
- "zk1.airbnb.com:2181"
41
+ "localhost:2181"
45
42
  ]
46
43
  },
47
- "listen": [
48
- "mode http",
49
- "option httpchk /health",
50
- ]
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
+ }
51
52
  }
52
- ],
53
+ },
53
54
  "haproxy": {
54
55
  "reload_command": "sudo service haproxy reload",
55
56
  "config_file_path": "/etc/haproxy/haproxy.cfg",
@@ -85,12 +86,5 @@
85
86
  "stats refresh 5s"
86
87
  ]
87
88
  }
88
- },
89
- "synapse": {
90
- "self_check_port": 3210,
91
- "self_check_proxy_port": 3211,
92
- "zk_servers": [
93
- "localhost:2181"
94
- ]
95
89
  }
96
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
+ }