diff --git a/include/proto/server.h b/include/proto/server.h index 0ed68b8c1..a7cc5d569 100644 --- a/include/proto/server.h +++ b/include/proto/server.h @@ -45,6 +45,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 3c757296c..4923d8609 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -8450,13 +8450,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 8198e4efc..2b12ba3bf 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -956,6 +956,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 cc1f0d10a..f38ee8d0c 100644 --- a/src/server.c +++ b/src/server.c @@ -710,6 +710,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 . + * 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 as its list will be overwritten. * Please take care of keeping this list alphabetically sorted, doing so helps * all code contributors. @@ -2028,15 +2062,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]); }