# HG changeset patch
# User Dan Smith <danms(a)us.ibm.com>
# Date 1204053596 28800
# Node ID fce1a31a53090b42dbfbd788a6db2a1164636197
# Parent bb0530f50ea8d4a75ec34cd54f3bc2daebbda556
Add VirtualSystemSnapshotService
Changes:
- Added header block
Signed-off-by: Dan Smith <danms(a)us.ibm.com>
diff -r bb0530f50ea8 -r fce1a31a5309 src/Virt_VirtualSystemSnapshotService.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Virt_VirtualSystemSnapshotService.c Tue Feb 26 11:19:56 2008 -0800
@@ -0,0 +1,521 @@
+/*
+ * Copyright IBM Corp. 2007
+ *
+ * Authors:
+ * Dan Smith <danms(a)us.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#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"
+
+#include "Virt_VirtualSystemSnapshotService.h"
+
+#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;
+}
+
+char *vsss_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:
+ */
diff -r bb0530f50ea8 -r fce1a31a5309 src/Virt_VirtualSystemSnapshotService.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Virt_VirtualSystemSnapshotService.h Tue Feb 26 11:19:56 2008 -0800
@@ -0,0 +1,42 @@
+/*
+ * Copyright IBM Corp. 2007
+ *
+ * Authors:
+ * Dan Smith <danms(a)us.ibm.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* Returns a malloc()'d string; caller must free() */
+char *vsss_get_save_path(const char *domname);
+
+#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
+
+/*
+ * Local Variables:
+ * mode: C
+ * c-set-style: "K&R"
+ * tab-width: 8
+ * c-basic-offset: 8
+ * indent-tabs-mode: nil
+ * End:
+ */