From: Amaury Denoyelle Date: Thu, 30 Jul 2026 12:42:43 +0000 (+0200) Subject: MINOR: proxy: implement "show default-server" X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c93862d80f4c4e67aac19c851d612a058be8e77a;p=thirdparty%2Fhaproxy.git MINOR: proxy: implement "show default-server" 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. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index eeca5b44f..3050e155c 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -4237,7 +4237,8 @@ tune.defaults.purge [] 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 ] [from ] [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 diff --git a/doc/management.txt b/doc/management.txt index 5de0b3cbb..8c2b8abd5 100644 --- a/doc/management.txt +++ b/doc/management.txt @@ -1813,7 +1813,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 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 [] + 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 diff --git a/reg-tests/server/from_keyword.vtc b/reg-tests/server/from_keyword.vtc index 6467a6a01..78a5e9570 100644 --- a/reg-tests/server/from_keyword.vtc +++ b/reg-tests/server/from_keyword.vtc @@ -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" +} diff --git a/src/proxy.c b/src/proxy.c index 8ec08a5df..34a99aaac 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -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 [] 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 [] 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 : re-enable specific frontend", cli_parse_enable_frontend, NULL, NULL }, { { "publish", "backend", NULL }, "publish backend : mark backend as ready for traffic", cli_parse_publish_backend, NULL, NULL }, { { "set", "maxconn", "frontend", NULL }, "set maxconn frontend : change a frontend's maxconn setting", cli_parse_set_maxconn_frontend, NULL }, + { { "show", "default-server", NULL }, "show default-server [] : 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 [] : 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 [] : 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 },