diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 3f634e683f..edf876ef48 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -234,6 +234,7 @@ typedef virDomainInfo *virDomainInfoPtr; typedef enum { VIR_DOMAIN_NONE = 0, /* Default behavior */ VIR_DOMAIN_START_PAUSED = 1 << 0, /* Launch guest in paused state */ + VIR_DOMAIN_START_AUTODESTROY = 1 << 1, /* Automatically kill guest when virConnectPtr is closed */ } virDomainCreateFlags; diff --git a/src/libvirt.c b/src/libvirt.c index 69e0ea89ba..8a2988c0f7 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -1793,6 +1793,17 @@ virDomainGetConnect (virDomainPtr dom) * is destroyed, or if the host is restarted (see virDomainDefineXML() to * define persistent domains). * + * If the VIR_DOMAIN_START_PAUSED flag is set, the guest domain + * will be started, but its CPUs will remain paused. The CPUs + * can later be manually started using virDomainResume. + * + * If the VIR_DOMAIN_START_AUTODESTROY flag is set, the guest + * domain will be automatically destroyed when the virConnectPtr + * object is finally released. This will also happen if the + * client application crashes / looses its connection to the + * libvirtd daemon. Any domains marked for auto destroy will + * block attempts at migration or save-to-file + * * Returns a new domain object or NULL in case of failure */ virDomainPtr @@ -6522,6 +6533,17 @@ error: * Launch a defined domain. If the call succeeds the domain moves from the * defined to the running domains pools. * + * If the VIR_DOMAIN_START_PAUSED flag is set, the guest domain + * will be started, but its CPUs will remain paused. The CPUs + * can later be manually started using virDomainResume. + * + * If the VIR_DOMAIN_START_AUTODESTROY flag is set, the guest + * domain will be automatically destroyed when the virConnectPtr + * object is finally released. This will also happen if the + * client application crashes / looses its connection to the + * libvirtd daemon. Any domains marked for auto destroy will + * block attempts at migration or save-to-file + * * Returns 0 in case of success, -1 in case of error */ int diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index e73f0d715a..32a5ba1743 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -119,7 +119,8 @@ static int qemudShutdown(void); static int qemudDomainObjStart(virConnectPtr conn, struct qemud_driver *driver, virDomainObjPtr vm, - bool start_paused); + bool start_paused, + bool autodestroy); static int qemudDomainGetMaxVcpus(virDomainPtr dom); @@ -148,7 +149,7 @@ qemuAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaq } else { if (vm->autostart && !virDomainObjIsActive(vm) && - qemudDomainObjStart(data->conn, data->driver, vm, false) < 0) { + qemudDomainObjStart(data->conn, data->driver, vm, false, false) < 0) { err = virGetLastError(); VIR_ERROR(_("Failed to autostart VM '%s': %s"), vm->def->name, @@ -1246,7 +1247,8 @@ static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml, virDomainPtr dom = NULL; virDomainEventPtr event = NULL; - virCheckFlags(VIR_DOMAIN_START_PAUSED, NULL); + virCheckFlags(VIR_DOMAIN_START_PAUSED | + VIR_DOMAIN_START_AUTODESTROY, NULL); qemuDriverLock(driver); if (!(def = virDomainDefParseString(driver->caps, xml, @@ -1277,7 +1279,7 @@ static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml, if (qemuProcessStart(conn, driver, vm, NULL, (flags & VIR_DOMAIN_START_PAUSED) != 0, - false, + (flags & VIR_DOMAIN_START_AUTODESTROY) != 0, -1, NULL, VIR_VM_OP_CREATE) < 0) { qemuAuditDomainStart(vm, "booted", false); if (qemuDomainObjEndJob(vm) > 0) @@ -1333,6 +1335,12 @@ static int qemudDomainSuspend(virDomainPtr dom) { goto cleanup; } + if (qemuProcessAutoDestroyActive(driver, vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is marked for auto destroy")); + goto cleanup; + } + priv = vm->privateData; if (priv->jobActive == QEMU_JOB_MIGRATION_OUT) { @@ -3882,7 +3890,8 @@ static int qemudNumDefinedDomains(virConnectPtr conn) { static int qemudDomainObjStart(virConnectPtr conn, struct qemud_driver *driver, virDomainObjPtr vm, - bool start_paused) + bool start_paused, + bool autodestroy) { int ret = -1; char *managed_save; @@ -3906,7 +3915,7 @@ static int qemudDomainObjStart(virConnectPtr conn, } ret = qemuProcessStart(conn, driver, vm, NULL, start_paused, - false, -1, NULL, VIR_VM_OP_CREATE); + autodestroy, -1, NULL, VIR_VM_OP_CREATE); qemuAuditDomainStart(vm, "booted", ret >= 0); if (ret >= 0) { virDomainEventPtr event = @@ -3929,7 +3938,8 @@ qemudDomainStartWithFlags(virDomainPtr dom, unsigned int flags) virDomainObjPtr vm; int ret = -1; - virCheckFlags(VIR_DOMAIN_START_PAUSED, -1); + virCheckFlags(VIR_DOMAIN_START_PAUSED | + VIR_DOMAIN_START_AUTODESTROY, -1); qemuDriverLock(driver); vm = virDomainFindByUUID(&driver->domains, dom->uuid); @@ -3951,8 +3961,12 @@ qemudDomainStartWithFlags(virDomainPtr dom, unsigned int flags) goto endjob; } - ret = qemudDomainObjStart(dom->conn, driver, vm, - (flags & VIR_DOMAIN_START_PAUSED) != 0); + if (qemudDomainObjStart(dom->conn, driver, vm, + (flags & VIR_DOMAIN_START_PAUSED) != 0, + (flags & VIR_DOMAIN_START_AUTODESTROY) != 0) < 0) + goto endjob; + + ret = 0; endjob: if (qemuDomainObjEndJob(vm) == 0) diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c index dcbc15889b..78acffb60f 100644 --- a/src/qemu/qemu_migration.c +++ b/src/qemu/qemu_migration.c @@ -1000,6 +1000,12 @@ char *qemuMigrationBegin(struct qemud_driver *driver, goto cleanup; } + if (qemuProcessAutoDestroyActive(driver, vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is marked for auto destroy")); + goto cleanup; + } + if (!qemuMigrationIsAllowed(vm->def)) goto cleanup; @@ -2288,6 +2294,12 @@ int qemuMigrationPerform(struct qemud_driver *driver, goto endjob; } + if (qemuProcessAutoDestroyActive(driver, vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is marked for auto destroy")); + goto endjob; + } + memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index b4b745e3c9..2d2037b100 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -3158,3 +3158,14 @@ int qemuProcessAutoDestroyRemove(struct qemud_driver *driver, return -1; return 0; } + +bool qemuProcessAutoDestroyActive(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 (virHashLookup(driver->autodestroy, uuidstr) != NULL) + return true; + return false; +} diff --git a/src/qemu/qemu_process.h b/src/qemu/qemu_process.h index 7c5e8e803a..0e74d2a57a 100644 --- a/src/qemu/qemu_process.h +++ b/src/qemu/qemu_process.h @@ -67,6 +67,7 @@ int qemuProcessAutoDestroyAdd(struct qemud_driver *driver, virConnectPtr conn); int qemuProcessAutoDestroyRemove(struct qemud_driver *driver, virDomainObjPtr vm); - +bool qemuProcessAutoDestroyActive(struct qemud_driver *driver, + virDomainObjPtr vm); #endif /* __QEMU_PROCESS_H__ */ diff --git a/tools/virsh.c b/tools/virsh.c index fcd254db7a..cafbb4bb94 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -1305,6 +1305,7 @@ static const vshCmdOptDef opts_create[] = { {"console", VSH_OT_BOOL, 0, N_("attach to console after creation")}, #endif {"paused", VSH_OT_BOOL, 0, N_("leave the guest paused after creation")}, + {"autodestroy", VSH_OT_BOOL, 0, N_("automatically destroy the guest when virsh disconnects")}, {NULL, 0, 0, NULL} }; @@ -1331,6 +1332,8 @@ cmdCreate(vshControl *ctl, const vshCmd *cmd) if (vshCommandOptBool(cmd, "paused")) flags |= VIR_DOMAIN_START_PAUSED; + if (vshCommandOptBool(cmd, "autodestroy")) + flags |= VIR_DOMAIN_START_AUTODESTROY; dom = virDomainCreateXML(ctl->conn, buffer, flags); VIR_FREE(buffer); @@ -1466,6 +1469,7 @@ static const vshCmdOptDef opts_start[] = { {"console", VSH_OT_BOOL, 0, N_("attach to console after creation")}, #endif {"paused", VSH_OT_BOOL, 0, N_("leave the guest paused after creation")}, + {"autodestroy", VSH_OT_BOOL, 0, N_("automatically destroy the guest when virsh disconnects")}, {NULL, 0, 0, NULL} }; @@ -1494,6 +1498,8 @@ cmdStart(vshControl *ctl, const vshCmd *cmd) if (vshCommandOptBool(cmd, "paused")) flags |= VIR_DOMAIN_START_PAUSED; + if (vshCommandOptBool(cmd, "autodestroy")) + flags |= VIR_DOMAIN_START_AUTODESTROY; /* Prefer older API unless we have to pass a flag. */ if ((flags ? virDomainCreateWithFlags(dom, flags) diff --git a/tools/virsh.pod b/tools/virsh.pod index 023ab42d44..bdaea48e92 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -392,13 +392,16 @@ I parameter refers to the device alias of an alternate console, serial or parallel device configured for the guest. If omitted, the primary console will be opened. -=item B I optional I<--console> I<--paused> +=item B I optional I<--console> I<--paused> I<--autodestroy> Create a domain from an XML . An easy way to create the XML is to use the B command to obtain the definition of a pre-existing guest. The domain will be paused if the I<--paused> option is used and supported by the driver; otherwise it will be running. If I<--console> is requested, attach to the console after creation. +If I<--autodestroy> is requested, then the guest will be automatically +destroyed when virsh closes its connection to libvirt, or otherwise +exits. B @@ -786,13 +789,16 @@ services must be shutdown in the domain. The exact behavior of a domain when it shuts down is set by the I parameter in the domain's XML definition. -=item B I optional I<--console> I<--paused> +=item B I optional I<--console> I<--paused> I<--autodestroy> Start a (previously defined) inactive domain, either from the last B state, or via a fresh boot if no managedsave state is present. The domain will be paused if the I<--paused> option is used and supported by the driver; otherwise it will be running. If I<--console> is requested, attach to the console after creation. +If I<--autodestroy> is requested, then the guest will be automatically +destroyed when virsh closes its connection to libvirt, or otherwise +exits. =item B I