MEDIUM: checks: Support expression to set the port

Since we have a session attached to tcp-check healthchecks, It is possible use
sample expression and variables. In addition, it is possible to add tcp-check
set-var rules to define custom variables. So, now, a sample expression can be
used to define the port to use to establish a connection for a tcp-check connect
rule. For instance:

    tcp-check set-var(check.port) int(8888)
    tcp-check connect port var(check.port)
This commit is contained in:
Christopher Faulet 2020-03-30 15:19:03 +02:00
parent 5c28874a69
commit b7d30098f3
3 changed files with 50 additions and 8 deletions

View File

@ -9821,10 +9821,10 @@ tcp-check connect [params*]
default Use default options of the server line to do the health default Use default options of the server line to do the health
checks. This parameter is exclusive with all other options. checks. This parameter is exclusive with all other options.
port if not set, check port or server port is used. port <expr> if not set, check port or server port is used.
It tells HAProxy where to open the connection to. It tells HAProxy where to open the connection to.
<port> must be a valid TCP port source integer, from 1 to <port> must be a valid TCP port source integer, from 1 to
65535. 65535 or an sample-fetch expression.
addr <ip> defines the IP address to do the health check. addr <ip> defines the IP address to do the health check.

View File

@ -225,6 +225,7 @@ struct tcpcheck_connect {
int alpn_len; /* ALPN string length */ int alpn_len; /* ALPN string length */
uint16_t options; /* options when setting up a new connection */ uint16_t options; /* options when setting up a new connection */
uint16_t port; /* port to connect to */ uint16_t port; /* port to connect to */
struct sample_expr *port_expr; /* sample expr to determine the port, may be NULL */
struct sockaddr_storage addr; /* the address to the connect */ struct sockaddr_storage addr; /* the address to the connect */
}; };

View File

@ -64,6 +64,7 @@
#include <proto/dns.h> #include <proto/dns.h>
#include <proto/proto_udp.h> #include <proto/proto_udp.h>
#include <proto/ssl_sock.h> #include <proto/ssl_sock.h>
#include <proto/sample.h>
static int httpchk_expect(struct server *s, int done); static int httpchk_expect(struct server *s, int done);
static int tcpcheck_get_step_id(struct check *, struct tcpcheck_rule *); static int tcpcheck_get_step_id(struct check *, struct tcpcheck_rule *);
@ -2870,6 +2871,15 @@ static enum tcpcheck_eval_ret tcpcheck_eval_connect(struct check *check, struct
port = 0; port = 0;
if (!port && connect->port) if (!port && connect->port)
port = connect->port; port = connect->port;
if (!port && connect->port_expr) {
struct sample *smp;
smp = sample_fetch_as_type(check->proxy, check->sess, NULL,
SMP_OPT_DIR_REQ | SMP_OPT_FINAL,
connect->port_expr, SMP_T_SINT);
if (smp)
port = smp->data.u.sint;
}
if (!port && is_inet_addr(&connect->addr)) if (!port && is_inet_addr(&connect->addr))
port = get_host_port(&connect->addr); port = get_host_port(&connect->addr);
if (!port && check->port) if (!port && check->port)
@ -3465,6 +3475,7 @@ static void free_tcpcheck(struct tcpcheck_rule *rule, int in_pool)
case TCPCHK_ACT_CONNECT: case TCPCHK_ACT_CONNECT:
free(rule->connect.sni); free(rule->connect.sni);
free(rule->connect.alpn); free(rule->connect.alpn);
release_sample_expr(rule->connect.port_expr);
break; break;
case TCPCHK_ACT_COMMENT: case TCPCHK_ACT_COMMENT:
break; break;
@ -4084,11 +4095,12 @@ static struct tcpcheck_rule *parse_tcpcheck_action(char **args, int cur_arg, str
} }
static struct tcpcheck_rule *parse_tcpcheck_connect(char **args, int cur_arg, struct proxy *px, struct list *rules, static struct tcpcheck_rule *parse_tcpcheck_connect(char **args, int cur_arg, struct proxy *px, struct list *rules,
char **errmsg) const char *file, int line, char **errmsg)
{ {
struct tcpcheck_rule *chk = NULL; struct tcpcheck_rule *chk = NULL;
struct sockaddr_storage *sk = NULL; struct sockaddr_storage *sk = NULL;
char *comment = NULL, *sni = NULL, *alpn = NULL; char *comment = NULL, *sni = NULL, *alpn = NULL;
struct sample_expr *port_expr = NULL;
unsigned short conn_opts = 0; unsigned short conn_opts = 0;
long port = 0; long port = 0;
int alpn_len = 0; int alpn_len = 0;
@ -4144,14 +4156,41 @@ static struct tcpcheck_rule *parse_tcpcheck_connect(char **args, int cur_arg, st
cur_arg++; cur_arg++;
} }
else if (strcmp(args[cur_arg], "port") == 0) { else if (strcmp(args[cur_arg], "port") == 0) {
const char *p, *end;
if (!*(args[cur_arg+1])) { if (!*(args[cur_arg+1])) {
memprintf(errmsg, "'%s' expects a port number as argument.", args[cur_arg]); memprintf(errmsg, "'%s' expects a port number or a sample expression as argument.", args[cur_arg]);
goto error; goto error;
} }
cur_arg++; cur_arg++;
port = atol(args[cur_arg]);
if (port > 65535 || port < 1) { port = 0;
memprintf(errmsg, "expects a valid TCP port (from range 1 to 65535), got %s.", args[cur_arg]); release_sample_expr(port_expr);
p = args[cur_arg]; end = p + strlen(p);
port = read_uint(&p, end);
if (p != end) {
int idx = 0;
px->conf.args.ctx = ARGC_SRV;
port_expr = sample_parse_expr((char *[]){args[cur_arg], NULL}, &idx,
file, line, errmsg, &px->conf.args, NULL);
if (!port_expr) {
memprintf(errmsg, "error detected while parsing port expression : %s", *errmsg);
goto error;
}
if (!(port_expr->fetch->val & SMP_VAL_BE_CHK_RUL)) {
memprintf(errmsg, "error detected while parsing port expression : "
" fetch method '%s' extracts information from '%s', "
"none of which is available here.\n",
args[cur_arg], sample_src_names(port_expr->fetch->use));
goto error;
}
px->http_needed |= !!(port_expr->fetch->use & SMP_USE_HTTP_ANY);
}
else if (port > 65535 || port < 1) {
memprintf(errmsg, "expects a valid TCP port (from range 1 to 65535) or a sample expression, got %s.",
args[cur_arg]);
goto error; goto error;
} }
} }
@ -4231,6 +4270,7 @@ static struct tcpcheck_rule *parse_tcpcheck_connect(char **args, int cur_arg, st
chk->connect.sni = sni; chk->connect.sni = sni;
chk->connect.alpn = alpn; chk->connect.alpn = alpn;
chk->connect.alpn_len= alpn_len; chk->connect.alpn_len= alpn_len;
chk->connect.port_expr= port_expr;
if (sk) if (sk)
chk->connect.addr = *sk; chk->connect.addr = *sk;
return chk; return chk;
@ -4239,6 +4279,7 @@ static struct tcpcheck_rule *parse_tcpcheck_connect(char **args, int cur_arg, st
free(alpn); free(alpn);
free(sni); free(sni);
free(comment); free(comment);
release_sample_expr(port_expr);
return NULL; return NULL;
} }
@ -4535,7 +4576,7 @@ static int proxy_parse_tcpcheck(char **args, int section, struct proxy *curpx,
cur_arg = 1; cur_arg = 1;
if (strcmp(args[cur_arg], "connect") == 0) if (strcmp(args[cur_arg], "connect") == 0)
chk = parse_tcpcheck_connect(args, cur_arg, curpx, rules, errmsg); chk = parse_tcpcheck_connect(args, cur_arg, curpx, rules, file, line, errmsg);
else if (strcmp(args[cur_arg], "send") == 0 || strcmp(args[cur_arg], "send-binary") == 0) else if (strcmp(args[cur_arg], "send") == 0 || strcmp(args[cur_arg], "send-binary") == 0)
chk = parse_tcpcheck_send(args, cur_arg, rules, errmsg); chk = parse_tcpcheck_send(args, cur_arg, rules, errmsg);
else if (strcmp(args[cur_arg], "expect") == 0) else if (strcmp(args[cur_arg], "expect") == 0)