diff --git a/include/proto/backend.h b/include/proto/backend.h index 8043613f1..601a61ada 100644 --- a/include/proto/backend.h +++ b/include/proto/backend.h @@ -61,7 +61,9 @@ static inline int srv_is_usable(const struct server *srv) if (!srv->eweight) return 0; - if (state & (SRV_STF_GOINGDOWN | SRV_STF_MAINTAIN)) + if (srv->admin & SRV_ADMF_MAINT) + return 0; + if (state & SRV_STF_GOINGDOWN) return 0; if (!(state & SRV_STF_RUNNING)) return 0; @@ -77,7 +79,9 @@ static inline int srv_was_usable(const struct server *srv) if (!srv->prev_eweight) return 0; - if (state & (SRV_STF_GOINGDOWN | SRV_STF_MAINTAIN)) + if (srv->prev_admin & SRV_ADMF_MAINT) + return 0; + if (state & SRV_STF_GOINGDOWN) return 0; if (!(state & SRV_STF_RUNNING)) return 0; @@ -90,6 +94,7 @@ static inline int srv_was_usable(const struct server *srv) static inline void srv_lb_commit_status(struct server *srv) { srv->prev_state = srv->state; + srv->prev_admin = srv->admin; srv->prev_eweight = srv->eweight; } @@ -99,6 +104,7 @@ static inline void srv_lb_commit_status(struct server *srv) static inline int srv_lb_status_changed(const struct server *srv) { return (srv->state != srv->prev_state || + srv->admin != srv->prev_admin || srv->eweight != srv->prev_eweight); } diff --git a/include/types/server.h b/include/types/server.h index 6b77b1581..ba0a1a51f 100644 --- a/include/types/server.h +++ b/include/types/server.h @@ -48,7 +48,16 @@ enum srv_state { SRV_STF_RUNNING = 0x1, /* the server is UP */ SRV_STF_GOINGDOWN = 0x2, /* the server is going down (eg: 404) */ SRV_STF_WARMINGUP = 0x4, /* the server is warming up after a failure */ - SRV_STF_MAINTAIN = 0x8, /* the server is in maintenance mode */ +}; + +/* Maintenance mode : each server may be in maintenance by itself or may inherit + * this status from another server it tracks. Let's store these origins here as + * flags. If no maintenance origin is specified, the server is not in maintenance. + */ +enum srv_admin { + SRV_ADMF_FMAINT = 0x1, /* the server was explicitly forced into maintenance */ + SRV_ADMF_IMAINT = 0x2, /* the server has inherited the maintenance status from a tracked server */ + SRV_ADMF_MAINT = 0x3, /* mask to check if any maintenance flag is present */ }; /* server flags */ @@ -105,6 +114,7 @@ struct tree_occ { struct server { enum obj_type obj_type; /* object type == OBJ_TYPE_SERVER */ enum srv_state state, prev_state; /* server state among SRV_STF_* */ + enum srv_admin admin, prev_admin; /* server maintenance status : SRV_ADMF_* */ unsigned char flags; /* server flags (SRV_F_*) */ struct server *next; int cklen; /* the len of the cookie, to speed up checks */ diff --git a/src/backend.c b/src/backend.c index 3ce7415da..0b4ff4dec 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1489,7 +1489,7 @@ smp_fetch_srv_is_up(struct proxy *px, struct session *l4, void *l7, unsigned int smp->flags = SMP_F_VOL_TEST; smp->type = SMP_T_BOOL; - if (!(srv->state & SRV_STF_MAINTAIN) && + if (!(srv->admin & SRV_ADMF_MAINT) && (!(srv->check.state & CHK_ST_CONFIGURED) || (srv->state & SRV_STF_RUNNING))) smp->data.uint = 1; else diff --git a/src/cfgparse.c b/src/cfgparse.c index a002cb234..037eaa913 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -6617,7 +6617,7 @@ out_uri_auth_compat: } /* if the other server is forced disabled, we have to do the same here */ - if (srv->state & SRV_STF_MAINTAIN) { + if (srv->admin & SRV_ADMF_MAINT) { newsrv->state &= ~SRV_STF_RUNNING; newsrv->check.health = 0; newsrv->agent.health = 0; diff --git a/src/checks.c b/src/checks.c index 9228c8958..f4bfd54b4 100644 --- a/src/checks.c +++ b/src/checks.c @@ -412,7 +412,7 @@ void set_server_down(struct check *check) struct server *srv; int xferred; - if (s->state & SRV_STF_MAINTAIN) { + if (s->admin & SRV_ADMF_MAINT) { check->health = check->rise; } @@ -436,7 +436,7 @@ void set_server_down(struct check *check) chunk_reset(&trash); - if (s->state & SRV_STF_MAINTAIN) { + if (s->admin & SRV_ADMF_MAINT) { chunk_appendf(&trash, "%sServer %s/%s is DOWN for maintenance", s->flags & SRV_F_BACKUP ? "Backup " : "", s->proxy->id, s->id); @@ -463,7 +463,7 @@ void set_server_down(struct check *check) s->counters.down_trans++; for (srv = s->trackers; srv; srv = srv->tracknext) - if (!(srv->state & SRV_STF_MAINTAIN)) + if (!(srv->admin & SRV_ADMF_MAINT)) /* Only notify tracking servers that are not already in maintenance. */ set_server_down(&srv->check); } @@ -476,9 +476,9 @@ void set_server_up(struct check *check) { struct server *s = check->server; struct server *srv; int xferred; - enum srv_state old_state = s->state; + enum srv_admin old_admin = s->admin; - if (s->state & SRV_STF_MAINTAIN) { + if (s->admin & SRV_ADMF_MAINT) { check->health = check->rise; } @@ -499,7 +499,7 @@ void set_server_up(struct check *check) { s->last_change = now.tv_sec; s->state |= SRV_STF_RUNNING; - s->state &= ~SRV_STF_MAINTAIN; + s->admin &= ~SRV_ADMF_FMAINT; s->check.state &= ~CHK_ST_PAUSED; if (s->slowstart > 0) { @@ -525,7 +525,7 @@ void set_server_up(struct check *check) { chunk_reset(&trash); - if (old_state & SRV_STF_MAINTAIN) { + if (old_admin) { chunk_appendf(&trash, "%sServer %s/%s is UP (leaving maintenance)", s->flags & SRV_F_BACKUP ? "Backup " : "", s->proxy->id, s->id); @@ -543,7 +543,7 @@ void set_server_up(struct check *check) { send_log(s->proxy, LOG_NOTICE, "%s.\n", trash.str); for (srv = s->trackers; srv; srv = srv->tracknext) - if (!(srv->state & SRV_STF_MAINTAIN)) + if (!(srv->admin & SRV_ADMF_MAINT)) /* Only notify tracking servers if they're not in maintenance. */ set_server_up(&srv->check); } @@ -1480,7 +1480,8 @@ static struct task *server_warmup(struct task *t) /* by default, plan on stopping the task */ t->expire = TICK_ETERNITY; - if ((s->state & (SRV_STF_RUNNING|SRV_STF_WARMINGUP|SRV_STF_MAINTAIN)) != (SRV_STF_RUNNING|SRV_STF_WARMINGUP)) + if ((s->admin & SRV_ADMF_MAINT) || + (s->state & (SRV_STF_RUNNING|SRV_STF_WARMINGUP)) != (SRV_STF_RUNNING|SRV_STF_WARMINGUP)) return t; server_recalc_eweight(s); @@ -1707,7 +1708,7 @@ static struct task *process_chk(struct task *t) set_server_disabled(check); } - if (!(s->state & SRV_STF_MAINTAIN) && + if (!(s->admin & SRV_ADMF_MAINT) && check->health < check->rise + check->fall - 1) { check->health++; /* was bad, stays for a while */ set_server_up(check); diff --git a/src/dumpstats.c b/src/dumpstats.c index 47328cecc..1de4199fd 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -1710,7 +1710,7 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line) if (!sv) return 1; - if (sv->state & SRV_STF_MAINTAIN) { + if (sv->admin & SRV_ADMF_MAINT) { /* The server is really in maintenance, we can change the server state */ if (sv->track) { /* If this server tracks the status of another one, @@ -1720,7 +1720,7 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line) set_server_up(&sv->check); sv->check.health = sv->check.rise; /* up, but will fall down at first failure */ } else { - sv->state &= ~SRV_STF_MAINTAIN; + sv->admin &= ~SRV_ADMF_FMAINT; sv->check.state &= ~CHK_ST_PAUSED; set_server_down(&sv->check); } @@ -1782,9 +1782,9 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line) if (!sv) return 1; - if (! (sv->state & SRV_STF_MAINTAIN)) { + if (!(sv->admin & SRV_ADMF_MAINT)) { /* Not already in maintenance, we can change the server state */ - sv->state |= SRV_STF_MAINTAIN; + sv->admin |= SRV_ADMF_FMAINT; sv->check.state |= CHK_ST_PAUSED; set_server_down(&sv->check); } @@ -2780,7 +2780,7 @@ static int stats_dump_sv_stats(struct stream_interface *si, struct proxy *px, in "no check" }; - if ((sv->state & SRV_STF_MAINTAIN) || (ref->state & SRV_STF_MAINTAIN)) + if ((sv->admin | ref->admin) & SRV_ADMF_MAINT) chunk_appendf(&trash, ""); else chunk_appendf(&trash, @@ -2911,11 +2911,11 @@ static int stats_dump_sv_stats(struct stream_interface *si, struct proxy *px, in /* status, lest check */ chunk_appendf(&trash, ""); - if (sv->state & SRV_STF_MAINTAIN) { + if (sv->admin & SRV_ADMF_MAINT) { chunk_appendf(&trash, "%s ", human_time(now.tv_sec - sv->last_change, 1)); chunk_appendf(&trash, "MAINT"); } - else if (ref != sv && ref->state & SRV_STF_MAINTAIN) { + else if (ref != sv && (ref->admin & SRV_ADMF_MAINT)) { chunk_appendf(&trash, "%s ", human_time(now.tv_sec - ref->last_change, 1)); chunk_appendf(&trash, "MAINT(via)"); } @@ -2976,7 +2976,7 @@ static int stats_dump_sv_stats(struct stream_interface *si, struct proxy *px, in ref->counters.down_trans, human_time(srv_downtime(sv), 1)); } else if (sv != ref) { - if (sv->state & SRV_STF_MAINTAIN) + if (sv->admin & SRV_ADMF_MAINT) chunk_appendf(&trash, ""); else chunk_appendf(&trash, @@ -3030,9 +3030,9 @@ static int stats_dump_sv_stats(struct stream_interface *si, struct proxy *px, in sv->counters.retries, sv->counters.redispatches); /* status */ - if (sv->state & SRV_STF_MAINTAIN) + if (sv->admin & SRV_ADMF_MAINT) chunk_appendf(&trash, "MAINT,"); - else if (ref != sv && ref->state & SRV_STF_MAINTAIN) + else if (ref != sv && (ref->admin & SRV_ADMF_MAINT)) chunk_appendf(&trash, "MAINT(via),"); else chunk_appendf(&trash, @@ -3638,7 +3638,7 @@ static int stats_dump_proxy_to_buffer(struct stream_interface *si, struct proxy else sv_state = 0; /* DOWN */ - if (((sv_state == 0) || (sv->state & SRV_STF_MAINTAIN)) && (appctx->ctx.stats.flags & STAT_HIDE_DOWN)) { + if (((sv_state == 0) || (sv->admin & SRV_ADMF_MAINT)) && (appctx->ctx.stats.flags & STAT_HIDE_DOWN)) { /* do not report servers which are DOWN */ appctx->ctx.stats.sv = sv->next; continue; @@ -4249,9 +4249,9 @@ static int stats_process_http_post(struct stream_interface *si) else if ((sv = findserver(px, value)) != NULL) { switch (action) { case ST_ADM_ACTION_DISABLE: - if ((px->state != PR_STSTOPPED) && !(sv->state & SRV_STF_MAINTAIN)) { + if ((px->state != PR_STSTOPPED) && !(sv->admin & SRV_ADMF_MAINT)) { /* Not already in maintenance, we can change the server state */ - sv->state |= SRV_STF_MAINTAIN; + sv->admin |= SRV_ADMF_FMAINT; sv->check.state |= CHK_ST_PAUSED; set_server_down(&sv->check); altered_servers++; @@ -4259,7 +4259,7 @@ static int stats_process_http_post(struct stream_interface *si) } break; case ST_ADM_ACTION_ENABLE: - if ((px->state != PR_STSTOPPED) && (sv->state & SRV_STF_MAINTAIN)) { + if ((px->state != PR_STSTOPPED) && (sv->admin & SRV_ADMF_MAINT)) { /* Already in maintenance, we can change the server state. * If this server tracks the status of another one, * we must restore the good status. @@ -4269,7 +4269,7 @@ static int stats_process_http_post(struct stream_interface *si) sv->check.health = sv->check.rise; /* up, but will fall down at first failure */ } else { - sv->state &= ~SRV_STF_MAINTAIN; + sv->admin &= ~SRV_ADMF_FMAINT; sv->check.state &= ~CHK_ST_PAUSED; set_server_down(&sv->check); } diff --git a/src/server.c b/src/server.c index dc0883e8d..7309f4281 100644 --- a/src/server.c +++ b/src/server.c @@ -346,6 +346,7 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr do_check = 0; do_agent = 0; newsrv->flags = 0; + newsrv->admin = 0; newsrv->state = SRV_STF_RUNNING; /* early server setup */ newsrv->last_change = now.tv_sec; newsrv->id = strdup(args[1]); @@ -680,7 +681,7 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr cur_arg += 1; } else if (!defsrv && !strcmp(args[cur_arg], "disabled")) { - newsrv->state |= SRV_STF_MAINTAIN; + newsrv->admin |= SRV_ADMF_FMAINT; newsrv->state &= ~SRV_STF_RUNNING; newsrv->check.state |= CHK_ST_PAUSED; newsrv->check.health = 0;