mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-24 14:45:24 +00:00
Split virDomainMigrate into functions.
Re-factor virDomainMigrate to split out the version 1 and version 2 protocols into their own functions. In reality, the two versions share very little in common, so forcing them together in the same function was just confusing. This will also make adding tunnelled migration easier. Signed-off-by: Chris Lalancette <clalance@redhat.com>
This commit is contained in:
parent
cbcf5ba7d4
commit
3c7a12b416
260
src/libvirt.c
260
src/libvirt.c
@ -2853,6 +2853,146 @@ error:
|
||||
}
|
||||
|
||||
|
||||
static virDomainPtr
|
||||
virDomainMigrateVersion1 (virDomainPtr domain,
|
||||
virConnectPtr dconn,
|
||||
unsigned long flags,
|
||||
const char *dname,
|
||||
const char *uri,
|
||||
unsigned long bandwidth)
|
||||
{
|
||||
virDomainPtr ddomain = NULL;
|
||||
char *uri_out = NULL;
|
||||
char *cookie = NULL;
|
||||
int cookielen = 0;
|
||||
|
||||
/* Prepare the migration.
|
||||
*
|
||||
* The destination host may return a cookie, or leave cookie as
|
||||
* NULL.
|
||||
*
|
||||
* The destination host MUST set uri_out if uri_in is NULL.
|
||||
*
|
||||
* If uri_in is non-NULL, then the destination host may modify
|
||||
* the URI by setting uri_out. If it does not wish to modify
|
||||
* the URI, it should leave uri_out as NULL.
|
||||
*/
|
||||
if (dconn->driver->domainMigratePrepare
|
||||
(dconn, &cookie, &cookielen, uri, &uri_out, flags, dname,
|
||||
bandwidth) == -1)
|
||||
goto done;
|
||||
|
||||
if (uri == NULL && uri_out == NULL) {
|
||||
virLibConnError (domain->conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("domainMigratePrepare did not set uri"));
|
||||
goto done;
|
||||
}
|
||||
if (uri_out)
|
||||
uri = uri_out; /* Did domainMigratePrepare change URI? */
|
||||
assert (uri != NULL);
|
||||
|
||||
/* Perform the migration. The driver isn't supposed to return
|
||||
* until the migration is complete.
|
||||
*/
|
||||
if (domain->conn->driver->domainMigratePerform
|
||||
(domain, cookie, cookielen, uri, flags, dname, bandwidth) == -1)
|
||||
goto done;
|
||||
|
||||
/* Get the destination domain and return it or error.
|
||||
* 'domain' no longer actually exists at this point
|
||||
* (or so we hope), but we still use the object in memory
|
||||
* in order to get the name.
|
||||
*/
|
||||
dname = dname ? dname : domain->name;
|
||||
if (dconn->driver->domainMigrateFinish)
|
||||
ddomain = dconn->driver->domainMigrateFinish
|
||||
(dconn, dname, cookie, cookielen, uri, flags);
|
||||
else
|
||||
ddomain = virDomainLookupByName (dconn, dname);
|
||||
|
||||
done:
|
||||
VIR_FREE (uri_out);
|
||||
VIR_FREE (cookie);
|
||||
return ddomain;
|
||||
}
|
||||
|
||||
static virDomainPtr
|
||||
virDomainMigrateVersion2 (virDomainPtr domain,
|
||||
virConnectPtr dconn,
|
||||
unsigned long flags,
|
||||
const char *dname,
|
||||
const char *uri,
|
||||
unsigned long bandwidth)
|
||||
{
|
||||
virDomainPtr ddomain = NULL;
|
||||
char *uri_out = NULL;
|
||||
char *cookie = NULL;
|
||||
char *dom_xml = NULL;
|
||||
int cookielen = 0, ret;
|
||||
|
||||
/* Prepare the migration.
|
||||
*
|
||||
* The destination host may return a cookie, or leave cookie as
|
||||
* NULL.
|
||||
*
|
||||
* The destination host MUST set uri_out if uri_in is NULL.
|
||||
*
|
||||
* If uri_in is non-NULL, then the destination host may modify
|
||||
* the URI by setting uri_out. If it does not wish to modify
|
||||
* the URI, it should leave uri_out as NULL.
|
||||
*/
|
||||
|
||||
/* In version 2 of the protocol, the prepare step is slightly
|
||||
* different. We fetch the domain XML of the source domain
|
||||
* and pass it to Prepare2.
|
||||
*/
|
||||
if (!domain->conn->driver->domainDumpXML) {
|
||||
virLibConnError (domain->conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
dom_xml = domain->conn->driver->domainDumpXML (domain,
|
||||
VIR_DOMAIN_XML_SECURE);
|
||||
if (!dom_xml)
|
||||
return NULL;
|
||||
|
||||
ret = dconn->driver->domainMigratePrepare2
|
||||
(dconn, &cookie, &cookielen, uri, &uri_out, flags, dname,
|
||||
bandwidth, dom_xml);
|
||||
VIR_FREE (dom_xml);
|
||||
if (ret == -1)
|
||||
goto done;
|
||||
|
||||
if (uri == NULL && uri_out == NULL) {
|
||||
virLibConnError (domain->conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("domainMigratePrepare2 did not set uri"));
|
||||
goto done;
|
||||
}
|
||||
if (uri_out)
|
||||
uri = uri_out; /* Did domainMigratePrepare2 change URI? */
|
||||
assert (uri != NULL);
|
||||
|
||||
/* Perform the migration. The driver isn't supposed to return
|
||||
* until the migration is complete.
|
||||
*/
|
||||
ret = domain->conn->driver->domainMigratePerform
|
||||
(domain, cookie, cookielen, uri, flags, dname, bandwidth);
|
||||
if (ret == -1)
|
||||
goto done;
|
||||
|
||||
/* In version 2 of the migration protocol, we pass the
|
||||
* status code from the sender to the destination host,
|
||||
* so it can do any cleanup if the migration failed.
|
||||
*/
|
||||
dname = dname ? dname : domain->name;
|
||||
ddomain = dconn->driver->domainMigrateFinish2
|
||||
(dconn, dname, cookie, cookielen, uri, flags, ret);
|
||||
|
||||
done:
|
||||
VIR_FREE (uri_out);
|
||||
VIR_FREE (cookie);
|
||||
return ddomain;
|
||||
}
|
||||
|
||||
/**
|
||||
* virDomainMigrate:
|
||||
* @domain: a domain object
|
||||
@ -2909,140 +3049,52 @@ virDomainMigrate (virDomainPtr domain,
|
||||
const char *uri,
|
||||
unsigned long bandwidth)
|
||||
{
|
||||
virConnectPtr conn;
|
||||
virDomainPtr ddomain = NULL;
|
||||
char *uri_out = NULL;
|
||||
char *cookie = NULL;
|
||||
char *dom_xml = NULL;
|
||||
int cookielen = 0, ret, version = 0;
|
||||
DEBUG("domain=%p, dconn=%p, flags=%lu, dname=%s, uri=%s, bandwidth=%lu",
|
||||
domain, dconn, flags, NULLSTR(dname), NULLSTR(uri), bandwidth);
|
||||
|
||||
virResetLastError();
|
||||
|
||||
/* First checkout the source */
|
||||
if (!VIR_IS_CONNECTED_DOMAIN (domain)) {
|
||||
virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
conn = domain->conn; /* Source connection. */
|
||||
if (!VIR_IS_CONNECT (dconn)) {
|
||||
virLibConnError (conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (domain->conn->flags & VIR_CONNECT_RO) {
|
||||
virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Now checkout the destination */
|
||||
if (!VIR_IS_CONNECT (dconn)) {
|
||||
virLibConnError (domain->conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
|
||||
goto error;
|
||||
}
|
||||
if (dconn->flags & VIR_CONNECT_RO) {
|
||||
/* NB, delibrately report error against source object, not dest here */
|
||||
virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
|
||||
/* NB, deliberately report error against source object, not dest */
|
||||
virLibDomainError (domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Check that migration is supported by both drivers. */
|
||||
if (VIR_DRV_SUPPORTS_FEATURE (conn->driver, conn,
|
||||
if (VIR_DRV_SUPPORTS_FEATURE (domain->conn->driver, domain->conn,
|
||||
VIR_DRV_FEATURE_MIGRATION_V1) &&
|
||||
VIR_DRV_SUPPORTS_FEATURE (dconn->driver, dconn,
|
||||
VIR_DRV_FEATURE_MIGRATION_V1))
|
||||
version = 1;
|
||||
else if (VIR_DRV_SUPPORTS_FEATURE (conn->driver, conn,
|
||||
ddomain = virDomainMigrateVersion1 (domain, dconn, flags, dname, uri, bandwidth);
|
||||
else if (VIR_DRV_SUPPORTS_FEATURE (domain->conn->driver, domain->conn,
|
||||
VIR_DRV_FEATURE_MIGRATION_V2) &&
|
||||
VIR_DRV_SUPPORTS_FEATURE (dconn->driver, dconn,
|
||||
VIR_DRV_FEATURE_MIGRATION_V2))
|
||||
version = 2;
|
||||
ddomain = virDomainMigrateVersion2 (domain, dconn, flags, dname, uri, bandwidth);
|
||||
else {
|
||||
virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
|
||||
virLibConnError (domain->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Prepare the migration.
|
||||
*
|
||||
* The destination host may return a cookie, or leave cookie as
|
||||
* NULL.
|
||||
*
|
||||
* The destination host MUST set uri_out if uri_in is NULL.
|
||||
*
|
||||
* If uri_in is non-NULL, then the destination host may modify
|
||||
* the URI by setting uri_out. If it does not wish to modify
|
||||
* the URI, it should leave uri_out as NULL.
|
||||
*/
|
||||
if (version == 1) {
|
||||
ret = dconn->driver->domainMigratePrepare
|
||||
(dconn, &cookie, &cookielen, uri, &uri_out, flags, dname,
|
||||
bandwidth);
|
||||
if (ret == -1) goto done;
|
||||
if (uri == NULL && uri_out == NULL) {
|
||||
virLibConnError (conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("domainMigratePrepare did not set uri"));
|
||||
goto done;
|
||||
}
|
||||
if (uri_out) uri = uri_out; /* Did domainMigratePrepare change URI? */
|
||||
if (ddomain == NULL)
|
||||
goto error;
|
||||
|
||||
assert (uri != NULL);
|
||||
}
|
||||
else /* if (version == 2) */ {
|
||||
/* In version 2 of the protocol, the prepare step is slightly
|
||||
* different. We fetch the domain XML of the source domain
|
||||
* and pass it to Prepare2.
|
||||
*/
|
||||
if (!conn->driver->domainDumpXML) {
|
||||
virLibConnError (conn, VIR_ERR_INTERNAL_ERROR, __FUNCTION__);
|
||||
goto error;
|
||||
}
|
||||
dom_xml = conn->driver->domainDumpXML (domain,
|
||||
VIR_DOMAIN_XML_SECURE);
|
||||
|
||||
if (!dom_xml)
|
||||
goto error;
|
||||
|
||||
ret = dconn->driver->domainMigratePrepare2
|
||||
(dconn, &cookie, &cookielen, uri, &uri_out, flags, dname,
|
||||
bandwidth, dom_xml);
|
||||
VIR_FREE (dom_xml);
|
||||
if (ret == -1) goto done;
|
||||
if (uri == NULL && uri_out == NULL) {
|
||||
virLibConnError (conn, VIR_ERR_INTERNAL_ERROR,
|
||||
_("domainMigratePrepare2 did not set uri"));
|
||||
goto done;
|
||||
}
|
||||
if (uri_out) uri = uri_out; /* Did domainMigratePrepare2 change URI? */
|
||||
|
||||
assert (uri != NULL);
|
||||
}
|
||||
|
||||
/* Perform the migration. The driver isn't supposed to return
|
||||
* until the migration is complete.
|
||||
*/
|
||||
ret = conn->driver->domainMigratePerform
|
||||
(domain, cookie, cookielen, uri, flags, dname, bandwidth);
|
||||
|
||||
if (version == 1) {
|
||||
if (ret == -1) goto done;
|
||||
/* Get the destination domain and return it or error.
|
||||
* 'domain' no longer actually exists at this point
|
||||
* (or so we hope), but we still use the object in memory
|
||||
* in order to get the name.
|
||||
*/
|
||||
dname = dname ? dname : domain->name;
|
||||
if (dconn->driver->domainMigrateFinish)
|
||||
ddomain = dconn->driver->domainMigrateFinish
|
||||
(dconn, dname, cookie, cookielen, uri, flags);
|
||||
else
|
||||
ddomain = virDomainLookupByName (dconn, dname);
|
||||
} else /* if (version == 2) */ {
|
||||
/* In version 2 of the migration protocol, we pass the
|
||||
* status code from the sender to the destination host,
|
||||
* so it can do any cleanup if the migration failed.
|
||||
*/
|
||||
dname = dname ? dname : domain->name;
|
||||
ddomain = dconn->driver->domainMigrateFinish2
|
||||
(dconn, dname, cookie, cookielen, uri, flags, ret);
|
||||
}
|
||||
|
||||
done:
|
||||
VIR_FREE (uri_out);
|
||||
VIR_FREE (cookie);
|
||||
return ddomain;
|
||||
|
||||
error:
|
||||
|
Loading…
Reference in New Issue
Block a user