]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MINOR] checks: add the server's status in the checks
authorWilly Tarreau <w@1wt.eu>
Wed, 27 Jan 2010 10:53:01 +0000 (11:53 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 27 Jan 2010 19:16:12 +0000 (20:16 +0100)
Now a server can check the contents of the header X-Haproxy-Server-State
to know how haproxy sees it. The same values as those reported in the stats
are provided :
  - up/down status + check counts
  - throttle
  - weight vs backend weight
  - active sessions vs backend sessions
  - queue length
  - haproxy node name

doc/configuration.txt
include/types/proxy.h
src/cfgparse.c
src/checks.c

index 40ba6b58b9181eca715ee90d5c37ac6ba74045d8..b77156d5813925300fd74c60bce88d1e5b3a9ad1 100644 (file)
@@ -1936,6 +1936,49 @@ http-check disable-on-404
   See also : "option httpchk"
 
 
+http-check send-state
+  Enable emission of a state header with HTTP health checks
+  May be used in sections :   defaults | frontend | listen | backend
+                                 yes   |    no    |   yes  |   yes
+  Arguments : none
+
+  When this option is set, haproxy will systematically send a special header
+  "X-Haproxy-Server-State" with a list of parameters indicating to each server
+  how they are seen by haproxy. This can be used for instance when a server is
+  manipulated without access to haproxy and the operator needs to know whether
+  haproxy still sees it up or not, or if the server is the last one in a farm.
+
+  The header is composed of fields delimited by semi-colons, the first of which
+  is a word ("UP", "DOWN", "NOLB"), possibly followed by a number of valid
+  checks on the total number before transition, just as appears in the stats
+  interface. Next headers are in the form "<variable>=<value>", indicating in
+  no specific order some values available in the stats interface :
+    - a variable "name", containing the name of the backend followed by a slash
+      ("/") then the name of the server. This can be used when a server is
+      checked in multiple backends.
+
+    - a variable "node" containing the name of the haproxy node, as set in the
+      global "node" variable, otherwise the system's hostname if unspecified.
+
+    - a variable "weight" indicating the weight of the server, a slash ("/")
+      and the total weight of the farm (just counting usable servers). This
+      helps to know if other servers are available to handle the load when this
+      one fails.
+
+    - a variable "scur" indicating the current number of concurrent connections
+      on the server, followed by a slash ("/") then the total number of
+      connections on all servers of the same backend.
+
+    - a variable "qcur" indicating the current number of requests in the
+      server's queue.
+
+  Example of a header received by the application server :
+    >>>  X-Haproxy-Server-State: UP 2/3; name=bck/srv2; node=lb1; weight=1/2; \
+           scur=13/22; qcur=0
+
+  See also : "option httpchk", "http-check disable-on-404"
+
+
 id <value>
   Set a persistent ID to a proxy.
   May be used in sections :   defaults | frontend | listen | backend
index 0571f1747760bed4d46bb894770bc1bcdfd89d0f..bdb42b90431e6c08cc811544a890bd355c636fd6 100644 (file)
 
 #define PR_O2_MYSQL_CHK 0x00020000      /* use MYSQL check for server health */
 #define PR_O2_USE_PXHDR 0x00040000      /* use Proxy-Connection for proxy requests */
+#define PR_O2_CHK_SNDST 0x00080000      /* send the state of each server along with HTTP health checks */
 /* end of proxy->options2 */
 
 /* bits for sticking rules */
index 587a020dfb730c3388ae3d003429849e4e6dac2f..ef7725410d2a3fa222c9bb51c43dfb482006cf4a 100644 (file)
@@ -2757,6 +2757,10 @@ stats_error_parsing:
                        /* enable a graceful server shutdown on an HTTP 404 response */
                        curproxy->options |= PR_O_DISABLE404;
                }
+               else if (strcmp(args[1], "send-state") == 0) {
+                       /* enable emission of the apparent state of a server in HTTP checks */
+                       curproxy->options2 |= PR_O2_CHK_SNDST;
+               }
                else {
                        Alert("parsing [%s:%d] : '%s' only supports 'disable-on-404'.\n", file, linenum, args[0]);
                        err_code |= ERR_ALERT | ERR_FATAL;
@@ -4676,6 +4680,13 @@ int check_config_validity()
                        err_code |= ERR_WARN;
                }
 
+               if ((curproxy->options2 & PR_O2_CHK_SNDST) && !(curproxy->options & PR_O_HTTP_CHK)) {
+                       curproxy->options &= ~PR_O2_CHK_SNDST;
+                       Warning("config : '%s' will be ignored for %s '%s' (requires 'option httpchk').\n",
+                               "send-state", proxy_type_str(curproxy), curproxy->id);
+                       err_code |= ERR_WARN;
+               }
+
                /* if a default backend was specified, let's find it */
                if (curproxy->defbe.name) {
                        struct proxy *target;
@@ -5045,7 +5056,7 @@ int check_config_validity()
                                if (curproxy != px &&
                                        (curproxy->options & PR_O_DISABLE404) != (px->options & PR_O_DISABLE404)) {
                                        Alert("config : %s '%s', server '%s': unable to use %s/%s for"
-                                               "tracing: disable-on-404 option inconsistency.\n",
+                                               "tracking: disable-on-404 option inconsistency.\n",
                                                proxy_type_str(curproxy), curproxy->id,
                                                newsrv->id, px->id, srv->id);
                                        cfgerr++;
index 3f6fa901bea51683777c7a113eaf9d6b58715af9..f59fbbe89ea7df5868d9466fc144da9ee54273e8 100644 (file)
@@ -629,6 +629,62 @@ void health_adjust(struct server *s, short status) {
        }
 }
 
+static int httpchk_build_status_header(struct server *s, char *buffer)
+{
+       int sv_state;
+       int ratio;
+       int hlen = 0;
+       const char *srv_hlt_st[7] = { "DOWN", "DOWN %d/%d",
+                                     "UP %d/%d", "UP",
+                                     "NOLB %d/%d", "NOLB",
+                                     "no check" };
+
+       memcpy(buffer + hlen, "X-Haproxy-Server-State: ", 24);
+       hlen += 24;
+
+       if (!(s->state & SRV_CHECKED))
+               sv_state = 6; /* should obviously never happen */
+       else if (s->state & SRV_RUNNING) {
+               if (s->health == s->rise + s->fall - 1)
+                       sv_state = 3; /* UP */
+               else
+                       sv_state = 2; /* going down */
+
+               if (s->state & SRV_GOINGDOWN)
+                       sv_state += 2;
+       } else {
+               if (s->health)
+                       sv_state = 1; /* going up */
+               else
+                       sv_state = 0; /* DOWN */
+       }
+
+       hlen += sprintf(buffer + hlen,
+                            srv_hlt_st[sv_state],
+                            (s->state & SRV_RUNNING) ? (s->health - s->rise + 1) : (s->health),
+                            (s->state & SRV_RUNNING) ? (s->fall) : (s->rise));
+
+       hlen += sprintf(buffer + hlen, "; name=%s/%s; node=%s; weight=%d/%d; scur=%d/%d; qcur=%d",
+                            s->proxy->id, s->id,
+                            global.node,
+                            (s->eweight * s->proxy->lbprm.wmult + s->proxy->lbprm.wdiv - 1) / s->proxy->lbprm.wdiv,
+                            (s->proxy->lbprm.tot_weight * s->proxy->lbprm.wmult + s->proxy->lbprm.wdiv - 1) / s->proxy->lbprm.wdiv,
+                            s->cur_sess, s->proxy->beconn - s->proxy->nbpend,
+                            s->nbpend);
+
+       if ((s->state & SRV_WARMINGUP) &&
+           now.tv_sec < s->last_change + s->slowstart &&
+           now.tv_sec >= s->last_change) {
+               ratio = MAX(1, 100 * (now.tv_sec - s->last_change) / s->slowstart);
+               hlen += sprintf(buffer + hlen, "; throttle=%d%%", ratio);
+       }
+
+       buffer[hlen++] = '\r';
+       buffer[hlen++] = '\n';
+
+       return hlen;
+}
+
 /*
  * This function is used only for server health-checks. It handles
  * the connection acknowledgement. If the proxy requires L7 health-checks,
@@ -678,6 +734,10 @@ static int event_srv_chk_w(int fd)
                        }
                        else if (s->proxy->options & PR_O_HTTP_CHK) {
                                memcpy(trash, check_req, check_len);
+
+                               if (s->proxy->options2 & PR_O2_CHK_SNDST)
+                                       check_len += httpchk_build_status_header(s, trash + check_len);
+
                                trash[check_len++] = '\r';
                                trash[check_len++] = '\n';
                                trash[check_len] = '\0';