mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-23 06:05:27 +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;
|
||||
|
||||
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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
Loading…
Reference in New Issue
Block a user