diff --git a/doc/configuration.txt b/doc/configuration.txt index 4fd93892f..05bdf4ea4 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -17551,6 +17551,51 @@ downinter "inter" setting will have a very limited effect as it will not be able to reduce the time spent in the queue. +init-state { fully-up | up | down | fully-down } + May be used in the following contexts: tcp, http + + May be used in sections : defaults | frontend | listen | backend + no | no | yes | yes + + The "init-state" option sets the initial state of the server: + - when set to 'fully-up', the server is considered immediately available + and can turn to the DOWN sate when ALL health checks fail. + - when set to 'up' (the default), the server is considered immediately + available and will initiate a health check that can turn it to the DOWN + state immediately if it fails. + - when set to 'down', the server initially is considered unavailable and + will initiate a health check that can turn it to the UP state immediately + if it succeeds. + - when set to 'fully-down', the server is initially considered unavailable + and can turn to the UP state when ALL health checks succeed. + + The server's init-state is considered when the HAProxy instance is + (re)started, a new server is detected (for example via service discovery / + DNS resolution), a server exits maintenance, etc. + + Examples: + # pass client traffic ONLY to Redis "master" node + backend redis-master + mode tcp + balance first + option tcp-check + tcp-check send role\r\n + tcp-check expect string master + server-template redis 3 _redis._tcp.redis-headless-service.sandbox.svc.cluster.local:6379 check ... init-state down + + # pass traffic to the server only after 3 successful health checks + backend google-backend + mode http + server srv1 google.com:80 check init-state down rise 3 + server srv2 google.com:80 check init-state down rise 3 + + # or + listen + mode http + server-template srv 2 google.com:80 check init-state down rise 3 + +See also: "option tcp-check", "option httpchk" + log-bufsize May be used in the following contexts: log diff --git a/include/haproxy/server-t.h b/include/haproxy/server-t.h index 4233fff80..7fc7b1c9d 100644 --- a/include/haproxy/server-t.h +++ b/include/haproxy/server-t.h @@ -101,6 +101,17 @@ enum srv_initaddr { SRV_IADDR_IP = 4, /* we set an arbitrary IP address to the server */ } __attribute__((packed)); +/* options for servers' "init-state" parameter this parameter may be + * used to drive HAProxy's behavior when determining a server's status + * at start up time. + */ +enum srv_init_state { + SRV_INIT_STATE_FULLY_DOWN = 0, /* the server should initially be considered DOWN until it passes all health checks. Please keep set to zero. */ + SRV_INIT_STATE_DOWN, /* the server should initially be considered DOWN until it passes one health check. */ + SRV_INIT_STATE_UP, /* the server should initially be considered UP, but will go DOWN if it fails one health check. */ + SRV_INIT_STATE_FULLY_UP, /* the server should initially be considered UP, but will go DOWN if it fails all health checks. */ +} __attribute__((packed)); + /* server-state-file version */ #define SRV_STATE_FILE_VERSION 1 #define SRV_STATE_FILE_VERSION_MIN 1 @@ -279,6 +290,7 @@ struct proxy; struct server { /* mostly config or admin stuff, doesn't change often */ enum obj_type obj_type; /* object type == OBJ_TYPE_SERVER */ + enum srv_init_state init_state; /* server's initial state among SRV_INIT_STATE */ enum srv_state next_state, cur_state; /* server state among SRV_ST_* */ enum srv_admin next_admin, cur_admin; /* server maintenance status : SRV_ADMF_* */ signed char use_ssl; /* ssl enabled (1: on, 0: disabled, -1 forced off) */ diff --git a/src/server.c b/src/server.c index 3e0b99e92..29beffe82 100644 --- a/src/server.c +++ b/src/server.c @@ -1054,6 +1054,27 @@ static int srv_parse_init_addr(char **args, int *cur_arg, return 0; } +/* Parse the "init-state" server keyword */ +static int srv_parse_init_state(char **args, int *cur_arg, + struct proxy *curproxy, struct server *newsrv, char **err) +{ + if (strcmp(args[*cur_arg + 1], "fully-up") == 0) + newsrv->init_state= SRV_INIT_STATE_FULLY_UP; + else if (strcmp(args[*cur_arg + 1], "up") == 0) + newsrv->init_state = SRV_INIT_STATE_UP; + else if (strcmp(args[*cur_arg + 1], "down") == 0) + newsrv->init_state= SRV_INIT_STATE_DOWN; + else if (strcmp(args[*cur_arg + 1], "fully-down") == 0) + newsrv->init_state= SRV_INIT_STATE_FULLY_DOWN; + else { + memprintf(err, "'%s' expects one of 'fully-up', 'up', 'down', or 'fully-down' but got '%s'", + args[*cur_arg], args[*cur_arg + 1]); + return ERR_ALERT | ERR_FATAL; + } + + return 0; +} + /* Parse the "log-bufsize" server keyword */ static int srv_parse_log_bufsize(char **args, int *cur_arg, struct proxy *curproxy, struct server *newsrv, char **err) @@ -2302,6 +2323,7 @@ static struct srv_kw_list srv_kws = { "ALL", { }, { { "hash-key", srv_parse_hash_key, 1, 1, 1 }, /* Configure how chash keys are computed */ { "id", srv_parse_id, 1, 0, 1 }, /* set id# of server */ { "init-addr", srv_parse_init_addr, 1, 1, 0 }, /* */ + { "init-state", srv_parse_init_state, 1, 1, 0 }, /* Set the initial state of the server */ { "log-bufsize", srv_parse_log_bufsize, 1, 1, 0 }, /* Set the ring bufsize for log server (only for log backends) */ { "log-proto", srv_parse_log_proto, 1, 1, 0 }, /* Set the protocol for event messages, only relevant in a log or ring section */ { "maxconn", srv_parse_maxconn, 1, 1, 1 }, /* Set the max number of concurrent connection */ @@ -2713,6 +2735,8 @@ void srv_settings_init(struct server *srv) srv->agent.fall = DEF_AGENT_FALLTIME; srv->agent.port = 0; + srv->init_state = SRV_INIT_STATE_UP; + srv->maxqueue = 0; srv->minconn = 0; srv->maxconn = 0; @@ -2842,6 +2866,8 @@ void srv_settings_cpy(struct server *srv, const struct server *src, int srv_tmpl srv->init_addr_methods = src->init_addr_methods; srv->init_addr = src->init_addr; + + srv->init_state = src->init_state; #if defined(USE_OPENSSL) srv_ssl_settings_cpy(srv, src); #endif @@ -6504,7 +6530,17 @@ static int _srv_update_status_adm(struct server *s, enum srv_adm_st_chg_cause ca */ if (s->check.state & CHK_ST_ENABLED) { s->check.state &= ~CHK_ST_PAUSED; - s->check.health = s->check.rise; /* start OK but check immediately */ + if(s->init_state == SRV_INIT_STATE_FULLY_UP) { + s->check.health = s->check.rise + s->check.fall - 1; /* initially UP, when all checks fail to bring server DOWN */ + } + else if(s->init_state == SRV_INIT_STATE_DOWN) { + s->check.health = s->check.rise - 1; /* initially DOWN, when one check is successful bring server UP */ + } + else if(s->init_state == SRV_INIT_STATE_FULLY_DOWN) { + s->check.health = 0; /* initially DOWN, when all checks are successful bring server UP */ + } else { + s->check.health = s->check.rise; /* initially UP, when one check fails check brings server DOWN */ + } } if ((!s->track || s->track->next_state != SRV_ST_STOPPED) &&