From 55c8d1a95f9736641aab15bd7562db7d6890aceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 23 Jul 2019 11:06:27 +0100 Subject: [PATCH] remote: handle autoprobing of driver within virtproxyd MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The virtproxyd daemon is merely responsible for forwarding RPC calls to one of the other per-driver daemons. As such, it does not have any drivers loaded and so regular auto-probing logic will not work. We need it to be able to handle NULL URIs though, so must implement some kind of alternative probing logic. When running as root this is quite crude. If a per-driver daemon is running, its UNIX socket will exist and we can assume it will accept connections. If the per-driver daemon is not running, but socket autostart is enabled, we again just assume it will accept connections. The is not great, however, because a default install may well have all sockets available for activation. IOW, the virtxend socket may exist, despite the fact that the libxl driver will not actually work. When running as non-root this is slightly easier as we only have two drivers, QEMU and VirtualBox. These daemons will likely not be running and socket activation won't be used either, as libvirt spawns the daemon on demand. So we just check whether the daemon actually is installed. Reviewed-by: Andrea Bolognani Signed-off-by: Daniel P. Berrangé --- src/remote/Makefile.inc.am | 1 + src/remote/remote_daemon_dispatch.c | 138 ++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) diff --git a/src/remote/Makefile.inc.am b/src/remote/Makefile.inc.am index 0a3aef1ec1..09535ee6bb 100644 --- a/src/remote/Makefile.inc.am +++ b/src/remote/Makefile.inc.am @@ -235,6 +235,7 @@ virtproxyd_CFLAGS = \ -DSOCK_PREFIX="\"libvirt\"" \ -DDAEMON_NAME="\"virtproxyd\"" \ -DENABLE_IP \ + -DVIRTPROXYD \ $(NULL) virtproxyd_LDFLAGS = $(REMOTE_DAEMON_LD_FLAGS) virtproxyd_LDADD = $(REMOTE_DAEMON_LD_ADD) diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c index 7a66629d5b..c8e353ebd3 100644 --- a/src/remote/remote_daemon_dispatch.c +++ b/src/remote/remote_daemon_dispatch.c @@ -50,6 +50,7 @@ #include "viraccessapicheckqemu.h" #include "virpolkit.h" #include "virthreadjob.h" +#include "configmake.h" #define VIR_FROM_THIS VIR_FROM_RPC @@ -2094,6 +2095,131 @@ void *remoteClientNew(virNetServerClientPtr client, /*----- Functions. -----*/ +#ifdef VIRTPROXYD +/* + * When running in virtproxyd regular auto-probing of drivers + * does not work as we don't have any drivers present (except + * stateless ones inside libvirt.so). All the interesting + * drivers are in separate daemons. Thus when we get a NULL + * URI we need to simulate probing that virConnectOpen would + * previously do. We use the existance of the UNIX domain + * socket as our hook for probing. + * + * This assumes no stale sockets left over from a now dead + * daemon, but that's reasonable since libvirtd unlinks + * sockets it creates on shutdown, or uses systemd activation + * + * We only try to probe for primary hypervisor drivers, + * not the secondary drivers. + */ +static int +remoteDispatchProbeURI(bool readonly, + char **probeduri) +{ + *probeduri = NULL; + VIR_DEBUG("Probing for driver daemon sockets"); + + /* + * If running root, either the daemon is running and the socket + * exists, or we're using socket activation so the socket exists + * too. + * + * If running non-root, chances are that the daemon won't be + * running, nor any socket activation is used. We need to + * be able to auto-spawn the daemon. We thus just check to + * see what daemons are installed. This is not a big deal as + * only QEMU & VBox run as non-root, anyway. + */ + if (geteuid() != 0) { + /* Order these the same as virDriverLoadModule + * calls in daemonInitialize */ + const char *drivers[] = { +# ifdef WITH_QEMU + "qemu", +# endif +# ifdef WITH_VBOX + "vbox", +# endif + }; + size_t i; + + for (i = 0; i < ARRAY_CARDINALITY(drivers) && !*probeduri; i++) { + VIR_AUTOFREE(char *) daemonname = NULL; + VIR_AUTOFREE(char *) daemonpath = NULL; + + if (virAsprintf(&daemonname, "virt%sd", drivers[i]) < 0) + return -1; + + if (!(daemonpath = virFileFindResource(daemonname, "src", SBINDIR))) + return -1; + + if (!virFileExists(daemonpath)) { + VIR_DEBUG("Missing daemon %s for driver %s", daemonpath, drivers[i]); + continue; + } + + if (virAsprintf(probeduri, "%s:///session", drivers[i]) < 0) + return -1; + + VIR_DEBUG("Probed URI %s via daemon %s", *probeduri, daemonpath); + return 0; + } + } else { + /* Order these the same as virDriverLoadModule + * calls in daemonInitialize */ + const char *drivers[] = { +# ifdef WITH_LIBXL + "libxl", +# endif +# ifdef WITH_QEMU + "qemu", +# endif +# ifdef WITH_LXC + "lxc", +# endif +# ifdef WITH_VBOX + "vbox", +# endif +# ifdef WITH_BHYVE + "bhyve", +# endif +# ifdef WITH_VZ + "vz", +# endif + }; + size_t i; + + for (i = 0; i < ARRAY_CARDINALITY(drivers) && !*probeduri; i++) { + VIR_AUTOFREE(char *) sockname = NULL; + + if (virAsprintf(&sockname, "%s/run/libvirt/virt%sd-%s", + LOCALSTATEDIR, drivers[i], + readonly ? "sock-ro" : "sock") < 0) + return -1; + + if (!virFileExists(sockname)) { + VIR_DEBUG("Missing sock %s for driver %s", sockname, drivers[i]); + continue; + } + + if (virAsprintf(probeduri, "%s:///system", drivers[i]) < 0) + return -1; + + VIR_DEBUG("Probed URI %s via sock %s", *probeduri, sockname); + return 0; + } + } + + /* Even if we didn't probe any socket, we won't + * return error. Just let virConnectOpen's normal + * logic run which will likely return an error anyway + */ + VIR_DEBUG("No driver sock exists"); + return 0; +} +#endif /* VIRTPROXYD */ + + static int remoteDispatchConnectOpen(virNetServerPtr server ATTRIBUTE_UNUSED, virNetServerClientPtr client, @@ -2102,6 +2228,9 @@ remoteDispatchConnectOpen(virNetServerPtr server ATTRIBUTE_UNUSED, struct remote_connect_open_args *args) { const char *name; +#ifdef VIRTPROXYD + VIR_AUTOFREE(char *) probeduri = NULL; +#endif unsigned int flags; struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client); int rv = -1; @@ -2128,6 +2257,15 @@ remoteDispatchConnectOpen(virNetServerPtr server ATTRIBUTE_UNUSED, priv->readonly = flags & VIR_CONNECT_RO; +#ifdef VIRTPROXYD + if (!name || STREQ(name, "")) { + if (remoteDispatchProbeURI(priv->readonly, &probeduri) < 0) + goto cleanup; + + name = probeduri; + } +#endif + VIR_DEBUG("Opening driver %s", name); if (priv->readonly) { if (!(priv->conn = virConnectOpenReadOnly(name)))