mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-23 23:01:24 +02:00
MEDIUM: stream: support use-server rules with dynamic names
With server-template was introduced the possibility to scale the number of servers in a backend without needing a configuration change and associated reload. On the other hand it became impractical to write use-server rules for these servers as they would only accept existing server labels as argument. This patch allows the use of log-format notation to describe targets of a use-server rules, such as in the example below: listen test bind *:1234 use-server %[hdr(srv)] if { hdr(srv) -m found } use-server s1 if { path / } server s1 127.0.0.1:18080 server s2 127.0.0.1:18081 If a use-server rule is applied because it was conditionned by an ACL returning true, but the target of the use-server rule cannot be resolved, no other use-server rule is evaluated and we fall back to load balancing. This feature was requested on the ML, and bumped with issue #563.
This commit is contained in:
parent
eb421b2fe0
commit
824186bb08
@ -11141,7 +11141,8 @@ use-server <server> unless <condition>
|
|||||||
May be used in sections : defaults | frontend | listen | backend
|
May be used in sections : defaults | frontend | listen | backend
|
||||||
no | no | yes | yes
|
no | no | yes | yes
|
||||||
Arguments :
|
Arguments :
|
||||||
<server> is the name of a valid server in the same backend section.
|
<server> is the name of a valid server in the same backend section
|
||||||
|
or a "log-format" string resolving to a server name.
|
||||||
|
|
||||||
<condition> is a condition composed of ACLs, as described in section 7.
|
<condition> is a condition composed of ACLs, as described in section 7.
|
||||||
|
|
||||||
@ -11186,6 +11187,13 @@ use-server <server> unless <condition>
|
|||||||
# all the rest is forwarded to this server
|
# all the rest is forwarded to this server
|
||||||
server default 192.168.0.2:443 check
|
server default 192.168.0.2:443 check
|
||||||
|
|
||||||
|
When <server> is a simple name, it is checked against existing servers in the
|
||||||
|
configuration and an error is reported if the specified server does not exist.
|
||||||
|
If it is a log-format, no check is performed when parsing the configuration,
|
||||||
|
and if we can't resolve a valid server name at runtime but the use-server rule
|
||||||
|
was conditionned by an ACL returning true, no other use-server rule is applied
|
||||||
|
and we fall back to load balancing.
|
||||||
|
|
||||||
See also: "use_backend", section 5 about server and section 7 about ACLs.
|
See also: "use_backend", section 5 about server and section 7 about ACLs.
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,6 +81,7 @@ enum {
|
|||||||
ARGC_SRV, /* server line */
|
ARGC_SRV, /* server line */
|
||||||
ARGC_SPOE, /* spoe message args */
|
ARGC_SPOE, /* spoe message args */
|
||||||
ARGC_UBK, /* use_backend message */
|
ARGC_UBK, /* use_backend message */
|
||||||
|
ARGC_USRV, /* use-server message */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* flags used when compiling and executing regex */
|
/* flags used when compiling and executing regex */
|
||||||
|
@ -509,10 +509,14 @@ struct switching_rule {
|
|||||||
struct server_rule {
|
struct server_rule {
|
||||||
struct list list; /* list linked to from the proxy */
|
struct list list; /* list linked to from the proxy */
|
||||||
struct acl_cond *cond; /* acl condition to meet */
|
struct acl_cond *cond; /* acl condition to meet */
|
||||||
|
int dynamic;
|
||||||
union {
|
union {
|
||||||
struct server *ptr; /* target server */
|
struct server *ptr; /* target server */
|
||||||
char *name; /* target server name during config parsing */
|
char *name; /* target server name during config parsing */
|
||||||
} srv;
|
} srv;
|
||||||
|
struct list expr; /* logformat expression to use for dynamic rules */
|
||||||
|
char *file;
|
||||||
|
int line;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct persist_rule {
|
struct persist_rule {
|
||||||
|
@ -1592,6 +1592,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
|||||||
rule = calloc(1, sizeof(*rule));
|
rule = calloc(1, sizeof(*rule));
|
||||||
rule->cond = cond;
|
rule->cond = cond;
|
||||||
rule->srv.name = strdup(args[1]);
|
rule->srv.name = strdup(args[1]);
|
||||||
|
rule->line = linenum;
|
||||||
|
rule->file = strdup(file);
|
||||||
LIST_INIT(&rule->list);
|
LIST_INIT(&rule->list);
|
||||||
LIST_ADDQ(&curproxy->server_rules, &rule->list);
|
LIST_ADDQ(&curproxy->server_rules, &rule->list);
|
||||||
curproxy->be_req_ana |= AN_REQ_SRV_RULES;
|
curproxy->be_req_ana |= AN_REQ_SRV_RULES;
|
||||||
|
@ -2701,7 +2701,40 @@ int check_config_validity()
|
|||||||
|
|
||||||
/* find the target server for 'use_server' rules */
|
/* find the target server for 'use_server' rules */
|
||||||
list_for_each_entry(srule, &curproxy->server_rules, list) {
|
list_for_each_entry(srule, &curproxy->server_rules, list) {
|
||||||
struct server *target = findserver(curproxy, srule->srv.name);
|
struct server *target;
|
||||||
|
struct logformat_node *node;
|
||||||
|
char *server_name;
|
||||||
|
|
||||||
|
/* We try to parse the string as a log format expression. If the result of the parsing
|
||||||
|
* is only one entry containing a single string, then it's a standard string corresponding
|
||||||
|
* to a static rule, thus the parsing is cancelled and we fall back to setting srv.ptr.
|
||||||
|
*/
|
||||||
|
server_name = srule->srv.name;
|
||||||
|
LIST_INIT(&srule->expr);
|
||||||
|
curproxy->conf.args.ctx = ARGC_USRV;
|
||||||
|
err = NULL;
|
||||||
|
if (!parse_logformat_string(server_name, curproxy, &srule->expr, 0, SMP_VAL_FE_HRQ_HDR, &err)) {
|
||||||
|
ha_alert("Parsing [%s:%d]; use-server rule failed to parse log-format '%s' : %s.\n",
|
||||||
|
srule->file, srule->line, server_name, err);
|
||||||
|
free(err);
|
||||||
|
cfgerr++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
node = LIST_NEXT(&srule->expr, struct logformat_node *, list);
|
||||||
|
|
||||||
|
if (!LIST_ISEMPTY(&srule->expr)) {
|
||||||
|
if (node->type != LOG_FMT_TEXT || node->list.n != &srule->expr) {
|
||||||
|
srule->dynamic = 1;
|
||||||
|
free(server_name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
free(node->arg);
|
||||||
|
free(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
srule->dynamic = 0;
|
||||||
|
srule->srv.name = server_name;
|
||||||
|
target = findserver(curproxy, srule->srv.name);
|
||||||
|
|
||||||
if (!target) {
|
if (!target) {
|
||||||
ha_alert("config : %s '%s' : unable to find server '%s' referenced in a 'use-server' rule.\n",
|
ha_alert("config : %s '%s' : unable to find server '%s' referenced in a 'use-server' rule.\n",
|
||||||
|
15
src/stream.c
15
src/stream.c
@ -1169,7 +1169,20 @@ static int process_server_rules(struct stream *s, struct channel *req, int an_bi
|
|||||||
ret = !ret;
|
ret = !ret;
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
struct server *srv = rule->srv.ptr;
|
struct server *srv;
|
||||||
|
|
||||||
|
if (rule->dynamic) {
|
||||||
|
struct buffer *tmp = get_trash_chunk();
|
||||||
|
|
||||||
|
if (!build_logline(s, tmp->area, tmp->size, &rule->expr))
|
||||||
|
break;
|
||||||
|
|
||||||
|
srv = findserver(s->be, tmp->area);
|
||||||
|
if (!srv)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
srv = rule->srv.ptr;
|
||||||
|
|
||||||
if ((srv->cur_state != SRV_ST_STOPPED) ||
|
if ((srv->cur_state != SRV_ST_STOPPED) ||
|
||||||
(px->options & PR_O_PERSIST) ||
|
(px->options & PR_O_PERSIST) ||
|
||||||
|
Loading…
x
Reference in New Issue
Block a user