diff options
author | Kaushal M <kaushal@redhat.com> | 2012-02-15 16:18:25 +0530 |
---|---|---|
committer | Vijay Bellur <vijay@gluster.com> | 2012-02-15 21:45:27 -0800 |
commit | 26800453aacd76e6edc36c078aaacbe7c16aa75e (patch) | |
tree | 3f25a508ac5f2a85871a4890cb798464dafd6671 | |
parent | c8d47f056ef69d2a644646fd24e8f58de4c0e70e (diff) |
cli: Enable output in XML
This patch enables gluster cli to output data in xml format. XML output can be
obtained by passing "--xml" as an argument.
A new "volume list" command, which lists the volumes present in a cluster, has
been added. This can be used for obtaining a quick list of volumes.
Several commands, including "volume top", "volume profile", "volume status" and
"volume info", "volume list", have custom XML output routines. Other commands
use either one of the 2 generic output routines, cli_xml_output_str() &
cli_xml_output_dict().
NOTE: When using "all" for "volume status" and "volume info" the XML output will
have multiple roots.
Change-Id: I6117baa02ec06fda116177dbd401f66521263ac6
BUG: 790713
Signed-off-by: Kaushal M <kaushal@redhat.com>
Reviewed-on: http://review.gluster.com/2753
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Amar Tumballi <amarts@redhat.com>
Reviewed-by: Vijay Bellur <vijay@gluster.com>
-rw-r--r-- | cli/src/Makefile.am | 8 | ||||
-rw-r--r-- | cli/src/cli-cmd-volume.c | 31 | ||||
-rw-r--r-- | cli/src/cli-rpc-ops.c | 594 | ||||
-rw-r--r-- | cli/src/cli-xml-output.c | 2258 | ||||
-rw-r--r-- | cli/src/cli.c | 5 | ||||
-rw-r--r-- | cli/src/cli.h | 26 | ||||
-rw-r--r-- | rpc/rpc-lib/src/protocol-common.h | 1 | ||||
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-handler.c | 59 | ||||
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-rpc-ops.c | 1 | ||||
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd.h | 3 |
10 files changed, 2891 insertions, 95 deletions
diff --git a/cli/src/Makefile.am b/cli/src/Makefile.am index b76a9efd3..800283618 100644 --- a/cli/src/Makefile.am +++ b/cli/src/Makefile.am @@ -2,13 +2,13 @@ sbin_PROGRAMS = gluster gluster_SOURCES = cli.c registry.c input.c cli-cmd.c cli-rl.c \ cli-cmd-volume.c cli-cmd-peer.c cli-rpc-ops.c cli-cmd-parser.c\ - cli-cmd-system.c cli-cmd-misc.c + cli-cmd-system.c cli-cmd-misc.c cli-xml-output.c gluster_LDADD = $(top_builddir)/libglusterfs/src/libglusterfs.la $(GF_LDADD)\ $(RLLIBS) $(top_builddir)/rpc/xdr/src/libgfxdr.la \ $(top_builddir)/rpc/rpc-lib/src/libgfrpc.la -gluster_LDFLAGS = $(GF_LDFLAGS) $(GF_GLUSTERFS_LDFLAGS) +gluster_LDFLAGS = $(GF_LDFLAGS) $(GF_GLUSTERFS_LDFLAGS) $(LIBXML2_LIBS) noinst_HEADERS = cli.h cli-mem-types.h cli-cmd.h AM_CFLAGS = -fPIC -Wall -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -D$(GF_HOST_OS)\ @@ -17,8 +17,8 @@ AM_CFLAGS = -fPIC -Wall -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -D$(GF_HOST_OS)\ -DDATADIR=\"$(localstatedir)\" \ -DCONFDIR=\"$(sysconfdir)/glusterfs\" $(GF_GLUSTERFS_CFLAGS)\ -DGSYNCD_PREFIX=\"$(libexecdir)/glusterfs\"\ - -DSYNCDAEMON_COMPILE=$(SYNCDAEMON_COMPILE) -DSBIN_DIR=\"$(sbindir)\" - + -DSYNCDAEMON_COMPILE=$(SYNCDAEMON_COMPILE) -DSBIN_DIR=\"$(sbindir)\"\ + $(LIBXML2_CFLAGS) CLEANFILES = diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c index 521e3eb84..9c7a43b9f 100644 --- a/cli/src/cli-cmd-volume.c +++ b/cli/src/cli-cmd-volume.c @@ -1653,6 +1653,33 @@ out: return ret; } +int +cli_cmd_volume_list_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + call_frame_t *frame = NULL; + rpc_clnt_procedure_t *proc = NULL; + int sent = 0; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_LIST_VOLUME]; + if (proc->fn) { + ret = proc->fn (frame, THIS, NULL); + } + +out: + if (ret) { + cli_cmd_sent_status_get (&sent); + if (sent == 0) + cli_out ("Volume list failed"); + } + + return ret; +} struct cli_cmd volume_cmds[] = { { "volume info [all|<VOLNAME>]", @@ -1754,6 +1781,10 @@ struct cli_cmd volume_cmds[] = { cli_cmd_volume_statedump_cbk, "perform statedump on bricks"}, + {"volume list", + cli_cmd_volume_list_cbk, + "list all volumes in cluster"}, + { NULL, NULL, NULL } }; diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c index 78b2980ad..8d22f1b1d 100644 --- a/cli/src/cli-rpc-ops.c +++ b/cli/src/cli-rpc-ops.c @@ -91,13 +91,13 @@ rpc_clnt_prog_t cli_pmap_prog = { .progver = GLUSTER_PMAP_VERSION, }; - int gf_cli3_1_probe_cbk (struct rpc_req *req, struct iovec *iov, int count, void *myframe) { - gf1_cli_probe_rsp rsp = {0,}; + gf1_cli_probe_rsp rsp = {0,}; int ret = -1; + char msg[1024] = {0,}; if (-1 == req->rpc_status) { goto out; @@ -115,18 +115,23 @@ gf_cli3_1_probe_cbk (struct rpc_req *req, struct iovec *iov, if (!rsp.op_ret) { switch (rsp.op_errno) { case GF_PROBE_SUCCESS: - cli_out ("Probe successful"); + snprintf (msg, sizeof (msg), + "Probe successful"); break; case GF_PROBE_LOCALHOST: - cli_out ("Probe on localhost not needed"); + snprintf (msg, sizeof (msg), + "Probe on localhost not needed"); break; case GF_PROBE_FRIEND: - cli_out ("Probe on host %s port %d already" - " in peer list", rsp.hostname, rsp.port); + snprintf (msg, sizeof (msg), + "Probe on host %s port %d already" + " in peer list", rsp.hostname, + rsp.port); break; default: - cli_out ("Probe returned with unknown errno %d", - rsp.op_errno); + snprintf (msg, sizeof (msg), + "Probe returned with unknown errno %d", + rsp.op_errno); break; } } @@ -134,33 +139,52 @@ gf_cli3_1_probe_cbk (struct rpc_req *req, struct iovec *iov, if (rsp.op_ret) { switch (rsp.op_errno) { case GF_PROBE_ANOTHER_CLUSTER: - cli_out ("%s is already part of " - "another cluster", rsp.hostname); + snprintf (msg, sizeof (msg), + "%s is already part of another" + " cluster", rsp.hostname); break; case GF_PROBE_VOLUME_CONFLICT: - cli_out ("Atleast one volume on %s conflicts " - "with existing volumes in the " - "cluster", rsp.hostname); + snprintf (msg, sizeof (msg), + "Atleast one volume on %s conflicts " + "with existing volumes in the " + "cluster", rsp.hostname); break; case GF_PROBE_UNKNOWN_PEER: - cli_out ("%s responded with 'unknown peer' error, " - "this could happen if %s doesn't have" - " localhost in its peer database", - rsp.hostname, rsp.hostname); + snprintf (msg, sizeof (msg), + "%s responded with 'unknown peer'" + " error, this could happen if %s " + "doesn't have localhost in its peer" + " database", rsp.hostname, + rsp.hostname); break; case GF_PROBE_ADD_FAILED: - cli_out ("Failed to add peer information " - "on %s" , rsp.hostname); + snprintf (msg, sizeof (msg), + "Failed to add peer information " + "on %s" , rsp.hostname); break; default: - cli_out ("Probe unsuccessful\nProbe returned " - "with unknown errno %d", rsp.op_errno); + snprintf (msg, sizeof (msg), + "Probe unsuccessful\nProbe returned " + "with unknown errno %d", + rsp.op_errno); break; } gf_log ("glusterd",GF_LOG_ERROR,"Probe failed with op_ret %d" " and op_errno %d", rsp.op_ret, rsp.op_errno); } + +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("peerProbe", msg, rsp.op_ret, + rsp.op_errno, NULL); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + cli_out ("%s", msg); ret = rsp.op_ret; out: @@ -174,6 +198,7 @@ gf_cli3_1_deprobe_cbk (struct rpc_req *req, struct iovec *iov, { gf1_cli_deprobe_rsp rsp = {0,}; int ret = -1; + char msg[1024] = {0,}; if (-1 == req->rpc_status) { goto out; @@ -191,34 +216,48 @@ gf_cli3_1_deprobe_cbk (struct rpc_req *req, struct iovec *iov, if (rsp.op_ret) { switch (rsp.op_errno) { case GF_DEPROBE_LOCALHOST: - cli_out ("%s is localhost", - rsp.hostname); + snprintf (msg, sizeof (msg), + "%s is localhost", rsp.hostname); break; case GF_DEPROBE_NOT_FRIEND: - cli_out ("%s is not part of cluster", - rsp.hostname); + snprintf (msg, sizeof (msg), + "%s is not part of cluster", + rsp.hostname); break; case GF_DEPROBE_BRICK_EXIST: - cli_out ("Brick(s) with the peer %s exist in " - "cluster", rsp.hostname); + snprintf (msg, sizeof (msg), + "Brick(s) with the peer %s exist in " + "cluster", rsp.hostname); break; case GF_DEPROBE_FRIEND_DOWN: - cli_out ("One of the peers is probably down." - " Check with 'peer status'."); + snprintf (msg, sizeof (msg), + "One of the peers is probably down." + " Check with 'peer status'."); break; default: - cli_out ("Detach unsuccessful\nDetach returned " - "with unknown errno %d", - rsp.op_errno); + snprintf (msg, sizeof (msg), + "Detach unsuccessful\nDetach returned" + " with unknown errno %d", + rsp.op_errno); break; } gf_log ("glusterd",GF_LOG_ERROR,"Detach failed with op_ret %d" " and op_errno %d", rsp.op_ret, rsp.op_errno); } else { - cli_out ("Detach successful"); + snprintf (msg, sizeof (msg), "Detach successful"); } - +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("peerDetach", msg, rsp.op_ret, + rsp.op_errno, NULL); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + cli_out ("%s", msg); ret = rsp.op_ret; out: @@ -254,7 +293,6 @@ gf_cli3_1_list_friends_cbk (struct rpc_req *req, struct iovec *iov, goto out; } - gf_log ("cli", GF_LOG_INFO, "Received resp to list: %d", rsp.op_ret); @@ -285,6 +323,17 @@ gf_cli3_1_list_friends_cbk (struct rpc_req *req, struct iovec *iov, goto out; } +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_dict ("peerStatus", dict, + rsp.op_ret, rsp.op_errno, + NULL); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error ouputting to xml"); + goto out; + } +#endif ret = dict_get_int32 (dict, "count", &count); if (ret) { @@ -475,6 +524,18 @@ gf_cli3_1_get_volume_cbk (struct rpc_req *req, struct iovec *iov, } } +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_vol_info (dict, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + } + goto out; + } +#endif + while ( i < count) { cli_out (" "); snprintf (key, 256, "volume%d.name", i); @@ -660,6 +721,18 @@ gf_cli3_1_create_volume_cbk (struct rpc_req *req, struct iovec *iov, ret = dict_get_str (dict, "volname", &volname); gf_log ("cli", GF_LOG_INFO, "Received resp to create volume"); + +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_dict ("volCreate", dict, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + if (rsp.op_ret && strcmp (rsp.op_errstr, "")) cli_out ("%s", rsp.op_errstr); else @@ -718,6 +791,17 @@ gf_cli3_1_delete_volume_cbk (struct rpc_req *req, struct iovec *iov, gf_log ("cli", GF_LOG_INFO, "Received resp to delete volume"); +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_dict ("volDelete", dict, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + if (rsp.op_ret && strcmp (rsp.op_errstr, "")) cli_out ("%s", rsp.op_errstr); else @@ -776,6 +860,17 @@ gf_cli3_1_start_volume_cbk (struct rpc_req *req, struct iovec *iov, gf_log ("cli", GF_LOG_INFO, "Received resp to start volume"); +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_dict ("volStart", dict, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + if (rsp.op_ret && strcmp (rsp.op_errstr, "")) cli_out ("%s", rsp.op_errstr); else @@ -835,6 +930,17 @@ gf_cli3_1_stop_volume_cbk (struct rpc_req *req, struct iovec *iov, gf_log ("cli", GF_LOG_INFO, "Received resp to stop volume"); +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_dict ("volStop", dict, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + if (rsp.op_ret && strcmp (rsp.op_errstr, "")) cli_out ("%s", rsp.op_errstr); else @@ -869,6 +975,7 @@ gf_cli3_1_defrag_volume_cbk (struct rpc_req *req, struct iovec *iov, uint64_t files = 0; uint64_t size = 0; uint64_t lookup = 0; + char msg[1024] = {0,}; if (-1 == req->rpc_status) { goto out; @@ -937,24 +1044,29 @@ gf_cli3_1_defrag_volume_cbk (struct rpc_req *req, struct iovec *iov, if (cmd == GF_DEFRAG_CMD_STOP) { if (rsp.op_ret == -1) { if (strcmp (rsp.op_errstr, "")) - cli_out ("%s", rsp.op_errstr); + snprintf (msg, sizeof (msg), + "%s", rsp.op_errstr); else - cli_out ("rebalance volume %s stop failed", - volname); + snprintf (msg, sizeof (msg), + "rebalance volume %s stop failed", + volname); } else { - cli_out ("stopped rebalance process of volume %s \n" - "(after rebalancing %"PRId64" files totaling " - "%"PRId64" bytes)", volname, files, size); + snprintf (msg, sizeof (msg), + "stopped rebalance process of volume %s \n" + "(after rebalancing %"PRId64" files totaling" + " %"PRId64" bytes)", volname, files, size); } goto done; } if (cmd == GF_DEFRAG_CMD_STATUS) { if (rsp.op_ret == -1) { if (strcmp (rsp.op_errstr, "")) - cli_out ("%s", rsp.op_errstr); + snprintf (msg, sizeof (msg), + "%s", rsp.op_errstr); else - cli_out ("failed to get the status of " - "rebalance process"); + snprintf (msg, sizeof (msg), + "failed to get the status of " + "rebalance process"); goto done; } @@ -988,36 +1100,51 @@ gf_cli3_1_defrag_volume_cbk (struct rpc_req *req, struct iovec *iov, break; } if (files && (rsp.op_errno == 1)) { - cli_out ("rebalance %s: fixed layout %"PRId64, - status, files); + snprintf (msg, sizeof (msg), + "rebalance %s: fixed layout %"PRId64, + status, files); goto done; } if (files && (rsp.op_errno == 6)) { - cli_out ("rebalance %s: fixed layout %"PRId64, - status, files); + snprintf (msg, sizeof (msg), + "rebalance %s: fixed layout %"PRId64, + status, files); goto done; } if (files) { - cli_out ("rebalance %s: rebalanced %"PRId64 - " files of size %"PRId64" (total files" - " scanned %"PRId64")", status, - files, size, lookup); + snprintf (msg, sizeof (msg), + "rebalance %s: rebalanced %"PRId64 + " files of size %"PRId64" (total files" + " scanned %"PRId64")", status, + files, size, lookup); goto done; } - cli_out ("rebalance %s", status); + snprintf (msg, sizeof (msg), "rebalance %s", status); goto done; } /* All other possibility is about starting a volume */ if (rsp.op_ret && strcmp (rsp.op_errstr, "")) - cli_out ("%s", rsp.op_errstr); + snprintf (msg, sizeof (msg), "%s", rsp.op_errstr); else - cli_out ("starting rebalance on volume %s has been %s", - volname, (rsp.op_ret) ? "unsuccessful": - "successful"); + snprintf (msg, sizeof (msg), + "starting rebalance on volume %s has been %s", + volname, (rsp.op_ret) ? "unsuccessful": + "successful"); done: +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("volRebalance", msg, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + cli_out ("%s", msg); ret = rsp.op_ret; out: @@ -1041,6 +1168,7 @@ gf_cli3_1_rename_volume_cbk (struct rpc_req *req, struct iovec *iov, { gf_cli_rsp rsp = {0,}; int ret = -1; + char msg[1024] = {0,}; if (-1 == req->rpc_status) { goto out; @@ -1054,9 +1182,21 @@ gf_cli3_1_rename_volume_cbk (struct rpc_req *req, struct iovec *iov, gf_log ("cli", GF_LOG_INFO, "Received resp to probe"); - cli_out ("Rename volume %s", (rsp.op_ret) ? "unsuccessful": - "successful"); + snprintf (msg, sizeof (msg), "Rename volume %s", + (rsp.op_ret) ? "unsuccessful": "successful"); +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("volRename", msg, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + + cli_out ("%s", msg); ret = rsp.op_ret; out: @@ -1070,6 +1210,7 @@ gf_cli3_1_reset_volume_cbk (struct rpc_req *req, struct iovec *iov, { gf_cli_rsp rsp = {0,}; int ret = -1; + char msg[1024] = {0,}; if (-1 == req->rpc_status) { goto out; @@ -1084,11 +1225,23 @@ gf_cli3_1_reset_volume_cbk (struct rpc_req *req, struct iovec *iov, gf_log ("cli", GF_LOG_INFO, "Received resp to reset"); if (rsp.op_ret && strcmp (rsp.op_errstr, "")) - cli_out ("%s", rsp.op_errstr); + snprintf (msg, sizeof (msg), "%s", rsp.op_errstr); else - cli_out ("reset volume %s", (rsp.op_ret) ? "unsuccessful": - "successful"); + snprintf (msg, sizeof (msg), "reset volume %s", + (rsp.op_ret) ? "unsuccessful": "successful"); +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("volReset", msg, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + + cli_out ("%s", msg); ret = rsp.op_ret; out: @@ -1104,6 +1257,7 @@ gf_cli3_1_set_volume_cbk (struct rpc_req *req, struct iovec *iov, int ret = -1; dict_t *dict = NULL; char *help_str = NULL; + char msg[1024] = {0,}; if (-1 == req->rpc_status) { goto out; @@ -1118,7 +1272,7 @@ gf_cli3_1_set_volume_cbk (struct rpc_req *req, struct iovec *iov, gf_log ("cli", GF_LOG_INFO, "Received resp to set"); if (rsp.op_ret && strcmp (rsp.op_errstr, "")) - cli_out ("%s", rsp.op_errstr); + snprintf (msg, sizeof (msg), "%s", rsp.op_errstr); dict = dict_new (); @@ -1133,11 +1287,23 @@ gf_cli3_1_set_volume_cbk (struct rpc_req *req, struct iovec *iov, goto out; if (dict_get_str (dict, "help-str", &help_str)) - cli_out ("Set volume %s", (rsp.op_ret) ? "unsuccessful": - "successful"); + snprintf (msg, sizeof (msg), "Set volume %s", + (rsp.op_ret) ? "unsuccessful": "successful"); else - cli_out ("%s", help_str); + snprintf (msg, sizeof (msg), "%s", help_str); + +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("volSet", msg, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + cli_out ("%s", msg); ret = rsp.op_ret; out: @@ -1151,6 +1317,7 @@ gf_cli3_1_add_brick_cbk (struct rpc_req *req, struct iovec *iov, { gf_cli_rsp rsp = {0,}; int ret = -1; + char msg[1024] = {0,}; if (-1 == req->rpc_status) { goto out; @@ -1166,10 +1333,23 @@ gf_cli3_1_add_brick_cbk (struct rpc_req *req, struct iovec *iov, gf_log ("cli", GF_LOG_INFO, "Received resp to add brick"); if (rsp.op_ret && strcmp (rsp.op_errstr, "")) - cli_out ("%s", rsp.op_errstr); + snprintf (msg, sizeof (msg), "%s", rsp.op_errstr); else - cli_out ("Add Brick %s", (rsp.op_ret) ? "unsuccessful": - "successful"); + snprintf (msg, sizeof (msg), "Add Brick %s", + (rsp.op_ret) ? "unsuccessful": "successful"); + +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("volAddBrick", msg, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + + cli_out ("%s", msg); ret = rsp.op_ret; out: @@ -1191,6 +1371,7 @@ gf_cli3_remove_brick_status_cbk (struct rpc_req *req, struct iovec *iov, uint64_t files = 0; uint64_t size = 0; dict_t *dict = NULL; + char msg[1024] = {0,}; if (-1 == req->rpc_status) { goto out; @@ -1263,24 +1444,39 @@ gf_cli3_remove_brick_status_cbk (struct rpc_req *req, struct iovec *iov, "failed to get size of xfer"); if (files && (rsp.op_errno == 1)) { - cli_out ("remove-brick %s: fixed layout %"PRId64, - status,files); + snprintf (msg, sizeof (msg), + "remove-brick %s: fixed layout %"PRId64, + status,files); goto out; } if (files && (rsp.op_errno == 6)) { - cli_out ("remove-brick %s: fixed layout %"PRId64, - status, files); + snprintf (msg, sizeof (msg), + "remove-brick %s: fixed layout %"PRId64, + status, files); goto out; } if (files) { - cli_out ("remove-brick %s: decommissioned %"PRId64 - " files of size %"PRId64, status, - files, size); + snprintf (msg, sizeof (msg), + "remove-brick %s: decommissioned %"PRId64 + " files of size %"PRId64, status, + files, size); goto out; } - cli_out ("remove-brick %s", status); + snprintf (msg, sizeof (msg), "remove-brick %s", status); +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("volRemoveBrick", msg, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + + cli_out ("%s", msg); out: if (rsp.dict.dict_val) free (rsp.dict.dict_val); //malloced by xdr @@ -1297,6 +1493,7 @@ gf_cli3_1_remove_brick_cbk (struct rpc_req *req, struct iovec *iov, { gf_cli_rsp rsp = {0,}; int ret = -1; + char msg[1024] = {0,}; if (-1 == req->rpc_status) { goto out; @@ -1311,11 +1508,22 @@ gf_cli3_1_remove_brick_cbk (struct rpc_req *req, struct iovec *iov, gf_log ("cli", GF_LOG_INFO, "Received resp to remove brick"); if (rsp.op_ret && strcmp (rsp.op_errstr, "")) - cli_out ("%s", rsp.op_errstr); + snprintf (msg, sizeof (msg), "%s", rsp.op_errstr); else - cli_out ("Remove Brick %s", (rsp.op_ret) ? "unsuccessful": - "successful"); + snprintf (msg, sizeof (msg), "Remove Brick %s", + (rsp.op_ret) ? "unsuccessful": "successful"); +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("volRemoveBrick", msg, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + cli_out ("%s", msg); ret = rsp.op_ret; out: @@ -1344,6 +1552,7 @@ gf_cli3_1_replace_brick_cbk (struct rpc_req *req, struct iovec *iov, gf1_cli_replace_op replace_op = 0; char *rb_operation_str = NULL; dict_t *rsp_dict = NULL; + char msg[1024] = {0,}; if (-1 == req->rpc_status) { goto out; @@ -1457,9 +1666,21 @@ gf_cli3_1_replace_brick_cbk (struct rpc_req *req, struct iovec *iov, } gf_log ("cli", GF_LOG_INFO, "Received resp to replace brick"); - cli_out ("%s", - rb_operation_str ? rb_operation_str : "Unknown operation"); + snprintf (msg,sizeof (msg), "%s", + rb_operation_str ? rb_operation_str : "Unknown operation"); +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("volReplaceBrick", msg, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + + cli_out ("%s", msg); ret = rsp.op_ret; out: @@ -1484,6 +1705,7 @@ gf_cli3_1_log_rotate_cbk (struct rpc_req *req, struct iovec *iov, { gf_cli_rsp rsp = {0,}; int ret = -1; + char msg[1024] = {0,}; if (-1 == req->rpc_status) { goto out; @@ -1498,11 +1720,23 @@ gf_cli3_1_log_rotate_cbk (struct rpc_req *req, struct iovec *iov, gf_log ("cli", GF_LOG_DEBUG, "Received resp to log rotate"); if (rsp.op_ret && strcmp (rsp.op_errstr, "")) - cli_out ("%s", rsp.op_errstr); + snprintf (msg, sizeof (msg), "%s", rsp.op_errstr); else - cli_out ("log rotate %s", (rsp.op_ret) ? "unsuccessful": - "successful"); + snprintf (msg, sizeof (msg), "log rotate %s", + (rsp.op_ret) ? "unsuccessful": "successful"); +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("volLogRotate", msg, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + + cli_out ("%s", msg); ret = rsp.op_ret; out: @@ -1519,6 +1753,7 @@ gf_cli3_1_sync_volume_cbk (struct rpc_req *req, struct iovec *iov, { gf_cli_rsp rsp = {0,}; int ret = -1; + char msg[1024] = {0,}; if (-1 == req->rpc_status) { goto out; @@ -1533,10 +1768,23 @@ gf_cli3_1_sync_volume_cbk (struct rpc_req *req, struct iovec *iov, gf_log ("cli", GF_LOG_DEBUG, "Received resp to sync"); if (rsp.op_ret && strcmp (rsp.op_errstr, "")) - cli_out ("%s", rsp.op_errstr); + snprintf (msg, sizeof (msg), "%s", rsp.op_errstr); else - cli_out ("volume sync: %s", + snprintf (msg, sizeof (msg), "volume sync: %s", (rsp.op_ret) ? "unsuccessful": "successful"); + +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("volSync", msg, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + + cli_out ("%s", msg); ret = rsp.op_ret; out: @@ -3063,6 +3311,17 @@ gf_cli3_1_gsync_set_cbk (struct rpc_req *req, struct iovec *iov, if (ret) goto out; +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_dict ("volGeoRep", dict, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + if (rsp.op_ret) { cli_out ("%s", rsp.op_errstr ? rsp.op_errstr : GEOREP" command unsuccessful"); @@ -3388,6 +3647,18 @@ gf_cli3_1_profile_volume_cbk (struct rpc_req *req, struct iovec *iov, dict->extra_stdfree = rsp.dict.dict_val; } +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_vol_profile (dict, rsp.op_ret, + rsp.op_errno, + rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + ret = dict_get_str (dict, "volname", &volname); if (ret) goto out; @@ -3573,6 +3844,20 @@ gf_cli3_1_top_volume_cbk (struct rpc_req *req, struct iovec *iov, ret = 0; goto out; } + +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_vol_top (dict, rsp.op_ret, + rsp.op_errno, + rsp.op_errstr); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + } + goto out; + } +#endif + ret = dict_get_int32 (dict, "count", &brick_count); if (ret) goto out; @@ -4708,7 +4993,6 @@ gf_cli3_1_status_cbk (struct rpc_req *req, struct iovec *iov, ret = 0; goto out; } - ret = dict_get_int32 (dict, "count", &count); if (ret) goto out; @@ -4717,6 +5001,18 @@ gf_cli3_1_status_cbk (struct rpc_req *req, struct iovec *iov, goto out; } +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_vol_status (dict, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + } + goto out; + } +#endif + status.brick = GF_CALLOC (1, PATH_MAX + 256, gf_common_mt_strdup); switch (cmd & GF_CLI_STATUS_MASK) { @@ -5086,6 +5382,17 @@ gf_cli3_1_heal_volume_cbk (struct rpc_req *req, struct iovec *iov, if (local) dict = local->dict; +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_dict ("volHeal", dict, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + ret = dict_get_str (dict, "volname", &volname); if (ret) { gf_log (THIS->name, GF_LOG_ERROR, "failed to get volname"); @@ -5167,6 +5474,7 @@ gf_cli3_1_statedump_volume_cbk (struct rpc_req *req, struct iovec *iov, { gf_cli_rsp rsp = {0,}; int ret = -1; + char msg[1024] = {0,}; if (-1 == req->rpc_status) goto out; @@ -5178,10 +5486,22 @@ gf_cli3_1_statedump_volume_cbk (struct rpc_req *req, struct iovec *iov, } gf_log ("cli", GF_LOG_DEBUG, "Recieved response to statedump"); if (rsp.op_ret) - cli_out ("%s", rsp.op_errstr); + snprintf (msg, sizeof(msg), "%s", rsp.op_errstr); else - cli_out ("Volume statedump sucessful"); + snprintf (msg, sizeof (msg), "Volume statedump sucessful"); +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("volStatedump", msg, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + + cli_out ("%s", msg); ret = rsp.op_ret; out: @@ -5227,6 +5547,99 @@ out: return ret; } +int32_t +gf_cli3_1_list_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + int ret = -1; + gf_cli_rsp rsp = {0,}; + dict_t *dict = NULL; + int vol_count = 0;; + char *volname = NULL; + char key[1024] = {0,}; + int i = 0; + + if (-1 == req->rpc_status) + goto out; + ret = xdr_to_generic (*iov, &rsp, + (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (THIS->name, GF_LOG_ERROR, "XDR decoding failed"); + goto out; + } + + dict = dict_new (); + if (!dict) { + ret = -1; + goto out; + } + + ret = dict_unserialize (rsp.dict.dict_val, rsp.dict.dict_len, &dict); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to allocate memory"); + goto out; + } + +#if (HAVE_LIB_XML) + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_vol_list (dict, rsp.op_ret, rsp.op_errno, + rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } +#endif + if (rsp.op_ret) + cli_out ("%s", rsp.op_errstr); + else { + ret = dict_get_int32 (dict, "count", &vol_count); + if (ret) + goto out; + + if (vol_count == 0) { + cli_out ("No volumes present in cluster"); + goto out; + } + cli_out ("%d %s present in cluster", vol_count, + ((vol_count == 1) ? "volume" : "volumes")); + + for (i = 0; i < vol_count; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d", i); + ret = dict_get_str (dict, key, &volname); + if (ret) + goto out; + cli_out ("\t%d. %s", i+1, volname); + } + } + + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + return ret; +} + +int32_t +gf_cli3_1_list_volume (call_frame_t *frame, xlator_t *this, void *data) +{ + int ret = -1; + gf_cli_req req = {{0,}}; + + if (!frame || !this) + goto out; + + ret = cli_cmd_submit (&req, frame, cli_rpc_prog, + GLUSTER_CLI_LIST_VOLUME, NULL, + this, gf_cli3_1_list_volume_cbk, + (xdrproc_t)xdr_gf_cli_req); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + struct rpc_clnt_procedure gluster_cli_actors[GLUSTER_CLI_MAXVALUE] = { [GLUSTER_CLI_NULL] = {"NULL", NULL }, [GLUSTER_CLI_PROBE] = {"PROBE_QUERY", gf_cli3_1_probe}, @@ -5261,6 +5674,7 @@ struct rpc_clnt_procedure gluster_cli_actors[GLUSTER_CLI_MAXVALUE] = { [GLUSTER_CLI_UMOUNT] = {"UMOUNT", gf_cli3_1_umount}, [GLUSTER_CLI_HEAL_VOLUME] = {"HEAL_VOLUME", gf_cli3_1_heal_volume}, [GLUSTER_CLI_STATEDUMP_VOLUME] = {"STATEDUMP_VOLUME", gf_cli3_1_statedump_volume}, + [GLUSTER_CLI_LIST_VOLUME] = {"LIST_VOLUME", gf_cli3_1_list_volume}, }; struct rpc_clnt_program cli_prog = { diff --git a/cli/src/cli-xml-output.c b/cli/src/cli-xml-output.c new file mode 100644 index 000000000..3e081277b --- /dev/null +++ b/cli/src/cli-xml-output.c @@ -0,0 +1,2258 @@ +/* + Copyright (c) 2010-2011 Gluster, Inc. <http://www.gluster.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <cli.h> +#include <cli1-xdr.h> + +#if (HAVE_LIB_XML) + +#include <libxml/encoding.h> +#include <libxml/xmlwriter.h> + +#define XML_RET_CHECK_AND_GOTO(ret, label) do { \ + if (ret < 0) { \ + ret = -1; \ + goto label; \ + } \ + }while (0); \ + +int +cli_begin_xml_output (xmlTextWriterPtr *writer, xmlBufferPtr *buf) +{ + int ret = -1; + + *buf = xmlBufferCreateSize (8192); + if (buf == NULL) { + ret = -1; + goto out; + } + xmlBufferSetAllocationScheme (*buf, XML_BUFFER_ALLOC_DOUBLEIT); + + *writer = xmlNewTextWriterMemory (*buf, 0); + if (writer == NULL) { + ret = -1; + goto out; + } + + ret = xmlTextWriterStartDocument (*writer, "1.0", "UTF-8", "yes"); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <cliOutput> */ + ret = xmlTextWriterStartElement (*writer, (xmlChar *)"cliOutput"); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_end_xml_output (xmlTextWriterPtr writer, xmlBufferPtr buf) +{ + int ret = -1; + + /* </cliOutput> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterEndDocument (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + cli_out ("%s", (const char *)buf->content); + + xmlFreeTextWriter (writer); + xmlBufferFree (buf); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_common (xmlTextWriterPtr writer, int op_ret, int op_errno, + char *op_errstr) +{ + int ret = -1; + + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"opRet", + "%d", op_ret); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"opErrno", + "%d", op_errno); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"opErrstr", + "%s", op_errstr); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_str (char *op, char *str, int op_ret, int op_errno, + char *op_errstr) +{ + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlBufferPtr buf = NULL; + + ret = cli_begin_xml_output (&writer, &buf); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"cliOp", + "%s", op); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"output", + "%s", str); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_end_xml_output (writer, buf); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +void +cli_xml_output_data_pair (dict_t *this, char *key, data_t *value, + void *data) +{ + int ret = -1; + xmlTextWriterPtr *writer = NULL; + + writer = (xmlTextWriterPtr *)data; + + ret = xmlTextWriterWriteFormatElement (*writer, (xmlChar *)key, + "%s", value->data); + + return; +} + +int +cli_xml_output_dict ( char *op, dict_t *dict, int op_ret, int op_errno, + char *op_errstr) +{ + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlBufferPtr buf = NULL; + + ret = cli_begin_xml_output (&writer, &buf); + if (ret) + goto out; + /* <"op"> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)op); + XML_RET_CHECK_AND_GOTO (ret, out); + + dict_foreach (dict, cli_xml_output_data_pair, &writer); + + /* </"op"> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_end_xml_output (writer, buf); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_common (xmlTextWriterPtr writer, dict_t *dict, + int brick_index, int *online) +{ + int ret = -1; + char *hostname = NULL; + char *path = NULL; + int port = 0; + int status = 0; + int pid = 0; + char key[1024] = {0,}; + + snprintf (key, sizeof (key), "brick%d.hostname", brick_index); + ret = dict_get_str (dict, key, &hostname); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"hostname", + "%s", hostname); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.path", brick_index); + ret = dict_get_str (dict, key, &path); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"path", + "%s", path); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.port", brick_index); + ret = dict_get_int32 (dict, key, &port); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"port", + "%d", port); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.status", brick_index); + ret = dict_get_int32 (dict, key, &status); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"status", + "%d", status); + XML_RET_CHECK_AND_GOTO (ret, out); + *online = status; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.pid", brick_index); + ret = dict_get_int32 (dict, key, &pid); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"pid", + "%d", pid); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_detail (xmlTextWriterPtr writer, dict_t *dict, + int brick_index) +{ + int ret = -1; + uint64_t size_total = 0; + uint64_t size_free = 0; + char *device = NULL; + uint64_t block_size = 0; + char *mnt_options = NULL; + char *fs_name = NULL; + char *inode_size = NULL; + uint64_t inodes_total = 0; + uint64_t inodes_free = 0; + char key[1024] = {0,}; + + snprintf (key, sizeof (key), "brick%d.total", brick_index); + ret = dict_get_uint64 (dict, key, &size_total); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"sizeTotal", + "%"PRIu64, size_total); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.free", brick_index); + ret = dict_get_uint64 (dict, key, &size_free); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"sizeFree", + "%"PRIu64, size_free); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.device", brick_index); + ret = dict_get_str (dict, key, &device); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"device", + "%s", device); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.block_size", brick_index); + ret = dict_get_uint64 (dict, key, &block_size); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"blockSize", + "%"PRIu64, block_size); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mnt_options", brick_index); + ret = dict_get_str (dict, key, &mnt_options); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"mntOptions", + "%s", mnt_options); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.fs_name", brick_index); + ret = dict_get_str (dict, key, &fs_name); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"fsName", + "%s", fs_name); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* inode details are only available for ext 2/3/4 & xfs */ + if (!IS_EXT_FS(fs_name) || strcmp (fs_name, "xfs")) { + ret = 0; + goto out; + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.inode_size", brick_index); + ret = dict_get_str (dict, key, &inode_size); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"inodeSize", + "%s", fs_name); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.total_inodes", brick_index); + ret = dict_get_uint64 (dict, key, &inodes_total); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"inodesTotal", + "%"PRIu64, inodes_total); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.free_inodes", brick_index); + ret = dict_get_uint64 (dict, key, &inodes_free); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"inodesFree", + "%"PRIu64, inodes_free); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_mempool (xmlTextWriterPtr writer, dict_t *dict, + char *prefix) +{ + int ret = -1; + int mempool_count = 0; + char *name = NULL; + int hotcount = 0; + int coldcount = 0; + uint64_t paddedsizeof = 0; + uint64_t alloccount = 0; + int maxalloc = 0; + char key[1024] = {0,}; + int i = 0; + + /* <mempool> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"mempool"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%s.mempool-count", prefix); + ret = dict_get_int32 (dict, key, &mempool_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"count", + "%d", mempool_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < mempool_count; i++) { + /* <pool> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"pool"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.name", prefix, i); + ret = dict_get_str (dict, key, &name); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"name", + "%s", name); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.hotcount", prefix, i); + ret = dict_get_int32 (dict, key, &hotcount); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"hotCount", + "%d", hotcount); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.coldcount", prefix, i); + ret = dict_get_int32 (dict, key, &coldcount); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"coldCount", + "%d", coldcount); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.paddedsizeof", + prefix, i); + ret = dict_get_uint64 (dict, key, &paddedsizeof); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"padddedSizeOf", "%"PRIu64, + paddedsizeof); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.alloccount", prefix, i); + ret = dict_get_uint64 (dict, key, &alloccount); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"allocCount", + "%"PRIu64, alloccount); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pool%d.max_alloc", prefix, i); + ret = dict_get_int32 (dict, key, &maxalloc); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"maxAlloc", + "%d", maxalloc); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </pool> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </mempool> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_mem (xmlTextWriterPtr writer, dict_t *dict, + int brick_index) +{ + int ret = -1; + int arena = 0; + int ordblks = 0; + int smblks = 0; + int hblks = 0; + int hblkhd = 0; + int usmblks = 0; + int fsmblks = 0; + int uordblks = 0; + int fordblks = 0; + int keepcost = 0; + char key[1024] = {0,}; + + /* <memStatus> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"memStatus"); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <mallinfo> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"mallinfo"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "brick%d.mallinfo.arena", brick_index); + ret = dict_get_int32 (dict, key, &arena); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"arena", + "%d", arena); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.ordblks", brick_index); + ret = dict_get_int32 (dict, key, &ordblks); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"ordblks", + "%d", ordblks); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.smblks", brick_index); + ret = dict_get_int32 (dict, key, &smblks); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"smblks", + "%d", smblks); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.hblks", brick_index); + ret = dict_get_int32 (dict, key, &hblks); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"hblks", + "%d", hblks); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.hblkhd", brick_index); + ret = dict_get_int32 (dict, key, &hblkhd); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"hblkhd", + "%d", hblkhd); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.usmblks", brick_index); + ret = dict_get_int32 (dict, key, &usmblks); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"usmblks", + "%d", usmblks); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.fsmblks", brick_index); + ret = dict_get_int32 (dict, key, &fsmblks); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"fsmblks", + "%d", fsmblks); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.uordblks", brick_index); + ret = dict_get_int32 (dict, key, &uordblks); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"uordblks", + "%d", uordblks); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.fordblks", brick_index); + ret = dict_get_int32 (dict, key, &fordblks); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"fordblks", + "%d", fordblks); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mallinfo.keepcost", brick_index); + ret = dict_get_int32 (dict, key, &keepcost); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"keepcost", + "%d", keepcost); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </mallinfo> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d", brick_index); + ret = cli_xml_output_vol_status_mempool (writer, dict, key); + if (ret) + goto out; + + /* </memStatus> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_clients (xmlTextWriterPtr writer, dict_t *dict, + int brick_index) +{ + int ret = -1; + int client_count = 0; + char *hostname = NULL; + uint64_t bytes_read = 0; + uint64_t bytes_write = 0; + char key[1024] = {0,}; + int i = 0; + + /* <clientsStatus> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"clientsStatus"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "brick%d.clientcount", brick_index); + ret = dict_get_int32 (dict, key, &client_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"clientCount", + "%d", client_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < client_count; i++) { + /* <client> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"client"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.client%d.hostname", + brick_index, i); + ret = dict_get_str (dict, key, &hostname); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"hostname", + "%s", hostname); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.client%d.bytesread", + brick_index, i); + ret = dict_get_uint64 (dict, key, &bytes_read); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"bytesRead", + "%"PRIu64, bytes_read); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.client%d.byteswrite", + brick_index, i); + ret = dict_get_uint64 (dict, key, &bytes_write); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"bytesWrite", + "%"PRIu64, bytes_write); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </client> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </clientsStatus> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_inode_entry (xmlTextWriterPtr writer, dict_t *dict, + char *prefix) +{ + int ret = -1; + char *gfid = NULL; + uint64_t nlookup = 0; + uint32_t ref = 0; + int ia_type = 0; + char key[1024] = {0,}; + + /* <inode> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"inode"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%s.gfid", prefix); + ret = dict_get_str (dict, key, &gfid); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"gfid", + "%s", gfid); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key,0, sizeof (key)); + snprintf (key, sizeof (key), "%s.nlookup", prefix); + ret = dict_get_uint64 (dict, key, &nlookup); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"nLookup", + "%"PRIu64, nlookup); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key,0, sizeof (key)); + snprintf (key, sizeof (key), "%s.ref", prefix); + ret = dict_get_uint32 (dict, key, &ref); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"ref", + "%"PRIu32, ref); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key,0, sizeof (key)); + snprintf (key, sizeof (key), "%s.ia_type", prefix); + ret = dict_get_int32 (dict, key, &ia_type); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"iaType", + "%d", ia_type); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </inode> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_itable (xmlTextWriterPtr writer, dict_t *dict, + char *prefix) +{ + int ret = -1; + uint32_t active_size = 0; + uint32_t lru_size = 0; + uint32_t purge_size = 0; + char key[1024] = {0,}; + int i = 0; + + snprintf (key, sizeof (key), "%s.active_size", prefix); + ret = dict_get_uint32 (dict, key, &active_size); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"activeSize", + "%"PRIu32, active_size); + XML_RET_CHECK_AND_GOTO (ret, out); + if (active_size != 0) { + /* <active> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"active"); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < active_size; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.active%d", prefix, i); + ret = cli_xml_output_vol_status_inode_entry + (writer, dict, key); + if (ret) + goto out; + } + /* </active> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.lru_size", prefix); + ret = dict_get_uint32 (dict, key, &lru_size); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"lruSize", + "%"PRIu32, lru_size); + XML_RET_CHECK_AND_GOTO (ret, out); + if (lru_size != 0) { + /* <lru> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"lru"); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < lru_size; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.lru%d", prefix, i); + ret = cli_xml_output_vol_status_inode_entry + (writer, dict, key); + if (ret) + goto out; + } + /* </lru> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.purge_size", prefix); + ret = dict_get_uint32 (dict, key, &purge_size); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"purgeSize", + "%"PRIu32, purge_size); + XML_RET_CHECK_AND_GOTO (ret, out); + if (purge_size != 0) { + /* <purge> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"purge"); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < purge_size; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.purge%d", prefix, i); + ret = cli_xml_output_vol_status_inode_entry + (writer, dict, key); + if (ret) + goto out; + } + /* </purge> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_inode (xmlTextWriterPtr writer, dict_t *dict, + int brick_index) +{ + int ret = -1; + int conn_count = 0; + char key[1024] = {0,}; + int i = 0; + + /* <inodeStatus> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"inodeStatus"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "brick%d.conncount", brick_index); + ret = dict_get_int32 (dict, key, &conn_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"connections", + "%d", conn_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < conn_count; i++) { + /* <connection> */ + ret = xmlTextWriterStartElement (writer, + (xmlChar *)"connection"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.conn%d.itable", + brick_index, i); + ret = cli_xml_output_vol_status_itable (writer, dict, key); + if (ret) + goto out; + + /* </connection> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </inodeStatus> */ + ret= xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_fdtable (xmlTextWriterPtr writer, dict_t *dict, + char *prefix) +{ + int ret = -1; + int refcount = 0; + uint32_t maxfds = 0; + int firstfree = 0; + int openfds = 0; + int fd_pid = 0; + int fd_refcount = 0; + int fd_flags = 0; + char key[1024] = {0,}; + int i = 0; + + /* <fdTable> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"fdTable"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%s.refcount", prefix); + ret = dict_get_int32 (dict, key, &refcount); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"refCount", + "%d", refcount); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.maxfds", prefix); + ret = dict_get_uint32 (dict, key, &maxfds); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"maxFds", + "%"PRIu32, maxfds); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.firstfree", prefix); + ret = dict_get_int32 (dict, key, &firstfree); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"firstFree", + "%d", firstfree); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.openfds", prefix); + ret = dict_get_int32 (dict, key, &openfds); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"openFds", + "%d", openfds); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < maxfds; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.fdentry%d.pid", prefix, i); + ret = dict_get_int32 (dict, key, &fd_pid); + if (ret) + continue; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.fdentry%d.refcount", + prefix, i); + ret = dict_get_int32 (dict, key, &fd_refcount); + if (ret) + continue; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.fdentry%d.flags", prefix, i); + ret = dict_get_int32 (dict, key, &fd_flags); + if (ret) + continue; + + /* <fd> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"fd"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"entry", + "%d", i+1); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"pid", + "%d", fd_pid); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"refCount", + "%d", fd_refcount); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"flags", + "%d", fd_flags); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </fd> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </fdTable> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_fd (xmlTextWriterPtr writer, dict_t *dict, + int brick_index) +{ + int ret = -1; + int conn_count = 0; + char key[1024] = {0,}; + int i = 0; + + /* <fdStatus> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"fdStatus"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "brick%d.conncount", brick_index); + ret = dict_get_int32 (dict, key, &conn_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"connections", + "%d", conn_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < conn_count; i++) { + /* <connection> */ + ret = xmlTextWriterStartElement (writer, + (xmlChar *)"connection"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.conn%d.fdtable", + brick_index, i); + ret = cli_xml_output_vol_status_fdtable (writer, dict, key); + if (ret) + goto out; + + /* </connection> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </fdStatus> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_callframe (xmlTextWriterPtr writer, dict_t *dict, + char *prefix) +{ + int ret = -1; + int ref_count = 0; + char *translator = NULL; + int complete = 0; + char *parent = NULL; + char *wind_from = NULL; + char *wind_to = NULL; + char *unwind_from = NULL; + char *unwind_to = NULL; + char key[1024] = {0,}; + + /* <callFrame> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"callFrame"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%s.refcount", prefix); + ret = dict_get_int32 (dict, key, &ref_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"refCount", + "%d", ref_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.translator", prefix); + ret = dict_get_str (dict, key, &translator); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"translator", + "%s", translator); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.complete", prefix); + ret = dict_get_int32 (dict, key, &complete); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"complete", + "%d", complete); + XML_RET_CHECK_AND_GOTO (ret ,out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.parent", prefix); + ret = dict_get_str (dict, key, &parent); + if (!ret) { + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"parent", + "%s", parent); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.windfrom", prefix); + ret = dict_get_str (dict, key, &wind_from); + if (!ret) { + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"windFrom", + "%s", wind_from); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.windto", prefix); + ret = dict_get_str (dict, key, &wind_to); + if (!ret) { + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"windTo", + "%s", wind_to); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.unwindfrom", prefix); + ret = dict_get_str (dict, key, &unwind_from); + if (!ret) { + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"unwindFrom", + "%s", unwind_from); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.unwindto", prefix); + ret = dict_get_str (dict, key, &unwind_to); + if (!ret) { + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"unwindTo", + "%s", unwind_to); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </callFrame> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_callstack (xmlTextWriterPtr writer, dict_t *dict, + char *prefix) +{ + int ret = -1; + int uid = 0; + int gid = 0; + int pid = 0; + uint64_t unique = 0; + int frame_count = 0; + char key[1024] = {0,}; + int i = 0; + + /* <callStack> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"callStack"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%s.uid", prefix); + ret = dict_get_int32 (dict, key, &uid); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"uid", + "%d", uid); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.gid", prefix); + ret = dict_get_int32 (dict, key, &gid); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"gid", + "%d", gid); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pid", prefix); + ret = dict_get_int32 (dict, key, &pid); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"pid", + "%d", pid); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.unique", prefix); + ret = dict_get_uint64 (dict, key, &unique); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"unique", + "%"PRIu64, unique); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.count", prefix); + ret = dict_get_int32 (dict, key, &frame_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"frameCount", + "%d", frame_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < frame_count; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.frame%d", prefix, i); + ret = cli_xml_output_vol_status_callframe (writer, dict, + key); + if (ret) + goto out; + } + + /* </callStack> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_callpool (xmlTextWriterPtr writer, dict_t *dict, + int brick_index) +{ + int ret = -1; + int call_count = 0; + char key[1024] = {0,}; + int i = 0; + + /* <callpoolStatus> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"callpoolStatus"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "brick%d.callpool.count", brick_index); + ret = dict_get_int32 (dict, key, &call_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"count", + "%d", call_count); + + for (i = 0; i < call_count; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.callpool.stack%d", + brick_index, i); + ret = cli_xml_output_vol_status_callstack (writer, dict, + key); + if (ret) + goto out; + } + + /* </callpoolStatus> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status (dict_t *dict, int op_ret, int op_errno, + char *op_errstr) +{ + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlBufferPtr buf = NULL; + char *volname = NULL; + int brick_count = 0; + uint32_t cmd = GF_CLI_STATUS_NONE; + int online = 0; + int i; + + ret = cli_begin_xml_output (&writer, &buf); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <volStatus> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volStatus"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"volName", + "%s", volname); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_int32 (dict, "count", &brick_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"brickCount", + "%d", brick_count); + if (ret) + goto out; + + ret = dict_get_uint32 (dict, "cmd", &cmd); + if (ret) + goto out; + + for (i = 0; i < brick_count; i++) { + /* <brick> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"brick"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_xml_output_vol_status_common (writer, dict, i, + &online); + if (ret) + goto out; + + switch (cmd & GF_CLI_STATUS_MASK) { + case GF_CLI_STATUS_DETAIL: + ret = cli_xml_output_vol_status_detail (writer, + dict, i); + if (ret) + goto out; + break; + + case GF_CLI_STATUS_MEM: + if (online) { + ret = cli_xml_output_vol_status_mem + (writer, dict, i); + if (ret) + goto out; + } + break; + + case GF_CLI_STATUS_CLIENTS: + if (online) { + ret = cli_xml_output_vol_status_clients + (writer, dict, i); + if (ret) + goto out; + } + break; + + case GF_CLI_STATUS_INODE: + if (online) { + ret = cli_xml_output_vol_status_inode + (writer, dict, i); + if (ret) + goto out; + } + break; + + case GF_CLI_STATUS_FD: + if (online) { + ret = cli_xml_output_vol_status_fd + (writer, dict, i); + if (ret) + goto out; + } + break; + + case GF_CLI_STATUS_CALLPOOL: + if (online) { + ret = cli_xml_output_vol_status_callpool + (writer, dict, i); + if (ret) + goto out; + } + break; + + default: + goto out; + + } + /* </brick> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </volStatus> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + ret = cli_end_xml_output (writer, buf); + if (ret) + goto out; + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_top_rw_perf (xmlTextWriterPtr writer, dict_t *dict, + int brick_index, int member_index) +{ + int ret = -1; + char *filename = NULL; + uint64_t throughput = 0; + long int time_sec = 0; + long int time_usec = 0; + struct tm *tm = NULL; + char timestr[256] = {0,}; + char key[1024] = {0,}; + + /* <file> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"file"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%d-filename-%d", brick_index, + member_index); + ret = dict_get_str (dict, key, &filename); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"filename", + "%s", filename); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-value-%d", brick_index, member_index); + ret = dict_get_uint64 (dict, key, &throughput); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"count", + "%"PRIu64, throughput); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-time-sec-%d", brick_index, + member_index); + ret = dict_get_int32 (dict, key, (int32_t *)&time_sec); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-time-usec-%d", brick_index, + member_index); + ret = dict_get_int32 (dict, key, (int32_t *)&time_usec); + if (ret) + goto out; + + tm = localtime (&time_sec); + if (!tm) { + ret = -1; + goto out; + } + strftime (timestr, sizeof (timestr), "%Y-%m-%d %H:%M:%S", tm); + snprintf (timestr + strlen (timestr), + sizeof (timestr) - strlen (timestr), + ".%"GF_PRI_SUSECONDS, time_usec); + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"time", + "%s", timestr); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </file> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_top_other (xmlTextWriterPtr writer, dict_t *dict, + int brick_index, int member_index) +{ + int ret = -1; + char *filename = NULL; + uint64_t count = 0; + char key[1024] = {0,}; + + /* <file> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"file"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%d-filename-%d", brick_index, + member_index); + ret = dict_get_str (dict, key, &filename); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"filename", + "%s", filename); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-value-%d", brick_index, member_index); + ret = dict_get_uint64 (dict, key, &count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"count", + "%"PRIu64, count); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </file> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_top (dict_t *dict, int op_ret, int op_errno, + char *op_errstr) +{ + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlBufferPtr buf = NULL; + int brick_count = 0; + int top_op = GF_CLI_TOP_NONE; + char *brick_name = NULL; + int members = 0; + uint64_t current_open = 0; + uint64_t max_open = 0; + char *max_open_time = NULL; + double throughput = 0.0; + double time_taken = 0.0; + char key[1024] = {0,}; + int i = 0; + int j = 0; + + ret = cli_begin_xml_output (&writer, &buf); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <volTop> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volTop"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_int32 (dict, "count", &brick_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"brickCount", + "%d", brick_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_int32 (dict, "1-top-op", &top_op); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"topOp", + "%d", top_op); + XML_RET_CHECK_AND_GOTO (ret, out); + + while (i < brick_count) { + i++; + + /* <brick> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"brick"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-brick", i); + ret = dict_get_str (dict, key, &brick_name); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"name", + "%s", brick_name); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key , sizeof (key), "%d-members", i); + ret = dict_get_int32 (dict, key, &members); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"members", + "%d", members); + XML_RET_CHECK_AND_GOTO (ret, out); + + switch (top_op) { + case GF_CLI_TOP_OPEN: + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-current-open", i); + ret = dict_get_uint64 (dict, key, ¤t_open); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"currentOpen", "%"PRIu64, + current_open); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-max-open", i); + ret = dict_get_uint64 (dict, key, &max_open); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"maxOpen", "%"PRIu64, + max_open); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-max-openfd-time", i); + ret = dict_get_str (dict, key, &max_open_time); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"maxOpenTime", "%s", + max_open_time); + XML_RET_CHECK_AND_GOTO (ret, out); + + case GF_CLI_TOP_READ: + case GF_CLI_TOP_WRITE: + case GF_CLI_TOP_OPENDIR: + case GF_CLI_TOP_READDIR: + if (!members) + continue; + + break; + + case GF_CLI_TOP_READ_PERF: + case GF_CLI_TOP_WRITE_PERF: + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-throughput", i); + ret = dict_get_double (dict, key, &throughput); + if (!ret) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-time", i); + ret = dict_get_double (dict, key, &time_taken); + } + + if (!ret) { + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"throughput", + "%f", throughput); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"timeTaken", + "%f", time_taken); + } + + if (!members) + continue; + + break; + + default: + ret = -1; + goto out; + } + + for (j = 1; j <= members; j++) { + if (top_op == GF_CLI_TOP_READ_PERF || + top_op == GF_CLI_TOP_WRITE_PERF) { + ret = cli_xml_output_vol_top_rw_perf + (writer, dict, i, j); + } else { + ret = cli_xml_output_vol_top_other + (writer, dict, i, j); + } + if (ret) + goto out; + } + + + /* </brick> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </volTop> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + ret = cli_end_xml_output (writer, buf); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_profile_stats (xmlTextWriterPtr writer, dict_t *dict, + int brick_index, int interval) +{ + int ret = -1; + uint64_t read_count = 0; + uint64_t write_count = 0; + uint64_t hits = 0; + double avg_latency = 0.0; + double max_latency = 0.0; + double min_latency = 0.0; + uint64_t duration = 0; + uint64_t total_read = 0; + uint64_t total_write = 0; + char key[1024] = {0}; + int i = 0; + + /* <cumulativeStats> || <intervalStats> */ + if (interval == -1) + ret = xmlTextWriterStartElement (writer, + (xmlChar *)"cumulativeStats"); + else + ret = xmlTextWriterStartElement (writer, + (xmlChar *)"intervalStats"); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <blockStats> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"blockStats"); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < 32; i++) { + /* <block> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"block"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"size", "%"PRIu32, (1 << i)); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-read-%d", brick_index, + interval, (1 << i)); + ret = dict_get_uint64 (dict, key, &read_count); + if (ret) + read_count = 0; + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"reads", "%"PRIu64, read_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-write-%d", brick_index, + interval, (1 << i)); + ret = dict_get_uint64 (dict, key, &write_count); + if (ret) + write_count = 0; + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"writes", "%"PRIu64, write_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </block> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </blockStats> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <fopStats> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"fopStats"); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < GF_FOP_MAXVALUE; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-%d-hits", brick_index, + interval, i); + ret = dict_get_uint64 (dict, key, &hits); + if (ret) + goto cont; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-%d-avglatency", brick_index, + interval, i); + ret = dict_get_double (dict, key, &avg_latency); + if (ret) + goto cont; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-%d-minlatency", brick_index, + interval, i); + ret = dict_get_double (dict, key, &min_latency); + if (ret) + goto cont; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-%d-maxlatency", brick_index, + interval, i); + ret = dict_get_double (dict, key, &max_latency); + if (ret) + goto cont; + + /* <fop> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"fop"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"name","%s", gf_fop_list[i]); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"hits", "%"PRIu64, hits); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"avgLatency", "%f", avg_latency); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"minLatency", "%f", min_latency); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"maxLatency", "%f", max_latency); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </fop> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +cont: + hits = 0; + avg_latency = 0.0; + min_latency = 0.0; + max_latency = 0.0; + } + + /* </fopStats> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-duration", brick_index, interval); + ret = dict_get_uint64 (dict, key, &duration); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"duration", + "%"PRIu64, duration); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-total-read", brick_index, interval); + ret = dict_get_uint64 (dict, key, &total_read); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"totalRead", + "%"PRIu64, total_read); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-%d-total-write", brick_index, interval); + ret = dict_get_uint64 (dict, key, &total_write); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"totalWrite", + "%"PRIu64, total_write); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </cumulativeStats> || </intervalStats> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_profile (dict_t *dict, int op_ret, int op_errno, + char *op_errstr) +{ + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlBufferPtr buf = NULL; + char *volname = NULL; + int op = GF_CLI_STATS_NONE; + int brick_count = 0; + char *brick_name = NULL; + int interval = 0; + char key[1024] = {0,}; + int i = 0; + + ret = cli_begin_xml_output (&writer, &buf); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <volProfile> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volProfile"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"volname", + "%s", volname); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_int32 (dict, "op", &op); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"profileOp", + "%d", op); + XML_RET_CHECK_AND_GOTO (ret, out); + + if (op != GF_CLI_STATS_INFO) + goto cont; + + ret = dict_get_int32 (dict, "count", &brick_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"brickCount", + "%d", brick_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + while (i < brick_count) { + i++; + + /* <brick> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"brick"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%d-brick", i); + ret = dict_get_str (dict, key, &brick_name); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"brickName", "%s", brick_name); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%d-cumulative", i); + ret = dict_get_int32 (dict, key, &interval); + if (ret == 0) { + ret = cli_xml_output_vol_profile_stats + (writer, dict, i, interval); + if (ret) + goto out; + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%d-interval", i); + ret = dict_get_int32 (dict, key, &interval); + if (ret == 0) { + ret = cli_xml_output_vol_profile_stats + (writer, dict, i, interval); + if (ret) + goto out; + } + + /* </brick> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + +cont: + /* </volProfile> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_end_xml_output (writer, buf); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; + +} + +int +cli_xml_output_vol_list (dict_t *dict, int op_ret, int op_errno, + char *op_errstr) +{ + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlBufferPtr buf = NULL; + int count = 0; + char *volname = NULL; + char key[1024] = {0,}; + int i = 0; + + ret = cli_begin_xml_output (&writer, &buf); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <volList> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volList"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_int32 (dict, "count", &count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"count", + "%d", count); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < count; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d", i); + ret = dict_get_str (dict, key, &volname); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"volume", + "%s", volname); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </volList> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_end_xml_output (writer, buf); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_info_option (xmlTextWriterPtr writer, char *substr, + char *optstr, char *valstr) +{ + int ret = -1; + char *ptr1 = NULL; + char *ptr2 = NULL; + + ptr1 = substr; + ptr2 = optstr; + + while (ptr1) { + if (*ptr1 != *ptr2) + break; + ptr1++; + ptr2++; + if (!ptr1) + goto out; + if (!ptr2) + goto out; + } + if (*ptr2 == '\0') + goto out; + + /* <option> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"option"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"name", + "%s", ptr2); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"value", + "%s", valstr); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </option> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_info_options (xmlTextWriterPtr writer, dict_t *dict, + char *prefix) +{ + int ret = -1; + int opt_count = 0; + data_pair_t *pairs = 0; + data_t *value = 0; + char *ptr = NULL; + char key[1024] = {0,}; + int i = 0; + + pairs = dict->members_list; + if (!pairs) { + ret = -1; + goto out; + } + + snprintf (key, sizeof (key), "%s.opt_count", prefix); + ret = dict_get_int32 (dict, key, &opt_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"optCount", + "%d", opt_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + while (i < opt_count) { + snprintf (key, sizeof (key), "%s.option.", prefix); + while (pairs) { + ptr = strstr (pairs->key, "option."); + if (ptr) { + value = pairs->value; + if (!value) { + ret = -1; + goto out; + } + ret = cli_xml_output_vol_info_option + (writer, key, pairs->key, value->data); + if (ret) + goto out; + } + pairs = pairs->next; + } + i++; + } +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_info (dict_t *dict, int op_ret, int op_errno, + char *op_errstr) +{ + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlBufferPtr buf = NULL; + int count = 0; + char *volname = NULL; + char *volume_id = NULL; + int type = 0; + int status = 0; + int brick_count = 0; + int dist_count = 0; + int stripe_count = 0; + int replica_count = 0; + int transport = 0; + char *brick = NULL; + char key[1024] = {0,}; + int i = 0; + int j = 1; + + ret = cli_begin_xml_output (&writer, &buf); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <volInfo> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volInfo"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_int32 (dict, "count", &count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"count", + "%d", count); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (i = 0; i < count; i++) { + /* <volume> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volume"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.name", i); + ret = dict_get_str (dict, key, &volname); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"name", + "%s", volname); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.volume_id", i); + ret = dict_get_str (dict, key, &volume_id); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"id", + "%s", volume_id); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.type", i); + ret = dict_get_int32 (dict, key, &type); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"type", + "%d", type); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.status", i); + ret = dict_get_int32 (dict, key, &status); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"status", + "%d", status); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.brick_count", i); + ret = dict_get_int32 (dict, key, &brick_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"brickCount", + "%d", brick_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.dist_count", i); + ret = dict_get_int32 (dict, key, &dist_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"distCount", + "%d", dist_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.stripe_count", i); + ret = dict_get_int32 (dict, key, &stripe_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"stripeCount", + "%d", stripe_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.replica_count", i); + ret = dict_get_int32 (dict, key, &replica_count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"replicaCount", + "%d", replica_count); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.transport", i); + ret = dict_get_int32 (dict, key, &transport); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"transport", + "%d", transport); + XML_RET_CHECK_AND_GOTO (ret, out); + + while (j <= brick_count) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.brick%d", i, j); + ret = dict_get_str (dict, key, &brick); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"brick", "%s", brick); + XML_RET_CHECK_AND_GOTO (ret, out); + j++; + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d", i); + ret = cli_xml_output_vol_info_options (writer, dict, key); + if (ret) + goto out; + + /* </volume> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </volInfo> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_end_xml_output (writer, buf); + if (ret) + goto out; +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} +#endif diff --git a/cli/src/cli.c b/cli/src/cli.c index 78c76c53f..70204cabe 100644 --- a/cli/src/cli.c +++ b/cli/src/cli.c @@ -327,6 +327,11 @@ cli_opt_parse (char *opt, struct cli_state *state) exit (0); } + if (strcmp (opt, "xml") == 0) { + state->mode |= GLUSTER_MODE_XML; + return 0; + } + oarg = strtail (opt, "mode="); if (oarg) { if (strcmp (oarg, "script") == 0) { diff --git a/cli/src/cli.h b/cli/src/cli.h index e091e7004..0814065a0 100644 --- a/cli/src/cli.h +++ b/cli/src/cli.h @@ -46,7 +46,7 @@ enum argp_option_keys { #define GLUSTER_MODE_SCRIPT (1 << 0) #define GLUSTER_MODE_ERR_FATAL (1 << 1) - +#define GLUSTER_MODE_XML (1 << 2) struct cli_state; struct cli_cmd_word; struct cli_cmd_tree; @@ -264,4 +264,28 @@ cli_get_detail_status (dict_t *dict, int i, cli_volume_status_t *status); void cli_print_line (int len); + +#if (HAVE_LIB_XML) +int +cli_xml_output_str (char *op, char *str, int op_ret, int op_errno, char *op_errstr); + +int +cli_xml_output_dict (char *op, dict_t *dict, int op_ret, int op_errno, char *op_errstr); + +int +cli_xml_output_vol_top (dict_t *dict, int op_ret, int op_errno, char *op_errstr); + +int +cli_xml_output_vol_profile (dict_t *dict, int op_ret, int op_errno, char *op_errstr); + +int +cli_xml_output_vol_status (dict_t *dict, int op_ret, int op_errno, char *op_errstr); + +int +cli_xml_output_vol_list (dict_t *dict, int op_ret, int op_errno, char *op_errstr); + +int +cli_xml_output_vol_info (dict_t *dict, int op_ret, int op_errno, char *op_errstr); +#endif + #endif /* __CLI_H__ */ diff --git a/rpc/rpc-lib/src/protocol-common.h b/rpc/rpc-lib/src/protocol-common.h index 971996091..08f6194a9 100644 --- a/rpc/rpc-lib/src/protocol-common.h +++ b/rpc/rpc-lib/src/protocol-common.h @@ -154,6 +154,7 @@ enum gluster_cli_procnum { GLUSTER_CLI_UMOUNT, GLUSTER_CLI_HEAL_VOLUME, GLUSTER_CLI_STATEDUMP_VOLUME, + GLUSTER_CLI_LIST_VOLUME, GLUSTER_CLI_MAXVALUE, }; diff --git a/xlators/mgmt/glusterd/src/glusterd-handler.c b/xlators/mgmt/glusterd/src/glusterd-handler.c index f2980e7ef..257930720 100644 --- a/xlators/mgmt/glusterd/src/glusterd-handler.c +++ b/xlators/mgmt/glusterd/src/glusterd-handler.c @@ -883,6 +883,64 @@ out: return ret; } +int +glusterd_handle_cli_list_volume (rpcsvc_request_t *req) +{ + int ret = -1; + dict_t *dict = NULL; + glusterd_conf_t *priv = NULL; + glusterd_volinfo_t *volinfo = NULL; + int count = 0; + char key[1024] = {0,}; + gf_cli_rsp rsp = {0,}; + + GF_ASSERT (req); + + priv = THIS->private; + GF_ASSERT (priv); + + dict = dict_new (); + if (!dict) + goto out; + + list_for_each_entry (volinfo, &priv->volumes, vol_list) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d", count); + ret = dict_set_str (dict, key, volinfo->volname); + if (ret) + goto out; + count++; + } + + ret = dict_set_int32 (dict, "count", count); + if (ret) + goto out; + + ret = dict_allocate_and_serialize (dict, &rsp.dict.dict_val, + (size_t *)&rsp.dict.dict_len); + if (ret) + goto out; + + ret = 0; + +out: + rsp.op_ret = ret; + if (ret) + rsp.op_errstr = "Error listing volumes"; + else + rsp.op_errstr = ""; + + ret = glusterd_submit_reply (req, &rsp, NULL, 0, NULL, + (xdrproc_t)xdr_gf_cli_rsp); + + if (dict) + dict_unref (dict); + + glusterd_friend_sm (); + glusterd_op_sm (); + return ret; +} + int32_t glusterd_op_begin (rpcsvc_request_t *req, glusterd_op_t op, void *ctx) { @@ -2839,6 +2897,7 @@ rpcsvc_actor_t gd_svc_cli_actors[] = { [GLUSTER_CLI_UMOUNT] = { "UMOUNT", GLUSTER_CLI_UMOUNT, glusterd_handle_umount, NULL, NULL, 1}, [GLUSTER_CLI_HEAL_VOLUME] = { "HEAL_VOLUME", GLUSTER_CLI_HEAL_VOLUME, glusterd_handle_cli_heal_volume, NULL, NULL, 0}, [GLUSTER_CLI_STATEDUMP_VOLUME] = {"STATEDUMP_VOLUME", GLUSTER_CLI_STATEDUMP_VOLUME, glusterd_handle_cli_statedump_volume, NULL, NULL, 0}, + [GLUSTER_CLI_LIST_VOLUME] = {"LIST_VOLUME", GLUSTER_CLI_LIST_VOLUME, glusterd_handle_cli_list_volume, NULL, NULL, 0}, }; struct rpcsvc_program gd_svc_cli_prog = { diff --git a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c index 21d8ab0ac..275e1ccff 100644 --- a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c +++ b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c @@ -146,6 +146,7 @@ glusterd_op_send_cli_response (glusterd_op_t op, int32_t op_ret, case GD_OP_REPLACE_BRICK: case GD_OP_STATUS_VOLUME: case GD_OP_SET_VOLUME: + case GD_OP_LIST_VOLUME: { /*nothing specific to be done*/ break; diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h index 3c671da64..bea15689b 100644 --- a/xlators/mgmt/glusterd/src/glusterd.h +++ b/xlators/mgmt/glusterd/src/glusterd.h @@ -77,6 +77,7 @@ typedef enum glusterd_op_ { GD_OP_REBALANCE, GD_OP_HEAL_VOLUME, GD_OP_STATEDUMP_VOLUME, + GD_OP_LIST_VOLUME, GD_OP_MAX, } glusterd_op_t; @@ -541,6 +542,8 @@ int glusterd_handle_defrag_start (glusterd_volinfo_t *volinfo, char *op_errstr, size_t len, int cmd, defrag_cbk_fn_t cbk); int glusterd_handle_cli_heal_volume (rpcsvc_request_t *req); +int glusterd_handle_cli_list_volume (rpcsvc_request_t *req); + /* op-sm functions */ int glusterd_op_stage_heal_volume (dict_t *dict, char **op_errstr); int glusterd_op_heal_volume (dict_t *dict, char **op_errstr); |