From: Amaury Denoyelle Date: Thu, 9 Jul 2026 09:41:50 +0000 (+0200) Subject: MEDIUM: server: implement "from srv:" X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;ds=inline;p=thirdparty%2Fhaproxy.git MEDIUM: server: implement "from srv:" Implement "srv:" notation for the "from" server keyword. This allows to specify a server or default-server by its name. It may be optionnaly prefixed by a backend name using a slash separator. If this is not the case, lookup is performed under the backend where the current newly created server instance is attached. This is implemented by extending _srv_parse_from() to support "from srv:" argument value. An internal function lookup_srv_be_arg() is defined to parse the argument of the form "[/]". This is similar to already existing lookup functions such as cli_find_server(), however there is some differences which forces to have duplicated code for the moment. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index ac4b3de9b..7fa73bede 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -18244,6 +18244,12 @@ from behavior for servers defined in the configuration file. This empty value is mostly useful for dynamic servers created on the CLI which by default ignore any default-server, which is equivalent to the "none" value. + - srv:[/] + instructs to reuse the settings from the designated backend's server or named + default-server resulting from the processing of all its default-server + directives using the same name. The backend name is optional. If unset, + this designates the proxy where the currently newly defined server will + be attached. The currently supported server settings are the following ones. Note that all these settings are supported both by "server" and "default-server" keywords, diff --git a/doc/management.txt b/doc/management.txt index bd03ad728..5de0b3cbb 100644 --- a/doc/management.txt +++ b/doc/management.txt @@ -1812,8 +1812,8 @@ add server / [args]* By default, 'default-server' is ignored by a dynamically created server. However, it is possible to use the 'from' server positional keyword to - explicitely preset the settings of the newly created server from a - default-server instance. + explicitely preset the settings of the newly created server from another + server or a default-server instance, either named or unnamed. Currently a dynamic server is statically initialized with the "none" init-addr method. This means that no resolution will be undertaken if a FQDN diff --git a/reg-tests/server/from_keyword.vtc b/reg-tests/server/from_keyword.vtc index 78402f4c1..6467a6a01 100644 --- a/reg-tests/server/from_keyword.vtc +++ b/reg-tests/server/from_keyword.vtc @@ -38,6 +38,22 @@ haproxy h1 -conf { # configure new default-server settings used for dynamic servers default-server weight 10 + + # named default-server should use base settings by default + default-server name other + server srvconf4 ${s1_addr}:${s1_port} from srv:other + + # override named default-server + default-server name other from be: + server srvconf5 ${s1_addr}:${s1_port} from srv:other + + # reset named default-server + default-server name other from none + server srvconf6 ${s1_addr}:${s1_port} from srv:other + + # define new settings on named default-server + default-server name other weight 5 + server srvconf7 ${s1_addr}:${s1_port} from srv:other } -start haproxy h1 -cli { @@ -54,6 +70,21 @@ haproxy h1 -cli { expect ~ "1 \\(initial 1\\)" } +# named default-server +haproxy h1 -cli { + send "get weight be/srvconf4" + expect ~ "1 \\(initial 1\\)" + + send "get weight be/srvconf5" + expect ~ "10 \\(initial 10\\)" + + send "get weight be/srvconf6" + expect ~ "1 \\(initial 1\\)" + + send "get weight be/srvconf7" + expect ~ "5 \\(initial 5\\)" +} + # dynamic servers haproxy h1 -cli { # dynamic server does not use the default-server by default @@ -67,4 +98,10 @@ haproxy h1 -cli { expect ~ "New server registered." send "get weight be/srvdyn2" expect ~ "10 \\(initial 10\\)" + + # use from keyword for dynamic server + send "add server be/srvdyn3 ${s1_addr}:${s1_port} from srv:other" + expect ~ "New server registered." + send "get weight be/srvdyn3" + expect ~ "5 \\(initial 5\\)" } diff --git a/src/server.c b/src/server.c index 83024f89b..bca44ec03 100644 --- a/src/server.c +++ b/src/server.c @@ -3962,6 +3962,44 @@ out: return err_code; } +/* Look up a server according to argument of the form [/]. + * Both standard and default-server are searched. If the proxy is not + * specified, caller must set as a default value. If the server is + * not found, is allocated to indicate the failure reason. + * + * Returns the server instance or NULL if not found. + */ +static struct server *lookup_srv_be_arg(struct ist sv_name, + struct proxy *curproxy, + char **msg) +{ + struct server *srv; + struct ist be_name; + struct proxy *px = curproxy; + + if (istchr(sv_name, '/')) { + be_name = istsplit(&sv_name, '/'); + px = proxy_be_by_name(ist0(be_name)); + if (!px) { + memprintf(msg, "unknown backend '%s'", istptr(be_name)); + return NULL; + } + } + + if (!istlen(sv_name) || !px) { + memprintf(msg, "require /"); + return NULL; + } + + srv = server_find_by_name2(px, istptr(sv_name)); + if (!srv) { + memprintf(msg, "unknown server '%s' in backend '%s'", + istptr(sv_name), px->id); + } + + return srv; +} + /* Try to parse optional positional "from" keyword for server instance. * The keyword is read from . If found is incremented to the * next argument. @@ -4004,6 +4042,18 @@ static int _srv_parse_from(struct server *srv, char **args, int *cur_arg, *from = px->defsrv; } + else if (strncmp(args[*cur_arg + 1], "srv:", 4) == 0) { + struct ist sv_name = istadv(ist(args[*cur_arg + 1]), 4); + char *errmsg = NULL; + + *from = lookup_srv_be_arg(sv_name, curproxy, &errmsg); + if (!*from) { + ha_alert("from: %s.\n", errmsg); + ha_free(&errmsg); + err_code = ERR_ALERT | ERR_FATAL; + goto out; + } + } else { ha_alert("invalid '%s' value for 'from' keyword.\n", args[*cur_arg + 1]); err_code |= ERR_FATAL | ERR_ALERT;