MAJOR: checks: add support for a new "drain" administrative mode

This patch adds support for a new "drain" mode. So now we have 3 admin
modes for a server :
  - READY
  - DRAIN
  - MAINT

The drain mode disables load balancing but leaves the server up. It can
coexist with maint, except that maint has precedence. It is also inherited
from tracked servers, so just like maint, it's represented with 2 bits.

New functions were designed to set/clear each flag and to propagate the
changes to tracking servers when relevant, and to log the changes. Existing
functions srv_set_adm_maint() and srv_set_adm_ready() were replaced to make
use of the new functions.

Currently the drain mode is not yet used, however the whole logic was tested
with all combinations of set/clear of both flags in various orders to catch
all corner cases.
diff --git a/include/proto/backend.h b/include/proto/backend.h
index 901d9f4..56df516 100644
--- a/include/proto/backend.h
+++ b/include/proto/backend.h
@@ -63,6 +63,8 @@
 		return 0;
 	if (srv->admin & SRV_ADMF_MAINT)
 		return 0;
+	if (srv->admin & SRV_ADMF_DRAIN)
+		return 0;
 	switch (state) {
 	case SRV_ST_STARTING:
 	case SRV_ST_RUNNING:
@@ -85,6 +87,8 @@
 		return 0;
 	if (srv->prev_admin & SRV_ADMF_MAINT)
 		return 0;
+	if (srv->prev_admin & SRV_ADMF_DRAIN)
+		return 0;
 	switch (state) {
 	case SRV_ST_STARTING:
 	case SRV_ST_RUNNING:
diff --git a/include/proto/server.h b/include/proto/server.h
index aae1bd7..9893266 100644
--- a/include/proto/server.h
+++ b/include/proto/server.h
@@ -101,7 +101,7 @@
  */
 static inline int server_is_draining(const struct server *s)
 {
-	return !s->uweight;
+	return !s->uweight || (s->admin & SRV_ADMF_DRAIN);
 }
 
 /* Shutdown all connections of a server. The caller must pass a termination
@@ -156,24 +156,49 @@
  */
 void srv_set_stopping(struct server *s, const char *reason);
 
+/* Enables admin flag <mode> (among SRV_ADMF_*) on server <s>. This is used to
+ * enforce either maint mode or drain mode. It is not allowed to set more than
+ * one flag at once. The equivalent "inherited" flag is propagated to all
+ * tracking servers. Maintenance mode disables health checks (but not agent
+ * checks). When either the flag is already set or no flag is passed, nothing
+ * is done.
+ */
+void srv_set_admin_flag(struct server *s, enum srv_admin mode);
+
+/* Disables admin flag <mode> (among SRV_ADMF_*) on server <s>. This is used to
+ * stop enforcing either maint mode or drain mode. It is not allowed to set more
+ * than one flag at once. The equivalent "inherited" flag is propagated to all
+ * tracking servers. Leaving maintenance mode re-enables health checks. When
+ * either the flag is already cleared or no flag is passed, nothing is done.
+ */
+void srv_clr_admin_flag(struct server *s, enum srv_admin mode);
+
 /* Puts server <s> into maintenance mode, and propagate that status down to all
- * tracking servers. This does the same action as the CLI's "disable server x".
- * A log is emitted for all servers that were not yet in maintenance mode.
- * Health checks are disabled but not agent checks. The server is marked as
- * being either forced into maintenance by having <mode> set to SRV_ADMF_FMAINT,
- * or as inheriting the maintenance status by having <mode> set to
- * SRV_ADMF_IMAINT. Nothing is done if neither flag is set.
+ * tracking servers.
  */
-void srv_adm_set_maint(struct server *s, enum srv_admin mode);
+static inline void srv_adm_set_maint(struct server *s)
+{
+	srv_set_admin_flag(s, SRV_ADMF_FMAINT);
+	srv_clr_admin_flag(s, SRV_ADMF_FDRAIN);
+}
 
-/* Gets server <s> out of maintenance mode, and propagate that status down to
- * all tracking servers. This does the same action as the CLI's "enable server x".
- * A log is emitted for all servers that leave maintenance mode. Health checks
- * are possibly enabled again. The server is marked as leaving forced maintenance
- * when <mode> is set to SRV_ADMF_FMAINT, or as leaving inherited maintenance
- * when <mode> set to SRV_ADMF_IMAINT. Nothing is done if neither flag is set.
+/* Puts server <s> into drain mode, and propagate that status down to all
+ * tracking servers.
  */
-void srv_adm_set_ready(struct server *s, enum srv_admin mode);
+static inline void srv_adm_set_drain(struct server *s)
+{
+	srv_set_admin_flag(s, SRV_ADMF_FDRAIN);
+	srv_clr_admin_flag(s, SRV_ADMF_FMAINT);
+}
+
+/* Puts server <s> into ready mode, and propagate that status down to all
+ * tracking servers.
+ */
+static inline void srv_adm_set_ready(struct server *s)
+{
+	srv_clr_admin_flag(s, SRV_ADMF_FDRAIN);
+	srv_clr_admin_flag(s, SRV_ADMF_FMAINT);
+}
 
 /*
  * Local variables: