From: Amaury Denoyelle Date: Mon, 21 Sep 2026 15:45:26 +0000 (+0200) Subject: MEDIUM: server: implement "purge all servers" CLI X-Git-Tag: v3.5-dev9~10 X-Git-Url: https://git.kaiwu.me/$%7BGITURL%7D$%7Bcid%7D?a=commitdiff_plain;h=d4d8a762a0fd;p=haproxy.git MEDIUM: server: implement "purge all servers" CLI Implement a new CLI command "purge all servers ". It tries to delete every server present in a backend or if not possible flag them for background deletion. If the deletion is impossible due to a specific configuration of the server, the instance is skipped and the following entries are handled. At the end of the iteration, a summary is displayed on the CLI with the number of servers deleted, flagged and skipped. If at least one server is flagged for background deletion, proxy purge task is scheduled. The command runs via a parser and a handler. While it is not strictly necessary currently, this will serve as a skeleton to implement yielding. --- diff --git a/doc/management.txt b/doc/management.txt index fc3270bb0..b4070ed72 100644 --- a/doc/management.txt +++ b/doc/management.txt @@ -2597,6 +2597,11 @@ publish backend operation of "unpublish backend" command. This command is restricted and can only be issued on sockets configured for levels "operator" or "admin". +purge all servers + Removes or schedules deletion of all servers in a target backend. This is + equivalent to using "purge server" on each entry. If a server cannot be + removed due to configuration limitation, it is skipped. + purge server / This is an alternative command to "del server". Its main difference is that if the server cannot be immediately removed due to remaining active or idle diff --git a/src/server.c b/src/server.c index 8031d6b13..2bab37dfd 100644 --- a/src/server.c +++ b/src/server.c @@ -7182,6 +7182,105 @@ static int cli_parse_purge_server(char **args, char *payload, struct appctx *app return 1; } +struct purge_all_servers_ctx { + char *bename; +}; + +/* Parser for "purge all servers" CLI command. Prepare context for performing + * the required task in a dedicated handler. + * + * Returns 0 in normal cases to let the handler run, or 1 for an invalid + * argument. + */ +static int cli_parse_purge_all_servers(char **args, char *payload, struct appctx *appctx, void *private) +{ + struct purge_all_servers_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx)); + + if (!cli_has_level(appctx, ACCESS_LVL_ADMIN)) + return 1; + + if (!*args[3]) + return cli_err(appctx, "A backend name is expected.\n"); + + /* Perform a first lookup to immediately detect a non existing backend. */ + if (!proxy_be_by_name(args[3])) + return cli_err(appctx, "No such backend.\n"); + + ctx->bename = strdup(args[3]); + if (!ctx->bename) + return cli_err(appctx, "Out of memory.\n"); + + return 0; +} + +/* Handler for "purge all servers" CLI command. */ +static int cli_io_handler_purge_all_server(struct appctx *appctx) +{ + struct purge_all_servers_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx)); + struct proxy *be; + struct server *srv, *srvtmp; + int c0 = 0, c1 = 0, c2 = 0; + int ret; + + chunk_reset(&trash); + + thread_isolate_full(); + + be = proxy_be_by_name(ctx->bename); + if (!be) { + chunk_printf(&trash, "Command interrupted by backend deletion.\n"); + ret = 1; + goto out; + } + + list_for_each_entry_safe(srv, srvtmp, &be->servers, el_px) { + if (srv->flags & (SRV_F_NON_PURGEABLE | SRV_F_NAME_REFD)) { + ++c2; + continue; + } + + if (!(srv->cur_admin & SRV_ADMF_MAINT)) + srv_adm_set_maint(srv); + + if (srv_in_use(srv)) { + if (!LIST_INLIST(&srv->el_alt)) + LIST_APPEND(&be->servers_purge, &srv->el_alt); + srv->flags |= SRV_F_TO_PURGE; + ha_notice("Server '%s/%s' flagged for deletion.\n", be->id, srv->id); + ++c1; + } + else { + srv_unregister(srv); + ha_notice("Server '%s/%s' deleted.\n", be->id, srv->id); + srv_drop(srv); + ++c0; + } + } + + if (c1) { + if (!tick_isset(be->purge_task->expire)) + be->purge_task->expire = tick_add(now_ms, 1000); + task_queue(be->purge_task); + } + + chunk_printf(&trash, "Servers backend iteration performed: " + "%d removed, %d scheduled, %d skipped.\n", + c0, c1, c2); + ret = 1; + + out: + if (applet_putchk(appctx, &trash) < 0) + ret = 0; + thread_release(); + return ret; +} + +static void cli_release_purge_all_servers(struct appctx *appctx) +{ + struct purge_all_servers_ctx *ctx = applet_reserve_svcctx(appctx, sizeof(*ctx)); + ha_free(&ctx->bename); +} + /* Reset the statistics counters of a single server, invoked from the * "clear counters server / [force]" CLI command (dispatched * by cli_parse_clear_counters() in stats.c, since "clear counters" is a @@ -7249,6 +7348,7 @@ static struct cli_kw_list cli_kws = {{ },{ { { "add", "server", NULL }, "add server / : create a new server", cli_parse_add_server, cli_io_handler_add_server }, { { "del", "server", NULL }, "del server / : remove a server", cli_parse_delete_server, NULL }, { { "purge", "server", NULL }, "purge server / : remove on background a server", cli_parse_purge_server, NULL }, + { { "purge", "all", "servers", NULL }, "purge all servers : remove all servers from a backend", cli_parse_purge_all_servers, cli_io_handler_purge_all_server, cli_release_purge_all_servers }, {{},} }};