]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: checks: Add status-code sample expression on tcp-check expect rules
authorChristopher Faulet <cfaulet@haproxy.com>
Wed, 1 Apr 2020 18:52:31 +0000 (20:52 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Mon, 27 Apr 2020 07:39:37 +0000 (09:39 +0200)
This option defines a sample expression, evaluated as an integer, to set the
status code (check->code) if a tcp-check healthcheck ends on the corresponding
expect rule.

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

index ee1ef187bdbdc792dd93f1c2b74b6783ccb83e44..e6373584dc44a4b6894cebdbb57e707e88438a29 100644 (file)
@@ -9873,7 +9873,7 @@ tcp-check connect [params*]
 
 
 tcp-check expect [min-recv <int>] [error-status <st>] [tout-status <st>]
-                 [on-success <fmt>] [on-error <fmt>]
+                 [on-success <fmt>] [on-error <fmt>] [status-code <expr>]
                  [!] <match> <pattern>
   Specify data to be collected and analyzed during a generic health check
   May be used in sections:   defaults | frontend | listen | backend
@@ -9922,6 +9922,11 @@ tcp-check expect [min-recv <int>] [error-status <st>] [tout-status <st>]
                        occurred during the expect rule evaluation. <fmt> is a
                        log-format string.
 
+    status-code <expr> is optional and can be used to set the check status code
+                       reported in logs, on success or on error. <expr> is a
+                       standard HAProxy expression formed by a sample-fetch
+                       followed by some converters.
+
     <pattern> is the pattern to look for. It may be a string or a regular
               expression. If the pattern contains spaces, they must be escaped
               with the usual backslash ('\').
index 0d479e354b70e7c9d94aa8cb768ed067348fd613..3c44d82aaa0f758b9241f325427f0b82ebb69fa0 100644 (file)
@@ -268,6 +268,7 @@ struct tcpcheck_expect {
        struct list onsuccess_fmt;      /* log-format string to use as comment on success (if last rule) */
        enum healthcheck_status err_status;  /* The healthcheck status to use on error (default: L7RSP) */
        enum healthcheck_status tout_status; /* The healthcheck status to use on timeout (default: L7TOUT) */
+       struct sample_expr *status_expr; /* sample expr to determine the check status code */
 };
 
 struct tcpcheck_action_kw {
index 01fc2c307c03e98c863755e6dcc77401c8f4aed6..55307b5b3174d285beec26fe01eaa017e0b09beb 100644 (file)
@@ -3187,6 +3187,16 @@ static enum tcpcheck_eval_ret tcpcheck_eval_expect(struct check *check, struct t
                        chunk_appendf(msg, " comment: '%s'", rule->comment);
        }
 
+       if (expect->status_expr) {
+               struct sample *smp;
+
+               smp = sample_fetch_as_type(check->proxy, check->sess, NULL,
+                                          SMP_OPT_DIR_RES | SMP_OPT_FINAL,
+                                          expect->status_expr, SMP_T_SINT);
+               if (smp)
+                       check->code = smp->data.u.sint;
+       }
+
   no_desc:
        set_server_check_status(check, expect->err_status, (msg ? b_head(msg) : NULL));
        ret = TCPCHK_EVAL_STOP;
@@ -3386,12 +3396,23 @@ static int tcpcheck_main(struct check *check)
        }
 
        /* All rules was evaluated */
-       if (check->current_step && check->current_step->action == TCPCHK_ACT_EXPECT &&
-           !LIST_ISEMPTY(&check->current_step->expect.onsuccess_fmt)) {
-               msg = alloc_trash_chunk();
-               if (msg)
-                       msg->data += sess_build_logline(check->sess, NULL, b_tail(msg), b_room(msg),
-                                                       &check->current_step->expect.onsuccess_fmt);
+       if (check->current_step && check->current_step->action == TCPCHK_ACT_EXPECT) {
+               if (!LIST_ISEMPTY(&check->current_step->expect.onsuccess_fmt)) {
+                       msg = alloc_trash_chunk();
+                       if (msg)
+                               msg->data += sess_build_logline(check->sess, NULL, b_tail(msg), b_room(msg),
+                                                               &check->current_step->expect.onsuccess_fmt);
+               }
+
+               if (check->current_step->expect.status_expr) {
+                       struct sample *smp;
+
+                       smp = sample_fetch_as_type(check->proxy, check->sess, NULL,
+                                                  SMP_OPT_DIR_RES | SMP_OPT_FINAL,
+                                                  check->current_step->expect.status_expr, SMP_T_SINT);
+                       if (smp)
+                               check->code = smp->data.u.sint;
+               }
        }
 
        set_server_check_status(check, HCHK_STATUS_L7OKD, (msg ? b_head(msg) : "(tcp-check)"));
@@ -3492,6 +3513,7 @@ static void free_tcpcheck(struct tcpcheck_rule *rule, int in_pool)
                        free(lf->arg);
                        free(lf);
                }
+               release_sample_expr(rule->expect.status_expr);
                switch (rule->expect.type) {
                case TCPCHK_EXPECT_STRING:
                case TCPCHK_EXPECT_BINARY:
@@ -4556,6 +4578,7 @@ static struct tcpcheck_rule *parse_tcpcheck_expect(char **args, int cur_arg, str
                                                   const char *file, int line, char **errmsg)
 {
        struct tcpcheck_rule *prev_check, *chk = NULL;
+       struct sample_expr *status_expr = NULL;
        char *str, *on_success_msg, *on_error_msg, *comment, *pattern;
        enum tcpcheck_expect_type type = TCPCHK_EXPECT_UNDEF;
        enum healthcheck_status err_st = HCHK_STATUS_L7RSP;
@@ -4693,6 +4716,36 @@ static struct tcpcheck_rule *parse_tcpcheck_expect(char **args, int cur_arg, str
                        }
                        cur_arg++;
                }
+               else if (strcmp(args[cur_arg], "status-code") == 0) {
+                       int idx = 0;
+
+                       if (in_pattern) {
+                               memprintf(errmsg, "[!] not supported with '%s'", args[cur_arg]);
+                               goto error;
+                       }
+                       if (!*(args[cur_arg+1])) {
+                               memprintf(errmsg, "'%s' expects an expression as argument", args[cur_arg]);
+                               goto error;
+                       }
+
+                       cur_arg++;
+                       release_sample_expr(status_expr);
+                       px->conf.args.ctx = ARGC_SRV;
+                       status_expr = sample_parse_expr((char *[]){args[cur_arg], NULL}, &idx,
+                                                       file, line, errmsg, &px->conf.args, NULL);
+                       if (!status_expr) {
+                               memprintf(errmsg, "error detected while parsing status-code expression : %s", *errmsg);
+                               goto error;
+                       }
+                       if (!(status_expr->fetch->val & SMP_VAL_BE_CHK_RUL)) {
+                               memprintf(errmsg, "error detected while parsing status-code expression : "
+                                         " fetch method '%s' extracts information from '%s', "
+                                         "none of which is available here.\n",
+                                         args[cur_arg], sample_src_names(status_expr->fetch->use));
+                                       goto error;
+                       }
+                       px->http_needed |= !!(status_expr->fetch->use & SMP_USE_HTTP_ANY);
+               }
                else if (strcmp(args[cur_arg], "tout-status") == 0) {
                        if (in_pattern) {
                                memprintf(errmsg, "[!] not supported with '%s'", args[cur_arg]);
@@ -4758,6 +4811,7 @@ static struct tcpcheck_rule *parse_tcpcheck_expect(char **args, int cur_arg, str
        chk->expect.with_capture = with_capture;
        chk->expect.err_status = err_st;
        chk->expect.tout_status = tout_st;
+       chk->expect.status_expr = status_expr; status_expr = NULL;
 
        if (on_success_msg) {
                px->conf.args.ctx = ARGC_SRV;
@@ -4825,6 +4879,7 @@ static struct tcpcheck_rule *parse_tcpcheck_expect(char **args, int cur_arg, str
        free(comment);
        free(on_success_msg);
        free(on_error_msg);
+       release_sample_expr(status_expr);
        return NULL;
 }