On Tue, Aug 25, 2015 at 12:04:14PM +0300, nshirokovskiy(a)virtuozzo.com wrote:
From: Nikolay Shirokovskiy <nshirokovskiy(a)virtuozzo.com>
This patch makes basic vz migration possible. For example by virsh:
virsh -c vz:///system migrate --direct $NAME $STUB vz+ssh://$DST/system
$STUB could be anything as it is required virsh argument but it is not
used in direct migration.
Vz migration is implemented as direct migration. The reason is that vz sdk do
all the job. Prepare phase function is used to pass session uuid from
destination to source so we don't introduce new rpc call.
Looking more closely at migration again, the scenario you have is pretty
much identical to the Xen scenario, in that the hypervisor actually
manages the migration, but you still need a connection to dest libvirtd
to fetch some initialization data.
You have claimed you are implementing, what we describe as "direct, unmanaged"
migration on this page:
http://libvirt.org/migration.html
But based on the fact that you need to talk to dest libvirtd, you should
in fact implement 'direct, managed' migration - this name is slightly
misleading as the VZ SDK is still actually managing it.
Since you don't need to have the begin/confirm phases, you also don't
need to implement the V3 migration protocol - it is sufficient to just
use V1.
This doesn't need many changes in your patch fortunately.
diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c
index 8fa7957..f82fff8 100644
--- a/src/vz/vz_driver.c
+++ b/src/vz/vz_driver.c
@@ -1343,6 +1343,196 @@ vzDomainMemoryStats(virDomainPtr domain,
return ret;
}
+static char*
+vzFormatCookie(const unsigned char *session_uuid)
+{
+ char uuidstr[VIR_UUID_STRING_BUFLEN];
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+
+ virBufferAddLit(&buf, "<vz-migration1>\n");
+ virUUIDFormat(session_uuid, uuidstr);
+ virBufferAsprintf(&buf,
"<session_uuid>%s</session_uuid>\n", uuidstr);
+ virBufferAddLit(&buf, "</vz-migration1>\n");
+
+ if (virBufferCheckError(&buf) < 0)
+ return NULL;
+
+ return virBufferContentAndReset(&buf);
+}
+
+static int
+vzParseCookie(const char *xml, unsigned char *session_uuid)
+{
+ xmlDocPtr doc = NULL;
+ xmlXPathContextPtr ctx = NULL;
+ char *tmp = NULL;
+ int ret = -1;
+
+ if (!(doc = virXMLParseStringCtxt(xml, _("(_migration_cookie)"),
&ctx)))
+ goto cleanup;
+
+ if (!(tmp = virXPathString("string(./session_uuid[1])", ctx))) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("missing session_uuid element in migration
data"));
+ goto cleanup;
+ }
+ if (virUUIDParse(tmp, session_uuid) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("malformed session_uuid element in
migration data"));
+ goto cleanup;
+ }
+ ret = 0;
+
+ cleanup:
+ xmlXPathFreeContext(ctx);
+ xmlFreeDoc(doc);
+ VIR_FREE(tmp);
+
+ return ret;
+}
+
+static int
+vzDomainMigratePrepare3(virConnectPtr conn,
+ const char *cookiein ATTRIBUTE_UNUSED,
+ int cookieinlen ATTRIBUTE_UNUSED,
+ char **cookieout,
+ int *cookieoutlen,
+ const char *uri_in ATTRIBUTE_UNUSED,
+ char **uri_out ATTRIBUTE_UNUSED,
+ unsigned long flags,
+ const char *dname ATTRIBUTE_UNUSED,
+ unsigned long resource ATTRIBUTE_UNUSED,
+ const char *dom_xml ATTRIBUTE_UNUSED)
Switch to implement domainMigratePrepare, instead of the v3
method, since you don't need anything except the cookieout
parameters
+{
+ vzConnPtr privconn = conn->privateData;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ if (!(*cookieout = vzFormatCookie(privconn->session_uuid)))
+ goto cleanup;
+ *cookieoutlen = strlen(*cookieout) + 1;
+ ret = 0;
Also fill in the uri_out parameter, so that the user does
not need to provide a URI explicitly.
+
+ cleanup:
+ if (ret != 0) {
+ VIR_FREE(*cookieout);
+ *cookieoutlen = 0;
+ }
+
+ return ret;
+}
+
+static int
+vzConnectSupportsFeature(virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
+{
+ switch (feature) {
+ case VIR_DRV_FEATURE_MIGRATION_V3:
+ case VIR_DRV_FEATURE_MIGRATION_DIRECT:
+ return 1;
+ default:
+ return 0;
+ }
+}
You can drop this since you don't need V3 or DIRECT features.
+static virURIPtr
+vzMakeVzUri(const char *connuri_str)
+{
+ virURIPtr connuri = NULL;
+ virURIPtr vzuri = NULL;
+ int ret = -1;
+
+ if (!(connuri = virURIParse(connuri_str)))
+ goto cleanup;
+
+ if (VIR_ALLOC(vzuri) < 0)
+ goto cleanup;
+ memset(vzuri, 0, sizeof(*vzuri));
+
+ if (VIR_STRDUP(vzuri->server, connuri->server) < 0)
+ goto cleanup;
+ vzuri->port = connuri->port;
+ ret = 0;
+
+ cleanup:
+
+ virURIFree(connuri);
+ if (ret < 0) {
+ virURIFree(vzuri);
+ vzuri = NULL;
+ }
+
+ return vzuri;
+}
+
+#define VZ_MIGRATION_FLAGS (0)
+
+#define VZ_MIGRATION_PARAMETERS (NULL)
+
+static int
+vzDomainMigratePerform3(virDomainPtr domain,
+ const char *xmlin ATTRIBUTE_UNUSED,
+ const char *cookiein ATTRIBUTE_UNUSED,
+ int cookieinlen ATTRIBUTE_UNUSED,
+ char **cookieout ATTRIBUTE_UNUSED,
+ int *cookieoutlen ATTRIBUTE_UNUSED,
+ const char *dconnuri ATTRIBUTE_UNUSED,
+ const char *uri,
+ unsigned long flags,
+ const char *dname ATTRIBUTE_UNUSED,
+ unsigned long bandwidth ATTRIBUTE_UNUSED)
Switch to implement domainMigratePerform instead of Perform3,
and remove the ATTRIBUTE_UNUSED on the cookiein + cookieinlen
parameters.
+{
+ int ret = -1;
+ virDomainObjPtr dom = NULL;
+ virConnectPtr dconn = NULL;
+ virURIPtr vzuri = NULL;
+ unsigned char session_uuid[VIR_UUID_BUFLEN];
+ vzConnPtr privconn = domain->conn->privateData;
+ char *cookie = NULL;
+ int cookielen = 0;
+
+ virCheckFlags(VZ_MIGRATION_FLAGS, -1);
+
+ if (!(vzuri = vzMakeVzUri(uri)))
+ goto cleanup;
Remove the MakeVzUri call and just use the 'uri' parameter
directly - the Prepare method should populate uri_out in
the required format for the prlsdkMigrate() API call.
+ if (!(dom = vzDomObjFromDomain(domain)))
+ goto cleanup;
+
+ dconn = virConnectOpen(uri);
+ if (dconn == NULL) {
+ virReportError(VIR_ERR_OPERATION_FAILED,
+ _("Failed to connect to remote libvirt URI %s: %s"),
+ uri, virGetLastErrorMessage());
+ goto cleanup;
+ }
+
+ /* NULL and zero elements are unused */
+ /* domxml is passed as "" or otherwise we will fail at rpc call */
+ if (virDomainMigratePrepare3(dconn, NULL, 0, &cookie, &cookielen, NULL,
NULL, 0, NULL, 0, "") < 0)
+ goto cleanup;
Instead of opening the connection and calling Prepare3, simply
use the 'cookiein' parameter passed to Perform()
+
+ if (vzParseCookie(cookie, session_uuid) < 0)
+ goto cleanup;
+
+ if (prlsdkMigrate(dom, vzuri, session_uuid) < 0)
+ goto cleanup;
+
+ virDomainObjListRemove(privconn->domains, dom);
+ dom = NULL;
+
+ ret = 0;
+
+ cleanup:
+ if (dom)
+ virObjectUnlock(dom);
+ virObjectUnref(dconn);
+ virURIFree(vzuri);
+ VIR_FREE(cookie);
+
+ return ret;
+}
+
static virHypervisorDriver vzDriver = {
.name = "vz",
.connectOpen = vzConnectOpen, /* 0.10.0 */
@@ -1396,6 +1586,9 @@ static virHypervisorDriver vzDriver = {
.domainBlockStatsFlags = vzDomainBlockStatsFlags, /* 1.2.17 */
.domainInterfaceStats = vzDomainInterfaceStats, /* 1.2.17 */
.domainMemoryStats = vzDomainMemoryStats, /* 1.2.17 */
+ .connectSupportsFeature = vzConnectSupportsFeature, /* 1.2.19 */
+ .domainMigratePrepare3 = vzDomainMigratePrepare3, /* 1.2.19 */
+ .domainMigratePerform3 = vzDomainMigratePerform3, /* 1.2.19 */
Drop the '3' from these.
Regards,
Daniel
--
|:
http://berrange.com -o-
http://www.flickr.com/photos/dberrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|:
http://entangle-photo.org -o-
http://live.gnome.org/gtk-vnc :|