MINOR: systemd wrapper: re-execute on SIGUSR2

Re-execute the systemd wrapper on SIGUSR2 and before reloading HAProxy,
making it possible to load a completely new version of HAProxy
(including a new version of the systemd wrapper) gracefully.
Since the wrapper accepts no command-line arguments of its own,
re-execution is signaled using the HAPROXY_SYSTEMD_REEXEC environment
variable.

This is primarily intended to help seamless upgrades of distribution
packages.
This commit is contained in:
Apollon Oikonomopoulos 2014-04-17 16:39:28 +03:00 committed by Willy Tarreau
parent 45ad91efa3
commit b3fce6ef4d
1 changed files with 40 additions and 14 deletions

View File

@ -18,9 +18,11 @@
#include <unistd.h> #include <unistd.h>
#include <sys/wait.h> #include <sys/wait.h>
#define REEXEC_FLAG "HAPROXY_SYSTEMD_REEXEC"
static char *pid_file = "/run/haproxy.pid"; static char *pid_file = "/run/haproxy.pid";
static int main_argc; static int wrapper_argc;
static char **main_argv; static char **wrapper_argv;
static void locate_haproxy(char *buffer, size_t buffer_size) static void locate_haproxy(char *buffer, size_t buffer_size)
{ {
@ -42,6 +44,11 @@ static void spawn_haproxy(char **pid_strv, int nb_pid)
{ {
char haproxy_bin[512]; char haproxy_bin[512];
pid_t pid; pid_t pid;
int main_argc;
char **main_argv;
main_argc = wrapper_argc - 1;
main_argv = wrapper_argv + 1;
pid = fork(); pid = fork();
if (!pid) { if (!pid) {
@ -96,15 +103,10 @@ static int read_pids(char ***pid_strv)
static void sigusr2_handler(int signum __attribute__((unused))) static void sigusr2_handler(int signum __attribute__((unused)))
{ {
int i; setenv(REEXEC_FLAG, "1", 1);
char **pid_strv = NULL; printf("haproxy-systemd-wrapper: re-executing\n");
int nb_pid = read_pids(&pid_strv);
spawn_haproxy(pid_strv, nb_pid); execv(wrapper_argv[0], wrapper_argv);
for (i = 0; i < nb_pid; ++i)
free(pid_strv[i]);
free(pid_strv);
} }
static void sigint_handler(int signum __attribute__((unused))) static void sigint_handler(int signum __attribute__((unused)))
@ -140,16 +142,40 @@ int main(int argc, char **argv)
{ {
int status; int status;
--argc; ++argv; wrapper_argc = argc;
main_argc = argc; wrapper_argv = argv;
main_argv = argv;
--argc; ++argv;
init(argc, argv); init(argc, argv);
signal(SIGINT, &sigint_handler); signal(SIGINT, &sigint_handler);
signal(SIGUSR2, &sigusr2_handler); signal(SIGUSR2, &sigusr2_handler);
spawn_haproxy(NULL, 0); if (getenv(REEXEC_FLAG) != NULL) {
/* We are being re-executed: restart HAProxy gracefully */
int i;
char **pid_strv = NULL;
int nb_pid = read_pids(&pid_strv);
sigset_t sigs;
unsetenv(REEXEC_FLAG);
spawn_haproxy(pid_strv, nb_pid);
/* Unblock SIGUSR2 which was blocked by the signal handler
* before re-exec */
sigprocmask(SIG_BLOCK, NULL, &sigs);
sigdelset(&sigs, SIGUSR2);
sigprocmask(SIG_SETMASK, &sigs, NULL);
for (i = 0; i < nb_pid; ++i)
free(pid_strv[i]);
free(pid_strv);
}
else {
/* Start a fresh copy of HAProxy */
spawn_haproxy(NULL, 0);
}
status = -1; status = -1;
while (-1 != wait(&status) || errno == EINTR) while (-1 != wait(&status) || errno == EINTR)
; ;