mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-11 09:17:52 +03: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 {
|
typedef enum {
|
||||||
VIR_DOMAIN_NONE = 0, /* Default behavior */
|
VIR_DOMAIN_NONE = 0, /* Default behavior */
|
||||||
VIR_DOMAIN_START_PAUSED = 1 << 0, /* Launch guest in paused state */
|
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;
|
} virDomainCreateFlags;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1793,6 +1793,17 @@ virDomainGetConnect (virDomainPtr dom)
|
|||||||
* is destroyed, or if the host is restarted (see virDomainDefineXML() to
|
* is destroyed, or if the host is restarted (see virDomainDefineXML() to
|
||||||
* define persistent domains).
|
* 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
|
* Returns a new domain object or NULL in case of failure
|
||||||
*/
|
*/
|
||||||
virDomainPtr
|
virDomainPtr
|
||||||
@ -6522,6 +6533,17 @@ error:
|
|||||||
* Launch a defined domain. If the call succeeds the domain moves from the
|
* Launch a defined domain. If the call succeeds the domain moves from the
|
||||||
* defined to the running domains pools.
|
* 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
|
* Returns 0 in case of success, -1 in case of error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
@ -119,7 +119,8 @@ static int qemudShutdown(void);
|
|||||||
static int qemudDomainObjStart(virConnectPtr conn,
|
static int qemudDomainObjStart(virConnectPtr conn,
|
||||||
struct qemud_driver *driver,
|
struct qemud_driver *driver,
|
||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
bool start_paused);
|
bool start_paused,
|
||||||
|
bool autodestroy);
|
||||||
|
|
||||||
static int qemudDomainGetMaxVcpus(virDomainPtr dom);
|
static int qemudDomainGetMaxVcpus(virDomainPtr dom);
|
||||||
|
|
||||||
@ -148,7 +149,7 @@ qemuAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED, void *opaq
|
|||||||
} else {
|
} else {
|
||||||
if (vm->autostart &&
|
if (vm->autostart &&
|
||||||
!virDomainObjIsActive(vm) &&
|
!virDomainObjIsActive(vm) &&
|
||||||
qemudDomainObjStart(data->conn, data->driver, vm, false) < 0) {
|
qemudDomainObjStart(data->conn, data->driver, vm, false, false) < 0) {
|
||||||
err = virGetLastError();
|
err = virGetLastError();
|
||||||
VIR_ERROR(_("Failed to autostart VM '%s': %s"),
|
VIR_ERROR(_("Failed to autostart VM '%s': %s"),
|
||||||
vm->def->name,
|
vm->def->name,
|
||||||
@ -1246,7 +1247,8 @@ static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
|
|||||||
virDomainPtr dom = NULL;
|
virDomainPtr dom = NULL;
|
||||||
virDomainEventPtr event = NULL;
|
virDomainEventPtr event = NULL;
|
||||||
|
|
||||||
virCheckFlags(VIR_DOMAIN_START_PAUSED, NULL);
|
virCheckFlags(VIR_DOMAIN_START_PAUSED |
|
||||||
|
VIR_DOMAIN_START_AUTODESTROY, NULL);
|
||||||
|
|
||||||
qemuDriverLock(driver);
|
qemuDriverLock(driver);
|
||||||
if (!(def = virDomainDefParseString(driver->caps, xml,
|
if (!(def = virDomainDefParseString(driver->caps, xml,
|
||||||
@ -1277,7 +1279,7 @@ static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
|
|||||||
|
|
||||||
if (qemuProcessStart(conn, driver, vm, NULL,
|
if (qemuProcessStart(conn, driver, vm, NULL,
|
||||||
(flags & VIR_DOMAIN_START_PAUSED) != 0,
|
(flags & VIR_DOMAIN_START_PAUSED) != 0,
|
||||||
false,
|
(flags & VIR_DOMAIN_START_AUTODESTROY) != 0,
|
||||||
-1, NULL, VIR_VM_OP_CREATE) < 0) {
|
-1, NULL, VIR_VM_OP_CREATE) < 0) {
|
||||||
qemuAuditDomainStart(vm, "booted", false);
|
qemuAuditDomainStart(vm, "booted", false);
|
||||||
if (qemuDomainObjEndJob(vm) > 0)
|
if (qemuDomainObjEndJob(vm) > 0)
|
||||||
@ -1333,6 +1335,12 @@ static int qemudDomainSuspend(virDomainPtr dom) {
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (qemuProcessAutoDestroyActive(driver, vm)) {
|
||||||
|
qemuReportError(VIR_ERR_OPERATION_INVALID,
|
||||||
|
"%s", _("domain is marked for auto destroy"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
priv = vm->privateData;
|
priv = vm->privateData;
|
||||||
|
|
||||||
if (priv->jobActive == QEMU_JOB_MIGRATION_OUT) {
|
if (priv->jobActive == QEMU_JOB_MIGRATION_OUT) {
|
||||||
@ -3882,7 +3890,8 @@ static int qemudNumDefinedDomains(virConnectPtr conn) {
|
|||||||
static int qemudDomainObjStart(virConnectPtr conn,
|
static int qemudDomainObjStart(virConnectPtr conn,
|
||||||
struct qemud_driver *driver,
|
struct qemud_driver *driver,
|
||||||
virDomainObjPtr vm,
|
virDomainObjPtr vm,
|
||||||
bool start_paused)
|
bool start_paused,
|
||||||
|
bool autodestroy)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
char *managed_save;
|
char *managed_save;
|
||||||
@ -3906,7 +3915,7 @@ static int qemudDomainObjStart(virConnectPtr conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = qemuProcessStart(conn, driver, vm, NULL, start_paused,
|
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);
|
qemuAuditDomainStart(vm, "booted", ret >= 0);
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
virDomainEventPtr event =
|
virDomainEventPtr event =
|
||||||
@ -3929,7 +3938,8 @@ qemudDomainStartWithFlags(virDomainPtr dom, unsigned int flags)
|
|||||||
virDomainObjPtr vm;
|
virDomainObjPtr vm;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
virCheckFlags(VIR_DOMAIN_START_PAUSED, -1);
|
virCheckFlags(VIR_DOMAIN_START_PAUSED |
|
||||||
|
VIR_DOMAIN_START_AUTODESTROY, -1);
|
||||||
|
|
||||||
qemuDriverLock(driver);
|
qemuDriverLock(driver);
|
||||||
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
vm = virDomainFindByUUID(&driver->domains, dom->uuid);
|
||||||
@ -3951,8 +3961,12 @@ qemudDomainStartWithFlags(virDomainPtr dom, unsigned int flags)
|
|||||||
goto endjob;
|
goto endjob;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = qemudDomainObjStart(dom->conn, driver, vm,
|
if (qemudDomainObjStart(dom->conn, driver, vm,
|
||||||
(flags & VIR_DOMAIN_START_PAUSED) != 0);
|
(flags & VIR_DOMAIN_START_PAUSED) != 0,
|
||||||
|
(flags & VIR_DOMAIN_START_AUTODESTROY) != 0) < 0)
|
||||||
|
goto endjob;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
endjob:
|
endjob:
|
||||||
if (qemuDomainObjEndJob(vm) == 0)
|
if (qemuDomainObjEndJob(vm) == 0)
|
||||||
|
@ -1000,6 +1000,12 @@ char *qemuMigrationBegin(struct qemud_driver *driver,
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (qemuProcessAutoDestroyActive(driver, vm)) {
|
||||||
|
qemuReportError(VIR_ERR_OPERATION_INVALID,
|
||||||
|
"%s", _("domain is marked for auto destroy"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
if (!qemuMigrationIsAllowed(vm->def))
|
if (!qemuMigrationIsAllowed(vm->def))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
@ -2288,6 +2294,12 @@ int qemuMigrationPerform(struct qemud_driver *driver,
|
|||||||
goto endjob;
|
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));
|
memset(&priv->jobInfo, 0, sizeof(priv->jobInfo));
|
||||||
priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED;
|
priv->jobInfo.type = VIR_DOMAIN_JOB_UNBOUNDED;
|
||||||
|
|
||||||
|
@ -3158,3 +3158,14 @@ int qemuProcessAutoDestroyRemove(struct qemud_driver *driver,
|
|||||||
return -1;
|
return -1;
|
||||||
return 0;
|
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);
|
virConnectPtr conn);
|
||||||
int qemuProcessAutoDestroyRemove(struct qemud_driver *driver,
|
int qemuProcessAutoDestroyRemove(struct qemud_driver *driver,
|
||||||
virDomainObjPtr vm);
|
virDomainObjPtr vm);
|
||||||
|
bool qemuProcessAutoDestroyActive(struct qemud_driver *driver,
|
||||||
|
virDomainObjPtr vm);
|
||||||
|
|
||||||
#endif /* __QEMU_PROCESS_H__ */
|
#endif /* __QEMU_PROCESS_H__ */
|
||||||
|
@ -1305,6 +1305,7 @@ static const vshCmdOptDef opts_create[] = {
|
|||||||
{"console", VSH_OT_BOOL, 0, N_("attach to console after creation")},
|
{"console", VSH_OT_BOOL, 0, N_("attach to console after creation")},
|
||||||
#endif
|
#endif
|
||||||
{"paused", VSH_OT_BOOL, 0, N_("leave the guest paused after creation")},
|
{"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}
|
{NULL, 0, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1331,6 +1332,8 @@ cmdCreate(vshControl *ctl, const vshCmd *cmd)
|
|||||||
|
|
||||||
if (vshCommandOptBool(cmd, "paused"))
|
if (vshCommandOptBool(cmd, "paused"))
|
||||||
flags |= VIR_DOMAIN_START_PAUSED;
|
flags |= VIR_DOMAIN_START_PAUSED;
|
||||||
|
if (vshCommandOptBool(cmd, "autodestroy"))
|
||||||
|
flags |= VIR_DOMAIN_START_AUTODESTROY;
|
||||||
|
|
||||||
dom = virDomainCreateXML(ctl->conn, buffer, flags);
|
dom = virDomainCreateXML(ctl->conn, buffer, flags);
|
||||||
VIR_FREE(buffer);
|
VIR_FREE(buffer);
|
||||||
@ -1466,6 +1469,7 @@ static const vshCmdOptDef opts_start[] = {
|
|||||||
{"console", VSH_OT_BOOL, 0, N_("attach to console after creation")},
|
{"console", VSH_OT_BOOL, 0, N_("attach to console after creation")},
|
||||||
#endif
|
#endif
|
||||||
{"paused", VSH_OT_BOOL, 0, N_("leave the guest paused after creation")},
|
{"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}
|
{NULL, 0, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1494,6 +1498,8 @@ cmdStart(vshControl *ctl, const vshCmd *cmd)
|
|||||||
|
|
||||||
if (vshCommandOptBool(cmd, "paused"))
|
if (vshCommandOptBool(cmd, "paused"))
|
||||||
flags |= VIR_DOMAIN_START_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. */
|
/* Prefer older API unless we have to pass a flag. */
|
||||||
if ((flags ? virDomainCreateWithFlags(dom, flags)
|
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.
|
console, serial or parallel device configured for the guest.
|
||||||
If omitted, the primary console will be opened.
|
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
|
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
|
<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
|
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.
|
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<--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>
|
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
|
The exact behavior of a domain when it shuts down is set by the
|
||||||
I<on_shutdown> parameter in the domain's XML definition.
|
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
|
Start a (previously defined) inactive domain, either from the last
|
||||||
B<managedsave> state, or via a fresh boot if no managedsave state is
|
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
|
present. The domain will be paused if the I<--paused> option is
|
||||||
used and supported by the driver; otherwise it will be running.
|
used and supported by the driver; otherwise it will be running.
|
||||||
If I<--console> is requested, attach to the console after creation.
|
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>
|
=item B<suspend> I<domain-id>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user