提交 3ba937da 编写于 作者: D Daniel P. Berrange

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
上级 2c2effa1
...@@ -234,6 +234,7 @@ typedef virDomainInfo *virDomainInfoPtr; ...@@ -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) ...@@ -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: ...@@ -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); ...@@ -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 ...@@ -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, ...@@ -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, ...@@ -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) { ...@@ -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) { ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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[] = { ...@@ -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) ...@@ -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[] = { ...@@ -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) ...@@ -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 ...@@ -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. ...@@ -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>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册