[PATCH 0 of 2] Add migration job support

This set adds job support to migration, so that the migration methods return immediately with a job reference. The progress of the migration can be monitored by looking at Virt_MigrationJob instances. I left a good opening for indications (which will be necessary) by adding the migrate_job_set_state() function. This updates the state of the persistent job, which would be time(s) when we're looking to send an indication. Right now, Jobs are left in the persistent store after they're complete. Comments about the best policy for handling this are welcome. I know that I should be able to put a lifetime on them so they expire after completion, but I'm not sure if that's something that should be left to the client.

# HG changeset patch # User Dan Smith <danms@us.ibm.com> # Date 1197311334 28800 # Node ID 3515a63e76897dec28f1543f9ce7172e5bae567d # Parent 70e9f11ed6d3ea63b342c4c3de68cc948d7c1cfd Add MigrationJob schema Signed-off-by: Dan Smith <danms@us.ibm.com> diff -r 70e9f11ed6d3 -r 3515a63e7689 schema/VSMigrationService.mof --- a/schema/VSMigrationService.mof Mon Dec 10 08:54:08 2007 -0800 +++ b/schema/VSMigrationService.mof Mon Dec 10 10:28:54 2007 -0800 @@ -33,6 +33,9 @@ class CIM_VirtualSystemMigrationService }; +class Virt_MigrationJob : CIM_ConcreteJob { +}; + class Xen_VirtualSystemMigrationService : CIM_VirtualSystemMigrationService { };

# HG changeset patch # User Dan Smith <danms@us.ibm.com> # Date 1197314773 28800 # Node ID 9a8027256eec1641b901477a63f7787c73edd1ee # Parent 3515a63e76897dec28f1543f9ce7172e5bae567d Make migration spawn an asynchronous job Signed-off-by: Dan Smith <danms@us.ibm.com> diff -r 3515a63e7689 -r 9a8027256eec src/Virt_VSMigrationService.c --- a/src/Virt_VSMigrationService.c Mon Dec 10 10:28:54 2007 -0800 +++ b/src/Virt_VSMigrationService.c Mon Dec 10 11:26:13 2007 -0800 @@ -22,6 +22,8 @@ #include <stdlib.h> #include <string.h> +#include <uuid/uuid.h> + #include <libvirt/libvirt.h> #include <cmpidt.h> @@ -35,6 +37,10 @@ #include "Virt_VSMigrationService.h" +#define CIM_JOBSTATE_STARTING 3 +#define CIM_JOBSTATE_RUNNING 4 +#define CIM_JOBSTATE_COMPLETE 7 + #define METHOD_RETURN(r, v) do { \ uint32_t rc = v; \ CMReturnData(r, (CMPIValue *)&rc, CMPI_uint32); \ @@ -42,12 +48,17 @@ const static CMPIBroker *_BROKER; -static const char *transport_from_ref(const CMPIObjectPath *ref) -{ - const char *cn; - - cn = CLASSNAME(ref); - +struct migration_job { + CMPIContext *context; + char *domain; + char *host; + char *ref_cn; + char *ref_ns; + char uuid[33]; +}; + +static const char *transport_from_class(const char *cn) +{ if (STARTS_WITH(cn, "Xen")) return "xen+ssh"; else if (STARTS_WITH(cn, "KVM")) @@ -56,15 +67,15 @@ static const char *transport_from_ref(co return NULL; } -static char *dest_uri(const CMPIObjectPath *ref, +static char *dest_uri(const char *cn, const char *dest) { char *uri; const char *tport = NULL; - tport = transport_from_ref(ref); + tport = transport_from_class(cn); if (tport == NULL) { - CU_DEBUG("Failed to get transport for %s", CLASSNAME(ref)); + CU_DEBUG("Failed to get transport for %s", cn); return NULL; } @@ -127,7 +138,7 @@ static CMPIStatus vs_migratable(const CM virConnectPtr dconn = NULL; uint32_t retcode = 1; - uri = dest_uri(ref, destination); + uri = dest_uri(CLASSNAME(ref), destination); if (uri == NULL) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, @@ -230,10 +241,48 @@ static CMPIStatus vs_migratable_system(C return vs_migratable(ref, name, dname, results); } -static CMPIStatus migrate_vs(const CMPIObjectPath *ref, - const char *domain, - const char *destination, - const CMPIResult *results) +static void migrate_job_set_state(struct migration_job *job, + uint16_t state, + const char *status) +{ + CMPIInstance *inst; + CMPIStatus s; + CMPIObjectPath *op; + + op = CMNewObjectPath(_BROKER, + job->ref_ns, + "Virt_MigrationJob", + &s); + if (s.rc != CMPI_RC_OK) { + CU_DEBUG("Failed to create job path for update"); + return; + } + + CMSetNameSpace(op, job->ref_ns); + CMAddKey(op, "InstanceID", (CMPIValue *)job->uuid, CMPI_chars); + + CU_DEBUG("Getting job instance %s", job->uuid); + CU_DEBUG(" OP: %s", CMGetCharPtr(CMObjectPathToString(op, NULL))); + inst = CBGetInstance(_BROKER, job->context, op, NULL, &s); + if ((inst == NULL) || (s.rc != CMPI_RC_OK)) { + CU_DEBUG("Failed to get job instance for update (%i)", s.rc); + return; + } + + CMSetProperty(inst, "JobState", + (CMPIValue *)&state, CMPI_uint16); + CMSetProperty(inst, "Status", + (CMPIValue *)status, CMPI_chars); + + CU_DEBUG("Modifying job %s (%i:%s)", job->uuid, state, status); + + s = CBModifyInstance(_BROKER, job->context, op, inst, NULL); + if (s.rc != CMPI_RC_OK) + CU_DEBUG("Failed to update job instance: %s", + CMGetCharPtr(s.msg)); +} + +static CMPIStatus migrate_vs(struct migration_job *job) { CMPIStatus s; virConnectPtr conn = NULL; @@ -241,9 +290,8 @@ static CMPIStatus migrate_vs(const CMPIO virDomainPtr dom = NULL; virDomainPtr ddom = NULL; char *uri = NULL; - uint32_t retcode = 1; - - uri = dest_uri(ref, destination); + + uri = dest_uri(job->ref_cn, job->host); if (uri == NULL) { cu_statusf(_BROKER, &s, CMPI_RC_ERR_FAILED, @@ -251,16 +299,16 @@ static CMPIStatus migrate_vs(const CMPIO goto out; } - conn = connect_by_classname(_BROKER, CLASSNAME(ref), &s); + conn = connect_by_classname(_BROKER, job->ref_cn, &s); if (conn == NULL) goto out; - dom = virDomainLookupByName(conn, domain); + dom = virDomainLookupByName(conn, job->domain); if (dom == NULL) { - CU_DEBUG("Failed to lookup `%s'", domain); - cu_statusf(_BROKER, &s, - CMPI_RC_ERR_FAILED, - "Failed to lookup domain `%s'", domain); + CU_DEBUG("Failed to lookup `%s'", job->domain); + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Failed to lookup domain `%s'", job->domain); goto out; } @@ -273,7 +321,7 @@ static CMPIStatus migrate_vs(const CMPIO goto out; } - CU_DEBUG("Migrating %s -> %s", domain, uri); + CU_DEBUG("Migrating %s -> %s", job->domain, uri); ddom = virDomainMigrate(dom, dconn, VIR_MIGRATE_LIVE, NULL, NULL, 0); if (ddom == NULL) { @@ -285,17 +333,194 @@ static CMPIStatus migrate_vs(const CMPIO } CU_DEBUG("Migration succeeded"); - retcode = 0; CMSetStatus(&s, CMPI_RC_OK); out: - CMReturnData(results, (CMPIValue *)&retcode, CMPI_uint32); - free(uri); virDomainFree(dom); virDomainFree(ddom); virConnectClose(conn); virConnectClose(dconn); + + return s; +} + +static CMPI_THREAD_RETURN migration_thread(struct migration_job *job) +{ + CMPIStatus s; + + CBAttachThread(_BROKER, job->context); + + CU_DEBUG("Migration Job %s started", job->uuid); + migrate_job_set_state(job, CIM_JOBSTATE_RUNNING, "Running"); + + s = migrate_vs(job); + + CU_DEBUG("Migration Job %s finished: %i", job->uuid, s.rc); + if (s.rc != CMPI_RC_OK) + migrate_job_set_state(job, + CIM_JOBSTATE_COMPLETE, + CMGetCharPtr(s.msg)); + else + migrate_job_set_state(job, + CIM_JOBSTATE_COMPLETE, + "Completed"); + + free(job->domain); + free(job->host); + free(job->ref_cn); + free(job->ref_ns); + free(job); + + return NULL; +} + +static CMPIInstance *_migrate_job_new_instance(const char *cn, + const char *ns) +{ + CMPIObjectPath *op; + CMPIInstance *inst; + CMPIStatus s; + + op = CMNewObjectPath(_BROKER, ns, cn, &s); + if ((s.rc != CMPI_RC_OK) || (CMIsNullObject(op))) { + CU_DEBUG("Failed to create ref: %s:%s", ns, cn); + return NULL; + } + + inst = CMNewInstance(_BROKER, op, &s); + if ((s.rc != CMPI_RC_OK) || (CMIsNullObject(op))) { + CU_DEBUG("Failed to create instance from ref: %s", + CMGetCharPtr(CMObjectPathToString(op, NULL))); + return NULL; + } + + return inst; +} + +static CMPIStatus migrate_create_job_instance(const CMPIContext *context, + struct migration_job *job, + CMPIObjectPath **job_op) +{ + CMPIStatus s; + CMPIInstance *jobinst; + CMPIDateTime *start; + CMPIBoolean autodelete = true; + uint16_t state = CIM_JOBSTATE_STARTING; + + start = CMNewDateTime(_BROKER, &s); + if ((s.rc != CMPI_RC_OK) || CMIsNullObject(start)) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Failed to get job start time"); + goto out; + } + + jobinst = _migrate_job_new_instance("Virt_MigrationJob", + job->ref_ns); + if (jobinst == NULL) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Unable to get instance of MigrationJob"); + goto out; + } + + CMSetProperty(jobinst, "InstanceID", + (CMPIValue *)job->uuid, CMPI_chars); + CMSetProperty(jobinst, "Name", + (CMPIValue *)"Migration", CMPI_chars); + CMSetProperty(jobinst, "StartTime", + (CMPIValue *)&start, CMPI_dateTime); + CMSetProperty(jobinst, "JobState", + (CMPIValue *)&state, CMPI_uint16); + CMSetProperty(jobinst, "Status", + (CMPIValue *)"Queued", CMPI_chars); + CMSetProperty(jobinst, "DeleteOnCompletion", + (CMPIValue *)&autodelete, CMPI_boolean); + + *job_op = CMGetObjectPath(jobinst, &s); + if ((*job_op == NULL) || (s.rc != CMPI_RC_OK)) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Failed to get path for job instance"); + goto out; + } + + CMSetNameSpace(*job_op, job->ref_ns); + + CU_DEBUG("Creating instance: %s", + CMGetCharPtr(CMObjectPathToString(*job_op, NULL))); + + *job_op = CBCreateInstance(_BROKER, context, *job_op, jobinst, &s); + if ((s.rc != CMPI_RC_OK) || (CMIsNullObject(*job_op))) { + CU_DEBUG("Failed to create job instance: %i", s.rc); + goto out; + } + + out: + return s; +} + +static struct migration_job *migrate_job_prepare(const CMPIContext *context, + const CMPIObjectPath *ref, + const char *domain, + const char *host) +{ + struct migration_job *job; + uuid_t uuid; + + job = malloc(sizeof(*job)); + if (job == NULL) + return NULL; + + job->domain = strdup(domain); + job->host = strdup(host); + job->ref_cn = strdup(CLASSNAME(ref)); + job->ref_ns = strdup(NAMESPACE(ref)); + + uuid_generate(uuid); + uuid_unparse(uuid, job->uuid); + + job->context = CBPrepareAttachThread(_BROKER, context); + + return job; +} + +static CMPIStatus migrate_do(const CMPIObjectPath *ref, + const CMPIContext *context, + const char *domain, + const char *host, + const CMPIResult *results, + CMPIArgs *argsout) +{ + CMPIStatus s; + CMPIObjectPath *job_op; + struct migration_job *job; + CMPI_THREAD_TYPE thread; + uint32_t retcode = 1; + + job = migrate_job_prepare(context, ref, domain, host); + if (job == NULL) { + cu_statusf(_BROKER, &s, + CMPI_RC_ERR_FAILED, + "Unable to prepare migration job"); + goto out; + } + + CU_DEBUG("Prepared migration job %s", job->uuid); + + s = migrate_create_job_instance(context, job, &job_op); + if (s.rc != CMPI_RC_OK) + goto out; + + CMAddArg(argsout, "Job", (CMPIValue *)&job_op, CMPI_ref); + + thread = _BROKER->xft->newThread((void*)migration_thread, job, 0); + + retcode = 0; + + out: + CMReturnData(results, (CMPIValue *)&retcode, CMPI_uint32); return s; } @@ -323,15 +548,15 @@ static CMPIStatus migrate_vs_host(CMPIMe return s; } - return migrate_vs(ref, name, dhost, results); + return migrate_do(ref, ctx, name, dhost, results, argsout); } static CMPIStatus migrate_vs_system(CMPIMethodMI *self, - const CMPIContext *ctx, - const CMPIResult *results, - const CMPIObjectPath *ref, - const CMPIArgs *argsin, - CMPIArgs *argsout) + const CMPIContext *ctx, + const CMPIResult *results, + const CMPIObjectPath *ref, + const CMPIArgs *argsin, + CMPIArgs *argsout) { CMPIStatus s; CMPIObjectPath *dsys; @@ -358,7 +583,7 @@ static CMPIStatus migrate_vs_system(CMPI return s; } - return migrate_vs(ref, name, dname, results); + return migrate_do(ref, ctx, name, dname, results, argsout); } static struct method_handler vsimth = {

Dan Smith wrote:
This set adds job support to migration, so that the migration methods return immediately with a job reference. The progress of the migration can be monitored by looking at Virt_MigrationJob instances.
I left a good opening for indications (which will be necessary) by adding the migrate_job_set_state() function. This updates the state of the persistent job, which would be time(s) when we're looking to send an indication.
Right now, Jobs are left in the persistent store after they're complete. Comments about the best policy for handling this are welcome. I know that I should be able to put a lifetime on them so they expire after completion, but I'm not sure if that's something that should be left to the client.
I was finally able to test migration along with this patchset. Looks good. I didn't catch anything during the read through either. +1 -- Kaitlin Rupert IBM Linux Technology Center karupert@us.ibm.com
participants (2)
-
Dan Smith
-
Kaitlin Rupert