This patch introduces mworker_cli_proxy_new_listener() which allows the
creation of new listeners for the CLI proxy.

Using this function it is possible to create new listeners from the
program arguments with -Sa <unix_socket>. It is allowed to create
multiple listeners with several -Sa.
---
 include/proto/cli.h |  1 +
 src/cli.c           | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/haproxy.c       | 32 +++++++++++++++++
 3 files changed, 131 insertions(+)

diff --git a/include/proto/cli.h b/include/proto/cli.h
index 6d6ca35ff..467a86ea7 100644
--- a/include/proto/cli.h
+++ b/include/proto/cli.h
@@ -29,6 +29,7 @@ void cli_register_kw(struct cli_kw_list *kw_list);
 int cli_has_level(struct appctx *appctx, int level);
 
 int mworker_cli_proxy_create();
+int mworker_cli_proxy_new_listener(char *line);
 int mworker_cli_sockpair_new(struct mworker_proc *mworker_proc, int proc);
 
 #endif /* _PROTO_CLI_H */
diff --git a/src/cli.c b/src/cli.c
index 161d1ebb0..8a4fbc52c 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -1651,6 +1651,104 @@ int mworker_cli_proxy_create()
        return 0;
 }
 
+/*
+ * Create a new listener for the master CLI proxy
+ */
+int mworker_cli_proxy_new_listener(char *line)
+{
+       struct bind_conf *bind_conf;
+       struct listener *l;
+       char *err = NULL;
+       char *args[MAX_LINE_ARGS + 1];
+       int arg;
+       int cur_arg;
+
+       arg = 0;
+       args[0] = line;
+
+       /* args is a bind configuration with spaces replaced by commas */
+       while (*line && arg < MAX_LINE_ARGS) {
+
+               if (*line == ',') {
+                       *line++ = '\0';
+                       while (*line == ',')
+                               line++;
+                       args[++arg] = line;
+               }
+               line++;
+       }
+
+       args[++arg] = "\0";
+
+       bind_conf = bind_conf_alloc(mworker_proxy, "master-socket", 0, "", 
xprt_get(XPRT_RAW));
+
+       bind_conf->level &= ~ACCESS_LVL_MASK;
+       bind_conf->level |= ACCESS_LVL_ADMIN;
+
+       if (!str2listener(args[0], mworker_proxy, bind_conf, "master-socket", 
0, &err)) {
+               ha_alert("Cannot create the listener of the master CLI\n");
+               return -1;
+       }
+
+       cur_arg = 1;
+
+       while (*args[cur_arg]) {
+                       static int bind_dumped;
+                       struct bind_kw *kw;
+
+                       kw = bind_find_kw(args[cur_arg]);
+                       if (kw) {
+                               if (!kw->parse) {
+                                       memprintf(&err, "'%s %s' : '%s' option 
is not implemented in this version (check build options).",
+                                                 args[0], args[1], 
args[cur_arg]);
+                                       goto err;
+                               }
+
+                               if (kw->parse(args, cur_arg, global.stats_fe, 
bind_conf, &err) != 0) {
+                                       if (err)
+                                               memprintf(&err, "'%s %s' : 
'%s'", args[0], args[1], err);
+                                       else
+                                               memprintf(&err, "'%s %s' : 
error encountered while processing '%s'",
+                                                         args[0], args[1], 
args[cur_arg]);
+                                       goto err;
+                               }
+
+                               cur_arg += 1 + kw->skip;
+                               continue;
+                       }
+
+                       if (!bind_dumped) {
+                               bind_dump_kws(&err);
+                               indent_msg(&err, 4);
+                               bind_dumped = 1;
+                       }
+
+                       memprintf(&err, "'%s %s' : unknown keyword '%s'.%s%s",
+                                 args[0], args[1], args[cur_arg],
+                                 err ? " Registered keywords :" : "", err ? 
err : "");
+                       goto err;
+       }
+
+
+       list_for_each_entry(l, &bind_conf->listeners, by_bind) {
+               l->maxconn = 10;
+               l->backlog = 10;
+               l->accept = session_accept_fd;
+               l->default_target = mworker_proxy->default_target;
+               /* don't make the peers subject to global limits and don't 
close it in the master */
+               l->options |= (LI_O_UNLIMITED|LI_O_MWORKER); /* we are keeping 
this FD in the master */
+               l->nice = -64;  /* we want to boost priority for local stats */
+               global.maxsock += l->maxconn;
+       }
+
+       return 0;
+
+err:
+       ha_alert("%s\n", err);
+       return -1;
+
+}
+
 /*
  * Create a new CLI socket using a socketpair for a worker process
  * <mworker_proc> is the process structure, and <proc> is the process number
diff --git a/src/haproxy.c b/src/haproxy.c
index 5affcd208..4e6d24303 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -224,6 +224,8 @@ static void *run_thread_poll_loop(void *data);
 /* bitfield of a few warnings to emit just once (WARN_*) */
 unsigned int warned = 0;
 
+/* master CLI configuration (-S flag) */
+struct list mworker_cli_conf = LIST_HEAD_INIT(mworker_cli_conf);
 
 /* These are strings to be reported in the output of "haproxy -vv". They may
  * either be constants (in which case must_free must be zero) or dynamically
@@ -452,6 +454,7 @@ static void usage(char *name)
                "        -dV disables SSL verify on servers side\n"
                "        -sf/-st [pid ]* finishes/terminates old pids.\n"
                "        -x <unix_socket> get listening sockets from a unix 
socket\n"
+               "        -S <unix_socket>[,<bind options>...] new stats socket 
for the master\n"
                "\n",
                name, DEFAULT_MAXCONN, cfg_maxpconn);
        exit(1);
@@ -1563,6 +1566,22 @@ static void init(int argc, char **argv)
                                argv++;
                                argc--;
                        }
+                       else if (*flag == 'S') {
+                               struct wordlist *c;
+
+                               if (argc <= 1 || argv[1][0] == '-') {
+                                       ha_alert("Socket and optional bind 
parameters expected with the -S flag\n");
+                                       usage(progname);
+                               }
+                               if ((c = malloc(sizeof(*c))) == NULL || (c->s = 
strdup(argv[1])) == NULL) {
+                                       ha_alert("Cannot allocate memory\n");
+                                       exit(EXIT_FAILURE);
+                               }
+                               LIST_ADD(&mworker_cli_conf, &c->list);
+
+                               argv++;
+                               argc--;
+                       }
                        else if (*flag == 's' && (flag[1] == 'f' || flag[1] == 
't')) {
                                /* list of pids to finish ('f') or terminate 
('t') */
 
@@ -1701,6 +1720,7 @@ static void init(int argc, char **argv)
 
        if (global.mode & MODE_MWORKER) {
                int proc;
+               struct wordlist *it, *c;
 
                for (proc = 0; proc < global.nbproc; proc++) {
                        struct mworker_proc *tmproc;
@@ -1727,6 +1747,18 @@ static void init(int argc, char **argv)
                                ha_alert("Can't create the master's CLI.\n");
                                exit(EXIT_FAILURE);
                }
+
+               list_for_each_entry_safe(c, it, &mworker_cli_conf, list) {
+
+                       if (mworker_cli_proxy_new_listener(c->s) < 0) {
+                               ha_alert("Can't create the master's CLI.\n");
+                               exit(EXIT_FAILURE);
+                       }
+                       LIST_DEL(&c->list);
+                       free(c->s);
+                       free(c);
+               }
+
        }
 
        pattern_finalize_config();
-- 
2.16.4


Reply via email to