Add infrastructure to automatically destroy guests when a connection closes

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
This commit is contained in:
Daniel P. Berrange 2011-06-23 10:37:57 +01:00
parent 42f43592be
commit 558b7fd03d
5 changed files with 154 additions and 8 deletions

View File

@ -127,6 +127,11 @@ struct qemud_driver {
virSysinfoDefPtr hostsysinfo; virSysinfoDefPtr hostsysinfo;
virLockManagerPluginPtr lockManager; 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; typedef struct _qemuDomainCmdlineDef qemuDomainCmdlineDef;

View File

@ -603,6 +603,9 @@ qemudStartup(int privileged) {
qemu_driver->hugepage_path = mempath; qemu_driver->hugepage_path = mempath;
} }
if (qemuProcessAutoDestroyInit(qemu_driver) < 0)
goto error;
/* Get all the running persistent or transient configs first */ /* Get all the running persistent or transient configs first */
if (virDomainLoadAllConfigs(qemu_driver->caps, if (virDomainLoadAllConfigs(qemu_driver->caps,
&qemu_driver->domains, &qemu_driver->domains,
@ -736,6 +739,8 @@ qemudShutdown(void) {
virSysinfoDefFree(qemu_driver->hostsysinfo); virSysinfoDefFree(qemu_driver->hostsysinfo);
qemuProcessAutoDestroyShutdown(qemu_driver);
VIR_FREE(qemu_driver->configDir); VIR_FREE(qemu_driver->configDir);
VIR_FREE(qemu_driver->autostartDir); VIR_FREE(qemu_driver->autostartDir);
VIR_FREE(qemu_driver->logDir); VIR_FREE(qemu_driver->logDir);
@ -860,6 +865,7 @@ static int qemudClose(virConnectPtr conn) {
qemuDriverLock(driver); qemuDriverLock(driver);
virDomainEventCallbackListRemoveConn(conn, virDomainEventCallbackListRemoveConn(conn,
driver->domainEventState->callbacks); driver->domainEventState->callbacks);
qemuProcessAutoDestroyRun(driver, conn);
qemuDriverUnlock(driver); qemuDriverUnlock(driver);
conn->privateData = NULL; conn->privateData = NULL;
@ -1271,6 +1277,7 @@ static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
if (qemuProcessStart(conn, driver, vm, NULL, if (qemuProcessStart(conn, driver, vm, NULL,
(flags & VIR_DOMAIN_START_PAUSED) != 0, (flags & VIR_DOMAIN_START_PAUSED) != 0,
false,
-1, NULL, VIR_VM_OP_CREATE) < 0) { -1, NULL, VIR_VM_OP_CREATE) < 0) {
qemuAuditDomainStart(vm, "booted", false); qemuAuditDomainStart(vm, "booted", false);
if (qemuDomainObjEndJob(vm) > 0) if (qemuDomainObjEndJob(vm) > 0)
@ -3528,8 +3535,8 @@ qemuDomainSaveImageStartVM(virConnectPtr conn,
} }
/* Set the migration source and start it up. */ /* Set the migration source and start it up. */
ret = qemuProcessStart(conn, driver, vm, "stdio", true, *fd, path, ret = qemuProcessStart(conn, driver, vm, "stdio", true,
VIR_VM_OP_RESTORE); false, *fd, path, VIR_VM_OP_RESTORE);
if (intermediatefd != -1) { if (intermediatefd != -1) {
if (ret < 0) { if (ret < 0) {
@ -3898,8 +3905,8 @@ static int qemudDomainObjStart(virConnectPtr conn,
goto cleanup; goto cleanup;
} }
ret = qemuProcessStart(conn, driver, vm, NULL, start_paused, -1, NULL, ret = qemuProcessStart(conn, driver, vm, NULL, start_paused,
VIR_VM_OP_CREATE); false, -1, NULL, VIR_VM_OP_CREATE);
qemuAuditDomainStart(vm, "booted", ret >= 0); qemuAuditDomainStart(vm, "booted", ret >= 0);
if (ret >= 0) { if (ret >= 0) {
virDomainEventPtr event = virDomainEventPtr event =
@ -7854,7 +7861,7 @@ static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
goto endjob; goto endjob;
rc = qemuProcessStart(snapshot->domain->conn, driver, vm, NULL, 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); qemuAuditDomainStart(vm, "from-snapshot", rc >= 0);
if (qemuDomainSnapshotSetCurrentInactive(vm, driver->snapshotDir) < 0) if (qemuDomainSnapshotSetCurrentInactive(vm, driver->snapshotDir) < 0)
goto endjob; goto endjob;

View File

@ -1119,8 +1119,9 @@ qemuMigrationPrepareTunnel(struct qemud_driver *driver,
/* Start the QEMU daemon, with the same command-line arguments plus /* Start the QEMU daemon, with the same command-line arguments plus
* -incoming stdio (which qemu_command might convert to exec:cat or fd:n) * -incoming stdio (which qemu_command might convert to exec:cat or fd:n)
*/ */
internalret = qemuProcessStart(dconn, driver, vm, "stdio", true, dataFD[0], internalret = qemuProcessStart(dconn, driver, vm, "stdio", true,
NULL, VIR_VM_OP_MIGRATE_IN_START); false, dataFD[0], NULL,
VIR_VM_OP_MIGRATE_IN_START);
if (internalret < 0) { if (internalret < 0) {
qemuAuditDomainStart(vm, "migrated", false); qemuAuditDomainStart(vm, "migrated", false);
/* Note that we don't set an error here because qemuProcessStart /* 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 * -incoming tcp:0.0.0.0:port
*/ */
snprintf (migrateFrom, sizeof (migrateFrom), "tcp:0.0.0.0:%d", this_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) { -1, NULL, VIR_VM_OP_MIGRATE_IN_START) < 0) {
qemuAuditDomainStart(vm, "migrated", false); qemuAuditDomainStart(vm, "migrated", false);
/* Note that we don't set an error here because qemuProcessStart /* Note that we don't set an error here because qemuProcessStart

View File

@ -55,6 +55,7 @@
#include "processinfo.h" #include "processinfo.h"
#include "domain_nwfilter.h" #include "domain_nwfilter.h"
#include "locking/domain_lock.h" #include "locking/domain_lock.h"
#include "uuid.h"
#define VIR_FROM_THIS VIR_FROM_QEMU #define VIR_FROM_THIS VIR_FROM_QEMU
@ -2408,6 +2409,7 @@ int qemuProcessStart(virConnectPtr conn,
virDomainObjPtr vm, virDomainObjPtr vm,
const char *migrateFrom, const char *migrateFrom,
bool start_paused, bool start_paused,
bool autodestroy,
int stdin_fd, int stdin_fd,
const char *stdin_path, const char *stdin_path,
enum virVMOperationType vmop) enum virVMOperationType vmop)
@ -2795,6 +2797,10 @@ int qemuProcessStart(virConnectPtr conn,
VIR_DOMAIN_PAUSED_USER); VIR_DOMAIN_PAUSED_USER);
} }
if (autodestroy &&
qemuProcessAutoDestroyAdd(driver, vm, conn) < 0)
goto cleanup;
VIR_DEBUG("Writing domain status to disk"); VIR_DEBUG("Writing domain status to disk");
if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
goto cleanup; goto cleanup;
@ -2935,6 +2941,9 @@ void qemuProcessStop(struct qemud_driver *driver,
/* shut it off for sure */ /* shut it off for sure */
qemuProcessKill(vm); qemuProcessKill(vm);
/* Stop autodestroy in case guest is restarted */
qemuProcessAutoDestroyRemove(driver, vm);
/* now that we know it's stopped call the hook if present */ /* now that we know it's stopped call the hook if present */
if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) { if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
char *xml = virDomainDefFormat(vm->def, 0); char *xml = virDomainDefFormat(vm->def, 0);
@ -3037,3 +3046,115 @@ retry:
virFreeError(orig_err); 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;
}

View File

@ -46,6 +46,7 @@ int qemuProcessStart(virConnectPtr conn,
virDomainObjPtr vm, virDomainObjPtr vm,
const char *migrateFrom, const char *migrateFrom,
bool start_paused, bool start_paused,
bool autodestroy,
int stdin_fd, int stdin_fd,
const char *stdin_path, const char *stdin_path,
enum virVMOperationType vmop); enum virVMOperationType vmop);
@ -57,4 +58,15 @@ void qemuProcessStop(struct qemud_driver *driver,
void qemuProcessKill(virDomainObjPtr vm); 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__ */ #endif /* __QEMU_PROCESS_H__ */