This introduces a new binary 'libvirt_qemu' which can be used to launch
guests externally from libvirtd. eg
libvirt_qemu -c qemu:///system /path/to/xml/file
This will launch a guest from the requested XML file and then connect to
qemu:///system to register it with libvirtd. At this point all normal
libvirtd operations should generally work.
NB, this impl has many flaws:
- We don't generate a unique 'id', so all guests will get id==1.
Surprisingly this doesn't break the world.
- Tracking of unique name + UUIDs is *not* race free.
- No tracking/allocation of shared resource state (PCI devices,
etc)
Most other functionality works, but might have expected results.
In terms of namespace support there's some restrictions
- The mount namespace must share certain dirs
/etc/libvirt
/var/run/libvirt
/var/lib/libvirt
/var/cache/libvirt
between the libvirtd and libvirt_qemu processes
- The PID namespace must match libvirtd & libvirt_qemu
though this will be addressed in another patch to
come
- The network namespace can be different
- Hotplug/unplug will likely break if separate
namespaces are used
- The libvirt_qemu will exit if startup fails, however, it
won't exit when QEMU later shuts down - you must listen
for libvirtd events to detect that right now. We'll
fix that
- Killing the libvirt_qemu shim will not kill the QEMU
process. You must kill via the libvirt API as normal.
This won't change, because we need to be able to
ultimately restart the libvirt_qemu shim in order to
apply software updates to running instance.
We might wire up a special signal though to let
you kill libvirt_qemu & take out QEMU at same time
eg SIGQUIT or something like that perhaps.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
po/POTFILES.in | 1 +
src/Makefile.am | 49 ++++
src/qemu/qemu_conf.h | 2 +-
src/qemu/qemu_controller.c | 551 +++++++++++++++++++++++++++++++++++++++++++++
src/qemu/qemu_domain.c | 2 +-
src/qemu/qemu_driver.c | 2 +-
6 files changed, 604 insertions(+), 3 deletions(-)
create mode 100644 src/qemu/qemu_controller.c
diff --git a/po/POTFILES.in b/po/POTFILES.in
index c1fa23427e..d97175b6d5 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -133,6 +133,7 @@ src/qemu/qemu_block.c
src/qemu/qemu_capabilities.c
src/qemu/qemu_cgroup.c
src/qemu/qemu_command.c
+src/qemu/qemu_controller.c
src/qemu/qemu_conf.c
src/qemu/qemu_domain.c
src/qemu/qemu_domain_address.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 4c022d1e44..7ca5ad4d3c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -922,6 +922,9 @@ QEMU_DRIVER_SOURCES = \
qemu/qemu_capspriv.h \
qemu/qemu_security.c qemu/qemu_security.h
+QEMU_CONTROLLER_SOURCES = \
+ qemu/qemu_controller.c
+
XENAPI_DRIVER_SOURCES = \
xenapi/xenapi_driver.c xenapi/xenapi_driver.h \
xenapi/xenapi_driver_private.h \
@@ -3115,6 +3118,52 @@ endif WITH_LIBVIRTD
endif WITH_LXC
EXTRA_DIST += $(LXC_CONTROLLER_SOURCES)
+if WITH_QEMU
+if WITH_LIBVIRTD
+libexec_PROGRAMS += libvirt_qemu
+
+libvirt_qemu_SOURCES = \
+ $(QEMU_CONTROLLER_SOURCES) \
+ $(DATATYPES_SOURCES)
+libvirt_qemu_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(PIE_LDFLAGS) \
+ $(NULL)
+libvirt_qemu_LDADD = \
+ libvirt.la \
+ libvirt-qemu.la \
+ libvirt_driver_qemu_impl.la
+if WITH_NETWORK
+libvirt_qemu_LDADD += libvirt_driver_network_impl.la
+endif WITH_NETWORK
+if WITH_STORAGE
+libvirt_qemu_LDADD += libvirt_driver_storage_impl.la
+endif WITH_STORAGE
+libvirt_qemu_LDADD += ../gnulib/lib/libgnu.la $(LIBSOCKET)
+if WITH_DTRACE_PROBES
+libvirt_qemu_LDADD += libvirt_probes.lo libvirt_qemu_probes.lo
+endif WITH_DTRACE_PROBES
+libvirt_qemu_LDADD += $(SECDRIVER_LIBS)
+libvirt_qemu_CFLAGS = \
+ -I$(srcdir)/access \
+ -I$(srcdir)/conf \
+ -I$(srcdir)/secret \
+ $(AM_CFLAGS) \
+ $(PIE_CFLAGS) \
+ $(LIBNL_CFLAGS) \
+ $(FUSE_CFLAGS) \
+ $(DBUS_CFLAGS) \
+ $(XDR_CFLAGS) \
+ $(NULL)
+if WITH_BLKID
+libvirt_qemu_CFLAGS += $(BLKID_CFLAGS)
+libvirt_qemu_LDADD += $(BLKID_LIBS)
+endif WITH_BLKID
+libvirt_qemu_CFLAGS += $(SECDRIVER_CFLAGS)
+endif WITH_LIBVIRTD
+endif WITH_QEMU
+EXTRA_DIST += $(QEMU_CONTROLLER_SOURCES)
+
if WITH_SECDRIVER_APPARMOR
if WITH_LIBVIRTD
libexec_PROGRAMS += virt-aa-helper
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index a553e30e2e..a19b199147 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -296,7 +296,7 @@ struct _qemuDomainCmdlineDef {
char **env_value;
};
-
+int qemuSecurityInit(virQEMUDriverPtr driver);
void qemuDomainCmdlineDefFree(qemuDomainCmdlineDefPtr def);
diff --git a/src/qemu/qemu_controller.c b/src/qemu/qemu_controller.c
new file mode 100644
index 0000000000..320d9a99b6
--- /dev/null
+++ b/src/qemu/qemu_controller.c
@@ -0,0 +1,551 @@
+/*
+ * qemu_controller.c: QEMU process controller
+ *
+ * Copyright (C) 2006-2018 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "virgettext.h"
+#include "virthread.h"
+#include "virlog.h"
+#include "virfile.h"
+#include "viralloc.h"
+#include "virstring.h"
+#include "dirname.h"
+#include "driver.h"
+
+#include "qemu/qemu_conf.h"
+#include "qemu/qemu_process.h"
+#include "qemu/qemu_driver.h"
+#include "libvirt_internal.h"
+
+static const char *argv0;
+
+#define VIR_FROM_THIS VIR_FROM_QEMU
+
+VIR_LOG_INIT("qemu.qemu_controller");
+
+typedef struct virQEMUController virQEMUController;
+typedef virQEMUController *virQEMUControllerPtr;
+struct virQEMUController {
+ const char *uri;
+ bool privileged;
+ const char *xml;
+ virQEMUDriverPtr driver;
+ virConnectPtr conn;
+ virDomainObjPtr vm;
+};
+
+static void
+virQEMUControllerDriverFree(virQEMUDriverPtr driver)
+{
+ if (!driver)
+ return;
+
+ virObjectUnref(driver->config);
+ virObjectUnref(driver->hostdevMgr);
+ virHashFree(driver->sharedDevices);
+ virObjectUnref(driver->caps);
+ virObjectUnref(driver->qemuCapsCache);
+
+ virObjectUnref(driver->domains);
+ virObjectUnref(driver->remotePorts);
+ virObjectUnref(driver->webSocketPorts);
+ virObjectUnref(driver->migrationPorts);
+ virObjectUnref(driver->migrationErrors);
+
+ virObjectUnref(driver->xmlopt);
+
+ virSysinfoDefFree(driver->hostsysinfo);
+
+ virObjectUnref(driver->closeCallbacks);
+
+ VIR_FREE(driver->qemuImgBinary);
+
+ virObjectUnref(driver->securityManager);
+
+ ebtablesContextFree(driver->ebtables);
+
+ virLockManagerPluginUnref(driver->lockManager);
+
+ virMutexDestroy(&driver->lock);
+ VIR_FREE(driver);
+}
+
+static virQEMUDriverPtr virQEMUControllerNewDriver(bool privileged)
+{
+ virQEMUDriverPtr driver = NULL;
+ char *driverConf = NULL;
+ virConnectPtr conn = NULL;
+ virQEMUDriverConfigPtr cfg;
+ uid_t run_uid = -1;
+ gid_t run_gid = -1;
+ char *hugepagePath = NULL;
+ char *memoryBackingPath = NULL;
+ size_t i;
+
+ if (VIR_ALLOC(driver) < 0)
+ return NULL;
+
+ if (virMutexInit(&driver->lock) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("cannot initialize mutex"));
+ VIR_FREE(driver);
+ return NULL;
+ }
+
+ driver->privileged = privileged;
+
+ /* read the host sysinfo */
+ if (privileged)
+ driver->hostsysinfo = virSysinfoRead();
+
+ if (!(driver->config = cfg = virQEMUDriverConfigNew(privileged)))
+ goto error;
+
+ if (virAsprintf(&driverConf, "%s/qemu.conf", cfg->configBaseDir) < 0)
+ goto error;
+
+ if (virQEMUDriverConfigLoadFile(cfg, driverConf, privileged) < 0)
+ goto error;
+ VIR_FREE(driverConf);
+
+ if (virQEMUDriverConfigValidate(cfg) < 0)
+ goto error;
+
+ if (virFileMakePath(cfg->stateDir) < 0) {
+ virReportSystemError(errno, _("Failed to create state dir %s"),
+ cfg->stateDir);
+ goto error;
+ }
+ if (virFileMakePath(cfg->libDir) < 0) {
+ virReportSystemError(errno, _("Failed to create lib dir %s"),
+ cfg->libDir);
+ goto error;
+ }
+ if (virFileMakePath(cfg->cacheDir) < 0) {
+ virReportSystemError(errno, _("Failed to create cache dir %s"),
+ cfg->cacheDir);
+ goto error;
+ }
+ if (virFileMakePath(cfg->saveDir) < 0) {
+ virReportSystemError(errno, _("Failed to create save dir %s"),
+ cfg->saveDir);
+ goto error;
+ }
+ if (virFileMakePath(cfg->snapshotDir) < 0) {
+ virReportSystemError(errno, _("Failed to create save dir %s"),
+ cfg->snapshotDir);
+ goto error;
+ }
+ if (virFileMakePath(cfg->autoDumpPath) < 0) {
+ virReportSystemError(errno, _("Failed to create dump dir %s"),
+ cfg->autoDumpPath);
+ goto error;
+ }
+ if (virFileMakePath(cfg->channelTargetDir) < 0) {
+ virReportSystemError(errno, _("Failed to create channel target dir %s"),
+ cfg->channelTargetDir);
+ goto error;
+ }
+ if (virFileMakePath(cfg->nvramDir) < 0) {
+ virReportSystemError(errno, _("Failed to create nvram dir %s"),
+ cfg->nvramDir);
+ goto error;
+ }
+ if (virFileMakePath(cfg->memoryBackingDir) < 0) {
+ virReportSystemError(errno, _("Failed to create memory backing dir %s"),
+ cfg->memoryBackingDir);
+ goto error;
+ }
+
+ driver->qemuImgBinary = virFindFileInPath("qemu-img");
+
+ if (!(driver->lockManager =
+ virLockManagerPluginNew(cfg->lockManagerName ?
+ cfg->lockManagerName : "nop",
+ "qemu",
+ cfg->configBaseDir,
+ 0)))
+ goto error;
+
+ if (cfg->macFilter) {
+ if (!(driver->ebtables = ebtablesContextNew("qemu"))) {
+ virReportSystemError(errno,
+ _("failed to enable mac filter in '%s'"),
+ __FILE__);
+ goto error;
+ }
+
+ if (ebtablesAddForwardPolicyReject(driver->ebtables) < 0)
+ goto error;
+ }
+
+ /* Allocate bitmap for remote display port reservations. We cannot
+ * do this before the config is loaded properly, since the port
+ * numbers are configurable now */
+ if ((driver->remotePorts =
+ virPortAllocatorNew(_("display"),
+ cfg->remotePortMin,
+ cfg->remotePortMax,
+ 0)) == NULL)
+ goto error;
+
+ if ((driver->webSocketPorts =
+ virPortAllocatorNew(_("webSocket"),
+ cfg->webSocketPortMin,
+ cfg->webSocketPortMax,
+ 0)) == NULL)
+ goto error;
+
+ if ((driver->migrationPorts =
+ virPortAllocatorNew(_("migration"),
+ cfg->migrationPortMin,
+ cfg->migrationPortMax,
+ 0)) == NULL)
+ goto error;
+
+ if (qemuSecurityInit(driver) < 0)
+ goto error;
+
+ if (!(driver->hostdevMgr = virHostdevManagerGetDefault()))
+ goto error;
+
+ if (!(driver->sharedDevices = virHashCreate(30, qemuSharedDeviceEntryFree)))
+ goto error;
+
+ if (privileged) {
+ char *channeldir;
+
+ if (chown(cfg->libDir, cfg->user, cfg->group) < 0) {
+ virReportSystemError(errno,
+ _("unable to set ownership of '%s' to user %d:%d"),
+ cfg->libDir, (int) cfg->user,
+ (int) cfg->group);
+ goto error;
+ }
+ if (chown(cfg->cacheDir, cfg->user, cfg->group) < 0) {
+ virReportSystemError(errno,
+ _("unable to set ownership of '%s' to %d:%d"),
+ cfg->cacheDir, (int) cfg->user,
+ (int) cfg->group);
+ goto error;
+ }
+ if (chown(cfg->saveDir, cfg->user, cfg->group) < 0) {
+ virReportSystemError(errno,
+ _("unable to set ownership of '%s' to %d:%d"),
+ cfg->saveDir, (int) cfg->user,
+ (int) cfg->group);
+ goto error;
+ }
+ if (chown(cfg->snapshotDir, cfg->user, cfg->group) < 0) {
+ virReportSystemError(errno,
+ _("unable to set ownership of '%s' to %d:%d"),
+ cfg->snapshotDir, (int) cfg->user,
+ (int) cfg->group);
+ goto error;
+ }
+ if (chown(cfg->autoDumpPath, cfg->user, cfg->group) < 0) {
+ virReportSystemError(errno,
+ _("unable to set ownership of '%s' to %d:%d"),
+ cfg->autoDumpPath, (int) cfg->user,
+ (int) cfg->group);
+ goto error;
+ }
+ if (!(channeldir = mdir_name(cfg->channelTargetDir))) {
+ virReportOOMError();
+ goto error;
+ }
+ if (chown(channeldir, cfg->user, cfg->group) < 0) {
+ virReportSystemError(errno,
+ _("unable to set ownership of '%s' to %d:%d"),
+ channeldir, (int) cfg->user,
+ (int) cfg->group);
+ VIR_FREE(channeldir);
+ goto error;
+ }
+ VIR_FREE(channeldir);
+ if (chown(cfg->channelTargetDir, cfg->user, cfg->group) < 0) {
+ virReportSystemError(errno,
+ _("unable to set ownership of '%s' to %d:%d"),
+ cfg->channelTargetDir, (int) cfg->user,
+ (int) cfg->group);
+ goto error;
+ }
+ if (chown(cfg->nvramDir, cfg->user, cfg->group) < 0) {
+ virReportSystemError(errno,
+ _("unable to set ownership of '%s' to %d:%d"),
+ cfg->nvramDir, (int) cfg->user,
+ (int) cfg->group);
+ goto error;
+ }
+ if (chown(cfg->memoryBackingDir, cfg->user, cfg->group) < 0) {
+ virReportSystemError(errno,
+ _("unable to set ownership of '%s' to %d:%d"),
+ cfg->memoryBackingDir, (int) cfg->user,
+ (int) cfg->group);
+ goto error;
+ }
+
+ run_uid = cfg->user;
+ run_gid = cfg->group;
+ }
+
+ driver->qemuCapsCache = virQEMUCapsCacheNew(cfg->libDir,
+ cfg->cacheDir,
+ run_uid,
+ run_gid);
+ if (!driver->qemuCapsCache)
+ goto error;
+
+ if ((driver->caps = virQEMUDriverCreateCapabilities(driver)) == NULL)
+ goto error;
+
+ if (!(driver->xmlopt = virQEMUDriverCreateXMLConf(driver)))
+ goto error;
+
+ /* If hugetlbfs is present, then we need to create a sub-directory within
+ * it, since we can't assume the root mount point has permissions that
+ * will let our spawned QEMU instances use it. */
+ for (i = 0; i < cfg->nhugetlbfs; i++) {
+ hugepagePath = qemuGetBaseHugepagePath(&cfg->hugetlbfs[i]);
+
+ if (!hugepagePath)
+ goto error;
+
+ if (virFileMakePath(hugepagePath) < 0) {
+ virReportSystemError(errno,
+ _("unable to create hugepage path %s"),
+ hugepagePath);
+ goto error;
+ }
+ if (privileged &&
+ virFileUpdatePerm(cfg->hugetlbfs[i].mnt_dir,
+ 0, S_IXGRP | S_IXOTH) < 0)
+ goto error;
+ VIR_FREE(hugepagePath);
+ }
+
+ if (qemuGetMemoryBackingBasePath(cfg, &memoryBackingPath) < 0)
+ goto error;
+
+ if (virFileMakePath(memoryBackingPath) < 0) {
+ virReportSystemError(errno,
+ _("unable to create memory backing path %s"),
+ memoryBackingPath);
+ goto error;
+ }
+
+ if (privileged &&
+ virFileUpdatePerm(memoryBackingPath,
+ 0, S_IXGRP | S_IXOTH) < 0)
+ goto error;
+ VIR_FREE(memoryBackingPath);
+
+ if (!(driver->closeCallbacks = virCloseCallbacksNew()))
+ goto error;
+
+ return driver;
+
+ error:
+ virObjectUnref(conn);
+ VIR_FREE(driverConf);
+ VIR_FREE(hugepagePath);
+ VIR_FREE(memoryBackingPath);
+ virQEMUControllerDriverFree(driver);
+ return NULL;
+}
+
+static void show_help(FILE *io)
+{
+ fprintf(io, "\n");
+ fprintf(io, "syntax: %s [OPTIONS] PATH-TO-XML\n", argv0);
+ fprintf(io, "\n");
+ fprintf(io, "Options\n");
+ fprintf(io, "\n");
+ fprintf(io, " -c URI, --connect URI\n");
+ fprintf(io, " -h, --help\n");
+ fprintf(io, "\n");
+}
+
+static void
+virQEMUControllerMain(void *opaque)
+{
+ int ret = -1;
+ virQEMUControllerPtr ctrl = opaque;
+ virQEMUDriverConfigPtr cfg;
+ virDomainChrSourceDef monitor_chr = { 0 };
+ qemuDomainObjPrivatePtr priv;
+ virDomainPtr dom;
+
+ if (!(ctrl->conn = virConnectOpen(ctrl->uri))) {
+ fprintf(stderr, "Unable to connect to %s: %s",
+ ctrl->uri, virGetLastErrorMessage());
+ goto cleanup;
+ }
+
+ if (!(ctrl->driver = virQEMUControllerNewDriver(ctrl->privileged))) {
+ fprintf(stderr, "Unable to initialize driver: %s",
+ virGetLastErrorMessage());
+ goto cleanup;
+ }
+
+ cfg = virObjectRef(ctrl->driver->config);
+
+ if (qemuProcessPrepareMonitorChr(&monitor_chr, cfg->libDir) < 0) {
+ fprintf(stderr, "Unable to prepare QEMU monitor: %s\n",
+ virGetLastErrorMessage());
+ goto cleanup;
+ }
+
+ if (!(ctrl->vm = virDomainObjNew(ctrl->driver->xmlopt))) {
+ fprintf(stderr, "Unable to allocate domain object: %s\n",
+ virGetLastErrorMessage());
+ goto cleanup;
+ }
+
+ if (!(ctrl->vm->def = virDomainDefParseFile(ctrl->xml,
+ ctrl->driver->caps, ctrl->driver->xmlopt,
+ NULL, VIR_DOMAIN_DEF_PARSE_INACTIVE))) {
+ fprintf(stderr, "Unable to parse domain config %s\n",
+ virGetLastErrorMessage());
+ goto cleanup;
+ }
+
+ if (qemuProcessStart(NULL, ctrl->driver, ctrl->vm, NULL, 0, NULL, -1, NULL, NULL, 0, 0) < 0) {
+ fprintf(stderr, "Unable to start QEMU: %s\n",
+ virGetLastErrorMessage());
+ goto cleanup;
+ }
+
+ priv = ctrl->vm->privateData;
+
+ /* Release the monitor & agent sockets, so main libvirtd can take over */
+ qemuMonitorClose(priv->mon);
+ if (priv->agent)
+ qemuAgentClose(priv->agent);
+
+ dom = virDomainQemuReconnect(ctrl->conn, ctrl->vm->def->name, 0);
+ if (!dom) {
+ qemuProcessStop(ctrl->driver, ctrl->vm, 0, 0, 0);
+ fprintf(stderr, "Unable to reconnect with libvirtd: %s\n",
+ virGetLastErrorMessage());
+ goto cleanup;
+ }
+
+ virObjectUnref(dom);
+
+ fprintf(stderr, "QEMU running and connected\n");
+ ret = 0;
+ cleanup:
+ virConnectClose(ctrl->conn);
+ if (ret < 0)
+ exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv)
+{
+ int rc = 1;
+ virThread thr;
+ virQEMUControllerPtr ctrl;
+ const struct option options[] = {
+ { "connect", 1, NULL, 'c' },
+ { "help", 0, NULL, 'h' },
+ { 0, 0, 0, 0 },
+ };
+
+ argv0 = argv[0];
+
+ if (virGettextInitialize() < 0 ||
+ virThreadInitialize() < 0 ||
+ virErrorInitialize() < 0) {
+ fprintf(stderr, _("%s: initialization failed\n"), argv0);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Initialize logging */
+ virLogSetFromEnv();
+
+ virUpdateSelfLastChanged(argv[0]);
+
+ virFileActivateDirOverride(argv[0]);
+
+ if (VIR_ALLOC(ctrl) < 0)
+ goto cleanup;
+
+ ctrl->privileged = geteuid() == 0;
+ ctrl->uri = ctrl->privileged ? "qemu:///system" : "qemu:///session";
+
+ while (1) {
+ int c;
+
+ c = getopt_long(argc, argv, "c:h",
+ options, NULL);
+
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'c':
+ ctrl->uri = optarg;
+ break;
+
+ case 'h':
+ case '?':
+ show_help(stdout);
+ rc = 0;
+ goto cleanup;
+ }
+ }
+
+ ctrl->xml = argv[optind];
+
+ if (ctrl->xml == NULL) {
+ fprintf(stderr, "Missing XML file path\n");
+ show_help(stderr);
+ goto cleanup;
+ }
+
+ if (virEventRegisterDefaultImpl() < 0) {
+ fprintf(stderr, "Unable to initialize events: %s",
+ virGetLastErrorMessage());
+ goto cleanup;
+ }
+
+ if (virThreadCreate(&thr, false, virQEMUControllerMain, ctrl) < 0)
+ goto cleanup;
+
+ for (;;)
+ virEventRunDefaultImpl();
+
+ rc = 0;
+
+ cleanup:
+ virStateCleanup();
+ if (ctrl->conn)
+ virConnectClose(ctrl->conn);
+ virObjectUnref(ctrl->vm);
+ VIR_FREE(ctrl);
+ return rc;
+}
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index 74b82450b4..8c8e9891c8 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -262,7 +262,7 @@ qemuDomainDisableNamespace(virDomainObjPtr vm,
void qemuDomainEventQueue(virQEMUDriverPtr driver,
virObjectEventPtr event)
{
- if (event)
+ if (event && driver->domainEventState)
virObjectEventStateQueue(driver->domainEventState, event);
}
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index fea1f24250..a7252ea913 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -371,7 +371,7 @@ qemuSecurityChownCallback(const virStorageSource *src,
}
-static int
+int
qemuSecurityInit(virQEMUDriverPtr driver)
{
char **names;
--
2.14.3
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
On Wed, Dec 20, 2017 at 04:47:50PM +0000, Daniel P. Berrange wrote: >This introduces a new binary 'libvirt_qemu' which can be used to launch >guests externally from libvirtd. eg > > libvirt_qemu -c qemu:///system /path/to/xml/file > >This will launch a guest from the requested XML file and then connect to >qemu:///system to register it with libvirtd. At this point all normal >libvirtd operations should generally work. > >NB, this impl has many flaws: > > - We don't generate a unique 'id', so all guests will get id==1. > Surprisingly this doesn't break the world. > > - Tracking of unique name + UUIDs is *not* race free. > > - No tracking/allocation of shared resource state (PCI devices, > etc) > You will also not get the same events as you would when starting the domain as usual. >Most other functionality works, but might have expected results. > If I start a domain with a network, it segfaults. I'll see later if that's my fault or not. It probably (and hopefully) is. >In terms of namespace support there's some restrictions > > - The mount namespace must share certain dirs > > /etc/libvirt > /var/run/libvirt > /var/lib/libvirt > /var/cache/libvirt > > between the libvirtd and libvirt_qemu processes > > - The PID namespace must match libvirtd & libvirt_qemu > though this will be addressed in another patch to > come > > - The network namespace can be different > > - Hotplug/unplug will likely break if separate > namespaces are used > > - The libvirt_qemu will exit if startup fails, however, it > won't exit when QEMU later shuts down - you must listen > for libvirtd events to detect that right now. We'll > fix that > > - Killing the libvirt_qemu shim will not kill the QEMU > process. You must kill via the libvirt API as normal. > This won't change, because we need to be able to > ultimately restart the libvirt_qemu shim in order to > apply software updates to running instance. > We might wire up a special signal though to let > you kill libvirt_qemu & take out QEMU at same time > eg SIGQUIT or something like that perhaps. > IMHO we should use standard signals to do standard things. TERM should gracefully shutdown the domain. Not in PoC, but later. That way users can treat the shim process as other processes. >Signed-off-by: Daniel P. Berrange <berrange@redhat.com> >--- > po/POTFILES.in | 1 + > src/Makefile.am | 49 ++++ > src/qemu/qemu_conf.h | 2 +- > src/qemu/qemu_controller.c | 551 +++++++++++++++++++++++++++++++++++++++++++++ > src/qemu/qemu_domain.c | 2 +- > src/qemu/qemu_driver.c | 2 +- > 6 files changed, 604 insertions(+), 3 deletions(-) > create mode 100644 src/qemu/qemu_controller.c > >diff --git a/po/POTFILES.in b/po/POTFILES.in >index c1fa23427e..d97175b6d5 100644 >--- a/po/POTFILES.in >+++ b/po/POTFILES.in >@@ -133,6 +133,7 @@ src/qemu/qemu_block.c > src/qemu/qemu_capabilities.c > src/qemu/qemu_cgroup.c > src/qemu/qemu_command.c >+src/qemu/qemu_controller.c > src/qemu/qemu_conf.c > src/qemu/qemu_domain.c > src/qemu/qemu_domain_address.c >diff --git a/src/Makefile.am b/src/Makefile.am >index 4c022d1e44..7ca5ad4d3c 100644 >--- a/src/Makefile.am >+++ b/src/Makefile.am >@@ -922,6 +922,9 @@ QEMU_DRIVER_SOURCES = \ > qemu/qemu_capspriv.h \ > qemu/qemu_security.c qemu/qemu_security.h > >+QEMU_CONTROLLER_SOURCES = \ >+ qemu/qemu_controller.c >+ > XENAPI_DRIVER_SOURCES = \ > xenapi/xenapi_driver.c xenapi/xenapi_driver.h \ > xenapi/xenapi_driver_private.h \ >@@ -3115,6 +3118,52 @@ endif WITH_LIBVIRTD > endif WITH_LXC > EXTRA_DIST += $(LXC_CONTROLLER_SOURCES) > >+if WITH_QEMU >+if WITH_LIBVIRTD >+libexec_PROGRAMS += libvirt_qemu >+ Shouldn't I be able to launch this as a user without mgmt app? It should go to bin_PROGRAMS, I presume. >+libvirt_qemu_SOURCES = \ >+ $(QEMU_CONTROLLER_SOURCES) \ >+ $(DATATYPES_SOURCES) >+libvirt_qemu_LDFLAGS = \ >+ $(AM_LDFLAGS) \ >+ $(PIE_LDFLAGS) \ >+ $(NULL) >+libvirt_qemu_LDADD = \ >+ libvirt.la \ >+ libvirt-qemu.la \ >+ libvirt_driver_qemu_impl.la >+if WITH_NETWORK >+libvirt_qemu_LDADD += libvirt_driver_network_impl.la >+endif WITH_NETWORK >+if WITH_STORAGE >+libvirt_qemu_LDADD += libvirt_driver_storage_impl.la >+endif WITH_STORAGE >+libvirt_qemu_LDADD += ../gnulib/lib/libgnu.la $(LIBSOCKET) This is not part of any condition, should be up there with libvirt.la just for clarity. Those are just nits, of course. [...] >+static void >+virQEMUControllerDriverFree(virQEMUDriverPtr driver) >+{ >+ if (!driver) >+ return; >+ >+ virObjectUnref(driver->config); >+ virObjectUnref(driver->hostdevMgr); >+ virHashFree(driver->sharedDevices); >+ virObjectUnref(driver->caps); >+ virObjectUnref(driver->qemuCapsCache); >+ >+ virObjectUnref(driver->domains); >+ virObjectUnref(driver->remotePorts); >+ virObjectUnref(driver->webSocketPorts); >+ virObjectUnref(driver->migrationPorts); >+ virObjectUnref(driver->migrationErrors); >+ >+ virObjectUnref(driver->xmlopt); >+ >+ virSysinfoDefFree(driver->hostsysinfo); >+ >+ virObjectUnref(driver->closeCallbacks); >+ >+ VIR_FREE(driver->qemuImgBinary); >+ >+ virObjectUnref(driver->securityManager); >+ >+ ebtablesContextFree(driver->ebtables); >+ >+ virLockManagerPluginUnref(driver->lockManager); >+ >+ virMutexDestroy(&driver->lock); >+ VIR_FREE(driver); >+} >+ >+static virQEMUDriverPtr virQEMUControllerNewDriver(bool privileged) This is very similar to what I did, but I just exported this function privately si that there is less duplication of code and I added an enum that is used as a parameter instead of the bool @privileged. It is a tristate (user, system, shim) that special-cases the shim slightly. The reason behind that is that I kind of presumed we need to be able to launch system QEMUs with non-root user. Thinking about it I'm not sure that's the case for kubevirt, but it definitely is for others. The way it is done now is that you initialize the driver based on geteuid(), but you connect to any uri specified by the user. What I had in mind was that with this shim PoC users would be able to start their own VMs (if libvirtd permissions are set up the right way, even with some directory access changes done in the daemon) as system VMs as if they had seclabel set up for their user. I think it's feasible, but I maybe overestimated what's possible for the PoC. -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
On Tue, Jan 09, 2018 at 03:13:41PM +0100, Martin Kletzander wrote: > On Wed, Dec 20, 2017 at 04:47:50PM +0000, Daniel P. Berrange wrote: > > This introduces a new binary 'libvirt_qemu' which can be used to launch > > guests externally from libvirtd. eg > > > > libvirt_qemu -c qemu:///system /path/to/xml/file > > > > This will launch a guest from the requested XML file and then connect to > > qemu:///system to register it with libvirtd. At this point all normal > > libvirtd operations should generally work. > > > > NB, this impl has many flaws: > > > > - We don't generate a unique 'id', so all guests will get id==1. > > Surprisingly this doesn't break the world. > > > > - Tracking of unique name + UUIDs is *not* race free. > > > > - No tracking/allocation of shared resource state (PCI devices, > > etc) > > > > You will also not get the same events as you would when starting the domain > as usual. Hmm, yes, interesting. If someone is connected to libvirtd watching events they'll not get any startup events. That's something we'd need to fix. > > Most other functionality works, but might have expected results. > > > > If I start a domain with a network, it segfaults. I'll see later if that's my > fault or not. It probably (and hopefully) is. Not intentional if that's happening ! > > - The libvirt_qemu will exit if startup fails, however, it > > won't exit when QEMU later shuts down - you must listen > > for libvirtd events to detect that right now. We'll > > fix that > > > > - Killing the libvirt_qemu shim will not kill the QEMU > > process. You must kill via the libvirt API as normal. > > This won't change, because we need to be able to > > ultimately restart the libvirt_qemu shim in order to > > apply software updates to running instance. > > We might wire up a special signal though to let > > you kill libvirt_qemu & take out QEMU at same time > > eg SIGQUIT or something like that perhaps. > > > > IMHO we should use standard signals to do standard things. TERM should > gracefully shutdown the domain. Not in PoC, but later. That way users > can treat the shim process as other processes. I guess we can use SIGUSR1 to trigger restart of the shim while leaving QEMU running. > > +if WITH_QEMU > > +if WITH_LIBVIRTD > > +libexec_PROGRAMS += libvirt_qemu > > + > > Shouldn't I be able to launch this as a user without mgmt app? It > should go to bin_PROGRAMS, I presume. Yes > > +libvirt_qemu_SOURCES = \ > > + $(QEMU_CONTROLLER_SOURCES) \ > > + $(DATATYPES_SOURCES) > > +libvirt_qemu_LDFLAGS = \ > > + $(AM_LDFLAGS) \ > > + $(PIE_LDFLAGS) \ > > + $(NULL) > > +libvirt_qemu_LDADD = \ > > + libvirt.la \ > > + libvirt-qemu.la \ > > + libvirt_driver_qemu_impl.la > > +if WITH_NETWORK > > +libvirt_qemu_LDADD += libvirt_driver_network_impl.la > > +endif WITH_NETWORK > > +if WITH_STORAGE > > +libvirt_qemu_LDADD += libvirt_driver_storage_impl.la > > +endif WITH_STORAGE > > > +libvirt_qemu_LDADD += ../gnulib/lib/libgnu.la $(LIBSOCKET) > > This is not part of any condition, should be up there with libvirt.la > just for clarity. IIRC, libgnu.la needs to be the last library listed > > +static void > > +virQEMUControllerDriverFree(virQEMUDriverPtr driver) > > +{ > > + if (!driver) > > + return; > > + > > + virObjectUnref(driver->config); > > + virObjectUnref(driver->hostdevMgr); > > + virHashFree(driver->sharedDevices); > > + virObjectUnref(driver->caps); > > + virObjectUnref(driver->qemuCapsCache); > > + > > + virObjectUnref(driver->domains); > > + virObjectUnref(driver->remotePorts); > > + virObjectUnref(driver->webSocketPorts); > > + virObjectUnref(driver->migrationPorts); > > + virObjectUnref(driver->migrationErrors); > > + > > + virObjectUnref(driver->xmlopt); > > + > > + virSysinfoDefFree(driver->hostsysinfo); > > + > > + virObjectUnref(driver->closeCallbacks); > > + > > + VIR_FREE(driver->qemuImgBinary); > > + > > + virObjectUnref(driver->securityManager); > > + > > + ebtablesContextFree(driver->ebtables); > > + > > + virLockManagerPluginUnref(driver->lockManager); > > + > > + virMutexDestroy(&driver->lock); > > + VIR_FREE(driver); > > +} > > + > > +static virQEMUDriverPtr virQEMUControllerNewDriver(bool privileged) > > This is very similar to what I did, but I just exported this function > privately si that there is less duplication of code and I added an enum > that is used as a parameter instead of the bool @privileged. It is a > tristate (user, system, shim) that special-cases the shim slightly. Yeah, there's definitely much more duplication here that I would like. I would expect to refactor this better. > The reason behind that is that I kind of presumed we need to be able to > launch system QEMUs with non-root user. Thinking about it I'm not sure > that's the case for kubevirt, but it definitely is for others. The way > it is done now is that you initialize the driver based on geteuid(), but > you connect to any uri specified by the user. What I had in mind was > that with this shim PoC users would be able to start their own VMs (if > libvirtd permissions are set up the right way, even with some directory > access changes done in the daemon) as system VMs as if they had seclabel > set up for their user. I think it's feasible, but I maybe overestimated > what's possible for the PoC. Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :| -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
© 2016 - 2025 Red Hat, Inc.