From: "Daniel P. Berrange" <berrange@xxxxxxxxxx> I wrote this months ago and thought I had already submitted/merged it. Obviously not. I need this for the virt sandbox tools asap. 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 --- src/lxc/lxc_conf.h | 5 ++ src/lxc/lxc_driver.c | 140 +++++++++++++++++++++++++++++++++++++++++-- src/uml/uml_conf.h | 6 ++ src/uml/uml_driver.c | 164 +++++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 289 insertions(+), 26 deletions(-) diff --git a/src/lxc/lxc_conf.h b/src/lxc/lxc_conf.h index 66aa469..b124330 100644 --- a/src/lxc/lxc_conf.h +++ b/src/lxc/lxc_conf.h @@ -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); diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c index c475887..f08e8d1 100644 --- a/src/lxc/lxc_driver.c +++ b/src/lxc/lxc_driver.c @@ -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); diff --git a/src/uml/uml_conf.h b/src/uml/uml_conf.h index 5401a7e..657f877 100644 --- a/src/uml/uml_conf.h +++ b/src/uml/uml_conf.h @@ -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; }; diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 2b7219a..16ab73a 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -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, ¨_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, -- 1.7.6.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list