]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Add infrastructure to automatically destroy guests when a connection closes
authorDaniel P. Berrange <berrange@redhat.com>
Thu, 23 Jun 2011 09:37:57 +0000 (10:37 +0100)
committerDaniel P. Berrange <berrange@redhat.com>
Fri, 24 Jun 2011 11:15:10 +0000 (12:15 +0100)
Sometimes it is useful to be able to automatically destroy a guest when
a connection is closed. For example, kill an incoming migration if
the client managing the migration dies. This introduces a map between
guest 'uuid' strings and virConnectPtr objects. When a connection is
closed, any associated guests are killed off.

* src/qemu/qemu_conf.h: Add autokill hash table to qemu driver
* src/qemu/qemu_process.c, src/qemu/qemu_process.h: Add APIs
  for performing autokill of guests associated with a connection
* src/qemu/qemu_driver.c: Initialize autodestroy map

src/qemu/qemu_conf.h
src/qemu/qemu_driver.c
src/qemu/qemu_migration.c
src/qemu/qemu_process.c
src/qemu/qemu_process.h

index bf6dcf4275fe559469c82d2902225ae8381ec1b2..fa4c607d4a15775e3ddd4a400b67d372d45c7c92 100644 (file)
@@ -127,6 +127,11 @@ struct qemud_driver {
     virSysinfoDefPtr hostsysinfo;
 
     virLockManagerPluginPtr lockManager;
+
+    /* Mapping of 'char *uuidstr' -> virConnectPtr
+     * of guests which will be automatically killed
+     * when the virConnectPtr is closed*/
+    virHashTablePtr autodestroy;
 };
 
 typedef struct _qemuDomainCmdlineDef qemuDomainCmdlineDef;
index 18fa4e0cd81937d157327659123e420ae782c54f..e73f0d715afba594872d2e7c9e4a6dc6ea3aa4ca 100644 (file)
@@ -603,6 +603,9 @@ qemudStartup(int privileged) {
         qemu_driver->hugepage_path = mempath;
     }
 
+    if (qemuProcessAutoDestroyInit(qemu_driver) < 0)
+        goto error;
+
     /* Get all the running persistent or transient configs first */
     if (virDomainLoadAllConfigs(qemu_driver->caps,
                                 &qemu_driver->domains,
@@ -736,6 +739,8 @@ qemudShutdown(void) {
 
     virSysinfoDefFree(qemu_driver->hostsysinfo);
 
+    qemuProcessAutoDestroyShutdown(qemu_driver);
+
     VIR_FREE(qemu_driver->configDir);
     VIR_FREE(qemu_driver->autostartDir);
     VIR_FREE(qemu_driver->logDir);
@@ -860,6 +865,7 @@ static int qemudClose(virConnectPtr conn) {
     qemuDriverLock(driver);
     virDomainEventCallbackListRemoveConn(conn,
                                          driver->domainEventState->callbacks);
+    qemuProcessAutoDestroyRun(driver, conn);
     qemuDriverUnlock(driver);
 
     conn->privateData = NULL;
@@ -1271,6 +1277,7 @@ static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
 
     if (qemuProcessStart(conn, driver, vm, NULL,
                          (flags & VIR_DOMAIN_START_PAUSED) != 0,
+                         false,
                          -1, NULL, VIR_VM_OP_CREATE) < 0) {
         qemuAuditDomainStart(vm, "booted", false);
         if (qemuDomainObjEndJob(vm) > 0)
@@ -3528,8 +3535,8 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
     }
 
     /* Set the migration source and start it up. */
-    ret = qemuProcessStart(conn, driver, vm, "stdio", true, *fd, path,
-                           VIR_VM_OP_RESTORE);
+    ret = qemuProcessStart(conn, driver, vm, "stdio", true,
+                           false, *fd, path, VIR_VM_OP_RESTORE);
 
     if (intermediatefd != -1) {
         if (ret < 0) {
@@ -3898,8 +3905,8 @@ static int qemudDomainObjStart(virConnectPtr conn,
         goto cleanup;
     }
 
-    ret = qemuProcessStart(conn, driver, vm, NULL, start_paused, -1, NULL,
-                           VIR_VM_OP_CREATE);
+    ret = qemuProcessStart(conn, driver, vm, NULL, start_paused,
+                           false, -1, NULL, VIR_VM_OP_CREATE);
     qemuAuditDomainStart(vm, "booted", ret >= 0);
     if (ret >= 0) {
         virDomainEventPtr event =
@@ -7854,7 +7861,7 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
                 goto endjob;
 
             rc = qemuProcessStart(snapshot->domain->conn, driver, vm, NULL,
-                                  false, -1, NULL, VIR_VM_OP_CREATE);
+                                  false, false, -1, NULL, VIR_VM_OP_CREATE);
             qemuAuditDomainStart(vm, "from-snapshot", rc >= 0);
             if (qemuDomainSnapshotSetCurrentInactive(vm, driver->snapshotDir) < 0)
                 goto endjob;
index 87e0417120ae286b045476f716117b39167e4d3b..fbee6538341821ee303666518a342df5d365faf8 100644 (file)
@@ -1119,8 +1119,9 @@ qemuMigrationPrepareTunnel(struct qemud_driver *driver,
     /* Start the QEMU daemon, with the same command-line arguments plus
      * -incoming stdio (which qemu_command might convert to exec:cat or fd:n)
      */
-    internalret = qemuProcessStart(dconn, driver, vm, "stdio", true, dataFD[0],
-                                   NULL, VIR_VM_OP_MIGRATE_IN_START);
+    internalret = qemuProcessStart(dconn, driver, vm, "stdio", true,
+                                   false, dataFD[0], NULL,
+                                   VIR_VM_OP_MIGRATE_IN_START);
     if (internalret < 0) {
         qemuAuditDomainStart(vm, "migrated", false);
         /* Note that we don't set an error here because qemuProcessStart
@@ -1347,7 +1348,7 @@ qemuMigrationPrepareDirect(struct qemud_driver *driver,
      * -incoming tcp:0.0.0.0:port
      */
     snprintf (migrateFrom, sizeof (migrateFrom), "tcp:0.0.0.0:%d", this_port);
-    if (qemuProcessStart(dconn, driver, vm, migrateFrom, true,
+    if (qemuProcessStart(dconn, driver, vm, migrateFrom, true, false,
                          -1, NULL, VIR_VM_OP_MIGRATE_IN_START) < 0) {
         qemuAuditDomainStart(vm, "migrated", false);
         /* Note that we don't set an error here because qemuProcessStart
index f8f95e2db09af267a503f1722cfea1551b209543..b4b745e3c926193c9923b903ed317b28d2a60822 100644 (file)
@@ -55,6 +55,7 @@
 #include "processinfo.h"
 #include "domain_nwfilter.h"
 #include "locking/domain_lock.h"
+#include "uuid.h"
 
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
@@ -2408,6 +2409,7 @@ int qemuProcessStart(virConnectPtr conn,
                      virDomainObjPtr vm,
                      const char *migrateFrom,
                      bool start_paused,
+                     bool autodestroy,
                      int stdin_fd,
                      const char *stdin_path,
                      enum virVMOperationType vmop)
@@ -2795,6 +2797,10 @@ int qemuProcessStart(virConnectPtr conn,
                              VIR_DOMAIN_PAUSED_USER);
     }
 
+    if (autodestroy &&
+        qemuProcessAutoDestroyAdd(driver, vm, conn) < 0)
+        goto cleanup;
+
     VIR_DEBUG("Writing domain status to disk");
     if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
         goto cleanup;
@@ -2935,6 +2941,9 @@ void qemuProcessStop(struct qemud_driver *driver,
     /* shut it off for sure */
     qemuProcessKill(vm);
 
+    /* Stop autodestroy in case guest is restarted */
+    qemuProcessAutoDestroyRemove(driver, vm);
+
     /* now that we know it's stopped call the hook if present */
     if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
         char *xml = virDomainDefFormat(vm->def, 0);
@@ -3037,3 +3046,115 @@ retry:
         virFreeError(orig_err);
     }
 }
+
+
+int qemuProcessAutoDestroyInit(struct qemud_driver *driver)
+{
+    if (!(driver->autodestroy = virHashCreate(5, NULL)))
+        return -1;
+
+    return 0;
+}
+
+struct qemuProcessAutoDestroyData {
+    struct qemud_driver *driver;
+    virConnectPtr conn;
+};
+
+static void qemuProcessAutoDestroyDom(void *payload,
+                                      const void *name,
+                                      void *opaque)
+{
+    struct qemuProcessAutoDestroyData *data = opaque;
+    virConnectPtr conn = payload;
+    const char *uuidstr = name;
+    unsigned char uuid[VIR_UUID_BUFLEN];
+    virDomainObjPtr dom;
+    qemuDomainObjPrivatePtr priv;
+    virDomainEventPtr event = NULL;
+
+    VIR_DEBUG("conn=%p uuidstr=%s thisconn=%p", conn, uuidstr, data->conn);
+
+    if (data->conn != conn)
+        return;
+
+    if (virUUIDParse(uuidstr, uuid) < 0) {
+        VIR_WARN("Failed to parse %s", uuidstr);
+        return;
+    }
+
+    if (!(dom = virDomainFindByUUID(&data->driver->domains,
+                                    uuid))) {
+        VIR_DEBUG("No domain object to kill");
+        return;
+    }
+
+    priv = dom->privateData;
+    if (priv->jobActive == QEMU_JOB_MIGRATION_IN) {
+        VIR_DEBUG("vm=%s has incoming migration active, cancelling",
+                  dom->def->name);
+        priv->jobActive = QEMU_JOB_NONE;
+        memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
+    }
+
+    if (qemuDomainObjBeginJobWithDriver(data->driver, dom) < 0)
+        goto cleanup;
+
+    VIR_DEBUG("Killing domain");
+    qemuProcessStop(data->driver, dom, 1, VIR_DOMAIN_SHUTOFF_DESTROYED);
+    qemuAuditDomainStop(dom, "destroyed");
+    event = virDomainEventNewFromObj(dom,
+                                     VIR_DOMAIN_EVENT_STOPPED,
+                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
+    if (qemuDomainObjEndJob(dom) == 0)
+        dom = NULL;
+    if (dom && !dom->persistent)
+        virDomainRemoveInactive(&data->driver->domains, dom);
+
+cleanup:
+    if (dom)
+        virDomainObjUnlock(dom);
+    if (event)
+        qemuDomainEventQueue(data->driver, event);
+    virHashRemoveEntry(data->driver->autodestroy, uuidstr);
+}
+
+/*
+ * Precondition: driver is locked
+ */
+void qemuProcessAutoDestroyRun(struct qemud_driver *driver, virConnectPtr conn)
+{
+    struct qemuProcessAutoDestroyData data = {
+        driver, conn
+    };
+    VIR_DEBUG("conn=%p", conn);
+    virHashForEach(driver->autodestroy, qemuProcessAutoDestroyDom, &data);
+}
+
+void qemuProcessAutoDestroyShutdown(struct qemud_driver *driver)
+{
+    virHashFree(driver->autodestroy);
+}
+
+int qemuProcessAutoDestroyAdd(struct qemud_driver *driver,
+                              virDomainObjPtr vm,
+                              virConnectPtr conn)
+{
+    char uuidstr[VIR_UUID_STRING_BUFLEN];
+    virUUIDFormat(vm->def->uuid, uuidstr);
+    VIR_DEBUG("vm=%s uuid=%s conn=%p", vm->def->name, uuidstr, conn);
+    if (virHashAddEntry(driver->autodestroy, uuidstr, conn) < 0)
+        return -1;
+    return 0;
+}
+
+int qemuProcessAutoDestroyRemove(struct qemud_driver *driver,
+                                 virDomainObjPtr vm)
+{
+    char uuidstr[VIR_UUID_STRING_BUFLEN];
+    virUUIDFormat(vm->def->uuid, uuidstr);
+    VIR_DEBUG("vm=%s uuid=%s", vm->def->name, uuidstr);
+    if (virHashRemoveEntry(driver->autodestroy, uuidstr) < 0)
+        return -1;
+    return 0;
+}
index 7ec9d7d70d0d51a807e49921124cc900387fc496..7c5e8e803a83ff41528515f5a0913bada9b26137 100644 (file)
@@ -46,6 +46,7 @@ int qemuProcessStart(virConnectPtr conn,
                      virDomainObjPtr vm,
                      const char *migrateFrom,
                      bool start_paused,
+                     bool autodestroy,
                      int stdin_fd,
                      const char *stdin_path,
                      enum virVMOperationType vmop);
@@ -57,4 +58,15 @@ void qemuProcessStop(struct qemud_driver *driver,
 
 void qemuProcessKill(virDomainObjPtr vm);
 
+int qemuProcessAutoDestroyInit(struct qemud_driver *driver);
+void qemuProcessAutoDestroyRun(struct qemud_driver *driver,
+                               virConnectPtr conn);
+void qemuProcessAutoDestroyShutdown(struct qemud_driver *driver);
+int qemuProcessAutoDestroyAdd(struct qemud_driver *driver,
+                              virDomainObjPtr vm,
+                              virConnectPtr conn);
+int qemuProcessAutoDestroyRemove(struct qemud_driver *driver,
+                                 virDomainObjPtr vm);
+
+
 #endif /* __QEMU_PROCESS_H__ */