summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cli/src/cli-cmd-parser.c19
-rw-r--r--cli/src/cli-cmd-volume.c2
-rw-r--r--cli/src/cli-rpc-ops.c471
-rw-r--r--cli/src/cli.h14
-rw-r--r--rpc/xdr/src/cli1-xdr.x4
5 files changed, 367 insertions, 143 deletions
diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c
index 26ac6f384eb..547f1d90f01 100644
--- a/cli/src/cli-cmd-parser.c
+++ b/cli/src/cli-cmd-parser.c
@@ -1763,7 +1763,7 @@ cli_cmd_gsync_set_parse (const char **words, int wordcount, dict_t **options)
unsigned cmdi = 0;
char *opwords[] = { "create", "status", "start", "stop",
"config", "force", "delete",
- "push-pem", NULL };
+ "push-pem", "detail", NULL };
char *w = NULL;
GF_ASSERT (words);
@@ -1776,7 +1776,7 @@ cli_cmd_gsync_set_parse (const char **words, int wordcount, dict_t **options)
/* new syntax:
*
* volume geo-replication $m $s create [push-pem] [force]
- * volume geo-replication [$m [$s]] status
+ * volume geo-replication [$m [$s]] status [detail]
* volume geo-replication [$m] $s config [[!]$opt [$val]]
* volume geo-replication $m $s start|stop [force]
* volume geo-replication $m $s delete
@@ -1873,6 +1873,21 @@ cli_cmd_gsync_set_parse (const char **words, int wordcount, dict_t **options)
if (ret)
goto out;
+ if (!strcmp ((char *)words[wordcount-1], "detail")) {
+ if (strcmp ((char *)words[wordcount-2], "status")) {
+ ret = -1;
+ goto out;
+ }
+ if (!slavei || !masteri) {
+ ret = -1;
+ goto out;
+ }
+ ret = dict_set_uint32 (dict, "status-detail", _gf_true);
+ if (ret)
+ goto out;
+ cmdi++;
+ }
+
if (type != GF_GSYNC_OPTION_TYPE_CONFIG &&
(cmdi < wordcount - 1 || glob))
goto out;
diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c
index 8d508158690..040f610adca 100644
--- a/cli/src/cli-cmd-volume.c
+++ b/cli/src/cli-cmd-volume.c
@@ -1894,7 +1894,7 @@ struct cli_cmd volume_cmds[] = {
#if (SYNCDAEMON_COMPILE)
{"volume "GEOREP" [<VOLNAME>] [<SLAVE-URL>] {create [push-pem] [force]"
- "|start [force]|stop [force]|config|status|delete} [options...]",
+ "|start [force]|stop [force]|config|status [detail]|delete} [options...]",
cli_cmd_volume_gsync_set_cbk,
"Geo-sync operations",
cli_cmd_check_gsync_exists_cbk},
diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c
index 25e2796a3ee..74b7ac0c94b 100644
--- a/cli/src/cli-rpc-ops.c
+++ b/cli/src/cli-rpc-ops.c
@@ -3808,156 +3808,121 @@ gf_cli_gsync_config_command (dict_t *dict)
return runner_run (&runner);
}
-static int
-gf_cli_fetch_gsyncd_health_uptime (char *status, char **health, char **uptime)
+int
+gf_cli_fetch_gsyncd_status_values (char *status,
+ gf_cli_gsync_status_t *sts_val)
{
+ int32_t ret = -1;
char *tmp = NULL;
char *save_ptr = NULL;
- int32_t ret = -1;
char *key = NULL;
char *value = NULL;
- if (!health || !uptime || !status) {
- gf_log ("", GF_LOG_ERROR, "health or uptime or status is null");
+ if (!status || !sts_val) {
+ gf_log ("", GF_LOG_ERROR, "status or sts_val is null");
goto out;
}
tmp = strtok_r (status, "\n", &save_ptr);
if (tmp)
- *health = gf_strdup (tmp);
+ sts_val->health = gf_strdup (tmp);
while (tmp) {
key = strtok_r (tmp, "=", &value);
- if ((key) && (!strcmp(key, "Uptime"))) {
- *uptime = gf_strdup (value);
- break;
- }
- tmp = strtok_r (NULL, ";", &save_ptr);
- }
- if (*health)
- ret = 0;
+ if ((key) && (!strcmp(key, "Uptime")))
+ sts_val->uptime = gf_strdup (value);
- if (!*uptime)
- *uptime = gf_strdup ("N/A");
-out:
- gf_log ("", GF_LOG_DEBUG, "Returning %d.", ret);
- return ret;
-}
+ if ((key) && (!strcmp(key, "FilesSyncd")))
+ sts_val->files_syncd = gf_strdup (value);
-int
-gf_cli_gsync_out_status (dict_t *dict)
-{
- char mst[PATH_MAX] = {0, };
- char slv[PATH_MAX] = {0, };
- char sts[PATH_MAX] = {0, };
- char nds[PATH_MAX] = {0, };
- char errmsg[1024] = "";
- char *sts_val = NULL;
- char *master = NULL;
- char *slave = NULL;
- char **output_values = NULL;
- char **dict_values = NULL;
- char *hyphens = NULL;
- char *title_values[] = {"NODE", "MASTER", "SLAVE",
- "HEALTH", "UPTIME"};
- int gsync_count = 0;
- int i = 0;
- int j = 0;
- int dict_val_count = 0;
- int ret = 0;
- int spacing[5] = {0, 0, 0, 0, 10};
- int total_spacing = 0;
+ if ((key) && (!strcmp(key, "FilesPending")))
+ sts_val->files_pending = gf_strdup (value);
- /* Checks if any session is active or not */
- ret = dict_get_int32 (dict, "gsync-count", &gsync_count);
- if (ret) {
- ret = dict_get_str (dict, "master", &master);
+ if ((key) && (!strcmp(key, "BytesPending"))) {
+ value = gf_uint64_2human_readable(atol(value));
+ sts_val->bytes_pending = gf_strdup (value);
+ }
- ret = dict_get_str (dict, "slave", &slave);
+ if ((key) && (!strcmp(key, "DeletesPending")))
+ sts_val->deletes_pending = gf_strdup (value);
- if (master) {
- if (slave)
- snprintf (errmsg, sizeof(errmsg), "No active "
- "geo-replication sessions between %s"
- " and %s", master, slave);
- else
- snprintf (errmsg, sizeof(errmsg), "No active "
- "geo-replication sessions for %s",
- master);
- } else
- snprintf (errmsg, sizeof(errmsg), "No active "
- "geo-replication sessions");
+ tmp = strtok_r (NULL, ";", &save_ptr);
+ }
- gf_log ("cli", GF_LOG_INFO, "%s", errmsg);
- cli_out ("%s", errmsg);
+ if (sts_val->health)
ret = 0;
- goto out;
- }
- /* (gsync_count = number of nodes reporting output *
- 5 = number of fields) = total number of values to
- be fetched from dict */
- dict_values = GF_CALLOC (gsync_count * 5, sizeof (char *),
- gf_common_mt_char);
- if (!dict_values) {
- gf_log ("cli", GF_LOG_ERROR, "Out Of Memory");
- ret = -1;
- goto out;
- }
+ if (!sts_val->uptime)
+ sts_val->uptime = gf_strdup ("N/A");
- for (i = 1, j = 0; i <= gsync_count; i++) {
- snprintf (nds, sizeof(nds), "node%d", i);
- snprintf (mst, sizeof(mst), "master%d", i);
- snprintf (slv, sizeof(slv), "slave%d", i);
- snprintf (sts, sizeof(sts), "status%d", i);
+ if (!sts_val->files_syncd)
+ sts_val->files_syncd = gf_strdup ("N/A");
- /* Fetching the values from dict, and calculating
- the max length for each field */
- ret = dict_get_str (dict, nds, &dict_values[j]);
- if (ret)
- goto out;
- if (strlen (dict_values[j]) > spacing [0])
- spacing[0] = strlen (dict_values[j]);
- j++;
+ if (!sts_val->files_pending)
+ sts_val->files_pending = gf_strdup ("N/A");
- ret = dict_get_str (dict, mst, &dict_values[j]);
- if (ret)
- goto out;
- if (strlen (dict_values[j]) > spacing [1])
- spacing[1] = strlen (dict_values[j]);
- j++;
+ if (!sts_val->bytes_pending)
+ sts_val->bytes_pending = gf_strdup ("N/A");
- ret = dict_get_str (dict, slv, &dict_values[j]);
- if (ret)
- goto out;
- if (strlen (dict_values[j]) > spacing [2])
- spacing[2] = strlen (dict_values[j]);
- j++;
+ if (!sts_val->deletes_pending)
+ sts_val->deletes_pending = gf_strdup ("N/A");
- ret = dict_get_str (dict, sts, &sts_val);
- if (ret)
- goto out;
+out:
+ gf_log ("", GF_LOG_DEBUG, "Returning %d.", ret);
+ return ret;
+}
- /* Fetching health and uptime from sts_val */
- ret = gf_cli_fetch_gsyncd_health_uptime (sts_val,
- &dict_values[j],
- &dict_values[j+1]);
- if (ret)
- goto out;
+char*
+get_struct_variable (int mem_num, gf_cli_gsync_status_t *sts_val)
+{
+ switch (mem_num) {
+ case 0: return (sts_val->node);
+ case 1: return (sts_val->master);
+ case 2: return (sts_val->slave);
+ case 3: return (sts_val->health);
+ case 4: return (sts_val->uptime);
+ case 5: return (sts_val->files_syncd);
+ case 6: return (sts_val->files_pending);
+ case 7: return (sts_val->bytes_pending);
+ case 8: return (sts_val->deletes_pending);
+ default:
+ goto out;
+ }
- if (strlen (dict_values[j]) > spacing [3])
- spacing[3] = strlen (dict_values[j]);
- j++;
+out:
+ return NULL;
+}
- if (strlen (dict_values[j]) > spacing [4])
- spacing[4] = strlen (dict_values[j]);
- j++;
- }
+int
+gf_cli_print_status (char **title_values,
+ gf_cli_gsync_status_t **sts_vals,
+ int *spacing, int gsync_count,
+ int number_of_fields, int is_detail)
+{
+ int indents = 0;
+ int i = 0;
+ int j = 0;
+ int ret = 0;
+ int total_spacing = 0;
+ char **output_values = NULL;
+ char *tmp = NULL;
+ char *hyphens = NULL;
+ char heading[PATH_MAX] = {0, };
+ char indent_spaces[PATH_MAX] = {0, };
/* calculating spacing for hyphens */
- for (i = 0; i < 5; i++) {
+ for (i = 0; i < number_of_fields; i++) {
+ /* Suppressing master and slave output for status detail */
+ if ((is_detail) && ((i == 1) || (i == 2))) {
+ total_spacing++;
+ continue;
+ } else if ((!is_detail) && (i > 4)) {
+ /* Suppressing detailed output for
+ * status */
+ continue;
+ }
spacing[i] += 3; /* Adding extra space to
distinguish between fields */
total_spacing += spacing[i];
@@ -3965,73 +3930,298 @@ gf_cli_gsync_out_status (dict_t *dict)
total_spacing += 4; /* For the spacing between the fields */
/* char pointers for each field */
- output_values = GF_CALLOC (5, sizeof (char *), gf_common_mt_char);
- if (!output_values)
+ output_values = GF_CALLOC (number_of_fields, sizeof (char *),
+ gf_common_mt_char);
+ if (!output_values) {
ret = -1;
- for (i = 0; i < 5; i++) {
+ goto out;
+ }
+ for (i = 0; i < number_of_fields; i++) {
output_values[i] = GF_CALLOC (spacing[i] + 1, sizeof (char),
gf_common_mt_char);
- if (!output_values[i])
+ if (!output_values[i]) {
ret = -1;
+ goto out;
+ }
}
hyphens = GF_CALLOC (total_spacing + 1, sizeof (char),
gf_common_mt_char);
- if (!hyphens)
+ if (!hyphens) {
ret = -1;
+ goto out;
+ }
+ ret = snprintf(heading, sizeof(heading), "MASTER: %s SLAVE: %s",
+ sts_vals[0]->master, sts_vals[0]->slave);
if (ret) {
- gf_log ("cli", GF_LOG_ERROR, "Out Of Memory");
+ if (ret < sizeof(heading))
+ heading[ret] = '\0';
+ else
+ heading[sizeof(heading) - 1] = '\0';
+ ret = 0;
+ } else {
ret = -1;
goto out;
}
+ if (is_detail) {
+ cli_out (" ");
+ if (strlen(heading) > total_spacing)
+ cli_out ("%s", heading);
+ else {
+ /* Printing the heading with centre justification */
+ indents = (total_spacing - strlen(heading)) / 2;
+ memset (indent_spaces, ' ', indents);
+ indent_spaces[indents] = '\0';
+ ret = snprintf (hyphens, total_spacing, "%s%s",
+ indent_spaces, heading);
+ if (ret) {
+ hyphens[ret] = '\0';
+ cli_out ("%s", hyphens);
+ ret = 0;
+ } else {
+ ret = -1;
+ goto out;
+ }
+ }
+ cli_out (" ");
+ }
+
/* setting the title "NODE", "MASTER", etc. from title_values[]
and printing the same */
- for (j = 0; j < 5; j++) {
+ for (j = 0; j < number_of_fields; j++) {
+ /* Suppressing master and slave output for status detail */
+ if ((is_detail) && ((j == 1) || (j == 2))) {
+ output_values[j][0] = '\0';
+ continue;
+ } else if ((!is_detail) && (j > 4)) {
+ /* Suppressing detailed output for
+ * status */
+ output_values[j][0] = '\0';
+ continue;
+ }
memset (output_values[j], ' ', spacing[j]);
memcpy (output_values[j], title_values[j],
strlen(title_values[j]));
output_values[j][spacing[j]] = '\0';
}
- cli_out ("%s %s %s %s %s", output_values[0], output_values[1],
- output_values[2], output_values[3], output_values[4]);
+ cli_out ("%s %s %s %s %s %s %s %s %s", output_values[0],
+ output_values[1], output_values[2], output_values[3],
+ output_values[4], output_values[5], output_values[6],
+ output_values[7], output_values[8]);
/* setting and printing the hyphens */
memset (hyphens, '-', total_spacing);
hyphens[total_spacing] = '\0';
cli_out ("%s", hyphens);
- for (i = 1, dict_val_count = 0; i <= gsync_count; i++) {
- /* Setting the field values for each row */
- for (j = 0; j < 5; j++) {
+ for (i = 0; i < gsync_count; i++) {
+ for (j = 0; j < number_of_fields; j++) {
+ /* Suppressing master and slave output for
+ * status detail */
+ if ((is_detail) && ((j == 1) || (j == 2))) {
+ output_values[j][0] = '\0';
+ continue;
+ } else if ((!is_detail) && (j > 4)) {
+ /* Suppressing detailed output for
+ * status */
+ output_values[j][0] = '\0';
+ continue;
+ }
+ tmp = get_struct_variable(j, sts_vals[i]);
+ if (!tmp) {
+ gf_log ("", GF_LOG_ERROR,
+ "struct member empty.");
+ ret = -1;
+ goto out;
+ }
memset (output_values[j], ' ', spacing[j]);
- memcpy (output_values[j], dict_values[dict_val_count],
- strlen(dict_values[dict_val_count]));
+ memcpy (output_values[j], tmp, strlen (tmp));
output_values[j][spacing[j]] = '\0';
- dict_val_count++;
}
- cli_out ("%s %s %s %s %s", output_values[0], output_values[1],
- output_values[2], output_values[3], output_values[4]);
+
+ cli_out ("%s %s %s %s %s %s %s %s %s", output_values[0],
+ output_values[1], output_values[2], output_values[3],
+ output_values[4], output_values[5], output_values[6],
+ output_values[7], output_values[8]);
}
+
out:
if (output_values) {
- for (i = 0; i < 5; i++) {
+ for (i = 0; i < number_of_fields; i++) {
if (output_values[i])
GF_FREE (output_values[i]);
}
GF_FREE (output_values);
}
- if (dict_values)
- GF_FREE (dict_values);
-
if (hyphens)
GF_FREE (hyphens);
return ret;
}
+int
+gf_cli_read_status_data (dict_t *dict,
+ gf_cli_gsync_status_t **sts_vals,
+ int *spacing, int gsync_count,
+ int number_of_fields)
+{
+ int ret = 0;
+ int i = 0;
+ int j = 0;
+ char mst[PATH_MAX] = {0, };
+ char slv[PATH_MAX] = {0, };
+ char sts[PATH_MAX] = {0, };
+ char nds[PATH_MAX] = {0, };
+ char *status = NULL;
+ char *tmp = NULL;
+
+ /* Storing per node status info in each object */
+ for (i = 0; i < gsync_count; i++) {
+ snprintf (nds, sizeof(nds), "node%d", i + 1);
+ snprintf (mst, sizeof(mst), "master%d", i + 1);
+ snprintf (slv, sizeof(slv), "slave%d", i + 1);
+ snprintf (sts, sizeof(sts), "status%d", i + 1);
+
+ /* Fetching the values from dict, and calculating
+ the max length for each field */
+ ret = dict_get_str (dict, nds, &(sts_vals[i]->node));
+ if (ret)
+ goto out;
+
+ ret = dict_get_str (dict, mst, &(sts_vals[i]->master));
+ if (ret)
+ goto out;
+
+ ret = dict_get_str (dict, slv, &(sts_vals[i]->slave));
+ if (ret)
+ goto out;
+
+ ret = dict_get_str (dict, sts, &status);
+ if (ret)
+ goto out;
+
+ /* Fetching health and uptime from sts_val */
+ ret = gf_cli_fetch_gsyncd_status_values (status, sts_vals[i]);
+ if (ret)
+ goto out;
+
+ for (j = 0; j < number_of_fields; j++) {
+ tmp = get_struct_variable(j, sts_vals[i]);
+ if (!tmp) {
+ gf_log ("", GF_LOG_ERROR,
+ "struct member empty.");
+ ret = -1;
+ goto out;
+ }
+ if (strlen (tmp) > spacing[j])
+ spacing[j] = strlen (tmp);
+ }
+ }
+
+out:
+ return ret;
+}
+
+int
+gf_cli_gsync_status_output (dict_t *dict, int status_detail)
+{
+ int gsync_count = 0;
+ int i = 0;
+ int j = 0;
+ int ret = 0;
+ int spacing[10] = {0};
+ int num_of_fields = 9;
+ char errmsg[1024] = "";
+ char *master = NULL;
+ char *slave = NULL;
+ char *tmp = NULL;
+ char *title_values[] = {"NODE", "MASTER", "SLAVE",
+ "HEALTH", "UPTIME",
+ "FILES SYNCD",
+ "FILES PENDING",
+ "BYTES PENDING",
+ "DELETES PENDING"};
+ gf_cli_gsync_status_t **sts_vals = NULL;
+
+ /* Checks if any session is active or not */
+ ret = dict_get_int32 (dict, "gsync-count", &gsync_count);
+ if (ret) {
+ ret = dict_get_str (dict, "master", &master);
+
+ ret = dict_get_str (dict, "slave", &slave);
+
+ if (master) {
+ if (slave)
+ snprintf (errmsg, sizeof(errmsg), "No active "
+ "geo-replication sessions between %s"
+ " and %s", master, slave);
+ else
+ snprintf (errmsg, sizeof(errmsg), "No active "
+ "geo-replication sessions for %s",
+ master);
+ } else
+ snprintf (errmsg, sizeof(errmsg), "No active "
+ "geo-replication sessions");
+
+ gf_log ("cli", GF_LOG_INFO, "%s", errmsg);
+ cli_out ("%s", errmsg);
+ ret = 0;
+ goto out;
+ }
+
+ for (i = 0; i < num_of_fields; i++)
+ spacing[i] = strlen(title_values[i]);
+
+ /* gsync_count = number of nodes reporting output.
+ each sts_val object will store output of each
+ node */
+ sts_vals = GF_CALLOC (gsync_count, sizeof (gf_cli_gsync_status_t *),
+ gf_common_mt_char);
+ if (!sts_vals) {
+ ret = -1;
+ goto out;
+ }
+ for (i = 0; i < gsync_count; i++) {
+ sts_vals[i] = GF_CALLOC (1, sizeof (gf_cli_gsync_status_t),
+ gf_common_mt_char);
+ if (!sts_vals[i]) {
+ ret = -1;
+ goto out;
+ }
+ }
+
+ ret = gf_cli_read_status_data (dict, sts_vals, spacing,
+ gsync_count, num_of_fields);
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR, "Unable to read status data");
+ goto out;
+ }
+
+ ret = gf_cli_print_status (title_values, sts_vals, spacing, gsync_count,
+ num_of_fields, status_detail);
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR, "Unable to print status output");
+ goto out;
+ }
+
+out:
+ if (sts_vals) {
+ for (i = 0; i < gsync_count; i++) {
+ for (j = 3; j < num_of_fields; j++) {
+ tmp = get_struct_variable(j, sts_vals[i]);
+ if (tmp)
+ GF_FREE (tmp);
+ }
+ }
+ GF_FREE (sts_vals);
+ }
+
+ return ret;
+}
+
static int32_t
write_contents_to_common_pem_file (dict_t *dict, int output_count)
{
@@ -4266,6 +4456,8 @@ gf_cli_gsync_set_cbk (struct rpc_req *req, struct iovec *iov,
char *slave = NULL;
int32_t type = 0;
call_frame_t *frame = NULL;
+ gf_boolean_t status_detail = _gf_false;
+
if (req->rpc_status == -1) {
ret = -1;
@@ -4341,7 +4533,10 @@ gf_cli_gsync_set_cbk (struct rpc_req *req, struct iovec *iov,
break;
case GF_GSYNC_OPTION_TYPE_STATUS:
- ret = gf_cli_gsync_out_status (dict);
+ status_detail = dict_get_str_boolean (dict,
+ "status-detail",
+ _gf_false);
+ ret = gf_cli_gsync_status_output (dict, status_detail);
break;
case GF_GSYNC_OPTION_TYPE_DELETE:
diff --git a/cli/src/cli.h b/cli/src/cli.h
index 259f3bd3980..9b3afff36dc 100644
--- a/cli/src/cli.h
+++ b/cli/src/cli.h
@@ -147,6 +147,18 @@ struct cli_local {
#endif
};
+struct gf_cli_gsync_detailed_status_ {
+ char *node;
+ char *master;
+ char *slave;
+ char *health;
+ char *uptime;
+ char *files_syncd;
+ char *files_pending;
+ char *bytes_pending;
+ char *deletes_pending;
+};
+
struct cli_volume_status {
int port;
int online;
@@ -165,6 +177,8 @@ struct cli_volume_status {
#endif
};
+typedef struct gf_cli_gsync_detailed_status_ gf_cli_gsync_status_t;
+
typedef struct cli_volume_status cli_volume_status_t;
typedef struct cli_local cli_local_t;
diff --git a/rpc/xdr/src/cli1-xdr.x b/rpc/xdr/src/cli1-xdr.x
index b85ecf87ab2..d674030ec78 100644
--- a/rpc/xdr/src/cli1-xdr.x
+++ b/rpc/xdr/src/cli1-xdr.x
@@ -76,8 +76,8 @@ enum gf1_cli_gsync_set {
GF_GSYNC_OPTION_TYPE_CONFIG,
GF_GSYNC_OPTION_TYPE_STATUS,
GF_GSYNC_OPTION_TYPE_ROTATE,
- GF_GSYNC_OPTION_TYPE_DELETE,
- GF_GSYNC_OPTION_TYPE_CREATE
+ GF_GSYNC_OPTION_TYPE_CREATE,
+ GF_GSYNC_OPTION_TYPE_DELETE
};
enum gf1_cli_stats_op {