qemu: Add pre-migration hook

This hook is called during the Prepare phase on destination host and may
be used for changing domain XML.
This commit is contained in:
Jiri Denemark 2012-02-28 13:42:42 +01:00
parent 8ab785783f
commit 04dec5826d
4 changed files with 69 additions and 13 deletions

View File

@ -120,6 +120,16 @@
called again, <span class="since">since 0.9.0</span>, to allow called again, <span class="since">since 0.9.0</span>, to allow
any additional resource cleanup:<br/> any additional resource cleanup:<br/>
<pre>/etc/libvirt/hooks/qemu guest_name release end -</pre></li> <pre>/etc/libvirt/hooks/qemu guest_name release end -</pre></li>
<li><span class="since">Since 0.9.11</span>, the qemu hook script
is also called at the beginning of incoming migration. It is called
as: <pre>/etc/libvirt/hooks/qemu 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>
</ul> </ul>
<h5><a name="lxc">/etc/libvirt/hooks/lxc</a></h5> <h5><a name="lxc">/etc/libvirt/hooks/lxc</a></h5>
@ -161,19 +171,20 @@
source and destination hosts:</p> source and destination hosts:</p>
<ol> <ol>
<li>At the beginning of the migration, the <i>qemu</i> hook script on <li>At the beginning of the migration, the <i>qemu</i> hook script on
the <b>destination</b> host is executed with the "start" the <b>destination</b> host is executed with the "migrate"
operation.<br/><br/></li> operation.</li>
<li>If this hook script returns indicating success (error code 0), the <li>Before QEMU process is spawned, the two operations ("prepare" and
migration continues. Any other return code indicates failure, and "start") called for domain start are executed on
the migration is aborted.<br/><br/></li> <b>destination</b> host.</li>
<li>The QEMU guest is then migrated to the destination host.<br/> <li>If both of these hook script executions exit successfully (exit
<br/></li> status 0), the migration continues. Any other exit code indicates
failure, and the migration is aborted.</li>
<li>The QEMU guest is then migrated to the destination host.</li>
<li>Unless an error occurs during the migration process, the <i>qemu</i> <li>Unless an error occurs during the migration process, the <i>qemu</i>
hook script on the <b>source</b> host is then executed with the "stopped" hook script on the <b>source</b> host is then executed with the
operation, to indicate it is no longer running on this "stopped" and "release" operations to indicate it is no longer
host.<br/><br/> running on this host. Regardless of the return codes, the
Regardless of the return code from this hook script, the migration migration is not aborted as it has already been performed.</li>
is not aborted as it has already been performed.</li>
</ol> </ol>
<br/> <br/>

View File

@ -47,6 +47,7 @@
#include "rpc/virnetsocket.h" #include "rpc/virnetsocket.h"
#include "storage_file.h" #include "storage_file.h"
#include "viruri.h" #include "viruri.h"
#include "hooks.h"
#define VIR_FROM_THIS VIR_FROM_QEMU #define VIR_FROM_THIS VIR_FROM_QEMU
@ -1130,6 +1131,7 @@ qemuMigrationPrepareAny(struct qemud_driver *driver,
qemuMigrationCookiePtr mig = NULL; qemuMigrationCookiePtr mig = NULL;
bool tunnel = !!st; bool tunnel = !!st;
char *origname = NULL; char *origname = NULL;
char *xmlout = NULL;
if (virTimeMillisNow(&now) < 0) if (virTimeMillisNow(&now) < 0)
return -1; return -1;
@ -1150,6 +1152,46 @@ qemuMigrationPrepareAny(struct qemud_driver *driver,
goto cleanup; goto cleanup;
} }
/* Let migration hook filter domain XML */
if (virHookPresent(VIR_HOOK_DRIVER_QEMU)) {
char *xml;
int hookret;
if (!(xml = virDomainDefFormat(def, VIR_DOMAIN_XML_SECURE)))
goto cleanup;
hookret = virHookCall(VIR_HOOK_DRIVER_QEMU, def->name,
VIR_HOOK_QEMU_OP_MIGRATE, VIR_HOOK_SUBOP_BEGIN,
NULL, xml, &xmlout);
VIR_FREE(xml);
if (hookret < 0) {
goto cleanup;
} else if (hookret == 0) {
if (!*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(driver->caps, xmlout,
QEMU_EXPECTED_VIRT_TYPES,
VIR_DOMAIN_XML_INACTIVE);
if (!newdef)
goto cleanup;
if (!virDomainDefCheckABIStability(def, newdef)) {
virDomainDefFree(newdef);
goto cleanup;
}
virDomainDefFree(def);
def = newdef;
}
}
}
if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0) if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
goto cleanup; goto cleanup;
@ -1244,6 +1286,7 @@ qemuMigrationPrepareAny(struct qemud_driver *driver,
cleanup: cleanup:
VIR_FREE(origname); VIR_FREE(origname);
VIR_FREE(xmlout);
virDomainDefFree(def); virDomainDefFree(def);
VIR_FORCE_CLOSE(dataFD[0]); VIR_FORCE_CLOSE(dataFD[0]);
VIR_FORCE_CLOSE(dataFD[1]); VIR_FORCE_CLOSE(dataFD[1]);

View File

@ -73,7 +73,8 @@ VIR_ENUM_IMPL(virHookQemuOp, VIR_HOOK_QEMU_OP_LAST,
"start", "start",
"stopped", "stopped",
"prepare", "prepare",
"release") "release",
"migrate")
VIR_ENUM_IMPL(virHookLxcOp, VIR_HOOK_LXC_OP_LAST, VIR_ENUM_IMPL(virHookLxcOp, VIR_HOOK_LXC_OP_LAST,
"start", "start",

View File

@ -56,6 +56,7 @@ enum virHookQemuOpType {
VIR_HOOK_QEMU_OP_STOPPED, /* domain has stopped */ VIR_HOOK_QEMU_OP_STOPPED, /* domain has stopped */
VIR_HOOK_QEMU_OP_PREPARE, /* domain startup initiated */ VIR_HOOK_QEMU_OP_PREPARE, /* domain startup initiated */
VIR_HOOK_QEMU_OP_RELEASE, /* domain destruction is over */ VIR_HOOK_QEMU_OP_RELEASE, /* domain destruction is over */
VIR_HOOK_QEMU_OP_MIGRATE, /* domain is being migrated */
VIR_HOOK_QEMU_OP_LAST, VIR_HOOK_QEMU_OP_LAST,
}; };