summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRajesh Joseph <rjoseph@redhat.com>2014-05-05 13:37:34 +0530
committerVijay Bellur <vbellur@redhat.com>2014-07-12 09:50:25 -0700
commit656e6b38189d14c440a46d4d69b5ddfc5d8cfffc (patch)
tree6c8b5c8125258816b18e79cd0e342014892d4cbe
parent99685f18f190a73f2a46478cac0b09f4c59834b1 (diff)
cli/snapshot: provide --xml support for all snapshot command
Now --xml option can be used with all snapshot command. It will form the cli output in xml form. Change-Id: Ifc0ac31d2a9f91e136e87f3b51a629df7dba94e8 BUG: 1096610 Signed-off-by: Rajesh Joseph <rjoseph@redhat.com> Reviewed-on: http://review.gluster.org/7663 Reviewed-by: Sachin Pandit <spandit@redhat.com> Reviewed-by: Vijaikumar Mallikarjuna <vmallika@redhat.com> Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Vijay Bellur <vbellur@redhat.com>
-rw-r--r--cli/src/cli-rpc-ops.c170
-rw-r--r--cli/src/cli-xml-output.c1464
-rw-r--r--cli/src/cli.h11
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-snapshot.c86
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-utils.c13
5 files changed, 1679 insertions, 65 deletions
diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c
index 43db8358bcf..0575440e486 100644
--- a/cli/src/cli-rpc-ops.c
+++ b/cli/src/cli-rpc-ops.c
@@ -8105,9 +8105,9 @@ cli_call_snapshot_info (dict_t *dict, gf_boolean_t bool_snap_driven) {
GF_ASSERT (dict);
- ret = dict_get_int32 (dict, "snap-count", &snap_count);
+ ret = dict_get_int32 (dict, "snapcount", &snap_count);
if (ret) {
- gf_log ("cli", GF_LOG_ERROR, "Unable to get snap-count");
+ gf_log ("cli", GF_LOG_ERROR, "Unable to get snapcount");
goto out;
}
@@ -8149,9 +8149,9 @@ cli_get_snaps_in_volume (dict_t *dict) {
}
cli_out (INDENT_MAIN_HEAD "%s", "Volume Name", ":", get_buffer);
- ret = dict_get_int32 (dict, "snap-count", &avail);
+ ret = dict_get_int32 (dict, "snapcount", &avail);
if (ret) {
- gf_log ("cli", GF_LOG_ERROR, "Could not fetch snap-count");
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch snapcount");
goto out;
}
cli_out (INDENT_MAIN_HEAD "%d", "Snaps Taken", ":", avail);
@@ -8199,7 +8199,7 @@ cli_snapshot_list (dict_t *dict) {
GF_ASSERT (dict);
- ret = dict_get_int32 (dict, "snap-count", &snapcount);
+ ret = dict_get_int32 (dict, "snapcount", &snapcount);
if (ret) {
gf_log ("cli", GF_LOG_ERROR, "Could not fetch snap count");
goto out;
@@ -8527,11 +8527,22 @@ cli_snapshot_status (dict_t *dict, gf_cli_rsp *rsp,
goto out;
}
- ret = cli_get_single_snap_status (dict, key);
- if (ret) {
- gf_log ("cli", GF_LOG_ERROR, "Could not fetch "
- "status of snap");
- goto out;
+ if (global_state->mode & GLUSTER_MODE_XML) {
+ ret = cli_xml_snapshot_status_per_snap (local->writer,
+ local->doc,
+ dict, key);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to create "
+ "xml output for snapshot status");
+ goto out;
+ }
+ } else {
+ ret = cli_get_single_snap_status (dict, key);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch "
+ "status of snap");
+ goto out;
+ }
}
ret = 0;
@@ -8585,6 +8596,18 @@ gf_cli_snapshot_cbk (struct rpc_req *req, struct iovec *iov,
goto out;
}
+ /* Snapshot status command is handled separately */
+ if (global_state->mode & GLUSTER_MODE_XML &&
+ GF_SNAP_OPTION_TYPE_STATUS != type) {
+ ret = cli_xml_output_snapshot (type, dict, rsp.op_ret,
+ rsp.op_errno, rsp.op_errstr);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Error outputting to xml");
+ }
+
+ goto out;
+ }
+
switch (type) {
case GF_SNAP_OPTION_TYPE_CREATE:
if (rsp.op_ret) {
@@ -8801,72 +8824,80 @@ gf_cli_snapshot_for_status (call_frame_t *frame, xlator_t *this,
int snapcount = 0;
int i = 0;
- if (!frame || !this || !data)
+ GF_VALIDATE_OR_GOTO ("cli", frame, out);
+ GF_VALIDATE_OR_GOTO ("cli", frame->local, out);
+ GF_VALIDATE_OR_GOTO ("cli", this, out);
+ GF_VALIDATE_OR_GOTO ("cli", data, out);
+
+ local = frame->local;
+ options = data;
+
+ ret = dict_get_int32 (local->dict, "status-cmd", &cmd);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get status-cmd");
goto out;
+ }
- if (frame->local) {
- local = frame->local;
- } else {
+ /* Snapshot status of single snap (i.e. GF_SNAP_STATUS_TYPE_SNAP)
+ * is already handled. Therefore we can return from here.
+ * If want to get status of all snaps in the system or volume then
+ * we should get them one by one.*/
+ if (cmd == GF_SNAP_STATUS_TYPE_SNAP) {
+ ret = 0;
goto out;
}
- options = data;
+ ret = dict_get_int32 (local->dict, "status.snapcount", &snapcount);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not get snapcount");
+ goto out;
+ }
- ret = dict_get_int32 (local->dict, "status-cmd", &cmd);
+ if (snapcount == 0) {
+ cli_out ("No snapshots present");
+ }
- if (cmd == GF_SNAP_STATUS_TYPE_ALL ||
- cmd == GF_SNAP_STATUS_TYPE_VOL) {
+ for (i = 0 ; i < snapcount; i++) {
+ ret = -1;
- ret = dict_get_int32 (local->dict, "status.snapcount",
- &snapcount);
- if (ret) {
- gf_log ("cli", GF_LOG_ERROR, "Could not get snapcount");
+ snap_dict = dict_new();
+ if (!snap_dict)
goto out;
- }
- if (snapcount == 0) {
- cli_out ("No snapshots present");
+ ret = cli_populate_req_dict_for_status (snap_dict,
+ local->dict, i);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not "
+ "populate snap request dictionary");
+ goto out;
}
- for (i = 0 ; i < snapcount; i++) {
- ret = -1;
-
- snap_dict = dict_new();
- if (!snap_dict)
- goto out;
+ ret = cli_to_glusterd (&req, frame,
+ gf_cli_snapshot_cbk,
+ (xdrproc_t) xdr_gf_cli_req, snap_dict,
+ GLUSTER_CLI_SNAP, this, cli_rpc_prog,
+ NULL);
- ret = cli_populate_req_dict_for_status (snap_dict,
- local->dict, i);
- if (ret) {
- gf_log ("cli", GF_LOG_ERROR, "Could not "
- "populate snap request dictionary");
- goto out;
- }
-
- ret = cli_to_glusterd (&req, frame,
- gf_cli_snapshot_cbk,
- (xdrproc_t) xdr_gf_cli_req, snap_dict,
- GLUSTER_CLI_SNAP, this, cli_rpc_prog,
- NULL);
-
- /* Ignore the return value and error for snapshot
- * status of type "ALL" or "VOL"
- *
- * Scenario : There might be case where status command
- * and delete command might be issued at the same time.
- * In that case when status tried to fetch detail of
- * snap which has been deleted by concurrent command,
- * then it will show snapshot not present. Which will
- * not be appropriate.
- */
- dict_unref (snap_dict);
- }
+ /* Ignore the return value and error for snapshot
+ * status of type "ALL" or "VOL"
+ *
+ * Scenario : There might be case where status command
+ * and delete command might be issued at the same time.
+ * In that case when status tried to fetch detail of
+ * snap which has been deleted by concurrent command,
+ * then it will show snapshot not present. Which will
+ * not be appropriate.
+ */
+ dict_unref (snap_dict);
+ snap_dict = NULL;
}
-out:
- return ret;
- if (ret && snap_dict)
+ ret = 0;
+out:
+ if (snap_dict)
dict_unref (snap_dict);
+
+ return ret;
}
int32_t
@@ -8894,6 +8925,16 @@ gf_cli_snapshot (call_frame_t *frame, xlator_t *this,
ret = dict_get_int32 (local->dict, "type", &type);
+ if (GF_SNAP_OPTION_TYPE_STATUS == type &&
+ global_state->mode & GLUSTER_MODE_XML) {
+ ret = cli_xml_output_snap_status_begin (local, 0, 0, NULL);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Error creating xml "
+ "output");
+ goto out;
+ }
+ }
+
ret = cli_to_glusterd (&req, frame, gf_cli_snapshot_cbk,
(xdrproc_t) xdr_gf_cli_req, options,
@@ -8912,6 +8953,15 @@ gf_cli_snapshot (call_frame_t *frame, xlator_t *this,
"for snapshot status command failed");
goto out;
}
+
+ if (global_state->mode & GLUSTER_MODE_XML) {
+ ret = cli_xml_output_snap_status_end (local);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Error creating "
+ "xml output");
+ goto out;
+ }
+ }
}
ret = 0;
diff --git a/cli/src/cli-xml-output.c b/cli/src/cli-xml-output.c
index 1bf4e874647..dd38a51c6c0 100644
--- a/cli/src/cli-xml-output.c
+++ b/cli/src/cli-xml-output.c
@@ -3853,3 +3853,1467 @@ out:
return 0;
#endif
}
+
+#if (HAVE_LIB_XML)
+/* This function will generate snapshot create output in xml format.
+ *
+ * @param writer xmlTextWriterPtr
+ * @param doc xmlDocPtr
+ * @param dict dict containing create output
+ *
+ * @return 0 on success and -1 on failure
+ */
+static int
+cli_xml_snapshot_create (xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
+{
+ int ret = -1;
+ char *str_value = NULL;
+
+ GF_ASSERT (writer);
+ GF_ASSERT (doc);
+ GF_ASSERT (dict);
+
+ /* <snapCreate> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"snapCreate");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* <snapshot> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"snapshot");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = dict_get_str (dict, "snapname", &str_value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get snap name");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "name",
+ "%s", str_value);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = dict_get_str (dict, "snapuuid", &str_value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get snap uuid");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "uuid",
+ "%s", str_value);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* </snapshot> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* </snapCreate> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = 0;
+out:
+ return ret;
+}
+
+/* This function will generate snapshot delete output in xml format.
+ *
+ * @param writer xmlTextWriterPtr
+ * @param doc xmlDocPtr
+ * @param dict dict containing delete output
+ *
+ * @return 0 on success and -1 on failure
+ */
+static int
+cli_xml_snapshot_delete (xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
+{
+ int ret = -1;
+ char *str_value = NULL;
+
+ GF_ASSERT (writer);
+ GF_ASSERT (doc);
+ GF_ASSERT (dict);
+
+ /* <snapDelete> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"snapDelete");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* <snapshot> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"snapshot");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = dict_get_str (dict, "snapname", &str_value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get snap name");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "name",
+ "%s", str_value);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = dict_get_str (dict, "snapuuid", &str_value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get snap uuid");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "uuid",
+ "%s", str_value);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* </snapshot> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* </snapDelete> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = 0;
+out:
+
+ return ret;
+}
+
+/* This function will generate snapshot restore output in xml format.
+ *
+ * @param writer xmlTextWriterPtr
+ * @param doc xmlDocPtr
+ * @param dict dict containing restore output
+ *
+ * @return 0 on success and -1 on failure
+ */
+static int
+cli_xml_snapshot_restore (xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
+{
+ int ret = -1;
+ char *str_value = NULL;
+
+ GF_ASSERT (writer);
+ GF_ASSERT (doc);
+ GF_ASSERT (dict);
+
+ /* <snapRestore> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"snapRestore");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* <volume> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"volume");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = dict_get_str (dict, "volname", &str_value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get vol name");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "name",
+ "%s", str_value);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = dict_get_str (dict, "volid", &str_value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get volume id");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "uuid",
+ "%s", str_value);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* </volume> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+
+ /* <snapshot> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"snapshot");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = dict_get_str (dict, "snapname", &str_value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get snap name");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "name",
+ "%s", str_value);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = dict_get_str (dict, "snapuuid", &str_value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get snap uuid");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "uuid",
+ "%s", str_value);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* </snapshot> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* </snapRestore> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = 0;
+out:
+
+ return ret;
+}
+
+/* This function will generate snapshot list output in xml format.
+ *
+ * @param writer xmlTextWriterPtr
+ * @param doc xmlDocPtr
+ * @param dict dict containing list output
+ *
+ * @return 0 on success and -1 on failure
+ */
+static int
+cli_xml_snapshot_list (xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
+{
+ int ret = -1;
+ int i = 0;
+ int snapcount = 0;
+ char *str_value = NULL;
+ char key[PATH_MAX] = "";
+
+ GF_ASSERT (writer);
+ GF_ASSERT (doc);
+ GF_ASSERT (dict);
+
+ /* <snapList> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"snapList");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = dict_get_int32 (dict, "snapcount", &snapcount);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get snapcount");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "count",
+ "%d", snapcount);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ for (i = 1; i <= snapcount; ++i) {
+ ret = snprintf (key, sizeof (key), "snapname%d", i);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = dict_get_str (dict, key, &str_value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not get %s ", key);
+ goto out;
+ } else {
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *)"snapshot", "%s", str_value);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+ }
+ }
+
+ /* </snapList> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = 0;
+out:
+
+ return ret;
+}
+
+/* This function will generate xml output for origin volume
+ * of the given snapshot.
+ *
+ * @param writer xmlTextWriterPtr
+ * @param doc xmlDocPtr
+ * @param dict dict containing info output
+ * @param keyprefix prefix for dictionary key
+ *
+ * @return 0 on success and -1 on failure
+ */
+static int
+cli_xml_snapshot_info_orig_vol (xmlTextWriterPtr writer, xmlDocPtr doc,
+ dict_t *dict, char *keyprefix)
+{
+ int ret = -1;
+ int value = 0;
+ char *buffer = NULL;
+ char key [PATH_MAX] = "";
+
+ GF_ASSERT (dict);
+ GF_ASSERT (keyprefix);
+ GF_ASSERT (writer);
+ GF_ASSERT (doc);
+
+ /* <originVolume> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"originVolume");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (key, sizeof (key), "%sorigin-volname", keyprefix);
+
+ ret = dict_get_str (dict, key, &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_WARNING, "Failed to get %s", key);
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "name",
+ "%s", buffer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (key, sizeof (key), "%ssnapcount", keyprefix);
+
+ ret = dict_get_int32 (dict, key, &value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get %s", key);
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "snapCount",
+ "%d", value);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (key, sizeof (key), "%ssnaps-available", keyprefix);
+
+ ret = dict_get_int32 (dict, key, &value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get %s", key);
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "snapRemaining", "%d", value);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* </originVolume> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = 0;
+out:
+ return ret;
+}
+
+/* This function will generate xml output of snapshot volume info.
+ *
+ * @param writer xmlTextWriterPtr
+ * @param doc xmlDocPtr
+ * @param dict dict containing info output
+ * @param keyprefix key prefix for dictionary
+ * @param snap_driven boolean to check if output is based of volume
+ * or snapshot
+ *
+ * @return 0 on success and -1 on failure
+ */
+static int
+cli_xml_snapshot_info_snap_vol (xmlTextWriterPtr writer, xmlDocPtr doc,
+ dict_t *dict, char *keyprefix,
+ gf_boolean_t snap_driven)
+{
+ char key [PATH_MAX] = "";
+ char *buffer = NULL;
+ int value = 0;
+ int ret = -1;
+
+ GF_ASSERT (dict);
+ GF_ASSERT (keyprefix);
+ GF_ASSERT (writer);
+ GF_ASSERT (doc);
+
+ /* <snapVolume> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"snapVolume");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (key, sizeof (key), "%s.volname", keyprefix);
+
+ ret = dict_get_str (dict, key, &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get %s", key);
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "name",
+ "%s", buffer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (key, sizeof (key), "%s.vol-status", keyprefix);
+
+ ret = dict_get_str (dict, key, &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get %s", key);
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "status",
+ "%s", buffer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* If the command is snap_driven then we need to show origin volume
+ * info. Else this is shown in the start of info display.*/
+ if (snap_driven) {
+ snprintf (key, sizeof (key), "%s.", keyprefix);
+ ret = cli_xml_snapshot_info_orig_vol (writer, doc, dict, key);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to create "
+ "xml output for snapshot's origin volume");
+ goto out;
+ }
+ }
+
+ /* </snapVolume> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = 0;
+out:
+ return ret;
+}
+
+/* This function will generate snapshot info of individual snapshot
+ * in xml format.
+ *
+ * @param writer xmlTextWriterPtr
+ * @param doc xmlDocPtr
+ * @param dict dict containing info output
+ * @param keyprefix key prefix for dictionary
+ * @param snap_driven boolean to check if output is based of volume
+ * or snapshot
+ *
+ * @return 0 on success and -1 on failure
+ */
+static int
+cli_xml_snapshot_info_per_snap (xmlTextWriterPtr writer, xmlDocPtr doc,
+ dict_t *dict, char *keyprefix,
+ gf_boolean_t snap_driven)
+{
+ char key_buffer[PATH_MAX] = "";
+ char *buffer = NULL;
+ int volcount = 0;
+ int ret = -1;
+ int i = 0;
+
+ GF_ASSERT (dict);
+ GF_ASSERT (keyprefix);
+ GF_ASSERT (writer);
+ GF_ASSERT (doc);
+
+ /* <snapshot> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"snapshot");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (key_buffer, sizeof (key_buffer), "%s.snapname",
+ keyprefix);
+
+ ret = dict_get_str (dict, key_buffer, &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to fetch snapname %s ",
+ key_buffer);
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "name",
+ "%s", buffer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (key_buffer, sizeof (key_buffer), "%s.snap-id", keyprefix);
+
+ ret = dict_get_str (dict, key_buffer, &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to fetch snap-id %s ",
+ key_buffer);
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "uuid",
+ "%s", buffer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (key_buffer, sizeof (key_buffer), "%s.snap-desc", keyprefix);
+
+ ret = dict_get_str (dict, key_buffer, &buffer);
+ if (!ret) {
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "description",
+ "%s", buffer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+ }
+
+ snprintf (key_buffer, sizeof (key_buffer), "%s.snap-time", keyprefix);
+
+ ret = dict_get_str (dict, key_buffer, &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to fetch snap-time %s ",
+ keyprefix);
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "createTime",
+ "%s", buffer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (key_buffer, sizeof (key_buffer), "%s.vol-count", keyprefix);
+ ret = dict_get_int32 (dict, key_buffer, &volcount);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Fail to get snap vol count");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "volCount",
+ "%d", volcount);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = dict_get_int32 (dict, key_buffer, &volcount);
+ /* Display info of each snapshot volume */
+ for (i = 1 ; i <= volcount ; i++) {
+ snprintf (key_buffer, sizeof (key_buffer), "%s.vol%d",
+ keyprefix, i);
+
+ ret = cli_xml_snapshot_info_snap_vol (writer, doc, dict,
+ key_buffer, snap_driven);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not list "
+ "details of volume in a snap");
+ goto out;
+ }
+ }
+
+ /* </snapshot> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+out:
+ return ret;
+}
+
+/* This function will generate snapshot info output in xml format.
+ *
+ * @param writer xmlTextWriterPtr
+ * @param doc xmlDocPtr
+ * @param dict dict containing info output
+ *
+ * @return 0 on success and -1 on failure
+ */
+static int
+cli_xml_snapshot_info (xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
+{
+ int ret = -1;
+ int i = 0;
+ int snapcount = 0;
+ char key [PATH_MAX] = "";
+ char *str_value = NULL;
+ gf_boolean_t snap_driven = _gf_false;
+
+ GF_ASSERT (writer);
+ GF_ASSERT (doc);
+ GF_ASSERT (dict);
+
+ /* <snapInfo> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"snapInfo");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snap_driven = dict_get_str_boolean (dict, "snap-driven", _gf_false);
+
+ /* If the approach is volume based then we should display orgin volume
+ * information first followed by per snap info*/
+ if (!snap_driven) {
+ ret = cli_xml_snapshot_info_orig_vol (writer, doc, dict, "");
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to create "
+ "xml output for snapshot's origin volume");
+ goto out;
+ }
+ }
+
+ ret = dict_get_int32 (dict, "snapcount", &snapcount);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get snapcount");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "count",
+ "%d", snapcount);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* <snapshots> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"snapshots");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* Get snapshot info of individual snapshots */
+ for (i = 1; i <= snapcount; ++i) {
+ snprintf (key, sizeof (key), "snap%d", i);
+
+ ret = cli_xml_snapshot_info_per_snap (writer, doc, dict,
+ key, snap_driven);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not get %s ", key);
+ goto out;
+ }
+ }
+
+ /* </snapshots> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* </snapInfo> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = 0;
+out:
+
+ return ret;
+}
+
+/* This function will generate snapshot status of individual
+ * snapshot volume in xml format.
+ *
+ * @param writer xmlTextWriterPtr
+ * @param doc xmlDocPtr
+ * @param dict dict containing status output
+ * @param keyprefix key prefix for dictionary
+ *
+ * @return 0 on success and -1 on failure
+ */
+static int
+cli_xml_snapshot_volume_status (xmlTextWriterPtr writer, xmlDocPtr doc,
+ dict_t *dict, const char *keyprefix)
+{
+ int ret = -1;
+ int brickcount = 0;
+ int i = 0;
+ int value = 0;
+ int pid = 0;
+ char *buffer = NULL;
+ char key[PATH_MAX] = "";
+
+ GF_ASSERT (writer);
+ GF_ASSERT (doc);
+ GF_ASSERT (dict);
+ GF_ASSERT (keyprefix);
+
+ snprintf (key, sizeof (key), "%s.brickcount", keyprefix);
+
+ ret = dict_get_int32 (dict, key, &brickcount);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to fetch brickcount");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "brickCount",
+ "%d", brickcount);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* Get status of every brick belonging to the snapshot volume */
+ for (i = 0 ; i < brickcount ; i++) {
+ /* <snapInfo> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"brick");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (key, sizeof (key), "%s.brick%d.path", keyprefix, i);
+
+ ret = dict_get_str (dict, key, &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_INFO, "Unable to get Brick Path");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "path", "%s", buffer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (key, sizeof (key), "%s.brick%d.vgname",
+ keyprefix, i);
+
+ ret = dict_get_str (dict, key, &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_INFO,
+ "Unable to get Volume Group");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "volumeGroup",
+ "%s", buffer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (key, sizeof (key), "%s.brick%d.status", keyprefix, i);
+
+ ret = dict_get_str (dict, key, &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR,
+ "Unable to get Brick Running");
+ goto out;
+ }
+
+ snprintf (key, sizeof (key), "%s.brick%d.pid", keyprefix, i);
+
+ ret = dict_get_int32 (dict, key, &pid);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to get pid");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "pid", "%d", pid);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (key, sizeof (key), "%s.brick%d.data", keyprefix, i);
+
+ ret = dict_get_str (dict, key, &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR,
+ "Unable to get Data Percent");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "lvUsage",
+ "%s", buffer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (key, sizeof (key), "%s.brick%d.lvsize",
+ keyprefix, i);
+ ret = dict_get_str (dict, key, &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_INFO, "Unable to get LV Size");
+ goto out;
+ }
+
+ /* Truncate any newline character */
+ buffer = strtok (buffer, "\n");
+
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "lvSize",
+ "%s", buffer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* </brick> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+ }
+
+out:
+ return ret;
+}
+
+/* This function will generate snapshot status of individual
+ * snapshot in xml format.
+ *
+ * @param writer xmlTextWriterPtr
+ * @param doc xmlDocPtr
+ * @param dict dict containing status output
+ *
+ * @return 0 on success and -1 on failure
+ */
+int
+cli_xml_snapshot_status_per_snap (xmlTextWriterPtr writer, xmlDocPtr doc,
+ dict_t *dict, const char *keyprefix)
+{
+ int ret = -1;
+ int snapcount = 0;
+ int volcount = 0;
+ int i = 0;
+ char *buffer = NULL;
+ char key [PATH_MAX] = "";
+
+ GF_ASSERT (writer);
+ GF_ASSERT (doc);
+ GF_ASSERT (dict);
+ GF_ASSERT (keyprefix);
+
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"snapshot");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (key, sizeof (key), "%s.snapname", keyprefix);
+
+ ret = dict_get_str (dict, key, &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to get snapname");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "name",
+ "%s", buffer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (key, sizeof (key), "%s.uuid", keyprefix);
+
+ ret = dict_get_str (dict, key, &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to get snap UUID");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "uuid",
+ "%s", buffer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (key, sizeof (key), "%s.volcount", keyprefix);
+
+ ret = dict_get_int32 (dict, key, &volcount);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to get volume count");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "volCount",
+ "%d", volcount);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* Get snapshot status of individual snapshot volume */
+ for (i = 0 ; i < volcount ; i++) {
+ /* <volume> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"volume");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (key, sizeof (key), "%s.vol%d", keyprefix, i);
+
+ ret = cli_xml_snapshot_volume_status (writer, doc,
+ dict, key);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR,
+ "Could not get snap volume status");
+ goto out;
+ }
+
+ /* </volume> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+ }
+
+ /* </snapshot> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = 0;
+out:
+ return ret;
+}
+
+/* This function will generate snapshot status output in xml format.
+ *
+ * @param writer xmlTextWriterPtr
+ * @param doc xmlDocPtr
+ * @param dict dict containing status output
+ *
+ * @return 0 on success and -1 on failure
+ */
+static int
+cli_xml_snapshot_status (xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
+{
+ int ret = -1;
+ int snapcount = 0;
+ int i = 0;
+ int status_cmd = 0;
+ char *str_value = NULL;
+ char key [PATH_MAX] = "";
+
+ GF_ASSERT (writer);
+ GF_ASSERT (doc);
+ GF_ASSERT (dict);
+
+ /* <snapStatus> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"snapStatus");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = dict_get_int32 (dict, "status-cmd", &status_cmd);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch status type");
+ goto out;
+ }
+
+ if (GF_SNAP_STATUS_TYPE_SNAP == status_cmd) {
+ snapcount = 1;
+ } else {
+ ret = dict_get_int32 (dict, "status.snapcount", &snapcount);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not get snapcount");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "count",
+ "%d", snapcount);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+ }
+
+ for (i = 0 ; i < snapcount; i++) {
+ snprintf (key, sizeof (key), "status.snap%d", i);
+
+ ret = cli_xml_snapshot_status_per_snap (writer, doc,
+ dict, key);
+ if (ret < 0) {
+ gf_log ("cli", GF_LOG_ERROR, "failed to create xml "
+ "output for snapshot status");
+ goto out;
+ }
+ }
+
+ /* </snapStatus> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = 0;
+out:
+
+ return ret;
+}
+
+/* This function will generate snapshot config show output in xml format.
+ *
+ * @param writer xmlTextWriterPtr
+ * @param doc xmlDocPtr
+ * @param dict dict containing status output
+ *
+ * @return 0 on success and -1 on failure
+ */
+static int
+cli_xml_snapshot_config_show (xmlTextWriterPtr writer,
+ xmlDocPtr doc, dict_t *dict)
+{
+ int ret = -1;
+ uint64_t i = 0;
+ uint64_t value = 0;
+ uint64_t volcount = 0;
+ char buf[PATH_MAX] = "";
+ char *str_value = NULL;
+
+ GF_ASSERT (writer);
+ GF_ASSERT (doc);
+ GF_ASSERT (dict);
+
+ /* <systemConfig> */
+ ret = xmlTextWriterStartElement (writer,
+ (xmlChar *)"systemConfig");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = dict_get_uint64 (dict, "snap-max-hard-limit", &value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get "
+ "snap-max-hard-limit");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "hardLimit", "%"PRIu64, value);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = dict_get_uint64 (dict, "snap-max-soft-limit", &value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get "
+ "snap-max-soft-limit");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "softLimit",
+ "%"PRIu64"%%", value);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = dict_get_str (dict, "auto-delete", &str_value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch auto-delet");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "autoDelete", "%s", str_value);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* </systemConfig> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* <volumeConfig> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"volumeConfig");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = dict_get_uint64 (dict, "voldisplaycount", &volcount);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch volcount");
+ goto out;
+ }
+
+ /* Get config of all the volumes */
+ for (i = 0; i < volcount; i++) {
+ /* <volume> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"volume");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (buf, sizeof(buf), "volume%"PRIu64"-volname", i);
+ ret = dict_get_str (dict, buf, &str_value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch %s", buf);
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "name", "%s", str_value);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+
+ snprintf (buf, sizeof(buf),
+ "volume%"PRIu64"-snap-max-hard-limit", i);
+ ret = dict_get_uint64 (dict, buf, &value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch %s", buf);
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "hardLimit", "%"PRIu64, value);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (buf, sizeof(buf),
+ "volume%"PRIu64"-active-hard-limit", i);
+ ret = dict_get_uint64 (dict, buf, &value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch"
+ " effective snap_max_hard_limit for "
+ "%s", str_value);
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "effectiveHardLimit",
+ "%"PRIu64, value);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ snprintf (buf, sizeof(buf),
+ "volume%"PRIu64"-snap-max-soft-limit", i);
+ ret = dict_get_uint64 (dict, buf, &value);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch %s", buf);
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "softLimit",
+ "%"PRIu64, value);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* </volume> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+ }
+
+ /* </volume> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = 0;
+out:
+ return ret;
+}
+
+/* This function will generate snapshot config set output in xml format.
+ *
+ * @param writer xmlTextWriterPtr
+ * @param doc xmlDocPtr
+ * @param dict dict containing status output
+ *
+ * @return 0 on success and -1 on failure
+ */
+static int
+cli_xml_snapshot_config_set (xmlTextWriterPtr writer, xmlDocPtr doc,
+ dict_t *dict)
+{
+ int ret = -1;
+ uint64_t hard_limit = 0;
+ uint64_t soft_limit = 0;
+ char *volname = NULL;
+ char *auto_delete = NULL;
+
+ GF_ASSERT (writer);
+ GF_ASSERT (doc);
+ GF_ASSERT (dict);
+
+ /* This is optional parameter therefore ignore the error */
+ ret = dict_get_uint64 (dict, "snap-max-hard-limit", &hard_limit);
+ /* This is optional parameter therefore ignore the error */
+ ret = dict_get_uint64 (dict, "snap-max-soft-limit", &soft_limit);
+ ret = dict_get_str (dict, "auto-delete", &auto_delete);
+
+ if (!hard_limit && !soft_limit && !auto_delete) {
+ ret = -1;
+ gf_log ("cli", GF_LOG_ERROR, "At least one option from "
+ "snap-max-hard-limit, snap-max-soft-limit and "
+ "auto-delete should be set");
+ goto out;
+ }
+
+ /* Ignore the error, as volname is optional */
+ ret = dict_get_str (dict, "volname", &volname);
+
+ if (NULL == volname) {
+ /* <systemConfig> */
+ ret = xmlTextWriterStartElement (writer,
+ (xmlChar *)"systemConfig");
+ } else {
+ /* <volumeConfig> */
+ ret = xmlTextWriterStartElement (writer,
+ (xmlChar *)"volumeConfig");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "name", "%s", volname);
+ }
+
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ if (hard_limit) {
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "newHardLimit",
+ "%"PRIu64, hard_limit);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+ }
+
+ if (soft_limit) {
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "newSoftLimit",
+ "%"PRIu64, soft_limit);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+ }
+
+ if (auto_delete) {
+ ret = xmlTextWriterWriteFormatElement (writer,
+ (xmlChar *) "autoDelete", "%s", auto_delete);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+ }
+
+ /* </volumeConfig> or </systemConfig> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = 0;
+out:
+ return ret;
+}
+
+/* This function will generate snapshot config output in xml format.
+ *
+ * @param writer xmlTextWriterPtr
+ * @param doc xmlDocPtr
+ * @param dict dict containing config output
+ *
+ * @return 0 on success and -1 on failure
+ */
+static int
+cli_xml_snapshot_config (xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
+{
+ int ret = -1;
+ int config_command = 0;
+
+ GF_ASSERT (writer);
+ GF_ASSERT (doc);
+ GF_ASSERT (dict);
+
+ /* <snapConfig> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"snapConfig");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = dict_get_int32 (dict, "config-command", &config_command);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not fetch config type");
+ goto out;
+ }
+
+ switch (config_command) {
+ case GF_SNAP_CONFIG_TYPE_SET:
+ ret = cli_xml_snapshot_config_set (writer, doc, dict);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to create xml "
+ "output for snapshot config set command");
+ goto out;
+ }
+
+ break;
+ case GF_SNAP_CONFIG_DISPLAY:
+ ret = cli_xml_snapshot_config_show (writer, doc, dict);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to create xml "
+ "output for snapshot config show command");
+ goto out;
+ }
+ break;
+ default:
+ gf_log ("cli", GF_LOG_ERROR, "Uknown config command :%d",
+ config_command);
+ ret = -1;
+ goto out;
+ }
+
+ /* </snapConfig> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = 0;
+out:
+
+ return ret;
+}
+
+/* This function will generate snapshot activate or
+ * deactivate output in xml format.
+ *
+ * @param writer xmlTextWriterPtr
+ * @param doc xmlDocPtr
+ * @param dict dict containing activate or deactivate output
+ *
+ * @return 0 on success and -1 on failure
+ */
+static int
+cli_xml_snapshot_activate_deactivate (xmlTextWriterPtr writer, xmlDocPtr doc,
+ dict_t *dict, int cmd)
+{
+ int ret = -1;
+ char *buffer = NULL;
+ char *tag = NULL;
+
+ GF_ASSERT (writer);
+ GF_ASSERT (doc);
+ GF_ASSERT (dict);
+
+ if (GF_SNAP_OPTION_TYPE_ACTIVATE == cmd) {
+ tag = "snapActivate";
+ } else if (GF_SNAP_OPTION_TYPE_DEACTIVATE == cmd) {
+ tag = "snapDeactivate";
+ } else {
+ gf_log ("cli", GF_LOG_ERROR, "invalid command %d", cmd);
+ goto out;
+ }
+
+ /* <snapActivate> or <snapDeactivate> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)tag);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* <snapshot> */
+ ret = xmlTextWriterStartElement (writer, (xmlChar *)"snapshot");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = dict_get_str (dict, "snapname", &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get snap name");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "name",
+ "%s", buffer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = dict_get_str (dict, "snapuuid", &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get snap uuid");
+ goto out;
+ }
+
+ ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *) "uuid",
+ "%s", buffer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* </snapshot> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+
+ /* </snapActivate> or </snapDeactivate> */
+ ret = xmlTextWriterEndElement (writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = 0;
+out:
+
+ return ret;
+}
+#endif /* HAVE_LIB_XML */
+
+int
+cli_xml_output_snap_status_begin (cli_local_t *local, int op_ret, int op_errno,
+ char *op_errstr)
+{
+#if (HAVE_LIB_XML)
+ int ret = -1;
+
+ GF_ASSERT (local);
+
+ ret = cli_begin_xml_output (&(local->writer), &(local->doc));
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ ret = cli_xml_output_common (local->writer, op_ret, op_errno,
+ op_errstr);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* <snapStatus> */
+ ret = xmlTextWriterStartElement (local->writer,
+ (xmlChar *) "snapStatus");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* <snapshots> */
+ ret = xmlTextWriterStartElement (local->writer, (xmlChar *)"snapshots");
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+out:
+ gf_log ("cli", GF_LOG_TRACE, "Returning %d", ret);
+ return ret;
+#else
+ return 0;
+#endif
+}
+
+int
+cli_xml_output_snap_status_end (cli_local_t *local)
+{
+#if (HAVE_LIB_XML)
+ int ret = -1;
+
+ GF_ASSERT (local);
+
+ /* </snapshots> */
+ ret = xmlTextWriterEndElement (local->writer);
+ XML_RET_CHECK_AND_GOTO (ret, out);
+
+ /* </snapStatus> */
+ ret = xmlTextWriterEndElement (local->writer);
+ XML_RET_CHECK_AND_GOTO(ret, out);
+
+ ret = cli_end_xml_output (local->writer, local->doc);
+out:
+ gf_log ("cli", GF_LOG_TRACE, "Returning %d", ret);
+ return ret;
+#else
+ return 0;
+#endif
+}
+
+/* This function will generate xml output for all the snapshot commands
+ *
+ * @param cmd_type command type
+ * @param dict dict containing snapshot command output
+ * @param op_ret return value of the snapshot command
+ * @param op_errno errno for the snapshot command
+ * @param op_errstr error string for the snapshot command
+ *
+ * @return 0 on success and -1 on failure
+ */
+int
+cli_xml_output_snapshot (int cmd_type, dict_t *dict, int op_ret,
+ int op_errno, char *op_errstr)
+{
+#if (HAVE_LIB_XML)
+ int ret = -1;
+ xmlTextWriterPtr writer = NULL;
+ xmlDocPtr doc = NULL;
+
+ GF_ASSERT (dict);
+
+ ret = cli_begin_xml_output (&writer, &doc);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to output "
+ "xml begin block");
+ goto out;
+ }
+
+ ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to output "
+ "xml common block");
+ goto out;
+ }
+
+ /* In case of command failure just printing the error message is good
+ * enough */
+ if (0 != op_ret) {
+ goto end;
+ }
+
+ switch (cmd_type) {
+ case GF_SNAP_OPTION_TYPE_CREATE:
+ ret = cli_xml_snapshot_create (writer, doc, dict);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to create "
+ "xml output for snapshot create command");
+ goto out;
+ }
+ break;
+ case GF_SNAP_OPTION_TYPE_DELETE:
+ ret = cli_xml_snapshot_delete (writer, doc, dict);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to create "
+ "xml output for snapshot delete command");
+ goto out;
+ }
+ break;
+ case GF_SNAP_OPTION_TYPE_RESTORE:
+ ret = cli_xml_snapshot_restore (writer, doc, dict);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to create "
+ "xml output for snapshot restore command");
+ goto out;
+ }
+ break;
+ case GF_SNAP_OPTION_TYPE_LIST:
+ ret = cli_xml_snapshot_list (writer, doc, dict);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to create "
+ "xml output for snapshot list command");
+ goto out;
+ }
+ break;
+ case GF_SNAP_OPTION_TYPE_STATUS:
+ ret = cli_xml_snapshot_status (writer, doc, dict);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to create"
+ "xml output for snapshot status command");
+ goto out;
+ }
+ break;
+ case GF_SNAP_OPTION_TYPE_INFO:
+ ret = cli_xml_snapshot_info (writer, doc, dict);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to create "
+ "xml output for snapshot info command");
+ goto out;
+ }
+ break;
+ case GF_SNAP_OPTION_TYPE_ACTIVATE:
+ case GF_SNAP_OPTION_TYPE_DEACTIVATE:
+ ret = cli_xml_snapshot_activate_deactivate (writer, doc,
+ dict, cmd_type);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to create "
+ "xml output for snapshot config command");
+ }
+ break;
+ case GF_SNAP_OPTION_TYPE_CONFIG:
+ ret = cli_xml_snapshot_config (writer, doc, dict);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to create "
+ "xml output for snapshot config command");
+ }
+ break;
+ default:
+ gf_log ("cli", GF_LOG_ERROR,
+ "Unexpected snapshot command: %d", cmd_type);
+ goto out;
+ }
+
+end:
+ ret = cli_end_xml_output (writer, doc);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to output "
+ "xml end block");
+ goto out;
+ }
+
+ ret = 0;
+out:
+ return ret;
+#else
+ return 0;
+#endif /* HAVE_LIB_XML */
+}
diff --git a/cli/src/cli.h b/cli/src/cli.h
index a1a78eca2bc..74d35992680 100644
--- a/cli/src/cli.h
+++ b/cli/src/cli.h
@@ -388,6 +388,17 @@ cli_xml_output_vol_gsync (dict_t *dict, int op_ret, int op_errno,
int
cli_xml_output_vol_status_tasks_detail (cli_local_t *local, dict_t *dict);
+int
+cli_xml_output_snap_status_begin (cli_local_t *local, int op_ret, int op_errno,
+ char *op_errstr);
+int
+cli_xml_output_snap_status_end (cli_local_t *local);
+int
+cli_xml_snapshot_status_per_snap (xmlTextWriterPtr writer, xmlDocPtr doc,
+ dict_t *dict, const char *keyprefix);
+int
+cli_xml_output_snapshot (int cmd_type, dict_t *dict, int op_ret,
+ int op_errno, char *op_errstr);
char *
is_server_debug_xlator (void *myframe);
diff --git a/xlators/mgmt/glusterd/src/glusterd-snapshot.c b/xlators/mgmt/glusterd/src/glusterd-snapshot.c
index 7678d77b3d5..dccf57f7c93 100644
--- a/xlators/mgmt/glusterd/src/glusterd-snapshot.c
+++ b/xlators/mgmt/glusterd/src/glusterd-snapshot.c
@@ -770,6 +770,34 @@ glusterd_snapshot_restore (dict_t *dict, char **op_errstr, dict_t *rsp_dict)
goto out;
}
+ ret = dict_set_dynstr_with_alloc (rsp_dict, "snapuuid",
+ uuid_utoa (snap->snap_id));
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set snap "
+ "uuid in response dictionary for %s snapshot",
+ snap->snapname);
+ goto out;
+ }
+
+
+ ret = dict_set_dynstr_with_alloc (rsp_dict, "volname",
+ snap_volinfo->parent_volname);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set snap "
+ "uuid in response dictionary for %s snapshot",
+ snap->snapname);
+ goto out;
+ }
+
+ ret = dict_set_dynstr_with_alloc (rsp_dict, "volid",
+ uuid_utoa (parent_volinfo->volume_id));
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set snap "
+ "uuid in response dictionary for %s snapshot",
+ snap->snapname);
+ goto out;
+ }
+
/* Take backup of the volinfo folder */
ret = glusterd_snapshot_backup_vol (parent_volinfo);
if (ret) {
@@ -2768,7 +2796,7 @@ glusterd_snapshot_get_all_snap_info (dict_t *dict)
}
}
- ret = dict_set_int32 (dict, "snap-count", snapcount);
+ ret = dict_set_int32 (dict, "snapcount", snapcount);
if (ret) {
gf_log (this->name, GF_LOG_ERROR, "Failed to set snapcount");
goto out;
@@ -2870,7 +2898,7 @@ glusterd_snapshot_get_info_by_volume (dict_t *dict, char *volname,
goto out;
}
}
- ret = dict_set_int32 (dict, "snap-count", snapcount);
+ ret = dict_set_int32 (dict, "snapcount", snapcount);
if (ret) {
gf_log (this->name, GF_LOG_ERROR, "Failed to set snapcount");
goto out;
@@ -2941,7 +2969,7 @@ glusterd_handle_snapshot_info (rpcsvc_request_t *req, glusterd_op_t op,
goto out;
}
- ret = dict_set_int32 (dict, "snap-count", 1);
+ ret = dict_set_int32 (dict, "snapcount", 1);
if (ret) {
gf_log (this->name, GF_LOG_ERROR,
"Failed to set snapcount");
@@ -3047,7 +3075,7 @@ glusterd_snapshot_get_all_snapnames (dict_t *dict)
}
}
- ret = dict_set_int32 (dict, "snap-count", snapcount);
+ ret = dict_set_int32 (dict, "snapcount", snapcount);
if (ret) {
gf_log (this->name, GF_LOG_ERROR, "Failed to set snapcount");
goto out;
@@ -3096,7 +3124,7 @@ glusterd_snapshot_get_vol_snapnames (dict_t *dict, glusterd_volinfo_t *volinfo)
}
}
- ret = dict_set_int32 (dict, "snap-count", snapcount);
+ ret = dict_set_int32 (dict, "snapcount", snapcount);
if (ret) {
gf_log (this->name, GF_LOG_ERROR, "Failed to set snapcount");
goto out;
@@ -4538,6 +4566,15 @@ glusterd_snapshot_remove_prevalidate (dict_t *dict, char **op_errstr,
goto out;
}
+ ret = dict_set_dynstr_with_alloc (dict, "snapuuid",
+ uuid_utoa (snap->snap_id));
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set snap "
+ "uuid in response dictionary for %s snapshot",
+ snap->snapname);
+ goto out;
+ }
+
ret = 0;
out:
return ret;
@@ -4699,6 +4736,16 @@ glusterd_snapshot_activate_commit (dict_t *dict, char **op_errstr,
snap_volinfo->volname, snap->snapname);
goto out;
}
+
+ ret = dict_set_dynstr_with_alloc (rsp_dict, "snapuuid",
+ uuid_utoa (snap->snap_id));
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set snap "
+ "uuid in response dictionary for %s snapshot",
+ snap->snapname);
+ goto out;
+ }
+
ret = 0;
out:
return ret;
@@ -4759,6 +4806,15 @@ glusterd_snapshot_deactivate_commit (dict_t *dict, char **op_errstr,
goto out;
}
+ ret = dict_set_dynstr_with_alloc (rsp_dict, "snapuuid",
+ uuid_utoa (snap->snap_id));
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set snap "
+ "uuid in response dictionary for %s snapshot",
+ snap->snapname);
+ goto out;
+ }
+
ret = 0;
out:
return ret;
@@ -4805,6 +4861,15 @@ glusterd_snapshot_remove_commit (dict_t *dict, char **op_errstr,
goto out;
}
+ ret = dict_set_dynstr_with_alloc (rsp_dict, "snapuuid",
+ uuid_utoa (snap->snap_id));
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set snap uuid in "
+ "response dictionary for %s snapshot",
+ snap->snapname);
+ goto out;
+ }
+
/* Save the snap status as GD_SNAP_STATUS_DECOMMISSION so
* that if the node goes down the snap would be removed
*/
@@ -5276,6 +5341,17 @@ glusterd_snapshot_create_commit (dict_t *dict, char **op_errstr,
}
}
+ ret = dict_set_dynstr_with_alloc (rsp_dict, "snapuuid",
+ uuid_utoa (snap->snap_id));
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set snap "
+ "uuid in response dictionary for %s snapshot",
+ snap->snapname);
+ goto out;
+ }
+
+ ret = 0;
+
out:
if (ret) {
if (snap)
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c
index aff2356eb4f..baa845b0a91 100644
--- a/xlators/mgmt/glusterd/src/glusterd-utils.c
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.c
@@ -10796,6 +10796,19 @@ glusterd_snap_create_use_rsp_dict (dict_t *dst, dict_t *src)
goto out;
}
+ ret = dict_get_str (src, "snapuuid", &buf);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "failed to get snap UUID");
+ goto out;
+ }
+
+ ret = dict_set_dynstr_with_alloc (dst, "snapuuid", buf);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "Failed to set snap uuid in dict");
+ goto out;
+ }
+
/* set in dst dictionary soft-limit-reach only if soft-limit-reach
* is present src dictionary */
ret = dict_get_int8 (src, "soft-limit-reach", &soft_limit_flag);