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>

---

v4
* Do not duplicate code that is in process_result()

v2 - v3
* No change
---
 doc/configuration.txt |   24 ++++++++++++--
 include/types/proxy.h |    2 ++
 src/cfgparse.c        |   20 +++++++++++-
 src/checks.c          |   85 +++++++++++++++++++++++++++++++++++--------------
 4 files changed, 104 insertions(+), 27 deletions(-)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index acb356d..19dc7db 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -1139,6 +1139,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
@@ -2527,6 +2528,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
@@ -7682,10 +7701,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 e6bc755..66e5db7 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -328,6 +328,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 */
@@ -359,6 +360,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 ab309cf..23bbf2b 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -3867,7 +3867,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;
                }
diff --git a/src/checks.c b/src/checks.c
index 249a6ee..5d893f8 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -1306,6 +1306,35 @@ 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);
+               }
+       }
+       check->state &= ~CHK_RUNNING;
+}
+
 /*
  * manages a server health-check. Returns
  * the time the task accepts to wait, or TIME_ETERNITY for infinity.
@@ -1502,29 +1531,17 @@ static struct task *process_chk(struct task *t)
                        conn_full_close(conn);
                }
 
-               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);
-                       }
+               process_result(check);
 
-                       if (check->health < s->rise + s->fall - 1) {
-                               check->health++; /* was bad, stays for a while 
*/
-                               set_server_up(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);
                }
-               check->state &= ~CHK_RUNNING;
 
                rv = 0;
                if (global.spread_checks > 0) {
@@ -1716,9 +1733,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:
@@ -1739,7 +1769,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') {
@@ -1747,7 +1778,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
@@ -1780,6 +1811,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