[Libvirt-cim] [PATCH 1 of 2] Add VirtualSystemSnapshotService

Dan Smith danms at us.ibm.com
Tue Feb 26 15:31:57 UTC 2008


# HG changeset patch
# User Dan Smith <danms at us.ibm.com>
# Date 1204039738 28800
# Node ID c173208c9c4c70d4ca736f31a19f278268e73971
# Parent  bb0530f50ea8d4a75ec34cd54f3bc2daebbda556
Add VirtualSystemSnapshotService

Signed-off-by: Dan Smith <danms at us.ibm.com>

diff -r bb0530f50ea8 -r c173208c9c4c src/Virt_VirtualSystemSnapshotService.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Virt_VirtualSystemSnapshotService.c	Tue Feb 26 07:28:58 2008 -0800
@@ -0,0 +1,508 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <uuid/uuid.h>
+
+#include <cmpidt.h>
+#include <cmpift.h>
+#include <cmpimacs.h>
+
+#include <libcmpiutil/libcmpiutil.h>
+#include <libcmpiutil/std_invokemethod.h>
+
+#include "misc_util.h"
+
+#define CIM_VSSS_SNAPSHOT_FULL 2
+#define CIM_VSSS_SNAPSHOT_DISK 3
+
+/* VIR_VSSS_SNAPSHOT_MEM  - Attempt to save/restore to create a running snap
+ * VIR_VSSS_SNAPSHOT_MEMT - Just save and let the domain be "off"
+ */
+#define VIR_VSSS_SNAPSHOT_MEM  32768
+#define VIR_VSSS_SNAPSHOT_MEMT 32769
+
+#define CIM_JOBSTATE_STARTING 3
+#define CIM_JOBSTATE_RUNNING 4
+#define CIM_JOBSTATE_COMPLETE 7
+
+static const CMPIBroker *_BROKER;
+
+struct snap_context {
+        CMPIContext *context;
+        char *domain;
+        char uuid[33];
+        char *save_path;
+        char *ref_ns;
+        char *ref_cn;
+
+        bool save;
+        bool restore;
+};
+
+static void snap_job_free(struct snap_context *ctx)
+{
+        free(ctx->domain);
+        free(ctx->save_path);
+        free(ctx->ref_ns);
+        free(ctx->ref_cn);
+        free(ctx);
+}
+
+static void snap_job_set_status(struct snap_context *ctx,
+                                uint16_t state,
+                                const char *status)
+{
+        CMPIInstance *inst;
+        CMPIStatus s;
+        CMPIObjectPath *op;
+
+        op = CMNewObjectPath(_BROKER,
+                             ctx->ref_ns,
+                             "CIM_ConcreteJob",
+                             &s);
+        if (s.rc != CMPI_RC_OK) {
+                CU_DEBUG("Failed to create job path for update");
+                return;
+        }
+
+        CMAddKey(op, "InstanceID", (CMPIValue *)ctx->uuid, CMPI_chars);
+
+        inst = CBGetInstance(_BROKER, ctx->context, op, NULL, &s);
+        if ((inst == NULL) || (s.rc != CMPI_RC_OK)) {
+                CU_DEBUG("Failed to get job instance for update of %s",
+                         ctx->uuid);
+                return;
+        }
+
+        CMSetProperty(inst, "JobState",
+                      (CMPIValue *)&state, CMPI_uint16);
+        CMSetProperty(inst, "Status",
+                      (CMPIValue *)status, CMPI_chars);
+
+        s = CBModifyInstance(_BROKER, ctx->context, op, inst, NULL);
+        if (s.rc != CMPI_RC_OK) {
+                CU_DEBUG("Failed to update job instance %s: %s",
+                         ctx->uuid,
+                         CMGetCharPtr(s.msg));
+                return;
+        }
+
+        CU_DEBUG("Set %s status to %i:%s", ctx->uuid, state, status);
+}
+
+static void do_snapshot(struct snap_context *ctx,
+                        virConnectPtr conn,
+                        virDomainPtr dom)
+{
+        int ret;
+
+        if (ctx->save) {
+                CU_DEBUG("Starting save to %s", ctx->save_path);
+
+                ret = virDomainSave(dom, ctx->save_path);
+                if (ret == -1) {
+                        CU_DEBUG("Save failed");
+                        snap_job_set_status(ctx,
+                                            CIM_JOBSTATE_COMPLETE,
+                                            "Snapshot Failed (save)");
+                        return;
+                }
+
+                CU_DEBUG("Save completed");
+                snap_job_set_status(ctx,
+                                    CIM_JOBSTATE_RUNNING,
+                                    "Save finished");
+        }
+
+        if (ctx->restore) {
+                CU_DEBUG("Starting restore from %s", ctx->save_path);
+
+                ret = virDomainRestore(conn, ctx->save_path);
+                if (ret == -1) {
+                        CU_DEBUG("Restore failed");
+                        snap_job_set_status(ctx,
+                                            CIM_JOBSTATE_COMPLETE,
+                                            "Snapshot Failed (restore)");
+                        return;
+                }
+
+                CU_DEBUG("Restore completed");
+                snap_job_set_status(ctx,
+                                    CIM_JOBSTATE_RUNNING,
+                                    "Restore finished");
+        }
+
+        CU_DEBUG("Snapshot (%s/%s) completed",
+                 ctx->save ? "Save" : "None",
+                 ctx->restore ? "Restore" : "None");
+
+        snap_job_set_status(ctx,
+                            CIM_JOBSTATE_COMPLETE,
+                            "Snapshot complete");
+
+        return;
+}
+
+static CMPI_THREAD_RETURN snapshot_thread(struct snap_context *ctx)
+{
+        CMPIStatus s;
+        virConnectPtr conn = NULL;
+        virDomainPtr dom = NULL;
+
+        CU_DEBUG("Snapshot thread alive");
+
+        CBAttachThread(_BROKER, ctx->context);
+
+        snap_job_set_status(ctx, CIM_JOBSTATE_RUNNING, "Running");
+
+        conn = connect_by_classname(_BROKER, ctx->ref_cn, &s);
+        if (conn == NULL) {
+                CU_DEBUG("Failed to connect with classname `%s'", ctx->ref_cn);
+                snap_job_set_status(ctx,
+                                    CIM_JOBSTATE_COMPLETE,
+                                    "Unable to connect to hypervisor");
+                goto out;
+        }
+
+        dom = virDomainLookupByName(conn, ctx->domain);
+        if (dom == NULL) {
+                CU_DEBUG("No such domain `%s'", ctx->domain);
+                snap_job_set_status(ctx,
+                                    CIM_JOBSTATE_COMPLETE,
+                                    "No such domain");
+                goto out;
+        }
+
+        do_snapshot(ctx, conn, dom);
+
+ out:
+        virDomainFree(dom);
+        virConnectClose(conn);
+
+        snap_job_free(ctx);
+
+        return NULL;
+}
+
+static CMPIStatus create_job(const CMPIContext *context,
+                             const CMPIObjectPath *ref,
+                             struct snap_context *ctx,
+                             CMPIObjectPath **job)
+{
+        CMPIObjectPath *op;
+        CMPIInstance *inst;
+        CMPIStatus s;
+
+        op = CMNewObjectPath(_BROKER,
+                             NAMESPACE(ref),
+                             "CIM_ConcreteJob", /*FIXME*/
+                             &s);
+        if ((s.rc != CMPI_RC_OK) || (op == NULL)) {
+                CU_DEBUG("Failed to create job path");
+                goto out;
+        }
+
+        CMSetNameSpace(op, NAMESPACE(ref));
+
+        inst = CMNewInstance(_BROKER, op, &s);
+        if ((s.rc != CMPI_RC_OK) || (inst == NULL)) {
+                CU_DEBUG("Failed to create job instance");
+                goto out;
+        }
+
+        CMSetProperty(inst, "InstanceID",
+                      (CMPIValue *)ctx->uuid, CMPI_chars);
+
+        CMSetProperty(inst, "Name",
+                      (CMPIValue *)"Snapshot", CMPI_chars);
+
+        CMSetProperty(inst, "Status",
+                      (CMPIValue *)"Queued", CMPI_chars);
+
+        op = CMGetObjectPath(inst, &s);
+        if ((op == NULL) || (s.rc != CMPI_RC_OK)) {
+                CU_DEBUG("Failed to get path of job instance");
+                goto out;
+        }
+
+        CMSetNameSpace(op, NAMESPACE(ref));
+
+        CU_DEBUG("ref was %s", CMGetCharPtr(CMObjectPathToString(op, NULL)));
+
+        *job = CBCreateInstance(_BROKER, context, op, inst, &s);
+        if ((*job == NULL) || (s.rc != CMPI_RC_OK)) {
+                CU_DEBUG("Failed to create job");
+                goto out;
+        }
+
+        ctx->ref_ns = strdup(NAMESPACE(ref));
+        ctx->ref_cn = strdup(CLASSNAME(ref));
+
+        ctx->context = CBPrepareAttachThread(_BROKER, context);
+
+        _BROKER->xft->newThread((void *)snapshot_thread, ctx, 0);
+
+        cu_statusf(_BROKER, &s,
+                   CMPI_RC_OK,
+                   "");
+ out:
+        return s;
+}
+
+static char *get_save_path(const char *domname)
+{
+        int ret;
+        char *path = NULL;
+
+        ret = asprintf(&path,
+                       "/var/lib/libvirt/%s.save", domname);
+        if (ret == -1)
+                return NULL;
+
+        return path;
+}
+
+static struct snap_context *new_context(const char *name,
+                                        CMPIStatus *s)
+{
+        struct snap_context *ctx;
+        uuid_t uuid;
+
+        ctx = calloc(1, sizeof(*ctx));
+        if (ctx == NULL) {
+                CU_DEBUG("Failed to alloc snapshot context");
+                goto out;
+        }
+
+        ctx->domain = strdup(name);
+
+        uuid_generate(uuid);
+        uuid_unparse(uuid, ctx->uuid);
+
+        ctx->save_path = get_save_path(ctx->domain);
+        if (ctx->save_path == NULL) {
+                cu_statusf(_BROKER, s,
+                           CMPI_RC_ERR_FAILED,
+                           "Unable to get save_path");
+                goto out;
+        }
+
+        cu_statusf(_BROKER, s,
+                   CMPI_RC_OK,
+                   "");
+ out:
+        if (s->rc != CMPI_RC_OK) {
+                snap_job_free(ctx);
+                ctx = NULL;
+        }
+
+        return ctx;
+}
+
+static CMPIStatus start_snapshot_job(const CMPIObjectPath *ref,
+                                     const CMPIContext *context,
+                                     const char *name,
+                                     uint16_t type)
+{
+        struct snap_context *ctx;
+        CMPIStatus s;
+        CMPIObjectPath *job;
+
+        ctx = new_context(name, &s);
+        if (ctx == NULL)
+                goto out;
+
+        ctx->save = (type != 0);
+        ctx->restore = (type != VIR_VSSS_SNAPSHOT_MEM);
+
+        s = create_job(context, ref, ctx, &job);
+
+ out:
+        return s;
+}
+
+static CMPIStatus create_snapshot(CMPIMethodMI *self,
+                                  const CMPIContext *context,
+                                  const CMPIResult *results,
+                                  const CMPIObjectPath *reference,
+                                  const CMPIArgs *argsin,
+                                  CMPIArgs *argsout)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        CMPIObjectPath *system;
+        CMPIInstance *sd;
+        uint16_t type;
+        uint32_t retcode = 0;
+        const char *name;
+
+        if (cu_get_u16_arg(argsin, "SnapshotType", &type) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                           CMPI_RC_ERR_INVALID_PARAMETER,
+                           "Missing SnapshotType");
+                goto out;
+        }
+
+        if ((type != VIR_VSSS_SNAPSHOT_MEM) &&
+            (type != VIR_VSSS_SNAPSHOT_MEMT)) {
+                cu_statusf(_BROKER, &s,
+                           CMPI_RC_ERR_NOT_SUPPORTED,
+                           "Only memory(%i,%i) snapshots are supported",
+                           VIR_VSSS_SNAPSHOT_MEM,
+                           VIR_VSSS_SNAPSHOT_MEMT);
+                goto out;
+        }
+
+        if (cu_get_ref_arg(argsin, "AffectedSystem", &system) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                           CMPI_RC_ERR_INVALID_PARAMETER,
+                           "Missing AffectedSystem");
+                goto out;
+        }
+
+        if (cu_get_inst_arg(argsin, "SnapshotSettings", &sd) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                           CMPI_RC_ERR_INVALID_PARAMETER,
+                           "Missing SnapshotSettings");
+                goto out;
+        }
+
+        if (cu_get_str_path(system, "Name", &name) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                           CMPI_RC_ERR_INVALID_PARAMETER,
+                           "Missing Name property of AffectedSystem");
+                goto out;
+        }
+
+        s = start_snapshot_job(reference, context, name, type);
+
+        CMReturnData(results, (CMPIValue *)&retcode, CMPI_uint32);
+ out:
+        CU_DEBUG("Returning: %i", s.rc);
+        return s;
+}
+
+static CMPIStatus destroy_snapshot(CMPIMethodMI *self,
+                                   const CMPIContext *context,
+                                   const CMPIResult *results,
+                                   const CMPIObjectPath *reference,
+                                   const CMPIArgs *argsin,
+                                   CMPIArgs *argsout)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        CMPIObjectPath *snap;
+        char *name = NULL;
+        char *path = NULL;
+
+        if (cu_get_ref_arg(argsin, "AffectedSnapshot", &snap) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                           CMPI_RC_ERR_INVALID_PARAMETER,
+                           "Missing Snapshot");
+                goto out;
+        }
+
+        if (!parse_instanceid(snap, NULL, &name)) {
+                cu_statusf(_BROKER, &s,
+                           CMPI_RC_ERR_FAILED,
+                           "Invalid InstanceID in Snapshot");
+                goto out;
+        }
+
+        path = get_save_path(name);
+        if (path == NULL) {
+                cu_statusf(_BROKER, &s,
+                           CMPI_RC_ERR_FAILED,
+                           "Unable to get save_path");
+                goto out;
+        }
+
+        if (unlink(path) == -1) {
+                cu_statusf(_BROKER, &s,
+                           CMPI_RC_ERR_FAILED,
+                           "Unable to remove snapshot: %s", path);
+        }
+ out:
+        free(path);
+        free(name);
+
+        return s;
+}
+
+static CMPIStatus apply_snapshot(CMPIMethodMI *self,
+                                 const CMPIContext *context,
+                                 const CMPIResult *results,
+                                 const CMPIObjectPath *reference,
+                                 const CMPIArgs *argsin,
+                                 CMPIArgs *argsout)
+{
+        CMPIStatus s = {CMPI_RC_OK, NULL};
+        CMPIObjectPath *snap;
+        char *name = NULL;
+
+        if (cu_get_ref_arg(argsin, "AffectedSnapshot", &snap) != CMPI_RC_OK) {
+                cu_statusf(_BROKER, &s,
+                           CMPI_RC_ERR_INVALID_PARAMETER,
+                           "Missing Snapshot");
+                goto out;
+        }
+
+        if (!parse_instanceid(snap, NULL, &name)) {
+                cu_statusf(_BROKER, &s,
+                           CMPI_RC_ERR_FAILED,
+                           "Invalid InstanceID in Snapshot");
+                goto out;
+        }
+
+        s = start_snapshot_job(reference, context, name, 0);
+
+ out:
+        free(name);
+
+        return s;
+}
+
+static struct method_handler CreateSnapshot = {
+        .name = "CreateSnapshot",
+        .handler = create_snapshot,
+        .args = {{"AffectedSystem", CMPI_ref, false},
+                 {"SnapshotSettings", CMPI_instance, false},
+                 {"SnapshotType", CMPI_uint16, false},
+                 ARG_END}
+};
+
+static struct method_handler DestroySnapshot = {
+        .name = "DestroySnapshot",
+        .handler = destroy_snapshot,
+        .args = {{"AffectedSnapshot", CMPI_ref, false},
+                 ARG_END}
+};
+
+static struct method_handler ApplySnapshot = {
+        .name = "ApplySnapshot",
+        .handler = apply_snapshot,
+        .args = {{"AffectedSnapshot", CMPI_ref, false},
+                 ARG_END}
+};
+
+static struct method_handler *handlers[] = {
+        &CreateSnapshot,
+        &DestroySnapshot,
+        &ApplySnapshot,
+        NULL
+};
+
+STDIM_MethodMIStub(, Virt_VirtualSystemSnapshotService,
+                   _BROKER, libvirt_cim_init(), handlers);
+
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-set-style: "K&R"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * indent-tabs-mode: nil
+ * End:
+ */




More information about the Libvirt-cim mailing list