From: Amaury Denoyelle Date: Wed, 9 Sep 2026 14:36:46 +0000 (+0200) Subject: MINOR: server: extract unregistering from "delete server" CLI parser X-Git-Tag: v3.5-dev9~19 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=aa8e3eefa6077218f4c8d5359e046a266d8d0627;p=haproxy.git MINOR: server: extract unregistering from "delete server" CLI parser Extract the code which performs the server deletion from the "del server" CLI parser in a new function named srv_unregister(). Its purpose is to ensure that a server is detached from any visible elements, most notably the parent proxy list and name tree, and the global GUID tree. This step is mandatory to remove a server at runtime but is skipped on deinit. This reorg allows to implement alternative method for server deletion at runtime. This will be useful for the future "purge server" CLI command. --- diff --git a/include/haproxy/server.h b/include/haproxy/server.h index b0c9526c5..e5e7f2d96 100644 --- a/include/haproxy/server.h +++ b/include/haproxy/server.h @@ -94,7 +94,9 @@ int srv_set_ssl(struct server *s, int use_ssl); 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); +void srv_unregister(struct server *srv); /* functions related to server name resolution */ int srv_prepare_for_resolution(struct server *srv, const char *hostname); diff --git a/src/server.c b/src/server.c index 6bc9f3490..bda1e856f 100644 --- a/src/server.c +++ b/src/server.c @@ -6979,41 +6979,28 @@ leave: return ret; } -/* Parse a "del server" command - * Returns 0 if the server has been successfully initialized, 1 on failure. +/* Removes server from its various attach points in other objects, most + * notably in its parent proxy and global trees. This liberates the server name + * slot in the proxy and the global GUID value which can be reused by a newly + * added instance. This also schedules deletion of any active check and + * agent-check. + * + * This operation is mandatory prior the runtime removal of a server. Once + * detached, the server is flagged for deletion and the associated event is + * published. The server instance will be finally freed when its refcount + * reaches zero. + * + * This function cannot fail. This operation is not thread-safe and must only + * be called under thread isolation. */ -static int cli_parse_delete_server(char **args, char *payload, struct appctx *appctx, void *private) +void srv_unregister(struct server *srv) { - struct proxy *be; - struct server *srv, *next; + struct server *next; struct watcher *srv_watch; - const char *be_name, *sv_name, *msg; - int ret; - - if (!cli_has_level(appctx, ACCESS_LVL_ADMIN)) - return 1; - - ++args; - - /* The proxy servers list is currently not protected by a lock so this - * requires thread isolation. In addition, any place referencing the - * server about to be deleted would be unsafe after our operation, so - * we must be certain to be alone so that no other thread has even - * started to grab a temporary reference to this server. - */ - thread_isolate_full(); - - if (parse_be_srv(args[1], &be_name, &sv_name, &msg)) { - cli_err(appctx, msg); - goto out; - } + int i; - ret = srv_check_for_deletion(be_name, sv_name, &be, &srv, &msg); - if (ret <= 0) { - /* failure (recoverable or not) */ - cli_err(appctx, msg); - goto out; - } + /* Only servers in maintenance can be deleted at runtime. */ + BUG_ON(!(srv->cur_admin & SRV_ADMF_MAINT)); /* removing cannot fail anymore when we reach this: * publishing EVENT_HDL_SUB_SERVER_DEL @@ -7033,6 +7020,7 @@ static int cli_parse_delete_server(char **args, char *payload, struct appctx *ap if (srv->proxy->lbprm.ops && srv->proxy->lbprm.ops->server_deinit) srv->proxy->lbprm.ops->server_deinit(srv); + /* reattach all currently present watchers to the next proxy server */ next = proxy_next_server(srv); BUG_ON(next && next->flags & SRV_F_DELETED); while (!MT_LIST_ISEMPTY(&srv->watcher_list)) { @@ -7040,10 +7028,7 @@ static int cli_parse_delete_server(char **args, char *payload, struct appctx *ap watcher_next(srv_watch, next); } - /* detach the server from the proxy linked list - * The proxy servers list is currently not protected by a lock, so this - * requires thread_isolate/release. - */ + /* detach the server from the proxy linked list */ srv_detach(srv); /* Mark the server as being deleted (ie removed from its proxy list) @@ -7057,22 +7042,59 @@ static int cli_parse_delete_server(char **args, char *payload, struct appctx *ap proxy_take(srv->proxy); /* remove srv from proxy trees (IDs, names and addresses) */ - if (srv->puid < be->conf.first_unused_id) - be->conf.first_unused_id = srv->puid; // search from there for next add. - ceb32_item_delete(&be->conf.used_server_id, conf.puid_node, puid, srv); - cebuis_item_delete(&be->conf.used_server_name, conf.name_node, id, srv); - cebuis_item_delete(&be->used_server_addr, addr_node, addr_key, srv); + if (srv->puid < srv->proxy->conf.first_unused_id) + srv->proxy->conf.first_unused_id = srv->puid; // search from there for next add. + ceb32_item_delete(&srv->proxy->conf.used_server_id, conf.puid_node, puid, srv); + cebuis_item_delete(&srv->proxy->conf.used_server_name, conf.name_node, id, srv); + cebuis_item_delete(&srv->proxy->used_server_addr, addr_node, addr_key, srv); /* remove srv from global GUID tree */ guid_remove(&srv->guid); /* remove srv from global tree for idle conn cleanup */ - for (ret = 0; ret < global.nbthread; ret++) - eb32_delete(&srv->per_thr[ret].idle_node); + for (i = 0; i < global.nbthread; ++i) + eb32_delete(&srv->per_thr[i].idle_node); /* set LSB bit (odd bit) for reuse_cnt */ srv_id_reuse_cnt |= 1; +} + +/* Parse a "del server" command + * Returns 0 if the server has been successfully initialized, 1 on failure. + */ +static int cli_parse_delete_server(char **args, char *payload, struct appctx *appctx, void *private) +{ + struct proxy *be; + struct server *srv; + const char *be_name, *sv_name, *msg; + int ret; + + if (!cli_has_level(appctx, ACCESS_LVL_ADMIN)) + return 1; + + ++args; + + /* The proxy servers list is currently not protected by a lock so this + * requires thread isolation. In addition, any place referencing the + * server about to be deleted would be unsafe after our operation, so + * we must be certain to be alone so that no other thread has even + * started to grab a temporary reference to this server. + */ + thread_isolate_full(); + + if (parse_be_srv(args[1], &be_name, &sv_name, &msg)) { + cli_err(appctx, msg); + goto out; + } + + ret = srv_check_for_deletion(be_name, sv_name, &be, &srv, &msg); + if (ret <= 0) { + /* failure (recoverable or not) */ + cli_err(appctx, msg); + goto out; + } + srv_unregister(srv); thread_release(); ha_notice("Server deleted.\n");