You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

172 lines
6.3 KiB

  1. From c449c9835e7d9e02cf0aeafc482364d5090db543 Mon Sep 17 00:00:00 2001
  2. From: Willy Tarreau <w@1wt.eu>
  3. Date: Thu, 3 Nov 2016 19:22:19 +0100
  4. Subject: [PATCH 30/31] BUG/MEDIUM: servers: properly propagate the maintenance
  5. states during startup
  6. Right now there is an issue with the way the maintenance flags are
  7. propagated upon startup. They are not propagate, just copied from the
  8. tracked server. This implies that depending on the server's order, some
  9. tracking servers may not be marked down. For example this configuration
  10. does not work as expected :
  11. server s1 1.1.1.1:8000 track s2
  12. server s2 1.1.1.1:8000 track s3
  13. server s3 1.1.1.1:8000 track s4
  14. server s4 wtap:8000 check inter 1s disabled
  15. It results in s1/s2 being up, and s3/s4 being down, while all of them
  16. should be down.
  17. The only clean way to process this is to run through all "root" servers
  18. (those not tracking any other server), and to propagate their state down
  19. to all their trackers. This is the same algorithm used to propagate the
  20. state changes. It has to be done both to compute the IDRAIN flag and the
  21. IMAINT flag. However, doing so requires that tracking servers are not
  22. marked as inherited maintenance anymore while parsing the configuration
  23. (and given that it is wrong, better drop it).
  24. This fix also addresses another side effect of the bug above which is
  25. that the IDRAIN/IMAINT flags are stored in the state files, and if
  26. restored while the tracked server doesn't have the equivalent flag,
  27. the servers may end up in a situation where it's impossible to remove
  28. these flags. For example in the configuration above, after removing
  29. "disabled" on server s4, the other servers would have remained down,
  30. and not anymore with this fix. Similarly, the combination of IMAINT
  31. or IDRAIN with their respective forced modes was not accepted on
  32. reload, which is wrong as well.
  33. This bug has been present at least since 1.5, maybe even 1.4 (it came
  34. with tracking support). The fix needs to be backported there, though
  35. the srv-state parts are irrelevant.
  36. This commit relies on previous patch to silence warnings on startup.
  37. (cherry picked from commit 757478e900ebc1e67c1fe060b9b561d276cab3e1)
  38. ---
  39. include/proto/server.h | 1 +
  40. src/cfgparse.c | 7 -------
  41. src/haproxy.c | 4 ++++
  42. src/server.c | 42 +++++++++++++++++++++++++++++++++++++++---
  43. 4 files changed, 44 insertions(+), 10 deletions(-)
  44. diff --git a/include/proto/server.h b/include/proto/server.h
  45. index d75cc9f..b6572ba 100644
  46. --- a/include/proto/server.h
  47. +++ b/include/proto/server.h
  48. @@ -44,6 +44,7 @@ struct server *server_find_by_id(struct proxy *bk, int id);
  49. struct server *server_find_by_name(struct proxy *bk, const char *name);
  50. struct server *server_find_best_match(struct proxy *bk, char *name, int id, int *diff);
  51. void apply_server_state(void);
  52. +void srv_compute_all_admin_states(struct proxy *px);
  53. /* functions related to server name resolution */
  54. int snr_update_srv_status(struct server *s);
  55. diff --git a/src/cfgparse.c b/src/cfgparse.c
  56. index b8289a2..365b283 100644
  57. --- a/src/cfgparse.c
  58. +++ b/src/cfgparse.c
  59. @@ -8275,13 +8275,6 @@ out_uri_auth_compat:
  60. goto next_srv;
  61. }
  62. - /* if the other server is forced disabled, we have to do the same here */
  63. - if (srv->admin & SRV_ADMF_MAINT) {
  64. - newsrv->admin |= SRV_ADMF_IMAINT;
  65. - newsrv->state = SRV_ST_STOPPED;
  66. - newsrv->check.health = 0;
  67. - }
  68. -
  69. newsrv->track = srv;
  70. newsrv->tracknext = srv->trackers;
  71. srv->trackers = newsrv;
  72. diff --git a/src/haproxy.c b/src/haproxy.c
  73. index 2d476f2..1699132 100644
  74. --- a/src/haproxy.c
  75. +++ b/src/haproxy.c
  76. @@ -566,6 +566,7 @@ void init(int argc, char **argv)
  77. struct wordlist *wl;
  78. char *progname;
  79. char *change_dir = NULL;
  80. + struct proxy *px;
  81. chunk_init(&trash, malloc(global.tune.bufsize), global.tune.bufsize);
  82. alloc_trash_buffers(global.tune.bufsize);
  83. @@ -852,6 +853,9 @@ void init(int argc, char **argv)
  84. /* Apply server states */
  85. apply_server_state();
  86. + for (px = proxy; px; px = px->next)
  87. + srv_compute_all_admin_states(px);
  88. +
  89. global_listener_queue_task = task_new();
  90. if (!global_listener_queue_task) {
  91. Alert("Out of memory when initializing global task\n");
  92. diff --git a/src/server.c b/src/server.c
  93. index b0c7bbe..f2923ae 100644
  94. --- a/src/server.c
  95. +++ b/src/server.c
  96. @@ -705,6 +705,40 @@ void srv_clr_admin_flag(struct server *s, enum srv_admin mode)
  97. srv_clr_admin_flag(srv, mode);
  98. }
  99. +/* principle: propagate maint and drain to tracking servers. This is useful
  100. + * upon startup so that inherited states are correct.
  101. + */
  102. +static void srv_propagate_admin_state(struct server *srv)
  103. +{
  104. + struct server *srv2;
  105. +
  106. + if (!srv->trackers)
  107. + return;
  108. +
  109. + for (srv2 = srv->trackers; srv2; srv2 = srv2->tracknext) {
  110. + if (srv->admin & (SRV_ADMF_MAINT | SRV_ADMF_CMAINT))
  111. + srv_set_admin_flag(srv2, SRV_ADMF_IMAINT);
  112. +
  113. + if (srv->admin & SRV_ADMF_DRAIN)
  114. + srv_set_admin_flag(srv2, SRV_ADMF_IDRAIN);
  115. + }
  116. +}
  117. +
  118. +/* Compute and propagate the admin states for all servers in proxy <px>.
  119. + * Only servers *not* tracking another one are considered, because other
  120. + * ones will be handled when the server they track is visited.
  121. + */
  122. +void srv_compute_all_admin_states(struct proxy *px)
  123. +{
  124. + struct server *srv;
  125. +
  126. + for (srv = px->srv; srv; srv = srv->next) {
  127. + if (srv->track)
  128. + continue;
  129. + srv_propagate_admin_state(srv);
  130. + }
  131. +}
  132. +
  133. /* Note: must not be declared <const> as its list will be overwritten.
  134. * Please take care of keeping this list alphabetically sorted, doing so helps
  135. * all code contributors.
  136. @@ -1955,15 +1989,17 @@ static void srv_update_state(struct server *srv, int version, char **params)
  137. p = NULL;
  138. errno = 0;
  139. srv_admin_state = strtol(params[2], &p, 10);
  140. +
  141. + /* inherited statuses will be recomputed later */
  142. + srv_admin_state &= ~SRV_ADMF_IDRAIN & ~SRV_ADMF_IMAINT;
  143. +
  144. if ((p == params[2]) || errno == EINVAL || errno == ERANGE ||
  145. (srv_admin_state != 0 &&
  146. srv_admin_state != SRV_ADMF_FMAINT &&
  147. - srv_admin_state != SRV_ADMF_IMAINT &&
  148. srv_admin_state != SRV_ADMF_CMAINT &&
  149. srv_admin_state != (SRV_ADMF_CMAINT | SRV_ADMF_FMAINT) &&
  150. srv_admin_state != (SRV_ADMF_CMAINT | SRV_ADMF_FDRAIN) &&
  151. - srv_admin_state != SRV_ADMF_FDRAIN &&
  152. - srv_admin_state != SRV_ADMF_IDRAIN)) {
  153. + srv_admin_state != SRV_ADMF_FDRAIN)) {
  154. chunk_appendf(msg, ", invalid srv_admin_state value '%s'", params[2]);
  155. }
  156. --
  157. 2.7.3