In master worker mode, you can't specify the stats socket where you get your listeners FDs on a reload, because the command line of the re-exec is launched by the master.
To solve the problem, when -x is found on the command line, its parameter is rewritten on a reexec with the first stats socket with the capability to send sockets. It tries to reuse the original parameter if it has this capability. --- src/haproxy.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 5 deletions(-) diff --git a/src/haproxy.c b/src/haproxy.c index 61114b6..57a5db6 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -175,6 +175,8 @@ static int oldpids_sig; /* use USR1 or TERM */ /* Path to the unix socket we use to retrieve listener sockets from the old process */ static const char *old_unixsocket; +static char *cur_unixsocket = NULL; + /* this is used to drain data, and as a temporary buffer for sprintf()... */ struct chunk trash = { }; @@ -514,6 +516,42 @@ int delete_oldpid(int pid) return 0; } + +static void get_cur_unixsocket() +{ + /* if -x was used, try to update the stat socket if not available anymore */ + if (global.stats_fe) { + struct bind_conf *bind_conf; + + /* pass through all stats socket */ + list_for_each_entry(bind_conf, &global.stats_fe->conf.bind, by_fe) { + struct listener *l; + + list_for_each_entry(l, &bind_conf->listeners, by_bind) { + + if (l->addr.ss_family == AF_UNIX && + (bind_conf->level & ACCESS_FD_LISTENERS)) { + const struct sockaddr_un *un; + + un = (struct sockaddr_un *)&l->addr; + /* priority to old_unixsocket */ + if (!cur_unixsocket) { + cur_unixsocket = strdup(un->sun_path); + } else { + if (old_unixsocket && !strcmp(un->sun_path, old_unixsocket)) { + free(cur_unixsocket); + cur_unixsocket = strdup(old_unixsocket); + return; + } + } + } + } + } + } + if (!cur_unixsocket && old_unixsocket) + cur_unixsocket = strdup(old_unixsocket); +} + /* * When called, this function reexec haproxy with -sf followed by current * children PIDs and possibily old children PIDs if they didn't leave yet. @@ -532,8 +570,8 @@ static void mworker_reload() while (next_argv[next_argc]) next_argc++; - /* 1 for haproxy -sf */ - next_argv = realloc(next_argv, (next_argc + 1 + global.nbproc + nb_oldpids + 1) * sizeof(char *)); + /* 1 for haproxy -sf, 2 for -x /socket */ + next_argv = realloc(next_argv, (next_argc + 1 + 2 + global.nbproc + nb_oldpids + 1) * sizeof(char *)); if (next_argv == NULL) goto alloc_error; @@ -557,6 +595,26 @@ static void mworker_reload() msg = NULL; } next_argv[next_argc] = NULL; + + /* if -x was used, try to update the stat socket if not available anymore */ + if (cur_unixsocket) { + + if (old_unixsocket) { + + /* look for -x <path> */ + for (j = 0; next_argv[j]; j++) { + if (!strcmp(next_argv[j], "-x")) + next_argv[j + 1] = (char *)cur_unixsocket; + } + } else { + /* if -x is not specified but we know the socket, add -x with it */ + next_argv[next_argc++] = "-x"; + next_argv[next_argc++] = (char *)cur_unixsocket; + next_argv[next_argc++] = NULL; + + } + } + deinit(); /* we don't want to leak FD there */ Warning("Reexecuting Master process\n"); execv(next_argv[0], next_argv); @@ -2218,11 +2276,16 @@ int main(int argc, char **argv) } if (old_unixsocket) { - if (get_old_sockets(old_unixsocket) != 0) { - Alert("Failed to get the sockets from the old process!\n"); - exit(1); + if (strcmp("/dev/null", old_unixsocket) != 0) { + if (get_old_sockets(old_unixsocket) != 0) { + Alert("Failed to get the sockets from the old process!\n"); + if (!(global.mode & MODE_MWORKER)) + exit(1); + } } } + get_cur_unixsocket(); + /* We will loop at most 100 times with 10 ms delay each time. * That's at most 1 second. We only send a signal to old pids * if we cannot grab at least one port. @@ -2410,6 +2473,7 @@ int main(int argc, char **argv) exit(0); } + /* the father launches the required number of processes */ for (proc = 0; proc < global.nbproc; proc++) { ret = fork(); -- 2.10.2