From 0c39eccdd43e02d0248b9729c4cb8316a9f5fb9a Mon Sep 17 00:00:00 2001 From: Gaetan Rivet Date: Mon, 24 Feb 2020 17:34:11 +0100 Subject: [PATCH] MINOR: checks: Add support to set-var and unset-var rules in tcp-checks Evaluate the registered action_ptr associated with each CHK_ACTION_KW rules from a ruleset. Currently only the 'set-var' and 'unset-var' are parsed by the tcp-check parser. Thus it is now possible to set or unset variables. It is possible to use such rules before the first connect of the ruleset. --- doc/configuration.txt | 53 +++++++++++++++++++++++++++++++++++++++++++ src/checks.c | 33 +++++++++++++++++++++++---- src/vars.c | 1 + 3 files changed, 83 insertions(+), 4 deletions(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index 09f4b669e..40585b815 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -2759,6 +2759,8 @@ tcp-check connect - - X X tcp-check expect - - X X tcp-check send - - X X tcp-check send-binary - - X X +tcp-check set-var - - X X +tcp-check unset-var - - X X tcp-request connection - X X - tcp-request content - X X X tcp-request inspect-delay - X X X @@ -7986,6 +7988,10 @@ option tcp-check in debug mode. It is useful to make user-friendly error reporting. The "comment" is of course optional. + During the execution of a health check, a variable scope is made available + to store data samples, using the "tcp-check set-var" operation. Freeing + those variable is possible using "tcp-check unset-var". + Examples : # perform a POP check (analyze only server's banner) @@ -9805,6 +9811,9 @@ tcp-check connect [params*] the ruleset with a 'connect' rule. Purpose is to ensure admin know what they do. + When a connect must start the ruleset, if may still be preceded by set-var, + unset-var or comment rules. + Parameters : They are optional and can be used to describe how HAProxy should open and use the TCP connection. @@ -9991,6 +10000,50 @@ tcp-check send-binary "tcp-check send", tune.chksize +tcp-check set-var() + + This operation sets the content of a variable. The variable is declared inline. + + May be used in sections: defaults | frontend | listen | backend + no | no | yes | yes + + Arguments: + The name of the variable starts with an indication about its + scope. The scopes allowed for tcp-check are: + "proc" : the variable is shared with the whole process. + "sess" : the variable is shared with the tcp-check session. + "check": the variable is declared for the lifetime of the tcp-check. + This prefix is followed by a name. The separator is a '.'. + The name may only contain characters 'a-z', 'A-Z', '0-9', '.', + and '-'. + + Is a sample-fetch expression potentially followed by converters. + + Example: + tcp-check set-var(check.port) int(1234) + + +tcp-check unset-var() + + Free a reference to a variable within its scope. + + May be used in sections: defaults | frontend | listen | backend + no | no | yes | yes + + Arguments: + The name of the variable starts with an indication about its + scope. The scopes allowed for tcp-check are: + "proc" : the variable is shared with the whole process. + "sess" : the variable is shared with the tcp-check session. + "check": the variable is declared for the lifetime of the tcp-check. + This prefix is followed by a name. The separator is a '.'. + The name may only contain characters 'a-z', 'A-Z', '0-9', '.', + and '-'. + + Example: + tcp-check unset-var(check.port) + + tcp-request connection [{if | unless} ] Perform an action on an incoming connection depending on a layer 4 condition May be used in sections : defaults | frontend | listen | backend diff --git a/src/checks.c b/src/checks.c index 5e147b81f..b9fb4d53a 100644 --- a/src/checks.c +++ b/src/checks.c @@ -3042,8 +3042,7 @@ static enum tcpcheck_eval_ret tcpcheck_eval_send(struct check *check, struct tcp } /* Evaluate a TCPCHK_ACT_EXPECT rule. It returns 1 to evaluate the next rule, 0 - * to wait and -1 to stop the check. is updated to point on the last - * evaluated TCPCHK_ACT_EXPECT rule. + * to wait and -1 to stop the check. */ static enum tcpcheck_eval_ret tcpcheck_eval_expect(struct check *check, struct tcpcheck_rule *rule, int last_read) { @@ -3167,6 +3166,27 @@ static enum tcpcheck_eval_ret tcpcheck_eval_expect(struct check *check, struct t return ret; } +/* Evaluate a TCPCHK_ACT_ACTION_KW rule. It returns 1 to evaluate the next rule, 0 + * to wait and -1 to stop the check. + */ +static enum tcpcheck_eval_ret tcpcheck_eval_action_kw(struct check *check, struct tcpcheck_rule *rule) +{ + enum tcpcheck_eval_ret ret = TCPCHK_EVAL_CONTINUE; + struct act_rule *act_rule; + enum act_return act_ret; + + act_rule =rule->action_kw.rule; + act_ret = act_rule->action_ptr(act_rule, check->proxy, check->sess, NULL, 0); + if (act_ret != ACT_RET_CONT) { + chunk_printf(&trash, "TCPCHK ACTION unexpected result at step %d\n", + tcpcheck_get_step_id(check, rule)); + set_server_check_status(check, HCHK_STATUS_L7RSP, trash.area); + ret = TCPCHK_EVAL_STOP; + } + + return ret; +} + /* proceed with next steps for the TCP checks . Note that this is called * both from the connection's wake() callback and from the check scheduling task. * It returns 0 on normal cases, or <0 if a close() has happened on an existing @@ -3308,12 +3328,17 @@ static int tcpcheck_main(struct check *check) } must_read = 0; } + eval_ret = tcpcheck_eval_expect(check, rule, last_read); if (eval_ret == TCPCHK_EVAL_WAIT) { check->current_step = rule->expect.head; conn->mux->subscribe(cs, SUB_RETRY_RECV, &check->wait_list); } break; + case TCPCHK_ACT_ACTION_KW: + /* Don't update the current step */ + eval_ret = tcpcheck_eval_action_kw(check, rule); + break; default: /* Otherwise, just go to the next one and don't update * the current step @@ -3588,7 +3613,7 @@ static int add_tcpcheck_expect_str(struct list *list, const char *str) tcpcheck->expect.head = prev_check; continue; } - if (prev_check->action != TCPCHK_ACT_COMMENT) + if (prev_check->action != TCPCHK_ACT_COMMENT && prev_check->action != TCPCHK_ACT_ACTION_KW) break; } LIST_ADDQ(list, &tcpcheck->list); @@ -4368,7 +4393,7 @@ static struct tcpcheck_rule *parse_tcpcheck_expect(char **args, int cur_arg, str chk->expect.head = prev_check; continue; } - if (prev_check->action != TCPCHK_ACT_COMMENT) + if (prev_check->action != TCPCHK_ACT_COMMENT && prev_check->action != TCPCHK_ACT_ACTION_KW) break; } return chk; diff --git a/src/vars.c b/src/vars.c index 7f3d2d0cf..0fa3397c7 100644 --- a/src/vars.c +++ b/src/vars.c @@ -671,6 +671,7 @@ static enum act_return action_store(struct act_rule *rule, struct proxy *px, case ACT_F_TCP_RES_CNT: dir = SMP_OPT_DIR_RES; break; case ACT_F_HTTP_REQ: dir = SMP_OPT_DIR_REQ; break; case ACT_F_HTTP_RES: dir = SMP_OPT_DIR_RES; break; + case ACT_F_TCP_CHK: dir = SMP_OPT_DIR_REQ; break; default: send_log(px, LOG_ERR, "Vars: internal error while execute action store."); if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))