MINOR: proxy: define a basic "del backend" CLI

Add "del backend" handler which is restricted to admin level. Along with
it, a new function be_check_for_deletion() is used to test if the
backend is removable.
This commit is contained in:
Amaury Denoyelle 2026-01-06 11:40:05 +01:00
parent d166894fef
commit 08623228a1
3 changed files with 106 additions and 0 deletions

View File

@ -2124,6 +2124,16 @@ del acl <acl> [<key>|#<ref>]
listing the content of the acl. Note that if the reference <acl> is a name and
is shared with a map, the entry will be also deleted in the map.
del backend <name>
Removes the backend proxy with the name <name>.
This operation is only possible for TCP or HTTP proxies. To succeed, the
backend instance must have been first unpublished.
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").
del map <map> [<key>|#<ref>]
Delete all the map entries from the map <map> corresponding to the key <key>.
<map> is the #<id> or the <name> returned by "show map". If the <ref> is used,

View File

@ -101,6 +101,8 @@ void free_server_rules(struct list *srules);
int proxy_init_per_thr(struct proxy *px);
int proxy_finalize(struct proxy *px, int *err_code);
int be_check_for_deletion(const char *bename, struct proxy **pb, const char **pm);
/*
* This function returns a string containing the type of the proxy in a format
* suitable for error messages, from its capabilities.

View File

@ -4970,6 +4970,99 @@ static int cli_parse_add_backend(char **args, char *payload, struct appctx *appc
return 1;
}
/* Test if the backend instance named <bename> can be deleted.
*
* Returns a positive integer if backend can be deleted. Else, 0 is returned if
* backend should be deletable after some delay. A negative value indicates
* that backend cannot be deleted without any external action.
*
* If <pb> is not NULL, it will be set to point to the backend instance if name
* is found. If <pm> is not NULL, it will be used on error to point to the
* description failure.
*/
int be_check_for_deletion(const char *bename, struct proxy **pb, const char **pm)
{
struct proxy *be = NULL;
const char *msg = NULL;
int ret;
/* First, unrecoverable errors */
ret = -1;
if (!(be = proxy_be_by_name(bename))) {
msg = "No such backend.";
goto out;
}
if (be->cap & PR_CAP_FE) {
msg = "Cannot delete a listen section.";
goto out;
}
if (be->mode != PR_MODE_TCP && be->mode != PR_MODE_HTTP) {
msg = "Only TCP or HTTP proxies can be removed at runtime.";
goto out;
}
if (!(be->flags & PR_FL_BE_UNPUBLISHED)) {
msg = "Backend must be unpublished prior to its deletion.";
goto out;
}
/* Second, conditions that may change over time */
ret = 0;
if (be->beconn) {
msg = "Backend still has attached streams on it.";
goto out;
}
ret = 1;
out:
if (pb)
*pb = be;
if (pm)
*pm = msg;
return ret;
}
/* Handler for "delete backend". Runs under thread isolation. Always returns 1. */
static int cli_parse_delete_backend(char **args, char *payload, struct appctx *appctx, void *private)
{
struct proxy *px;
const char *msg;
char *be_name;
int ret;
if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
return 1;
if (*args[3]) {
cli_err(appctx, "Usage: del backend <name>.\n");
return 1;
}
thread_isolate_full();
be_name = args[2];
ret = be_check_for_deletion(be_name, &px, &msg);
if (ret <= 0) {
cli_err(appctx, msg);
goto out;
}
thread_release();
ha_notice("Backend deleted.\n");
cli_umsg(appctx, LOG_INFO);
return 1;
out:
thread_release();
return 1;
}
/* Parses the "disable frontend" directive, it always returns 1.
*
* Grabs the proxy lock.
@ -5292,6 +5385,7 @@ static int cli_io_handler_show_errors(struct appctx *appctx)
/* register cli keywords */
static struct cli_kw_list cli_kws = {{ },{
{ { "add", "backend", NULL }, "add backend <backend> : add a new backend", cli_parse_add_backend, NULL, NULL, NULL, ACCESS_EXPERIMENTAL },
{ { "del", "backend", NULL }, "del backend <backend> : delete a backend", cli_parse_delete_backend, NULL, NULL, NULL, ACCESS_EXPERIMENTAL },
{ { "disable", "frontend", NULL }, "disable frontend <frontend> : temporarily disable specific frontend", cli_parse_disable_frontend, NULL, NULL },
{ { "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 },