Support a dynamic health check performed by opening a TCP socket to a
pre-defined port and reading an ascii string. The string should have one of
the following forms:

i. An ascii representation of an positive integer percentage.
   e.g. "75%"

   Values in this format will set the wight proportional to the initial
   weight of a server as configured when haproxy starts.

ii. The string "drain".

   This will cause the weight of a server to be set to 0, and thus it will
   not accept any new connections other than those that are accepted via
   persistence.

ii. The string "disable".

   Put the server into maintenance mode. The server must be re-enabled
   before any further health checks will be performed.

A dynmaic helath check may be configued using "option dynamic-chk".
The use of an alternate check-port, used to obtain dynamic heath check
information described above as opposed to the port of the service,
may be useful in conjunction with this option.

e.g.

    option  dynamic-chk
    server  http1_1 10.0.0.10:80 check port 10000 weight 100

Signed-off-by: Simon Horman <[email protected]>
---
 include/types/peers.h |    1 +
 include/types/proxy.h |    3 ++-
 src/cfgparse.c        |    7 +++++++
 src/checks.c          |   28 ++++++++++++++++++++++++++++
 src/dumpstats.c       |    2 +-
 5 files changed, 39 insertions(+), 2 deletions(-)

diff --git a/include/types/peers.h b/include/types/peers.h
index d52dc8c..41a1cce 100644
--- a/include/types/peers.h
+++ b/include/types/peers.h
@@ -72,6 +72,7 @@ struct peer {
                int line;         /* line where the section appears */
        } conf;                   /* config information */
        time_t last_change;
+       time_t last_slowstart_change;
        struct sockaddr_storage addr;  /* peer address */
        struct protocol *proto;        /* peer address protocol */
        struct xprt_ops *xprt;         /* peer socket operations at transport 
layer */
diff --git a/include/types/proxy.h b/include/types/proxy.h
index ceb14d1..db3e01f 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -151,7 +151,8 @@ enum {
 #define PR_O2_MYSQL_CHK 0x50000000      /* use MYSQL check for server health */
 #define PR_O2_LDAP_CHK  0x60000000      /* use LDAP check for server health */
 #define PR_O2_SSL3_CHK  0x70000000      /* use SSLv3 CLIENT_HELLO packets for 
server health */
-/* unused: 0x80000000 to 0xF000000, reserved for health checks */
+#define PR_O2_FEEDBACK_CHK 0x80000000   /* use a TCP connection to obtain a 
metric of server health */
+/* unused: 0x90000000 to 0xF000000, reserved for health checks */
 #define PR_O2_CHK_ANY   0xF0000000      /* Mask to cover any check */
 /* end of proxy->options2 */
 
diff --git a/src/cfgparse.c b/src/cfgparse.c
index f7dcf06..9526068 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -3577,6 +3577,13 @@ stats_error_parsing:
                                }
                        }
                }
+               else if (!strcmp(args[1], "dynamic-chk")) {
+                       /* use dynmaic health check */
+                       free(curproxy->check_req);
+                       curproxy->check_req = NULL;
+                       curproxy->options2 &= ~PR_O2_CHK_ANY;
+                       curproxy->options2 |= PR_O2_FEEDBACK_CHK;
+               }
                else if (!strcmp(args[1], "pgsql-check")) {
                        /* use PostgreSQL request to check servers' health */
                        if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, 
args[1], NULL))
diff --git a/src/checks.c b/src/checks.c
index 394d29e..e619fa7 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -25,6 +25,7 @@
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <arpa/inet.h>
+#include <stdbool.h>
 
 #include <common/chunk.h>
 #include <common/compat.h>
@@ -37,6 +38,7 @@
 
 #include <proto/backend.h>
 #include <proto/checks.h>
+#include <proto/dumpstats.h>
 #include <proto/fd.h>
 #include <proto/log.h>
 #include <proto/queue.h>
@@ -966,6 +968,32 @@ static void event_srv_chk_r(struct connection *conn)
                        set_server_check_status(s, HCHK_STATUS_L7STS, desc);
                break;
 
+       case PR_O2_FEEDBACK_CHK: {
+               short status = HCHK_STATUS_L7RSP;
+
+               if (!done)
+                       goto wait_more_data;
+
+               cut_crlf(s->check.bi->data);
+
+               if (s->check.bi->i > 0 &&
+                   isdigit((unsigned char) *s->check.bi->data) &&
+                   strchr(s->check.bi->data, '%')) {
+                       if (!process_weight_change_request(s, 
s->check.bi->data))
+                           status = HCHK_STATUS_L7OKD;
+               } else if (!strncasecmp(s->check.bi->data, "drain", 
s->check.bi->i)) {
+                       if (!process_weight_change_request(s, "0%"))
+                           status = HCHK_STATUS_L7OKD;
+               } else if (!strncasecmp(s->check.bi->data, "disable", 
s->check.bi->i)) {
+                       s->state |= SRV_MAINTAIN;
+                       s->health = s->rise;
+                       status = HCHK_STATUS_L7STS;
+               }
+
+               set_server_check_status(s, status, s->check.bi->data);
+               break;
+       }
+
        case PR_O2_PGSQL_CHK:
                if (!done && s->check.bi->i < 9)
                        goto wait_more_data;
diff --git a/src/dumpstats.c b/src/dumpstats.c
index 81d8564..f860f93 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -983,7 +983,7 @@ err:
 
 int process_weight_change_request(struct server *sv, const char *weight_str)
 {
-       stats_sock_parse_weight_change_request(NULL, sv, weight_str);
+       return stats_sock_parse_weight_change_request(NULL, sv, weight_str);
 }
 
 /* Processes the stats interpreter on the statistics socket. This function is
-- 
1.7.10.4


Reply via email to