]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: proxy: implement "show default-server"
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 30 Jul 2026 12:42:43 +0000 (14:42 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 5 Aug 2026 09:36:20 +0000 (11:36 +0200)
Define a new CLI command "show default-server". This lists all the
default-server instances, both unnamed and named. By default, all
backends are displayed. A single instance only can be requested.

Command is protected against runtime backend deletion via a watcher. It
is only attached for a full iteration. If only a single instance is
requested, watcher_is_attached() will detects this and interrupt the for
loop.

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

index eeca5b44fce7b45f0ed78383d05e5a0b8c36c0b4..3050e155c622993a81f03f7196781f8553542fd1 100644 (file)
@@ -4237,7 +4237,8 @@ tune.defaults.purge [<element[,...]>]
 
   Default-server instances are kept in memory after parsing as they may be
   reused for dynamic servers added at runtime. Similarly, named defaults
-  proxies sections are preserved as dynamic backends rely on them.
+  proxies sections are preserved as dynamic backends rely on them. The command
+  "show default-server" may be used to list them.
 
   This may consume a noticeable amount of memory if the number of default
   instances is important. It's possible to reclaim this memory after the
@@ -7415,7 +7416,8 @@ default-server [name <name>] [from <origin>] [param*]
   keyword. An unnamed default-server with no parameter set will automatically
   be purged after parsing. As such, a final "default-server from none"
   statement will be sufficient to release this unused memory, regardless of the
-  global setting.
+  global setting. It is possible to list the preserved instances via the
+  command "show default-server".
 
   See also: "server", section 5 about server options and global
     "tune.defaults.purge" option
index 5de0b3cbba59cc9b2124e395f99608bfa9c3eb6e..8c2b8abd5ad03d7eed3a56e1022b906a2d147499 100644 (file)
@@ -1813,7 +1813,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 another
-  server or a default-server instance, either named or unnamed.
+  server or a default-server instance, either named or unnamed. The additional
+  command "show default-server" lists the available entries.
 
   Currently a dynamic server is statically initialized with the "none"
   init-addr method. This means that no resolution will be undertaken if a FQDN
@@ -3065,6 +3066,11 @@ show cache
   6. number of transactions using the entry
   7. expiration time, can be negative if already expired
 
+show default-server [<backend>]
+  Dump the list of default-server instances still present in a backend after
+  configuration parsing. These instances can be referenced via the server
+  keyword from during "add server".
+
 show dev
   This command is meant to centralize some information that HAProxy developers
   might need to better understand the causes of a given problem. It generally
index 6467a6a01649451c8391402d1a8708c184640588..78a5e95708abf6a7363c152316f1fad91466b8c2 100644 (file)
@@ -54,6 +54,11 @@ haproxy h1 -conf {
                # define new settings on named default-server
                default-server name other weight 5
                server srvconf7 ${s1_addr}:${s1_port} from srv:other
+
+       backend be_defempty
+               default-server check
+               # reset default-server will be purged on post parsing
+               default-server from none
 } -start
 
 haproxy h1 -cli {
@@ -105,3 +110,11 @@ haproxy h1 -cli {
        send "get weight be/srvdyn3"
        expect ~ "5 \\(initial 5\\)"
 }
+
+haproxy h1 -cli {
+       send "show default-server"
+       expect ~  "\\* be\n  be/other"
+
+       send "show default-server"
+       expect !~ "be_defempty"
+}
index 8ec08a5df778faefd82c90f988408cf448cdeb95..34a99aaac448d6c36152a29e2c03233fba8cf424 100644 (file)
@@ -92,7 +92,7 @@ unsigned int error_snapshot_id = 0;     /* global ID assigned to each error then
 
 unsigned int dynpx_next_id = 0; /* lowest ID assigned to dynamic proxies */
 
-/* CLI context used during "show backend" */
+/* CLI context used during "show backend" and "show default-server" */
 struct show_be_ctx {
        struct proxy *px;
        struct watcher px_watch; /* watcher to automatically update px pointer on backend deletion */
@@ -4423,6 +4423,75 @@ struct proxy *cli_find_backend(struct appctx *appctx, const char *arg)
        return px;
 }
 
+/* Parser for "show default-server [<backend>] command.
+ * Returns 0 unless a requested backend is unknown.
+ */
+static int cli_parse_show_default_server(char **args, char *payload, struct appctx *appctx, void *private)
+{
+       struct show_be_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx));
+
+       /* Watch proxies list as backends may be deleted during iteration. No
+        * need to watch for servers as default-server instances cannot be
+        * removed.
+        */
+       watcher_init(&ctx->px_watch, &ctx->px, offsetof(struct proxy, watcher_list));
+
+       /* check if a backend name has been provided */
+       if (*args[2]) {
+               ctx->px = proxy_be_by_name(args[2]);
+               if (!ctx->px)
+                       return cli_err(appctx, "Can't find backend.\n");
+       }
+       else {
+               /* Only attach the watcher if full iteration is requested. */
+               watcher_attach(&ctx->px_watch, main_proxies_first());
+       }
+
+       return 0;
+}
+
+/* Handler for "show default-server [<backend>] command.
+ * Returns 1 on completion or 0 to yield due to output blocked.
+ */
+static int cli_io_handler_show_default_server(struct appctx *appctx)
+{
+       struct show_be_ctx *ctx = appctx->svcctx;
+       struct server *defsrv;
+       int prefix;
+
+       for (; ctx->px; watcher_next(&ctx->px_watch, main_proxies_next(ctx->px))) {
+               chunk_reset(&trash);
+               prefix = 1;
+
+               /* servers are only in backends */
+               if ((ctx->px->cap & PR_CAP_BE) && !(ctx->px->cap & PR_CAP_INT)) {
+                       /* Dump unnamed default-server if allocated. */
+                       if (ctx->px->defsrv) {
+                               chunk_appendf(&trash, "* %s\n", ctx->px->id);
+                               prefix = 0;
+                       }
+
+                       /* Dump named default-server instances. */
+                       for (defsrv = cebuis_item_first(&ctx->px->defsrv_by_name, conf.name_node, id, struct server);
+                            defsrv; defsrv = cebuis_item_next(&ctx->px->defsrv_by_name, conf.name_node, id, defsrv)) {
+                               chunk_appendf(&trash, "%s %s/%s\n",
+                                             prefix ? "*" : " ", ctx->px->id, defsrv->id);
+                               prefix = 0;
+                       }
+
+                       if (STRESS_RUN1(applet_putchk_stress(appctx, &trash) == -1,
+                                       applet_putchk(appctx, &trash) == -1)) {
+                               return 0;
+                       }
+               }
+
+               /* Watcher is not attached if a specific backend has been requested. */
+               if (!watcher_is_attached(&ctx->px_watch))
+                       break;
+       }
+
+       return 1;
+}
 
 /* parse a "show servers [state|conn]" CLI line, returns 0 if it wants to start
  * the dump or 1 if it stops immediately. If an argument is specified, it will
@@ -5453,6 +5522,7 @@ static struct cli_kw_list cli_kws = {{ },{
        { { "enable", "frontend",  NULL },                  "enable frontend <frontend>              : re-enable specific frontend",                                    cli_parse_enable_frontend, NULL, NULL },
        { { "publish", "backend",  NULL },                  "publish backend <backend>               : mark backend as ready for traffic",                              cli_parse_publish_backend, NULL, NULL },
        { { "set", "maxconn", "frontend",  NULL },          "set maxconn frontend <frontend> <value> : change a frontend's maxconn setting",                            cli_parse_set_maxconn_frontend, NULL },
+       { { "show", "default-server", NULL },               "show default-server [<backend>]         : list default-server instances in all or a single backend",       cli_parse_show_default_server, cli_io_handler_show_default_server, },
        { { "show","servers", "conn",  NULL },              "show servers conn [<backend>]           : dump server connections status (all or for a single backend)",   cli_parse_show_servers, cli_io_handler_servers_state },
        { { "show","servers", "state",  NULL },             "show servers state [<backend>]          : dump volatile server information (all or for a single backend)", cli_parse_show_servers, cli_io_handler_servers_state },
        { { "show", "backend", NULL },                      "show backend                            : list backends in the current running config", NULL,              cli_io_handler_show_backend },