mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-10 09:07:02 +02:00
MEDIUM: mworker/cli: keep the connection of the FD that ask for a reload
When using the "reload" command over the master CLI, all connections to the master CLI were cut, this was unfortunate because it could have been used to implement a synchronous reload command. This patch implements an architecture to keep the connection alive after the reload. The master CLI is now equipped with a listener which uses a socketpair, the 2 FDs of this socketpair are stored in the mworker_proc of the master, which the master keeps via the environment variable. ipc_fd[1] is used as a listener for the master CLI. During the "reload" command, the CLI will send the FD of the current session over ipc_fd[0], then the reload is achieved, so the master won't handle the recv of the FD. Once reloaded, ipc_fd[1] receives the FD of the session, so the connection is preserved. Of course it is a new context, so everything like the "prompt mode" are lost. Only the FD which performs the reload is kept.
This commit is contained in:
parent
d2605cf0e5
commit
ec059c249e
@ -2061,6 +2061,19 @@ static void init(int argc, char **argv)
|
|||||||
tmproc->options |= PROC_O_TYPE_MASTER; /* master */
|
tmproc->options |= PROC_O_TYPE_MASTER; /* master */
|
||||||
tmproc->pid = pid;
|
tmproc->pid = pid;
|
||||||
tmproc->timestamp = start_date.tv_sec;
|
tmproc->timestamp = start_date.tv_sec;
|
||||||
|
|
||||||
|
/* Creates the mcli_reload listener, which is the listener used
|
||||||
|
* to retrieve the master CLI session which asked for the reload.
|
||||||
|
*
|
||||||
|
* ipc_fd[1] will be used as a listener, and ipc_fd[0]
|
||||||
|
* will be used to send the FD of the session.
|
||||||
|
*
|
||||||
|
* Both FDs will be kept in the master.
|
||||||
|
*/
|
||||||
|
if (socketpair(AF_UNIX, SOCK_STREAM, 0, tmproc->ipc_fd) < 0) {
|
||||||
|
ha_alert("cannot create the mcli_reload socketpair.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
proc_self = tmproc;
|
proc_self = tmproc;
|
||||||
|
|
||||||
LIST_APPEND(&proc_list, &tmproc->list);
|
LIST_APPEND(&proc_list, &tmproc->list);
|
||||||
@ -2098,6 +2111,7 @@ static void init(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!LIST_ISEMPTY(&mworker_cli_conf)) {
|
if (!LIST_ISEMPTY(&mworker_cli_conf)) {
|
||||||
|
char *path = NULL;
|
||||||
|
|
||||||
if (mworker_cli_proxy_create() < 0) {
|
if (mworker_cli_proxy_create() < 0) {
|
||||||
ha_alert("Can't create the master's CLI.\n");
|
ha_alert("Can't create the master's CLI.\n");
|
||||||
@ -2114,6 +2128,14 @@ static void init(int argc, char **argv)
|
|||||||
free(c->s);
|
free(c->s);
|
||||||
free(c);
|
free(c);
|
||||||
}
|
}
|
||||||
|
/* Create the mcli_reload listener from the proc_self struct */
|
||||||
|
memprintf(&path, "sockpair@%d", proc_self->ipc_fd[1]);
|
||||||
|
|
||||||
|
if (mworker_cli_proxy_new_listener(path) < 0) {
|
||||||
|
ha_alert("Cannot create the mcli_reload listener.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
ha_free(&path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,10 +13,12 @@
|
|||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#if defined(USE_SYSTEMD)
|
#if defined(USE_SYSTEMD)
|
||||||
#include <systemd/sd-daemon.h>
|
#include <systemd/sd-daemon.h>
|
||||||
@ -32,6 +34,7 @@
|
|||||||
#include <haproxy/listener.h>
|
#include <haproxy/listener.h>
|
||||||
#include <haproxy/mworker.h>
|
#include <haproxy/mworker.h>
|
||||||
#include <haproxy/peers.h>
|
#include <haproxy/peers.h>
|
||||||
|
#include <haproxy/proto_sockpair.h>
|
||||||
#include <haproxy/proxy.h>
|
#include <haproxy/proxy.h>
|
||||||
#include <haproxy/sc_strm.h>
|
#include <haproxy/sc_strm.h>
|
||||||
#include <haproxy/signal.h>
|
#include <haproxy/signal.h>
|
||||||
@ -126,7 +129,7 @@ void mworker_proc_list_to_env()
|
|||||||
minreloads = child->reloads;
|
minreloads = child->reloads;
|
||||||
|
|
||||||
if (child->pid > -1)
|
if (child->pid > -1)
|
||||||
memprintf(&msg, "%s|type=%c;fd=%d;pid=%d;reloads=%d;failedreloads=%d;timestamp=%d;id=%s;version=%s", msg ? msg : "", type, child->ipc_fd[0], child->pid, child->reloads, child->failedreloads, child->timestamp, child->id ? child->id : "", child->version);
|
memprintf(&msg, "%s|type=%c;fd=%d;cfd=%d;pid=%d;reloads=%d;failedreloads=%d;timestamp=%d;id=%s;version=%s", msg ? msg : "", type, child->ipc_fd[0], child->ipc_fd[1], child->pid, child->reloads, child->failedreloads, child->timestamp, child->id ? child->id : "", child->version);
|
||||||
}
|
}
|
||||||
if (msg)
|
if (msg)
|
||||||
setenv("HAPROXY_PROCESSES", msg, 1);
|
setenv("HAPROXY_PROCESSES", msg, 1);
|
||||||
@ -203,6 +206,8 @@ int mworker_env_to_proc_list()
|
|||||||
|
|
||||||
} else if (strncmp(subtoken, "fd=", 3) == 0) {
|
} else if (strncmp(subtoken, "fd=", 3) == 0) {
|
||||||
child->ipc_fd[0] = atoi(subtoken+3);
|
child->ipc_fd[0] = atoi(subtoken+3);
|
||||||
|
} else if (strncmp(subtoken, "cfd=", 4) == 0) {
|
||||||
|
child->ipc_fd[1] = atoi(subtoken+4);
|
||||||
} else if (strncmp(subtoken, "pid=", 4) == 0) {
|
} else if (strncmp(subtoken, "pid=", 4) == 0) {
|
||||||
child->pid = atoi(subtoken+4);
|
child->pid = atoi(subtoken+4);
|
||||||
} else if (strncmp(subtoken, "reloads=", 8) == 0) {
|
} else if (strncmp(subtoken, "reloads=", 8) == 0) {
|
||||||
@ -623,9 +628,29 @@ static int cli_io_handler_show_proc(struct appctx *appctx)
|
|||||||
/* reload the master process */
|
/* reload the master process */
|
||||||
static int cli_parse_reload(char **args, char *payload, struct appctx *appctx, void *private)
|
static int cli_parse_reload(char **args, char *payload, struct appctx *appctx, void *private)
|
||||||
{
|
{
|
||||||
|
struct stconn *scb = NULL;
|
||||||
|
struct stream *strm = NULL;
|
||||||
|
struct connection *conn = NULL;
|
||||||
|
int fd = -1;
|
||||||
|
|
||||||
if (!cli_has_level(appctx, ACCESS_LVL_OPER))
|
if (!cli_has_level(appctx, ACCESS_LVL_OPER))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
/* This ask for a synchronous reload, which means we will keep this FD
|
||||||
|
instead of closing it. */
|
||||||
|
|
||||||
|
scb = appctx_sc(appctx);
|
||||||
|
if (scb)
|
||||||
|
strm = sc_strm(scb);
|
||||||
|
if (strm && strm->scf)
|
||||||
|
conn = sc_conn(strm->scf);
|
||||||
|
if (conn)
|
||||||
|
fd = conn_fd(conn);
|
||||||
|
|
||||||
|
/* Send the FD of the current session to the "cli_reload" FD, which won't be polled */
|
||||||
|
if (fd != -1 && send_fd_uxst(proc_self->ipc_fd[0], fd) == 0) {
|
||||||
|
close(fd); /* avoid the leak of the FD after sending it via the socketpair */
|
||||||
|
}
|
||||||
mworker_reload();
|
mworker_reload();
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user