]> git.kaiwu.me - haproxy.git/commitdiff
MINOR: mworker: assign a unique ID to the master process
authorWilly Tarreau <w@1wt.eu>
Tue, 15 Sep 2026 11:45:35 +0000 (13:45 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 16 Sep 2026 16:00:51 +0000 (18:00 +0200)
The master process now has a unique identifier, either generated at boot
as a time-ordered UUID (version 7), or inherited from the
HAPROXY_MASTER_ID environment variable when a valid one is already set
there (inherited from a previous master instance). An invalid value is
simply replaced by a generated one, since there is generally nothing the
user can do about it. The identifier is exported to the environment so
that it is both preserved by the next master upon reload (re-exec) and
visible from the worker, where it may be referenced as
"$HAPROXY_MASTER_ID" from the configuration.

The format is validated using guid_is_valid_fmt() so that it is exactly
the same as the one of the proxies' and servers' "guid": at most 127
characters among letters, digits, '.', ':', '-' and '_'.

Note that both mworker_reexec() and the worker restore their initial
environment before going further, so the variable has to be set again
after that point, hence the two extra setenv() calls, just like for a
few other such variables.

doc/configuration.txt
include/haproxy/global-t.h
src/haproxy.c
src/mworker.c

index 5fe5e4bfb1d4fb6a78ea7ed94898117e76955b71..7740b52e56ed3381e82e60c8808086ef8b93d473 100644 (file)
@@ -980,6 +980,7 @@ Some variables are marked as not usable and not modifiable:
   * HAPROXY_MWORKER
   * HAPROXY_CLI
   * HAPROXY_MASTER_CLI
+  * HAPROXY_MASTER_ID
   * HAPROXY_LOCALPEER
 
 Their values are undefined during configuration parsing, they are set later
@@ -1001,6 +1002,7 @@ modes:
   | HAPROXY_MWORKER           |    |    |      |     |  X  |  X  |
   | HAPROXY_CLI               |    |    |      |     |     |  X  |
   | HAPROXY_MASTER_CLI        |    |    |      |     |  X  |     |
+  | HAPROXY_MASTER_ID         |    | X  |      |     |  X  |  X  |
   | HAPROXY_LOCALPEER         |    | X  |      |     |     |  X  |
   | HAPROXY_HTTP_LOG_FMT      |    | X  |      |  X  |     |     |
   | HAPROXY_HTTP_CLF_LOG_FMT  |    | X  |      |  X  |     |     |
@@ -1060,6 +1062,15 @@ The variables in question are the following:
   * HAPROXY_MASTER_CLI: In master-worker mode, listeners addresses of the master
     CLI, separated by semicolons.
 
+  * HAPROXY_MASTER_ID: In master-worker mode, unique identifier of the master
+    process. A time-ordered UUID (version 7) is generated when the master
+    starts, unless a valid identifier is already present in the environment; an
+    invalid one is simply replaced by a generated one. It is then passed to the
+    next master upon reload, so that it remains stable for the whole life of
+    the master, and it is also exposed to the worker. Its format is the same as
+    the one of the proxies' and servers' "guid": at most 127 characters among
+    letters, digits, '.', ':', '-' and '_'.
+
   * HAPROXY_STARTUP_VERSION: contains the version used to start, in master-
     worker mode this is the version which was used to start the master, even
     after updating the binary and reloading.
index fd27e69ee80e32f8319b6be35d979b2b45ae014a..6d26cb2fc0adeab416a6095cfe2672bae2f8c1a5 100644 (file)
@@ -161,6 +161,7 @@ struct global {
        char *chroot;
        char *pidfile;
        char *node, *desc;              /* node name & description */
+       char *master_id;                /* master process' unique ID, preserved upon reload */
        int localpeer_cmdline;          /* whether or not the commandline "-L" was set */
        int fd_hard_limit;              /* hard limit on ulimit-n : 0=unset */
        struct buffer log_tag;           /* name for syslog */
index d305d17c0fb94b276db18b151b3165880a4017f2..ffe0d138b1eddf3c1f55dbbfda7884f8640609dc 100644 (file)
@@ -2882,6 +2882,7 @@ void deinit(void)
        ha_free(&global.pidfile);
        ha_free(&global.node);
        ha_free(&global.desc);
+       ha_free(&global.master_id);
        ha_free(&oldpids);
        ha_free(&old_argv);
        ha_free(&localpeer);
@@ -3613,6 +3614,12 @@ int main(int argc, char **argv)
                                exit(EXIT_FAILURE);
                        }
                        setenv("HAPROXY_MWORKER", "1", 1);
+
+                       /* restore_env() above has dropped it, put it back so
+                        * that the worker's config may reference it.
+                        */
+                       if (global.master_id)
+                               setenv("HAPROXY_MASTER_ID", global.master_id, 1);
                }
 
                /* localpeer default value could be redefined via 'localpeer' keyword
index 28028bc5704a2fef1131b1d690fa66a685fc25ef..dc043ceaea43b0761fe7dd38c217491355fdae8a 100644 (file)
 #include <unistd.h>
 
 #include <haproxy/api.h>
+#include <haproxy/buf.h>
 #include <haproxy/cfgparse.h>
 #include <haproxy/cli.h>
 #include <haproxy/errors.h>
 #include <haproxy/fd.h>
 #include <haproxy/global.h>
+#include <haproxy/guid.h>
 #include <haproxy/log.h>
 #include <haproxy/list.h>
 #include <haproxy/listener.h>
@@ -356,6 +358,13 @@ static void mworker_reexec(int hardreload)
 
        setenv("HAPROXY_MWORKER_REEXEC", "1", 1);
 
+       /* restore_env() above has dropped it, but the next master must keep
+        * the ID of the current one, which is the whole point of passing it
+        * through the environment.
+        */
+       if (global.master_id)
+               setenv("HAPROXY_MASTER_ID", global.master_id, 1);
+
        mworker_proc_list_to_env(); /* put the children description in the env */
 
        /* during the reload we must ensure that every FDs that can't be
@@ -1178,9 +1187,32 @@ void mworker_create_master_cli(void)
 void mworker_prepare_master(void)
 {
        struct mworker_proc *tmproc;
+       char uuid[40];
+       const char *id;
 
        setenv("HAPROXY_MWORKER", "1", 1);
 
+       /* Assign a unique ID to this master process. It is taken from the
+        * environment when a valid one is found there, which happens either on
+        * reload since the previous master passes its own to us, or when an
+        * orchestrator wants to force it. Otherwise a time-ordered UUID v7 is
+        * generated. This way it identifies this master for its whole life.
+        */
+       id = getenv("HAPROXY_MASTER_ID");
+       if (!id || !guid_is_valid_fmt(id, NULL)) {
+               struct buffer buf = b_make(uuid, sizeof(uuid), 0, 0);
+
+               ha_generate_uuid_v7(&buf);
+               id = uuid;
+       }
+
+       global.master_id = strdup(id);
+       if (!global.master_id) {
+               ha_alert("Cannot allocate memory for the master's ID.\n");
+               exit(EXIT_FAILURE);
+       }
+       setenv("HAPROXY_MASTER_ID", global.master_id, 1);
+
        if (getenv("HAPROXY_MWORKER_REEXEC") == NULL) {
 
                tmproc = mworker_proc_new();