Add support for autodestroy of guests to the LXC and UML drivers

We recently added support for VIR_DOMAIN_START_AUTODESTROY and
an impl to the QEMU driver. It is very desirable to support in
other drivers, so this adds it to LXC and UML

* src/lxc/lxc_conf.h, src/lxc/lxc_driver.c,
  src/uml/uml_conf.h, src/uml/uml_driver.c: Wire up autodestroy
  functions
This commit is contained in:
Daniel P. Berrange 2011-07-13 12:21:54 +01:00
parent 07862822f3
commit 02e92dc470
4 changed files with 289 additions and 26 deletions

View File

@ -56,6 +56,11 @@ struct __lxc_driver {
int have_netns;
virDomainEventStatePtr domainEventState;
/* Mapping of 'char *uuidstr' -> virConnectPtr
* of guests which will be automatically killed
* when the virConnectPtr is closed*/
virHashTablePtr autodestroy;
};
int lxcLoadDriverConfig(lxc_driver_t *driver);

View File

@ -110,6 +110,19 @@ static void lxcDomainEventFlush(int timer, void *opaque);
static void lxcDomainEventQueue(lxc_driver_t *driver,
virDomainEventPtr event);
static int lxcVmTerminate(lxc_driver_t *driver,
virDomainObjPtr vm,
virDomainShutoffReason reason);
static int lxcProcessAutoDestroyInit(lxc_driver_t *driver);
static void lxcProcessAutoDestroyRun(lxc_driver_t *driver,
virConnectPtr conn);
static void lxcProcessAutoDestroyShutdown(lxc_driver_t *driver);
static int lxcProcessAutoDestroyAdd(lxc_driver_t *driver,
virDomainObjPtr vm,
virConnectPtr conn);
static int lxcProcessAutoDestroyRemove(lxc_driver_t *driver,
virDomainObjPtr vm);
static virDrvOpenStatus lxcOpen(virConnectPtr conn,
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
@ -165,6 +178,7 @@ static int lxcClose(virConnectPtr conn)
lxcDriverLock(driver);
virDomainEventCallbackListRemoveConn(conn,
driver->domainEventState->callbacks);
lxcProcessAutoDestroyRun(driver, conn);
lxcDriverUnlock(driver);
conn->privateData = NULL;
@ -1001,6 +1015,104 @@ cleanup:
}
static int lxcProcessAutoDestroyInit(lxc_driver_t *driver)
{
if (!(driver->autodestroy = virHashCreate(5, NULL)))
return -1;
return 0;
}
struct lxcProcessAutoDestroyData {
lxc_driver_t *driver;
virConnectPtr conn;
};
static void lxcProcessAutoDestroyDom(void *payload,
const void *name,
void *opaque)
{
struct lxcProcessAutoDestroyData *data = opaque;
virConnectPtr conn = payload;
const char *uuidstr = name;
unsigned char uuid[VIR_UUID_BUFLEN];
virDomainObjPtr dom;
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;
}
VIR_DEBUG("Killing domain");
lxcVmTerminate(data->driver, dom, VIR_DOMAIN_SHUTOFF_DESTROYED);
virDomainAuditStop(dom, "destroyed");
event = virDomainEventNewFromObj(dom,
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
if (dom && !dom->persistent)
virDomainRemoveInactive(&data->driver->domains, dom);
if (dom)
virDomainObjUnlock(dom);
if (event)
lxcDomainEventQueue(data->driver, event);
virHashRemoveEntry(data->driver->autodestroy, uuidstr);
}
/*
* Precondition: driver is locked
*/
static void lxcProcessAutoDestroyRun(lxc_driver_t *driver, virConnectPtr conn)
{
struct lxcProcessAutoDestroyData data = {
driver, conn
};
VIR_DEBUG("conn=%p", conn);
virHashForEach(driver->autodestroy, lxcProcessAutoDestroyDom, &data);
}
static void lxcProcessAutoDestroyShutdown(lxc_driver_t *driver)
{
virHashFree(driver->autodestroy);
}
static int lxcProcessAutoDestroyAdd(lxc_driver_t *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;
}
static int lxcProcessAutoDestroyRemove(lxc_driver_t *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;
}
/**
* lxcVmCleanup:
* @driver: pointer to driver structure
@ -1028,6 +1140,9 @@ static void lxcVmCleanup(lxc_driver_t *driver,
VIR_FREE(xml);
}
/* Stop autodestroy in case guest is restarted */
lxcProcessAutoDestroyRemove(driver, vm);
virEventRemoveHandle(priv->monitorWatch);
VIR_FORCE_CLOSE(priv->monitor);
@ -1496,6 +1611,7 @@ cleanup:
* @conn: pointer to connection
* @driver: pointer to driver structure
* @vm: pointer to virtual machine structure
* @autoDestroy: mark the domain for auto destruction
* @reason: reason for switching vm to running state
*
* Starts a vm
@ -1505,6 +1621,7 @@ cleanup:
static int lxcVmStart(virConnectPtr conn,
lxc_driver_t * driver,
virDomainObjPtr vm,
bool autoDestroy,
virDomainRunningReason reason)
{
int rc = -1, r;
@ -1665,6 +1782,10 @@ static int lxcVmStart(virConnectPtr conn,
goto cleanup;
}
if (autoDestroy &&
lxcProcessAutoDestroyAdd(driver, vm, conn) < 0)
goto cleanup;
/*
* Again, need to save the live configuration, because the function
* requires vm->def->id != -1 to save tty info surely.
@ -1719,7 +1840,7 @@ static int lxcDomainStartWithFlags(virDomainPtr dom, unsigned int flags)
virDomainEventPtr event = NULL;
int ret = -1;
virCheckFlags(0, -1);
virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
lxcDriverLock(driver);
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
@ -1743,7 +1864,9 @@ static int lxcDomainStartWithFlags(virDomainPtr dom, unsigned int flags)
goto cleanup;
}
ret = lxcVmStart(dom->conn, driver, vm, VIR_DOMAIN_RUNNING_BOOTED);
ret = lxcVmStart(dom->conn, driver, vm,
(flags & VIR_DOMAIN_START_AUTODESTROY),
VIR_DOMAIN_RUNNING_BOOTED);
if (ret == 0) {
event = virDomainEventNewFromObj(vm,
@ -1796,7 +1919,7 @@ lxcDomainCreateAndStart(virConnectPtr conn,
virDomainPtr dom = NULL;
virDomainEventPtr event = NULL;
virCheckFlags(0, NULL);
virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, NULL);
lxcDriverLock(driver);
if (!(def = virDomainDefParseString(driver->caps, xml,
@ -1819,7 +1942,9 @@ lxcDomainCreateAndStart(virConnectPtr conn,
goto cleanup;
def = NULL;
if (lxcVmStart(conn, driver, vm, VIR_DOMAIN_RUNNING_BOOTED) < 0) {
if (lxcVmStart(conn, driver, vm,
(flags & VIR_DOMAIN_START_AUTODESTROY),
VIR_DOMAIN_RUNNING_BOOTED) < 0) {
virDomainAuditStart(vm, "booted", false);
virDomainRemoveInactive(&driver->domains, vm);
vm = NULL;
@ -2054,7 +2179,7 @@ lxcAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaqu
virDomainObjLock(vm);
if (vm->autostart &&
!virDomainObjIsActive(vm)) {
int ret = lxcVmStart(data->conn, data->driver, vm,
int ret = lxcVmStart(data->conn, data->driver, vm, false,
VIR_DOMAIN_RUNNING_BOOTED);
virDomainAuditStart(vm, "booted", ret >= 0);
if (ret < 0) {
@ -2205,6 +2330,9 @@ static int lxcStartup(int privileged)
lxc_driver->caps->privateDataAllocFunc = lxcDomainObjPrivateAlloc;
lxc_driver->caps->privateDataFreeFunc = lxcDomainObjPrivateFree;
if (lxcProcessAutoDestroyInit(lxc_driver) < 0)
goto cleanup;
/* Get all the running persistent or transient configs first */
if (virDomainLoadAllConfigs(lxc_driver->caps,
&lxc_driver->domains,
@ -2285,6 +2413,8 @@ static int lxcShutdown(void)
virDomainObjListDeinit(&lxc_driver->domains);
virDomainEventStateFree(lxc_driver->domainEventState);
lxcProcessAutoDestroyShutdown(lxc_driver);
virCapabilitiesFree(lxc_driver->caps);
VIR_FREE(lxc_driver->configDir);
VIR_FREE(lxc_driver->autostartDir);

View File

@ -33,6 +33,7 @@
# include "virterror_internal.h"
# include "threads.h"
# include "command.h"
# include "hash.h"
# define umlDebug(fmt, ...) do {} while(0)
@ -64,6 +65,11 @@ struct uml_driver {
/* Event handling */
virDomainEventStatePtr domainEventState;
/* Mapping of 'char *uuidstr' -> virConnectPtr
* of guests which will be automatically killed
* when the virConnectPtr is closed*/
virHashTablePtr autodestroy;
};

View File

@ -75,6 +75,16 @@ struct _umlDomainObjPrivate {
int monitorWatch;
};
static int umlProcessAutoDestroyInit(struct uml_driver *driver);
static void umlProcessAutoDestroyRun(struct uml_driver *driver,
virConnectPtr conn);
static void umlProcessAutoDestroyShutdown(struct uml_driver *driver);
static int umlProcessAutoDestroyAdd(struct uml_driver *driver,
virDomainObjPtr vm,
virConnectPtr conn);
static int umlProcessAutoDestroyRemove(struct uml_driver *driver,
virDomainObjPtr vm);
static int umlShutdown(void);
@ -119,10 +129,10 @@ static void umlDomainEventQueue(struct uml_driver *driver,
static int umlStartVMDaemon(virConnectPtr conn,
struct uml_driver *driver,
virDomainObjPtr vm);
virDomainObjPtr vm,
bool autoDestroy);
static void umlShutdownVMDaemon(virConnectPtr conn,
struct uml_driver *driver,
static void umlShutdownVMDaemon(struct uml_driver *driver,
virDomainObjPtr vm,
virDomainShutoffReason reason);
@ -150,7 +160,7 @@ umlAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaqu
!virDomainObjIsActive(vm)) {
int ret;
virResetLastError();
ret = umlStartVMDaemon(data->conn, data->driver, vm);
ret = umlStartVMDaemon(data->conn, data->driver, vm, false);
virDomainAuditStart(vm, "booted", ret >= 0);
if (ret < 0) {
virErrorPtr err = virGetLastError();
@ -309,7 +319,7 @@ reread:
continue;
}
umlShutdownVMDaemon(NULL, driver, dom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
umlShutdownVMDaemon(driver, dom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
virDomainAuditStop(dom, "shutdown");
event = virDomainEventNewFromObj(dom,
VIR_DOMAIN_EVENT_STOPPED,
@ -337,7 +347,7 @@ reread:
if (umlOpenMonitor(driver, dom) < 0) {
VIR_WARN("Could not open monitor for new domain");
umlShutdownVMDaemon(NULL, driver, dom,
umlShutdownVMDaemon(driver, dom,
VIR_DOMAIN_SHUTOFF_FAILED);
virDomainAuditStop(dom, "failed");
event = virDomainEventNewFromObj(dom,
@ -350,7 +360,7 @@ reread:
}
} else if (umlIdentifyChrPTY(driver, dom) < 0) {
VIR_WARN("Could not identify character devices for new domain");
umlShutdownVMDaemon(NULL, driver, dom,
umlShutdownVMDaemon(driver, dom,
VIR_DOMAIN_SHUTOFF_FAILED);
virDomainAuditStop(dom, "failed");
event = virDomainEventNewFromObj(dom,
@ -480,6 +490,9 @@ umlStartup(int privileged)
umlInotifyEvent, uml_driver, NULL)) < 0)
goto error;
if (umlProcessAutoDestroyInit(uml_driver) < 0)
goto error;
if (virDomainLoadAllConfigs(uml_driver->caps,
&uml_driver->domains,
uml_driver->configDir,
@ -577,7 +590,7 @@ umlShutdownOneVM(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaque)
virDomainObjLock(dom);
if (virDomainObjIsActive(dom)) {
umlShutdownVMDaemon(NULL, driver, dom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
umlShutdownVMDaemon(driver, dom, VIR_DOMAIN_SHUTOFF_SHUTDOWN);
virDomainAuditStop(dom, "shutdown");
}
virDomainObjUnlock(dom);
@ -612,6 +625,8 @@ umlShutdown(void) {
VIR_FREE(uml_driver->autostartDir);
VIR_FREE(uml_driver->monitorDir);
umlProcessAutoDestroyShutdown(uml_driver);
if (uml_driver->brctl)
brShutdown(uml_driver->brctl);
@ -623,6 +638,104 @@ umlShutdown(void) {
}
static int umlProcessAutoDestroyInit(struct uml_driver *driver)
{
if (!(driver->autodestroy = virHashCreate(5, NULL)))
return -1;
return 0;
}
struct umlProcessAutoDestroyData {
struct uml_driver *driver;
virConnectPtr conn;
};
static void umlProcessAutoDestroyDom(void *payload,
const void *name,
void *opaque)
{
struct umlProcessAutoDestroyData *data = opaque;
virConnectPtr conn = payload;
const char *uuidstr = name;
unsigned char uuid[VIR_UUID_BUFLEN];
virDomainObjPtr dom;
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;
}
VIR_DEBUG("Killing domain");
umlShutdownVMDaemon(data->driver, dom, VIR_DOMAIN_SHUTOFF_DESTROYED);
virDomainAuditStop(dom, "destroyed");
event = virDomainEventNewFromObj(dom,
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
if (dom && !dom->persistent)
virDomainRemoveInactive(&data->driver->domains, dom);
if (dom)
virDomainObjUnlock(dom);
if (event)
umlDomainEventQueue(data->driver, event);
virHashRemoveEntry(data->driver->autodestroy, uuidstr);
}
/*
* Precondition: driver is locked
*/
static void umlProcessAutoDestroyRun(struct uml_driver *driver, virConnectPtr conn)
{
struct umlProcessAutoDestroyData data = {
driver, conn
};
VIR_DEBUG("conn=%p", conn);
virHashForEach(driver->autodestroy, umlProcessAutoDestroyDom, &data);
}
static void umlProcessAutoDestroyShutdown(struct uml_driver *driver)
{
virHashFree(driver->autodestroy);
}
static int umlProcessAutoDestroyAdd(struct uml_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;
}
static int umlProcessAutoDestroyRemove(struct uml_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;
}
static int umlReadPidFile(struct uml_driver *driver,
virDomainObjPtr vm)
{
@ -842,8 +955,7 @@ error:
}
static int umlCleanupTapDevices(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainObjPtr vm) {
static int umlCleanupTapDevices(virDomainObjPtr vm) {
int i;
int err;
int ret = 0;
@ -873,7 +985,8 @@ static int umlCleanupTapDevices(virConnectPtr conn ATTRIBUTE_UNUSED,
static int umlStartVMDaemon(virConnectPtr conn,
struct uml_driver *driver,
virDomainObjPtr vm) {
virDomainObjPtr vm,
bool autoDestroy) {
int ret;
char *logfile;
int logfd = -1;
@ -935,7 +1048,7 @@ static int umlStartVMDaemon(virConnectPtr conn,
if (!(cmd = umlBuildCommandLine(conn, driver, vm))) {
VIR_FORCE_CLOSE(logfd);
virDomainConfVMNWFilterTeardown(vm);
umlCleanupTapDevices(conn, vm);
umlCleanupTapDevices(vm);
return -1;
}
@ -953,13 +1066,17 @@ static int umlStartVMDaemon(virConnectPtr conn,
if (ret < 0)
goto cleanup;
if (autoDestroy &&
umlProcessAutoDestroyAdd(driver, vm, conn) < 0)
goto cleanup;
ret = virDomainObjSetDefTransient(driver->caps, vm, false);
cleanup:
virCommandFree(cmd);
if (ret < 0) {
virDomainConfVMNWFilterTeardown(vm);
umlCleanupTapDevices(conn, vm);
umlCleanupTapDevices(vm);
}
/* NB we don't mark it running here - we do that async
@ -972,8 +1089,7 @@ cleanup:
return ret;
}
static void umlShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
struct uml_driver *driver ATTRIBUTE_UNUSED,
static void umlShutdownVMDaemon(struct uml_driver *driver,
virDomainObjPtr vm,
virDomainShutoffReason reason)
{
@ -997,7 +1113,10 @@ static void umlShutdownVMDaemon(virConnectPtr conn ATTRIBUTE_UNUSED,
virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, reason);
virDomainConfVMNWFilterTeardown(vm);
umlCleanupTapDevices(conn, vm);
umlCleanupTapDevices(vm);
/* Stop autodestroy in case guest is restarted */
umlProcessAutoDestroyRemove(driver, vm);
if (vm->newDef) {
virDomainDefFree(vm->def);
@ -1072,6 +1191,7 @@ static int umlClose(virConnectPtr conn) {
umlDriverLock(driver);
virDomainEventCallbackListRemoveConn(conn,
driver->domainEventState->callbacks);
umlProcessAutoDestroyRun(driver, conn);
umlDriverUnlock(driver);
conn->privateData = NULL;
@ -1342,7 +1462,7 @@ static virDomainPtr umlDomainCreate(virConnectPtr conn, const char *xml,
virDomainPtr dom = NULL;
virDomainEventPtr event = NULL;
virCheckFlags(0, NULL);
virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, NULL);
umlDriverLock(driver);
if (!(def = virDomainDefParseString(driver->caps, xml,
@ -1359,7 +1479,8 @@ static virDomainPtr umlDomainCreate(virConnectPtr conn, const char *xml,
goto cleanup;
def = NULL;
if (umlStartVMDaemon(conn, driver, vm) < 0) {
if (umlStartVMDaemon(conn, driver, vm,
(flags & VIR_DOMAIN_START_AUTODESTROY)) < 0) {
virDomainAuditStart(vm, "booted", false);
virDomainRemoveInactive(&driver->domains,
vm);
@ -1436,7 +1557,7 @@ umlDomainDestroyFlags(virDomainPtr dom,
goto cleanup;
}
umlShutdownVMDaemon(dom->conn, driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
umlShutdownVMDaemon(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED);
virDomainAuditStop(vm, "destroyed");
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STOPPED,
@ -1717,7 +1838,7 @@ static int umlDomainStartWithFlags(virDomainPtr dom, unsigned int flags) {
virDomainEventPtr event = NULL;
int ret = -1;
virCheckFlags(0, -1);
virCheckFlags(VIR_DOMAIN_START_AUTODESTROY, -1);
umlDriverLock(driver);
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
@ -1728,7 +1849,8 @@ static int umlDomainStartWithFlags(virDomainPtr dom, unsigned int flags) {
goto cleanup;
}
ret = umlStartVMDaemon(dom->conn, driver, vm);
ret = umlStartVMDaemon(dom->conn, driver, vm,
(flags & VIR_DOMAIN_START_AUTODESTROY));
virDomainAuditStart(vm, "booted", ret >= 0);
if (ret == 0)
event = virDomainEventNewFromObj(vm,