mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-25 15:03:03 +00:00
MEDIUM: checks: Add on-error/on-success option on tcp-check expect rules
These options define log-format strings used to produce the info message if a tcp-check expect rule fails (on-error option) or succeeds (on-success option). For this last option, it must be the ending rule, otherwise the parameter is ignored.
This commit is contained in:
parent
ba3c68f91b
commit
be52b4de66
@ -9873,6 +9873,7 @@ tcp-check connect [params*]
|
||||
|
||||
|
||||
tcp-check expect [min-recv <int>] [error-status <st>] [tout-status <st>]
|
||||
[on-success <fmt>] [on-error <fmt>]
|
||||
[!] <match> <pattern>
|
||||
Specify data to be collected and analyzed during a generic health check
|
||||
May be used in sections: defaults | frontend | listen | backend
|
||||
@ -9911,6 +9912,16 @@ tcp-check expect [min-recv <int>] [error-status <st>] [tout-status <st>]
|
||||
HCHK_STATUS_L6TOUT or HCHK_STATUS_L4TOUT timeout status.
|
||||
By default "L7TOUT" is used.
|
||||
|
||||
on-success <fmt> is optional and can be used to customize the
|
||||
informational message reported in logs if the expect
|
||||
rule is successfully evaluated and if it is the last rule
|
||||
in the tcp-check ruleset. <fmt> is a log-format string.
|
||||
|
||||
on-error <fmt> is optional and can be used to customize the
|
||||
informational message reported in logs if an error
|
||||
occurred during the expect rule evaluation. <fmt> is a
|
||||
log-format string.
|
||||
|
||||
<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 ('\').
|
||||
|
@ -264,6 +264,8 @@ struct tcpcheck_expect {
|
||||
int inverse; /* Match is inversed. */
|
||||
int with_capture; /* Match will store captured groups for back-reference in comment. */
|
||||
int min_recv; /* Minimum amount of data before an expect can be applied. (default: -1, ignored) */
|
||||
struct list onerror_fmt; /* log-format string to use as comment on error */
|
||||
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) */
|
||||
};
|
||||
|
131
src/checks.c
131
src/checks.c
@ -3073,7 +3073,7 @@ static enum tcpcheck_eval_ret tcpcheck_eval_expect(struct check *check, struct t
|
||||
{
|
||||
enum tcpcheck_eval_ret ret = TCPCHK_EVAL_CONTINUE;
|
||||
struct tcpcheck_expect *expect = &check->current_step->expect;
|
||||
char *diag;
|
||||
struct buffer *msg = NULL;
|
||||
int match;
|
||||
|
||||
/* The current expect might need more data than the previous one, check again
|
||||
@ -3138,24 +3138,23 @@ static enum tcpcheck_eval_ret tcpcheck_eval_expect(struct check *check, struct t
|
||||
|
||||
/* From this point on, we matched something we did not want, this is an error state. */
|
||||
ret = TCPCHK_EVAL_STOP;
|
||||
msg = alloc_trash_chunk();
|
||||
if (!msg)
|
||||
goto no_desc;
|
||||
|
||||
diag = match ? "matched unwanted content" : "did not match content";
|
||||
chunk_strcat(msg, (match ? "TCPCHK matched unwanted content" : "TCPCHK did not match content"));
|
||||
switch (expect->type) {
|
||||
case TCPCHK_EXPECT_STRING:
|
||||
chunk_printf(&trash, "TCPCHK %s '%s' at step %d",
|
||||
diag, expect->string, tcpcheck_get_step_id(check, rule));
|
||||
chunk_appendf(msg, " '%s' at step %d", expect->string, tcpcheck_get_step_id(check, rule));
|
||||
break;
|
||||
case TCPCHK_EXPECT_BINARY:
|
||||
chunk_printf(&trash, "TCPCHK %s (binary) at step %d",
|
||||
diag, tcpcheck_get_step_id(check, rule));
|
||||
chunk_appendf(msg, " (binary) at step %d", tcpcheck_get_step_id(check, rule));
|
||||
break;
|
||||
case TCPCHK_EXPECT_REGEX:
|
||||
chunk_printf(&trash, "TCPCHK %s (regex) at step %d",
|
||||
diag, tcpcheck_get_step_id(check, rule));
|
||||
chunk_appendf(msg, " (regex) at step %d", tcpcheck_get_step_id(check, rule));
|
||||
break;
|
||||
case TCPCHK_EXPECT_REGEX_BINARY:
|
||||
chunk_printf(&trash, "TCPCHK %s (binary regex) at step %d",
|
||||
diag, tcpcheck_get_step_id(check, rule));
|
||||
chunk_appendf(msg, " (binary regex) at step %d", tcpcheck_get_step_id(check, rule));
|
||||
|
||||
/* If references to the matched text were made, divide the
|
||||
* offsets by 2 to match offset of the original response buffer.
|
||||
@ -3171,22 +3170,29 @@ static enum tcpcheck_eval_ret tcpcheck_eval_expect(struct check *check, struct t
|
||||
break;
|
||||
case TCPCHK_EXPECT_UNDEF:
|
||||
/* Should never happen. */
|
||||
goto out;
|
||||
goto no_desc;
|
||||
}
|
||||
|
||||
if (rule->comment) {
|
||||
if (!LIST_ISEMPTY(&expect->onerror_fmt)) {
|
||||
chunk_strcat(msg, " comment: ");
|
||||
msg->data += sess_build_logline(check->sess, NULL, b_tail(msg), b_room(msg), &expect->onerror_fmt);
|
||||
}
|
||||
else if (rule->comment) {
|
||||
if (expect->with_capture) {
|
||||
ret = exp_replace(b_tail(&trash), b_room(&trash), b_head(&check->bi), rule->comment, pmatch);
|
||||
if (ret > 0) /* ignore comment if too large */
|
||||
trash.data += ret;
|
||||
ret = exp_replace(b_tail(msg), b_room(msg), b_head(&check->bi), rule->comment, pmatch);
|
||||
if (ret != -1) /* ignore comment if too large */
|
||||
msg->data += ret;
|
||||
}
|
||||
else
|
||||
chunk_appendf(&trash, " comment: '%s'", rule->comment);
|
||||
chunk_appendf(msg, " comment: '%s'", rule->comment);
|
||||
}
|
||||
set_server_check_status(check, expect->err_status, trash.area);
|
||||
|
||||
no_desc:
|
||||
set_server_check_status(check, expect->err_status, (msg ? b_head(msg) : NULL));
|
||||
ret = TCPCHK_EVAL_STOP;
|
||||
|
||||
out:
|
||||
free_trash_chunk(msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -3224,6 +3230,7 @@ static int tcpcheck_main(struct check *check)
|
||||
struct tcpcheck_rule *rule;
|
||||
struct conn_stream *cs = check->cs;
|
||||
struct connection *conn = cs_conn(cs);
|
||||
struct buffer *msg = NULL;
|
||||
int must_read = 1, last_read = 0;
|
||||
int ret, retcode = 0;
|
||||
|
||||
@ -3379,7 +3386,17 @@ static int tcpcheck_main(struct check *check)
|
||||
}
|
||||
|
||||
/* All rules was evaluated */
|
||||
set_server_check_status(check, HCHK_STATUS_L7OKD, "(tcp-check)");
|
||||
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);
|
||||
}
|
||||
|
||||
set_server_check_status(check, HCHK_STATUS_L7OKD, (msg ? b_head(msg) : "(tcp-check)"));
|
||||
check->current_step = NULL;
|
||||
free_trash_chunk(msg);
|
||||
|
||||
out_end_tcpcheck:
|
||||
if ((conn && conn->flags & CO_FL_ERROR) || (cs && cs->flags & CS_FL_ERROR))
|
||||
@ -3463,6 +3480,18 @@ static void free_tcpcheck(struct tcpcheck_rule *rule, int in_pool)
|
||||
}
|
||||
break;
|
||||
case TCPCHK_ACT_EXPECT:
|
||||
list_for_each_entry_safe(lf, lfb, &rule->expect.onerror_fmt, list) {
|
||||
LIST_DEL(&lf->list);
|
||||
release_sample_expr(lf->expr);
|
||||
free(lf->arg);
|
||||
free(lf);
|
||||
}
|
||||
list_for_each_entry_safe(lf, lfb, &rule->expect.onsuccess_fmt, list) {
|
||||
LIST_DEL(&lf->list);
|
||||
release_sample_expr(lf->expr);
|
||||
free(lf->arg);
|
||||
free(lf);
|
||||
}
|
||||
switch (rule->expect.type) {
|
||||
case TCPCHK_EXPECT_STRING:
|
||||
case TCPCHK_EXPECT_BINARY:
|
||||
@ -3636,6 +3665,8 @@ static int add_tcpcheck_expect_str(struct tcpcheck_rules *rules, const char *str
|
||||
|
||||
expect = &tcpcheck->expect;
|
||||
expect->type = TCPCHK_EXPECT_STRING;
|
||||
LIST_INIT(&expect->onerror_fmt);
|
||||
LIST_INIT(&expect->onsuccess_fmt);
|
||||
expect->err_status = HCHK_STATUS_L7RSP;
|
||||
expect->tout_status = HCHK_STATUS_L7TOUT;
|
||||
expect->string = strdup(str);
|
||||
@ -4525,13 +4556,14 @@ 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;
|
||||
char *str = NULL, *comment = NULL, *pattern = 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;
|
||||
enum healthcheck_status tout_st = HCHK_STATUS_L7TOUT;
|
||||
long min_recv = -1;
|
||||
int inverse = 0, with_capture = 0;
|
||||
|
||||
str = on_success_msg = on_error_msg = comment = pattern = NULL;
|
||||
if (!*(args[cur_arg+1]) || !*(args[cur_arg+2])) {
|
||||
memprintf(errmsg, "expects a pattern (type+string) as arguments");
|
||||
goto error;
|
||||
@ -4603,6 +4635,40 @@ static struct tcpcheck_rule *parse_tcpcheck_expect(char **args, int cur_arg, str
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "on-success") == 0) {
|
||||
if (in_pattern) {
|
||||
memprintf(errmsg, "[!] not supported with '%s'", args[cur_arg]);
|
||||
goto error;
|
||||
}
|
||||
if (!*(args[cur_arg+1])) {
|
||||
memprintf(errmsg, "'%s' expects a string as argument", args[cur_arg]);
|
||||
goto error;
|
||||
}
|
||||
cur_arg++;
|
||||
free(on_success_msg);
|
||||
on_success_msg = strdup(args[cur_arg]);
|
||||
if (!on_success_msg) {
|
||||
memprintf(errmsg, "out of memory");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "on-error") == 0) {
|
||||
if (in_pattern) {
|
||||
memprintf(errmsg, "[!] not supported with '%s'", args[cur_arg]);
|
||||
goto error;
|
||||
}
|
||||
if (!*(args[cur_arg+1])) {
|
||||
memprintf(errmsg, "'%s' expects a string as argument", args[cur_arg]);
|
||||
goto error;
|
||||
}
|
||||
cur_arg++;
|
||||
free(on_error_msg);
|
||||
on_error_msg = strdup(args[cur_arg]);
|
||||
if (!on_error_msg) {
|
||||
memprintf(errmsg, "out of memory");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else if (strcmp(args[cur_arg], "error-status") == 0) {
|
||||
if (in_pattern) {
|
||||
memprintf(errmsg, "[!] not supported with '%s'", args[cur_arg]);
|
||||
@ -4683,7 +4749,9 @@ static struct tcpcheck_rule *parse_tcpcheck_expect(char **args, int cur_arg, str
|
||||
goto error;
|
||||
}
|
||||
chk->action = TCPCHK_ACT_EXPECT;
|
||||
chk->comment = comment;
|
||||
LIST_INIT(&chk->expect.onerror_fmt);
|
||||
LIST_INIT(&chk->expect.onsuccess_fmt);
|
||||
chk->comment = comment; comment = NULL;
|
||||
chk->expect.type = type;
|
||||
chk->expect.min_recv = min_recv;
|
||||
chk->expect.inverse = inverse;
|
||||
@ -4691,6 +4759,25 @@ static struct tcpcheck_rule *parse_tcpcheck_expect(char **args, int cur_arg, str
|
||||
chk->expect.err_status = err_st;
|
||||
chk->expect.tout_status = tout_st;
|
||||
|
||||
if (on_success_msg) {
|
||||
px->conf.args.ctx = ARGC_SRV;
|
||||
if (!parse_logformat_string(on_success_msg, px, &chk->expect.onsuccess_fmt, 0, SMP_VAL_BE_CHK_RUL, errmsg)) {
|
||||
memprintf(errmsg, "'%s' invalid log-format string (%s).\n", on_success_msg, *errmsg);
|
||||
goto error;
|
||||
}
|
||||
free(on_success_msg);
|
||||
on_success_msg = NULL;
|
||||
}
|
||||
if (on_error_msg) {
|
||||
px->conf.args.ctx = ARGC_SRV;
|
||||
if (!parse_logformat_string(on_error_msg, px, &chk->expect.onerror_fmt, 0, SMP_VAL_BE_CHK_RUL, errmsg)) {
|
||||
memprintf(errmsg, "'%s' invalid log-format string (%s).\n", on_error_msg, *errmsg);
|
||||
goto error;
|
||||
}
|
||||
free(on_error_msg);
|
||||
on_error_msg = NULL;
|
||||
}
|
||||
|
||||
switch (chk->expect.type) {
|
||||
case TCPCHK_EXPECT_STRING:
|
||||
chk->expect.string = strdup(pattern);
|
||||
@ -4733,9 +4820,11 @@ static struct tcpcheck_rule *parse_tcpcheck_expect(char **args, int cur_arg, str
|
||||
return chk;
|
||||
|
||||
error:
|
||||
free(chk);
|
||||
free_tcpcheck(chk, 0);
|
||||
free(str);
|
||||
free(comment);
|
||||
free(on_success_msg);
|
||||
free(on_error_msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user