-
Notifications
You must be signed in to change notification settings - Fork 0
Set server name implementation #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 3 commits
6209d62
2c352da
a75d7dc
09a266a
31b6ba5
97425b4
42ca0ac
c45a814
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -56,6 +56,8 @@ | |
| #include <haproxy/tools.h> | ||
| #include <haproxy/xxhash.h> | ||
| #include <haproxy/event_hdl.h> | ||
| #include <haproxy/stick_table-t.h> | ||
| #include <haproxy/peers-t.h> | ||
|
|
||
| static void srv_update_status(struct server *s, int type, int cause); | ||
| static int srv_apply_lastaddr(struct server *srv, int *err_code); | ||
|
|
@@ -5397,6 +5399,114 @@ const char *srv_update_fqdn(struct server *server, const char *fqdn, const char | |
| } | ||
|
|
||
|
|
||
| /* Rename a server at runtime. This function handles all precondition checks, | ||
| * tree re-indexing under thread_isolate(), and event publication. | ||
| * | ||
| * The caller must NOT hold any lock — this function uses thread_isolate() | ||
| * internally for tree manipulation. | ||
| * | ||
| * Preconditions enforced: | ||
| * - backend must have "option server-rename" set | ||
| * - server must be administratively in maintenance | ||
| * - new name must not conflict with an existing server in the backend | ||
| * - new name must be syntactically valid (no spaces, '/', '#' prefix) | ||
| * - backend must not have sticking rules referencing a peer-synced table | ||
| * | ||
| * Returns NULL on success, or a pointer to a static/trash error message | ||
| * string on failure. On success, a ha_notice() is emitted and the | ||
| * EVENT_HDL_SUB_SERVER_NAME event is published. | ||
| */ | ||
| static const char *srv_update_server_name(struct server *srv, const char *new_name) | ||
| { | ||
| struct proxy *be = srv->proxy; | ||
| struct sticking_rule *rule; | ||
| char *old_name; | ||
| char *dup; | ||
| const char *p; | ||
|
|
||
| /* validate the new name is not empty */ | ||
| if (!*new_name) | ||
| return "Require a new server name.\n"; | ||
|
|
||
| /* reject names starting with '#' (numeric ID syntax in server_find) */ | ||
| if (*new_name == '#') | ||
| return "Server name must not start with '#'.\n"; | ||
|
|
||
| /* reject control characters, spaces, and '/' which break CLI parsing */ | ||
| for (p = new_name; *p; p++) { | ||
| if ((unsigned char)*p <= ' ' || *p == '/') | ||
| return "Server name must not contain spaces, control characters, or '/'.\n"; | ||
| } | ||
|
Comment on lines
+5517
to
+5521
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there no utility function for this task?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I searched again, but I couldn't find any helper like that sadly. |
||
|
|
||
| /* per-backend opt-in required */ | ||
| if (!(be->options3 & PR_O3_SRV_RENAME)) | ||
| return "Backend does not allow server renaming (add 'option server-rename').\n"; | ||
|
|
||
| /* server must be administratively down (in maintenance) */ | ||
| if (!(srv->cur_admin & SRV_ADMF_MAINT)) | ||
| return "Server must be in maintenance mode to be renamed (set server <b>/<s> state maint).\n"; | ||
|
|
||
| /* reject if any sticking rule references a peer-synced table */ | ||
| list_for_each_entry(rule, &be->sticking_rules, list) { | ||
| if (rule->table.t && rule->table.t->peers.p) | ||
| return "Cannot rename: backend has sticking rules using a peer-synced table.\n"; | ||
| } | ||
| list_for_each_entry(rule, &be->storersp_rules, list) { | ||
| if (rule->table.t && rule->table.t->peers.p) | ||
| return "Cannot rename: backend has store-response rules using a peer-synced table.\n"; | ||
| } | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Length of new server name is not checked. |
||
| /* same name is a no-op success */ | ||
| if (strcmp(srv->id, new_name) == 0) | ||
| return NULL; | ||
|
|
||
| /* allocate new name before taking isolation */ | ||
| dup = strdup(new_name); | ||
| if (!dup) | ||
| return "Out of memory allocating new server name.\n"; | ||
|
|
||
| /* tree manipulation requires thread isolation (same pattern as | ||
| * add/del server). This is rare enough that the cost is acceptable. | ||
| */ | ||
| thread_isolate(); | ||
|
|
||
| /* re-check for name conflict under isolation — another rename or | ||
| * add server could have raced before we isolated. | ||
| */ | ||
| if (server_find_by_name(be, new_name)) { | ||
| thread_release(); | ||
| free(dup); | ||
| return "A server with the same name already exists in this backend.\n"; | ||
| } | ||
|
|
||
| /* --- point of no return --- */ | ||
|
|
||
| old_name = srv->id; | ||
|
|
||
| /* re-index in the name tree */ | ||
| cebis_item_delete(&be->conf.used_server_name, conf.name_node, id, srv); | ||
| srv->id = dup; | ||
| cebis_item_insert(&be->conf.used_server_name, conf.name_node, id, srv); | ||
|
|
||
| /* publish rename event with both old and new names */ | ||
| { | ||
| struct event_hdl_cb_data_server_name cb_data; | ||
|
|
||
| _srv_event_hdl_prepare(&cb_data.server, srv, 1); | ||
| snprintf(cb_data.safe.old_name, sizeof(cb_data.safe.old_name), "%s", old_name); | ||
| snprintf(cb_data.safe.new_name, sizeof(cb_data.safe.new_name), "%s", new_name); | ||
| _srv_event_hdl_publish(EVENT_HDL_SUB_SERVER_NAME, cb_data, srv); | ||
| } | ||
|
|
||
| thread_release(); | ||
|
|
||
| ha_notice("Server %s/%s renamed from '%s'.\n", be->id, srv->id, old_name); | ||
| free(old_name); | ||
|
|
||
| return NULL; | ||
| } | ||
|
|
||
|
|
||
| /* Expects to find a backend and a server in <arg> under the form <backend>/<server>, | ||
| * and returns the pointer to the server. Otherwise, display adequate error messages | ||
| * on the CLI, sets the CLI's state to CLI_ST_PRINT and returns NULL. This is only | ||
|
|
@@ -5654,11 +5764,26 @@ static int cli_parse_set_server(char **args, char *payload, struct appctx *appct | |
| #else | ||
| cli_msg(appctx, LOG_NOTICE, "server ssl setting not supported.\n"); | ||
| #endif | ||
| } else { | ||
| } | ||
| else if (strcmp(args[3], "name") == 0) { | ||
| if (!*args[4]) { | ||
| cli_err(appctx, "set server <b>/<s> name requires a new name.\n"); | ||
| goto out; | ||
| } | ||
| /* srv_update_server_name() handles its own locking via | ||
| * thread_isolate(), so do NOT hold the server lock here. | ||
| */ | ||
| warning = srv_update_server_name(sv, args[4]); | ||
| if (warning) | ||
| cli_err(appctx, warning); | ||
| else | ||
| cli_msg(appctx, LOG_NOTICE, "Server name updated.\n"); | ||
| } | ||
| else { | ||
| cli_err(appctx, | ||
| "usage: set server <backend>/<server> " | ||
| "addr | agent | agent-addr | agent-port | agent-send | " | ||
| "check-addr | check-port | fqdn | health | ssl | " | ||
| "check-addr | check-port | fqdn | health | name | ssl | " | ||
| "state | weight\n"); | ||
| } | ||
| out: | ||
|
|
@@ -6533,7 +6658,7 @@ static struct cli_kw_list cli_kws = {{ },{ | |
| { { "enable", "health", NULL }, "enable health : enable health checks", cli_parse_enable_health, NULL }, | ||
| { { "enable", "server", NULL }, "enable server (DEPRECATED) : enable a disabled server (use 'set server' instead)", cli_parse_enable_server, NULL }, | ||
| { { "set", "maxconn", "server", NULL }, "set maxconn server <bk>/<srv> : change a server's maxconn setting", cli_parse_set_maxconn_server, NULL }, | ||
| { { "set", "server", NULL }, "set server <bk>/<srv> [opts] : change a server's state, weight, address or ssl", cli_parse_set_server }, | ||
| { { "set", "server", NULL }, "set server <bk>/<srv> [opts] : change a server's state, weight, address, name or ssl", cli_parse_set_server }, | ||
| { { "get", "weight", NULL }, "get weight <bk>/<srv> : report a server's current weight", cli_parse_get_weight }, | ||
| { { "set", "weight", NULL }, "set weight <bk>/<srv> (DEPRECATED) : change a server's weight (use 'set server' instead)", cli_parse_set_weight }, | ||
| { { "add", "server", NULL }, "add server <bk>/<srv> : create a new server", cli_parse_add_server, cli_io_handler_add_server }, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The imports are sorted