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.
Signed-off-by: Daniel P. Berrangé <berrange(a)redhat.com>
---
src/remote/Makefile.inc.am | 1 +
src/remote/remote_daemon_dispatch.c | 135 +++++++++++++++++++++++++++-
2 files changed, 135 insertions(+), 1 deletion(-)
diff --git a/src/remote/Makefile.inc.am b/src/remote/Makefile.inc.am
index 7b4f6a10bc..7f67495a0d 100644
--- a/src/remote/Makefile.inc.am
+++ b/src/remote/Makefile.inc.am
@@ -236,6 +236,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 f1304695bd..964d5d8347 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
@@ -2057,6 +2058,126 @@ 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;
+
+ if (!(daemonname = virFileFindResource("virtqemud",
"src", BINDIR)))
+ return -1;
+
+ if (!virFileExists(daemonname)) {
+ VIR_DEBUG("Missing daemon %s for driver %s", daemonname,
drivers[i]);
+ continue;
+ }
+
+ if (virAsprintf(probeduri, "%s:///session", drivers[i]) < 0)
+ return -1;
+
+ VIR_DEBUG("Probed URI %s via sock %s", *probeduri, daemonname);
+ 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,
@@ -2065,6 +2186,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;
@@ -2091,7 +2215,16 @@ remoteDispatchConnectOpen(virNetServerPtr server ATTRIBUTE_UNUSED,
priv->readonly = flags & VIR_CONNECT_RO;
- VIR_DEBUG("Opening driver %s", name);
+#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->conn = priv->readonly ?
virConnectOpenReadOnly(name) :
virConnectOpen(name)))
--
2.21.0