mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-21 20:15:17 +00:00
libxl: add hooks support
Introduce libxl hook and use it for start, prepare, started, stop, stopped, migrate events.
This commit is contained in:
parent
a9aafc0aa0
commit
7d3b2eb58f
@ -17,8 +17,10 @@
|
||||
(<span class="since">since 0.8.0</span>)<br/><br/></li>
|
||||
<li>A QEMU guest is started or stopped
|
||||
(<span class="since">since 0.8.0</span>)<br/><br/></li>
|
||||
<li>An LXC guest is started or stopped
|
||||
<li>An LXC guest is started or stopped
|
||||
(<span class="since">since 0.8.0</span>)<br/><br/></li>
|
||||
<li>A libxl-handled Xen guest is started or stopped
|
||||
(<span class="since">since 2.1.0</span>)<br/><br/></li>
|
||||
<li>A network is started or stopped or an interface is
|
||||
plugged/unplugged to/from the network
|
||||
(<span class="since">since 1.2.2</span>)<br/><br/></li>
|
||||
@ -41,7 +43,7 @@
|
||||
<br/>
|
||||
|
||||
<h2><a name="names">Script names</a></h2>
|
||||
<p>At present, there are three hook scripts that can be called:</p>
|
||||
<p>At present, there are five hook scripts that can be called:</p>
|
||||
<ul>
|
||||
<li><code>/etc/libvirt/hooks/daemon</code><br/><br/>
|
||||
Executed when the libvirt daemon is started, stopped, or reloads
|
||||
@ -50,6 +52,9 @@
|
||||
Executed when a QEMU guest is started, stopped, or migrated<br/><br/></li>
|
||||
<li><code>/etc/libvirt/hooks/lxc</code><br /><br/>
|
||||
Executed when an LXC guest is started or stopped</li>
|
||||
<li><code>/etc/libvirt/hooks/libxl</code><br/><br/>
|
||||
Executed when a libxl-handled Xen guest is started, stopped, or
|
||||
migrated<br/><br/></li>
|
||||
<li><code>/etc/libvirt/hooks/network</code><br/><br/>
|
||||
Executed when a network is started or stopped or an
|
||||
interface is plugged/unplugged to/from the network</li>
|
||||
@ -235,6 +240,50 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h5><a name="libxl">/etc/libvirt/hooks/libxl</a></h5>
|
||||
<ul>
|
||||
<li>Before a Xen guest is started using libxl driver, the libxl hook
|
||||
script is called in three locations; if any location fails, the guest
|
||||
is not started. The first location, <span class="since">since
|
||||
2.1.0</span>, is before libvirt performs any resource
|
||||
labeling, and the hook can allocate resources not managed by
|
||||
libvirt. This is called as:<br/>
|
||||
<pre>/etc/libvirt/hooks/libxl guest_name prepare begin -</pre>
|
||||
The second location, available <span class="since">Since
|
||||
2.1.0</span>, occurs after libvirt has finished labeling
|
||||
all resources, but has not yet started the guest, called as:<br/>
|
||||
<pre>/etc/libvirt/hooks/libxl guest_name start begin -</pre>
|
||||
The third location, <span class="since">2.1.0</span>,
|
||||
occurs after the domain has successfully started up:<br/>
|
||||
<pre>/etc/libvirt/hooks/libxl guest_name started begin -</pre>
|
||||
</li>
|
||||
<li>When a libxl-handled Xen guest is stopped, the libxl hook script
|
||||
is called in two locations, to match the startup.
|
||||
First, <span class="since">since 2.1.0</span>, the hook is
|
||||
called before libvirt restores any labels:<br/>
|
||||
<pre>/etc/libvirt/hooks/libxl guest_name stopped end -</pre>
|
||||
Then, after libvirt has released all resources, the hook is
|
||||
called again, <span class="since">since 2.1.0</span>, to allow
|
||||
any additional resource cleanup:<br/>
|
||||
<pre>/etc/libvirt/hooks/libxl guest_name release end -</pre></li>
|
||||
<li><span class="since">Since 2.1.0</span>, the libxl hook script
|
||||
is also called at the beginning of incoming migration. It is called
|
||||
as: <pre>/etc/libvirt/hooks/libxl guest_name migrate begin -</pre>
|
||||
with domain XML sent to standard input of the script. In this case,
|
||||
the script acts as a filter and is supposed to modify the domain
|
||||
XML and print it out on its standard output. Empty output is
|
||||
identical to copying the input XML without changing it. In case the
|
||||
script returns failure or the output XML is not valid, incoming
|
||||
migration will be canceled. This hook may be used, e.g., to change
|
||||
location of disk images for incoming domains.</li>
|
||||
<li><span class="since">Since 2.1.0</span>, the libxl hook script
|
||||
is also called when the libvirtd daemon restarts and reconnects
|
||||
to previously running Xen domains. If the script fails, the
|
||||
existing Xen domains will be killed off. It is called as:
|
||||
<pre>/etc/libvirt/hooks/libxl guest_name reconnect begin -</pre>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h5><a name="network">/etc/libvirt/hooks/network</a></h5>
|
||||
<ul>
|
||||
<li><span class="since">Since 1.2.2</span>, before a network is started,
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "viratomic.h"
|
||||
#include "virfile.h"
|
||||
#include "virerror.h"
|
||||
#include "virhook.h"
|
||||
#include "virlog.h"
|
||||
#include "virstring.h"
|
||||
#include "virtime.h"
|
||||
@ -737,6 +738,17 @@ libxlDomainCleanup(libxlDriverPrivatePtr driver,
|
||||
hostdev_flags |= VIR_HOSTDEV_SP_USB;
|
||||
#endif
|
||||
|
||||
/* now that we know it's stopped call the hook if present */
|
||||
if (virHookPresent(VIR_HOOK_DRIVER_LIBXL)) {
|
||||
char *xml = virDomainDefFormat(vm->def, cfg->caps, 0);
|
||||
|
||||
/* we can't stop the operation even if the script raised an error */
|
||||
ignore_value(virHookCall(VIR_HOOK_DRIVER_LIBXL, vm->def->name,
|
||||
VIR_HOOK_LIBXL_OP_STOPPED, VIR_HOOK_SUBOP_END,
|
||||
NULL, xml, NULL));
|
||||
VIR_FREE(xml);
|
||||
}
|
||||
|
||||
virHostdevReAttachDomainDevices(hostdev_mgr, LIBXL_DRIVER_NAME,
|
||||
vm->def, hostdev_flags, NULL);
|
||||
|
||||
@ -788,6 +800,17 @@ libxlDomainCleanup(libxlDriverPrivatePtr driver,
|
||||
VIR_FREE(file);
|
||||
}
|
||||
|
||||
/* The "release" hook cleans up additional resources */
|
||||
if (virHookPresent(VIR_HOOK_DRIVER_LIBXL)) {
|
||||
char *xml = virDomainDefFormat(vm->def, cfg->caps, 0);
|
||||
|
||||
/* we can't stop the operation even if the script raised an error */
|
||||
ignore_value(virHookCall(VIR_HOOK_DRIVER_LIBXL, vm->def->name,
|
||||
VIR_HOOK_LIBXL_OP_RELEASE, VIR_HOOK_SUBOP_END,
|
||||
NULL, xml, NULL);
|
||||
VIR_FREE(xml);
|
||||
}
|
||||
|
||||
if (vm->newDef) {
|
||||
virDomainDefFree(vm->def);
|
||||
vm->def = vm->newDef;
|
||||
@ -1107,6 +1130,23 @@ libxlDomainStart(libxlDriverPrivatePtr driver,
|
||||
if (virDomainObjSetDefTransient(cfg->caps, driver->xmlopt, vm) < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* Run an early hook to set-up missing devices */
|
||||
if (virHookPresent(VIR_HOOK_DRIVER_LIBXL)) {
|
||||
char *xml = virDomainDefFormat(vm->def, cfg->caps, 0);
|
||||
int hookret;
|
||||
|
||||
hookret = virHookCall(VIR_HOOK_DRIVER_LIBXL, vm->def->name,
|
||||
VIR_HOOK_LIBXL_OP_PREPARE, VIR_HOOK_SUBOP_BEGIN,
|
||||
NULL, xml, NULL);
|
||||
VIR_FREE(xml);
|
||||
|
||||
/*
|
||||
* If the script raised an error abort the launch
|
||||
*/
|
||||
if (hookret < 0)
|
||||
goto cleanup_dom;
|
||||
}
|
||||
|
||||
if (virDomainLockProcessStart(driver->lockManager,
|
||||
"xen:///system",
|
||||
vm,
|
||||
@ -1135,6 +1175,23 @@ libxlDomainStart(libxlDriverPrivatePtr driver,
|
||||
vm->def, hostdev_flags) < 0)
|
||||
goto cleanup_dom;
|
||||
|
||||
/* now that we know it is about to start call the hook if present */
|
||||
if (virHookPresent(VIR_HOOK_DRIVER_LIBXL)) {
|
||||
char *xml = virDomainDefFormat(vm->def, cfg->caps, 0);
|
||||
int hookret;
|
||||
|
||||
hookret = virHookCall(VIR_HOOK_DRIVER_LIBXL, vm->def->name,
|
||||
VIR_HOOK_LIBXL_OP_START, VIR_HOOK_SUBOP_BEGIN,
|
||||
NULL, xml, NULL);
|
||||
VIR_FREE(xml);
|
||||
|
||||
/*
|
||||
* If the script raised an error abort the launch
|
||||
*/
|
||||
if (hookret < 0)
|
||||
goto cleanup_dom;
|
||||
}
|
||||
|
||||
if (priv->hookRun) {
|
||||
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
||||
virUUIDFormat(vm->def->uuid, uuidstr);
|
||||
@ -1215,6 +1272,23 @@ libxlDomainStart(libxlDriverPrivatePtr driver,
|
||||
if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback)
|
||||
driver->inhibitCallback(true, driver->inhibitOpaque);
|
||||
|
||||
/* finally we can call the 'started' hook script if any */
|
||||
if (virHookPresent(VIR_HOOK_DRIVER_LIBXL)) {
|
||||
char *xml = virDomainDefFormat(vm->def, cfg->caps, 0);
|
||||
int hookret;
|
||||
|
||||
hookret = virHookCall(VIR_HOOK_DRIVER_LIBXL, vm->def->name,
|
||||
VIR_HOOK_LIBXL_OP_STARTED, VIR_HOOK_SUBOP_BEGIN,
|
||||
NULL, xml, NULL);
|
||||
VIR_FREE(xml);
|
||||
|
||||
/*
|
||||
* If the script raised an error abort the launch
|
||||
*/
|
||||
if (hookret < 0)
|
||||
goto cleanup_dom;
|
||||
}
|
||||
|
||||
event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STARTED,
|
||||
restore_fd < 0 ?
|
||||
VIR_DOMAIN_EVENT_STARTED_BOOTED :
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "virfile.h"
|
||||
#include "viralloc.h"
|
||||
#include "viruuid.h"
|
||||
#include "virhook.h"
|
||||
#include "vircommand.h"
|
||||
#include "libxl_domain.h"
|
||||
#include "libxl_driver.h"
|
||||
@ -415,6 +416,27 @@ libxlReconnectDomain(virDomainObjPtr vm,
|
||||
/* Enable domain death events */
|
||||
libxl_evenable_domain_death(cfg->ctx, vm->def->id, 0, &priv->deathW);
|
||||
|
||||
/* now that we know it's reconnected call the hook if present */
|
||||
if (virHookPresent(VIR_HOOK_DRIVER_LIBXL) &&
|
||||
STRNEQ("Domain-0", vm->def->name)) {
|
||||
char *xml = virDomainDefFormat(vm->def, cfg->caps, 0);
|
||||
int hookret;
|
||||
|
||||
/* we can't stop the operation even if the script raised an error */
|
||||
hookret = virHookCall(VIR_HOOK_DRIVER_LIBXL, vm->def->name,
|
||||
VIR_HOOK_LIBXL_OP_RECONNECT, VIR_HOOK_SUBOP_BEGIN,
|
||||
NULL, xml, NULL);
|
||||
VIR_FREE(xml);
|
||||
if (hookret < 0) {
|
||||
/* Stop the domain if the hook failed */
|
||||
if (virDomainObjIsActive(vm)) {
|
||||
libxlDomainDestroyInternal(driver, vm);
|
||||
virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_FAILED);
|
||||
}
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "virstring.h"
|
||||
#include "virobject.h"
|
||||
#include "virthread.h"
|
||||
#include "virhook.h"
|
||||
#include "rpc/virnetsocket.h"
|
||||
#include "libxl_domain.h"
|
||||
#include "libxl_driver.h"
|
||||
@ -490,9 +491,11 @@ libxlDomainMigrationPrepare(virConnectPtr dconn,
|
||||
unsigned int flags)
|
||||
{
|
||||
libxlDriverPrivatePtr driver = dconn->privateData;
|
||||
libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
|
||||
libxlMigrationCookiePtr mig = NULL;
|
||||
virDomainObjPtr vm = NULL;
|
||||
char *hostname = NULL;
|
||||
char *xmlout = NULL;
|
||||
unsigned short port;
|
||||
char portstr[100];
|
||||
virURIPtr uri = NULL;
|
||||
@ -500,6 +503,8 @@ libxlDomainMigrationPrepare(virConnectPtr dconn,
|
||||
size_t nsocks = 0;
|
||||
int nsocks_listen = 0;
|
||||
libxlMigrationDstArgs *args = NULL;
|
||||
bool taint_hook = false;
|
||||
libxlDomainObjPrivatePtr priv = NULL;
|
||||
size_t i;
|
||||
int ret = -1;
|
||||
|
||||
@ -513,6 +518,50 @@ libxlDomainMigrationPrepare(virConnectPtr dconn,
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Let migration hook filter domain XML */
|
||||
if (virHookPresent(VIR_HOOK_DRIVER_LIBXL)) {
|
||||
char *xml;
|
||||
int hookret;
|
||||
|
||||
if (!(xml = virDomainDefFormat(*def, cfg->caps,
|
||||
VIR_DOMAIN_XML_SECURE |
|
||||
VIR_DOMAIN_XML_MIGRATABLE)))
|
||||
goto error;
|
||||
|
||||
hookret = virHookCall(VIR_HOOK_DRIVER_LIBXL, (*def)->name,
|
||||
VIR_HOOK_LIBXL_OP_MIGRATE, VIR_HOOK_SUBOP_BEGIN,
|
||||
NULL, xml, &xmlout);
|
||||
VIR_FREE(xml);
|
||||
|
||||
if (hookret < 0) {
|
||||
goto error;
|
||||
} else if (hookret == 0) {
|
||||
if (virStringIsEmpty(xmlout)) {
|
||||
VIR_DEBUG("Migrate hook filter returned nothing; using the"
|
||||
" original XML");
|
||||
} else {
|
||||
virDomainDefPtr newdef;
|
||||
|
||||
VIR_DEBUG("Using hook-filtered domain XML: %s", xmlout);
|
||||
newdef = virDomainDefParseString(xmlout, cfg->caps, driver->xmlopt,
|
||||
VIR_DOMAIN_DEF_PARSE_INACTIVE |
|
||||
VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE);
|
||||
if (!newdef)
|
||||
goto error;
|
||||
|
||||
/* TODO At some stage we will want to have some check of what the user
|
||||
* did in the hook. */
|
||||
|
||||
virDomainDefFree(*def);
|
||||
*def = newdef;
|
||||
/* We should taint the domain here. However, @vm and therefore
|
||||
* privateData too are still NULL, so just notice the fact and
|
||||
* taint it later. */
|
||||
taint_hook = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(vm = virDomainObjListAdd(driver->domains, *def,
|
||||
driver->xmlopt,
|
||||
VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
|
||||
@ -520,6 +569,12 @@ libxlDomainMigrationPrepare(virConnectPtr dconn,
|
||||
NULL)))
|
||||
goto error;
|
||||
*def = NULL;
|
||||
priv = vm->privateData;
|
||||
|
||||
if (taint_hook) {
|
||||
/* Domain XML has been altered by a hook script. */
|
||||
priv->hookRun = true;
|
||||
}
|
||||
|
||||
/* Create socket connection to receive migration data */
|
||||
if (!uri_in) {
|
||||
@ -640,6 +695,7 @@ libxlDomainMigrationPrepare(virConnectPtr dconn,
|
||||
}
|
||||
|
||||
done:
|
||||
VIR_FREE(xmlout);
|
||||
libxlMigrationCookieFree(mig);
|
||||
if (!uri_in)
|
||||
VIR_FREE(hostname);
|
||||
@ -647,6 +703,7 @@ libxlDomainMigrationPrepare(virConnectPtr dconn,
|
||||
virURIFree(uri);
|
||||
if (vm)
|
||||
virObjectUnlock(vm);
|
||||
virObjectUnref(cfg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -51,13 +51,15 @@ VIR_ENUM_DECL(virHookSubop)
|
||||
VIR_ENUM_DECL(virHookQemuOp)
|
||||
VIR_ENUM_DECL(virHookLxcOp)
|
||||
VIR_ENUM_DECL(virHookNetworkOp)
|
||||
VIR_ENUM_DECL(virHookLibxlOp)
|
||||
|
||||
VIR_ENUM_IMPL(virHookDriver,
|
||||
VIR_HOOK_DRIVER_LAST,
|
||||
"daemon",
|
||||
"qemu",
|
||||
"lxc",
|
||||
"network")
|
||||
"network",
|
||||
"libxl")
|
||||
|
||||
VIR_ENUM_IMPL(virHookDaemonOp, VIR_HOOK_DAEMON_OP_LAST,
|
||||
"start",
|
||||
@ -96,6 +98,15 @@ VIR_ENUM_IMPL(virHookNetworkOp, VIR_HOOK_NETWORK_OP_LAST,
|
||||
"unplugged",
|
||||
"updated")
|
||||
|
||||
VIR_ENUM_IMPL(virHookLibxlOp, VIR_HOOK_LIBXL_OP_LAST,
|
||||
"start",
|
||||
"stopped",
|
||||
"prepare",
|
||||
"release",
|
||||
"migrate",
|
||||
"started",
|
||||
"reconnect")
|
||||
|
||||
static int virHooksFound = -1;
|
||||
|
||||
/**
|
||||
@ -261,6 +272,9 @@ virHookCall(int driver,
|
||||
case VIR_HOOK_DRIVER_LXC:
|
||||
opstr = virHookLxcOpTypeToString(op);
|
||||
break;
|
||||
case VIR_HOOK_DRIVER_LIBXL:
|
||||
opstr = virHookLibxlOpTypeToString(op);
|
||||
break;
|
||||
case VIR_HOOK_DRIVER_NETWORK:
|
||||
opstr = virHookNetworkOpTypeToString(op);
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ typedef enum {
|
||||
VIR_HOOK_DRIVER_QEMU, /* QEmu domains related events */
|
||||
VIR_HOOK_DRIVER_LXC, /* LXC domains related events */
|
||||
VIR_HOOK_DRIVER_NETWORK, /* network related events */
|
||||
VIR_HOOK_DRIVER_LIBXL, /* Xen libxl domains related events */
|
||||
|
||||
VIR_HOOK_DRIVER_LAST,
|
||||
} virHookDriverType;
|
||||
@ -87,6 +88,18 @@ typedef enum {
|
||||
VIR_HOOK_NETWORK_OP_LAST,
|
||||
} virHookNetworkOpType;
|
||||
|
||||
typedef enum {
|
||||
VIR_HOOK_LIBXL_OP_START, /* domain is about to start */
|
||||
VIR_HOOK_LIBXL_OP_STOPPED, /* domain has stopped */
|
||||
VIR_HOOK_LIBXL_OP_PREPARE, /* domain startup initiated */
|
||||
VIR_HOOK_LIBXL_OP_RELEASE, /* domain destruction is over */
|
||||
VIR_HOOK_LIBXL_OP_MIGRATE, /* domain is being migrated */
|
||||
VIR_HOOK_LIBXL_OP_STARTED, /* domain has started */
|
||||
VIR_HOOK_LIBXL_OP_RECONNECT, /* domain is being reconnected by libvirt */
|
||||
|
||||
VIR_HOOK_LIBXL_OP_LAST,
|
||||
} virHookLibxlOpType;
|
||||
|
||||
int virHookInitialize(void);
|
||||
|
||||
int virHookPresent(int driver);
|
||||
|
Loading…
x
Reference in New Issue
Block a user