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

Difference from v5 ================== 1. managed case is implemented 2. p2p follows managed migration flow now 3. 'vz: fix const correctness case' is needed to implement managed case. 4. misc options that are always on for vz (--live, --compressed) are not required to be set explicitly. 5. --offline is not supported anymore but migration of inactive domains is possible without this option set. 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 | 557 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/vz/vz_sdk.c | 90 +++++++-- src/vz/vz_sdk.h | 6 + src/vz/vz_utils.c | 2 +- src/vz/vz_utils.h | 6 +- 5 files changed, 645 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 8cc8430..5fee10c 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

22.04.2016 10:20, Nikolay Shirokovskiy пишет:
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(-)
ACK

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 ae99aa0..4b82c62 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

22.04.2016 10:20, Nikolay Shirokovskiy пишет:
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 ae99aa0..4b82c62 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);
ACK

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 | 444 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/vz/vz_sdk.c | 42 +++++ src/vz/vz_sdk.h | 6 + 3 files changed, 492 insertions(+) diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index 1497b72..46f2487 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,441 @@ 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 = NULL; + vzMigrationCookiePtr mig = NULL; + + if (VIR_ALLOC(mig) < 0) + return NULL; + + if (!cookiein) + return mig; + + if (cookiein[cookieinlen - 1] != '\0') { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Migration cookie was not NULL terminated")); + 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")); + 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")); + goto error; + } + + 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); + VIR_FREE(tmp); + 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 (!(mig = vzEatCookie(NULL, 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 + * managmed 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 +2086,12 @@ static virHypervisorDriver vzHypervisorDriver = { .connectUnregisterCloseCallback = vzConnectUnregisterCloseCallback, /* 1.3.2 */ .domainSetMemoryFlags = vzDomainSetMemoryFlags, /* 1.3.4 */ .domainSetMemory = vzDomainSetMemory, /* 1.3.4 */ + .connectSupportsFeature = vzConnectSupportsFeature, /* 1.3.4 */ + .domainMigrateBegin3Params = vzDomainMigrateBegin3Params, /* 1.3.4 */ + .domainMigratePrepare3Params = vzDomainMigratePrepare3Params, /* 1.3.4 */ + .domainMigratePerform3Params = vzDomainMigratePerform3Params, /* 1.3.4 */ + .domainMigrateFinish3Params = vzDomainMigrateFinish3Params, /* 1.3.4 */ + .domainMigrateConfirm3Params = vzDomainMigrateConfirm3Params, /* 1.3.4 */ }; static virConnectDriver vzConnectDriver = { diff --git a/src/vz/vz_sdk.c b/src/vz/vz_sdk.c index 5fee10c..f6a1152 100644 --- a/src/vz/vz_sdk.c +++ b/src/vz/vz_sdk.c @@ -4289,3 +4289,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

22.04.2016 10:20, 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 | 444 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/vz/vz_sdk.c | 42 +++++ src/vz/vz_sdk.h | 6 + 3 files changed, 492 insertions(+)
diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index 1497b72..46f2487 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,441 @@ 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 = NULL; + vzMigrationCookiePtr mig = NULL; + + if (VIR_ALLOC(mig) < 0) + return NULL; + + if (!cookiein) + return mig; +
Let's be paranoic and check for cookieinlen also here
+ if (cookiein[cookieinlen - 1] != '\0') { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Migration cookie was not NULL terminated")); + 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"));
I would free tmp here
+ 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"));
and here
+ goto error; + } + + 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); + VIR_FREE(tmp);
and removed here Then all parsing chunks would look symmetric
+ 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 (!(mig = vzEatCookie(NULL, 0))) + goto cleanup;
Hm. It's a strange way to allocate a structure. I'd prefer explicit VIR_ALLOC, especially taking into account the fact that EatCookie doesn't do anything else
+ + 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 + * managmed migration requirement */
s/managmed/managed
+ 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; +
I wish it was asynchrounous right now, but as a first implementation let it be as is.
+ 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 +2086,12 @@ static virHypervisorDriver vzHypervisorDriver = { .connectUnregisterCloseCallback = vzConnectUnregisterCloseCallback, /* 1.3.2 */ .domainSetMemoryFlags = vzDomainSetMemoryFlags, /* 1.3.4 */ .domainSetMemory = vzDomainSetMemory, /* 1.3.4 */ + .connectSupportsFeature = vzConnectSupportsFeature, /* 1.3.4 */ + .domainMigrateBegin3Params = vzDomainMigrateBegin3Params, /* 1.3.4 */ + .domainMigratePrepare3Params = vzDomainMigratePrepare3Params, /* 1.3.4 */ + .domainMigratePerform3Params = vzDomainMigratePerform3Params, /* 1.3.4 */ + .domainMigrateFinish3Params = vzDomainMigrateFinish3Params, /* 1.3.4 */ + .domainMigrateConfirm3Params = vzDomainMigrateConfirm3Params, /* 1.3.4 */
Should be 1.3.5
};
static virConnectDriver vzConnectDriver = { diff --git a/src/vz/vz_sdk.c b/src/vz/vz_sdk.c index 5fee10c..f6a1152 100644 --- a/src/vz/vz_sdk.c +++ b/src/vz/vz_sdk.c @@ -4289,3 +4289,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);
ACK as a starting point with comments inline. But we certaintly should improve the implementation by making it asynchonous.

On 17.05.2016 21:33, Maxim Nestratov wrote:
22.04.2016 10:20, 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 | 444 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/vz/vz_sdk.c | 42 +++++ src/vz/vz_sdk.h | 6 + 3 files changed, 492 insertions(+)
...
ACK as a starting point with comments inline. But we certaintly should improve the implementation by making it asynchonous.
Great. I'll fix all the minor issues then.

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 | 139 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 126 insertions(+), 13 deletions(-) diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index 46f2487..8264ac0 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -1700,7 +1700,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, \ @@ -1804,9 +1805,6 @@ vzDomainMigratePrepare3Params(virConnectPtr conn, 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, @@ -1844,6 +1842,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; @@ -1887,15 +1886,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; @@ -1948,6 +1944,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

22.04.2016 10:20, Nikolay Shirokovskiy пишет:
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 | 139 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 126 insertions(+), 13 deletions(-)
diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index 46f2487..8264ac0 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -1700,7 +1700,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, \ @@ -1804,9 +1805,6 @@ vzDomainMigratePrepare3Params(virConnectPtr conn,
virCheckFlags(VZ_MIGRATION_FLAGS, -1);
- if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) - goto cleanup; -
Is it intentionally removed? Why?
if (virTypedParamsGetString(params, nparams, VIR_MIGRATE_PARAM_URI, &miguri) < 0 || virTypedParamsGetString(params, nparams, @@ -1844,6 +1842,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; @@ -1887,15 +1886,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; @@ -1948,6 +1944,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,

On 17.05.2016 21:56, Maxim Nestratov wrote:
22.04.2016 10:20, Nikolay Shirokovskiy пишет:
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 | 139 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 126 insertions(+), 13 deletions(-)
diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index 46f2487..8264ac0 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -1700,7 +1700,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, \ @@ -1804,9 +1805,6 @@ vzDomainMigratePrepare3Params(virConnectPtr conn, virCheckFlags(VZ_MIGRATION_FLAGS, -1); - if (virTypedParamsValidate(params, nparams, VZ_MIGRATION_PARAMETERS) < 0) - goto cleanup; -
Is it intentionally removed? Why?
Looks like it's typo.

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 | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/vz/vz_sdk.c b/src/vz/vz_sdk.c index f6a1152..a96fc96 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[VZ_UUID_STRING_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[VZ_UUID_STRING_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[VZ_UUID_STRING_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[VZ_UUID_STRING_BUFLEN]; unsigned char uuid[VIR_UUID_BUFLEN]; PRL_EVENT_TYPE prlEventType; @@ -3569,7 +3569,7 @@ prlsdkDoApplyConfig(vzDriverPtr driver, { PRL_RESULT pret; size_t i; - char uuidstr[VIR_UUID_STRING_BUFLEN + 2]; + char uuidstr[VZ_UUID_STRING_BUFLEN]; char *mask = NULL; if (prlsdkCheckUnsupportedParams(sdkdom, def) < 0) @@ -4307,7 +4307,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[VZ_UUID_STRING_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..f88fe4e 100644 --- a/src/vz/vz_utils.h +++ b/src/vz/vz_utils.h @@ -60,6 +60,8 @@ struct _vzCapabilities { typedef struct _vzCapabilities vzCapabilities; typedef struct _vzCapabilities *vzCapabilitiesPtr; +# define VZ_UUID_STRING_BUFLEN (VIR_UUID_STRING_BUFLEN + 2) + struct _vzDriver { virObjectLockable parent; -- 1.8.3.1

22.04.2016 10:20, Nikolay Shirokovskiy пишет:
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 | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-)
I bet we will confuse VZ_UUID_STRING_BUFLEN and VIR_UUID_STRING_BUFLEN eventually That's why I doubt we need this patch

On 17.05.2016 22:02, Maxim Nestratov wrote:
22.04.2016 10:20, Nikolay Shirokovskiy пишет:
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 | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-)
I bet we will confuse VZ_UUID_STRING_BUFLEN and VIR_UUID_STRING_BUFLEN eventually That's why I doubt we need this patch
I see, what if I use VIR_UUID_STRING_BRACED_BUFLEN instead?

18.05.2016 10:54, Nikolay Shirokovskiy пишет:
On 17.05.2016 22:02, Maxim Nestratov wrote:
22.04.2016 10:20, Nikolay Shirokovskiy пишет:
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 | 2 ++ 2 files changed, 8 insertions(+), 6 deletions(-) I bet we will confuse VZ_UUID_STRING_BUFLEN and VIR_UUID_STRING_BUFLEN eventually That's why I doubt we need this patch
I see, what if I use VIR_UUID_STRING_BRACED_BUFLEN instead?
OK to me. But if you use VIR prefix, then it's better to define it beside VIR_UUID_STRING_BUFLEN
participants (2)
-
Maxim Nestratov
-
Nikolay Shirokovskiy