[libvirt] [PATCH v7 0/5] vz: add migration support

Difference from v6 ================== Minor fixes suggested by reviewer. Nikolay Shirokovskiy (5): vz: save session uuid on login vz: fix const correctness case vz: implement managed migration vz: implement p2p migration vz: cleanup: define vz format of uuids src/vz/vz_driver.c | 559 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/vz/vz_sdk.c | 90 +++++++-- src/vz/vz_sdk.h | 6 + src/vz/vz_utils.c | 2 +- src/vz/vz_utils.h | 7 +- 5 files changed, 648 insertions(+), 16 deletions(-) -- 1.8.3.1

This session uuid acts as authN token for different multihost vz operations one of which is migration. Unfortunately we can't get it from server at any time thus we need to save it at login. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_sdk.c | 40 +++++++++++++++++++++++++++++++--------- src/vz/vz_utils.h | 2 +- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/vz/vz_sdk.c b/src/vz/vz_sdk.c index b8943db..fbcf4d9 100644 --- a/src/vz/vz_sdk.c +++ b/src/vz/vz_sdk.c @@ -37,6 +37,9 @@ #define VIR_FROM_THIS VIR_FROM_PARALLELS #define JOB_INFINIT_WAIT_TIMEOUT UINT_MAX +static int +prlsdkUUIDParse(const char *uuidstr, unsigned char *uuid); + VIR_LOG_INIT("parallels.sdk"); /* @@ -268,24 +271,43 @@ prlsdkDeinit(void) int prlsdkConnect(vzDriverPtr driver) { - PRL_RESULT ret; + int ret = -1; + PRL_RESULT pret; PRL_HANDLE job = PRL_INVALID_HANDLE; + PRL_HANDLE result = PRL_INVALID_HANDLE; + PRL_HANDLE response = PRL_INVALID_HANDLE; + char session_uuid[VIR_UUID_STRING_BUFLEN + 2]; - ret = PrlSrv_Create(&driver->server); - if (PRL_FAILED(ret)) { - logPrlError(ret); - return -1; - } + pret = PrlSrv_Create(&driver->server); + prlsdkCheckRetExit(pret, -1); job = PrlSrv_LoginLocalEx(driver->server, NULL, 0, PSL_HIGH_SECURITY, PACF_NON_INTERACTIVE_MODE); + if (PRL_FAILED(getJobResult(job, &result))) + goto cleanup; - if (waitJob(job)) { + pret = PrlResult_GetParam(result, &response); + prlsdkCheckRetGoto(pret, cleanup); + + pret = prlsdkGetStringParamBuf(PrlLoginResponse_GetSessionUuid, + response, session_uuid, sizeof(session_uuid)); + prlsdkCheckRetGoto(pret, cleanup); + + if (prlsdkUUIDParse(session_uuid, driver->session_uuid) < 0) + goto cleanup; + + ret = 0; + + cleanup: + if (ret < 0) { PrlHandle_Free(driver->server); - return -1; + driver->server = PRL_INVALID_HANDLE; } - return 0; + PrlHandle_Free(result); + PrlHandle_Free(response); + + return ret; } void diff --git a/src/vz/vz_utils.h b/src/vz/vz_utils.h index ee843d8..6975f2c 100644 --- a/src/vz/vz_utils.h +++ b/src/vz/vz_utils.h @@ -65,7 +65,7 @@ struct _vzDriver { /* Immutable pointer, self-locking APIs */ virDomainObjListPtr domains; - + unsigned char session_uuid[VIR_UUID_BUFLEN]; PRL_HANDLE server; virCapsPtr caps; virDomainXMLOptionPtr xmlopt; -- 1.8.3.1

Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_utils.c | 2 +- src/vz/vz_utils.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vz/vz_utils.c b/src/vz/vz_utils.c index d9da1e7..5427314 100644 --- a/src/vz/vz_utils.c +++ b/src/vz/vz_utils.c @@ -160,7 +160,7 @@ vzGetOutput(const char *binary, ...) } virDomainObjPtr -vzNewDomain(vzDriverPtr driver, char *name, const unsigned char *uuid) +vzNewDomain(vzDriverPtr driver, const char *name, const unsigned char *uuid) { virDomainDefPtr def = NULL; virDomainObjPtr dom = NULL; diff --git a/src/vz/vz_utils.h b/src/vz/vz_utils.h index 6975f2c..f8a3bb3 100644 --- a/src/vz/vz_utils.h +++ b/src/vz/vz_utils.h @@ -123,7 +123,7 @@ vzDestroyDriverConnection(void); virDomainObjPtr vzNewDomain(vzDriverPtr driver, - char *name, + const char *name, const unsigned char *uuid); int vzInitVersion(vzDriverPtr driver); -- 1.8.3.1

The newest version of migration protocol - version 3 with parameters is implemented. Supported flags is VIR_MIGRATE_PAUSED only. Supported parameters are VIR_MIGRATE_PARAM_URI and VIR_MIGRATE_PARAM_DEST_NAME. VIR_MIGRATE_PARAM_DEST_XML is in VZ_MIGRATION_PARAMETERS for technical onyl reasons. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_driver.c | 443 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/vz/vz_sdk.c | 42 +++++ src/vz/vz_sdk.h | 6 + 3 files changed, 491 insertions(+) diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index 1497b72..d1b8558 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -139,6 +139,9 @@ vzBuildCapabilities(void) caps->host.cpu = cpu; + if (virCapabilitiesAddHostMigrateTransport(caps, "vzmigr") < 0) + goto error; + if (!(data = cpuNodeData(cpu->arch)) || cpuDecode(cpu, data, NULL, 0, NULL) < 0) { goto cleanup; @@ -1581,6 +1584,440 @@ static int vzDomainSetMemory(virDomainPtr domain, unsigned long memory) return vzDomainSetMemoryFlagsImpl(domain, memory, 0, false); } +typedef struct _vzMigrationCookie vzMigrationCookie; +typedef vzMigrationCookie *vzMigrationCookiePtr; +struct _vzMigrationCookie { + unsigned char session_uuid[VIR_UUID_BUFLEN]; + unsigned char uuid[VIR_UUID_BUFLEN]; + char *name; +}; + +static void +vzMigrationCookieFree(vzMigrationCookiePtr mig) +{ + if (!mig) + return; + VIR_FREE(mig->name); + VIR_FREE(mig); +} + +static int +vzBakeCookie(vzMigrationCookiePtr mig, char **cookieout, int *cookieoutlen) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (!cookieout || !cookieoutlen) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Migration cookie parameters are not provided.")); + return -1; + } + + *cookieout = NULL; + *cookieoutlen = 0; + + virBufferAddLit(&buf, "<vz-migration>\n"); + virBufferAdjustIndent(&buf, 2); + virUUIDFormat(mig->session_uuid, uuidstr); + virBufferAsprintf(&buf, "<session-uuid>%s</session-uuid>\n", uuidstr); + virUUIDFormat(mig->uuid, uuidstr); + virBufferAsprintf(&buf, "<uuid>%s</uuid>\n", uuidstr); + virBufferAsprintf(&buf, "<name>%s</name>\n", mig->name); + virBufferAdjustIndent(&buf, -2); + virBufferAddLit(&buf, "</vz-migration>\n"); + + if (virBufferCheckError(&buf) < 0) + return -1; + + *cookieout = virBufferContentAndReset(&buf); + *cookieoutlen = strlen(*cookieout) + 1; + + return 0; +} + +static vzMigrationCookiePtr +vzEatCookie(const char *cookiein, int cookieinlen) +{ + xmlDocPtr doc = NULL; + xmlXPathContextPtr ctx = NULL; + char *tmp; + vzMigrationCookiePtr mig = NULL; + + if (VIR_ALLOC(mig) < 0) + return NULL; + + if (!cookiein || cookieinlen <= 0 || cookiein[cookieinlen - 1] != '\0') { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Invalid migration cookie")); + goto error; + } + + if (!(doc = virXMLParseStringCtxt(cookiein, + _("(_migration_cookie)"), &ctx))) + goto error; + + if (!(tmp = virXPathString("string(./session-uuid[1])", ctx))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing session-uuid element in migration data")); + goto error; + } + if (virUUIDParse(tmp, mig->session_uuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed session-uuid element in migration data")); + VIR_FREE(tmp); + goto error; + } + VIR_FREE(tmp); + + if (!(tmp = virXPathString("string(./uuid[1])", ctx))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing uuid element in migration data")); + goto error; + } + if (virUUIDParse(tmp, mig->uuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed uuid element in migration data")); + VIR_FREE(tmp); + goto error; + } + VIR_FREE(tmp); + + if (!(mig->name = virXPathString("string(./name[1])", ctx))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing name element in migration data")); + goto error; + } + + cleanup: + xmlXPathFreeContext(ctx); + xmlFreeDoc(doc); + return mig; + + error: + vzMigrationCookieFree(mig); + mig = NULL; + goto cleanup; +} + +#define VZ_MIGRATION_FLAGS VIR_MIGRATE_PAUSED + +#define VZ_MIGRATION_PARAMETERS \ + VIR_MIGRATE_PARAM_DEST_XML, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_URI, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_DEST_NAME, VIR_TYPED_PARAM_STRING, \ + NULL + +static char * +vzDomainMigrateBegin3Params(virDomainPtr domain, + virTypedParameterPtr params, + int nparams, + char **cookieout, + int *cookieoutlen, + unsigned int flags) +{ + char *xml = NULL; + virDomainObjPtr dom = NULL; + vzConnPtr privconn = domain->conn->privateData; + vzMigrationCookiePtr mig = NULL; + + virCheckFlags(VZ_MIGRATION_FLAGS, NULL); + + if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) + goto cleanup; + + /* we can't do this check via VZ_MIGRATION_PARAMETERS as on preparation + * step domain xml will be passed via this parameter and it is a common + * style to use single allowed parameter list definition in all steps */ + if (virTypedParamsGet(params, nparams, VIR_MIGRATE_PARAM_DEST_XML)) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("Changing destination XML is not supported")); + goto cleanup; + } + + if (!(dom = vzDomObjFromDomain(domain))) + goto cleanup; + + if (VIR_ALLOC(mig) < 0) + goto cleanup; + + if (VIR_STRDUP(mig->name, dom->def->name) < 0) + goto cleanup; + + memcpy(mig->uuid, dom->def->uuid, VIR_UUID_BUFLEN); + + if (vzBakeCookie(mig, cookieout, cookieoutlen) < 0) + goto cleanup; + + xml = virDomainDefFormat(dom->def, privconn->driver->caps, + VIR_DOMAIN_XML_MIGRATABLE); + + cleanup: + + vzMigrationCookieFree(mig); + if (dom) + virObjectUnlock(dom); + return xml; +} + +static char* +vzMigrationCreateURI(void) +{ + char *hostname = NULL; + char *uri = NULL; + + if (!(hostname = virGetHostname())) + goto cleanup; + + if (STRPREFIX(hostname, "localhost")) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("hostname on destination resolved to localhost," + " but migration requires an FQDN")); + goto cleanup; + } + + if (virAsprintf(&uri, "vzmigr://%s", hostname) < 0) + goto cleanup; + + cleanup: + VIR_FREE(hostname); + return uri; +} + +static int +vzDomainMigratePrepare3Params(virConnectPtr conn, + virTypedParameterPtr params, + int nparams, + const char *cookiein, + int cookieinlen, + char **cookieout, + int *cookieoutlen, + char **uri_out, + unsigned int flags) +{ + vzConnPtr privconn = conn->privateData; + const char *miguri = NULL; + const char *dname = NULL; + virDomainObjPtr dom = NULL; + vzMigrationCookiePtr mig = NULL; + int ret = -1; + + virCheckFlags(VZ_MIGRATION_FLAGS, -1); + + if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) + goto cleanup; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_URI, &miguri) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, &dname) < 0) + goto cleanup; + + /* We must set uri_out if miguri is not set. This is direct + * managed migration requirement */ + if (!miguri && !(*uri_out = vzMigrationCreateURI())) + goto cleanup; + + if (!(mig = vzEatCookie(cookiein, cookieinlen))) + goto cleanup; + + memcpy(mig->session_uuid, privconn->driver->session_uuid, VIR_UUID_BUFLEN); + + if (vzBakeCookie(mig, cookieout, cookieoutlen) < 0) + goto cleanup; + + if (!(dom = vzNewDomain(privconn->driver, + dname ? dname : mig->name, mig->uuid))) + goto cleanup; + + ret = 0; + + cleanup: + vzMigrationCookieFree(mig); + if (dom) + virObjectUnlock(dom); + return ret; +} + +static int +vzConnectSupportsFeature(virConnectPtr conn ATTRIBUTE_UNUSED, int feature) +{ + switch (feature) { + case VIR_DRV_FEATURE_MIGRATION_PARAMS: + return 1; + default: + return 0; + } +} + +static virURIPtr +vzParseVzURI(const char *uri_str) +{ + virURIPtr uri = NULL; + + if (!(uri = virURIParse(uri_str))) + goto error; + + if (!uri->scheme || !uri->server) { + virReportError(VIR_ERR_INVALID_ARG, + _("scheme and host are mandatory vz migration URI: %s"), + uri_str); + goto error; + } + + if (uri->user || uri->path || uri->query || uri->fragment) { + virReportError(VIR_ERR_INVALID_ARG, + _("only scheme, host and port are supported in " + "vz migration URI: %s"), uri_str); + goto error; + } + + if (STRNEQ(uri->scheme, "vzmigr")) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, + _("unsupported scheme %s in migration URI %s"), + uri->scheme, uri_str); + goto error; + } + + return uri; + + error: + virURIFree(uri); + return NULL; +} + +static int +vzDomainMigratePerform3Params(virDomainPtr domain, + const char *dconnuri ATTRIBUTE_UNUSED, + virTypedParameterPtr params, + int nparams, + const char *cookiein, + int cookieinlen, + char **cookieout ATTRIBUTE_UNUSED, + int *cookieoutlen ATTRIBUTE_UNUSED, + unsigned int flags) +{ + int ret = -1; + virDomainObjPtr dom = NULL; + virURIPtr vzuri = NULL; + vzConnPtr privconn = domain->conn->privateData; + const char *miguri = NULL; + const char *dname = NULL; + vzMigrationCookiePtr mig = NULL; + + virCheckFlags(VZ_MIGRATION_FLAGS, -1); + + if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) + goto cleanup; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_URI, &miguri) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, &dname) < 0) + goto cleanup; + + if (!miguri) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("migrate uri is not set")); + goto cleanup; + } + + if (!(mig = vzEatCookie(cookiein, cookieinlen))) + goto cleanup; + + if (!(dom = vzDomObjFromDomain(domain))) + goto cleanup; + + if (!(vzuri = vzParseVzURI(miguri))) + goto cleanup; + + if (prlsdkMigrate(dom, vzuri, mig->session_uuid, dname, flags) < 0) + goto cleanup; + + virDomainObjListRemove(privconn->driver->domains, dom); + dom = NULL; + + ret = 0; + + cleanup: + if (dom) + virObjectUnlock(dom); + virURIFree(vzuri); + vzMigrationCookieFree(mig); + + return ret; +} + +static virDomainPtr +vzDomainMigrateFinish3Params(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) +{ + virDomainObjPtr dom = NULL; + virDomainPtr domain = NULL; + vzConnPtr privconn = dconn->privateData; + vzDriverPtr driver = privconn->driver; + const char *name = NULL; + + virCheckFlags(VZ_MIGRATION_FLAGS, NULL); + + if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) + goto cleanup; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, &name) < 0) + goto cleanup; + + if (!(dom = virDomainObjListFindByName(driver->domains, name))) { + virReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching name '%s'"), name); + goto cleanup; + } + + if (cancelled) { + virDomainObjListRemove(driver->domains, dom); + dom = NULL; + goto cleanup; + } + + if (prlsdkLoadDomain(driver, dom)) + goto cleanup; + + domain = virGetDomain(dconn, dom->def->name, dom->def->uuid); + if (domain) + domain->id = dom->def->id; + + cleanup: + /* In this situation we have to restore domain on source. But the migration + * is already finished. */ + if (!cancelled && !domain) + VIR_WARN("Can't provide domain '%s' after successfull migration.", name); + virDomainObjEndAPI(&dom); + return domain; +} + +static int +vzDomainMigrateConfirm3Params(virDomainPtr domain ATTRIBUTE_UNUSED, + virTypedParameterPtr params, + int nparams, + const char *cookiein ATTRIBUTE_UNUSED, + int cookieinlen ATTRIBUTE_UNUSED, + unsigned int flags, + int cancelled ATTRIBUTE_UNUSED) +{ + virCheckFlags(VZ_MIGRATION_FLAGS, -1); + + if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) + return -1; + + return 0; +} + static virHypervisorDriver vzHypervisorDriver = { .name = "vz", .connectOpen = vzConnectOpen, /* 0.10.0 */ @@ -1648,6 +2085,12 @@ static virHypervisorDriver vzHypervisorDriver = { .connectUnregisterCloseCallback = vzConnectUnregisterCloseCallback, /* 1.3.2 */ .domainSetMemoryFlags = vzDomainSetMemoryFlags, /* 1.3.4 */ .domainSetMemory = vzDomainSetMemory, /* 1.3.4 */ + .connectSupportsFeature = vzConnectSupportsFeature, /* 1.3.5 */ + .domainMigrateBegin3Params = vzDomainMigrateBegin3Params, /* 1.3.5 */ + .domainMigratePrepare3Params = vzDomainMigratePrepare3Params, /* 1.3.5 */ + .domainMigratePerform3Params = vzDomainMigratePerform3Params, /* 1.3.5 */ + .domainMigrateFinish3Params = vzDomainMigrateFinish3Params, /* 1.3.5 */ + .domainMigrateConfirm3Params = vzDomainMigrateConfirm3Params, /* 1.3.5 */ }; static virConnectDriver vzConnectDriver = { diff --git a/src/vz/vz_sdk.c b/src/vz/vz_sdk.c index fbcf4d9..559f149 100644 --- a/src/vz/vz_sdk.c +++ b/src/vz/vz_sdk.c @@ -4296,3 +4296,45 @@ int prlsdkSetMemsize(virDomainObjPtr dom, unsigned int memsize) error: return -1; } + +/* high security is default choice for 2 reasons: + * 1. as this is the highest set security we can't get + * reject from server with high security settings + * 2. this is on par with security level of driver + * connection to dispatcher + */ + +#define PRLSDK_MIGRATION_FLAGS (PSL_HIGH_SECURITY) + +int prlsdkMigrate(virDomainObjPtr dom, virURIPtr uri, + const unsigned char *session_uuid, + const char *dname, + unsigned int flags) +{ + int ret = -1; + vzDomObjPtr privdom = dom->privateData; + PRL_HANDLE job = PRL_INVALID_HANDLE; + char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + PRL_UINT32 vzflags = PRLSDK_MIGRATION_FLAGS; + + if (flags & VIR_MIGRATE_PAUSED) + vzflags |= PVMT_DONT_RESUME_VM; + + prlsdkUUIDFormat(session_uuid, uuidstr); + job = PrlVm_MigrateWithRenameEx(privdom->sdkdom, uri->server, + uri->port, uuidstr, + dname == NULL ? "" : dname, + "", + vzflags, + 0, + PRL_TRUE + ); + + if (PRL_FAILED(waitJob(job))) + goto cleanup; + + ret = 0; + + cleanup: + return ret; +} diff --git a/src/vz/vz_sdk.h b/src/vz/vz_sdk.h index e562f98..3d27d12 100644 --- a/src/vz/vz_sdk.h +++ b/src/vz/vz_sdk.h @@ -82,3 +82,9 @@ void prlsdkDomObjFreePrivate(void *p); /* memsize is in MiB */ int prlsdkSetMemsize(virDomainObjPtr dom, unsigned int memsize); +int +prlsdkMigrate(virDomainObjPtr dom, + virURIPtr uri, + const char unsigned *session_uuid, + const char *dname, + unsigned int flags); -- 1.8.3.1

18.05.2016 11:11, Nikolay Shirokovskiy пишет:
The newest version of migration protocol - version 3 with parameters is implemented. Supported flags is VIR_MIGRATE_PAUSED only. Supported parameters are VIR_MIGRATE_PARAM_URI and VIR_MIGRATE_PARAM_DEST_NAME. VIR_MIGRATE_PARAM_DEST_XML is in VZ_MIGRATION_PARAMETERS for technical onyl reasons.
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_driver.c | 443 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/vz/vz_sdk.c | 42 +++++ src/vz/vz_sdk.h | 6 + 3 files changed, 491 insertions(+)
diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index 1497b72..d1b8558 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -139,6 +139,9 @@ vzBuildCapabilities(void)
caps->host.cpu = cpu;
+ if (virCapabilitiesAddHostMigrateTransport(caps, "vzmigr") < 0) + goto error; + if (!(data = cpuNodeData(cpu->arch)) || cpuDecode(cpu, data, NULL, 0, NULL) < 0) { goto cleanup; @@ -1581,6 +1584,440 @@ static int vzDomainSetMemory(virDomainPtr domain, unsigned long memory) return vzDomainSetMemoryFlagsImpl(domain, memory, 0, false); }
+typedef struct _vzMigrationCookie vzMigrationCookie; +typedef vzMigrationCookie *vzMigrationCookiePtr; +struct _vzMigrationCookie { + unsigned char session_uuid[VIR_UUID_BUFLEN]; + unsigned char uuid[VIR_UUID_BUFLEN]; + char *name; +}; + +static void +vzMigrationCookieFree(vzMigrationCookiePtr mig) +{ + if (!mig) + return; + VIR_FREE(mig->name); + VIR_FREE(mig); +} + +static int +vzBakeCookie(vzMigrationCookiePtr mig, char **cookieout, int *cookieoutlen) +{ + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virBuffer buf = VIR_BUFFER_INITIALIZER; + + if (!cookieout || !cookieoutlen) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Migration cookie parameters are not provided.")); + return -1; + } + + *cookieout = NULL; + *cookieoutlen = 0; + + virBufferAddLit(&buf, "<vz-migration>\n"); + virBufferAdjustIndent(&buf, 2); + virUUIDFormat(mig->session_uuid, uuidstr); + virBufferAsprintf(&buf, "<session-uuid>%s</session-uuid>\n", uuidstr); + virUUIDFormat(mig->uuid, uuidstr); + virBufferAsprintf(&buf, "<uuid>%s</uuid>\n", uuidstr); + virBufferAsprintf(&buf, "<name>%s</name>\n", mig->name); + virBufferAdjustIndent(&buf, -2); + virBufferAddLit(&buf, "</vz-migration>\n"); + + if (virBufferCheckError(&buf) < 0) + return -1; + + *cookieout = virBufferContentAndReset(&buf); + *cookieoutlen = strlen(*cookieout) + 1; + + return 0; +} + +static vzMigrationCookiePtr +vzEatCookie(const char *cookiein, int cookieinlen) +{ + xmlDocPtr doc = NULL; + xmlXPathContextPtr ctx = NULL; + char *tmp; + vzMigrationCookiePtr mig = NULL; + + if (VIR_ALLOC(mig) < 0) + return NULL; + + if (!cookiein || cookieinlen <= 0 || cookiein[cookieinlen - 1] != '\0') { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Invalid migration cookie")); + goto error; + } + + if (!(doc = virXMLParseStringCtxt(cookiein, + _("(_migration_cookie)"), &ctx))) + goto error; + + if (!(tmp = virXPathString("string(./session-uuid[1])", ctx))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing session-uuid element in migration data")); + goto error; + } + if (virUUIDParse(tmp, mig->session_uuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed session-uuid element in migration data")); + VIR_FREE(tmp); + goto error; + } + VIR_FREE(tmp); + + if (!(tmp = virXPathString("string(./uuid[1])", ctx))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing uuid element in migration data")); + goto error; + } + if (virUUIDParse(tmp, mig->uuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("malformed uuid element in migration data")); + VIR_FREE(tmp); + goto error; + } + VIR_FREE(tmp); + + if (!(mig->name = virXPathString("string(./name[1])", ctx))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("missing name element in migration data")); + goto error; + } + + cleanup: + xmlXPathFreeContext(ctx); + xmlFreeDoc(doc); + return mig; + + error: + vzMigrationCookieFree(mig); + mig = NULL; + goto cleanup; +} + +#define VZ_MIGRATION_FLAGS VIR_MIGRATE_PAUSED + +#define VZ_MIGRATION_PARAMETERS \ + VIR_MIGRATE_PARAM_DEST_XML, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_URI, VIR_TYPED_PARAM_STRING, \ + VIR_MIGRATE_PARAM_DEST_NAME, VIR_TYPED_PARAM_STRING, \ + NULL + +static char * +vzDomainMigrateBegin3Params(virDomainPtr domain, + virTypedParameterPtr params, + int nparams, + char **cookieout, + int *cookieoutlen, + unsigned int flags) +{ + char *xml = NULL; + virDomainObjPtr dom = NULL; + vzConnPtr privconn = domain->conn->privateData; + vzMigrationCookiePtr mig = NULL; + + virCheckFlags(VZ_MIGRATION_FLAGS, NULL); + + if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) + goto cleanup; + + /* we can't do this check via VZ_MIGRATION_PARAMETERS as on preparation + * step domain xml will be passed via this parameter and it is a common + * style to use single allowed parameter list definition in all steps */ + if (virTypedParamsGet(params, nparams, VIR_MIGRATE_PARAM_DEST_XML)) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("Changing destination XML is not supported")); + goto cleanup; + } + + if (!(dom = vzDomObjFromDomain(domain))) + goto cleanup; + + if (VIR_ALLOC(mig) < 0) + goto cleanup; + + if (VIR_STRDUP(mig->name, dom->def->name) < 0) + goto cleanup; + + memcpy(mig->uuid, dom->def->uuid, VIR_UUID_BUFLEN); + + if (vzBakeCookie(mig, cookieout, cookieoutlen) < 0) + goto cleanup; + + xml = virDomainDefFormat(dom->def, privconn->driver->caps, + VIR_DOMAIN_XML_MIGRATABLE); + + cleanup: + + vzMigrationCookieFree(mig); + if (dom) + virObjectUnlock(dom); + return xml; +} + +static char* +vzMigrationCreateURI(void) +{ + char *hostname = NULL; + char *uri = NULL; + + if (!(hostname = virGetHostname())) + goto cleanup; + + if (STRPREFIX(hostname, "localhost")) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("hostname on destination resolved to localhost," + " but migration requires an FQDN")); + goto cleanup; + } + + if (virAsprintf(&uri, "vzmigr://%s", hostname) < 0) + goto cleanup; + + cleanup: + VIR_FREE(hostname); + return uri; +} + +static int +vzDomainMigratePrepare3Params(virConnectPtr conn, + virTypedParameterPtr params, + int nparams, + const char *cookiein, + int cookieinlen, + char **cookieout, + int *cookieoutlen, + char **uri_out, + unsigned int flags) +{ + vzConnPtr privconn = conn->privateData; + const char *miguri = NULL; + const char *dname = NULL; + virDomainObjPtr dom = NULL; + vzMigrationCookiePtr mig = NULL; + int ret = -1; + + virCheckFlags(VZ_MIGRATION_FLAGS, -1); + + if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) + goto cleanup; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_URI, &miguri) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, &dname) < 0) + goto cleanup; + + /* We must set uri_out if miguri is not set. This is direct + * managed migration requirement */ + if (!miguri && !(*uri_out = vzMigrationCreateURI())) + goto cleanup; + + if (!(mig = vzEatCookie(cookiein, cookieinlen))) + goto cleanup; + + memcpy(mig->session_uuid, privconn->driver->session_uuid, VIR_UUID_BUFLEN); + + if (vzBakeCookie(mig, cookieout, cookieoutlen) < 0) + goto cleanup; + + if (!(dom = vzNewDomain(privconn->driver, + dname ? dname : mig->name, mig->uuid))) + goto cleanup;
Just realized that since virDomainObjListAdd returns a valid and existing domain if its name and uuid is the same this call can cause some problems. For instance, if a user specified the same source and destination uri, the migration will fail and Finish code will remove the domain from list. Thus what about the following chunk instead existing?: virObjectLock(privconn->driver); dom = virDomainObjListFindByUUID(privconn->driver->domains, mig->uuid); if (dom) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(mig->uuid, uuidstr); virReportError(VIR_ERR_INTERNAL_ERROR, _("A domain with uuid '%s' already exists"), uuidstr); goto unlock; } if (!(dom = vzNewDomain(privconn->driver, dname ? dname : mig->name, mig->uuid))) goto unlock; ret = 0; unlock: virObjectUnlock(privconn->driver);
+ + ret = 0; + + cleanup: + vzMigrationCookieFree(mig); + if (dom) + virObjectUnlock(dom); + return ret; +} + +static int +vzConnectSupportsFeature(virConnectPtr conn ATTRIBUTE_UNUSED, int feature) +{ + switch (feature) { + case VIR_DRV_FEATURE_MIGRATION_PARAMS: + return 1; + default: + return 0; + } +} + +static virURIPtr +vzParseVzURI(const char *uri_str) +{ + virURIPtr uri = NULL; + + if (!(uri = virURIParse(uri_str))) + goto error; + + if (!uri->scheme || !uri->server) { + virReportError(VIR_ERR_INVALID_ARG, + _("scheme and host are mandatory vz migration URI: %s"), + uri_str); + goto error; + } + + if (uri->user || uri->path || uri->query || uri->fragment) { + virReportError(VIR_ERR_INVALID_ARG, + _("only scheme, host and port are supported in " + "vz migration URI: %s"), uri_str); + goto error; + } + + if (STRNEQ(uri->scheme, "vzmigr")) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, + _("unsupported scheme %s in migration URI %s"), + uri->scheme, uri_str); + goto error; + } + + return uri; + + error: + virURIFree(uri); + return NULL; +} + +static int +vzDomainMigratePerform3Params(virDomainPtr domain, + const char *dconnuri ATTRIBUTE_UNUSED, + virTypedParameterPtr params, + int nparams, + const char *cookiein, + int cookieinlen, + char **cookieout ATTRIBUTE_UNUSED, + int *cookieoutlen ATTRIBUTE_UNUSED, + unsigned int flags) +{ + int ret = -1; + virDomainObjPtr dom = NULL; + virURIPtr vzuri = NULL; + vzConnPtr privconn = domain->conn->privateData; + const char *miguri = NULL; + const char *dname = NULL; + vzMigrationCookiePtr mig = NULL; + + virCheckFlags(VZ_MIGRATION_FLAGS, -1); + + if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) + goto cleanup; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_URI, &miguri) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, &dname) < 0) + goto cleanup; + + if (!miguri) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("migrate uri is not set")); + goto cleanup; + } + + if (!(mig = vzEatCookie(cookiein, cookieinlen))) + goto cleanup; + + if (!(dom = vzDomObjFromDomain(domain))) + goto cleanup; + + if (!(vzuri = vzParseVzURI(miguri))) + goto cleanup; + + if (prlsdkMigrate(dom, vzuri, mig->session_uuid, dname, flags) < 0) + goto cleanup; + + virDomainObjListRemove(privconn->driver->domains, dom); + dom = NULL; + + ret = 0; + + cleanup: + if (dom) + virObjectUnlock(dom); + virURIFree(vzuri); + vzMigrationCookieFree(mig); + + return ret; +} + +static virDomainPtr +vzDomainMigrateFinish3Params(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) +{ + virDomainObjPtr dom = NULL; + virDomainPtr domain = NULL; + vzConnPtr privconn = dconn->privateData; + vzDriverPtr driver = privconn->driver; + const char *name = NULL; + + virCheckFlags(VZ_MIGRATION_FLAGS, NULL); + + if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) + goto cleanup; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, &name) < 0) + goto cleanup; + + if (!(dom = virDomainObjListFindByName(driver->domains, name))) { + virReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching name '%s'"), name); + goto cleanup; + } + + if (cancelled) { + virDomainObjListRemove(driver->domains, dom); + dom = NULL; + goto cleanup; + } + + if (prlsdkLoadDomain(driver, dom)) + goto cleanup; + + domain = virGetDomain(dconn, dom->def->name, dom->def->uuid); + if (domain) + domain->id = dom->def->id; + + cleanup: + /* In this situation we have to restore domain on source. But the migration + * is already finished. */ + if (!cancelled && !domain) + VIR_WARN("Can't provide domain '%s' after successfull migration.", name); + virDomainObjEndAPI(&dom); + return domain; +} + +static int +vzDomainMigrateConfirm3Params(virDomainPtr domain ATTRIBUTE_UNUSED, + virTypedParameterPtr params, + int nparams, + const char *cookiein ATTRIBUTE_UNUSED, + int cookieinlen ATTRIBUTE_UNUSED, + unsigned int flags, + int cancelled ATTRIBUTE_UNUSED) +{ + virCheckFlags(VZ_MIGRATION_FLAGS, -1); + + if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) + return -1; + + return 0; +} + static virHypervisorDriver vzHypervisorDriver = { .name = "vz", .connectOpen = vzConnectOpen, /* 0.10.0 */ @@ -1648,6 +2085,12 @@ static virHypervisorDriver vzHypervisorDriver = { .connectUnregisterCloseCallback = vzConnectUnregisterCloseCallback, /* 1.3.2 */ .domainSetMemoryFlags = vzDomainSetMemoryFlags, /* 1.3.4 */ .domainSetMemory = vzDomainSetMemory, /* 1.3.4 */ + .connectSupportsFeature = vzConnectSupportsFeature, /* 1.3.5 */ + .domainMigrateBegin3Params = vzDomainMigrateBegin3Params, /* 1.3.5 */ + .domainMigratePrepare3Params = vzDomainMigratePrepare3Params, /* 1.3.5 */ + .domainMigratePerform3Params = vzDomainMigratePerform3Params, /* 1.3.5 */ + .domainMigrateFinish3Params = vzDomainMigrateFinish3Params, /* 1.3.5 */ + .domainMigrateConfirm3Params = vzDomainMigrateConfirm3Params, /* 1.3.5 */ };
static virConnectDriver vzConnectDriver = { diff --git a/src/vz/vz_sdk.c b/src/vz/vz_sdk.c index fbcf4d9..559f149 100644 --- a/src/vz/vz_sdk.c +++ b/src/vz/vz_sdk.c @@ -4296,3 +4296,45 @@ int prlsdkSetMemsize(virDomainObjPtr dom, unsigned int memsize) error: return -1; } + +/* high security is default choice for 2 reasons: + * 1. as this is the highest set security we can't get + * reject from server with high security settings + * 2. this is on par with security level of driver + * connection to dispatcher + */ + +#define PRLSDK_MIGRATION_FLAGS (PSL_HIGH_SECURITY) + +int prlsdkMigrate(virDomainObjPtr dom, virURIPtr uri, + const unsigned char *session_uuid, + const char *dname, + unsigned int flags) +{ + int ret = -1; + vzDomObjPtr privdom = dom->privateData; + PRL_HANDLE job = PRL_INVALID_HANDLE; + char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + PRL_UINT32 vzflags = PRLSDK_MIGRATION_FLAGS; + + if (flags & VIR_MIGRATE_PAUSED) + vzflags |= PVMT_DONT_RESUME_VM; + + prlsdkUUIDFormat(session_uuid, uuidstr); + job = PrlVm_MigrateWithRenameEx(privdom->sdkdom, uri->server, + uri->port, uuidstr, + dname == NULL ? "" : dname, + "", + vzflags, + 0, + PRL_TRUE + ); + + if (PRL_FAILED(waitJob(job))) + goto cleanup; + + ret = 0; + + cleanup: + return ret; +} diff --git a/src/vz/vz_sdk.h b/src/vz/vz_sdk.h index e562f98..3d27d12 100644 --- a/src/vz/vz_sdk.h +++ b/src/vz/vz_sdk.h @@ -82,3 +82,9 @@ void prlsdkDomObjFreePrivate(void *p); /* memsize is in MiB */ int prlsdkSetMemsize(virDomainObjPtr dom, unsigned int memsize); +int +prlsdkMigrate(virDomainObjPtr dom, + virURIPtr uri, + const char unsigned *session_uuid, + const char *dname, + unsigned int flags);

On 19.05.2016 13:38, Maxim Nestratov wrote:
18.05.2016 11:11, Nikolay Shirokovskiy пишет:
The newest version of migration protocol - version 3 with parameters is implemented. Supported flags is VIR_MIGRATE_PAUSED only. Supported parameters are VIR_MIGRATE_PARAM_URI and VIR_MIGRATE_PARAM_DEST_NAME. VIR_MIGRATE_PARAM_DEST_XML is in VZ_MIGRATION_PARAMETERS for technical onyl reasons.
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_driver.c | 443 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/vz/vz_sdk.c | 42 +++++ src/vz/vz_sdk.h | 6 + 3 files changed, 491 insertions(+)
...
+static int +vzDomainMigratePrepare3Params(virConnectPtr conn, + virTypedParameterPtr params, + int nparams, + const char *cookiein, + int cookieinlen, + char **cookieout, + int *cookieoutlen, + char **uri_out, + unsigned int flags) +{ + vzConnPtr privconn = conn->privateData; + const char *miguri = NULL; + const char *dname = NULL; + virDomainObjPtr dom = NULL; + vzMigrationCookiePtr mig = NULL; + int ret = -1; + + virCheckFlags(VZ_MIGRATION_FLAGS, -1); + + if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) + goto cleanup; + + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_URI, &miguri) < 0 || + virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, &dname) < 0) + goto cleanup; + + /* We must set uri_out if miguri is not set. This is direct + * managed migration requirement */ + if (!miguri && !(*uri_out = vzMigrationCreateURI())) + goto cleanup; + + if (!(mig = vzEatCookie(cookiein, cookieinlen))) + goto cleanup; + + memcpy(mig->session_uuid, privconn->driver->session_uuid, VIR_UUID_BUFLEN); + + if (vzBakeCookie(mig, cookieout, cookieoutlen) < 0) + goto cleanup; + + if (!(dom = vzNewDomain(privconn->driver, + dname ? dname : mig->name, mig->uuid))) + goto cleanup;
Just realized that since virDomainObjListAdd returns a valid and existing domain if its name and uuid is the same this call can cause some problems. For instance, if a user specified the same source and destination uri, the migration will fail and Finish code will remove the domain from list. Thus what about the following chunk instead existing?:
virObjectLock(privconn->driver); dom = virDomainObjListFindByUUID(privconn->driver->domains, mig->uuid); if (dom) { char uuidstr[VIR_UUID_STRING_BUFLEN]; virUUIDFormat(mig->uuid, uuidstr); virReportError(VIR_ERR_INTERNAL_ERROR, _("A domain with uuid '%s' already exists"), uuidstr); goto unlock; }
if (!(dom = vzNewDomain(privconn->driver, dname ? dname : mig->name, mig->uuid))) goto unlock;
ret = 0;
unlock: virObjectUnlock(privconn->driver);
Looks reasonable.
+ + ret = 0; + + cleanup: + vzMigrationCookieFree(mig); + if (dom) + virObjectUnlock(dom); + return ret; +} +

Peer to peer migration is implemented just as in managed case. Basically it is copy paste from managed case but with all the branches that are not applied to vz removed. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_driver.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 126 insertions(+), 10 deletions(-) diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index d1b8558..d3de490 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -1699,7 +1699,8 @@ vzEatCookie(const char *cookiein, int cookieinlen) goto cleanup; } -#define VZ_MIGRATION_FLAGS VIR_MIGRATE_PAUSED +#define VZ_MIGRATION_FLAGS (VIR_MIGRATE_PAUSED | \ + VIR_MIGRATE_PEER2PEER) #define VZ_MIGRATION_PARAMETERS \ VIR_MIGRATE_PARAM_DEST_XML, VIR_TYPED_PARAM_STRING, \ @@ -1843,6 +1844,7 @@ vzConnectSupportsFeature(virConnectPtr conn ATTRIBUTE_UNUSED, int feature) { switch (feature) { case VIR_DRV_FEATURE_MIGRATION_PARAMS: + case VIR_DRV_FEATURE_MIGRATION_P2P: return 1; default: return 0; @@ -1886,15 +1888,12 @@ vzParseVzURI(const char *uri_str) } static int -vzDomainMigratePerform3Params(virDomainPtr domain, - const char *dconnuri ATTRIBUTE_UNUSED, - virTypedParameterPtr params, - int nparams, - const char *cookiein, - int cookieinlen, - char **cookieout ATTRIBUTE_UNUSED, - int *cookieoutlen ATTRIBUTE_UNUSED, - unsigned int flags) +vzDomainMigratePerformStep(virDomainPtr domain, + virTypedParameterPtr params, + int nparams, + const char *cookiein, + int cookieinlen, + unsigned int flags) { int ret = -1; virDomainObjPtr dom = NULL; @@ -1947,6 +1946,123 @@ vzDomainMigratePerform3Params(virDomainPtr domain, return ret; } +static int +vzDomainMigratePerformP2P(virDomainPtr domain, + const char *dconnuri, + virTypedParameterPtr orig_params, + int nparams, + unsigned int flags) +{ + virDomainPtr ddomain = NULL; + char *uri = NULL; + char *cookiein = NULL; + char *cookieout = NULL; + char *dom_xml = NULL; + int cookieinlen = 0; + int cookieoutlen = 0; + virErrorPtr orig_err = NULL; + int cancelled = 1; + virConnectPtr dconn = NULL; + virTypedParameterPtr params = NULL; + int ret = -1; + + if (virTypedParamsCopy(¶ms, orig_params, nparams) < 0) + return -1; + + if (!(dconn = virConnectOpen(dconnuri))) + goto done; + + if (!(dom_xml = vzDomainMigrateBegin3Params(domain, params, nparams, + &cookieout, &cookieoutlen, + flags))) + goto done; + + cookiein = cookieout; + cookieinlen = cookieoutlen; + cookieout = NULL; + cookieoutlen = 0; + if (dconn->driver->domainMigratePrepare3Params + (dconn, params, nparams, cookiein, cookieinlen, + &cookieout, &cookieoutlen, &uri, flags) < 0) + goto done; + + /* preparation step was successful, thus on any error we must perform + * finish step to finalize migration on target + */ + if (uri && virTypedParamsReplaceString(¶ms, &nparams, + VIR_MIGRATE_PARAM_URI, uri) < 0) { + orig_err = virSaveLastError(); + goto finish; + } + + VIR_FREE(cookiein); + cookiein = cookieout; + cookieinlen = cookieoutlen; + cookieout = NULL; + cookieoutlen = 0; + if (vzDomainMigratePerformStep(domain, params, nparams, cookiein, + cookieinlen, flags) < 0) { + orig_err = virSaveLastError(); + goto finish; + } + + cancelled = 0; + + finish: + if (virTypedParamsGetString(params, nparams, + VIR_MIGRATE_PARAM_DEST_NAME, NULL) <= 0 && + virTypedParamsReplaceString(¶ms, &nparams, + VIR_MIGRATE_PARAM_DEST_NAME, + domain->name) < 0) + goto done; + + ddomain = dconn->driver->domainMigrateFinish3Params(dconn, params, nparams, + NULL, 0, NULL, NULL, + flags, cancelled); + if (ddomain) + ret = 0; + virObjectUnref(ddomain); + + /* confirm step is NOOP thus no need to call it */ + + done: + if (orig_err) { + virSetError(orig_err); + virFreeError(orig_err); + } + VIR_FREE(dom_xml); + VIR_FREE(uri); + VIR_FREE(cookiein); + VIR_FREE(cookieout); + virTypedParamsFree(params, nparams); + virObjectUnref(dconn); + return ret; +} + +static int +vzDomainMigratePerform3Params(virDomainPtr domain, + const char *dconnuri, + virTypedParameterPtr params, + int nparams, + const char *cookiein, + int cookieinlen, + char **cookieout ATTRIBUTE_UNUSED, + int *cookieoutlen ATTRIBUTE_UNUSED, + unsigned int flags) +{ + virCheckFlags(VZ_MIGRATION_FLAGS, -1); + + if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) + return -1; + + if (flags & VIR_MIGRATE_PEER2PEER) + return vzDomainMigratePerformP2P(domain, dconnuri, params, nparams, flags); + else + return vzDomainMigratePerformStep(domain, params, nparams, + cookiein, cookieinlen, flags); + +} + static virDomainPtr vzDomainMigrateFinish3Params(virConnectPtr dconn, virTypedParameterPtr params, -- 1.8.3.1

vz puts uuids into curly braces. Simply introduce new contstant to reflect this and get rid of magic +2 in code. Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com> --- src/vz/vz_sdk.c | 12 ++++++------ src/vz/vz_utils.h | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/vz/vz_sdk.c b/src/vz/vz_sdk.c index 559f149..02daf62 100644 --- a/src/vz/vz_sdk.c +++ b/src/vz/vz_sdk.c @@ -276,7 +276,7 @@ prlsdkConnect(vzDriverPtr driver) PRL_HANDLE job = PRL_INVALID_HANDLE; PRL_HANDLE result = PRL_INVALID_HANDLE; PRL_HANDLE response = PRL_INVALID_HANDLE; - char session_uuid[VIR_UUID_STRING_BUFLEN + 2]; + char session_uuid[VIR_UUID_STRING_BRACED_BUFLEN]; pret = PrlSrv_Create(&driver->server); prlsdkCheckRetExit(pret, -1); @@ -359,7 +359,7 @@ prlsdkUUIDFormat(const unsigned char *uuid, char *uuidstr) static PRL_HANDLE prlsdkSdkDomainLookupByUUID(vzDriverPtr driver, const unsigned char *uuid) { - char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + char uuidstr[VIR_UUID_STRING_BRACED_BUFLEN]; PRL_HANDLE sdkdom = PRL_INVALID_HANDLE; prlsdkUUIDFormat(uuid, uuidstr); @@ -404,7 +404,7 @@ prlsdkGetDomainIds(PRL_HANDLE sdkdom, char **name, unsigned char *uuid) { - char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + char uuidstr[VIR_UUID_STRING_BRACED_BUFLEN]; PRL_RESULT pret; if (name && !(*name = prlsdkGetStringParamVar(PrlVmCfg_GetName, sdkdom))) @@ -1893,7 +1893,7 @@ prlsdkEventsHandler(PRL_HANDLE prlEvent, PRL_VOID_PTR opaque) vzDriverPtr driver = opaque; PRL_RESULT pret = PRL_ERR_FAILURE; PRL_HANDLE_TYPE handleType; - char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + char uuidstr[VIR_UUID_STRING_BRACED_BUFLEN]; unsigned char uuid[VIR_UUID_BUFLEN]; PRL_EVENT_TYPE prlEventType; @@ -3572,7 +3572,7 @@ prlsdkDoApplyConfig(vzDriverPtr driver, { PRL_RESULT pret; size_t i; - char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + char uuidstr[VIR_UUID_STRING_BRACED_BUFLEN]; char *mask = NULL; if (prlsdkCheckUnsupportedParams(sdkdom, def) < 0) @@ -4314,7 +4314,7 @@ int prlsdkMigrate(virDomainObjPtr dom, virURIPtr uri, int ret = -1; vzDomObjPtr privdom = dom->privateData; PRL_HANDLE job = PRL_INVALID_HANDLE; - char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + char uuidstr[VIR_UUID_STRING_BRACED_BUFLEN]; PRL_UINT32 vzflags = PRLSDK_MIGRATION_FLAGS; if (flags & VIR_MIGRATE_PAUSED) diff --git a/src/vz/vz_utils.h b/src/vz/vz_utils.h index f8a3bb3..b8418cf 100644 --- a/src/vz/vz_utils.h +++ b/src/vz/vz_utils.h @@ -60,6 +60,9 @@ struct _vzCapabilities { typedef struct _vzCapabilities vzCapabilities; typedef struct _vzCapabilities *vzCapabilitiesPtr; +/* +2 to keep enclosing { and } */ +# define VIR_UUID_STRING_BRACED_BUFLEN (VIR_UUID_STRING_BUFLEN + 2) + struct _vzDriver { virObjectLockable parent; -- 1.8.3.1

18.05.2016 11:11, Nikolay Shirokovskiy пишет:
Difference from v6 ================== Minor fixes suggested by reviewer.
Nikolay Shirokovskiy (5): vz: save session uuid on login vz: fix const correctness case vz: implement managed migration vz: implement p2p migration vz: cleanup: define vz format of uuids
src/vz/vz_driver.c | 559 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/vz/vz_sdk.c | 90 +++++++-- src/vz/vz_sdk.h | 6 + src/vz/vz_utils.c | 2 +- src/vz/vz_utils.h | 7 +- 5 files changed, 648 insertions(+), 16 deletions(-)
ACK the series with changed mentioned inline for #3 patch. I modified as suggested and pushed. Thanks a lot! Maxim
participants (2)
-
Maxim Nestratov
-
Nikolay Shirokovskiy