synapse 0.13.1 → 0.13.5

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -149,9 +149,19 @@ Put these into the `discovery` section of the service hash, with these options:
149
149
  ##### Base #####
150
150
 
151
151
  The base watcher is useful in situations where you only want to use the servers in the `default_servers` list.
152
- It has only one option:
152
+ It has the following options:
153
153
 
154
154
  * `method`: base
155
+ * `label_filter`: optional filter to be applied to discovered service nodes
156
+
157
+ ###### Filtering service nodes ######
158
+ Synapse can be configured to only return service nodes that match a `label_filter` predicate. If provided, the `label_filter` hash should contain the following:
159
+
160
+ * `label`: The label for which the filter is applied
161
+ * `value`: The comparison value
162
+ * `condition` (one of ['`equals`']): The type of filter condition to be applied. Only `equals` is supported at present
163
+
164
+ Given a `label_filter`: `{ "label": "cluster", "value": "dev", "condition": "equals" }`, this will return only service nodes that contain the label value `{ "cluster": "dev" }`.
155
165
 
156
166
  ##### Zookeeper #####
157
167
 
@@ -175,6 +185,7 @@ Synapse attempts to decode the data in each of these nodes using JSON and you ca
175
185
  * `endpoint_name` (default: nil): If using the `serverset` method, this controls which of the `additionalEndpoints` is chosen instead of the `serviceEndpoint` data. If not supplied the `serverset` method will use the host/port from the `serviceEndpoint` data.
176
186
 
177
187
  If the `method` is `nerve`, then we expect to find nerve registrations with a `host` and a `port`.
188
+ Any additional metadata for the service node provided in the hash `labels` will be parsed. This information is used by `label_filter` configuration.
178
189
 
179
190
  If the `method` is `serverset` then we expect to find Finagle ServerSet
180
191
  (also used by [Aurora](https://github.com/apache/aurora/blob/master/docs/user-guide.md#service-discovery)) registrations with a `serviceEndpoint` and optionally one or more `additionalEndpoints`.
@@ -261,6 +272,7 @@ This section is its own hash, which should contain the following keys:
261
272
  * `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.
262
273
  * `backend_order`: optional: how backends should be ordered in the `backend` stanza. (default is shuffling). Setting to `asc` means sorting backends in ascending alphabetical order before generating stanza. `desc` means descending alphabetical order. `no_shuffle` means no shuffling or sorting.
263
274
  * `shared_frontend`: optional: haproxy configuration directives for a shared http frontend (see below)
275
+ * `cookie_value_method`: optional: default value is `name`, it defines the way your backends receive a cookie value in http mode. If equal to `hash`, synapse hashes backend names on cookie value assignation of your discovered backends, useful when you want to use haproxy cookie feature but you do not want that your end users receive a Set-Cookie with your server name and ip readable in clear.
264
276
 
265
277
  <a name="haproxy"/>
266
278
  ### Configuring HAProxy ###
@@ -1,15 +1,17 @@
1
1
  require 'fileutils'
2
2
  require 'json'
3
3
  require 'socket'
4
+ require 'digest/sha1'
4
5
 
5
6
  module Synapse
6
7
  class Haproxy
7
8
  include Logging
8
- attr_reader :opts, :name
9
+ attr_reader :opts
9
10
 
10
- # these come from the documentation for haproxy 1.5
11
+ # these come from the documentation for haproxy (1.5 and 1.6)
11
12
  # http://haproxy.1wt.eu/download/1.5/doc/configuration.txt
12
- @@section_fields = {
13
+ # http://haproxy.1wt.eu/download/1.6/doc/configuration.txt
14
+ SECTION_FIELDS = {
13
15
  "backend" => [
14
16
  "acl",
15
17
  "appsession",
@@ -23,6 +25,11 @@ module Synapse
23
25
  "description",
24
26
  "disabled",
25
27
  "dispatch",
28
+ "email-alert from",
29
+ "email-alert level",
30
+ "email-alert mailers",
31
+ "email-alert myhostname",
32
+ "email-alert to",
26
33
  "enabled",
27
34
  "errorfile",
28
35
  "errorloc",
@@ -37,10 +44,59 @@ module Synapse
37
44
  "http-check send-state",
38
45
  "http-request",
39
46
  "http-response",
47
+ "http-send-name-header",
48
+ "http-reuse",
49
+ "http-send-name-header",
40
50
  "id",
41
51
  "ignore-persist",
52
+ "load-server-state-from-file",
42
53
  "log",
54
+ "log-tag",
55
+ "max-keep-alive-queue",
43
56
  "mode",
57
+ "no log",
58
+ "no option abortonclose",
59
+ "no option accept-invalid-http-response",
60
+ "no option allbackups",
61
+ "no option allredisp",
62
+ "no option checkcache",
63
+ "no option forceclose",
64
+ "no option forwardfor",
65
+ "no option http-buffer-request",
66
+ "no option http-keep-alive",
67
+ "no option http-no-delay",
68
+ "no option http-pretend-keepalive",
69
+ "no option http-server-close",
70
+ "no option http-tunnel",
71
+ "no option httpchk",
72
+ "no option httpclose",
73
+ "no option httplog",
74
+ "no option http_proxy",
75
+ "no option independent-streams",
76
+ "no option lb-agent-chk",
77
+ "no option ldap-check",
78
+ "no option external-check",
79
+ "no option log-health-checks",
80
+ "no option mysql-check",
81
+ "no option pgsql-check",
82
+ "no option nolinger",
83
+ "no option originalto",
84
+ "no option persist",
85
+ "no option pgsql-check",
86
+ "no option prefer-last-server",
87
+ "no option redispatch",
88
+ "no option redis-check",
89
+ "no option smtpchk",
90
+ "no option splice-auto",
91
+ "no option splice-request",
92
+ "no option splice-response",
93
+ "no option srvtcpka",
94
+ "no option ssl-hello-chk",
95
+ "no option tcp-check",
96
+ "no option tcp-smart-connect",
97
+ "no option tcpka",
98
+ "no option tcplog",
99
+ "no option transparent",
44
100
  "option abortonclose",
45
101
  "option accept-invalid-http-response",
46
102
  "option allbackups",
@@ -48,9 +104,12 @@ module Synapse
48
104
  "option checkcache",
49
105
  "option forceclose",
50
106
  "option forwardfor",
107
+ "option http-buffer-request",
108
+ "option http-keep-alive",
51
109
  "option http-no-delay",
52
110
  "option http-pretend-keepalive",
53
111
  "option http-server-close",
112
+ "option http-tunnel",
54
113
  "option httpchk",
55
114
  "option httpclose",
56
115
  "option httplog",
@@ -58,12 +117,15 @@ module Synapse
58
117
  "option independent-streams",
59
118
  "option lb-agent-chk",
60
119
  "option ldap-check",
120
+ "option external-check",
61
121
  "option log-health-checks",
62
122
  "option mysql-check",
63
123
  "option pgsql-check",
64
124
  "option nolinger",
65
125
  "option originalto",
66
126
  "option persist",
127
+ "option pgsql-check",
128
+ "option prefer-last-server",
67
129
  "option redispatch",
68
130
  "option redis-check",
69
131
  "option smtpchk",
@@ -77,6 +139,8 @@ module Synapse
77
139
  "option tcpka",
78
140
  "option tcplog",
79
141
  "option transparent",
142
+ "external-check command",
143
+ "external-check path",
80
144
  "persist rdp-cookie",
81
145
  "redirect",
82
146
  "redisp",
@@ -105,6 +169,7 @@ module Synapse
105
169
  "rspirep",
106
170
  "rsprep",
107
171
  "server",
172
+ "server-state-file-name",
108
173
  "source",
109
174
  "srvtimeout",
110
175
  "stats admin",
@@ -139,6 +204,7 @@ module Synapse
139
204
  "timeout http-request",
140
205
  "timeout queue",
141
206
  "timeout server",
207
+ "timeout server-fin",
142
208
  "timeout srvtimeout",
143
209
  "timeout tarpit",
144
210
  "timeout tunnel",
@@ -156,6 +222,11 @@ module Synapse
156
222
  "default-server",
157
223
  "default_backend",
158
224
  "disabled",
225
+ "email-alert from",
226
+ "email-alert level",
227
+ "email-alert mailers",
228
+ "email-alert myhostname",
229
+ "email-alert to",
159
230
  "enabled",
160
231
  "errorfile",
161
232
  "errorloc",
@@ -166,11 +237,71 @@ module Synapse
166
237
  "hash-type",
167
238
  "http-check disable-on-404",
168
239
  "http-check send-state",
240
+ "http-reuse",
241
+ "load-server-state-from-file",
169
242
  "log",
243
+ "log-format",
244
+ "log-format-sd",
245
+ "log-tag",
246
+ "max-keep-alive-queue",
170
247
  "maxconn",
171
248
  "mode",
172
249
  "monitor-net",
173
250
  "monitor-uri",
251
+ "no log",
252
+ "no option abortonclose",
253
+ "no option accept-invalid-http-request",
254
+ "no option accept-invalid-http-response",
255
+ "no option allbackups",
256
+ "no option allredisp",
257
+ "no option checkcache",
258
+ "no option clitcpka",
259
+ "no option contstats",
260
+ "no option dontlog-normal",
261
+ "no option dontlognull",
262
+ "no option forceclose",
263
+ "no option forwardfor",
264
+ "no option http-buffer-request",
265
+ "no option http-ignore-probes",
266
+ "no option http-keep-alive",
267
+ "no option http-no-delay",
268
+ "no option http-pretend-keepalive",
269
+ "no option http-server-close",
270
+ "no option http-tunnel",
271
+ "no option http-use-proxy-header",
272
+ "no option httpchk",
273
+ "no option httpclose",
274
+ "no option httplog",
275
+ "no option http_proxy",
276
+ "no option independent-streams",
277
+ "no option lb-agent-chk",
278
+ "no option ldap-check",
279
+ "no option external-check",
280
+ "no option log-health-checks",
281
+ "no option log-separate-errors",
282
+ "no option logasap",
283
+ "no option mysql-check",
284
+ "no option pgsql-check",
285
+ "no option nolinger",
286
+ "no option originalto",
287
+ "no option persist",
288
+ "no option pgsql-check",
289
+ "no option prefer-last-server",
290
+ "no option redispatch",
291
+ "no option redis-check",
292
+ "no option smtpchk",
293
+ "no option socket-stats",
294
+ "no option splice-auto",
295
+ "no option splice-request",
296
+ "no option splice-response",
297
+ "no option srvtcpka",
298
+ "no option ssl-hello-chk",
299
+ "no option tcp-check",
300
+ "no option tcp-smart-accept",
301
+ "no option tcp-smart-connect",
302
+ "no option tcpka",
303
+ "no option tcplog",
304
+ "no option transparent",
174
305
  "option abortonclose",
175
306
  "option accept-invalid-http-request",
176
307
  "option accept-invalid-http-response",
@@ -183,9 +314,13 @@ module Synapse
183
314
  "option dontlognull",
184
315
  "option forceclose",
185
316
  "option forwardfor",
317
+ "option http-buffer-request",
318
+ "option http-ignore-probes",
319
+ "option http-keep-alive",
186
320
  "option http-no-delay",
187
321
  "option http-pretend-keepalive",
188
322
  "option http-server-close",
323
+ "option http-tunnel",
189
324
  "option http-use-proxy-header",
190
325
  "option httpchk",
191
326
  "option httpclose",
@@ -194,6 +329,7 @@ module Synapse
194
329
  "option independent-streams",
195
330
  "option lb-agent-chk",
196
331
  "option ldap-check",
332
+ "option external-check",
197
333
  "option log-health-checks",
198
334
  "option log-separate-errors",
199
335
  "option logasap",
@@ -202,6 +338,8 @@ module Synapse
202
338
  "option nolinger",
203
339
  "option originalto",
204
340
  "option persist",
341
+ "option pgsql-check",
342
+ "option prefer-last-server",
205
343
  "option redispatch",
206
344
  "option redis-check",
207
345
  "option smtpchk",
@@ -217,11 +355,14 @@ module Synapse
217
355
  "option tcpka",
218
356
  "option tcplog",
219
357
  "option transparent",
358
+ "external-check command",
359
+ "external-check path",
220
360
  "persist rdp-cookie",
221
361
  "rate-limit sessions",
222
362
  "redisp",
223
363
  "redispatch",
224
364
  "retries",
365
+ "server-state-file-name",
225
366
  "source",
226
367
  "srvtimeout",
227
368
  "stats auth",
@@ -236,6 +377,7 @@ module Synapse
236
377
  "stats uri",
237
378
  "timeout check",
238
379
  "timeout client",
380
+ "timeout client-fin",
239
381
  "timeout clitimeout",
240
382
  "timeout connect",
241
383
  "timeout contimeout",
@@ -243,6 +385,7 @@ module Synapse
243
385
  "timeout http-request",
244
386
  "timeout queue",
245
387
  "timeout server",
388
+ "timeout server-fin",
246
389
  "timeout srvtimeout",
247
390
  "timeout tarpit",
248
391
  "timeout tunnel",
@@ -261,9 +404,15 @@ module Synapse
261
404
  "capture response header",
262
405
  "clitimeout",
263
406
  "compression",
407
+ "declare capture",
264
408
  "default_backend",
265
409
  "description",
266
410
  "disabled",
411
+ "email-alert from",
412
+ "email-alert level",
413
+ "email-alert mailers",
414
+ "email-alert myhostname",
415
+ "email-alert to",
267
416
  "enabled",
268
417
  "errorfile",
269
418
  "errorloc",
@@ -276,11 +425,45 @@ module Synapse
276
425
  "id",
277
426
  "ignore-persist",
278
427
  "log",
428
+ "log-format",
429
+ "log-format-sd",
430
+ "log-tag",
279
431
  "maxconn",
280
432
  "mode",
281
433
  "monitor fail",
282
434
  "monitor-net",
283
435
  "monitor-uri",
436
+ "no log",
437
+ "no option accept-invalid-http-request",
438
+ "no option clitcpka",
439
+ "no option contstats",
440
+ "no option dontlog-normal",
441
+ "no option dontlognull",
442
+ "no option forceclose",
443
+ "no option forwardfor",
444
+ "no option http-buffer-request",
445
+ "no option http-ignore-probes",
446
+ "no option http-keep-alive",
447
+ "no option http-no-delay",
448
+ "no option http-pretend-keepalive",
449
+ "no option http-server-close",
450
+ "no option http-tunnel",
451
+ "no option http-use-proxy-header",
452
+ "no option httpclose",
453
+ "no option httplog",
454
+ "no option http_proxy",
455
+ "no option independent-streams",
456
+ "no option log-separate-errors",
457
+ "no option logasap",
458
+ "no option nolinger",
459
+ "no option originalto",
460
+ "no option socket-stats",
461
+ "no option splice-auto",
462
+ "no option splice-request",
463
+ "no option splice-response",
464
+ "no option tcp-smart-accept",
465
+ "no option tcpka",
466
+ "no option tcplog",
284
467
  "option accept-invalid-http-request",
285
468
  "option clitcpka",
286
469
  "option contstats",
@@ -288,9 +471,13 @@ module Synapse
288
471
  "option dontlognull",
289
472
  "option forceclose",
290
473
  "option forwardfor",
474
+ "option http-buffer-request",
475
+ "option http-ignore-probes",
476
+ "option http-keep-alive",
291
477
  "option http-no-delay",
292
478
  "option http-pretend-keepalive",
293
479
  "option http-server-close",
480
+ "option http-tunnel",
294
481
  "option http-use-proxy-header",
295
482
  "option httpclose",
296
483
  "option httplog",
@@ -331,10 +518,23 @@ module Synapse
331
518
  "rspideny",
332
519
  "rspirep",
333
520
  "rsprep",
521
+ "stats admin",
522
+ "stats auth",
523
+ "stats enable",
524
+ "stats hide-version",
525
+ "stats http-request",
526
+ "stats realm",
527
+ "stats refresh",
528
+ "stats scope",
529
+ "stats show-desc",
530
+ "stats show-legends",
531
+ "stats show-node",
532
+ "stats uri",
334
533
  "tcp-request connection",
335
534
  "tcp-request content",
336
535
  "tcp-request inspect-delay",
337
536
  "timeout client",
537
+ "timeout client-fin",
338
538
  "timeout clitimeout",
339
539
  "timeout http-keep-alive",
340
540
  "timeout http-request",
@@ -358,11 +558,17 @@ module Synapse
358
558
  "compression",
359
559
  "contimeout",
360
560
  "cookie",
561
+ "declare capture",
361
562
  "default-server",
362
563
  "default_backend",
363
564
  "description",
364
565
  "disabled",
365
566
  "dispatch",
567
+ "email-alert from",
568
+ "email-alert level",
569
+ "email-alert mailers",
570
+ "email-alert myhostname",
571
+ "email-alert to",
366
572
  "enabled",
367
573
  "errorfile",
368
574
  "errorloc",
@@ -377,14 +583,76 @@ module Synapse
377
583
  "http-check send-state",
378
584
  "http-request",
379
585
  "http-response",
586
+ "http-send-name-header",
587
+ "http-reuse",
588
+ "http-send-name-header",
380
589
  "id",
381
590
  "ignore-persist",
591
+ "load-server-state-from-file",
382
592
  "log",
593
+ "log-format",
594
+ "log-format-sd",
595
+ "log-tag",
596
+ "max-keep-alive-queue",
383
597
  "maxconn",
384
598
  "mode",
385
599
  "monitor fail",
386
600
  "monitor-net",
387
601
  "monitor-uri",
602
+ "no log",
603
+ "no option abortonclose",
604
+ "no option accept-invalid-http-request",
605
+ "no option accept-invalid-http-response",
606
+ "no option allbackups",
607
+ "no option allredisp",
608
+ "no option checkcache",
609
+ "no option clitcpka",
610
+ "no option contstats",
611
+ "no option dontlog-normal",
612
+ "no option dontlognull",
613
+ "no option forceclose",
614
+ "no option forwardfor",
615
+ "no option http-buffer-request",
616
+ "no option http-ignore-probes",
617
+ "no option http-keep-alive",
618
+ "no option http-no-delay",
619
+ "no option http-pretend-keepalive",
620
+ "no option http-server-close",
621
+ "no option http-tunnel",
622
+ "no option http-use-proxy-header",
623
+ "no option httpchk",
624
+ "no option httpclose",
625
+ "no option httplog",
626
+ "no option http_proxy",
627
+ "no option independent-streams",
628
+ "no option lb-agent-chk",
629
+ "no option ldap-check",
630
+ "no option external-check",
631
+ "no option log-health-checks",
632
+ "no option log-separate-errors",
633
+ "no option logasap",
634
+ "no option mysql-check",
635
+ "no option pgsql-check",
636
+ "no option nolinger",
637
+ "no option originalto",
638
+ "no option persist",
639
+ "no option pgsql-check",
640
+ "no option prefer-last-server",
641
+ "no option redispatch",
642
+ "no option redis-check",
643
+ "no option smtpchk",
644
+ "no option socket-stats",
645
+ "no option splice-auto",
646
+ "no option splice-request",
647
+ "no option splice-response",
648
+ "no option srvtcpka",
649
+ "no option ssl-hello-chk",
650
+ "no option tcp-check",
651
+ "no option tcp-smart-accept",
652
+ "no option tcp-smart-connect",
653
+ "no option tcpka",
654
+ "no option tcplog",
655
+ "no option transparent",
388
656
  "option abortonclose",
389
657
  "option accept-invalid-http-request",
390
658
  "option accept-invalid-http-response",
@@ -397,9 +665,13 @@ module Synapse
397
665
  "option dontlognull",
398
666
  "option forceclose",
399
667
  "option forwardfor",
668
+ "option http-buffer-request",
669
+ "option http-ignore-probes",
670
+ "option http-keep-alive",
400
671
  "option http-no-delay",
401
672
  "option http-pretend-keepalive",
402
673
  "option http-server-close",
674
+ "option http-tunnel",
403
675
  "option http-use-proxy-header",
404
676
  "option httpchk",
405
677
  "option httpclose",
@@ -408,6 +680,7 @@ module Synapse
408
680
  "option independent-streams",
409
681
  "option lb-agent-chk",
410
682
  "option ldap-check",
683
+ "option external-check",
411
684
  "option log-health-checks",
412
685
  "option log-separate-errors",
413
686
  "option logasap",
@@ -416,6 +689,8 @@ module Synapse
416
689
  "option nolinger",
417
690
  "option originalto",
418
691
  "option persist",
692
+ "option pgsql-check",
693
+ "option prefer-last-server",
419
694
  "option redispatch",
420
695
  "option redis-check",
421
696
  "option smtpchk",
@@ -431,6 +706,8 @@ module Synapse
431
706
  "option tcpka",
432
707
  "option tcplog",
433
708
  "option transparent",
709
+ "external-check command",
710
+ "external-check path",
434
711
  "persist rdp-cookie",
435
712
  "rate-limit sessions",
436
713
  "redirect",
@@ -460,6 +737,7 @@ module Synapse
460
737
  "rspirep",
461
738
  "rsprep",
462
739
  "server",
740
+ "server-state-file-name",
463
741
  "source",
464
742
  "srvtimeout",
465
743
  "stats admin",
@@ -490,6 +768,7 @@ module Synapse
490
768
  "tcp-response inspect-delay",
491
769
  "timeout check",
492
770
  "timeout client",
771
+ "timeout client-fin",
493
772
  "timeout clitimeout",
494
773
  "timeout connect",
495
774
  "timeout contimeout",
@@ -497,6 +776,7 @@ module Synapse
497
776
  "timeout http-request",
498
777
  "timeout queue",
499
778
  "timeout server",
779
+ "timeout server-fin",
500
780
  "timeout srvtimeout",
501
781
  "timeout tarpit",
502
782
  "timeout tunnel",
@@ -506,7 +786,10 @@ module Synapse
506
786
  "use_backend",
507
787
  "use-server"
508
788
  ]
509
- }
789
+ }.freeze
790
+
791
+ DEFAULT_STATE_FILE_TTL = (60 * 60 * 24).freeze # 24 hours
792
+ STATE_FILE_UPDATE_INTERVAL = 60.freeze # iterations; not a unit of time
510
793
 
511
794
  def initialize(opts)
512
795
  super()
@@ -527,7 +810,6 @@ module Synapse
527
810
  end
528
811
 
529
812
  @opts = opts
530
- @name = 'haproxy'
531
813
 
532
814
  @opts['do_writes'] = true unless @opts.key?('do_writes')
533
815
  @opts['do_socket'] = true unless @opts.key?('do_socket')
@@ -546,20 +828,15 @@ module Synapse
546
828
  @watcher_configs = {}
547
829
 
548
830
  @state_file_path = @opts['state_file_path']
549
- @state_file_ttl = @opts.fetch('state_file_ttl', 60 * 60 * 24).to_i
550
- @seen = {}
551
-
552
- unless @state_file_path.nil?
553
- begin
554
- @seen = JSON.load(File.read(@state_file_path))
555
- rescue StandardError => e
556
- # It's ok if the state file doesn't exist
557
- end
558
- end
831
+ @state_file_ttl = @opts.fetch('state_file_ttl', DEFAULT_STATE_FILE_TTL).to_i
832
+ end
833
+
834
+ def name
835
+ 'haproxy'
559
836
  end
560
837
 
561
838
  def tick(watchers)
562
- if @time % 60 == 0 && !@state_file_path.nil?
839
+ if (@time % STATE_FILE_UPDATE_INTERVAL) == 0
563
840
  update_state_file(watchers)
564
841
  end
565
842
 
@@ -654,7 +931,7 @@ module Synapse
654
931
  config[section].concat(
655
932
  watcher.haproxy['listen'].select {|setting|
656
933
  parsed_setting = setting.strip.gsub(/\s+/, ' ').downcase
657
- @@section_fields[section].any? {|field| parsed_setting.start_with?(field)}
934
+ SECTION_FIELDS[section].any? {|field| parsed_setting.start_with?(field)}
658
935
  })
659
936
 
660
937
  # pick only those fields that are valid and warn about the invalid ones
@@ -667,7 +944,7 @@ module Synapse
667
944
  def validate_haproxy_stanza(stanza, stanza_type, service_name)
668
945
  return stanza.select {|setting|
669
946
  parsed_setting = setting.strip.gsub(/\s+/, ' ').downcase
670
- if @@section_fields[stanza_type].any? {|field| parsed_setting.start_with?(field)}
947
+ if SECTION_FIELDS[stanza_type].any? {|field| parsed_setting.start_with?(field)}
671
948
  true
672
949
  else
673
950
  log.warn "synapse: service #{service_name} contains invalid #{stanza_type} setting: '#{setting}', discarding"
@@ -696,7 +973,7 @@ module Synapse
696
973
 
697
974
  # The ordering here is important. First we add all the backends in the
698
975
  # disabled state...
699
- @seen.fetch(watcher.name, []).each do |backend_name, backend|
976
+ seen.fetch(watcher.name, []).each do |backend_name, backend|
700
977
  backends[backend_name] = backend.merge('enabled' => false)
701
978
  end
702
979
 
@@ -731,13 +1008,21 @@ module Synapse
731
1008
  else
732
1009
  backends.keys.shuffle
733
1010
  end
1011
+
734
1012
  stanza = [
735
1013
  "\nbackend #{watcher.haproxy.fetch('backend_name', watcher.name)}",
736
1014
  config.map {|c| "\t#{c}"},
737
1015
  keys.map {|backend_name|
738
1016
  backend = backends[backend_name]
739
1017
  b = "\tserver #{backend_name} #{backend['host']}:#{backend['port']}"
740
- b = "#{b} cookie #{backend_name}" unless config.include?('mode tcp')
1018
+ unless config.include?('mode tcp')
1019
+ b = case watcher.haproxy['cookie_value_method']
1020
+ when 'hash'
1021
+ b = "#{b} cookie #{Digest::SHA1.hexdigest(backend_name)}"
1022
+ else
1023
+ b = "#{b} cookie #{backend_name}"
1024
+ end
1025
+ end
741
1026
  b = "#{b} #{watcher.haproxy['server_options']}" if watcher.haproxy['server_options']
742
1027
  b = "#{b} #{backend['haproxy_server_options']}" if backend['haproxy_server_options']
743
1028
  b = "#{b} disabled" unless backend['enabled']
@@ -745,16 +1030,24 @@ module Synapse
745
1030
  ]
746
1031
  end
747
1032
 
1033
+ def haproxy_exec(command)
1034
+ s = UNIXSocket.new(@opts['socket_file_path'])
1035
+ s.write(command)
1036
+ s.read
1037
+ ensure
1038
+ s.close if s
1039
+ end
1040
+
748
1041
  # tries to set active backends via haproxy's stats socket
749
1042
  # because we can't add backends via the socket, we might still need to restart haproxy
750
1043
  def update_backends(watchers)
751
1044
  # first, get a list of existing servers for various backends
752
1045
  begin
753
- s = UNIXSocket.new(@opts['socket_file_path'])
754
- s.write("show stat\n")
755
- info = s.read()
1046
+ stat_command = "show stat\n"
1047
+ info = haproxy_exec(stat_command)
756
1048
  rescue StandardError => e
757
- log.warn "synapse: unhandled error reading stats socket: #{e.inspect}"
1049
+ log.warn "synapse: restart required because socket command #{stat_command} failed "\
1050
+ "with error #{e.inspect}"
758
1051
  @restart_required = true
759
1052
  return
760
1053
  end
@@ -805,15 +1098,15 @@ module Synapse
805
1098
 
806
1099
  # actually write the command to the socket
807
1100
  begin
808
- s = UNIXSocket.new(@opts['socket_file_path'])
809
- s.write(command)
810
- output = s.read()
1101
+ output = haproxy_exec(command)
811
1102
  rescue StandardError => e
812
- log.warn "synapse: unknown error writing to socket"
1103
+ log.warn "synapse: restart required because socket command #{command} failed with "\
1104
+ "error #{e.inspect}"
813
1105
  @restart_required = true
814
1106
  else
815
1107
  unless output == "\n"
816
- log.warn "synapse: socket command #{command} failed: #{output}"
1108
+ log.warn "synapse: restart required because socket command #{command} failed with "\
1109
+ "output #{output}"
817
1110
  @restart_required = true
818
1111
  end
819
1112
  end
@@ -865,19 +1158,34 @@ module Synapse
865
1158
  def construct_name(backend)
866
1159
  name = "#{backend['host']}:#{backend['port']}"
867
1160
  if backend['name'] && !backend['name'].empty?
868
- name = "#{name}_#{backend['name']}"
1161
+ name = "#{backend['name']}_#{name}"
869
1162
  end
870
1163
 
871
1164
  return name
872
1165
  end
873
1166
 
1167
+ ######################################
1168
+ # methods for managing the state file
1169
+ ######################################
1170
+ def seen
1171
+ # if we don't support the state file, return nothing
1172
+ return {} if @state_file_path.nil?
1173
+
1174
+ # if we've never needed the backends, now is the time to load them
1175
+ @seen = read_state_file if @seen.nil?
1176
+
1177
+ @seen
1178
+ end
1179
+
874
1180
  def update_state_file(watchers)
875
- log.info "synapse: writing state file"
1181
+ # if we don't support the state file, do nothing
1182
+ return if @state_file_path.nil?
876
1183
 
1184
+ log.info "synapse: writing state file"
877
1185
  timestamp = Time.now.to_i
878
1186
 
879
1187
  # Remove stale backends
880
- @seen.each do |watcher_name, backends|
1188
+ seen.each do |watcher_name, backends|
881
1189
  backends.each do |backend_name, backend|
882
1190
  ts = backend.fetch('timestamp', 0)
883
1191
  delta = (timestamp - ts).abs
@@ -889,23 +1197,35 @@ module Synapse
889
1197
  end
890
1198
 
891
1199
  # Remove any services which no longer have any backends
892
- @seen = @seen.reject{|watcher_name, backends| backends.keys.length == 0}
1200
+ seen.reject!{|watcher_name, backends| backends.keys.length == 0}
893
1201
 
894
1202
  # Add backends from watchers
895
1203
  watchers.each do |watcher|
896
- unless @seen.key?(watcher.name)
897
- @seen[watcher.name] = {}
898
- end
1204
+ seen[watcher.name] ||= {}
899
1205
 
900
1206
  watcher.backends.each do |backend|
901
1207
  backend_name = construct_name(backend)
902
- @seen[watcher.name][backend_name] = backend.merge('timestamp' => timestamp)
1208
+ seen[watcher.name][backend_name] = backend.merge('timestamp' => timestamp)
903
1209
  end
904
1210
  end
905
1211
 
906
- # Atomically write new state file
1212
+ # write the data!
1213
+ write_data_to_state_file(seen)
1214
+ end
1215
+
1216
+ def read_state_file
1217
+ # Some versions of JSON return nil on an empty file ...
1218
+ JSON.load(File.read(@state_file_path)) || {}
1219
+ rescue StandardError => e
1220
+ # It's ok if the state file doesn't exist or contains invalid data
1221
+ # The state file will be rebuilt automatically
1222
+ {}
1223
+ end
1224
+
1225
+ # we do this atomically so the state file is always consistent
1226
+ def write_data_to_state_file(data)
907
1227
  tmp_state_file_path = @state_file_path + ".tmp"
908
- File.write(tmp_state_file_path, JSON.pretty_generate(@seen))
1228
+ File.write(tmp_state_file_path, JSON.pretty_generate(data))
909
1229
  FileUtils.mv(tmp_state_file_path, @state_file_path)
910
1230
  end
911
1231
  end