Allow agent checks to obtain information in
an HTTP header of the response to an http check.

Signed-off-by: Simon Horman <ho...@verge.net.au>
---
 doc/configuration.txt |   24 ++++++++++++++++--
 include/types/proxy.h |    2 ++
 src/cfgparse.c        |   38 +++++++++++++++++++++++------
 src/checks.c          |   65 ++++++++++++++++++++++++++++++++++++++++++++++---
 4 files changed, 116 insertions(+), 13 deletions(-)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index 344794e..87e0c5f 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -1124,6 +1124,7 @@ force-persist                             -          X    
     X         X
 fullconn                                  X          -         X         X
 grace                                     X          X         X         X
 hash-type                                 X          -         X         X
+http-check agent-hdr                      X          -         X         X
 http-check disable-on-404                 X          -         X         X
 http-check expect                         -          -         X         X
 http-check send-state                     X          -         X         X
@@ -2489,6 +2490,24 @@ hash-type <method>
   See also : "balance", "server"
 
 
+http-check agent-hdr
+  Use the value of the given http header as the result of an agent check
+  May be used in sections :   defaults | frontend | listen | backend
+                                 yes   |    no    |   yes  |   yes
+  Arguments :
+
+    <header>  The header string to use to send the server name
+
+  When this option is set an http check is enhanced to read the value
+  of the given header in the response to an http check and interpret
+  it as the result of an agent check. In this way an http and agent check
+  may be performed simultaneously.
+
+  This option is overridden by the agent-port parameter.
+
+  See also : "option lb-agent-chk", "agent-port"
+
+
 http-check disable-on-404
   Enable a maintenance mode upon HTTP/404 response to health-checks
   May be used in sections :   defaults | frontend | listen | backend
@@ -7422,10 +7441,11 @@ agent-port <port>
 
   In this the agent check is run in conjunction with another check
   and as such the check backend should be set to some value other than
-  "lb-agent-check". An alternative scenario is to run only an agent check
+  "lb-agent-check". A second scenario is to run only an agent check
   in which case the check backend should be set to "lb-agent-check" and
   "agent-port" should not be set; in that scenario the port may be set
-  using the "port" parameter.
+  using the "port" parameter. A third scenario is to use "http-check
+  agent-hdr" to run an agent and http checks simultaneously over HTTP.
 
   See also the "agent-inter" parameter.
 
diff --git a/include/types/proxy.h b/include/types/proxy.h
index 87e90ee..9ee1f85 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -327,6 +327,7 @@ struct proxy {
        int check_len;                          /* Length of the HTTP or SSL3 
request */
        char *expect_str;                       /* http-check expected content 
: string or text version of the regex */
        regex_t *expect_regex;                  /* http-check expected content 
*/
+       const char *agent_http_header;          /* http-check header to use for 
agent checks */
        struct chunk errmsg[HTTP_ERR_SIZE];     /* default or customized error 
messages for known errors */
        int uuid;                               /* universally unique proxy ID, 
used for SNMP */
        unsigned int backlog;                   /* force the frontend's listen 
backlog */
@@ -353,6 +354,7 @@ struct proxy {
        } conf;                                 /* config information */
        void *parent;                           /* parent of the proxy when 
applicable */
        struct comp *comp;                      /* http compression */
+
 };
 
 struct switching_rule {
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 37d35ec..12b3248 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -1631,7 +1631,7 @@ out:
        return err_code;
 }
 
-static int init_check(struct server *s, const char *name, struct check *check, 
const char * file, int linenum)
+static int init_check(struct server *s, struct check *check, const char * 
file, int linenum)
 {
        /* Allocate buffer for requests... */
        if ((check->bi = calloc(sizeof(struct buffer) + global.tune.chksize, 
sizeof(char))) == NULL) {
@@ -1654,9 +1654,7 @@ static int init_check(struct server *s, const char *name, 
struct check *check, c
        }
 
        check->conn->t.sock.fd = -1; /* no agent in progress yet */
-       check->status = HCHK_STATUS_INI;
        check->server = s;
-       check->name = name;
 
        return 0;
 }
@@ -3809,7 +3807,25 @@ stats_error_parsing:
                if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], 
NULL))
                        err_code |= ERR_WARN;
 
-               if (strcmp(args[1], "disable-on-404") == 0) {
+               if (strcmp(args[1], "agent-hdr") == 0) {
+                       int cur_arg;
+
+                       if (curproxy->agent_http_header) {
+                               Alert("parsing [%s:%d] : '%s %s' already 
specified.\n", file, linenum, args[0], args[1]);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto out;
+                       }
+
+                       cur_arg = 2;
+                       if (!*(args[cur_arg ])) {
+                               Alert("parsing [%s:%d] : '%s %s' expects 
<string> as an argument.\n",
+                                     file, linenum, args[0], args[1]);
+                               err_code |= ERR_ALERT | ERR_FATAL;
+                               goto out;
+                       }
+                       curproxy->agent_http_header = strdup(args[cur_arg]);
+               }
+               else if (strcmp(args[1], "disable-on-404") == 0) {
                        /* enable a graceful server shutdown on an HTTP 404 
response */
                        curproxy->options |= PR_O_DISABLE404;
                }
@@ -4189,8 +4205,14 @@ stats_error_parsing:
                        newsrv->uweight = newsrv->iweight
                                                = curproxy->defsrv.iweight;
 
-                       newsrv->check.health = newsrv->rise;    /* up, but will 
fall down at first failure */
-                       newsrv->agent.health = newsrv->rise;    /* up, but will 
fall down at first failure */
+                       newsrv->check.health    = newsrv->rise; /* up, but will 
fall down at first failure */
+                       newsrv->check.status    = HCHK_STATUS_INI;
+                       newsrv->check.name      = "Health";
+                       newsrv->check.server    = newsrv;
+                       newsrv->agent.health    = newsrv->rise; /* up, but will 
fall down at first failure */
+                       newsrv->agent.status    = HCHK_STATUS_INI;
+                       newsrv->agent.name      = "Agent";
+                       newsrv->agent.server    = newsrv;
 
                        cur_arg = 3;
                } else {
@@ -4792,7 +4814,7 @@ stats_error_parsing:
                                goto out;
                        }
 
-                       ret = init_check(newsrv, "Health", &newsrv->check, 
file, linenum);
+                       ret = init_check(newsrv, &newsrv->check, file, linenum);
                        if (ret) {
                                err_code |= ret;
                                goto out;
@@ -4821,7 +4843,7 @@ stats_error_parsing:
                        if (!newsrv->agent.inter)
                                newsrv->agent.inter = newsrv->check.inter;
 
-                       ret = init_check(newsrv, "Agent", &newsrv->agent, file, 
linenum);
+                       ret = init_check(newsrv, &newsrv->agent, file, linenum);
                        if (ret) {
                                err_code |= ret;
                                goto out;
diff --git a/src/checks.c b/src/checks.c
index 17d0321..872d075 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -1307,6 +1307,34 @@ static struct task *server_warmup(struct task *t)
        return t;
 }
 
+static void process_result(struct check *check)
+{
+       struct server *s = check->server;
+
+       if (check->result & SRV_CHK_FAILED) {    /* a failure or timeout 
detected */
+               if (check->health > s->rise) {
+                       check->health--; /* still good */
+                       s->counters.failed_checks++;
+               }
+               else
+                       set_server_down(check);
+       }
+       else {  /* check was OK */
+       /* we may have to add/remove this server from the LB group */
+               if ((s->state & SRV_RUNNING) && (s->proxy->options & 
PR_O_DISABLE404)) {
+                       if ((s->state & SRV_GOINGDOWN) && !(check->result & 
SRV_CHK_DISABLE))
+                               set_server_enabled(s);
+                       else if (!(s->state & SRV_GOINGDOWN) && (check->result 
& SRV_CHK_DISABLE))
+                               set_server_disabled(check);
+               }
+
+               if (check->health < s->rise + s->fall - 1) {
+                       check->health++; /* was bad, stays for a while */
+                       set_server_up(check);
+               }
+       }
+}
+
 /*
  * manages a server health-check. Returns
  * the time the task accepts to wait, or TIME_ETERNITY for infinity.
@@ -1485,6 +1513,17 @@ static struct task *process_chk(struct task *t)
                }
 
                /* check complete or aborted */
+               process_result(check);
+
+               /* The agent check may run without a task if
+                * it is performed as aprt of the primary health check.
+                * If so process its result, here, while processing
+                * the primary health check.
+                */
+               if (!check->server->agent.task &&
+                   check->server->agent.state != HCHK_STATUS_INI) {
+                       process_result(&check->server->agent);
+               }
 
                if (check->result & SRV_CHK_FAILED) {    /* a failure or 
timeout detected */
                        if (check->health > s->rise) {
@@ -1702,9 +1741,22 @@ static int httpchk_expect(struct server *s, int done)
 {
        static char status_msg[] = "HTTP status check returned code <000>";
        char status_code[] = "000";
-       char *contentptr;
+       char *contentptr = NULL, *agent_value = NULL;
        int ret;
 
+       if (s->proxy->agent_http_header) {
+               httpchk_parse_header(s, s->proxy->agent_http_header, 
&agent_value);
+
+               if (!agent_value || !strchr(agent_value, '\n')) {
+                       /* if we don't match, we may need to wait more */
+                       if (!done)
+                               return 0;
+                       set_server_check_status(&s->agent, HCHK_STATUS_L7RSP,
+                                               "HTTP check did not match 
agent-hdr");
+                       agent_value = NULL;
+               }
+       }
+
        switch (s->proxy->options2 & PR_O2_EXP_TYPE) {
        case PR_O2_EXP_STS:
        case PR_O2_EXP_RSTS:
@@ -1725,7 +1777,8 @@ static int httpchk_expect(struct server *s, int done)
 
        case PR_O2_EXP_STR:
        case PR_O2_EXP_RSTR:
-               contentptr = httpchk_parse_header(s, NULL, NULL);
+               if (!contentptr)
+                       contentptr = httpchk_parse_header(s, 
s->proxy->agent_http_header, &agent_value);
 
                /* Check that response contains a body... */
                if (*contentptr == '\0') {
@@ -1733,7 +1786,7 @@ static int httpchk_expect(struct server *s, int done)
                                return 0;
 
                        set_server_check_status(&s->check, HCHK_STATUS_L7RSP, 
"HTTP content check could not find a response body or an empty response body 
was found");
-                       return 1;
+                       goto agent;
                }
 
                /* Check the response content against the supplied string
@@ -1766,6 +1819,12 @@ static int httpchk_expect(struct server *s, int done)
                }
                break;
        }
+
+agent:
+       if (s->proxy->agent_http_header && agent_value) {
+               agent_expect(&s->agent, agent_value);
+       }
+
        return 1;
 }
 
-- 
1.7.10.4


Reply via email to