Allow the user to set the "initial state" of a server.
Context:
Servers are always set in an UP status by default. In
some cases, further checks are required to determine if the server is
ready to receive client traffic.
This introduces the "init-state {up|down}" configuration parameter to
the server.
- when not set, the server is considered available as soon as a connection
can be established.
- when set to 'up', the server is considered available as soon as a
connection can be established.
- when set to 'down', the server is initially considered unavailable until
it successfully completes its health checks.
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.
Link: https://github.com/haproxy/haproxy/issues/51
---
doc/configuration.txt | 37 +++++++++++++++++++++++++++++++++++++
include/haproxy/server-t.h | 10 ++++++++++
src/server.c | 28 +++++++++++++++++++++++++++-
3 files changed, 74 insertions(+), 1 deletion(-)
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 11d687928..614afaac8 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -17551,6 +17551,43 @@ downinter <delay>
"inter" setting will have a very limited effect as it will not be able to
reduce the time spent in the queue.
+init-state { up| 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 not set, the server is considered available as soon as a connection
+ can be established.
+ - when set to 'up', the server is considered available as soon as a
+ connection can be established.
+ - when set to 'down', the server is considered unavailable until it
+ successfully completes its health checks
+
+ Example:
+ # 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 <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..799d83048 100644
--- a/include/haproxy/server-t.h
+++ b/include/haproxy/server-t.h
@@ -101,6 +101,15 @@ 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_DOWN = 0, /* the server should initially be
considered DOWN. Please keep set to zero. */
+ SRV_INIT_STATE_UP, /* the server shoudl initially be
considered UP */
+} __attribute__((packed));
+
/* server-state-file version */
#define SRV_STATE_FILE_VERSION 1
#define SRV_STATE_FILE_VERSION_MIN 1
@@ -279,6 +288,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..71c4581d0 100644
--- a/src/server.c
+++ b/src/server.c
@@ -1054,6 +1054,23 @@ 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], "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 {
+ memprintf(err, "'%s' expects one of 'up' or '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 +2319,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 +2731,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 +2862,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 +6526,11 @@ 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_DOWN) {
+ s->check.health = 0; /* checks must pass before
the server is considered UP */
+ } else {
+ s->check.health = s->check.rise; /* start OK
but check immediately */
+ }
}
if ((!s->track || s->track->next_state != SRV_ST_STOPPED) &&
--
2.46.0