]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: server: implement "from srv:" master
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 9 Jul 2026 09:41:50 +0000 (11:41 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 3 Aug 2026 14:52:10 +0000 (16:52 +0200)
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 "[<be>/]<srv>". 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.

doc/configuration.txt
doc/management.txt
reg-tests/server/from_keyword.vtc
src/server.c

index ac4b3de9baea052f7d276d01005ccdf510f1158a..7fa73bede4720654c3cecd2b567f7d4cc142db8b 100644 (file)
@@ -18244,6 +18244,12 @@ from <origin>
       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:[<bename>/]<srvname>
+      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,
index bd03ad72839b5244a5c12bd7bba58c4e7d945919..5de0b3cbba59cc9b2124e395f99608bfa9c3eb6e 100644 (file)
@@ -1812,8 +1812,8 @@ add server <backend>/<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
index 78402f4c139cd10afa93a8194dfce6d6f882f37c..6467a6a01649451c8391402d1a8708c184640588 100644 (file)
@@ -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\\)"
 }
index 83024f89b8c888e93cc975bf0c4390282d051b38..bca44ec03dcc0da7095eee9b12d31f930ab45020 100644 (file)
@@ -3962,6 +3962,44 @@ out:
        return err_code;
 }
 
+/* Look up a server according to <sv_name> argument of the form [<be>/]<srv>.
+ * Both standard and default-server are searched. If the proxy is not
+ * specified, caller must set <curproxy> as a default value. If the server is
+ * not found, <msg> 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 <backend>/<server>");
+               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 <srv> server instance.
  * The keyword is read from <args>. If found <cur_arg> 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;