mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 21:55:25 +00:00
Allow automatic kill of guests when a connection is closed
If an application is using libvirt + KVM as a piece of its internal infrastructure to perform a specific task, it can be desirable to guarentee the VM dies when the virConnectPtr disconnects from libvirtd. This ensures the app can't leak any VMs it was using. Adding VIR_DOMAIN_START_AUTOKILL as a flag when starting guests enables this to be done. * include/libvirt/libvirt.h.in: All VIR_DOMAIN_START_AUTOKILL * src/qemu/qemu_driver.c: Support automatic killing of guests upon connection close * tools/virsh.c: Add --autokill flag to 'start' and 'create' commands
This commit is contained in:
parent
2c2effa1d7
commit
3ba937da42
@ -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;
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
@ -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)
|
||||
|
@ -392,13 +392,16 @@ I<devname> 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<create> I<FILE> optional I<--console> I<--paused>
|
||||
=item B<create> I<FILE> optional I<--console> I<--paused> I<--autodestroy>
|
||||
|
||||
Create a domain from an XML <file>. An easy way to create the XML
|
||||
<file> is to use the B<dumpxml> 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<Example>
|
||||
|
||||
@ -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<on_shutdown> parameter in the domain's XML definition.
|
||||
|
||||
=item B<start> I<domain-name> optional I<--console> I<--paused>
|
||||
=item B<start> I<domain-name> optional I<--console> I<--paused> I<--autodestroy>
|
||||
|
||||
Start a (previously defined) inactive domain, either from the last
|
||||
B<managedsave> 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<suspend> I<domain-id>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user