|
|
- From c449c9835e7d9e02cf0aeafc482364d5090db543 Mon Sep 17 00:00:00 2001
- From: Willy Tarreau <w@1wt.eu>
- Date: Thu, 3 Nov 2016 19:22:19 +0100
- Subject: [PATCH 30/31] BUG/MEDIUM: servers: properly propagate the maintenance
- states during startup
-
- Right now there is an issue with the way the maintenance flags are
- propagated upon startup. They are not propagate, just copied from the
- tracked server. This implies that depending on the server's order, some
- tracking servers may not be marked down. For example this configuration
- does not work as expected :
-
- server s1 1.1.1.1:8000 track s2
- server s2 1.1.1.1:8000 track s3
- server s3 1.1.1.1:8000 track s4
- server s4 wtap:8000 check inter 1s disabled
-
- It results in s1/s2 being up, and s3/s4 being down, while all of them
- should be down.
-
- The only clean way to process this is to run through all "root" servers
- (those not tracking any other server), and to propagate their state down
- to all their trackers. This is the same algorithm used to propagate the
- state changes. It has to be done both to compute the IDRAIN flag and the
- IMAINT flag. However, doing so requires that tracking servers are not
- marked as inherited maintenance anymore while parsing the configuration
- (and given that it is wrong, better drop it).
-
- This fix also addresses another side effect of the bug above which is
- that the IDRAIN/IMAINT flags are stored in the state files, and if
- restored while the tracked server doesn't have the equivalent flag,
- the servers may end up in a situation where it's impossible to remove
- these flags. For example in the configuration above, after removing
- "disabled" on server s4, the other servers would have remained down,
- and not anymore with this fix. Similarly, the combination of IMAINT
- or IDRAIN with their respective forced modes was not accepted on
- reload, which is wrong as well.
-
- This bug has been present at least since 1.5, maybe even 1.4 (it came
- with tracking support). The fix needs to be backported there, though
- the srv-state parts are irrelevant.
-
- This commit relies on previous patch to silence warnings on startup.
- (cherry picked from commit 757478e900ebc1e67c1fe060b9b561d276cab3e1)
- ---
- include/proto/server.h | 1 +
- src/cfgparse.c | 7 -------
- src/haproxy.c | 4 ++++
- src/server.c | 42 +++++++++++++++++++++++++++++++++++++++---
- 4 files changed, 44 insertions(+), 10 deletions(-)
-
- diff --git a/include/proto/server.h b/include/proto/server.h
- index d75cc9f..b6572ba 100644
- --- a/include/proto/server.h
- +++ b/include/proto/server.h
- @@ -44,6 +44,7 @@ struct server *server_find_by_id(struct proxy *bk, int id);
- struct server *server_find_by_name(struct proxy *bk, const char *name);
- struct server *server_find_best_match(struct proxy *bk, char *name, int id, int *diff);
- void apply_server_state(void);
- +void srv_compute_all_admin_states(struct proxy *px);
-
- /* functions related to server name resolution */
- int snr_update_srv_status(struct server *s);
- diff --git a/src/cfgparse.c b/src/cfgparse.c
- index b8289a2..365b283 100644
- --- a/src/cfgparse.c
- +++ b/src/cfgparse.c
- @@ -8275,13 +8275,6 @@ out_uri_auth_compat:
- goto next_srv;
- }
-
- - /* if the other server is forced disabled, we have to do the same here */
- - if (srv->admin & SRV_ADMF_MAINT) {
- - newsrv->admin |= SRV_ADMF_IMAINT;
- - newsrv->state = SRV_ST_STOPPED;
- - newsrv->check.health = 0;
- - }
- -
- newsrv->track = srv;
- newsrv->tracknext = srv->trackers;
- srv->trackers = newsrv;
- diff --git a/src/haproxy.c b/src/haproxy.c
- index 2d476f2..1699132 100644
- --- a/src/haproxy.c
- +++ b/src/haproxy.c
- @@ -566,6 +566,7 @@ void init(int argc, char **argv)
- struct wordlist *wl;
- char *progname;
- char *change_dir = NULL;
- + struct proxy *px;
-
- chunk_init(&trash, malloc(global.tune.bufsize), global.tune.bufsize);
- alloc_trash_buffers(global.tune.bufsize);
- @@ -852,6 +853,9 @@ void init(int argc, char **argv)
- /* Apply server states */
- apply_server_state();
-
- + for (px = proxy; px; px = px->next)
- + srv_compute_all_admin_states(px);
- +
- global_listener_queue_task = task_new();
- if (!global_listener_queue_task) {
- Alert("Out of memory when initializing global task\n");
- diff --git a/src/server.c b/src/server.c
- index b0c7bbe..f2923ae 100644
- --- a/src/server.c
- +++ b/src/server.c
- @@ -705,6 +705,40 @@ void srv_clr_admin_flag(struct server *s, enum srv_admin mode)
- srv_clr_admin_flag(srv, mode);
- }
-
- +/* principle: propagate maint and drain to tracking servers. This is useful
- + * upon startup so that inherited states are correct.
- + */
- +static void srv_propagate_admin_state(struct server *srv)
- +{
- + struct server *srv2;
- +
- + if (!srv->trackers)
- + return;
- +
- + for (srv2 = srv->trackers; srv2; srv2 = srv2->tracknext) {
- + if (srv->admin & (SRV_ADMF_MAINT | SRV_ADMF_CMAINT))
- + srv_set_admin_flag(srv2, SRV_ADMF_IMAINT);
- +
- + if (srv->admin & SRV_ADMF_DRAIN)
- + srv_set_admin_flag(srv2, SRV_ADMF_IDRAIN);
- + }
- +}
- +
- +/* Compute and propagate the admin states for all servers in proxy <px>.
- + * Only servers *not* tracking another one are considered, because other
- + * ones will be handled when the server they track is visited.
- + */
- +void srv_compute_all_admin_states(struct proxy *px)
- +{
- + struct server *srv;
- +
- + for (srv = px->srv; srv; srv = srv->next) {
- + if (srv->track)
- + continue;
- + srv_propagate_admin_state(srv);
- + }
- +}
- +
- /* Note: must not be declared <const> as its list will be overwritten.
- * Please take care of keeping this list alphabetically sorted, doing so helps
- * all code contributors.
- @@ -1955,15 +1989,17 @@ static void srv_update_state(struct server *srv, int version, char **params)
- p = NULL;
- errno = 0;
- srv_admin_state = strtol(params[2], &p, 10);
- +
- + /* inherited statuses will be recomputed later */
- + srv_admin_state &= ~SRV_ADMF_IDRAIN & ~SRV_ADMF_IMAINT;
- +
- if ((p == params[2]) || errno == EINVAL || errno == ERANGE ||
- (srv_admin_state != 0 &&
- srv_admin_state != SRV_ADMF_FMAINT &&
- - srv_admin_state != SRV_ADMF_IMAINT &&
- srv_admin_state != SRV_ADMF_CMAINT &&
- srv_admin_state != (SRV_ADMF_CMAINT | SRV_ADMF_FMAINT) &&
- srv_admin_state != (SRV_ADMF_CMAINT | SRV_ADMF_FDRAIN) &&
- - srv_admin_state != SRV_ADMF_FDRAIN &&
- - srv_admin_state != SRV_ADMF_IDRAIN)) {
- + srv_admin_state != SRV_ADMF_FDRAIN)) {
- chunk_appendf(msg, ", invalid srv_admin_state value '%s'", params[2]);
- }
-
- --
- 2.7.3
-
|