diff options
Diffstat (limited to 'cli/src/cli-xml-output.c')
| -rw-r--r-- | cli/src/cli-xml-output.c | 1895 |
1 files changed, 1694 insertions, 201 deletions
diff --git a/cli/src/cli-xml-output.c b/cli/src/cli-xml-output.c index 6a22b249b..d8884d44b 100644 --- a/cli/src/cli-xml-output.c +++ b/cli/src/cli-xml-output.c @@ -1,24 +1,52 @@ /* - 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/>. + Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ +#include <stdlib.h> +#include "cli.h" +#include "cli1-xdr.h" +#include "run.h" +#include "compat.h" +#include "syscall.h" + + +enum gf_task_types { + GF_TASK_TYPE_REBALANCE, + GF_TASK_TYPE_REMOVE_BRICK +}; + +/* + * IMPORTANT NOTE: + * All exported functions in this file which use libxml need use a + * #if (HAVE_LIB_XML), #else, #endif + * For eg, + * int exported_func () { + * #if (HAVE_LIB_XML) + * <Stuff using libxml> + * #else + * return 0; + * #endif + * } + * + * All other functions, which are called internally within this file need to be + * within #if (HAVE_LIB_XML), #endif statements + * For eg, + * #if (HAVE_LIB_XML) + * int internal_func () + * { + * } + * #endif + * + * Following the above formate ensures that all xml related code is compliled + * only when libxml2 is present, and also keeps the rest of the codebase free + * of #if (HAVE_LIB_XML) + */ -#include <cli.h> -#include <cli1-xdr.h> #if (HAVE_LIB_XML) @@ -30,21 +58,16 @@ ret = -1; \ goto label; \ } \ - }while (0); \ + else \ + ret = 0; \ + }while (0) \ int -cli_begin_xml_output (xmlTextWriterPtr *writer, xmlBufferPtr *buf) +cli_begin_xml_output (xmlTextWriterPtr *writer, xmlDocPtr *doc) { int ret = -1; - *buf = xmlBufferCreateSize (8192); - if (buf == NULL) { - ret = -1; - goto out; - } - xmlBufferSetAllocationScheme (*buf, XML_BUFFER_ALLOC_DOUBLEIT); - - *writer = xmlNewTextWriterMemory (*buf, 0); + *writer = xmlNewTextWriterDoc (doc, 0); if (writer == NULL) { ret = -1; goto out; @@ -63,7 +86,7 @@ out: } int -cli_end_xml_output (xmlTextWriterPtr writer, xmlBufferPtr buf) +cli_end_xml_output (xmlTextWriterPtr writer, xmlDocPtr doc) { int ret = -1; @@ -74,10 +97,13 @@ cli_end_xml_output (xmlTextWriterPtr writer, xmlBufferPtr buf) ret = xmlTextWriterEndDocument (writer); XML_RET_CHECK_AND_GOTO (ret, out); - cli_out ("%s", (const char *)buf->content); + + /* Dump xml document to stdout and pretty format it */ + xmlSaveFormatFileEnc ("-", doc, "UTF-8", 1); xmlFreeTextWriter (writer); - xmlBufferFree (buf); + xmlFreeDoc (doc); + out: gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); return ret; @@ -98,23 +124,25 @@ cli_xml_output_common (xmlTextWriterPtr writer, int op_ret, int op_errno, XML_RET_CHECK_AND_GOTO (ret, out); ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"opErrstr", - "%s", op_errstr); + "%s", op_errstr); XML_RET_CHECK_AND_GOTO (ret, out); out: gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); return ret; } +#endif int cli_xml_output_str (char *op, char *str, int op_ret, int op_errno, char *op_errstr) { +#if (HAVE_LIB_XML) int ret = -1; xmlTextWriterPtr writer = NULL; - xmlBufferPtr buf = NULL; + xmlDocPtr doc = NULL; - ret = cli_begin_xml_output (&writer, &buf); + ret = cli_begin_xml_output (&writer, &doc); if (ret) goto out; @@ -122,22 +150,32 @@ cli_xml_output_str (char *op, char *str, int op_ret, int op_errno, if (ret) goto out; - ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"cliOp", - "%s", op); - XML_RET_CHECK_AND_GOTO (ret, out); + if (op) { + 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); + if (str) { + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"output", + "%s", str); + XML_RET_CHECK_AND_GOTO (ret, out); + } - ret = cli_end_xml_output (writer, buf); + ret = cli_end_xml_output (writer, doc); out: gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); return ret; +#else + return 0; +#endif } -void +#if (HAVE_LIB_XML) +int cli_xml_output_data_pair (dict_t *this, char *key, data_t *value, void *data) { @@ -149,39 +187,52 @@ cli_xml_output_data_pair (dict_t *this, char *key, data_t *value, ret = xmlTextWriterWriteFormatElement (*writer, (xmlChar *)key, "%s", value->data); - return; + return ret; } +#endif int cli_xml_output_dict ( char *op, dict_t *dict, int op_ret, int op_errno, char *op_errstr) { +#if (HAVE_LIB_XML) int ret = -1; xmlTextWriterPtr writer = NULL; - xmlBufferPtr buf = NULL; + xmlDocPtr doc = NULL; + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; - ret = cli_begin_xml_output (&writer, &buf); + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); 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); + if (dict) + 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); + ret = cli_end_xml_output (writer, doc); out: gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); return ret; +#else + return 0; +#endif } +#if (HAVE_LIB_XML) int cli_xml_output_vol_status_common (xmlTextWriterPtr writer, dict_t *dict, - int brick_index, int *online) + int brick_index, int *online, + gf_boolean_t *node_present) { int ret = -1; char *hostname = NULL; @@ -193,8 +244,12 @@ cli_xml_output_vol_status_common (xmlTextWriterPtr writer, dict_t *dict, snprintf (key, sizeof (key), "brick%d.hostname", brick_index); ret = dict_get_str (dict, key, &hostname); - if (ret) + if (ret) { + *node_present = _gf_false; goto out; + } + *node_present = _gf_true; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"hostname", "%s", hostname); XML_RET_CHECK_AND_GOTO (ret, out); @@ -209,15 +264,6 @@ cli_xml_output_vol_status_common (xmlTextWriterPtr writer, dict_t *dict, 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) @@ -228,6 +274,27 @@ cli_xml_output_vol_status_common (xmlTextWriterPtr writer, dict_t *dict, *online = status; 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; + + /* If the process is either offline or doesn't provide a port (shd) + * port = "N/A" + * else print the port number of the process. + */ + + if (*online == 1 && port != 0) + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"port", + "%d", port); + else + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"port", + "%s", "N/A"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); snprintf (key, sizeof (key), "brick%d.pid", brick_index); ret = dict_get_int32 (dict, key, &pid); if (ret) @@ -1264,44 +1331,305 @@ out: gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); return ret; } +#endif int -cli_xml_output_vol_status (dict_t *dict, int op_ret, int op_errno, - char *op_errstr) +cli_xml_output_vol_status_begin (cli_local_t *local, int op_ret, int op_errno, + char *op_errstr) { +#if (HAVE_LIB_XML) 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); + ret = cli_begin_xml_output (&(local->writer), &(local->doc)); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_xml_output_common (local->writer, op_ret, op_errno, + op_errstr); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <volStatus> */ + ret = xmlTextWriterStartElement (local->writer, + (xmlChar *) "volStatus"); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <volumes> */ + ret = xmlTextWriterStartElement (local->writer, (xmlChar *)"volumes"); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +int +cli_xml_output_vol_status_end (cli_local_t *local) +{ +#if (HAVE_LIB_XML) + int ret = -1; + + /* </volumes> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </volStatus> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO(ret, out); + + ret = cli_end_xml_output (local->writer, local->doc); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +#if (HAVE_LIB_XML) +int +cli_xml_output_remove_brick_task_params (xmlTextWriterPtr writer, dict_t *dict, + char *prefix) +{ + int ret = -1; + char key[1024] = {0,}; + int count = 0; + int i = 0; + char *brick = NULL; + + /* <params> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"params"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%s.count", prefix); + ret = dict_get_int32 (dict, key, &count); if (ret) goto out; - ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + for (i = 1; i <= count; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.brick%d", prefix, i); + 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); + brick = NULL; + } + + /* </param> */ + ret = xmlTextWriterEndElement (writer); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_replace_brick_task_params (xmlTextWriterPtr writer, dict_t *dict, + char *prefix) +{ + + int ret = -1; + char key[1024] = {0,}; + char *brick = NULL; + + /* <params> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"params"); + XML_RET_CHECK_AND_GOTO (ret, out); + + snprintf (key, sizeof (key), "%s.src-brick", prefix); + ret = dict_get_str (dict, key, &brick); if (ret) goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"srcBrick", + "%s", brick); + XML_RET_CHECK_AND_GOTO (ret, out); - /* <volStatus> */ - ret = xmlTextWriterStartElement (writer, (xmlChar *)"volStatus"); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.dst-brick", prefix); + ret = dict_get_str (dict, key, &brick); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"dstBrick", + "%s", brick); + XML_RET_CHECK_AND_GOTO (ret, out); + + + /* </param> */ + ret = xmlTextWriterEndElement (writer); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_tasks (cli_local_t *local, dict_t *dict) { + int ret = -1; + char *task_type = NULL; + char *task_id_str = NULL; + int status = 0; + int tasks = 0; + char key[1024] = {0,}; + int i = 0; + + /* <tasks> */ + ret = xmlTextWriterStartElement (local->writer, (xmlChar *)"tasks"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_int32 (dict, "tasks", &tasks); + if (ret) + goto out; + + for (i = 0; i < tasks; i++) { + /* <task> */ + ret = xmlTextWriterStartElement (local->writer, + (xmlChar *)"task"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "task%d.type", i); + ret = dict_get_str (dict, key, &task_type); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"type", + "%s", task_type); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "task%d.id", i); + ret = dict_get_str (dict, key, &task_id_str); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"id", + "%s", task_id_str); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "task%d.status", i); + ret = dict_get_int32 (dict, key, &status); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"status", + "%d", status); + XML_RET_CHECK_AND_GOTO (ret, out); + + if (!strcmp (task_type, "Replace brick")) { + if (status) { + status = GF_DEFRAG_STATUS_COMPLETE; + } else { + status = GF_DEFRAG_STATUS_STARTED; + } + } + + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"statusStr", + "%s", + cli_vol_task_status_str[status]); + + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "task%d", i); + if (!strcmp (task_type, "Replace brick")) { + ret = cli_xml_output_replace_brick_task_params + (local->writer, dict, key); + if (ret) + goto out; + } else if (!strcmp (task_type, "Remove brick")) { + ret = cli_xml_output_remove_brick_task_params + (local->writer, dict, key); + if (ret) + goto out; + } + + + /* </task> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </tasks> */ + ret = xmlTextWriterEndElement (local->writer); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +cli_xml_output_vol_status_tasks_detail (cli_local_t *local, dict_t *dict) +{ + int ret = -1; + char *volname = NULL; + + /*<volume>*/ + ret = xmlTextWriterStartElement (local->writer, (xmlChar *)"volume"); 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); + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"volName", "%s", + volname); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_xml_output_vol_status_tasks (local, dict); + if (ret) + goto out; + + /* </volume> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + return ret; +} +#endif + +int +cli_xml_output_vol_status (cli_local_t *local, dict_t *dict) +{ +#if (HAVE_LIB_XML) + int ret = -1; + char *volname = NULL; + int brick_count = 0; + int brick_index_max = -1; + int other_count = 0; + int index_max = 0; + uint32_t cmd = GF_CLI_STATUS_NONE; + int online = 0; + gf_boolean_t node_present = _gf_true; + int i; + + + /* <volume> */ + ret = xmlTextWriterStartElement (local->writer, (xmlChar *)"volume"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (local->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); + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"nodeCount", "%d", + brick_count); if (ret) goto out; @@ -1309,19 +1637,33 @@ cli_xml_output_vol_status (dict_t *dict, int op_ret, int op_errno, if (ret) goto out; - for (i = 0; i < brick_count; i++) { - /* <brick> */ - ret = xmlTextWriterStartElement (writer, (xmlChar *)"brick"); + ret = dict_get_int32 (dict, "brick-index-max", &brick_index_max); + if (ret) + goto out; + ret = dict_get_int32 (dict, "other-count", &other_count); + if (ret) + goto out; + + index_max = brick_index_max + other_count; + + for (i = 0; i <= index_max; i++) { + /* <node> */ + ret = xmlTextWriterStartElement (local->writer, + (xmlChar *)"node"); XML_RET_CHECK_AND_GOTO (ret, out); - ret = cli_xml_output_vol_status_common (writer, dict, i, - &online); - if (ret) - goto out; + ret = cli_xml_output_vol_status_common (local->writer, dict, i, + &online, &node_present); + if (ret) { + if (node_present) + goto out; + else + continue; + } switch (cmd & GF_CLI_STATUS_MASK) { case GF_CLI_STATUS_DETAIL: - ret = cli_xml_output_vol_status_detail (writer, + ret = cli_xml_output_vol_status_detail (local->writer, dict, i); if (ret) goto out; @@ -1330,7 +1672,7 @@ cli_xml_output_vol_status (dict_t *dict, int op_ret, int op_errno, case GF_CLI_STATUS_MEM: if (online) { ret = cli_xml_output_vol_status_mem - (writer, dict, i); + (local->writer, dict, i); if (ret) goto out; } @@ -1339,7 +1681,7 @@ cli_xml_output_vol_status (dict_t *dict, int op_ret, int op_errno, case GF_CLI_STATUS_CLIENTS: if (online) { ret = cli_xml_output_vol_status_clients - (writer, dict, i); + (local->writer, dict, i); if (ret) goto out; } @@ -1348,7 +1690,7 @@ cli_xml_output_vol_status (dict_t *dict, int op_ret, int op_errno, case GF_CLI_STATUS_INODE: if (online) { ret = cli_xml_output_vol_status_inode - (writer, dict, i); + (local->writer, dict, i); if (ret) goto out; } @@ -1357,7 +1699,7 @@ cli_xml_output_vol_status (dict_t *dict, int op_ret, int op_errno, case GF_CLI_STATUS_FD: if (online) { ret = cli_xml_output_vol_status_fd - (writer, dict, i); + (local->writer, dict, i); if (ret) goto out; } @@ -1366,47 +1708,54 @@ cli_xml_output_vol_status (dict_t *dict, int op_ret, int op_errno, case GF_CLI_STATUS_CALLPOOL: if (online) { ret = cli_xml_output_vol_status_callpool - (writer, dict, i); + (local->writer, dict, i); if (ret) goto out; } break; - default: - goto out; + break; } - /* </brick> */ - ret = xmlTextWriterEndElement (writer); + /* </node> */ + ret = xmlTextWriterEndElement (local->writer); XML_RET_CHECK_AND_GOTO (ret, out); } - /* </volStatus> */ - ret = xmlTextWriterEndElement (writer); - XML_RET_CHECK_AND_GOTO (ret, out); + /* Tasks are only present when a normal volume status call is done on a + * single volume or on all volumes + */ + if (((cmd & GF_CLI_STATUS_MASK) == GF_CLI_STATUS_NONE) && + (cmd & (GF_CLI_STATUS_VOL|GF_CLI_STATUS_ALL))) { + ret = cli_xml_output_vol_status_tasks (local, dict); + if (ret) + goto out; + } - gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); - ret = cli_end_xml_output (writer, buf); - if (ret) - goto out; + /* </volume> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); out: gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); return ret; +#else + return 0; +#endif } +#if (HAVE_LIB_XML) 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,}; + int ret = -1; + char *filename = NULL; + uint64_t throughput = 0; + long int time_sec = 0; + long int time_usec = 0; + char timestr[256] = {0,}; + char key[1024] = {0,}; /* <file> */ ret = xmlTextWriterStartElement (writer, (xmlChar *)"file"); @@ -1444,14 +1793,9 @@ cli_xml_output_vol_top_rw_perf (xmlTextWriterPtr writer, dict_t *dict, 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); + gf_time_fmt (timestr, sizeof timestr, time_sec, gf_timefmt_FT); snprintf (timestr + strlen (timestr), - sizeof (timestr) - strlen (timestr), + sizeof timestr - strlen (timestr), ".%"GF_PRI_SUSECONDS, time_usec); ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"time", "%s", timestr); @@ -1505,14 +1849,16 @@ out: gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); return ret; } +#endif int cli_xml_output_vol_top (dict_t *dict, int op_ret, int op_errno, char *op_errstr) { +#if (HAVE_LIB_XML) int ret = -1; xmlTextWriterPtr writer = NULL; - xmlBufferPtr buf = NULL; + xmlDocPtr doc = NULL; int brick_count = 0; int top_op = GF_CLI_TOP_NONE; char *brick_name = NULL; @@ -1526,7 +1872,7 @@ cli_xml_output_vol_top (dict_t *dict, int op_ret, int op_errno, int i = 0; int j = 0; - ret = cli_begin_xml_output (&writer, &buf); + ret = cli_begin_xml_output (&writer, &doc); if (ret) goto out; @@ -1615,8 +1961,6 @@ cli_xml_output_vol_top (dict_t *dict, int op_ret, int op_errno, case GF_CLI_TOP_WRITE: case GF_CLI_TOP_OPENDIR: case GF_CLI_TOP_READDIR: - if (!members) - continue; break; @@ -1642,9 +1986,6 @@ cli_xml_output_vol_top (dict_t *dict, int op_ret, int op_errno, "%f", time_taken); } - if (!members) - continue; - break; default: @@ -1674,13 +2015,17 @@ cli_xml_output_vol_top (dict_t *dict, int op_ret, int op_errno, /* </volTop> */ ret = xmlTextWriterEndElement (writer); XML_RET_CHECK_AND_GOTO (ret, out); - ret = cli_end_xml_output (writer, buf); + ret = cli_end_xml_output (writer, doc); out: gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); return ret; +#else + return 0; +#endif } +#if (HAVE_LIB_XML) int cli_xml_output_vol_profile_stats (xmlTextWriterPtr writer, dict_t *dict, int brick_index, int interval) @@ -1856,14 +2201,16 @@ out: gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); return ret; } +#endif int cli_xml_output_vol_profile (dict_t *dict, int op_ret, int op_errno, char *op_errstr) { +#if (HAVE_LIB_XML) int ret = -1; xmlTextWriterPtr writer = NULL; - xmlBufferPtr buf = NULL; + xmlDocPtr doc = NULL; char *volname = NULL; int op = GF_CLI_STATS_NONE; int brick_count = 0; @@ -1872,7 +2219,7 @@ cli_xml_output_vol_profile (dict_t *dict, int op_ret, int op_errno, char key[1024] = {0,}; int i = 0; - ret = cli_begin_xml_output (&writer, &buf); + ret = cli_begin_xml_output (&writer, &doc); if (ret) goto out; @@ -1952,26 +2299,29 @@ cont: ret = xmlTextWriterEndElement (writer); XML_RET_CHECK_AND_GOTO (ret, out); - ret = cli_end_xml_output (writer, buf); + ret = cli_end_xml_output (writer, doc); out: gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); return ret; - +#else + return 0; +#endif } int cli_xml_output_vol_list (dict_t *dict, int op_ret, int op_errno, char *op_errstr) { +#if (HAVE_LIB_XML) int ret = -1; xmlTextWriterPtr writer = NULL; - xmlBufferPtr buf = NULL; + xmlDocPtr doc = NULL; int count = 0; char *volname = NULL; char key[1024] = {0,}; int i = 0; - ret = cli_begin_xml_output (&writer, &buf); + ret = cli_begin_xml_output (&writer, &doc); if (ret) goto out; @@ -2006,12 +2356,16 @@ cli_xml_output_vol_list (dict_t *dict, int op_ret, int op_errno, ret = xmlTextWriterEndElement (writer); XML_RET_CHECK_AND_GOTO (ret, out); - ret = cli_end_xml_output (writer, buf); + ret = cli_end_xml_output (writer, doc); out: gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); return ret; +#else + return 0; +#endif } +#if (HAVE_LIB_XML) int cli_xml_output_vol_info_option (xmlTextWriterPtr writer, char *substr, char *optstr, char *valstr) @@ -2056,23 +2410,44 @@ out: return ret; } +struct tmp_xml_option_logger { + char *key; + xmlTextWriterPtr writer; +}; + +static int +_output_vol_info_option (dict_t *d, char *k, data_t *v, + void *data) +{ + int ret = 0; + char *ptr = NULL; + struct tmp_xml_option_logger *tmp = NULL; + + tmp = data; + + ptr = strstr (k, "option."); + if (!ptr) + goto out; + + if (!v) { + ret = -1; + goto out; + } + ret = cli_xml_output_vol_info_option (tmp->writer, tmp->key, k, + v->data); + +out: + 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; - } + struct tmp_xml_option_logger tmp = {0,}; snprintf (key, sizeof (key), "%s.opt_count", prefix); ret = dict_get_int32 (dict, key, &opt_count); @@ -2082,40 +2457,35 @@ cli_xml_output_vol_info_options (xmlTextWriterPtr writer, dict_t *dict, "%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++; - } + /* <options> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"options"); + XML_RET_CHECK_AND_GOTO (ret, out); + snprintf (key, sizeof (key), "%s.option.", prefix); + + tmp.key = key; + tmp.writer = writer; + ret = dict_foreach (dict, _output_vol_info_option, &tmp); + if (ret) + goto out; + + /* </options> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); out: gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); return ret; } +#endif int -cli_xml_output_vol_info (dict_t *dict, int op_ret, int op_errno, - char *op_errstr) +cli_xml_output_vol_info (cli_local_t *local, dict_t *dict) { - int ret = -1; - xmlTextWriterPtr writer = NULL; - xmlBufferPtr buf = NULL; +#if (HAVE_LIB_XML) + int ret = 0; int count = 0; char *volname = NULL; char *volume_id = NULL; + char *uuid = NULL; int type = 0; int status = 0; int brick_count = 0; @@ -2127,29 +2497,18 @@ cli_xml_output_vol_info (dict_t *dict, int op_ret, int op_errno, 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); + char *caps = NULL; + int k __attribute__((unused)) = 0; + char *snap_volume = NULL; 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"); + ret = xmlTextWriterStartElement (local->writer, + (xmlChar *)"volume"); XML_RET_CHECK_AND_GOTO (ret, out); memset (key, 0, sizeof (key)); @@ -2157,7 +2516,7 @@ cli_xml_output_vol_info (dict_t *dict, int op_ret, int op_errno, ret = dict_get_str (dict, key, &volname); if (ret) goto out; - ret = xmlTextWriterWriteFormatElement (writer, + ret = xmlTextWriterWriteFormatElement (local->writer, (xmlChar *)"name", "%s", volname); XML_RET_CHECK_AND_GOTO (ret, out); @@ -2167,29 +2526,36 @@ cli_xml_output_vol_info (dict_t *dict, int op_ret, int op_errno, ret = dict_get_str (dict, key, &volume_id); if (ret) goto out; - ret = xmlTextWriterWriteFormatElement (writer, + ret = xmlTextWriterWriteFormatElement (local->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); + snprintf (key, sizeof (key), "volume%d.status", i); + ret = dict_get_int32 (dict, key, &status); if (ret) goto out; - ret = xmlTextWriterWriteFormatElement (writer, - (xmlChar *)"type", - "%d", type); + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"status", + "%d", status); 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); + snprintf (key, sizeof (key), "volume%d.snap_volume", i); + ret = dict_get_str (dict, key, &snap_volume); if (ret) goto out; - ret = xmlTextWriterWriteFormatElement (writer, - (xmlChar *)"status", - "%d", status); + if (snap_volume) { + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"snapVol", + "%s", snap_volume); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + ret =xmlTextWriterWriteFormatElement + (local->writer, (xmlChar *)"statusStr", "%s", + cli_vol_status_str[status]); XML_RET_CHECK_AND_GOTO (ret, out); memset (key, 0, sizeof (key)); @@ -2197,7 +2563,7 @@ cli_xml_output_vol_info (dict_t *dict, int op_ret, int op_errno, ret = dict_get_int32 (dict, key, &brick_count); if (ret) goto out; - ret = xmlTextWriterWriteFormatElement (writer, + ret = xmlTextWriterWriteFormatElement (local->writer, (xmlChar *)"brickCount", "%d", brick_count); XML_RET_CHECK_AND_GOTO (ret, out); @@ -2207,7 +2573,7 @@ cli_xml_output_vol_info (dict_t *dict, int op_ret, int op_errno, ret = dict_get_int32 (dict, key, &dist_count); if (ret) goto out; - ret = xmlTextWriterWriteFormatElement (writer, + ret = xmlTextWriterWriteFormatElement (local->writer, (xmlChar *)"distCount", "%d", dist_count); XML_RET_CHECK_AND_GOTO (ret, out); @@ -2217,7 +2583,7 @@ cli_xml_output_vol_info (dict_t *dict, int op_ret, int op_errno, ret = dict_get_int32 (dict, key, &stripe_count); if (ret) goto out; - ret = xmlTextWriterWriteFormatElement (writer, + ret = xmlTextWriterWriteFormatElement (local->writer, (xmlChar *)"stripeCount", "%d", stripe_count); XML_RET_CHECK_AND_GOTO (ret, out); @@ -2227,53 +2593,1180 @@ cli_xml_output_vol_info (dict_t *dict, int op_ret, int op_errno, ret = dict_get_int32 (dict, key, &replica_count); if (ret) goto out; - ret = xmlTextWriterWriteFormatElement (writer, + ret = xmlTextWriterWriteFormatElement (local->writer, (xmlChar *)"replicaCount", "%d", replica_count); 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; + /* For Distributed-(stripe,replicate,stipe-replicate) types */ + if ((type > 0) && (dist_count < brick_count)) + type += 3; + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"type", + "%d", type); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"typeStr", + "%s", + cli_vol_type_str[type]); + 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, + ret = xmlTextWriterWriteFormatElement (local->writer, (xmlChar *)"transport", "%d", transport); XML_RET_CHECK_AND_GOTO (ret, out); +#ifdef HAVE_BD_XLATOR + /* <xlators> */ + ret = xmlTextWriterStartElement (local->writer, + (xmlChar *)"xlators"); + XML_RET_CHECK_AND_GOTO (ret, out); + + for (k = 0; ; k++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key),"volume%d.xlator%d", i, k); + ret = dict_get_str (dict, key, &caps); + if (ret) + break; + + /* <xlator> */ + ret = xmlTextWriterStartElement (local->writer, + (xmlChar *)"xlator"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement + (local->writer, (xmlChar *)"name", "%s", caps); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <capabilities> */ + ret = xmlTextWriterStartElement (local->writer, + (xmlChar *) + "capabilities"); + XML_RET_CHECK_AND_GOTO (ret, out); + + j = 0; + for (j = 0; ;j++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), + "volume%d.xlator%d.caps%d", i, k, j); + ret = dict_get_str (dict, key, &caps); + if (ret) + break; + ret = xmlTextWriterWriteFormatElement + (local->writer, (xmlChar *)"capability", + "%s", caps); + XML_RET_CHECK_AND_GOTO (ret, out); + } + /* </capabilities> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + /* </xlator> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + ret = xmlTextWriterFullEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + /* </xlators> */ +#else + caps = 0; /* Avoid compiler warnings when BD not enabled */ +#endif + j = 1; + + /* <bricks> */ + ret = xmlTextWriterStartElement (local->writer, + (xmlChar *)"bricks"); + XML_RET_CHECK_AND_GOTO (ret, out); while (j <= brick_count) { + ret = xmlTextWriterStartElement + (local->writer, (xmlChar *)"brick"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "volume%d.brick%d.uuid", + i, j); + ret = dict_get_str (dict, key, &uuid); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatAttribute + (local->writer, (xmlChar *)"uuid", "%s", + uuid); + XML_RET_CHECK_AND_GOTO (ret, out); + 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); + ret = xmlTextWriterWriteFormatString + (local->writer, "%s", brick); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </brick> */ + ret = xmlTextWriterEndElement (local->writer); XML_RET_CHECK_AND_GOTO (ret, out); + j++; } + /* </bricks> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); memset (key, 0, sizeof (key)); snprintf (key, sizeof (key), "volume%d", i); - ret = cli_xml_output_vol_info_options (writer, dict, key); + ret = cli_xml_output_vol_info_options (local->writer, dict, + key); if (ret) goto out; /* </volume> */ - ret = xmlTextWriterEndElement (writer); + ret = xmlTextWriterEndElement (local->writer); XML_RET_CHECK_AND_GOTO (ret, out); } + if (volname) { + GF_FREE (local->get_vol.volname); + local->get_vol.volname = gf_strdup (volname); + local->vol_count += count; + } +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +int +cli_xml_output_vol_info_begin (cli_local_t *local, int op_ret, int op_errno, + char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + + GF_ASSERT (local); + + ret = cli_begin_xml_output (&(local->writer), &(local->doc)); + if (ret) + goto out; + + ret = cli_xml_output_common (local->writer, op_ret, op_errno, + op_errstr); + if (ret) + goto out; + + /* <volInfo> */ + ret = xmlTextWriterStartElement (local->writer, (xmlChar *)"volInfo"); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <volumes> */ + ret = xmlTextWriterStartElement (local->writer, (xmlChar *)"volumes"); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* Init vol count */ + local->vol_count = 0; + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +int +cli_xml_output_vol_info_end (cli_local_t *local) +{ +#if (HAVE_LIB_XML) + int ret = -1; + + GF_ASSERT (local); + + ret = xmlTextWriterWriteFormatElement (local->writer, + (xmlChar *)"count", + "%d", local->vol_count); + + /* </volumes> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + /* </volInfo> */ + ret = xmlTextWriterEndElement (local->writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_end_xml_output (local->writer, local->doc); + +out: + gf_log ("cli", GF_LOG_ERROR, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +int +cli_xml_output_vol_quota_limit_list (char *volname, char *limit_list, + int op_ret, int op_errno, + char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + int64_t size = 0; + int64_t limit_value = 0; + int i = 0; + int j = 0; + int k = 0; + int len = 0; + char *size_str = NULL; + char path[PATH_MAX] = {0,}; + char ret_str[1024] = {0,}; + char value[1024] = {0,}; + char mountdir[] = "/tmp/mountXXXXXX"; + char abspath[PATH_MAX] = {0,}; + runner_t runner = {0,}; + + GF_ASSERT (volname); + GF_ASSERT (limit_list); + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <volQuota> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volQuota"); + XML_RET_CHECK_AND_GOTO (ret, out); + + if (!limit_list) + goto cont; + + len = strlen (limit_list); + if (len == 0) + goto cont; + + if (mkdtemp (mountdir) == NULL) { + gf_log ("cli", GF_LOG_ERROR, "failed to create a temporary" + " mount directory"); + ret = -1; + goto out; + } + + ret = runcmd (SBIN_DIR"/glusterfs", "-s", "localhost", + "--volfile-id", volname, "-l", + DEFAULT_LOG_FILE_DIRECTORY"/quota-list-xml.log", + mountdir, NULL); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "failed to mount glusterfs client"); + ret = -1; + goto rm_dir; + } + + while (i < len) { + j = 0; + k = 0; + size = 0; + + while (limit_list[i] != ':') + path[k++] = limit_list[i++]; + path[k] = '\0'; + + i++; + + while (limit_list[i] != ',' && limit_list[i] != '\0') + value[j++] = limit_list[i++]; + i++; + + snprintf (abspath, sizeof (abspath), "%s/%s", mountdir, path); + ret = sys_lgetxattr (abspath, "trusted.limit.list", + (void *)ret_str, 4096); + if (ret >= 0) { + sscanf (ret_str, "%"SCNd64",%"SCNd64, &size, + &limit_value); + size_str = gf_uint64_2human_readable ((uint64_t)size); + } + + /* <quota> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"quota"); + XML_RET_CHECK_AND_GOTO (ret, unmount); + + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"path", "%s", path); + XML_RET_CHECK_AND_GOTO (ret, unmount); + + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"limit", "%s", value); + XML_RET_CHECK_AND_GOTO (ret, unmount); + + if (size_str) { + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"size", "%s", size_str); + XML_RET_CHECK_AND_GOTO (ret, unmount); + GF_FREE (size_str); + } else { + ret = xmlTextWriterWriteFormatElement + (writer, (xmlChar *)"size", "%"PRId64, size); + XML_RET_CHECK_AND_GOTO (ret, unmount); + } + + /* </quota> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, unmount); + + } + +unmount: + runinit (&runner); + runner_add_args (&runner, "umount", +#if GF_LINUX_HOST_OS + "-l", +#endif + mountdir, NULL); + ret = runner_run_reuse (&runner); + if (ret) + runner_log (&runner, "cli", GF_LOG_WARNING, "error executing"); + runner_end (&runner); + +rm_dir: + rmdir (mountdir); + +cont: + /* </volQuota> */ ret = xmlTextWriterEndElement (writer); XML_RET_CHECK_AND_GOTO (ret, out); - ret = cli_end_xml_output (writer, buf); + ret = cli_end_xml_output (writer, doc); + +out: + GF_FREE (size_str); + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +int +cli_xml_output_peer_status (dict_t *dict, int op_ret, int op_errno, + char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + int count = 0; + char *uuid = NULL; + char *hostname = NULL; + int connected = 0; + int state_id = 0; + char *state_str = NULL; + int i = 1; + char key[1024] = {0,}; + + ret = cli_begin_xml_output (&writer, &doc); if (ret) goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <peerStatus> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"peerStatus"); + XML_RET_CHECK_AND_GOTO (ret, out); + + if (!dict) + goto cont; + + ret = dict_get_int32 (dict, "count", &count); + if (ret) + goto out; + + while (i <= count) { + /* <peer> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"peer"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "friend%d.uuid", i); + ret = dict_get_str (dict, key, &uuid); + if (ret) + goto out; + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"uuid", + "%s", uuid); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "friend%d.hostname", 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), "friend%d.connected", i); + ret = dict_get_int32 (dict, key, &connected); + if (ret) + goto out; + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"connected", + "%d", connected); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "friend%d.stateId", i); + ret = dict_get_int32 (dict, key, &state_id); + if (!ret) { + /* ignore */ + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"state", "%d", state_id); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "friend%d.state", i); + ret = dict_get_str (dict, key, &state_str); + if (!ret) { + /* ignore */ + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"stateStr", "%s", state_str); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* </peer> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + i++; + } + +cont: + /* </peerStatus> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_end_xml_output (writer, doc); + out: gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); return ret; +#else + return 0; +#endif } + +#if (HAVE_LIB_XML) +/* Used for rebalance stop/status, remove-brick status */ +int +cli_xml_output_vol_rebalance_status (xmlTextWriterPtr writer, dict_t *dict, + enum gf_task_types task_type) +{ + int ret = -1; + int count = 0; + char *node_name = NULL; + char *node_uuid = NULL; + uint64_t files = 0; + uint64_t size = 0; + uint64_t lookups = 0; + int status_rcd = 0; + uint64_t failures = 0; + uint64_t skipped = 0; + uint64_t total_files = 0; + uint64_t total_size = 0; + uint64_t total_lookups = 0; + uint64_t total_failures = 0; + uint64_t total_skipped = 0; + char key[1024] = {0,}; + int i = 0; + int overall_status = -1; + double elapsed = 0; + double overall_elapsed = 0; + + if (!dict) { + ret = 0; + goto out; + } + + ret = dict_get_int32 (dict, "count", &count); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"nodeCount", + "%d", count); + XML_RET_CHECK_AND_GOTO (ret, out); + + while (i < count) { + i++; + + /* <node> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"node"); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "node-name-%d", i); + ret = dict_get_str (dict, key, &node_name); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"nodeName", + "%s", node_name); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "node-uuid-%d", i); + ret = dict_get_str (dict, key, &node_uuid); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"id", + "%s", node_uuid); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "files-%d", i); + ret = dict_get_uint64 (dict, key, &files); + if (ret) + goto out; + total_files += files; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"files", + "%"PRIu64, files); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "size-%d", i); + ret = dict_get_uint64 (dict, key, &size); + if (ret) + goto out; + total_size += size; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"size", + "%"PRIu64,size); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "lookups-%d", i); + ret = dict_get_uint64 (dict, key, &lookups); + if (ret) + goto out; + total_lookups += lookups; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"lookups", + "%"PRIu64, lookups); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "failures-%d", i); + ret = dict_get_uint64 (dict, key, &failures); + if (ret) + goto out; + total_failures += failures; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"failures", + "%"PRIu64, failures); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* skipped-%d is not available for remove brick in dict, + so using failures as skipped count in case of remove-brick + similar to logic used in CLI(non xml output) */ + if (task_type == GF_TASK_TYPE_REBALANCE) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "skipped-%d", i); + } + else { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "failures-%d", i); + } + + ret = dict_get_uint64 (dict, key, &skipped); + if (ret) + goto out; + total_skipped += skipped; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"skipped", + "%"PRIu64, skipped); + XML_RET_CHECK_AND_GOTO (ret, out); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "status-%d", i); + ret = dict_get_int32 (dict, key, &status_rcd); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"status", + "%d", status_rcd); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"statusStr", + "%s", + cli_vol_task_status_str[status_rcd]); + + memset (key, 0, 256); + snprintf (key, 256, "run-time-%d", i); + ret = dict_get_double (dict, key, &elapsed); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"runtime", + "%.2f", elapsed); + XML_RET_CHECK_AND_GOTO (ret, out); + + if (elapsed > overall_elapsed) { + overall_elapsed = elapsed; + } + + if (-1 == overall_status) + overall_status = status_rcd; + else if ((GF_DEFRAG_STATUS_COMPLETE == overall_status || + status_rcd > overall_status) && + (status_rcd != GF_DEFRAG_STATUS_COMPLETE)) + overall_status = status_rcd; + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </node> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + /* Aggregate status */ + /* <aggregate> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"aggregate"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer,(xmlChar *)"files", + "%"PRIu64, total_files); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer,(xmlChar *)"size", + "%"PRIu64, total_size); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer,(xmlChar *)"lookups", + "%"PRIu64, total_lookups); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer,(xmlChar *)"failures", + "%"PRIu64, total_failures); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer,(xmlChar *)"skipped", + "%"PRIu64, total_skipped); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer,(xmlChar *)"status", + "%d", overall_status); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer,(xmlChar *)"statusStr", + "%s", + cli_vol_task_status_str[overall_status]); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer,(xmlChar *)"runtime", + "%.2f", overall_elapsed); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </aggregate> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} +#endif + +int +cli_xml_output_vol_rebalance (gf_cli_defrag_type op, dict_t *dict, int op_ret, + int op_errno, char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + char *task_id_str = NULL; + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <volRebalance> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volRebalance"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_str (dict, GF_REBALANCE_TID_KEY, &task_id_str); + if (ret == 0) { + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"task-id", + "%s", task_id_str); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"op", + "%d", op); + XML_RET_CHECK_AND_GOTO (ret, out); + + if ((GF_DEFRAG_CMD_STOP == op) || (GF_DEFRAG_CMD_STATUS == op)) { + ret = cli_xml_output_vol_rebalance_status (writer, dict, + GF_TASK_TYPE_REBALANCE); + if (ret) + goto out; + } + + /* </volRebalance> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + + ret = cli_end_xml_output (writer, doc); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; #endif +} + +int +cli_xml_output_vol_remove_brick (gf_boolean_t status_op, dict_t *dict, + int op_ret, int op_errno, char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + char *task_id_str = NULL; + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <volRemoveBrick> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volRemoveBrick"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_str (dict, GF_REMOVE_BRICK_TID_KEY, &task_id_str); + if (ret == 0) { + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"task-id", + "%s", task_id_str); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + if (status_op) { + ret = cli_xml_output_vol_rebalance_status (writer, dict, + GF_TASK_TYPE_REMOVE_BRICK); + if (ret) + goto out; + } + + /* </volRemoveBrick> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + + ret = cli_end_xml_output (writer, doc); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +int +cli_xml_output_vol_replace_brick (gf1_cli_replace_op op, dict_t *dict, + int op_ret, int op_errno, char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + int status = 0; + uint64_t files = 0; + char *current_file = 0; + char *task_id_str = NULL; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <volReplaceBrick> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volReplaceBrick"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_str (dict, GF_REPLACE_BRICK_TID_KEY, &task_id_str); + if (ret == 0) { + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"task-id", + "%s", task_id_str); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"op", + "%d", op); + XML_RET_CHECK_AND_GOTO (ret, out); + + if (GF_REPLACE_OP_STATUS == op) { + ret = dict_get_int32 (dict, "status", &status); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"status", + "%d", status); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_uint64 (dict, "files", &files); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"files", + "%"PRIu64, files); + XML_RET_CHECK_AND_GOTO (ret, out); + + if (status) + goto cont; + + ret = dict_get_str (dict, "current_file", ¤t_file); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"currentFile", + "%s", current_file); + XML_RET_CHECK_AND_GOTO (ret, out); + } +cont: + /* </volReplaceBrick> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_end_xml_output (writer, doc); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +int +cli_xml_output_vol_create (dict_t *dict, int op_ret, int op_errno, + char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + char *volname = NULL; + char *volid = NULL; + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + if (dict) { + /* <volCreate> */ + ret = xmlTextWriterStartElement (writer, + (xmlChar *)"volCreate"); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <volume> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volume"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *) "name", + "%s", volname); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_str (dict, "volume-id", &volid); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"id", + "%s", volid); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </volume> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </volCreate> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + ret = cli_end_xml_output (writer, doc); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +int +cli_xml_output_generic_volume (char *op, dict_t *dict, int op_ret, int op_errno, + char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + char *volname = NULL; + char *volid = NULL; + + GF_ASSERT (op); + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + if (dict) { + /* <"op"> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)op); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* <volume> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"volume"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *) "name", + "%s", volname); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_str (dict, "vol-id", &volid); + if (ret) + goto out; + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"id", + "%s", volid); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </volume> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </"op"> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + } + + ret = cli_end_xml_output (writer, doc); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} + +#if (HAVE_LIB_XML) +int +cli_xml_output_vol_gsync_status (dict_t *dict, xmlTextWriterPtr writer) +{ + char master_key[PATH_MAX] = ""; + char slave_key[PATH_MAX] = ""; + char status_key[PATH_MAX] = ""; + char node_key[PATH_MAX] = ""; + char *master = NULL; + char *slave = NULL; + char *status = NULL; + char *node = NULL; + int ret = -1; + int gsync_count = 0; + int i = 1; + + ret = dict_get_int32 (dict, "gsync-count", &gsync_count); + if (ret) + goto out; + + for (i=1; i <= gsync_count; i++) { + snprintf (node_key, sizeof(node_key), "node%d", i); + snprintf (master_key, sizeof(master_key), "master%d", i); + snprintf (slave_key, sizeof(slave_key), "slave%d", i); + snprintf (status_key, sizeof(status_key), "status%d", i); + + ret = dict_get_str (dict, node_key, &node); + if (ret) + goto out; + + ret = dict_get_str (dict, master_key, &master); + if (ret) + goto out; + + ret = dict_get_str (dict, slave_key, &slave); + if (ret) + goto out; + + ret = dict_get_str (dict, status_key, &status); + if (ret) + goto out; + + /* <pair> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"pair"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"node", + "%s", node); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"master", + "%s", master); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"slave", + "%s", slave); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"status", + "%s", status); + XML_RET_CHECK_AND_GOTO (ret, out); + + /* </pair> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + } + +out: + gf_log ("cli",GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} +#endif + +int +cli_xml_output_vol_gsync (dict_t *dict, int op_ret, int op_errno, + char *op_errstr) +{ +#if (HAVE_LIB_XML) + int ret = -1; + xmlTextWriterPtr writer = NULL; + xmlDocPtr doc = NULL; + char *master = NULL; + char *slave = NULL; + int type = 0; + + GF_ASSERT (dict); + + ret = cli_begin_xml_output (&writer, &doc); + if (ret) + goto out; + + ret = cli_xml_output_common (writer, op_ret, op_errno, op_errstr); + if (ret) + goto out; + + /* <geoRep> */ + ret = xmlTextWriterStartElement (writer, (xmlChar *)"geoRep"); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = dict_get_int32 (dict, "type", &type); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to get type"); + goto out; + } + + ret = xmlTextWriterWriteFormatElement (writer, (xmlChar *)"type", + "%d", type); + XML_RET_CHECK_AND_GOTO (ret, out); + + switch (type) { + case GF_GSYNC_OPTION_TYPE_START: + case GF_GSYNC_OPTION_TYPE_STOP: + if (dict_get_str (dict, "master", &master) != 0) + master = "???"; + if (dict_get_str (dict, "slave", &slave) != 0) + slave = "???"; + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"master", + "%s", master); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = xmlTextWriterWriteFormatElement (writer, + (xmlChar *)"slave", + "%s", slave); + XML_RET_CHECK_AND_GOTO (ret, out); + + break; + + case GF_GSYNC_OPTION_TYPE_CONFIG: + break; + case GF_GSYNC_OPTION_TYPE_STATUS: + ret = cli_xml_output_vol_gsync_status(dict, writer); + break; + default: + ret = 0; + break; + } + + /* </geoRep> */ + ret = xmlTextWriterEndElement (writer); + XML_RET_CHECK_AND_GOTO (ret, out); + + ret = cli_end_xml_output (writer, doc); +out: + gf_log ("cli",GF_LOG_DEBUG, "Returning %d", ret); + return ret; +#else + return 0; +#endif +} |
