Normally, when you migrate a domain from host A to host B,
the domain on host A remains defined but shutoff and the domain
on host B remains running but is a "transient". Add a new
flag to virDomainMigrate() to allow the original domain to be
undefined on source host A, and a new flag to virDomainMigrate() to
allow the new domain to be persisted on the destination host B.
Signed-off-by: Chris Lalancette <clalance(a)redhat.com>
---
include/libvirt/libvirt.h.in | 2 ++
src/libvirt.c | 4 ++++
src/qemu/qemu_driver.c | 34 ++++++++++++++++++++++++++++++++--
tools/virsh.c | 8 ++++++++
4 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index f51a565..6186d4e 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -339,6 +339,8 @@ typedef enum {
VIR_MIGRATE_LIVE = (1 << 0), /* live migration */
VIR_MIGRATE_PEER2PEER = (1 << 1), /* direct source -> dest host
control channel */
VIR_MIGRATE_TUNNELLED = (1 << 2), /* tunnel migration data over
libvirtd connection */
+ VIR_MIGRATE_PERSIST_DEST = (1 << 3), /* persist the VM on the destination
*/
+ VIR_MIGRATE_UNDEFINE_SOURCE = (1 << 4), /* undefine the VM on the source */
} virDomainMigrateFlags;
/* Domain migration. */
diff --git a/src/libvirt.c b/src/libvirt.c
index b14942d..92a1eaa 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -3128,6 +3128,10 @@ virDomainMigrateDirect (virDomainPtr domain,
* VIR_MIGRATE_LIVE Do not pause the VM during migration
* VIR_MIGRATE_PEER2PEER Direct connection between source & destination hosts
* VIR_MIGRATE_TUNNELLED Tunnel migration data over the libvirt RPC channel
+ * VIR_MIGRATE_PERSIST_DEST If the migration is successful, persist the domain
+ * on the destination host.
+ * VIR_MIGRATE_UNDEFINE_SOURCE If the migration is successful, undefine the
+ * domain on the source host.
*
* VIR_MIGRATE_TUNNELLED requires that VIR_MIGRATE_PEER2PEER be set.
* Applications using the VIR_MIGRATE_PEER2PEER flag will probably
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 3812f91..ba5694e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6848,7 +6848,8 @@ qemudDomainMigratePerform (virDomainPtr dom,
event = virDomainEventNewFromObj(vm,
VIR_DOMAIN_EVENT_STOPPED,
VIR_DOMAIN_EVENT_STOPPED_MIGRATED);
- if (!vm->persistent) {
+ if (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE)) {
+ virDomainDeleteConfig(dom->conn, driver->configDir,
driver->autostartDir, vm);
virDomainRemoveInactive(&driver->domains, vm);
vm = NULL;
}
@@ -6886,13 +6887,14 @@ qemudDomainMigrateFinish2 (virConnectPtr dconn,
const char *cookie ATTRIBUTE_UNUSED,
int cookielen ATTRIBUTE_UNUSED,
const char *uri ATTRIBUTE_UNUSED,
- unsigned long flags ATTRIBUTE_UNUSED,
+ unsigned long flags,
int retcode)
{
struct qemud_driver *driver = dconn->privateData;
virDomainObjPtr vm;
virDomainPtr dom = NULL;
virDomainEventPtr event = NULL;
+ int newVM = 1;
qemuDriverLock(driver);
vm = virDomainFindByName(&driver->domains, dname);
@@ -6906,6 +6908,34 @@ qemudDomainMigrateFinish2 (virConnectPtr dconn,
* object, but if no, clean up the empty qemu process.
*/
if (retcode == 0) {
+ if (flags & VIR_MIGRATE_PERSIST_DEST) {
+ if (vm->persistent)
+ newVM = 0;
+ vm->persistent = 1;
+
+ if (virDomainSaveConfig(dconn, driver->configDir, vm->def) < 0) {
+ /* Hmpf. Migration was successful, but making it persistent
+ * was not. If we report successful, then when this domain
+ * shuts down, management tools are in for a surprise. On the
+ * other hand, if we report failure, then the management tools
+ * might try to restart the domain on the source side, even
+ * though the domain is actually running on the destination.
+ * Return a NULL dom pointer, and hope that this is a rare
+ * situation and management tools are smart.
+ */
+ vm = NULL;
+ goto cleanup;
+ }
+
+ event = virDomainEventNewFromObj(vm,
+ VIR_DOMAIN_EVENT_DEFINED,
+ newVM ?
+ VIR_DOMAIN_EVENT_DEFINED_ADDED :
+ VIR_DOMAIN_EVENT_DEFINED_UPDATED);
+ if (event)
+ qemuDomainEventQueue(driver, event);
+
+ }
dom = virGetDomain (dconn, vm->def->name, vm->def->uuid);
/* run 'cont' on the destination, which allows migration on qemu
diff --git a/tools/virsh.c b/tools/virsh.c
index 46c5454..47122d5 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -2465,6 +2465,8 @@ static const vshCmdOptDef opts_migrate[] = {
{"p2p", VSH_OT_BOOL, 0, gettext_noop("peer-2-peer migration")},
{"direct", VSH_OT_BOOL, 0, gettext_noop("direct migration")},
{"tunnelled", VSH_OT_BOOL, 0, gettext_noop("tunnelled
migration")},
+ {"persistent", VSH_OT_BOOL, 0, gettext_noop("persist VM on
destination")},
+ {"undefinesource", VSH_OT_BOOL, 0, gettext_noop("undefine VM on
source")},
{"domain", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("domain name, id
or uuid")},
{"desturi", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("connection URI
of the destination host")},
{"migrateuri", VSH_OT_DATA, 0, gettext_noop("migration URI, usually
can be omitted")},
@@ -2504,6 +2506,12 @@ cmdMigrate (vshControl *ctl, const vshCmd *cmd)
if (vshCommandOptBool (cmd, "tunnelled"))
flags |= VIR_MIGRATE_TUNNELLED;
+ if (vshCommandOptBool (cmd, "persistent"))
+ flags |= VIR_MIGRATE_PERSIST_DEST;
+
+ if (vshCommandOptBool (cmd, "undefinesource"))
+ flags |= VIR_MIGRATE_UNDEFINE_SOURCE;
+
if ((flags & VIR_MIGRATE_PEER2PEER) ||
vshCommandOptBool (cmd, "direct")) {
/* For peer2peer migration or direct migration we only expect one URI
--
1.6.0.6