]> git.kaiwu.me - haproxy.git/commitdiff
MINOR: server: set maintenance mode on "purge server"
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 21 Sep 2026 08:36:36 +0000 (10:36 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 14 Oct 2026 09:33:40 +0000 (11:33 +0200)
This patch changes behavior of "purge server" to automatically set a
server in maintenance mode if needed. This is not performed if a server
cannot be removed due to a configuration limitation.

The objective is to improve the user API. While not a big change in the
context of a single "purge server", automatic maintenance mode will
become a must have for the future "purge all servers". Thus, this change
allow guaranteeing a similar behavior between these two commands.

To implement it, a new argument is added to srv_check_for_deletion(),
indicating the deletion mode. For better code clarity, this is defined
as an enum type pr_del_mode.

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

index 3e2cca5c830aad6a4386edb2b9d14f885fce8388..7d41abd68021ad3e43690f7e6fdb4807348619bf 100644 (file)
@@ -2601,8 +2601,9 @@ purge server <backend>/<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
   connections, the server is flagged for background deletion instead of
-  rejecting the command. A scheduled deletion is cancelled if the server state
-  is explicitly reset, even if still in maintenance mode.
+  rejecting the command. To succeed, this also automatically puts the server
+  into maintenance if needed. A scheduled deletion is cancelled if the server
+  state is explicitly reset, even if still in maintenance mode.
 
 quit
   Close the connection when in interactive mode.
index d45d8731d9a62780d9b59591c2387f78b2d6b5cc..7b1b0148f6337781eda809487d514dd00bcbcb84 100644 (file)
@@ -60,6 +60,12 @@ enum pr_mode {
        PR_MODE_SPOP   = 0x20,
 } __attribute__((packed));
 
+/* Runtime deletion mode of operation */
+enum pr_del_mode {
+       PR_DEL_MODE_SYNC,
+       PR_DEL_MODE_ASYNC,
+};
+
 enum PR_SRV_STATE_FILE {
        PR_SRV_STATE_FILE_UNSPEC = 0,
        PR_SRV_STATE_FILE_NONE,
index 0f80a946755e0d3743ca07741361bd10eaefea15..6044152f2dcbb2f3f4125fd58cfb004cc54d1000 100644 (file)
@@ -96,7 +96,8 @@ const char *srv_adm_st_chg_cause(enum srv_adm_st_chg_cause cause);
 const char *srv_op_st_chg_cause(enum srv_op_st_chg_cause cause);
 void srv_event_hdl_publish_check(struct server *srv, struct check *check);
 
-int srv_check_for_deletion(const char *bename, const char *svname, struct proxy **pb, struct server **ps, const char **pm);
+int srv_check_for_deletion(const char *bename, const char *svname, enum pr_del_mode del_mode,
+                           struct proxy **pb, struct server **ps, const char **pm);
 void srv_unregister(struct server *srv);
 
 /* functions related to server name resolution */
index 21a23a1fb43da372bb391c1eaded9bbb06b51ed5..f7ad9cf79c27a2c341f2471e9fce73fa27003622 100644 (file)
--- a/src/cli.c
+++ b/src/cli.c
@@ -2545,7 +2545,7 @@ static int cli_io_handler_wait(struct appctx *appctx)
            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);
+                       ret = srv_check_for_deletion(ctx->args[0], ctx->args[1], PR_DEL_MODE_SYNC, NULL, NULL, &ctx->msg);
                }
                else {
                        ret = be_check_for_deletion(ctx->args[0], NULL, &ctx->msg);
index e29b9e7a6762bbf0e8f839308bf2305b937cb3a2..f9fe785c6dc65cdd1d58a06246933178ae02da95 100644 (file)
@@ -6909,19 +6909,29 @@ out:
        return 1;
 }
 
-/* Check if the server <bename>/<svname> exists and is ready for being deleted.
- * This means that the server is in maintenance with no streams attached to it,
- * no queue and no used idle conns. This is not supposed to change during all
- * the maintenance phase (except for force-persist etc, which are not covered).
- * Both <bename> and <svname> must be valid strings. If pb/ps are not null,
+/* Checks if the server <bename>/<svname> exists and is ready for being
+ * deleted. This means that the server is in maintenance with no streams
+ * attached to it, no queue and no used idle conns. This is not supposed to
+ * change during all the maintenance phase (except for force-persist etc, which
+ * are not covered). Both <bename> and <svname> must be valid strings.
+ *
+ * Input parameter <del_mode> indicates if the server deletion should be
+ * conducted immediately or could be performed in background. In the latter
+ * case, maintenance mode is set on the server if needed, instead of rejecting
+ * the deletion.
+ *
+ * If <pb>/<ps> are not null,
  * upon success, the pointer to the backend and server respectively will be put
- * there. If pm is not null, a pointer to an error/success message is returned
- * there (possibly NULL if nothing to say). Returned values:
- *  >0 if OK
- *   0 if not yet (should wait if it can)
- *  <0 if not possible
+ * there. If <pm> is not null, a pointer to an error/success message is returned
+ * there (possibly NULL if nothing to say).
+ *
+ * Returns a positive value if server can be deleted. If not possible, 0 is
+ * returned if removal is temporarily blocked. A negative value is used if
+ * removal is blocked indefinitely due to its configuration or that it requires
+ * an administrative interaction.
  */
-int srv_check_for_deletion(const char *bename, const char *svname, struct proxy **pb, struct server **ps, const char **pm)
+int srv_check_for_deletion(const char *bename, const char *svname, enum pr_del_mode del_mode,
+                           struct proxy **pb, struct server **ps, const char **pm)
 {
        struct server *srv = NULL;
        struct proxy *be = NULL;
@@ -6951,8 +6961,13 @@ int srv_check_for_deletion(const char *bename, const char *svname, struct proxy
         * lbprm.ops->set_server_status_down).
         */
        if (!(srv->cur_admin & SRV_ADMF_MAINT)) {
-               msg = "Only servers in maintenance mode can be deleted.";
-               goto leave;
+               if (del_mode == PR_DEL_MODE_SYNC) {
+                       msg = "Only servers in maintenance mode can be deleted.";
+                       goto leave;
+               }
+
+               /* Automatically set server in maintenance for background deletion. */
+               srv_adm_set_maint(srv);
        }
 
        /* Second, conditions that may change over time */
@@ -7088,7 +7103,7 @@ static int cli_parse_delete_server(char **args, char *payload, struct appctx *ap
                goto out;
        }
 
-       ret = srv_check_for_deletion(be_name, sv_name, &be, &srv, &msg);
+       ret = srv_check_for_deletion(be_name, sv_name, PR_DEL_MODE_SYNC, &be, &srv, &msg);
        if (ret <= 0) {
                /* failure (recoverable or not) */
                cli_err(appctx, msg);
@@ -7129,7 +7144,7 @@ static int cli_parse_purge_server(char **args, char *payload, struct appctx *app
                goto out;
        }
 
-       ret = srv_check_for_deletion(be_name, sv_name, &be, &srv, &msg);
+       ret = srv_check_for_deletion(be_name, sv_name, PR_DEL_MODE_ASYNC, &be, &srv, &msg);
        if (ret < 0) {
                /* Unremovable server, cancel purge. */
                cli_err(appctx, msg);