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.
  • /etc/libvirt/hooks/lxc
    @@ -161,19 +171,20 @@ source and destination hosts:

    1. At the beginning of the migration, the qemu hook script on - the destination host is executed with the "start" - operation.

    2. -
    3. If this hook script returns indicating success (error code 0), the - migration continues. Any other return code indicates failure, and - the migration is aborted.

    4. -
    5. The QEMU guest is then migrated to the destination host.
      -
    6. + the destination host is executed with the "migrate" + operation. +
    7. Before QEMU process is spawned, the two operations ("prepare" and + "start") called for domain start are executed on + destination host.
    8. +
    9. 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.
    10. +
    11. The QEMU guest is then migrated to the destination host.
    12. 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.
    13. + 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, };