1
0
mirror of https://gitlab.com/libvirt/libvirt.git synced 2024-12-23 21:34:54 +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:
Daniel P. Berrange 2011-06-23 11:41:57 +01:00
parent 2c2effa1d7
commit 3ba937da42
8 changed files with 85 additions and 12 deletions

View File

@ -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;

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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;
}

View File

@ -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__ */

View File

@ -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)

View File

@ -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>