From 04dec5826dc538d771fc29e4b8a2220d46050a44 Mon Sep 17 00:00:00 2001
From: Jiri Denemark
Date: Tue, 28 Feb 2012 13:42:42 +0100
Subject: [PATCH] qemu: Add pre-migration hook
This hook is called during the Prepare phase on destination host and may
be used for changing domain XML.
---
docs/hooks.html.in | 35 ++++++++++++++++++++-----------
src/qemu/qemu_migration.c | 43 +++++++++++++++++++++++++++++++++++++++
src/util/hooks.c | 3 ++-
src/util/hooks.h | 1 +
4 files changed, 69 insertions(+), 13 deletions(-)
diff --git a/docs/hooks.html.in b/docs/hooks.html.in
index 890359e64c..ab16db2177 100644
--- a/docs/hooks.html.in
+++ b/docs/hooks.html.in
@@ -120,6 +120,16 @@
called again, since 0.9.0, to allow
any additional resource cleanup:
/etc/libvirt/hooks/qemu guest_name release end -
+ Since 0.9.11, the qemu hook script
+ is also called at the beginning of incoming migration. It is called
+ as: /etc/libvirt/hooks/qemu guest_name migrate begin -
+ 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.
@@ -161,19 +171,20 @@
source and destination hosts:
- At the beginning of the migration, the qemu hook script on
- the destination host is executed with the "start"
- operation.
- - If this hook script returns indicating success (error code 0), the
- migration continues. Any other return code indicates failure, and
- the migration is aborted.
- - The QEMU guest is then migrated to the destination host.
-
+ the destination host is executed with the "migrate"
+ operation.
+ - Before QEMU process is spawned, the two operations ("prepare" and
+ "start") called for domain start are executed on
+ destination host.
+ - If both of these hook script executions exit successfully (exit
+ status 0), the migration continues. Any other exit code indicates
+ failure, and the migration is aborted.
+ - The QEMU guest is then migrated to the destination host.
- Unless an error occurs during the migration process, the qemu
- hook script on the source host is then executed with the "stopped"
- operation, to indicate it is no longer running on this
- host.
- Regardless of the return code from this hook script, the migration
- is not aborted as it has already been performed.
+ hook script on the source host is then executed with the
+ "stopped" and "release" operations to indicate it is no longer
+ running on this host. Regardless of the return codes, the
+ migration is not aborted as it has already been performed.
diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c
index 7df2d4f8ce..cf5895dae0 100644
--- a/src/qemu/qemu_migration.c
+++ b/src/qemu/qemu_migration.c
@@ -47,6 +47,7 @@
#include "rpc/virnetsocket.h"
#include "storage_file.h"
#include "viruri.h"
+#include "hooks.h"
#define VIR_FROM_THIS VIR_FROM_QEMU
@@ -1130,6 +1131,7 @@ qemuMigrationPrepareAny(struct qemud_driver *driver,
qemuMigrationCookiePtr mig = NULL;
bool tunnel = !!st;
char *origname = NULL;
+ char *xmlout = NULL;
if (virTimeMillisNow(&now) < 0)
return -1;
@@ -1150,6 +1152,46 @@ qemuMigrationPrepareAny(struct qemud_driver *driver,
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)
goto cleanup;
@@ -1244,6 +1286,7 @@ qemuMigrationPrepareAny(struct qemud_driver *driver,
cleanup:
VIR_FREE(origname);
+ VIR_FREE(xmlout);
virDomainDefFree(def);
VIR_FORCE_CLOSE(dataFD[0]);
VIR_FORCE_CLOSE(dataFD[1]);
diff --git a/src/util/hooks.c b/src/util/hooks.c
index 8c16a3a56d..b0c15fdcd0 100644
--- a/src/util/hooks.c
+++ b/src/util/hooks.c
@@ -73,7 +73,8 @@ VIR_ENUM_IMPL(virHookQemuOp, VIR_HOOK_QEMU_OP_LAST,
"start",
"stopped",
"prepare",
- "release")
+ "release",
+ "migrate")
VIR_ENUM_IMPL(virHookLxcOp, VIR_HOOK_LXC_OP_LAST,
"start",
diff --git a/src/util/hooks.h b/src/util/hooks.h
index a53ac2c300..7fd29f6cb1 100644
--- a/src/util/hooks.h
+++ b/src/util/hooks.h
@@ -56,6 +56,7 @@ enum virHookQemuOpType {
VIR_HOOK_QEMU_OP_STOPPED, /* domain has stopped */
VIR_HOOK_QEMU_OP_PREPARE, /* domain startup initiated */
VIR_HOOK_QEMU_OP_RELEASE, /* domain destruction is over */
+ VIR_HOOK_QEMU_OP_MIGRATE, /* domain is being migrated */
VIR_HOOK_QEMU_OP_LAST,
};