mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-23 14:15:28 +00:00
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:
parent
42f43592be
commit
558b7fd03d
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user