This commit remove the -Ds systemd mode in HAProxy in order to replace it by a more generic master workers system. It aims to replace entirely the systemd wrapper in the near future.
The master workers mode implements a new way of managing HAProxy processes. The master is in charge of parsing the configuration file and is responsible for spawning child processes. The master workers mode can be invoked by using the -W flag. It can be used either in background mode (-D) or foreground mode. When used in background mode, the master will fork to daemonize. In master workers background mode, chroot, setuid and setgid are done in each child rather than in the master process, because the master process will still need access to filesystem to reload the configuration. --- include/types/global.h | 2 +- src/haproxy.c | 133 +++++++++++++++++++++++++++++++++---------------- src/listener.c | 4 +- 3 files changed, 93 insertions(+), 46 deletions(-) diff --git a/include/types/global.h b/include/types/global.h index 57b969d..4af1212 100644 --- a/include/types/global.h +++ b/include/types/global.h @@ -44,7 +44,7 @@ #define MODE_VERBOSE 0x10 #define MODE_STARTING 0x20 #define MODE_FOREGROUND 0x40 -#define MODE_SYSTEMD 0x80 +#define MODE_MWORKER 0x80 /* Master Worker */ /* list of last checks to perform, depending on config options */ #define LSTCHK_CAP_BIND 0x00000001 /* check that we can bind to any port */ diff --git a/src/haproxy.c b/src/haproxy.c index 02f90a8..8c73613 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -921,11 +921,10 @@ static void init(int argc, char **argv) arg_mode |= MODE_DEBUG; else if (*flag == 'c') arg_mode |= MODE_CHECK; - else if (*flag == 'D') { + else if (*flag == 'D') arg_mode |= MODE_DAEMON; - if (flag[1] == 's') /* -Ds */ - arg_mode |= MODE_SYSTEMD; - } + else if (*flag == 'W') + arg_mode |= MODE_MWORKER; else if (*flag == 'q') arg_mode |= MODE_QUIET; else if (*flag == 'x') { @@ -1001,7 +1000,7 @@ static void init(int argc, char **argv) } global.mode = MODE_STARTING | /* during startup, we want most of the alerts */ - (arg_mode & (MODE_DAEMON | MODE_SYSTEMD | MODE_FOREGROUND | MODE_VERBOSE + (arg_mode & (MODE_DAEMON | MODE_MWORKER | MODE_FOREGROUND | MODE_VERBOSE | MODE_QUIET | MODE_CHECK | MODE_DEBUG)); if (change_dir && chdir(change_dir) < 0) { @@ -1330,24 +1329,24 @@ static void init(int argc, char **argv) if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) { /* command line debug mode inhibits configuration mode */ - global.mode &= ~(MODE_DAEMON | MODE_SYSTEMD | MODE_QUIET); + global.mode &= ~(MODE_DAEMON | MODE_QUIET); global.mode |= (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)); } - if (arg_mode & (MODE_DAEMON | MODE_SYSTEMD)) { + if (arg_mode & MODE_DAEMON) { /* command line daemon mode inhibits foreground and debug modes mode */ global.mode &= ~(MODE_DEBUG | MODE_FOREGROUND); - global.mode |= (arg_mode & (MODE_DAEMON | MODE_SYSTEMD)); + global.mode |= arg_mode & MODE_DAEMON; } global.mode |= (arg_mode & (MODE_QUIET | MODE_VERBOSE)); - if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_SYSTEMD | MODE_QUIET))) { - Warning("<debug> mode incompatible with <quiet>, <daemon> and <systemd>. Keeping <debug> only.\n"); - global.mode &= ~(MODE_DAEMON | MODE_SYSTEMD | MODE_QUIET); + if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) { + Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n"); + global.mode &= ~(MODE_DAEMON | MODE_QUIET); } - if ((global.nbproc > 1) && !(global.mode & (MODE_DAEMON | MODE_SYSTEMD))) { + if ((global.nbproc > 1) && !(global.mode & (MODE_DAEMON | MODE_MWORKER))) { if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG))) Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n"); global.nbproc = 1; @@ -2020,7 +2019,7 @@ int main(int argc, char **argv) } /* open log & pid files before the chroot */ - if (global.mode & (MODE_DAEMON | MODE_SYSTEMD) && global.pidfile != NULL) { + if (global.mode & MODE_DAEMON && global.pidfile != NULL) { unlink(global.pidfile); pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644); if (pidfd < 0) { @@ -2047,14 +2046,17 @@ int main(int argc, char **argv) " might not work well.\n" "", argv[0]); - /* chroot if needed */ - if (global.chroot != NULL) { - if (chroot(global.chroot) == -1 || chdir("/") == -1) { - Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot); - if (nb_oldpids) - tell_old_pids(SIGTTIN); - protocol_unbind_all(); - exit(1); + if ((global.mode & (MODE_MWORKER|MODE_DAEMON)) == 0) { + + /* chroot if needed */ + if (global.chroot != NULL) { + if (chroot(global.chroot) == -1 || chdir("/") == -1) { + Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot); + if (nb_oldpids) + tell_old_pids(SIGTTIN); + protocol_unbind_all(); + exit(1); + } } } @@ -2065,25 +2067,26 @@ int main(int argc, char **argv) * be able to restart the old pids. */ - /* setgid / setuid */ - if (global.gid) { - if (getgroups(0, NULL) > 0 && setgroups(0, NULL) == -1) - Warning("[%s.main()] Failed to drop supplementary groups. Using 'gid'/'group'" - " without 'uid'/'user' is generally useless.\n", argv[0]); + if ((global.mode & (MODE_MWORKER|MODE_DAEMON)) == 0) { + /* setgid / setuid */ + if (global.gid) { + if (getgroups(0, NULL) > 0 && setgroups(0, NULL) == -1) + Warning("[%s.main()] Failed to drop supplementary groups. Using 'gid'/'group'" + " without 'uid'/'user' is generally useless.\n", argv[0]); - if (setgid(global.gid) == -1) { - Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid); + if (setgid(global.gid) == -1) { + Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid); + protocol_unbind_all(); + exit(1); + } + } + + if (global.uid && setuid(global.uid) == -1) { + Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid); protocol_unbind_all(); exit(1); } } - - if (global.uid && setuid(global.uid) == -1) { - Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid); - protocol_unbind_all(); - exit(1); - } - /* check ulimits */ limit.rlim_cur = limit.rlim_max = 0; getrlimit(RLIMIT_NOFILE, &limit); @@ -2092,7 +2095,7 @@ int main(int argc, char **argv) argv[0], (int)limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock); } - if (global.mode & (MODE_DAEMON | MODE_SYSTEMD)) { + if (global.mode & (MODE_DAEMON | MODE_MWORKER)) { struct proxy *px; struct peers *curpeers; int ret = 0; @@ -2100,6 +2103,22 @@ int main(int argc, char **argv) int proc; char *wrapper_fd; + /* + * if daemon + mworker: must fork here to let a master + * process live in background before forking children + */ + if ((global.mode & MODE_MWORKER) && (global.mode & MODE_DAEMON)) { + ret = fork(); + if (ret < 0) { + Alert("[%s.main()] Cannot fork.\n", argv[0]); + protocol_unbind_all(); + exit(1); /* there has been an error */ + } + /* parent leave to daemonize */ + if (ret > 0) + exit(0); + } + /* the father launches the required number of processes */ for (proc = 0; proc < global.nbproc; proc++) { ret = fork(); @@ -2146,25 +2165,53 @@ int main(int argc, char **argv) /* We won't ever use this anymore */ free(oldpids); oldpids = NULL; - free(global.chroot); global.chroot = NULL; free(global.pidfile); global.pidfile = NULL; if (proc == global.nbproc) { - if (global.mode & MODE_SYSTEMD) { + if (global.mode & MODE_MWORKER) { int i; protocol_unbind_all(); - for (i = 1; i < argc; i++) { - memset(argv[i], '\0', strlen(argv[i])); - } - /* it's OK because "-Ds -f x" is the shortest form going here */ - memcpy(argv[0] + strlen(argv[0]), "-master", 8); for (proc = 0; proc < global.nbproc; proc++) while (waitpid(-1, NULL, 0) == -1 && errno == EINTR); } exit(0); /* parent must leave */ } + /* Must chroot and setgid/setuid in the children */ + /* chroot if needed */ + if (global.chroot != NULL) { + if (chroot(global.chroot) == -1 || chdir("/") == -1) { + Alert("[%s.main()] Cannot chroot1(%s).\n", argv[0], global.chroot); + if (nb_oldpids) + tell_old_pids(SIGTTIN); + protocol_unbind_all(); + exit(1); + } + } + + free(global.chroot); + global.chroot = NULL; + + /* setgid / setuid */ + if (global.gid) { + if (getgroups(0, NULL) > 0 && setgroups(0, NULL) == -1) + Warning("[%s.main()] Failed to drop supplementary groups. Using 'gid'/'group'" + " without 'uid'/'user' is generally useless.\n", argv[0]); + + if (setgid(global.gid) == -1) { + Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid); + protocol_unbind_all(); + exit(1); + } + } + + if (global.uid && setuid(global.uid) == -1) { + Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid); + protocol_unbind_all(); + exit(1); + } + /* we might have to unbind some proxies from some processes */ px = proxy; while (px != NULL) { diff --git a/src/listener.c b/src/listener.c index a99e4c0..69da2b7 100644 --- a/src/listener.c +++ b/src/listener.c @@ -53,7 +53,7 @@ struct xfer_sock_list *xfer_sock_list = NULL; void enable_listener(struct listener *listener) { if (listener->state == LI_LISTEN) { - if ((global.mode & (MODE_DAEMON | MODE_SYSTEMD)) && + if ((global.mode & (MODE_DAEMON | MODE_MWORKER)) && listener->bind_conf->bind_proc && !(listener->bind_conf->bind_proc & (1UL << (relative_pid - 1)))) { /* we don't want to enable this listener and don't @@ -135,7 +135,7 @@ int pause_listener(struct listener *l) */ int resume_listener(struct listener *l) { - if ((global.mode & (MODE_DAEMON | MODE_SYSTEMD)) && + if ((global.mode & (MODE_DAEMON | MODE_MWORKER)) && l->bind_conf->bind_proc && !(l->bind_conf->bind_proc & (1UL << (relative_pid - 1)))) return 1; -- 2.10.2