mirror of
https://github.com/gluster/glusterfs.git
synced 2026-02-06 18:48:16 +01:00
There's a small difference when structs are defined static.
Whenever possible, define them as such.
Specifically, before:
text data bss dec hex filename
678 216 0 894 37e ./cli/src/cli-cmd-misc.o
150024 1264 16 151304 24f08 ./cli/src/cli-rpc-ops.o
71980 64 0 72044 1196c ./cli/src/cli-cmd-parser.o
66189 4 16 66209 102a1 ./cli/src/cli-xml-output.o
After:
text data bss dec hex filename
670 216 0 886 376 ./cli/src/cli-cmd-misc.o
149848 1392 16 151256 24ed8 ./cli/src/cli-rpc-ops.o
70346 1320 0 71666 117f2 ./cli/src/cli-cmd-parser.o
66157 4 16 66177 10281 ./cli/src/cli-xml-output.o
Change-Id: I206bd895290595d79fac7b26eee66f4279b50f92
updates: bz#1193929
Signed-off-by: Yaniv Kaul <ykaul@redhat.com>
5843 lines
173 KiB
C
5843 lines
173 KiB
C
/*
|
|
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 <glusterfs/run.h>
|
|
#include <glusterfs/compat.h>
|
|
#include <glusterfs/syscall.h>
|
|
#include <glusterfs/upcall-utils.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 format ensures that all xml related code is compiled
|
|
* only when libxml2 is present, and also keeps the rest of the codebase free
|
|
* of #if (HAVE_LIB_XML)
|
|
*/
|
|
|
|
#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; \
|
|
} else \
|
|
ret = 0; \
|
|
} while (0)
|
|
|
|
int
|
|
cli_begin_xml_output(xmlTextWriterPtr *writer, xmlDocPtr *doc)
|
|
{
|
|
int ret = -1;
|
|
|
|
*writer = xmlNewTextWriterDoc(doc, 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, xmlDocPtr doc)
|
|
{
|
|
int ret = -1;
|
|
|
|
/* </cliOutput> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterEndDocument(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* Dump xml document to stdout and pretty format it */
|
|
xmlSaveFormatFileEnc("-", doc, "UTF-8", 1);
|
|
|
|
xmlFreeTextWriter(writer);
|
|
xmlFreeDoc(doc);
|
|
|
|
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);
|
|
|
|
if (op_errstr)
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"opErrstr",
|
|
"%s", op_errstr);
|
|
else
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"opErrstr",
|
|
"%s", "");
|
|
|
|
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;
|
|
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;
|
|
|
|
if (op) {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"cliOp", "%s",
|
|
op);
|
|
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, 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_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);
|
|
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
out:
|
|
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;
|
|
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;
|
|
|
|
/* <"op"> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)op);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
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, 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,
|
|
gf_boolean_t *node_present)
|
|
{
|
|
int ret = -1;
|
|
char *hostname = NULL;
|
|
char *path = NULL;
|
|
char *uuid = NULL;
|
|
int port = 0;
|
|
int rdma_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) {
|
|
*node_present = _gf_false;
|
|
goto out;
|
|
}
|
|
*node_present = _gf_true;
|
|
|
|
/* <node>
|
|
* will be closed in the calling function cli_xml_output_vol_status()*/
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"node");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"hostname", "%s",
|
|
hostname);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
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);
|
|
|
|
snprintf(key, sizeof(key), "brick%d.peerid", brick_index);
|
|
ret = dict_get_str(dict, key, &uuid);
|
|
if (ret)
|
|
goto out;
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"peerid", "%s",
|
|
uuid);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
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;
|
|
|
|
snprintf(key, sizeof(key), "brick%d.port", brick_index);
|
|
ret = dict_get_int32(dict, key, &port);
|
|
if (ret)
|
|
goto out;
|
|
|
|
snprintf(key, sizeof(key), "brick%d.rdma_port", brick_index);
|
|
ret = dict_get_int32(dict, key, &rdma_port);
|
|
|
|
/* If the process is either offline or doesn't provide a port (shd)
|
|
* port = "N/A"
|
|
* else print the port number of the process.
|
|
*/
|
|
|
|
/*
|
|
* Tag 'port' can be removed once console management is started
|
|
* to support new tag ports.
|
|
*/
|
|
|
|
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);
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"ports");
|
|
if (*online == 1 && (port != 0 || rdma_port != 0)) {
|
|
if (port) {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"tcp",
|
|
"%d", port);
|
|
} else {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"tcp",
|
|
"%s", "N/A");
|
|
}
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
if (rdma_port) {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"rdma",
|
|
"%d", rdma_port);
|
|
} else {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"rdma",
|
|
"%s", "N/A");
|
|
}
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
} else {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"tcp", "%s",
|
|
"N/A");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"rdma", "%s",
|
|
"N/A");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
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) {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"sizeTotal",
|
|
"%" PRIu64, size_total);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
snprintf(key, sizeof(key), "brick%d.free", brick_index);
|
|
ret = dict_get_uint64(dict, key, &size_free);
|
|
if (!ret) {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"sizeFree",
|
|
"%" PRIu64, size_free);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
snprintf(key, sizeof(key), "brick%d.device", brick_index);
|
|
ret = dict_get_str(dict, key, &device);
|
|
if (!ret) {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"device", "%s",
|
|
device);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
snprintf(key, sizeof(key), "brick%d.block_size", brick_index);
|
|
ret = dict_get_uint64(dict, key, &block_size);
|
|
if (!ret) {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"blockSize",
|
|
"%" PRIu64, block_size);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
snprintf(key, sizeof(key), "brick%d.mnt_options", brick_index);
|
|
ret = dict_get_str(dict, key, &mnt_options);
|
|
if (!ret) {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"mntOptions",
|
|
"%s", mnt_options);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
snprintf(key, sizeof(key), "brick%d.fs_name", brick_index);
|
|
ret = dict_get_str(dict, key, &fs_name);
|
|
if (!ret) {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"fsName", "%s",
|
|
fs_name);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
snprintf(key, sizeof(key), "brick%d.inode_size", brick_index);
|
|
ret = dict_get_str(dict, key, &inode_size);
|
|
if (!ret) {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"inodeSize",
|
|
"%s", fs_name);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
snprintf(key, sizeof(key), "brick%d.total_inodes", brick_index);
|
|
ret = dict_get_uint64(dict, key, &inodes_total);
|
|
if (!ret) {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"inodesTotal",
|
|
"%" PRIu64, inodes_total);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
snprintf(key, sizeof(key), "brick%d.free_inodes", brick_index);
|
|
ret = dict_get_uint64(dict, key, &inodes_free);
|
|
if (!ret) {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"inodesFree",
|
|
"%" PRIu64, inodes_free);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
} else {
|
|
ret = 0;
|
|
}
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
snprintf(key, sizeof(key), "%s.pool%d.pool-misses", prefix, i);
|
|
ret = dict_get_uint64(dict, key, &alloccount);
|
|
if (ret)
|
|
goto out;
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"poolMisses",
|
|
"%" PRIu64, alloccount);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "%s.pool%d.max-stdalloc", prefix, i);
|
|
ret = dict_get_int32(dict, key, &maxalloc);
|
|
if (ret)
|
|
goto out;
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"maxStdAlloc",
|
|
"%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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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;
|
|
uint32_t opversion = 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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
snprintf(key, sizeof(key), "brick%d.client%d.opversion", brick_index,
|
|
i);
|
|
ret = dict_get_uint32(dict, key, &opversion);
|
|
if (ret)
|
|
goto out;
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"opVersion",
|
|
"%" PRIu32, opversion);
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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++) {
|
|
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);
|
|
}
|
|
|
|
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++) {
|
|
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);
|
|
}
|
|
|
|
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++) {
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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++) {
|
|
snprintf(key, sizeof(key), "%s.fdentry%d.pid", prefix, i);
|
|
ret = dict_get_int32(dict, key, &fd_pid);
|
|
if (ret)
|
|
continue;
|
|
|
|
snprintf(key, sizeof(key), "%s.fdentry%d.refcount", prefix, i);
|
|
ret = dict_get_int32(dict, key, &fd_refcount);
|
|
if (ret)
|
|
continue;
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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++) {
|
|
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);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
for (i = 0; i < call_count; i++) {
|
|
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;
|
|
}
|
|
#endif
|
|
|
|
int
|
|
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;
|
|
|
|
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;
|
|
|
|
for (i = 1; i <= count; i++) {
|
|
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);
|
|
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_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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(local->writer,
|
|
(xmlChar *)"statusStr", "%s",
|
|
cli_vol_task_status_str[status]);
|
|
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "task%d", i);
|
|
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);
|
|
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_status_tasks_detail(cli_local_t *local, dict_t *dict)
|
|
{
|
|
#if (HAVE_LIB_XML)
|
|
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(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;
|
|
#else
|
|
return 0;
|
|
#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;
|
|
int type = -1;
|
|
|
|
/* <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(local->writer, (xmlChar *)"nodeCount",
|
|
"%d", brick_count);
|
|
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_uint32(dict, "cmd", &cmd);
|
|
if (ret)
|
|
goto out;
|
|
|
|
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;
|
|
|
|
ret = dict_get_int32(dict, "type", &type);
|
|
if (ret)
|
|
goto out;
|
|
|
|
for (i = 0; i <= index_max; i++) {
|
|
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(local->writer, dict, i);
|
|
if (ret)
|
|
goto out;
|
|
break;
|
|
|
|
case GF_CLI_STATUS_MEM:
|
|
if (online) {
|
|
ret = cli_xml_output_vol_status_mem(local->writer, dict, i);
|
|
if (ret)
|
|
goto out;
|
|
}
|
|
break;
|
|
|
|
case GF_CLI_STATUS_CLIENTS:
|
|
if (online) {
|
|
ret = cli_xml_output_vol_status_clients(local->writer, dict,
|
|
i);
|
|
if (ret)
|
|
goto out;
|
|
}
|
|
break;
|
|
|
|
case GF_CLI_STATUS_INODE:
|
|
if (online) {
|
|
ret = cli_xml_output_vol_status_inode(local->writer, dict,
|
|
i);
|
|
if (ret)
|
|
goto out;
|
|
}
|
|
break;
|
|
|
|
case GF_CLI_STATUS_FD:
|
|
if (online) {
|
|
ret = cli_xml_output_vol_status_fd(local->writer, dict, i);
|
|
if (ret)
|
|
goto out;
|
|
}
|
|
break;
|
|
|
|
case GF_CLI_STATUS_CALLPOOL:
|
|
if (online) {
|
|
ret = cli_xml_output_vol_status_callpool(local->writer,
|
|
dict, i);
|
|
if (ret)
|
|
goto out;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* </node> was opened in cli_xml_output_vol_status_common()*/
|
|
ret = xmlTextWriterEndElement(local->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;
|
|
}
|
|
|
|
/* </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;
|
|
char timestr[256] = {
|
|
0,
|
|
};
|
|
char key[1024] = {
|
|
0,
|
|
};
|
|
int len;
|
|
|
|
/* <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);
|
|
|
|
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);
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
gf_time_fmt(timestr, sizeof timestr, time_sec, gf_timefmt_FT);
|
|
len = strlen(timestr);
|
|
snprintf(timestr + len, sizeof(timestr) - len, ".%" 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);
|
|
|
|
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;
|
|
}
|
|
#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;
|
|
xmlDocPtr doc = 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, &doc);
|
|
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);
|
|
|
|
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);
|
|
|
|
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:
|
|
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);
|
|
|
|
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);
|
|
|
|
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:
|
|
|
|
break;
|
|
|
|
case GF_CLI_TOP_READ_PERF:
|
|
case GF_CLI_TOP_WRITE_PERF:
|
|
snprintf(key, sizeof(key), "%d-throughput", i);
|
|
ret = dict_get_double(dict, key, &throughput);
|
|
if (!ret) {
|
|
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);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
|
|
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, 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)
|
|
{
|
|
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);
|
|
|
|
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);
|
|
|
|
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++) {
|
|
snprintf(key, sizeof(key), "%d-%d-%d-hits", brick_index, interval, i);
|
|
ret = dict_get_uint64(dict, key, &hits);
|
|
if (ret)
|
|
goto cont;
|
|
|
|
snprintf(key, sizeof(key), "%d-%d-%d-avglatency", brick_index, interval,
|
|
i);
|
|
ret = dict_get_double(dict, key, &avg_latency);
|
|
if (ret)
|
|
goto cont;
|
|
|
|
snprintf(key, sizeof(key), "%d-%d-%d-minlatency", brick_index, interval,
|
|
i);
|
|
ret = dict_get_double(dict, key, &min_latency);
|
|
if (ret)
|
|
goto cont;
|
|
|
|
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;
|
|
}
|
|
|
|
for (i = 0; i < GF_UPCALL_FLAGS_MAXVALUE; i++) {
|
|
hits = 0;
|
|
avg_latency = 0.0;
|
|
min_latency = 0.0;
|
|
max_latency = 0.0;
|
|
|
|
snprintf(key, sizeof(key), "%d-%d-%d-upcall-hits", brick_index,
|
|
interval, i);
|
|
ret = dict_get_uint64(dict, key, &hits);
|
|
if (ret)
|
|
continue;
|
|
|
|
/* <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);
|
|
}
|
|
|
|
/* </fopStats> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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;
|
|
}
|
|
#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;
|
|
xmlDocPtr doc = NULL;
|
|
char *volname = NULL;
|
|
int op = GF_CLI_STATS_NONE;
|
|
int info_op = GF_CLI_INFO_NONE;
|
|
int brick_count = 0;
|
|
char *brick_name = NULL;
|
|
int interval = 0;
|
|
char key[1024] = {
|
|
0,
|
|
};
|
|
int i = 0;
|
|
int stats_cleared = 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;
|
|
|
|
/* <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 (GF_CLI_STATS_INFO != op)
|
|
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);
|
|
|
|
ret = dict_get_int32(dict, "info-op", &info_op);
|
|
if (ret)
|
|
goto 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);
|
|
|
|
if (GF_CLI_INFO_CLEAR == info_op) {
|
|
snprintf(key, sizeof(key), "%d-stats-cleared", i);
|
|
ret = dict_get_int32(dict, key, &stats_cleared);
|
|
if (ret)
|
|
goto out;
|
|
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
writer, (xmlChar *)"clearStats", "%s",
|
|
stats_cleared ? "Cleared stats." : "Failed to clear stats.");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
} else {
|
|
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;
|
|
}
|
|
|
|
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, 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;
|
|
xmlDocPtr doc = NULL;
|
|
int count = 0;
|
|
char *volname = NULL;
|
|
char key[1024] = {
|
|
0,
|
|
};
|
|
int i = 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;
|
|
|
|
/* <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++) {
|
|
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, 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)
|
|
{
|
|
int ret = -1;
|
|
char *ptr1 = NULL;
|
|
char *ptr2 = NULL;
|
|
|
|
ptr1 = substr;
|
|
ptr2 = optstr;
|
|
|
|
while (ptr1) {
|
|
if (*ptr1 != *ptr2)
|
|
break;
|
|
ptr1++;
|
|
ptr2++;
|
|
if (!*ptr1)
|
|
break;
|
|
if (!*ptr2)
|
|
break;
|
|
}
|
|
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;
|
|
}
|
|
|
|
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;
|
|
char key[1024] = {
|
|
0,
|
|
};
|
|
struct tmp_xml_option_logger tmp = {
|
|
0,
|
|
};
|
|
|
|
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);
|
|
|
|
/* <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(cli_local_t *local, dict_t *dict)
|
|
{
|
|
#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;
|
|
int dist_count = 0;
|
|
int stripe_count = 0;
|
|
int replica_count = 0;
|
|
int arbiter_count = 0;
|
|
int snap_count = 0;
|
|
int isArbiter = 0;
|
|
int disperse_count = 0;
|
|
int redundancy_count = 0;
|
|
int transport = 0;
|
|
char *brick = NULL;
|
|
char key[1024] = {
|
|
0,
|
|
};
|
|
int i = 0;
|
|
int j = 1;
|
|
char *caps __attribute__((unused)) = NULL;
|
|
int k __attribute__((unused)) = 0;
|
|
|
|
ret = dict_get_int32(dict, "count", &count);
|
|
if (ret)
|
|
goto out;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
/* <volume> */
|
|
ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"volume");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "volume%d.name", i);
|
|
ret = dict_get_str(dict, key, &volname);
|
|
if (ret)
|
|
goto out;
|
|
ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"name",
|
|
"%s", volname);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "volume%d.volume_id", i);
|
|
ret = dict_get_str(dict, key, &volume_id);
|
|
if (ret)
|
|
goto out;
|
|
ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"id",
|
|
"%s", volume_id);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "volume%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);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(local->writer,
|
|
(xmlChar *)"statusStr", "%s",
|
|
cli_vol_status_str[status]);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "volume%d.snap_count", i);
|
|
ret = dict_get_int32(dict, key, &snap_count);
|
|
if (ret)
|
|
goto out;
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"snapshotCount", "%d", snap_count);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "volume%d.brick_count", i);
|
|
ret = dict_get_int32(dict, key, &brick_count);
|
|
if (ret)
|
|
goto out;
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"brickCount", "%d", brick_count);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "volume%d.dist_count", i);
|
|
ret = dict_get_int32(dict, key, &dist_count);
|
|
if (ret)
|
|
goto out;
|
|
ret = xmlTextWriterWriteFormatElement(local->writer,
|
|
(xmlChar *)"distCount", "%d",
|
|
(brick_count / dist_count));
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "volume%d.stripe_count", i);
|
|
ret = dict_get_int32(dict, key, &stripe_count);
|
|
if (ret)
|
|
goto out;
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"stripeCount", "%d", stripe_count);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "volume%d.replica_count", i);
|
|
ret = dict_get_int32(dict, key, &replica_count);
|
|
if (ret)
|
|
goto out;
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"replicaCount", "%d", replica_count);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "volume%d.arbiter_count", i);
|
|
ret = dict_get_int32(dict, key, &arbiter_count);
|
|
if (ret)
|
|
goto out;
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"arbiterCount", "%d", arbiter_count);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "volume%d.disperse_count", i);
|
|
ret = dict_get_int32(dict, key, &disperse_count);
|
|
if (ret)
|
|
goto out;
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"disperseCount", "%d", disperse_count);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "volume%d.redundancy_count", i);
|
|
ret = dict_get_int32(dict, key, &redundancy_count);
|
|
if (ret)
|
|
goto out;
|
|
ret = xmlTextWriterWriteFormatElement(local->writer,
|
|
(xmlChar *)"redundancyCount",
|
|
"%d", redundancy_count);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
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,disperse)
|
|
types
|
|
*/
|
|
type = get_vol_type(type, dist_count, brick_count);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"type",
|
|
"%d", type);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"typeStr", "%s", vol_type_str[type]);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "volume%d.transport", i);
|
|
ret = dict_get_int32(dict, key, &transport);
|
|
if (ret)
|
|
goto out;
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"transport", "%d", transport);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
snprintf(key, sizeof(key), "volume%d.brick%d", i, j);
|
|
ret = dict_get_str(dict, key, &brick);
|
|
if (ret)
|
|
goto out;
|
|
ret = xmlTextWriterWriteFormatString(local->writer, "%s", brick);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"name", "%s", brick);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"hostUuid", "%s", uuid);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "volume%d.brick%d.isArbiter", i, j);
|
|
if (dict_get(dict, key))
|
|
isArbiter = 1;
|
|
else
|
|
isArbiter = 0;
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"isArbiter", "%d", isArbiter);
|
|
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);
|
|
|
|
snprintf(key, sizeof(key), "volume%d", i);
|
|
ret = cli_xml_output_vol_info_options(local->writer, dict, key);
|
|
if (ret)
|
|
goto out;
|
|
|
|
/* </volume> */
|
|
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);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
/* </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_DEBUG, "Returning %d", ret);
|
|
return ret;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
int
|
|
cli_xml_output_vol_quota_limit_list_end(cli_local_t *local)
|
|
{
|
|
#if (HAVE_LIB_XML)
|
|
int ret = -1;
|
|
|
|
ret = xmlTextWriterEndElement(local->writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = cli_end_xml_output(local->writer, local->doc);
|
|
|
|
out:
|
|
return ret;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
int
|
|
cli_xml_output_vol_quota_limit_list_begin(cli_local_t *local, int op_ret,
|
|
int op_errno, char *op_errstr)
|
|
{
|
|
#if (HAVE_LIB_XML)
|
|
int ret = -1;
|
|
|
|
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;
|
|
|
|
/* <volQuota> */
|
|
ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"volQuota");
|
|
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)
|
|
static int
|
|
cli_xml_output_peer_hostnames(xmlTextWriterPtr writer, dict_t *dict,
|
|
const char *prefix, int count)
|
|
{
|
|
int ret = -1;
|
|
int i = 0;
|
|
char *hostname = NULL;
|
|
char key[1024] = {
|
|
0,
|
|
};
|
|
|
|
/* <hostnames> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"hostnames");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
for (i = 0; i < count; i++) {
|
|
ret = snprintf(key, sizeof(key), "%s.hostname%d", prefix, i);
|
|
if (ret < 0)
|
|
goto out;
|
|
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);
|
|
hostname = NULL;
|
|
}
|
|
|
|
/* </hostnames> */
|
|
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_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 hostname_count = 0;
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
snprintf(key, sizeof(key), "friend%d.hostname_count", i);
|
|
ret = dict_get_int32(dict, key, &hostname_count);
|
|
if ((ret == 0) && (hostname_count > 0)) {
|
|
snprintf(key, sizeof(key), "friend%d", i);
|
|
ret = cli_xml_output_peer_hostnames(writer, dict, key,
|
|
hostname_count);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
|
|
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);
|
|
|
|
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);
|
|
}
|
|
|
|
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++;
|
|
/* Getting status early, to skip nodes that don't have the
|
|
* rebalance process started
|
|
*/
|
|
snprintf(key, sizeof(key), "status-%d", i);
|
|
ret = dict_get_int32(dict, key, &status_rcd);
|
|
|
|
/* If glusterd is down it fails to get the status, try
|
|
getting status from other nodes */
|
|
if (ret)
|
|
continue;
|
|
if (GF_DEFRAG_STATUS_NOT_STARTED == status_rcd)
|
|
continue;
|
|
|
|
/* <node> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"node");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
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);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
snprintf(key, sizeof(key), "failures-%d", i);
|
|
ret = dict_get_uint64(dict, key, &failures);
|
|
if (ret)
|
|
goto out;
|
|
|
|
snprintf(key, sizeof(key), "skipped-%d", i);
|
|
|
|
ret = dict_get_uint64(dict, key, &skipped);
|
|
if (ret)
|
|
goto out;
|
|
|
|
if (task_type == GF_TASK_TYPE_REMOVE_BRICK) {
|
|
failures += skipped;
|
|
skipped = 0;
|
|
}
|
|
|
|
total_failures += failures;
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"failures",
|
|
"%" PRIu64, failures);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
total_skipped += skipped;
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"skipped",
|
|
"%" PRIu64, skipped);
|
|
XML_RET_CHECK_AND_GOTO(ret, 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]);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "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;
|
|
}
|
|
|
|
/* Rebalance has 5 states,
|
|
* NOT_STARTED, STARTED, STOPPED, COMPLETE, FAILED
|
|
* The precedence used to determine the aggregate status is as
|
|
* below,
|
|
* STARTED > FAILED > STOPPED > COMPLETE > NOT_STARTED
|
|
*/
|
|
/* TODO: Move this to a common place utilities that both CLI and
|
|
* glusterd need.
|
|
* Till then if the below algorithm is changed, change it in
|
|
* glusterd_volume_status_aggregate_tasks_status in
|
|
* glusterd-utils.c
|
|
*/
|
|
|
|
if (-1 == overall_status)
|
|
overall_status = status_rcd;
|
|
int rank[] = {[GF_DEFRAG_STATUS_STARTED] = 1,
|
|
[GF_DEFRAG_STATUS_FAILED] = 2,
|
|
[GF_DEFRAG_STATUS_STOPPED] = 3,
|
|
[GF_DEFRAG_STATUS_COMPLETE] = 4,
|
|
[GF_DEFRAG_STATUS_NOT_STARTED] = 5};
|
|
if (rank[status_rcd] <= rank[overall_status])
|
|
overall_status = status_rcd;
|
|
|
|
/* </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);
|
|
|
|
if (overall_status == -1) {
|
|
overall_status = status_rcd;
|
|
}
|
|
|
|
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,
|
|
const char *op)
|
|
{
|
|
#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;
|
|
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)op);
|
|
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;
|
|
}
|
|
|
|
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(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;
|
|
|
|
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;
|
|
|
|
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
|
|
_output_gsync_config(FILE *fp, xmlTextWriterPtr writer, char *op_name)
|
|
{
|
|
char resbuf[256 + PATH_MAX] = {
|
|
0,
|
|
};
|
|
char *ptr = NULL;
|
|
char *v = NULL;
|
|
int blen = sizeof(resbuf);
|
|
int ret = 0;
|
|
|
|
for (;;) {
|
|
ptr = fgets(resbuf, blen, fp);
|
|
if (!ptr)
|
|
break;
|
|
|
|
v = resbuf + strlen(resbuf) - 1;
|
|
while (isspace(*v)) {
|
|
/* strip trailing space */
|
|
*v-- = '\0';
|
|
}
|
|
if (v == resbuf) {
|
|
/* skip empty line */
|
|
continue;
|
|
}
|
|
|
|
if (op_name != NULL) {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)op_name,
|
|
"%s", resbuf);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
goto out;
|
|
}
|
|
|
|
v = strchr(resbuf, ':');
|
|
if (!v) {
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
*v++ = '\0';
|
|
while (isspace(*v))
|
|
v++;
|
|
v = gf_strdup(v);
|
|
if (!v) {
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)resbuf, "%s",
|
|
v);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
out:
|
|
gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#if (HAVE_LIB_XML)
|
|
int
|
|
get_gsync_config(runner_t *runner,
|
|
int (*op_conf)(FILE *fp, xmlTextWriterPtr writer,
|
|
char *op_name),
|
|
xmlTextWriterPtr writer, char *op_name)
|
|
{
|
|
int ret = 0;
|
|
|
|
runner_redir(runner, STDOUT_FILENO, RUN_PIPE);
|
|
if (runner_start(runner) != 0) {
|
|
gf_log("cli", GF_LOG_ERROR, "spawning child failed");
|
|
return -1;
|
|
}
|
|
|
|
ret = op_conf(runner_chio(runner, STDOUT_FILENO), writer, op_name);
|
|
|
|
ret |= runner_end(runner);
|
|
if (ret)
|
|
gf_log("cli", GF_LOG_ERROR, "reading data from child failed");
|
|
|
|
return ret ? -1 : 0;
|
|
}
|
|
#endif
|
|
|
|
#if (HAVE_LIB_XML)
|
|
int
|
|
cli_xml_generate_gsync_config(dict_t *dict, xmlTextWriterPtr writer)
|
|
{
|
|
runner_t runner = {
|
|
0,
|
|
};
|
|
char *subop = NULL;
|
|
char *gwd = NULL;
|
|
char *slave = NULL;
|
|
char *confpath = NULL;
|
|
char *master = NULL;
|
|
char *op_name = NULL;
|
|
int ret = -1;
|
|
char conf_path[PATH_MAX] = "";
|
|
|
|
if (dict_get_str(dict, "subop", &subop) != 0) {
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
if (strcmp(subop, "get") != 0 && strcmp(subop, "get-all") != 0) {
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
writer, (xmlChar *)"message", "%s",
|
|
GEOREP " config updated successfully");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
ret = 0;
|
|
goto out;
|
|
}
|
|
|
|
if (dict_get_str(dict, "glusterd_workdir", &gwd) != 0 ||
|
|
dict_get_str(dict, "slave", &slave) != 0) {
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
if (dict_get_str(dict, "master", &master) != 0)
|
|
master = NULL;
|
|
|
|
if (dict_get_str(dict, "op_name", &op_name) != 0)
|
|
op_name = NULL;
|
|
|
|
ret = dict_get_str(dict, "conf_path", &confpath);
|
|
if (!confpath) {
|
|
ret = snprintf(conf_path, sizeof(conf_path) - 1,
|
|
"%s/" GEOREP "/gsyncd_template.conf", gwd);
|
|
conf_path[ret] = '\0';
|
|
confpath = conf_path;
|
|
}
|
|
|
|
runinit(&runner);
|
|
runner_add_args(&runner, GSYNCD_PREFIX "/gsyncd", "-c", NULL);
|
|
runner_argprintf(&runner, "%s", confpath);
|
|
runner_argprintf(&runner, "--iprefix=%s", DATADIR);
|
|
|
|
if (master)
|
|
runner_argprintf(&runner, ":%s", master);
|
|
|
|
runner_add_arg(&runner, slave);
|
|
runner_argprintf(&runner, "--config-%s", subop);
|
|
|
|
if (op_name)
|
|
runner_add_arg(&runner, op_name);
|
|
|
|
ret = get_gsync_config(&runner, _output_gsync_config, writer, op_name);
|
|
|
|
out:
|
|
gf_log("cli", GF_LOG_DEBUG, "Returning %d", ret);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#if (HAVE_LIB_XML)
|
|
int
|
|
cli_xml_output_vol_gsync_status(dict_t *dict, xmlTextWriterPtr writer)
|
|
{
|
|
int ret = -1;
|
|
int i = 1;
|
|
int j = 0;
|
|
int count = 0;
|
|
const int number_of_fields = 20;
|
|
int closed = 1;
|
|
int session_closed = 1;
|
|
gf_gsync_status_t **status_values = NULL;
|
|
char status_value_name[PATH_MAX] = "";
|
|
char *tmp = NULL;
|
|
char *volume = NULL;
|
|
char *volume_next = NULL;
|
|
char *slave = NULL;
|
|
char *slave_next = NULL;
|
|
static const char *title_values[] = {
|
|
"master_node", "", "master_brick", "slave_user", "slave", "slave_node",
|
|
"status", "crawl_status",
|
|
/* last_synced */
|
|
"", "entry", "data", "meta", "failures",
|
|
/* checkpoint_time */
|
|
"", "checkpoint_completed",
|
|
/* checkpoint_completion_time */
|
|
"", "master_node_uuid",
|
|
/* last_synced_utc */
|
|
"last_synced",
|
|
/* checkpoint_time_utc */
|
|
"checkpoint_time",
|
|
/* checkpoint_completion_time_utc */
|
|
"checkpoint_completion_time"};
|
|
|
|
GF_ASSERT(dict);
|
|
|
|
ret = dict_get_int32(dict, "gsync-count", &count);
|
|
if (ret)
|
|
goto out;
|
|
|
|
status_values = GF_MALLOC(count * sizeof(gf_gsync_status_t *),
|
|
gf_common_mt_char);
|
|
if (!status_values) {
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
for (i = 0; i < count; i++) {
|
|
status_values[i] = GF_CALLOC(1, sizeof(gf_gsync_status_t),
|
|
gf_common_mt_char);
|
|
if (!status_values[i]) {
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
snprintf(status_value_name, sizeof(status_value_name), "status_value%d",
|
|
i);
|
|
|
|
ret = dict_get_bin(dict, status_value_name,
|
|
(void **)&(status_values[i]));
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "struct member empty.");
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
qsort(status_values, count, sizeof(gf_gsync_status_t *),
|
|
gf_gsync_status_t_comparator);
|
|
|
|
for (i = 0; i < count; i++) {
|
|
if (closed) {
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"volume");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
tmp = get_struct_variable(1, status_values[i]);
|
|
if (!tmp) {
|
|
gf_log("cli", GF_LOG_ERROR, "struct member empty.");
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name",
|
|
"%s", tmp);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"sessions");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
closed = 0;
|
|
}
|
|
|
|
if (session_closed) {
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"session");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
session_closed = 0;
|
|
|
|
tmp = get_struct_variable(21, status_values[i]);
|
|
if (!tmp) {
|
|
gf_log("cli", GF_LOG_ERROR, "struct member empty.");
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
writer, (xmlChar *)"session_slave", "%s", tmp);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"pair");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
for (j = 0; j < number_of_fields; j++) {
|
|
/* XML ignore fields */
|
|
if (strcmp(title_values[j], "") == 0)
|
|
continue;
|
|
|
|
tmp = get_struct_variable(j, status_values[i]);
|
|
if (!tmp) {
|
|
gf_log("cli", GF_LOG_ERROR, "struct member empty.");
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
writer, (xmlChar *)title_values[j], "%s", tmp);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
if (i + 1 < count) {
|
|
slave = get_struct_variable(20, status_values[i]);
|
|
slave_next = get_struct_variable(20, status_values[i + 1]);
|
|
volume = get_struct_variable(1, status_values[i]);
|
|
volume_next = get_struct_variable(1, status_values[i + 1]);
|
|
if (!slave || !slave_next || !volume || !volume_next) {
|
|
gf_log("cli", GF_LOG_ERROR, "struct member empty.");
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
if (strcmp(volume, volume_next) != 0) {
|
|
closed = 1;
|
|
session_closed = 1;
|
|
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
} else if (strcmp(slave, slave_next) != 0) {
|
|
session_closed = 1;
|
|
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
} else {
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
}
|
|
out:
|
|
if (status_values)
|
|
GF_FREE(status_values);
|
|
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;
|
|
}
|
|
|
|
switch (type) {
|
|
case GF_GSYNC_OPTION_TYPE_START:
|
|
case GF_GSYNC_OPTION_TYPE_STOP:
|
|
case GF_GSYNC_OPTION_TYPE_PAUSE:
|
|
case GF_GSYNC_OPTION_TYPE_RESUME:
|
|
case GF_GSYNC_OPTION_TYPE_CREATE:
|
|
case GF_GSYNC_OPTION_TYPE_DELETE:
|
|
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:
|
|
if (op_ret == 0) {
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"config");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = cli_xml_generate_gsync_config(dict, writer);
|
|
if (ret)
|
|
goto out;
|
|
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
|
|
break;
|
|
case GF_GSYNC_OPTION_TYPE_STATUS:
|
|
ret = cli_xml_output_vol_gsync_status(dict, writer);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_DEBUG, "Failed to get gsync status");
|
|
goto out;
|
|
}
|
|
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
|
|
}
|
|
|
|
#if (HAVE_LIB_XML)
|
|
/* This function will generate snapshot create output in xml format.
|
|
*
|
|
* @param writer xmlTextWriterPtr
|
|
* @param doc xmlDocPtr
|
|
* @param dict dict containing create output
|
|
*
|
|
* @return 0 on success and -1 on failure
|
|
*/
|
|
static int
|
|
cli_xml_snapshot_create(xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
|
|
{
|
|
int ret = -1;
|
|
char *str_value = NULL;
|
|
|
|
GF_ASSERT(writer);
|
|
GF_ASSERT(doc);
|
|
GF_ASSERT(dict);
|
|
|
|
/* <snapCreate> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapCreate");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* <snapshot> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapshot");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_str(dict, "snapname", &str_value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Failed to get snap name");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
|
|
str_value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_str(dict, "snapuuid", &str_value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Failed to get snap uuid");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"uuid", "%s",
|
|
str_value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* </snapshot> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* </snapCreate> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = 0;
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
/* This function will generate snapshot clone output in xml format.
|
|
*
|
|
* @param writer xmlTextWriterPtr
|
|
* @param doc xmlDocPtr
|
|
* @param dict dict containing create output
|
|
*
|
|
* @return 0 on success and -1 on failure
|
|
*/
|
|
static int
|
|
cli_xml_snapshot_clone(xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
|
|
{
|
|
int ret = -1;
|
|
char *str_value = NULL;
|
|
|
|
GF_VALIDATE_OR_GOTO("cli", writer, out);
|
|
GF_VALIDATE_OR_GOTO("cli", doc, out);
|
|
GF_VALIDATE_OR_GOTO("cli", dict, out);
|
|
|
|
/* <CloneCreate> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"CloneCreate");
|
|
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, "clonename", &str_value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Failed to get clone name");
|
|
goto out;
|
|
}
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
|
|
str_value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_str(dict, "snapuuid", &str_value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Failed to get clone uuid");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"uuid", "%s",
|
|
str_value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* </volume> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* </CloneCreate> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = 0;
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
/* This function will generate snapshot restore output in xml format.
|
|
*
|
|
* @param writer xmlTextWriterPtr
|
|
* @param doc xmlDocPtr
|
|
* @param dict dict containing restore output
|
|
*
|
|
* @return 0 on success and -1 on failure
|
|
*/
|
|
static int
|
|
cli_xml_snapshot_restore(xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
|
|
{
|
|
int ret = -1;
|
|
char *str_value = NULL;
|
|
|
|
GF_ASSERT(writer);
|
|
GF_ASSERT(doc);
|
|
GF_ASSERT(dict);
|
|
|
|
/* <snapRestore> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapRestore");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* <volume> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"volume");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_str(dict, "volname", &str_value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Failed to get vol name");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
|
|
str_value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_str(dict, "volid", &str_value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Failed to get volume id");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"uuid", "%s",
|
|
str_value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* </volume> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* <snapshot> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapshot");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_str(dict, "snapname", &str_value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Failed to get snap name");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
|
|
str_value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_str(dict, "snapuuid", &str_value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Failed to get snap uuid");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"uuid", "%s",
|
|
str_value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* </snapshot> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* </snapRestore> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = 0;
|
|
out:
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* This function will generate snapshot list output in xml format.
|
|
*
|
|
* @param writer xmlTextWriterPtr
|
|
* @param doc xmlDocPtr
|
|
* @param dict dict containing list output
|
|
*
|
|
* @return 0 on success and -1 on failure
|
|
*/
|
|
static int
|
|
cli_xml_snapshot_list(xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
|
|
{
|
|
int ret = -1;
|
|
int i = 0;
|
|
int snapcount = 0;
|
|
char *str_value = NULL;
|
|
char key[PATH_MAX] = "";
|
|
|
|
GF_ASSERT(writer);
|
|
GF_ASSERT(doc);
|
|
GF_ASSERT(dict);
|
|
|
|
/* <snapList> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapList");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_int32(dict, "snapcount", &snapcount);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Failed to get snapcount");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"count", "%d",
|
|
snapcount);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
for (i = 1; i <= snapcount; ++i) {
|
|
ret = snprintf(key, sizeof(key), "snapname%d", i);
|
|
if (ret < 0) {
|
|
goto out;
|
|
}
|
|
|
|
ret = dict_get_str(dict, key, &str_value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Could not get %s ", key);
|
|
goto out;
|
|
} else {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"snapshot",
|
|
"%s", str_value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
}
|
|
|
|
/* </snapList> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = 0;
|
|
out:
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* This function will generate xml output for origin volume
|
|
* of the given snapshot.
|
|
*
|
|
* @param writer xmlTextWriterPtr
|
|
* @param doc xmlDocPtr
|
|
* @param dict dict containing info output
|
|
* @param keyprefix prefix for dictionary key
|
|
*
|
|
* @return 0 on success and -1 on failure
|
|
*/
|
|
static int
|
|
cli_xml_snapshot_info_orig_vol(xmlTextWriterPtr writer, xmlDocPtr doc,
|
|
dict_t *dict, char *keyprefix)
|
|
{
|
|
int ret = -1;
|
|
int value = 0;
|
|
char *buffer = NULL;
|
|
char key[PATH_MAX] = "";
|
|
|
|
GF_ASSERT(dict);
|
|
GF_ASSERT(keyprefix);
|
|
GF_ASSERT(writer);
|
|
GF_ASSERT(doc);
|
|
|
|
/* <originVolume> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"originVolume");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "%sorigin-volname", keyprefix);
|
|
|
|
ret = dict_get_str(dict, key, &buffer);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_WARNING, "Failed to get %s", key);
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
|
|
buffer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "%ssnapcount", keyprefix);
|
|
|
|
ret = dict_get_int32(dict, key, &value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Failed to get %s", key);
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"snapCount", "%d",
|
|
value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "%ssnaps-available", keyprefix);
|
|
|
|
ret = dict_get_int32(dict, key, &value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Failed to get %s", key);
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"snapRemaining",
|
|
"%d", value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* </originVolume> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = 0;
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
/* This function will generate xml output of snapshot volume info.
|
|
*
|
|
* @param writer xmlTextWriterPtr
|
|
* @param doc xmlDocPtr
|
|
* @param dict dict containing info output
|
|
* @param keyprefix key prefix for dictionary
|
|
* @param snap_driven boolean to check if output is based of volume
|
|
* or snapshot
|
|
*
|
|
* @return 0 on success and -1 on failure
|
|
*/
|
|
static int
|
|
cli_xml_snapshot_info_snap_vol(xmlTextWriterPtr writer, xmlDocPtr doc,
|
|
dict_t *dict, char *keyprefix,
|
|
gf_boolean_t snap_driven)
|
|
{
|
|
char key[PATH_MAX] = "";
|
|
char *buffer = NULL;
|
|
int ret = -1;
|
|
|
|
GF_ASSERT(dict);
|
|
GF_ASSERT(keyprefix);
|
|
GF_ASSERT(writer);
|
|
GF_ASSERT(doc);
|
|
|
|
/* <snapVolume> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapVolume");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = snprintf(key, sizeof(key), "%s.volname", keyprefix);
|
|
if (ret < 0)
|
|
goto out;
|
|
|
|
ret = dict_get_str(dict, key, &buffer);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Failed to get %s", key);
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
|
|
buffer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = snprintf(key, sizeof(key), "%s.vol-status", keyprefix);
|
|
if (ret < 0)
|
|
goto out;
|
|
|
|
ret = dict_get_str(dict, key, &buffer);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Failed to get %s", key);
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"status", "%s",
|
|
buffer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* If the command is snap_driven then we need to show origin volume
|
|
* info. Else this is shown in the start of info display.*/
|
|
if (snap_driven) {
|
|
ret = snprintf(key, sizeof(key), "%s.", keyprefix);
|
|
if (ret < 0)
|
|
goto out;
|
|
|
|
ret = cli_xml_snapshot_info_orig_vol(writer, doc, dict, key);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to create "
|
|
"xml output for snapshot's origin volume");
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
/* </snapVolume> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = 0;
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
/* This function will generate snapshot info of individual snapshot
|
|
* in xml format.
|
|
*
|
|
* @param writer xmlTextWriterPtr
|
|
* @param doc xmlDocPtr
|
|
* @param dict dict containing info output
|
|
* @param keyprefix key prefix for dictionary
|
|
* @param snap_driven boolean to check if output is based of volume
|
|
* or snapshot
|
|
*
|
|
* @return 0 on success and -1 on failure
|
|
*/
|
|
static int
|
|
cli_xml_snapshot_info_per_snap(xmlTextWriterPtr writer, xmlDocPtr doc,
|
|
dict_t *dict, char *keyprefix,
|
|
gf_boolean_t snap_driven)
|
|
{
|
|
char key_buffer[PATH_MAX] = "";
|
|
char *buffer = NULL;
|
|
int volcount = 0;
|
|
int ret = -1;
|
|
int i = 0;
|
|
|
|
GF_ASSERT(dict);
|
|
GF_ASSERT(keyprefix);
|
|
GF_ASSERT(writer);
|
|
GF_ASSERT(doc);
|
|
|
|
/* <snapshot> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapshot");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = snprintf(key_buffer, sizeof(key_buffer), "%s.snapname", keyprefix);
|
|
if (ret < 0)
|
|
goto out;
|
|
|
|
ret = dict_get_str(dict, key_buffer, &buffer);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Unable to fetch snapname %s ", key_buffer);
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
|
|
buffer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = snprintf(key_buffer, sizeof(key_buffer), "%s.snap-id", keyprefix);
|
|
if (ret < 0)
|
|
goto out;
|
|
|
|
ret = dict_get_str(dict, key_buffer, &buffer);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Unable to fetch snap-id %s ", key_buffer);
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"uuid", "%s",
|
|
buffer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = snprintf(key_buffer, sizeof(key_buffer), "%s.snap-desc", keyprefix);
|
|
if (ret < 0)
|
|
goto out;
|
|
|
|
ret = dict_get_str(dict, key_buffer, &buffer);
|
|
if (!ret) {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"description",
|
|
"%s", buffer);
|
|
} else {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"description",
|
|
"%s", "");
|
|
}
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = snprintf(key_buffer, sizeof(key_buffer), "%s.snap-time", keyprefix);
|
|
if (ret < 0)
|
|
goto out;
|
|
|
|
ret = dict_get_str(dict, key_buffer, &buffer);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Unable to fetch snap-time %s ", keyprefix);
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"createTime", "%s",
|
|
buffer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = snprintf(key_buffer, sizeof(key_buffer), "%s.vol-count", keyprefix);
|
|
if (ret < 0)
|
|
goto out;
|
|
|
|
ret = dict_get_int32(dict, key_buffer, &volcount);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Fail to get snap vol count");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"volCount", "%d",
|
|
volcount);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_int32(dict, key_buffer, &volcount);
|
|
/* Display info of each snapshot volume */
|
|
for (i = 1; i <= volcount; i++) {
|
|
ret = snprintf(key_buffer, sizeof(key_buffer), "%s.vol%d", keyprefix,
|
|
i);
|
|
if (ret < 0)
|
|
goto out;
|
|
|
|
ret = cli_xml_snapshot_info_snap_vol(writer, doc, dict, key_buffer,
|
|
snap_driven);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Could not list "
|
|
"details of volume in a snap");
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
/* </snapshot> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
/* This function will generate snapshot info output in xml format.
|
|
*
|
|
* @param writer xmlTextWriterPtr
|
|
* @param doc xmlDocPtr
|
|
* @param dict dict containing info output
|
|
*
|
|
* @return 0 on success and -1 on failure
|
|
*/
|
|
static int
|
|
cli_xml_snapshot_info(xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
|
|
{
|
|
int ret = -1;
|
|
int i = 0;
|
|
int snapcount = 0;
|
|
char key[PATH_MAX] = "";
|
|
gf_boolean_t snap_driven = _gf_false;
|
|
|
|
GF_ASSERT(writer);
|
|
GF_ASSERT(doc);
|
|
GF_ASSERT(dict);
|
|
|
|
/* <snapInfo> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapInfo");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snap_driven = dict_get_str_boolean(dict, "snap-driven", _gf_false);
|
|
|
|
/* If the approach is volume based then we should display origin volume
|
|
* information first followed by per snap info*/
|
|
if (!snap_driven) {
|
|
ret = cli_xml_snapshot_info_orig_vol(writer, doc, dict, "");
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to create "
|
|
"xml output for snapshot's origin volume");
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
ret = dict_get_int32(dict, "snapcount", &snapcount);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Failed to get snapcount");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"count", "%d",
|
|
snapcount);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* <snapshots> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapshots");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* Get snapshot info of individual snapshots */
|
|
for (i = 1; i <= snapcount; ++i) {
|
|
snprintf(key, sizeof(key), "snap%d", i);
|
|
|
|
ret = cli_xml_snapshot_info_per_snap(writer, doc, dict, key,
|
|
snap_driven);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Could not get %s ", key);
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
/* </snapshots> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* </snapInfo> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = 0;
|
|
out:
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* This function will generate snapshot status of individual
|
|
* snapshot volume in xml format.
|
|
*
|
|
* @param writer xmlTextWriterPtr
|
|
* @param doc xmlDocPtr
|
|
* @param dict dict containing status output
|
|
* @param keyprefix key prefix for dictionary
|
|
*
|
|
* @return 0 on success and -1 on failure
|
|
*/
|
|
static int
|
|
cli_xml_snapshot_volume_status(xmlTextWriterPtr writer, xmlDocPtr doc,
|
|
dict_t *dict, const char *keyprefix)
|
|
{
|
|
int ret = -1;
|
|
int brickcount = 0;
|
|
int i = 0;
|
|
int pid = 0;
|
|
char *buffer = NULL;
|
|
char key[PATH_MAX] = "";
|
|
|
|
GF_ASSERT(writer);
|
|
GF_ASSERT(doc);
|
|
GF_ASSERT(dict);
|
|
GF_ASSERT(keyprefix);
|
|
|
|
ret = snprintf(key, sizeof(key), "%s.brickcount", keyprefix);
|
|
if (ret < 0)
|
|
goto out;
|
|
|
|
ret = dict_get_int32(dict, key, &brickcount);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Failed to fetch brickcount");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"brickCount", "%d",
|
|
brickcount);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* Get status of every brick belonging to the snapshot volume */
|
|
for (i = 0; i < brickcount; i++) {
|
|
/* <snapInfo> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"brick");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = snprintf(key, sizeof(key), "%s.brick%d.path", keyprefix, i);
|
|
if (ret < 0)
|
|
goto out;
|
|
|
|
ret = dict_get_str(dict, key, &buffer);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Unable to get Brick Path");
|
|
/*
|
|
* If path itself is not present, then end *
|
|
* this brick's status and continue to the *
|
|
* brick *
|
|
*/
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
continue;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"path", "%s",
|
|
buffer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = snprintf(key, sizeof(key), "%s.brick%d.vgname", keyprefix, i);
|
|
if (ret < 0)
|
|
goto out;
|
|
|
|
ret = dict_get_str(dict, key, &buffer);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Unable to get Volume Group");
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
writer, (xmlChar *)"volumeGroup", "N/A");
|
|
} else
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
writer, (xmlChar *)"volumeGroup", "%s", buffer);
|
|
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = snprintf(key, sizeof(key), "%s.brick%d.status", keyprefix, i);
|
|
if (ret < 0)
|
|
goto out;
|
|
|
|
ret = dict_get_str(dict, key, &buffer);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_INFO, "Unable to get Brick Running");
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
writer, (xmlChar *)"brick_running", "N/A");
|
|
} else
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
writer, (xmlChar *)"brick_running", "%s", buffer);
|
|
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = snprintf(key, sizeof(key), "%s.brick%d.pid", keyprefix, i);
|
|
if (ret < 0)
|
|
goto out;
|
|
|
|
ret = dict_get_int32(dict, key, &pid);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_INFO, "Unable to get pid");
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"pid",
|
|
"N/A");
|
|
} else
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"pid",
|
|
"%d", pid);
|
|
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = snprintf(key, sizeof(key), "%s.brick%d.data", keyprefix, i);
|
|
if (ret < 0)
|
|
goto out;
|
|
|
|
ret = dict_get_str(dict, key, &buffer);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Unable to get Data Percent");
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
writer, (xmlChar *)"data_percentage", "N/A");
|
|
} else
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
writer, (xmlChar *)"data_percentage", "%s", buffer);
|
|
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = snprintf(key, sizeof(key), "%s.brick%d.lvsize", keyprefix, i);
|
|
if (ret < 0)
|
|
goto out;
|
|
|
|
ret = dict_get_str(dict, key, &buffer);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Unable to get LV Size");
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"lvSize",
|
|
"N/A");
|
|
} else {
|
|
/* Truncate any newline character */
|
|
buffer = strtok(buffer, "\n");
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"lvSize",
|
|
"%s", buffer);
|
|
}
|
|
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* </brick> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
/* This function will generate snapshot status of individual
|
|
* snapshot in xml format.
|
|
*
|
|
* @param writer xmlTextWriterPtr
|
|
* @param doc xmlDocPtr
|
|
* @param dict dict containing status output
|
|
*
|
|
* @return 0 on success and -1 on failure
|
|
*/
|
|
static int
|
|
cli_xml_snapshot_status_per_snap(xmlTextWriterPtr writer, xmlDocPtr doc,
|
|
dict_t *dict, const char *keyprefix)
|
|
{
|
|
int ret = -1;
|
|
int volcount = 0;
|
|
int i = 0;
|
|
char *buffer = NULL;
|
|
char key[PATH_MAX] = "";
|
|
|
|
GF_ASSERT(writer);
|
|
GF_ASSERT(doc);
|
|
GF_ASSERT(dict);
|
|
GF_ASSERT(keyprefix);
|
|
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapshot");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "%s.snapname", keyprefix);
|
|
|
|
ret = dict_get_str(dict, key, &buffer);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Unable to get snapname");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
|
|
buffer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "%s.uuid", keyprefix);
|
|
|
|
ret = dict_get_str(dict, key, &buffer);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Unable to get snap UUID");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"uuid", "%s",
|
|
buffer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "%s.volcount", keyprefix);
|
|
|
|
ret = dict_get_int32(dict, key, &volcount);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Unable to get volume count");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"volCount", "%d",
|
|
volcount);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* Get snapshot status of individual snapshot volume */
|
|
for (i = 0; i < volcount; i++) {
|
|
/* <volume> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"volume");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(key, sizeof(key), "%s.vol%d", keyprefix, i);
|
|
|
|
ret = cli_xml_snapshot_volume_status(writer, doc, dict, key);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Could not get snap volume status");
|
|
goto out;
|
|
}
|
|
|
|
/* </volume> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
|
|
/* </snapshot> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = 0;
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
/* This function will generate snapshot status output in xml format.
|
|
*
|
|
* @param writer xmlTextWriterPtr
|
|
* @param doc xmlDocPtr
|
|
* @param dict dict containing status output
|
|
*
|
|
* @return 0 on success and -1 on failure
|
|
*/
|
|
static int
|
|
cli_xml_snapshot_status(xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
|
|
{
|
|
int ret = -1;
|
|
int snapcount = 0;
|
|
int i = 0;
|
|
int status_cmd = 0;
|
|
char key[PATH_MAX] = "";
|
|
|
|
GF_ASSERT(writer);
|
|
GF_ASSERT(doc);
|
|
GF_ASSERT(dict);
|
|
|
|
/* <snapStatus> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapStatus");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_int32(dict, "sub-cmd", &status_cmd);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Could not fetch status type");
|
|
goto out;
|
|
}
|
|
|
|
if ((GF_SNAP_STATUS_TYPE_SNAP == status_cmd) ||
|
|
(GF_SNAP_STATUS_TYPE_ITER == status_cmd)) {
|
|
snapcount = 1;
|
|
} else {
|
|
ret = dict_get_int32(dict, "status.snapcount", &snapcount);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Could not get snapcount");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"count", "%d",
|
|
snapcount);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
|
|
for (i = 0; i < snapcount; i++) {
|
|
snprintf(key, sizeof(key), "status.snap%d", i);
|
|
|
|
ret = cli_xml_snapshot_status_per_snap(writer, doc, dict, key);
|
|
if (ret < 0) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"failed to create xml "
|
|
"output for snapshot status");
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
/* </snapStatus> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = 0;
|
|
out:
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* This function will generate snapshot config show output in xml format.
|
|
*
|
|
* @param writer xmlTextWriterPtr
|
|
* @param doc xmlDocPtr
|
|
* @param dict dict containing status output
|
|
*
|
|
* @return 0 on success and -1 on failure
|
|
*/
|
|
static int
|
|
cli_xml_snapshot_config_show(xmlTextWriterPtr writer, xmlDocPtr doc,
|
|
dict_t *dict)
|
|
{
|
|
int ret = -1;
|
|
uint64_t i = 0;
|
|
uint64_t value = 0;
|
|
uint64_t volcount = 0;
|
|
char buf[PATH_MAX] = "";
|
|
char *str_value = NULL;
|
|
|
|
GF_ASSERT(writer);
|
|
GF_ASSERT(doc);
|
|
GF_ASSERT(dict);
|
|
|
|
/* <systemConfig> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"systemConfig");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_uint64(dict, "snap-max-hard-limit", &value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to get "
|
|
"snap-max-hard-limit");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"hardLimit",
|
|
"%" PRIu64, value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_uint64(dict, "snap-max-soft-limit", &value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to get "
|
|
"snap-max-soft-limit");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"softLimit",
|
|
"%" PRIu64 "%%", value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_str(dict, "auto-delete", &str_value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Could not fetch auto-delete");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"autoDelete", "%s",
|
|
str_value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_str(dict, "snap-activate-on-create", &str_value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Could not fetch snap-activate-on-create-delete");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"activateOnCreate",
|
|
"%s", str_value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* </systemConfig> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* <volumeConfig> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"volumeConfig");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_uint64(dict, "voldisplaycount", &volcount);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Could not fetch volcount");
|
|
goto out;
|
|
}
|
|
|
|
/* Get config of all the volumes */
|
|
for (i = 0; i < volcount; i++) {
|
|
/* <volume> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"volume");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(buf, sizeof(buf), "volume%" PRIu64 "-volname", i);
|
|
ret = dict_get_str(dict, buf, &str_value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Could not fetch %s", buf);
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
|
|
str_value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(buf, sizeof(buf), "volume%" PRIu64 "-snap-max-hard-limit", i);
|
|
ret = dict_get_uint64(dict, buf, &value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Could not fetch %s", buf);
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"hardLimit",
|
|
"%" PRIu64, value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(buf, sizeof(buf), "volume%" PRIu64 "-active-hard-limit", i);
|
|
ret = dict_get_uint64(dict, buf, &value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Could not fetch"
|
|
" effective snap_max_hard_limit for "
|
|
"%s",
|
|
str_value);
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
writer, (xmlChar *)"effectiveHardLimit", "%" PRIu64, value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
snprintf(buf, sizeof(buf), "volume%" PRIu64 "-snap-max-soft-limit", i);
|
|
ret = dict_get_uint64(dict, buf, &value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Could not fetch %s", buf);
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"softLimit",
|
|
"%" PRIu64, value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* </volume> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
|
|
/* </volume> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = 0;
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
/* This function will generate snapshot config set output in xml format.
|
|
*
|
|
* @param writer xmlTextWriterPtr
|
|
* @param doc xmlDocPtr
|
|
* @param dict dict containing status output
|
|
*
|
|
* @return 0 on success and -1 on failure
|
|
*/
|
|
static int
|
|
cli_xml_snapshot_config_set(xmlTextWriterPtr writer, xmlDocPtr doc,
|
|
dict_t *dict)
|
|
{
|
|
int ret = -1;
|
|
uint64_t hard_limit = 0;
|
|
uint64_t soft_limit = 0;
|
|
char *volname = NULL;
|
|
char *auto_delete = NULL;
|
|
char *snap_activate = NULL;
|
|
|
|
GF_ASSERT(writer);
|
|
GF_ASSERT(doc);
|
|
GF_ASSERT(dict);
|
|
|
|
/* This is optional parameter therefore ignore the error */
|
|
ret = dict_get_uint64(dict, "snap-max-hard-limit", &hard_limit);
|
|
/* This is optional parameter therefore ignore the error */
|
|
ret = dict_get_uint64(dict, "snap-max-soft-limit", &soft_limit);
|
|
ret = dict_get_str(dict, "auto-delete", &auto_delete);
|
|
ret = dict_get_str(dict, "snap-activate-on-create", &snap_activate);
|
|
|
|
if (!hard_limit && !soft_limit && !auto_delete && !snap_activate) {
|
|
ret = -1;
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"At least one option from "
|
|
"snap-max-hard-limit, snap-max-soft-limit, auto-delete"
|
|
" and snap-activate-on-create should be set");
|
|
goto out;
|
|
}
|
|
|
|
/* Ignore the error, as volname is optional */
|
|
ret = dict_get_str(dict, "volname", &volname);
|
|
|
|
if (NULL == volname) {
|
|
/* <systemConfig> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"systemConfig");
|
|
} else {
|
|
/* <volumeConfig> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"volumeConfig");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
|
|
volname);
|
|
}
|
|
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
if (hard_limit) {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"newHardLimit",
|
|
"%" PRIu64, hard_limit);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
|
|
if (soft_limit) {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"newSoftLimit",
|
|
"%" PRIu64, soft_limit);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
|
|
if (auto_delete) {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"autoDelete",
|
|
"%s", auto_delete);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
|
|
if (snap_activate) {
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
writer, (xmlChar *)"activateOnCreate", "%s", snap_activate);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
}
|
|
|
|
/* </volumeConfig> or </systemConfig> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = 0;
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
/* This function will generate snapshot config output in xml format.
|
|
*
|
|
* @param writer xmlTextWriterPtr
|
|
* @param doc xmlDocPtr
|
|
* @param dict dict containing config output
|
|
*
|
|
* @return 0 on success and -1 on failure
|
|
*/
|
|
static int
|
|
cli_xml_snapshot_config(xmlTextWriterPtr writer, xmlDocPtr doc, dict_t *dict)
|
|
{
|
|
int ret = -1;
|
|
int config_command = 0;
|
|
|
|
GF_ASSERT(writer);
|
|
GF_ASSERT(doc);
|
|
GF_ASSERT(dict);
|
|
|
|
/* <snapConfig> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapConfig");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_int32(dict, "config-command", &config_command);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Could not fetch config type");
|
|
goto out;
|
|
}
|
|
|
|
switch (config_command) {
|
|
case GF_SNAP_CONFIG_TYPE_SET:
|
|
ret = cli_xml_snapshot_config_set(writer, doc, dict);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to create xml "
|
|
"output for snapshot config set command");
|
|
goto out;
|
|
}
|
|
|
|
break;
|
|
case GF_SNAP_CONFIG_DISPLAY:
|
|
ret = cli_xml_snapshot_config_show(writer, doc, dict);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to create xml "
|
|
"output for snapshot config show command");
|
|
goto out;
|
|
}
|
|
break;
|
|
default:
|
|
gf_log("cli", GF_LOG_ERROR, "Unknown config command :%d",
|
|
config_command);
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
/* </snapConfig> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = 0;
|
|
out:
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* This function will generate snapshot activate or
|
|
* deactivate output in xml format.
|
|
*
|
|
* @param writer xmlTextWriterPtr
|
|
* @param doc xmlDocPtr
|
|
* @param dict dict containing activate or deactivate output
|
|
*
|
|
* @return 0 on success and -1 on failure
|
|
*/
|
|
static int
|
|
cli_xml_snapshot_activate_deactivate(xmlTextWriterPtr writer, xmlDocPtr doc,
|
|
dict_t *dict, int cmd)
|
|
{
|
|
int ret = -1;
|
|
char *buffer = NULL;
|
|
char *tag = NULL;
|
|
|
|
GF_ASSERT(writer);
|
|
GF_ASSERT(doc);
|
|
GF_ASSERT(dict);
|
|
|
|
if (GF_SNAP_OPTION_TYPE_ACTIVATE == cmd) {
|
|
tag = "snapActivate";
|
|
} else if (GF_SNAP_OPTION_TYPE_DEACTIVATE == cmd) {
|
|
tag = "snapDeactivate";
|
|
} else {
|
|
gf_log("cli", GF_LOG_ERROR, "invalid command %d", cmd);
|
|
goto out;
|
|
}
|
|
|
|
/* <snapActivate> or <snapDeactivate> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)tag);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* <snapshot> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapshot");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_str(dict, "snapname", &buffer);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Failed to get snap name");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
|
|
buffer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_str(dict, "snapuuid", &buffer);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Failed to get snap uuid");
|
|
goto out;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"uuid", "%s",
|
|
buffer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* </snapshot> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* </snapActivate> or </snapDeactivate> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = 0;
|
|
out:
|
|
|
|
return ret;
|
|
}
|
|
#endif /* HAVE_LIB_XML */
|
|
|
|
/* This function will generate snapshot delete output in xml format.
|
|
*
|
|
* @param writer xmlTextWriterPtr
|
|
* @param doc xmlDocPtr
|
|
* @param dict dict containing delete output
|
|
* @param rsp cli response
|
|
*
|
|
* @return 0 on success and -1 on failure
|
|
*/
|
|
int
|
|
cli_xml_snapshot_delete(cli_local_t *local, dict_t *dict, gf_cli_rsp *rsp)
|
|
{
|
|
int ret = -1;
|
|
#ifdef HAVE_LIB_XML
|
|
char *str_value = NULL;
|
|
xmlTextWriterPtr writer = local->writer;
|
|
xmlDocPtr doc = local->doc;
|
|
|
|
GF_ASSERT(writer);
|
|
GF_ASSERT(doc);
|
|
GF_ASSERT(dict);
|
|
|
|
/* <snapshot> */
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"snapshot");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_str(dict, "snapname", &str_value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Failed to get snap name");
|
|
goto xmlend;
|
|
}
|
|
|
|
if (!rsp->op_ret) {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"status",
|
|
"Success");
|
|
} else {
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"status",
|
|
"Failure");
|
|
XML_RET_CHECK_AND_GOTO(ret, xmlend);
|
|
|
|
ret = cli_xml_output_common(writer, rsp->op_ret, rsp->op_errno,
|
|
rsp->op_errstr);
|
|
}
|
|
XML_RET_CHECK_AND_GOTO(ret, xmlend);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"name", "%s",
|
|
str_value);
|
|
XML_RET_CHECK_AND_GOTO(ret, xmlend);
|
|
|
|
ret = dict_get_str(dict, "snapuuid", &str_value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Failed to get snap uuid");
|
|
goto xmlend;
|
|
}
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"uuid", "%s",
|
|
str_value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
xmlend:
|
|
/* </snapshot> */
|
|
ret = xmlTextWriterEndElement(writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
#endif /* HAVE_LIB_XML */
|
|
ret = 0;
|
|
out:
|
|
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
cli_xml_output_snap_status_begin(cli_local_t *local, int op_ret, int op_errno,
|
|
char *op_errstr)
|
|
{
|
|
#if (HAVE_LIB_XML)
|
|
int ret = -1;
|
|
|
|
GF_ASSERT(local);
|
|
|
|
ret = cli_begin_xml_output(&(local->writer), &(local->doc));
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = cli_xml_output_common(local->writer, op_ret, op_errno, op_errstr);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* <snapStatus> */
|
|
ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"snapStatus");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* <snapshots> */
|
|
ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"snapshots");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
out:
|
|
gf_log("cli", GF_LOG_TRACE, "Returning %d", ret);
|
|
return ret;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
int
|
|
cli_xml_output_snap_status_end(cli_local_t *local)
|
|
{
|
|
#if (HAVE_LIB_XML)
|
|
int ret = -1;
|
|
|
|
GF_ASSERT(local);
|
|
|
|
/* </snapshots> */
|
|
ret = xmlTextWriterEndElement(local->writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* </snapStatus> */
|
|
ret = xmlTextWriterEndElement(local->writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = cli_end_xml_output(local->writer, local->doc);
|
|
out:
|
|
gf_log("cli", GF_LOG_TRACE, "Returning %d", ret);
|
|
return ret;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
int
|
|
cli_xml_output_snap_delete_begin(cli_local_t *local, int op_ret, int op_errno,
|
|
char *op_errstr)
|
|
{
|
|
#if (HAVE_LIB_XML)
|
|
int ret = -1;
|
|
int delete_cmd = -1;
|
|
|
|
GF_ASSERT(local);
|
|
|
|
ret = cli_begin_xml_output(&(local->writer), &(local->doc));
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_int32(local->dict, "sub-cmd", &delete_cmd);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Failed to get sub-cmd");
|
|
goto out;
|
|
}
|
|
|
|
ret = cli_xml_output_common(local->writer, op_ret, op_errno, op_errstr);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* <snapStatus> */
|
|
ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"snapDelete");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* <snapshots> */
|
|
ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"snapshots");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
out:
|
|
gf_log("cli", GF_LOG_TRACE, "Returning %d", ret);
|
|
return ret;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
int
|
|
cli_xml_output_snap_delete_end(cli_local_t *local)
|
|
{
|
|
#if (HAVE_LIB_XML)
|
|
int ret = -1;
|
|
|
|
GF_ASSERT(local);
|
|
|
|
/* </snapshots> */
|
|
ret = xmlTextWriterEndElement(local->writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
/* </snapDelete> */
|
|
ret = xmlTextWriterEndElement(local->writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = cli_end_xml_output(local->writer, local->doc);
|
|
out:
|
|
gf_log("cli", GF_LOG_TRACE, "Returning %d", ret);
|
|
return ret;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
/* This function will generate xml output for all the snapshot commands
|
|
*
|
|
* @param cmd_type command type
|
|
* @param dict dict containing snapshot command output
|
|
* @param op_ret return value of the snapshot command
|
|
* @param op_errno errno for the snapshot command
|
|
* @param op_errstr error string for the snapshot command
|
|
*
|
|
* @return 0 on success and -1 on failure
|
|
*/
|
|
int
|
|
cli_xml_output_snapshot(int cmd_type, dict_t *dict, int op_ret, int op_errno,
|
|
char *op_errstr)
|
|
{
|
|
#if (HAVE_LIB_XML)
|
|
int ret = -1;
|
|
xmlTextWriterPtr writer = NULL;
|
|
xmlDocPtr doc = NULL;
|
|
|
|
GF_ASSERT(dict);
|
|
|
|
ret = cli_begin_xml_output(&writer, &doc);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to output "
|
|
"xml begin block");
|
|
goto out;
|
|
}
|
|
|
|
ret = cli_xml_output_common(writer, op_ret, op_errno, op_errstr);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to output "
|
|
"xml common block");
|
|
goto out;
|
|
}
|
|
|
|
/* In case of command failure just printing the error message is good
|
|
* enough */
|
|
if (0 != op_ret) {
|
|
goto end;
|
|
}
|
|
|
|
switch (cmd_type) {
|
|
case GF_SNAP_OPTION_TYPE_CREATE:
|
|
ret = cli_xml_snapshot_create(writer, doc, dict);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to create "
|
|
"xml output for snapshot create command");
|
|
goto out;
|
|
}
|
|
break;
|
|
case GF_SNAP_OPTION_TYPE_CLONE:
|
|
ret = cli_xml_snapshot_clone(writer, doc, dict);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to create "
|
|
"xml output for snapshot clone command");
|
|
goto out;
|
|
}
|
|
break;
|
|
case GF_SNAP_OPTION_TYPE_RESTORE:
|
|
ret = cli_xml_snapshot_restore(writer, doc, dict);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to create "
|
|
"xml output for snapshot restore command");
|
|
goto out;
|
|
}
|
|
break;
|
|
case GF_SNAP_OPTION_TYPE_LIST:
|
|
ret = cli_xml_snapshot_list(writer, doc, dict);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to create "
|
|
"xml output for snapshot list command");
|
|
goto out;
|
|
}
|
|
break;
|
|
case GF_SNAP_OPTION_TYPE_STATUS:
|
|
ret = cli_xml_snapshot_status(writer, doc, dict);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to create"
|
|
"xml output for snapshot status command");
|
|
goto out;
|
|
}
|
|
break;
|
|
case GF_SNAP_OPTION_TYPE_INFO:
|
|
ret = cli_xml_snapshot_info(writer, doc, dict);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to create "
|
|
"xml output for snapshot info command");
|
|
goto out;
|
|
}
|
|
break;
|
|
case GF_SNAP_OPTION_TYPE_ACTIVATE:
|
|
case GF_SNAP_OPTION_TYPE_DEACTIVATE:
|
|
ret = cli_xml_snapshot_activate_deactivate(writer, doc, dict,
|
|
cmd_type);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to create "
|
|
"xml output for snapshot config command");
|
|
}
|
|
break;
|
|
case GF_SNAP_OPTION_TYPE_CONFIG:
|
|
ret = cli_xml_snapshot_config(writer, doc, dict);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to create "
|
|
"xml output for snapshot config command");
|
|
}
|
|
break;
|
|
default:
|
|
gf_log("cli", GF_LOG_ERROR, "Unexpected snapshot command: %d",
|
|
cmd_type);
|
|
goto out;
|
|
}
|
|
|
|
end:
|
|
ret = cli_end_xml_output(writer, doc);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to output "
|
|
"xml end block");
|
|
goto out;
|
|
}
|
|
|
|
ret = 0;
|
|
out:
|
|
return ret;
|
|
#else
|
|
return 0;
|
|
#endif /* HAVE_LIB_XML */
|
|
}
|
|
|
|
int
|
|
cli_xml_snapshot_begin_composite_op(cli_local_t *local)
|
|
{
|
|
int ret = -1;
|
|
#ifdef HAVE_LIB_XML
|
|
int cmd = -1;
|
|
int type = -1;
|
|
|
|
ret = dict_get_int32(local->dict, "sub-cmd", &cmd);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to get "
|
|
"sub-cmd");
|
|
ret = 0;
|
|
goto out;
|
|
}
|
|
|
|
if (cmd == GF_SNAP_STATUS_TYPE_ITER || cmd == GF_SNAP_DELETE_TYPE_SNAP) {
|
|
ret = 0;
|
|
goto out;
|
|
}
|
|
|
|
ret = dict_get_int32(local->dict, "type", &type);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to get snapshot "
|
|
"command type from dictionary");
|
|
goto out;
|
|
}
|
|
|
|
if (GF_SNAP_OPTION_TYPE_STATUS == type)
|
|
ret = cli_xml_output_snap_status_begin(local, 0, 0, NULL);
|
|
else if (GF_SNAP_OPTION_TYPE_DELETE == type)
|
|
ret = cli_xml_output_snap_delete_begin(local, 0, 0, NULL);
|
|
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR, "Error creating xml output");
|
|
goto out;
|
|
}
|
|
|
|
#endif /* HAVE_LIB_XML */
|
|
ret = 0;
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
cli_xml_snapshot_end_composite_op(cli_local_t *local)
|
|
{
|
|
int ret = -1;
|
|
#ifdef HAVE_LIB_XML
|
|
int cmd = -1;
|
|
int type = -1;
|
|
|
|
ret = dict_get_int32(local->dict, "sub-cmd", &cmd);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to get "
|
|
"sub-cmd");
|
|
ret = 0;
|
|
goto out;
|
|
}
|
|
|
|
if (cmd == GF_SNAP_STATUS_TYPE_ITER || cmd == GF_SNAP_DELETE_TYPE_SNAP) {
|
|
ret = 0;
|
|
goto out;
|
|
}
|
|
|
|
ret = dict_get_int32(local->dict, "type", &type);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to get snapshot "
|
|
"command type from dictionary");
|
|
goto out;
|
|
}
|
|
|
|
if (GF_SNAP_OPTION_TYPE_STATUS == type)
|
|
ret = cli_xml_output_snap_status_end(local);
|
|
else if (GF_SNAP_OPTION_TYPE_DELETE == type)
|
|
ret = cli_xml_output_snap_delete_end(local);
|
|
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Error creating xml "
|
|
"output");
|
|
goto out;
|
|
}
|
|
#endif /* HAVE_LIB_XML */
|
|
ret = 0;
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
cli_xml_snapshot_status_single_snap(cli_local_t *local, dict_t *dict, char *key)
|
|
{
|
|
#if (HAVE_LIB_XML)
|
|
int ret = -1;
|
|
|
|
GF_VALIDATE_OR_GOTO("cli", (local != NULL), out);
|
|
GF_VALIDATE_OR_GOTO("cli", (dict != NULL), out);
|
|
GF_VALIDATE_OR_GOTO("cli", (key != NULL), out);
|
|
|
|
ret = cli_xml_snapshot_status_per_snap(local->writer, local->doc, dict,
|
|
key);
|
|
out:
|
|
return ret;
|
|
#else
|
|
return 0;
|
|
#endif /* HAVE_LIB_XML */
|
|
}
|
|
|
|
int
|
|
cli_xml_output_vol_getopts(dict_t *dict, int op_ret, int op_errno,
|
|
char *op_errstr)
|
|
{
|
|
#if (HAVE_LIB_XML)
|
|
int i = 0;
|
|
int ret = -1;
|
|
int count = 0;
|
|
xmlTextWriterPtr writer = NULL;
|
|
xmlDocPtr doc = NULL;
|
|
char *key = NULL;
|
|
char *value = NULL;
|
|
char dict_key[50] = {
|
|
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;
|
|
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"volGetopts");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = dict_get_int32(dict, "count", &count);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to retrieve count "
|
|
"from the dictionary");
|
|
goto out;
|
|
}
|
|
if (count <= 0) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Value of count :%d is "
|
|
"invalid",
|
|
count);
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"count", "%d",
|
|
count);
|
|
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
for (i = 1; i <= count; i++) {
|
|
sprintf(dict_key, "key%d", i);
|
|
ret = dict_get_str(dict, dict_key, &key);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to"
|
|
" retrieve %s from the "
|
|
"dictionary",
|
|
dict_key);
|
|
goto out;
|
|
}
|
|
sprintf(dict_key, "value%d", i);
|
|
ret = dict_get_str(dict, dict_key, &value);
|
|
if (ret) {
|
|
gf_log("cli", GF_LOG_ERROR,
|
|
"Failed to "
|
|
"retrieve key value for %s from"
|
|
"the dictionary",
|
|
dict_key);
|
|
goto out;
|
|
}
|
|
ret = xmlTextWriterStartElement(writer, (xmlChar *)"Opt");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"Option", "%s",
|
|
key);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(writer, (xmlChar *)"Value", "%s",
|
|
value);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
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 /* HAVE_LIB_XML */
|
|
}
|
|
|
|
int
|
|
cli_quota_list_xml_error(cli_local_t *local, char *path, char *errstr)
|
|
{
|
|
#if (HAVE_LIB_XML)
|
|
int ret = -1;
|
|
|
|
ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"limit");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"path",
|
|
"%s", path);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"errstr",
|
|
"%s", errstr);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterEndElement(local->writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
out:
|
|
return ret;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
int
|
|
cli_quota_xml_output(cli_local_t *local, char *path, int64_t hl_str,
|
|
char *sl_final, int64_t sl_num, int64_t used,
|
|
int64_t avail, char *sl, char *hl, gf_boolean_t limit_set)
|
|
{
|
|
#if (HAVE_LIB_XML)
|
|
int ret = -1;
|
|
|
|
ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"limit");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"path",
|
|
"%s", path);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"hard_limit", !limit_set ? "N/A" : "%" PRId64,
|
|
hl_str);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(local->writer,
|
|
(xmlChar *)"soft_limit_percent",
|
|
!limit_set ? "N/A" : "%s", sl_final);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"soft_limit_value",
|
|
!limit_set ? "N/A" : "%" PRId64, sl_num);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"used_space", "%" PRId64, used);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"avail_space",
|
|
!limit_set ? "N/A" : "%" PRId64, avail);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"sl_exceeded", !limit_set ? "N/A" : "%s", sl);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"hl_exceeded", !limit_set ? "N/A" : "%s", hl);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterEndElement(local->writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
out:
|
|
return ret;
|
|
#else
|
|
return 0;
|
|
#endif /* HAVE_LIB_XML */
|
|
}
|
|
|
|
int
|
|
cli_quota_object_xml_output(cli_local_t *local, char *path, char *sl_str,
|
|
int64_t sl_val, quota_limits_t *limits,
|
|
quota_meta_t *used_space, int64_t avail, char *sl,
|
|
char *hl, gf_boolean_t limit_set)
|
|
{
|
|
#if (HAVE_LIB_XML)
|
|
int ret = -1;
|
|
|
|
ret = xmlTextWriterStartElement(local->writer, (xmlChar *)"limit");
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"path",
|
|
"%s", path);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"hard_limit", !limit_set ? "N/A" : "%" PRId64,
|
|
limits->hl);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(local->writer,
|
|
(xmlChar *)"soft_limit_percent",
|
|
!limit_set ? "N/A" : "%s", sl_str);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"soft_limit_value",
|
|
!limit_set ? "N/A" : "%" PRIu64, sl_val);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(local->writer,
|
|
(xmlChar *)"file_count", "%" PRId64,
|
|
used_space->file_count);
|
|
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"dir_count",
|
|
"%" PRIu64, used_space->dir_count);
|
|
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(local->writer, (xmlChar *)"available",
|
|
!limit_set ? "N/A" : "%" PRId64,
|
|
avail);
|
|
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"sl_exceeded", !limit_set ? "N/A" : "%s", sl);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterWriteFormatElement(
|
|
local->writer, (xmlChar *)"hl_exceeded", !limit_set ? "N/A" : "%s", hl);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
ret = xmlTextWriterEndElement(local->writer);
|
|
XML_RET_CHECK_AND_GOTO(ret, out);
|
|
|
|
out:
|
|
return ret;
|
|
#else
|
|
return 0;
|
|
#endif /* HAVE_LIB_XML */
|
|
}
|