From: Amaury Denoyelle Date: Wed, 8 Jul 2026 08:05:21 +0000 (+0200) Subject: MINOR: server: define _srv_parse_from() for server "from" keyword X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c81044a8bf0e9921e5080c01a7737b6f992c5d3b;p=thirdparty%2Fhaproxy.git MINOR: server: define _srv_parse_from() for server "from" keyword Prepare the support for a new server keyword "from". This keyword has special constraints : it is a positional one as it can only be specified once, after the server address and before the other parameters. The purpose of this keyword will be to define server settings inheritance outside of the default-server of the current backend. It will also be useful for dynamic servers which currently do not inherit from a default-server. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index bcdd50c25..b8a570466 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -7352,7 +7352,7 @@ declare capture [ request | response ] len "http-request capture" and "http-response capture". -default-server [param*] +default-server [from ] [param*] Change default options for a server in a backend May be used in the following contexts: tcp, http @@ -7361,6 +7361,11 @@ default-server [param*] yes | no | yes | yes Arguments: + instructs to reinitialize first the set of options to their + default values and then reusing the settings from the designated + server or default-server instance. See section 5.2 about server + options for a complete description of the supported arguments. + is a list of parameters for this server. The "default-server" keyword accepts an important number of options and has a complete section dedicated to it. Please refer to section 5 for more @@ -12525,7 +12530,7 @@ server-state-file-name [ { use-backend-name | } ] See also: "server-state-base", "load-server-state-from-file", and "show servers state" -server-template [:] [params*] +server-template [:] [from ] [params*] Set a template to initialize servers with shared parameters. The names of these servers are built from and parameters. @@ -12547,6 +12552,10 @@ server-template [:] [params*] Same meaning as "server" argument (see "server" keyword). + instructs to reuse the settings from the designated server or + default-server instance. See section 5.2 about server options for + a complete description of the supported arguments. + Remaining server parameters among all those supported by "server" keyword. @@ -18168,16 +18177,24 @@ which are all passed as arguments on the server line. The order in which those arguments appear does not count, and they are all optional. Some of those settings are single words (booleans) while others expect one or several values after them. In this case, the values must immediately follow the setting name. + Except default-server, all those settings must be specified after the server's -address if they are used: +address if they are used. Before any of those settings, the extra keyword +"from" may be used both on "server" and "default-server" lines to preset +its settings. - server
[:port] [settings ...] - default-server [settings ...] + server
[:port] [from ] [settings ...] + default-server [from ] [settings ...] -Note that all these settings are supported both by "server" and "default-server" -keywords, except "id" which is only supported by "server". +from + Preinitialize the server settings by copying values from another server or + default-server instance. -The currently supported settings are the following ones. + Here is the list of the supported values for the "from" keyword : + +The currently supported server settings are the following ones. Note that all +these settings are supported both by "server" and "default-server" keywords, +except "id" which is only supported by "server". addr May be used in the following contexts: tcp, http, log diff --git a/reg-tests/server/from_keyword.vtc b/reg-tests/server/from_keyword.vtc new file mode 100644 index 000000000..cf48f2fb3 --- /dev/null +++ b/reg-tests/server/from_keyword.vtc @@ -0,0 +1,48 @@ +varnishtest "Test server from keyword" + +feature ignore_unknown_macro + +# Do nothing. Is there only to create s1_* macros +server s1 { + rxreq + txresp +} -start + +haproxy h1 -conf { + global + .if feature(THREAD) + thread-groups 1 + .endif + + defaults + mode http + timeout connect "${HAPROXY_TEST_TIMEOUT-5s}" + timeout client "${HAPROXY_TEST_TIMEOUT-5s}" + timeout server "${HAPROXY_TEST_TIMEOUT-5s}" + + frontend fe + bind "fd@${feS}" + use_backend be + + backend be + default-server weight 10 + # ensure that default-server overloading is working as expected + default-server inter 5s + + server srvconf1 ${s1_addr}:${s1_port} +} -start + +haproxy h1 -cli { + # static server uses by default the default-server + send "get weight be/srvconf1" + expect ~ "10 \\(initial 10\\)" +} + +# dynamic servers +haproxy h1 -cli { + # dynamic server does not use the default-server by default + send "add server be/srvdyn1 ${s1_addr}:${s1_port}" + expect ~ "New server registered." + send "get weight be/srvdyn1" + expect ~ "1 \\(initial 1\\)" +} diff --git a/src/server.c b/src/server.c index 5e8bc7070..ec86c30b1 100644 --- a/src/server.c +++ b/src/server.c @@ -3888,11 +3888,6 @@ static int _srv_parse_init(struct server **srv, char **args, int *cur_arg, (*cur_arg)++; skip_addr: - if (!(parse_flags & SRV_PARSE_DYNAMIC)) { - /* Copy default server settings to new server */ - srv_settings_cpy(newsrv, curproxy->defsrv, 0); - } else - srv_settings_init(newsrv); HA_SPIN_INIT(&newsrv->lock); } else { @@ -3924,6 +3919,66 @@ out: return err_code; } +/* Try to parse optional positional "from" keyword for server instance. + * The keyword is read from . If found is incremented to the + * next argument. + * + * On return, will point to a server or default-instance from with + * settings must be copied. If NULL the server settings must be initialized to + * default clean values. If points to , the caller must neither + * reinit or copy settings. + * + * A mask of errors is returned. ERR_FATAL is set on parsing error. + */ +static int _srv_parse_from(struct server *srv, char **args, int *cur_arg, + struct proxy *curproxy, struct server **from, + int parse_flags) +{ + int err_code = ERR_NONE; + + if (strcmp(args[*cur_arg], "from") == 0) { + if (!*args[*cur_arg + 1]) { + ha_alert("from: missing value.\n"); + err_code |= ERR_FATAL | ERR_ALERT; + goto out; + } + else { + ha_alert("invalid '%s' value for 'from' keyword.\n", args[*cur_arg + 1]); + err_code |= ERR_FATAL | ERR_ALERT; + goto out; + } + + *cur_arg += 2; + + /* detect duplicate 'from' keyword usage. */ + if (strcmp(args[*cur_arg], "from") == 0) { + ha_alert("'from' keyword can only be specified once.\n"); + err_code |= ERR_FATAL | ERR_ALERT; + goto out; + } + } + else { + /* from keyword not used : fallback to the default behavior. */ + if (parse_flags & SRV_PARSE_DEFAULT_SERVER) { + /* default-server can be defined on multiple lines with settings overriding. + * In this case, caller do not have to reinit or copy the settings. + */ + *from = srv; + } + else if (!(parse_flags & SRV_PARSE_DYNAMIC)) { + /* Reuses the default-server in the current proxy when parsing configuration files. */ + *from = curproxy->defsrv; + } + else { + /* Servers added at runtime to not inherit by default from the default-server. */ + *from = NULL; + } + } + + out: + return err_code; +} + /* Parse the server keyword in . * is incremented beyond the keyword optional value. Note that this * might not be the case if an error is reported. @@ -4113,6 +4168,7 @@ int parse_server(const char *file, int linenum, char **args, int parse_flags) { struct server *newsrv = NULL; + struct server *from = NULL; int err_code = 0; int cur_arg; @@ -4137,10 +4193,19 @@ int parse_server(const char *file, int linenum, char **args, err_code = _srv_parse_init(&newsrv, args, &cur_arg, curproxy, parse_flags); - if (err_code & ERR_CODE) goto out; + err_code = _srv_parse_from(newsrv, args, &cur_arg, curproxy, &from, + parse_flags); + if (err_code & ERR_FATAL) + goto out; + + if (newsrv != from) { + /* This will copy settings or init them if NULL. */ + srv_settings_cpy(newsrv, from, !!(parse_flags & SRV_PARSE_TEMPLATE)); + } + if (!newsrv->conf.file) // note: do it only once for default-server newsrv->conf.file = strdup(file); newsrv->conf.line = linenum; @@ -6366,7 +6431,7 @@ static int cli_parse_add_server(char **args, char *payload, struct appctx *appct { struct add_srv_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx)); struct proxy *be; - struct server *srv; + struct server *srv, *from = NULL; char *be_name, *sv_name, *errmsg; int errcode, argc; const int parse_flags = SRV_PARSE_DYNAMIC|SRV_PARSE_PARSE_ADDR; @@ -6430,6 +6495,11 @@ static int cli_parse_add_server(char **args, char *payload, struct appctx *appct if (errcode) goto out; + errcode = _srv_parse_from(srv, args, &argc, be, &from, parse_flags); + if (errcode) + goto out; + srv_settings_cpy(srv, from, 0); + while (*args[argc]) { errcode = _srv_parse_kw(srv, args, &argc, be, parse_flags);