logd: add support for admin protocol in virtlogd

Add a virtlogd-admin-sock can serves the admin protocol for the virtlogd
daemon and define a virtlogd:///{system,session}  URI scheme for
connecting to it.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrange 2018-01-19 14:54:00 +00:00 committed by Daniel P. Berrangé
parent 8aca141081
commit 85d45ff05d
9 changed files with 149 additions and 41 deletions

View File

@ -2670,6 +2670,7 @@ virtlogd_LDFLAGS = \
$(PIE_LDFLAGS) \ $(PIE_LDFLAGS) \
$(NULL) $(NULL)
virtlogd_LDADD = \ virtlogd_LDADD = \
libvirt_driver_admin.la \
libvirt-net-rpc-server.la \ libvirt-net-rpc-server.la \
libvirt-net-rpc.la \ libvirt-net-rpc.la \
libvirt_util.la \ libvirt_util.la \

View File

@ -38,8 +38,9 @@
#define VIR_FROM_THIS VIR_FROM_ADMIN #define VIR_FROM_THIS VIR_FROM_ADMIN
#define LIBVIRTD_ADMIN_SOCK_NAME "/libvirt-admin-sock" #define LIBVIRTD_ADMIN_SOCK_NAME "libvirt-admin-sock"
#define LIBVIRTD_ADMIN_UNIX_SOCKET LOCALSTATEDIR "/run/libvirt" LIBVIRTD_ADMIN_SOCK_NAME #define VIRTLOGD_ADMIN_SOCK_NAME "virtlogd-admin-sock"
VIR_LOG_INIT("libvirt-admin"); VIR_LOG_INIT("libvirt-admin");
@ -128,18 +129,25 @@ getSocketPath(virURIPtr uri)
} }
if (!sock_path) { if (!sock_path) {
if (STRNEQ_NULLABLE(uri->scheme, "libvirtd")) { const char *sockbase = NULL;
if (STREQ_NULLABLE(uri->scheme, "libvirtd")) {
sockbase = LIBVIRTD_ADMIN_SOCK_NAME;
} else if (STREQ_NULLABLE(uri->scheme, "virtlogd")) {
sockbase = VIRTLOGD_ADMIN_SOCK_NAME;
} else {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Unsupported URI scheme '%s'"), _("Unsupported URI scheme '%s'"),
NULLSTR(uri->scheme)); NULLSTR(uri->scheme));
goto error; goto error;
} }
if (STREQ_NULLABLE(uri->path, "/system")) { if (STREQ_NULLABLE(uri->path, "/system")) {
if (VIR_STRDUP(sock_path, LIBVIRTD_ADMIN_UNIX_SOCKET) < 0) if (virAsprintf(&sock_path, LOCALSTATEDIR "/run/libvirt/%s",
sockbase) < 0)
goto error; goto error;
} else if (STREQ_NULLABLE(uri->path, "/session")) { } else if (STREQ_NULLABLE(uri->path, "/session")) {
if (!rundir || virAsprintf(&sock_path, "%s%s", rundir, if (!rundir || virAsprintf(&sock_path, "%s/%s", rundir,
LIBVIRTD_ADMIN_SOCK_NAME) < 0) sockbase) < 0)
goto error; goto error;
} else { } else {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, virReportError(VIR_ERR_CONFIG_UNSUPPORTED,

View File

@ -32,6 +32,7 @@
#include "log_daemon.h" #include "log_daemon.h"
#include "log_daemon_config.h" #include "log_daemon_config.h"
#include "admin/admin_server_dispatch.h"
#include "virutil.h" #include "virutil.h"
#include "virfile.h" #include "virfile.h"
#include "virpidfile.h" #include "virpidfile.h"
@ -137,7 +138,7 @@ static virLogDaemonPtr
virLogDaemonNew(virLogDaemonConfigPtr config, bool privileged) virLogDaemonNew(virLogDaemonConfigPtr config, bool privileged)
{ {
virLogDaemonPtr logd; virLogDaemonPtr logd;
virNetServerPtr srv; virNetServerPtr srv = NULL;
if (VIR_ALLOC(logd) < 0) if (VIR_ALLOC(logd) < 0)
return NULL; return NULL;
@ -149,6 +150,9 @@ virLogDaemonNew(virLogDaemonConfigPtr config, bool privileged)
return NULL; return NULL;
} }
if (!(logd->dmn = virNetDaemonNew()))
goto error;
if (!(srv = virNetServerNew("virtlogd", 1, if (!(srv = virNetServerNew("virtlogd", 1,
1, 1, 0, config->max_clients, 1, 1, 0, config->max_clients,
config->max_clients, -1, 0, config->max_clients, -1, 0,
@ -159,8 +163,22 @@ virLogDaemonNew(virLogDaemonConfigPtr config, bool privileged)
(void*)(intptr_t)(privileged ? 0x1 : 0x0)))) (void*)(intptr_t)(privileged ? 0x1 : 0x0))))
goto error; goto error;
if (!(logd->dmn = virNetDaemonNew()) || if (virNetDaemonAddServer(logd->dmn, srv) < 0)
virNetDaemonAddServer(logd->dmn, srv) < 0) goto error;
virObjectUnref(srv);
srv = NULL;
if (!(srv = virNetServerNew("admin", 1,
1, 1, 0, config->admin_max_clients,
config->admin_max_clients, -1, 0,
NULL,
remoteAdmClientNew,
remoteAdmClientPreExecRestart,
remoteAdmClientFree,
logd->dmn)))
goto error;
if (virNetDaemonAddServer(logd->dmn, srv) < 0)
goto error; goto error;
virObjectUnref(srv); virObjectUnref(srv);
srv = NULL; srv = NULL;
@ -189,7 +207,7 @@ virLogDaemonGetHandler(virLogDaemonPtr dmn)
static virNetServerPtr static virNetServerPtr
virLogDaemonNewServerPostExecRestart(virNetDaemonPtr dmn ATTRIBUTE_UNUSED, virLogDaemonNewServerPostExecRestart(virNetDaemonPtr dmn,
const char *name, const char *name,
virJSONValuePtr object, virJSONValuePtr object,
void *opaque) void *opaque)
@ -202,6 +220,14 @@ virLogDaemonNewServerPostExecRestart(virNetDaemonPtr dmn ATTRIBUTE_UNUSED,
virLogDaemonClientPreExecRestart, virLogDaemonClientPreExecRestart,
virLogDaemonClientFree, virLogDaemonClientFree,
opaque); opaque);
} else if (STREQ(name, "admin")) {
return virNetServerNewPostExecRestart(object,
name,
remoteAdmClientNew,
remoteAdmClientNewPostExecRestart,
remoteAdmClientPreExecRestart,
remoteAdmClientFree,
dmn);
} else { } else {
virReportError(VIR_ERR_INTERNAL_ERROR, virReportError(VIR_ERR_INTERNAL_ERROR,
_("Unexpected server name '%s' during restart"), _("Unexpected server name '%s' during restart"),
@ -354,10 +380,12 @@ virLogDaemonForkIntoBackground(const char *argv0)
static int static int
virLogDaemonUnixSocketPaths(bool privileged, virLogDaemonUnixSocketPaths(bool privileged,
char **sockfile) char **sockfile,
char **adminSockfile)
{ {
if (privileged) { if (privileged) {
if (VIR_STRDUP(*sockfile, LOCALSTATEDIR "/run/libvirt/virtlogd-sock") < 0) if (VIR_STRDUP(*sockfile, LOCALSTATEDIR "/run/libvirt/virtlogd-sock") < 0 ||
VIR_STRDUP(*adminSockfile, LOCALSTATEDIR "/run/libvirt/virtlogd-admin-sock") < 0)
goto error; goto error;
} else { } else {
char *rundir = NULL; char *rundir = NULL;
@ -374,7 +402,8 @@ virLogDaemonUnixSocketPaths(bool privileged,
} }
umask(old_umask); umask(old_umask);
if (virAsprintf(sockfile, "%s/virtlogd-sock", rundir) < 0) { if (virAsprintf(sockfile, "%s/virtlogd-sock", rundir) < 0 ||
virAsprintf(adminSockfile, "%s/virtlogd-admin-sock", rundir) < 0) {
VIR_FREE(rundir); VIR_FREE(rundir);
goto error; goto error;
} }
@ -485,29 +514,50 @@ virLogDaemonSetupSignals(virNetDaemonPtr dmn)
static int static int
virLogDaemonSetupNetworkingSystemD(virNetServerPtr srv) virLogDaemonSetupNetworkingSystemD(virNetServerPtr logSrv, virNetServerPtr adminSrv)
{ {
virNetServerServicePtr svc;
unsigned int nfds; unsigned int nfds;
size_t i;
if ((nfds = virGetListenFDs()) == 0) if ((nfds = virGetListenFDs()) == 0)
return 0; return 0;
if (nfds > 1) if (nfds > 2)
VIR_DEBUG("Too many (%d) file descriptors from systemd", nfds); VIR_DEBUG("Too many (%d) file descriptors from systemd", nfds);
nfds = 1;
/* Systemd passes FDs, starting immediately after stderr, for (i = 0; i < nfds && i < 2; i++) {
* so the first FD we'll get is '3'. */ virNetServerServicePtr svc;
if (!(svc = virNetServerServiceNewFD(3, 0, char *path = virGetUNIXSocketPath(3 + i);
virNetServerPtr srv;
if (!path)
return -1;
if (strstr(path, "virtlogd-admin-sock")) {
srv = adminSrv;
} else if (strstr(path, "virtlogd-sock")) {
srv = logSrv;
} else {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Unknown UNIX socket %s passed in"),
path);
VIR_FREE(path);
return -1;
}
VIR_FREE(path);
/* Systemd passes FDs, starting immediately after stderr,
* so the first FD we'll get is '3'. */
if (!(svc = virNetServerServiceNewFD(3 + i, 0,
#if WITH_GNUTLS #if WITH_GNUTLS
NULL, NULL,
#endif #endif
false, 0, 1))) false, 0, 1)))
return -1; return -1;
if (virNetServerAddService(srv, svc, NULL) < 0) { if (virNetServerAddService(srv, svc, NULL) < 0) {
virObjectUnref(svc); virObjectUnref(svc);
return -1; return -1;
}
} }
return 1; return 1;
} }
@ -878,8 +928,10 @@ virLogDaemonUsage(const char *argv0, bool privileged)
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {
virNetServerPtr srv = NULL; virNetServerPtr logSrv = NULL;
virNetServerPtr adminSrv = NULL;
virNetServerProgramPtr logProgram = NULL; virNetServerProgramPtr logProgram = NULL;
virNetServerProgramPtr adminProgram = NULL;
char *remote_config_file = NULL; char *remote_config_file = NULL;
int statuswrite = -1; int statuswrite = -1;
int ret = 1; int ret = 1;
@ -889,6 +941,7 @@ int main(int argc, char **argv) {
char *pid_file = NULL; char *pid_file = NULL;
int pid_file_fd = -1; int pid_file_fd = -1;
char *sock_file = NULL; char *sock_file = NULL;
char *admin_sock_file = NULL;
int timeout = -1; /* -t: Shutdown timeout */ int timeout = -1; /* -t: Shutdown timeout */
char *state_file = NULL; char *state_file = NULL;
bool implicit_conf = false; bool implicit_conf = false;
@ -1016,12 +1069,13 @@ int main(int argc, char **argv) {
VIR_DEBUG("Decided on pid file path '%s'", NULLSTR(pid_file)); VIR_DEBUG("Decided on pid file path '%s'", NULLSTR(pid_file));
if (virLogDaemonUnixSocketPaths(privileged, if (virLogDaemonUnixSocketPaths(privileged,
&sock_file) < 0) { &sock_file,
&admin_sock_file) < 0) {
VIR_ERROR(_("Can't determine socket paths")); VIR_ERROR(_("Can't determine socket paths"));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
VIR_DEBUG("Decided on socket paths '%s'", VIR_DEBUG("Decided on socket paths '%s' and '%s'",
sock_file); sock_file, admin_sock_file);
if (virLogDaemonExecRestartStatePath(privileged, if (virLogDaemonExecRestartStatePath(privileged,
&state_file) < 0) { &state_file) < 0) {
@ -1098,22 +1152,30 @@ int main(int argc, char **argv) {
goto cleanup; goto cleanup;
} }
srv = virNetDaemonGetServer(logDaemon->dmn, "virtlogd"); logSrv = virNetDaemonGetServer(logDaemon->dmn, "virtlogd");
if ((rv = virLogDaemonSetupNetworkingSystemD(srv)) < 0) { adminSrv = virNetDaemonGetServer(logDaemon->dmn, "admin");
if ((rv = virLogDaemonSetupNetworkingSystemD(logSrv, adminSrv)) < 0) {
ret = VIR_LOG_DAEMON_ERR_NETWORK; ret = VIR_LOG_DAEMON_ERR_NETWORK;
goto cleanup; goto cleanup;
} }
/* Only do this, if systemd did not pass a FD */ /* Only do this, if systemd did not pass a FD */
if (rv == 0 && if (rv == 0) {
virLogDaemonSetupNetworkingNative(srv, sock_file) < 0) { if (virLogDaemonSetupNetworkingNative(logSrv, sock_file) < 0 ||
ret = VIR_LOG_DAEMON_ERR_NETWORK; virLogDaemonSetupNetworkingNative(adminSrv, admin_sock_file) < 0) {
goto cleanup; ret = VIR_LOG_DAEMON_ERR_NETWORK;
goto cleanup;
}
} }
virObjectUnref(srv); virObjectUnref(logSrv);
virObjectUnref(adminSrv);
} }
srv = virNetDaemonGetServer(logDaemon->dmn, "virtlogd"); logSrv = virNetDaemonGetServer(logDaemon->dmn, "virtlogd");
/* If exec-restarting from old virtlogd, we won't have an
* admin server present */
if (virNetDaemonHasServer(logDaemon->dmn, "admin"))
adminSrv = virNetDaemonGetServer(logDaemon->dmn, "admin");
if (timeout != -1) { if (timeout != -1) {
VIR_DEBUG("Registering shutdown timeout %d", timeout); VIR_DEBUG("Registering shutdown timeout %d", timeout);
@ -1133,11 +1195,25 @@ int main(int argc, char **argv) {
ret = VIR_LOG_DAEMON_ERR_INIT; ret = VIR_LOG_DAEMON_ERR_INIT;
goto cleanup; goto cleanup;
} }
if (virNetServerAddProgram(srv, logProgram) < 0) { if (virNetServerAddProgram(logSrv, logProgram) < 0) {
ret = VIR_LOG_DAEMON_ERR_INIT; ret = VIR_LOG_DAEMON_ERR_INIT;
goto cleanup; goto cleanup;
} }
if (adminSrv != NULL) {
if (!(adminProgram = virNetServerProgramNew(ADMIN_PROGRAM,
ADMIN_PROTOCOL_VERSION,
adminProcs,
adminNProcs))) {
ret = VIR_LOG_DAEMON_ERR_INIT;
goto cleanup;
}
if (virNetServerAddProgram(adminSrv, adminProgram) < 0) {
ret = VIR_LOG_DAEMON_ERR_INIT;
goto cleanup;
}
}
/* Disable error func, now logging is setup */ /* Disable error func, now logging is setup */
virSetErrorFunc(NULL, virLogDaemonErrorHandler); virSetErrorFunc(NULL, virLogDaemonErrorHandler);
@ -1155,7 +1231,7 @@ int main(int argc, char **argv) {
/* Start accepting new clients from network */ /* Start accepting new clients from network */
virNetServerUpdateServices(srv, true); virNetDaemonUpdateServices(logDaemon->dmn, true);
virNetDaemonRun(logDaemon->dmn); virNetDaemonRun(logDaemon->dmn);
if (execRestart && if (execRestart &&
@ -1168,7 +1244,9 @@ int main(int argc, char **argv) {
cleanup: cleanup:
virObjectUnref(logProgram); virObjectUnref(logProgram);
virObjectUnref(srv); virObjectUnref(adminProgram);
virObjectUnref(logSrv);
virObjectUnref(adminSrv);
virLogDaemonFree(logDaemon); virLogDaemonFree(logDaemon);
if (statuswrite != -1) { if (statuswrite != -1) {
if (ret != 0) { if (ret != 0) {
@ -1184,6 +1262,7 @@ int main(int argc, char **argv) {
virPidFileReleasePath(pid_file, pid_file_fd); virPidFileReleasePath(pid_file, pid_file_fd);
VIR_FREE(pid_file); VIR_FREE(pid_file);
VIR_FREE(sock_file); VIR_FREE(sock_file);
VIR_FREE(admin_sock_file);
VIR_FREE(state_file); VIR_FREE(state_file);
VIR_FREE(run_dir); VIR_FREE(run_dir);
VIR_FREE(remote_config_file); VIR_FREE(remote_config_file);

View File

@ -73,6 +73,7 @@ virLogDaemonConfigNew(bool privileged ATTRIBUTE_UNUSED)
return NULL; return NULL;
data->max_clients = 1024; data->max_clients = 1024;
data->admin_max_clients = 5000;
data->max_size = 1024 * 1024 * 2; data->max_size = 1024 * 1024 * 2;
data->max_backups = 3; data->max_backups = 3;
@ -103,6 +104,8 @@ virLogDaemonConfigLoadOptions(virLogDaemonConfigPtr data,
return -1; return -1;
if (virConfGetValueUInt(conf, "max_clients", &data->max_clients) < 0) if (virConfGetValueUInt(conf, "max_clients", &data->max_clients) < 0)
return -1; return -1;
if (virConfGetValueUInt(conf, "admin_max_clients", &data->admin_max_clients) < 0)
return -1;
if (virConfGetValueSizeT(conf, "max_size", &data->max_size) < 0) if (virConfGetValueSizeT(conf, "max_size", &data->max_size) < 0)
return -1; return -1;
if (virConfGetValueSizeT(conf, "max_backups", &data->max_backups) < 0) if (virConfGetValueSizeT(conf, "max_backups", &data->max_backups) < 0)

View File

@ -34,6 +34,7 @@ struct _virLogDaemonConfig {
char *log_filters; char *log_filters;
char *log_outputs; char *log_outputs;
unsigned int max_clients; unsigned int max_clients;
unsigned int admin_max_clients;
size_t max_backups; size_t max_backups;
size_t max_size; size_t max_size;

View File

@ -2,6 +2,8 @@ module Test_virtlogd =
let conf = "log_level = 3 let conf = "log_level = 3
log_filters=\"3:remote 4:event\" log_filters=\"3:remote 4:event\"
log_outputs=\"3:syslog:virtlogd\" log_outputs=\"3:syslog:virtlogd\"
max_clients = 10
admin_max_clients = 10
max_size = 131072 max_size = 131072
max_backups = 3 max_backups = 3
" "
@ -10,5 +12,7 @@ max_backups = 3
{ "log_level" = "3" } { "log_level" = "3" }
{ "log_filters" = "3:remote 4:event" } { "log_filters" = "3:remote 4:event" }
{ "log_outputs" = "3:syslog:virtlogd" } { "log_outputs" = "3:syslog:virtlogd" }
{ "max_clients" = "10" }
{ "admin_max_clients" = "10" }
{ "max_size" = "131072" } { "max_size" = "131072" }
{ "max_backups" = "3" } { "max_backups" = "3" }

View File

@ -0,0 +1,10 @@
[Unit]
Description=Virtual machine log manager socket
Before=libvirtd.service
[Socket]
ListenStream=@localstatedir@/run/libvirt/virtlogd-admin-sock
Service=virtlogd.service
[Install]
WantedBy=sockets.target

View File

@ -29,6 +29,7 @@ module Virtlogd =
| str_entry "log_outputs" | str_entry "log_outputs"
| int_entry "log_buffer_size" | int_entry "log_buffer_size"
| int_entry "max_clients" | int_entry "max_clients"
| int_entry "admin_max_clients"
| int_entry "max_size" | int_entry "max_size"
| int_entry "max_backups" | int_entry "max_backups"

View File

@ -1,6 +1,7 @@
[Unit] [Unit]
Description=Virtual machine log manager Description=Virtual machine log manager
Requires=virtlogd.socket Requires=virtlogd.socket
Requires=virtlogd-admin.socket
Before=libvirtd.service Before=libvirtd.service
Documentation=man:virtlogd(8) Documentation=man:virtlogd(8)
Documentation=https://libvirt.org Documentation=https://libvirt.org