]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: mworker: replace systemd mode by master worker mode
authorWilliam Lallemand <wlallemand@haproxy.com>
Thu, 1 Jun 2017 15:38:50 +0000 (17:38 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 2 Jun 2017 08:56:32 +0000 (10:56 +0200)
This commit remove the -Ds systemd mode in HAProxy in order to replace
it by a more generic master worker system. It aims to replace entirely
the systemd wrapper in the near future.

The master worker 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 worker 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 worker 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
src/cfgparse.c
src/haproxy.c
src/listener.c

index aeb82eae967315b9873ef161383d34c20907dc3f..ee8e95e0e8b2368d2547c127901e4bc72c2573c9 100644 (file)
@@ -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 */
index 4c0e2d4f0ee43728948fc0fe36a6a60249d37227..bdf55a8da551c0021ef8a78abb3a421c751f92eb 100644 (file)
@@ -624,6 +624,11 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
                        goto out;
                global.mode |= MODE_DAEMON;
        }
+       else if (!strcmp(args[0], "master-worker")) {
+               if (alertif_too_many_args(0, file, linenum, args, &err_code))
+                       goto out;
+               global.mode |= MODE_MWORKER;
+       }
        else if (!strcmp(args[0], "debug")) {
                if (alertif_too_many_args(0, file, linenum, args, &err_code))
                        goto out;
index 6ecae257d5ad4e8dad1db652784a40cf1d292d35..0e8511bf131ef43dc2a5e6cbb759de6a7f5d0a4f 100644 (file)
@@ -348,6 +348,7 @@ static void usage(char *name)
                "        -dM[<byte>] poisons memory with <byte> (defaults to 0x50)\n"
                "        -V enters verbose mode (disables quiet mode)\n"
                "        -D goes daemon ; -C changes to <dir> before loading files.\n"
+               "        -W master-worker mode.\n"
                "        -q quiet mode : don't display messages\n"
                "        -c check mode : only check config files and exit\n"
                "        -n sets the maximum total # of connections (%d)\n"
@@ -921,11 +922,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 +1001,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 +1330,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 +2020,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 +2047,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 +2068,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);
+                               protocol_unbind_all();
+                               exit(1);
+                       }
+               }
 
-               if (setgid(global.gid) == -1) {
-                       Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
+               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 +2096,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 +2104,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,19 +2166,11 @@ 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) {
-                               int i;
-
+                       if (global.mode & MODE_MWORKER) {
                                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);
                        }
@@ -2168,6 +2180,40 @@ int main(int argc, char **argv)
                        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);
+               }
+
                /* pass through every cli socket, and check if it's bound to
                 * the current process and if it exposes listeners sockets.
                 * Caution: the GTUNE_SOCKET_TRANSFER is now set after the fork.
index a99e4c0d3573f00bea3fed0883b6fea61445bf42..69da2b77ff5a852414cc6fd0b0fdb30cf3167882 100644 (file)
@@ -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;