]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: cli: implement wait on be-removable
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 18 Feb 2026 13:00:08 +0000 (14:00 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 2 Mar 2026 13:08:30 +0000 (14:08 +0100)
Implement be-removable argument to CLI wait. This is implemented via
be_check_for_deletion() invokation, also used by "del backend" handler.

The objective is to test whether a backend instance can be removed. If
this is not the case, the command may returns immediately if the target
proxy is incompatible with dynamic removal or if a user action is
required. Else, the command will wait until the temporary restriction is
lifted.

doc/management.txt
include/haproxy/cli-t.h
src/cli.c

index 82f89305b20ce1786a04a62d7581b58a01df2a0a..9cae22aae2a0a6b26ce291f66b1def2b2a001ad5 100644 (file)
@@ -2129,7 +2129,8 @@ del backend <name>
 
   This operation is only possible for TCP or HTTP proxies. To succeed, the
   backend instance must have been first unpublished. Also, all of its servers
-  must first be removed (via "del server" CLI).
+  must first be removed (via "del server" CLI). Finally, no stream must still
+  be attached to the backend instance.
 
   There is additional restrictions which prevent backend removal. First, a
   backend cannot be removed if it is explicitely referenced by config elements,
@@ -2139,6 +2140,10 @@ del backend <name>
   cannot be removed if there is a stick-table declared in it. Finally, it is
   impossible for now to remove a backend if QUIC servers were present in it.
 
+  It can be useful to use "wait be-removable" prior to this command to check
+  for the aformentioned requisites. This also provides a methode to wait for
+  the final closure of the streams attached to the target backend.
+
   This command is restricted and can only be issued on sockets configured for
   level "admin". Moreover, this feature is still considered in development so it
   also requires experimental mode (see "experimental-mode on").
@@ -4545,6 +4550,13 @@ wait { -h | <delay> } [<condition> [<args>...]]
   specified condition to be satisfied, to unrecoverably fail, or to remain
   unsatisfied for the whole <delay> duration. The supported conditions are:
 
+  - be-removable <proxy> : this will wait for the specified proxy backend to be
+    removable by the "del backend" command. Some conditions will never be
+    accepted (e.g. backend not yet unpublished or with servers in it) and will
+    cause the report of a specific error message indicating what condition is
+    not met. If everything is OK before the delay, a success is returned and
+    the operation is terminated.
+
   - srv-removable <proxy>/<server> : this will wait for the specified server to
     be removable by the "del server" command, i.e. be in maintenance and no
     longer have any connection on it (neither active or idle). Some conditions
index a581f2a9460df1312703aed2c087916a6b2905c4..3332b6da68ca2d602527e13520593798cefbd6da 100644 (file)
@@ -100,6 +100,7 @@ enum cli_wait_err {
 enum cli_wait_cond {
        CLI_WAIT_COND_NONE,      // no condition to wait on
        CLI_WAIT_COND_SRV_UNUSED,// wait for server to become unused
+       CLI_WAIT_COND_BE_UNUSED, // wait for backend to become unused
 };
 
 struct cli_wait_ctx {
index ab5a008f37f0db71d7513b58aade2e98a6aa6ebc..312e2a2cb005dcc6200d480a824b9d99a31069f1 100644 (file)
--- a/src/cli.c
+++ b/src/cli.c
@@ -2120,6 +2120,14 @@ static int cli_parse_wait(char **args, char *payload, struct appctx *appctx, voi
                ctx->args[1] = ist0(sv_name);
                ctx->cond = CLI_WAIT_COND_SRV_UNUSED;
        }
+       else if (strcmp(args[2], "be-removable") == 0) {
+               if (!*args[3])
+                       return cli_err(appctx, "Missing backend name.\n");
+               ctx->args[0] = strdup(args[3]);
+               if (!ctx->args[0])
+                       return cli_err(appctx, "Out of memory trying to clone the backend name.\n");
+               ctx->cond = CLI_WAIT_COND_BE_UNUSED;
+       }
        else if (*args[2]) {
                /* show the command's help either upon request (-h) or error */
                err = "Usage: wait {-h|<duration>} [condition [args...]]\n"
@@ -2165,9 +2173,15 @@ static int cli_io_handler_wait(struct appctx *appctx)
 
        /* here we should evaluate our waiting conditions, if any */
 
-       if (ctx->cond == CLI_WAIT_COND_SRV_UNUSED) {
-               /* check if the server in args[0]/args[1] can be released now */
-               ret = srv_check_for_deletion(ctx->args[0], ctx->args[1], NULL, NULL, &ctx->msg);
+       if (ctx->cond == CLI_WAIT_COND_SRV_UNUSED ||
+           ctx->cond == CLI_WAIT_COND_BE_UNUSED) {
+               if (ctx->cond == CLI_WAIT_COND_SRV_UNUSED) {
+                       /* check if the server in args[0]/args[1] can be released now */
+                       ret = srv_check_for_deletion(ctx->args[0], ctx->args[1], NULL, NULL, &ctx->msg);
+               }
+               else {
+                       ret = be_check_for_deletion(ctx->args[0], NULL, &ctx->msg);
+               }
 
                if (ret < 0) {
                        /* unrecoverable failure */