[libvirt] [PATCH] add migration support for OpenVZ driver

Hongbin Lu hongbin034 at gmail.com
Fri Sep 5 02:25:06 UTC 2014


This patch adds initial migration support to the OpenVZ driver,
using the VIR_DRV_FEATURE_MIGRATION_PARAMS family of migration
functions.
---
 src/openvz/openvz_conf.h   |    5 +-
 src/openvz/openvz_driver.c |  348 ++++++++++++++++++++++++++++++++++++++++++++
 src/openvz/openvz_driver.h |   10 ++
 3 files changed, 361 insertions(+), 2 deletions(-)

diff --git a/src/openvz/openvz_conf.h b/src/openvz/openvz_conf.h
index a7de7d2..33998d6 100644
--- a/src/openvz/openvz_conf.h
+++ b/src/openvz/openvz_conf.h
@@ -35,8 +35,9 @@
 
 
 /* OpenVZ commands - Replace with wrapper scripts later? */
-# define VZLIST  "/usr/sbin/vzlist"
-# define VZCTL   "/usr/sbin/vzctl"
+# define VZLIST     "/usr/sbin/vzlist"
+# define VZCTL      "/usr/sbin/vzctl"
+# define VZMIGRATE  "/usr/sbin/vzmigrate"
 # define VZ_CONF_FILE "/etc/vz/vz.conf"
 
 # define VZCTL_BRIDGE_MIN_VERSION ((3 * 1000 * 1000) + (0 * 1000) + 22 + 1)
diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c
index 851ed30..57b3c22 100644
--- a/src/openvz/openvz_driver.c
+++ b/src/openvz/openvz_driver.c
@@ -2207,6 +2207,348 @@ openvzNodeGetCPUMap(virConnectPtr conn ATTRIBUTE_UNUSED,
 }
 
 
+static int
+openvzConnectSupportsFeature(virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
+{
+    switch (feature) {
+    case VIR_DRV_FEATURE_MIGRATION_PARAMS:
+    case VIR_DRV_FEATURE_MIGRATION_V3:
+        return 1;
+    default:
+        return 0;
+    }
+}
+
+
+static char *
+openvzDomainMigrateBegin3Params(virDomainPtr domain,
+                                virTypedParameterPtr params,
+                                int nparams,
+                                char **cookieout ATTRIBUTE_UNUSED,
+                                int *cookieoutlen ATTRIBUTE_UNUSED,
+                                unsigned int flags)
+{
+    virDomainObjPtr vm = NULL;
+    struct openvz_driver *driver = domain->conn->privateData;
+    char *xml = NULL;
+    int status;
+
+    virCheckFlags(OPENVZ_MIGRATION_FLAGS, NULL);
+    if (virTypedParamsValidate(params, nparams, OPENVZ_MIGRATION_PARAMETERS) < 0)
+        return NULL;
+
+    openvzDriverLock(driver);
+    vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
+    openvzDriverUnlock(driver);
+
+    if (!vm) {
+        virReportError(VIR_ERR_NO_DOMAIN, "%s",
+                       _("no domain with matching uuid"));
+        goto cleanup;
+    }
+
+    if (!virDomainObjIsActive(vm)) {
+        virReportError(VIR_ERR_OPERATION_INVALID,
+                       "%s", _("domain is not running"));
+        goto cleanup;
+    }
+
+    if (openvzGetVEStatus(vm, &status, NULL) == -1)
+        goto cleanup;
+
+    if (status != VIR_DOMAIN_RUNNING) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("domain is not in running state"));
+        goto cleanup;
+    }
+
+    xml = virDomainDefFormat(vm->def, VIR_DOMAIN_XML_SECURE);
+
+ cleanup:
+    if (vm)
+        virObjectUnlock(vm);
+    return xml;
+}
+
+static int
+openvzDomainMigratePrepare3Params(virConnectPtr dconn,
+                                  virTypedParameterPtr params,
+                                  int nparams,
+                                  const char *cookiein ATTRIBUTE_UNUSED,
+                                  int cookieinlen ATTRIBUTE_UNUSED,
+                                  char **cookieout ATTRIBUTE_UNUSED,
+                                  int *cookieoutlen ATTRIBUTE_UNUSED,
+                                  char **uri_out,
+                                  unsigned int fflags ATTRIBUTE_UNUSED)
+{
+    struct openvz_driver *driver = dconn->privateData;
+    const char *dom_xml = NULL;
+    const char *uri_in = NULL;
+    virDomainDefPtr def = NULL;
+    virDomainObjPtr vm = NULL;
+    char *hostname = NULL;
+    virURIPtr uri = NULL;
+    int ret = -1;
+
+    if (virTypedParamsValidate(params, nparams, OPENVZ_MIGRATION_PARAMETERS) < 0)
+        goto error;
+
+    if (virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_DEST_XML,
+                                &dom_xml) < 0 ||
+        virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_URI,
+                                &uri_in) < 0)
+        goto error;
+
+    if (!dom_xml) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("no domain XML passed"));
+        goto error;
+    }
+
+    if (!(def = virDomainDefParseString(dom_xml, driver->caps, driver->xmlopt,
+                                        1 << VIR_DOMAIN_VIRT_OPENVZ,
+                                        VIR_DOMAIN_XML_INACTIVE)))
+        goto error;
+
+    if (!(vm = virDomainObjListAdd(driver->domains, def,
+                                   driver->xmlopt,
+                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
+                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
+                                   NULL)))
+        goto error;
+    def = NULL;
+
+    if (!uri_in) {
+        if ((hostname = virGetHostname()) == NULL)
+            goto error;
+
+        if (STRPREFIX(hostname, "localhost")) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("hostname on destination resolved to localhost,"
+                             " but migration requires an FQDN"));
+            goto error;
+        }
+    } else {
+        uri = virURIParse(uri_in);
+
+        if (uri == NULL) {
+            virReportError(VIR_ERR_INVALID_ARG,
+                           _("unable to parse URI: %s"),
+                           uri_in);
+            goto error;
+        }
+
+        if (uri->server == NULL) {
+            virReportError(VIR_ERR_INVALID_ARG,
+                           _("missing host in migration URI: %s"),
+                           uri_in);
+            goto error;
+        } else {
+            hostname = uri->server;
+        }
+    }
+
+    if (virAsprintf(uri_out, "ssh://%s", hostname) < 0)
+        goto error;
+
+    ret = 0;
+    goto done;
+
+ error:
+    virDomainDefFree(def);
+    if (vm) {
+        virDomainObjListRemove(driver->domains, vm);
+        vm = NULL;
+    }
+
+ done:
+    virURIFree(uri);
+    if (vm)
+        virObjectUnlock(vm);
+    return ret;
+}
+
+static int
+openvzDomainMigratePerform3Params(virDomainPtr domain,
+                                  const char *dconnuri ATTRIBUTE_UNUSED,
+                                  virTypedParameterPtr params,
+                                  int nparams,
+                                  const char *cookiein ATTRIBUTE_UNUSED,
+                                  int cookieinlen ATTRIBUTE_UNUSED,
+                                  char **cookieout ATTRIBUTE_UNUSED,
+                                  int *cookieoutlen ATTRIBUTE_UNUSED,
+                                  unsigned int flags)
+{
+    struct openvz_driver *driver = domain->conn->privateData;
+    virDomainObjPtr vm = NULL;
+    const char *uri_str = NULL;
+    virURIPtr uri = NULL;
+    virCommandPtr cmd = virCommandNew(VZMIGRATE);
+    int ret = -1;
+
+    virCheckFlags(OPENVZ_MIGRATION_FLAGS, -1);
+    if (virTypedParamsValidate(params, nparams, OPENVZ_MIGRATION_PARAMETERS) < 0)
+        goto cleanup;
+
+    if (virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_URI,
+                                &uri_str) < 0)
+        goto cleanup;
+
+    openvzDriverLock(driver);
+    vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
+    openvzDriverUnlock(driver);
+
+    if (!vm) {
+        virReportError(VIR_ERR_NO_DOMAIN, "%s",
+                       _("no domain with matching uuid"));
+        goto cleanup;
+    }
+
+    /* parse dst host:port from uri */
+    uri = virURIParse(uri_str);
+    if (uri == NULL || uri->server == NULL)
+        goto cleanup;
+
+    if (flags & VIR_MIGRATE_LIVE)
+        virCommandAddArg(cmd, "--live");
+    virCommandAddArg(cmd, uri->server);
+    virCommandAddArg(cmd, vm->def->name);
+
+    if (virCommandRun(cmd, NULL) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+ cleanup:
+    virCommandFree(cmd);
+    virURIFree(uri);
+    if (vm)
+        virObjectUnlock(vm);
+    return ret;
+}
+
+static virDomainPtr
+openvzDomainMigrateFinish3Params(virConnectPtr dconn,
+                                 virTypedParameterPtr params,
+                                 int nparams,
+                                 const char *cookiein ATTRIBUTE_UNUSED,
+                                 int cookieinlen ATTRIBUTE_UNUSED,
+                                 char **cookieout ATTRIBUTE_UNUSED,
+                                 int *cookieoutlen ATTRIBUTE_UNUSED,
+                                 unsigned int flags,
+                                 int cancelled)
+{
+    struct openvz_driver *driver = dconn->privateData;
+    virDomainObjPtr vm = NULL;
+    const char *dname = NULL;
+    virDomainPtr dom = NULL;
+    int status;
+
+    if (cancelled)
+        goto cleanup;
+
+    virCheckFlags(OPENVZ_MIGRATION_FLAGS, NULL);
+    if (virTypedParamsValidate(params, nparams, OPENVZ_MIGRATION_PARAMETERS) < 0)
+        goto cleanup;
+
+    if (virTypedParamsGetString(params, nparams,
+                                VIR_MIGRATE_PARAM_DEST_NAME,
+                                &dname) < 0)
+        goto cleanup;
+
+    if (!dname ||
+        !(vm = virDomainObjListFindByName(driver->domains, dname))) {
+        /* Migration obviously failed if the domain doesn't exist */
+        virReportError(VIR_ERR_OPERATION_FAILED,
+                       _("Migration failed. No domain on destination host "
+                         "with matching name '%s'"),
+                       NULLSTR(dname));
+        goto cleanup;
+    }
+
+    if (openvzGetVEStatus(vm, &status, NULL) == -1)
+        goto cleanup;
+
+    if (status != VIR_DOMAIN_RUNNING) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("domain is not running on destination host"));
+        goto cleanup;
+    }
+
+    vm->def->id = strtoI(vm->def->name);
+    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_MIGRATED);
+
+    dom = virGetDomain(dconn, vm->def->name, vm->def->uuid);
+    if (dom)
+        dom->id = vm->def->id;
+
+ cleanup:
+    if (vm)
+        virObjectUnlock(vm);
+    return dom;
+}
+
+static int
+openvzDomainMigrateConfirm3Params(virDomainPtr domain,
+                                  virTypedParameterPtr params,
+                                  int nparams,
+                                  const char *cookiein ATTRIBUTE_UNUSED,
+                                  int cookieinlen ATTRIBUTE_UNUSED,
+                                  unsigned int flags,
+                                  int cancelled)
+{
+    struct openvz_driver *driver = domain->conn->privateData;
+    virDomainObjPtr vm = NULL;
+    int status;
+    int ret = -1;
+
+    virCheckFlags(OPENVZ_MIGRATION_FLAGS, -1);
+    if (virTypedParamsValidate(params, nparams, OPENVZ_MIGRATION_PARAMETERS) < 0)
+        goto cleanup;
+
+    openvzDriverLock(driver);
+    vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
+    openvzDriverUnlock(driver);
+
+    if (!vm) {
+        virReportError(VIR_ERR_NO_DOMAIN, "%s",
+                       _("no domain with matching uuid"));
+        goto cleanup;
+    }
+
+    if (cancelled) {
+        if (openvzGetVEStatus(vm, &status, NULL) == -1)
+            goto cleanup;
+
+        if (status == VIR_DOMAIN_RUNNING) {
+            ret = 0;
+        } else {
+            VIR_DEBUG("Domain '%s' does not recover after failed migration",
+                      vm->def->name);
+        }
+
+        goto cleanup;
+    }
+
+    vm->def->id = -1;
+
+    VIR_DEBUG("Domain '%s' successfully migrated", vm->def->name);
+
+    virDomainObjListRemove(driver->domains, vm);
+    vm = NULL;
+
+    ret = 0;
+
+ cleanup:
+    if (vm)
+        virObjectUnlock(vm);
+    return ret;
+}
+
+
 static virDriver openvzDriver = {
     .no = VIR_DRV_OPENVZ,
     .name = "OPENVZ",
@@ -2265,6 +2607,12 @@ static virDriver openvzDriver = {
     .connectIsAlive = openvzConnectIsAlive, /* 0.9.8 */
     .domainUpdateDeviceFlags = openvzDomainUpdateDeviceFlags, /* 0.9.13 */
     .domainGetHostname = openvzDomainGetHostname, /* 0.10.0 */
+    .connectSupportsFeature = openvzConnectSupportsFeature, /* 1.2.8 */
+    .domainMigrateBegin3Params = openvzDomainMigrateBegin3Params, /* 1.2.8 */
+    .domainMigratePrepare3Params = openvzDomainMigratePrepare3Params, /* 1.2.8 */
+    .domainMigratePerform3Params = openvzDomainMigratePerform3Params, /* 1.2.8 */
+    .domainMigrateFinish3Params = openvzDomainMigrateFinish3Params, /* 1.2.8 */
+    .domainMigrateConfirm3Params = openvzDomainMigrateConfirm3Params, /* 1.2.8 */
 };
 
 int openvzRegister(void)
diff --git a/src/openvz/openvz_driver.h b/src/openvz/openvz_driver.h
index b39e81c..0c7a070 100644
--- a/src/openvz/openvz_driver.h
+++ b/src/openvz/openvz_driver.h
@@ -31,6 +31,16 @@
 
 # include "internal.h"
 
+# define OPENVZ_MIGRATION_FLAGS                 \
+    (VIR_MIGRATE_LIVE)
+
+/* All supported migration parameters and their types. */
+# define OPENVZ_MIGRATION_PARAMETERS                            \
+    VIR_MIGRATE_PARAM_URI,              VIR_TYPED_PARAM_STRING, \
+    VIR_MIGRATE_PARAM_DEST_NAME,        VIR_TYPED_PARAM_STRING, \
+    VIR_MIGRATE_PARAM_DEST_XML,         VIR_TYPED_PARAM_STRING, \
+    NULL
+
 int openvzRegister(void);
 
 #endif
-- 
1.7.1




More information about the libvir-list mailing list