The driver URI: "qemu:///embed?root=/some/path" enables a new way to use the QEMU driver by embedding it directly in the calling process. To use this the process must have a thread running the libvirt event loop. This URI will then cause libvirt to dynamically load the QEMU driver module and call its global initialization function. The application can now make normal libvirt API calls which are all serviced in-process with no RPC layer involved. To avoid conflicting with the existing libvirtd daemon it is important to specify an alternative root directory. All the paths the QEMU driver normal creates will be placed under this root. For example using the path /home/berrange/tmp/embed, as an unprivileged process cause the creation of the following directories /home/berrange/tmp/embed/home/berrange/.config/libvirt/qemu/lib /home/berrange/tmp/embed/home/berrange/.config/libvirt/qemu/snapshot /home/berrange/tmp/embed/home/berrange/.config/libvirt/qemu/save /home/berrange/tmp/embed/home/berrange/.config/libvirt/qemu/channel/target /home/berrange/tmp/embed/home/berrange/.config/libvirt/qemu/ram/libvirt /home/berrange/tmp/embed/home/berrange/.config/libvirt/qemu/ram/libvirt/qemu /home/berrange/tmp/embed/home/berrange/.config/libvirt/qemu/nvram /home/berrange/tmp/embed/home/berrange/.config/libvirt/qemu/dump /home/berrange/tmp/embed/home/berrange/.cache/libvirt/qemu/cache/capabilities /home/berrange/tmp/embed/home/berrange/.cache/libvirt/qemu/log /home/berrange/tmp/embed/run/user/501/libvirt/qemu/run The application is responsible for purging everything underneath this root directory when no longer required. Note that QEMU is still daemonized right now and so the application embedding the QEMU driver can quit & restart and still have its VMs present, just as libvirtd would. A future patch will hook up VIR_DOMAIN_CREATE_AUTO_DESTROY flag such that the VM are not daemonized and still retain the parent/child relationship forcing them to die the the application exits. Thanks to previous refactoring, it is still possible to use functionality that calls out to other secondary drivers. For example it can open the network, secret or storage drivers. The network driver stuff is not fully functional though until the pending refactoring is done to introduce the virNetworkPort object concept. A key thing to note is that for this to work, the application that links to libvirt *MUST* be built with -Wl,--export-dynamic to ensure that symbols from libvirt.so are exported & thus available to the dynamically loaded QEMU driver module. If libvirt.so itself was dynamically loaded then RTLD_GLOBAL must be passed to dlopen(). Signed-off-by: Daniel P. Berrangé <berrange@xxxxxxxxxx> --- src/libvirt.c | 39 +++++++++++++++++++++++++++++++++++++- src/qemu/qemu_driver.c | 6 ++++-- src/remote/remote_driver.c | 7 +++++++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/libvirt.c b/src/libvirt.c index 677f1cef5f..e34fd5c96d 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -87,6 +87,7 @@ #ifdef WITH_BHYVE # include "bhyve/bhyve_driver.h" #endif +#include "access/viraccessmanager.h" #define VIR_FROM_THIS VIR_FROM_NONE @@ -841,6 +842,7 @@ virConnectOpenInternal(const char *name, virConnectPtr ret; virConfPtr conf = NULL; char *uristr = NULL; + bool embed = false; ret = virGetConnect(); if (ret == NULL) @@ -939,6 +941,36 @@ virConnectOpenInternal(const char *name, ret->uri) < 0) { goto failed; } + + if (STREQ(ret->uri->scheme, "qemu") && + STREQ(ret->uri->path, "/embed")) { + const char *root = NULL; + for (i = 0; i < ret->uri->paramsCount; i++) { + virURIParamPtr var = &ret->uri->params[i]; + if (STREQ(var->name, "root")) + root = var->value; + } + + if (!root) { + virReportError(VIR_ERR_INVALID_ARG, "%s", + _("root parameter required for embedded driver")); + goto failed; + } + + if (virDriverLoadModule("qemu", "qemuRegister", false) < 0) + goto failed; + + if (virAccessManagerGetDefault() == NULL) { + virAccessManagerPtr acl; + acl = virAccessManagerNew("none"); + virAccessManagerSetDefault(acl); + } + + if (virStateInitialize(geteuid() == 0, root, NULL, NULL) < 0) + goto failed; + + embed = true; + } } else { VIR_DEBUG("no name, allowing driver auto-select"); } @@ -1011,7 +1043,12 @@ virConnectOpenInternal(const char *name, continue; } } else { - VIR_DEBUG("Matching any URI scheme for '%s'", ret->uri ? ret->uri->scheme : ""); + if (embed) { + VIR_DEBUG("Skipping wildcard for embedded URI"); + continue; + } else { + VIR_DEBUG("Matching any URI scheme for '%s'", ret->uri ? ret->uri->scheme : ""); + } } /* before starting the new connection, check if the driver only works diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 019f6b2bf3..cdd483a338 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -1105,14 +1105,16 @@ static virDrvOpenStatus qemuConnectOpen(virConnectPtr conn, if (virQEMUDriverIsPrivileged(qemu_driver)) { if (STRNEQ(conn->uri->path, "/system") && - STRNEQ(conn->uri->path, "/session")) { + STRNEQ(conn->uri->path, "/session") && + STRNEQ(conn->uri->path, "/embed")) { virReportError(VIR_ERR_INTERNAL_ERROR, _("unexpected QEMU URI path '%s', try qemu:///system"), conn->uri->path); return VIR_DRV_OPEN_ERROR; } } else { - if (STRNEQ(conn->uri->path, "/session")) { + if (STRNEQ(conn->uri->path, "/session") && + STRNEQ(conn->uri->path, "/embed")) { virReportError(VIR_ERR_INTERNAL_ERROR, _("unexpected QEMU URI path '%s', try qemu:///session"), conn->uri->path); diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 244e384607..976f311060 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -1343,6 +1343,13 @@ remoteConnectOpen(virConnectPtr conn, if (flags & VIR_CONNECT_RO) rflags |= VIR_DRV_OPEN_REMOTE_RO; + if (conn->uri && + conn->uri->path && + STREQ(conn->uri->path, "/embed")) { + ret = VIR_DRV_OPEN_DECLINED; + goto cleanup; + } + /* * If no servername is given, and no +XXX * transport is listed, or transport is unix, -- 2.21.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list