From 845d6c76701a3de6a11b76b004176971411c714e Mon Sep 17 00:00:00 2001 From: ndarshan Date: Tue, 22 Jul 2014 14:19:19 +0530 Subject: cli: Xml output for geo-replication status command This patch adds xml output for geo-replication status and status detail command. sample: -------------------------------------------------------------- master :2a301d66-b9d2-44b4-b827-d680d67123eb:ssh://XXXXXXXXXX::slave localhost.localdomain 2a301d66-b9d2-44b4-b827-d680d67123eb /root/master_b1 ssh://XXXXXXXXXXX::slave faulty N/A N/A ------------------------------------------------------------- Change-Id: Ia19dbe751c3ab1ec7cb8923cdd6c8b99c374072f BUG: 1133464 Signed-off-by: ndarshan Reviewed-on: http://review.gluster.org/8089 Tested-by: Gluster Build System Reviewed-by: Kaushal M Signed-off-by: ndarshan Reviewed-on: http://review.gluster.org/8532 Reviewed-by: Sachin Pandit Reviewed-by: Vijay Bellur --- cli/src/cli-rpc-ops.c | 3 + cli/src/cli-xml-output.c | 255 +++++++++++++++++++++------ cli/src/cli.h | 2 + rpc/rpc-lib/src/protocol-common.h | 3 + xlators/mgmt/glusterd/src/glusterd-geo-rep.c | 29 +++ 5 files changed, 237 insertions(+), 55 deletions(-) diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c index b7c6691abd5..b4573f441f7 100644 --- a/cli/src/cli-rpc-ops.c +++ b/cli/src/cli-rpc-ops.c @@ -4018,6 +4018,9 @@ get_struct_variable (int mem_num, gf_gsync_status_t *sts_val) case 9: return (sts_val->bytes_remaining); case 10: return (sts_val->purges_remaining); case 11: return (sts_val->total_files_skipped); + case 12: return (sts_val->brick_host_uuid); + case 13: return (sts_val->slavekey); + case 14: return (sts_val->session_slave); default: goto out; } diff --git a/cli/src/cli-xml-output.c b/cli/src/cli-xml-output.c index 6ce8041f657..609f7847018 100644 --- a/cli/src/cli-xml-output.c +++ b/cli/src/cli-xml-output.c @@ -3899,76 +3899,219 @@ out: #if (HAVE_LIB_XML) int -cli_xml_output_vol_gsync_status (dict_t *dict, xmlTextWriterPtr writer) +gf_gsync_status_t_comparator (const void *p, const void *q) { - char master_key[PATH_MAX] = ""; - char slave_key[PATH_MAX] = ""; - char status_key[PATH_MAX] = ""; - char node_key[PATH_MAX] = ""; - char *master = NULL; - char *slave = NULL; - char *status = NULL; - char *node = NULL; - int ret = -1; - int gsync_count = 0; - int i = 1; + char *master1 = NULL; + char *master2 = NULL; + + master1 = get_struct_variable (1, (*(gf_gsync_status_t **)p)); + master2 = get_struct_variable (1, (*(gf_gsync_status_t **)q)); + if (!master1 || !master2) { + gf_log ("cli", GF_LOG_ERROR, + "struct member empty."); + return 0; + } + + return strcmp (master1,master2); +} +#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 = 12; + const int number_of_basic_fields = 7; + int closed = 1; + int session_closed = 1; + gf_gsync_status_t **status_values = NULL; + gf_boolean_t status_detail = _gf_false; + char status_value_name[PATH_MAX] = ""; + char *tmp = NULL; + char *volume = NULL; + char *volume_next = NULL; + char *slave = NULL; + char *slave_next = NULL; + char *title_values[] = {"master_node", + "master_node_uuid", + "master_brick", + "slave", + "status", + "checkpoint_status", + "crawl_status", + "files_syncd", + "files_pending", + "bytes_pending", + "deletes_pending", + "files_skipped"}; - ret = dict_get_int32 (dict, "gsync-count", &gsync_count); + GF_ASSERT (dict); + + ret = dict_get_int32 (dict, "gsync-count", &count); if (ret) goto out; - for (i=1; i <= gsync_count; i++) { - snprintf (node_key, sizeof(node_key), "node%d", i); - snprintf (master_key, sizeof(master_key), "master%d", i); - snprintf (slave_key, sizeof(slave_key), "slave%d", i); - snprintf (status_key, sizeof(status_key), "status%d", i); + status_detail = dict_get_str_boolean (dict, "status-detail", + _gf_false); - ret = dict_get_str (dict, node_key, &node); - if (ret) - goto out; + status_values = GF_CALLOC (count, sizeof (gf_gsync_status_t *), + gf_common_mt_char); + if (!status_values) { + ret = -1; + goto out; + } - ret = dict_get_str (dict, master_key, &master); - if (ret) + 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; + } - ret = dict_get_str (dict, slave_key, &slave); - if (ret) - goto out; + snprintf (status_value_name, sizeof (status_value_name), + "status_value%d", i); - ret = dict_get_str (dict, status_key, &status); - if (ret) + 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 (14, 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); - ret = xmlTextWriterWriteFormatElement (writer, - (xmlChar *)"node", - "%s", node); - XML_RET_CHECK_AND_GOTO (ret, out); + for (j = 0; j < number_of_fields; j++) { + // if detail option is not set and field is not under + // basic fields or if field is volume then skip + if(!status_detail && j >= number_of_basic_fields) + continue; - ret = xmlTextWriterWriteFormatElement (writer, - (xmlChar *)"master", - "%s", master); - XML_RET_CHECK_AND_GOTO (ret, out); + // Displaying the master_node uuid as second field - ret = xmlTextWriterWriteFormatElement (writer, - (xmlChar *)"slave", - "%s", slave); - XML_RET_CHECK_AND_GOTO (ret, out); + if (j == 1) + tmp = get_struct_variable (12, + status_values[i]); + else + 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 *)"status", - "%s", status); - XML_RET_CHECK_AND_GOTO (ret, 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 (13, status_values[i]); + slave_next = get_struct_variable (13, + 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: gf_log ("cli",GF_LOG_DEBUG, "Returning %d", ret); return ret; @@ -4032,19 +4175,21 @@ cli_xml_output_vol_gsync (dict_t *dict, int op_ret, int op_errno, break; case GF_GSYNC_OPTION_TYPE_CONFIG: - ret = xmlTextWriterStartElement (writer, (xmlChar *)"config"); - XML_RET_CHECK_AND_GOTO (ret, out); + 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 = cli_xml_generate_gsync_config (dict, writer); + if (ret) + goto out; - ret = xmlTextWriterEndElement (writer); - XML_RET_CHECK_AND_GOTO (ret, 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); + ret = cli_xml_output_vol_gsync_status (dict, writer); break; default: ret = 0; diff --git a/cli/src/cli.h b/cli/src/cli.h index 74d35992680..b48911648fa 100644 --- a/cli/src/cli.h +++ b/cli/src/cli.h @@ -181,6 +181,8 @@ extern struct cli_state *global_state; /* use only in readline callback */ typedef const char *(*cli_selector_t) (void *wcon); +char *get_struct_variable (int mem_num, gf_gsync_status_t *sts_val); + void *cli_getunamb (const char *tok, void **choices, cli_selector_t sel); int cli_cmd_register (struct cli_cmd_tree *tree, struct cli_cmd *cmd); diff --git a/rpc/rpc-lib/src/protocol-common.h b/rpc/rpc-lib/src/protocol-common.h index 1856387826b..b3e677afd17 100644 --- a/rpc/rpc-lib/src/protocol-common.h +++ b/rpc/rpc-lib/src/protocol-common.h @@ -244,6 +244,9 @@ struct gf_gsync_detailed_status_ { char bytes_remaining[NAME_MAX]; char purges_remaining[NAME_MAX]; char total_files_skipped[NAME_MAX]; + char brick_host_uuid[NAME_MAX]; + char slavekey[NAME_MAX]; + char session_slave[NAME_MAX]; }; enum glusterd_mgmt_v3_procnum { diff --git a/xlators/mgmt/glusterd/src/glusterd-geo-rep.c b/xlators/mgmt/glusterd/src/glusterd-geo-rep.c index def83fb2055..f4c5f1cb685 100644 --- a/xlators/mgmt/glusterd/src/glusterd-geo-rep.c +++ b/xlators/mgmt/glusterd/src/glusterd-geo-rep.c @@ -3471,6 +3471,10 @@ glusterd_read_status_file (glusterd_volinfo_t *volinfo, char *slave, char *statefile = NULL; char *socketfile = NULL; dict_t *confd = NULL; + char *slavekey = NULL; + char *slaveentry = NULL; + char *brick_host_uuid = NULL; + int brick_host_uuid_length = 0; int gsync_count = 0; int i = 0; int ret = 0; @@ -3676,9 +3680,34 @@ store_status: sts_val->node[strlen(node)] = '\0'; memcpy (sts_val->brick, brickinfo->path, strlen(brickinfo->path)); sts_val->brick[strlen(brickinfo->path)] = '\0'; + + ret = glusterd_get_slave (volinfo, slave, &slavekey); + if (ret < 0) { + GF_FREE (sts_val); + goto out; + } + memcpy (sts_val->slavekey, slavekey, strlen(slavekey)); + sts_val->slavekey[strlen(slavekey)] = '\0'; + + brick_host_uuid = uuid_utoa(brickinfo->uuid); + brick_host_uuid_length = strlen (brick_host_uuid); + memcpy (sts_val->brick_host_uuid, brick_host_uuid, + brick_host_uuid_length); + sts_val->brick_host_uuid[brick_host_uuid_length] = '\0'; + memcpy (sts_val->master, master, strlen(master)); sts_val->master[strlen(master)] = '\0'; + ret = dict_get_str (volinfo->gsync_slaves, slavekey, + &slaveentry); + if (ret < 0) { + GF_FREE (sts_val); + goto out; + } + memcpy (sts_val->session_slave, slaveentry, + strlen(slaveentry)); + sts_val->session_slave[strlen(slaveentry)] = '\0'; + snprintf (sts_val_name, sizeof (sts_val_name), "status_value%d", gsync_count); ret = dict_set_bin (dict, sts_val_name, sts_val, sizeof(gf_gsync_status_t)); if (ret) { -- cgit