MEDIUM: mworker: create CLI listeners from argv[]
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.
diff --git a/include/proto/cli.h b/include/proto/cli.h
index 6d6ca35..467a86e 100644
--- a/include/proto/cli.h
+++ b/include/proto/cli.h
@@ -29,6 +29,7 @@
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 161d1eb..8a4fbc5 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -1652,6 +1652,104 @@
}
/*
+ * 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 5affcd2..4e6d243 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -224,6 +224,8 @@
/* 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 @@
" -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 @@
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 @@
if (global.mode & MODE_MWORKER) {
int proc;
+ struct wordlist *it, *c;
for (proc = 0; proc < global.nbproc; proc++) {
struct mworker_proc *tmproc;
@@ -1726,7 +1746,19 @@
if (mworker_cli_proxy_create() < 0) {
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();