From 169c73f28dae61236de54889edcaa8236d91da59 Mon Sep 17 00:00:00 2001 From: Rajesh Amaravathi Date: Wed, 7 Dec 2011 20:51:03 +0530 Subject: cli: volume status enhancement * Support "gluster volume status (all)" option to display all volumes' status. * On option "detail" appended to "gluster volume status *", amount of storage free, total storage, and backend filesystem details like inode size, inode count, free inodes, fs type, device name of each brick is displayed. * One can also obtain [detailed]status of only one brick. * Format of the enhanced volume status command is: "gluster volume status [all|] [] [detail]" * Some generic functions have been added to common-utils: skipword get_nth_word These functions enable parsing and fetching of words in a sentence. glusterd_get_brick_root (in glusterd) These are self explanatory. Change-Id: I6f40c1e19810f8504cd3b1786207364053d82e28 BUG: 765464 Signed-off-by: Rajesh Amaravathi Reviewed-on: http://review.gluster.com/777 Tested-by: Gluster Build System Reviewed-by: Amar Tumballi --- cli/src/cli-cmd-parser.c | 71 ++++++++++++++++++-- cli/src/cli-cmd-volume.c | 166 ++++++++++++++++++++++++++++++++++++++++++---- cli/src/cli-rpc-ops.c | 169 ++++++++++++++++++++++++++++++++++++++--------- cli/src/cli.h | 28 +++++++- 4 files changed, 381 insertions(+), 53 deletions(-) (limited to 'cli') diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c index fa46fa066..acbd960ba 100644 --- a/cli/src/cli-cmd-parser.c +++ b/cli/src/cli-cmd-parser.c @@ -1795,23 +1795,84 @@ out: return ret; } -int32_t +int cli_cmd_volume_status_parse (const char **words, int wordcount, - dict_t **options) + dict_t **options) { dict_t *dict = NULL; int ret = -1; + int cmd = 0; - GF_ASSERT (words); GF_ASSERT (options); dict = dict_new (); if (!dict) goto out; - GF_ASSERT(words[2]); + switch (wordcount) { + + case 2: + cmd = GF_CLI_STATUS_ALL; + ret = 0; + break; + + case 3: + if (!strcmp (words[2], "all")) { + + cmd = GF_CLI_STATUS_ALL; + ret = 0; + + } else if (!strcmp (words[2], "detail")) { + + cmd = GF_CLI_STATUS_ALL_DETAIL; + ret = 0; + + } else { + cmd = GF_CLI_STATUS_VOL; + ret = dict_set_str (dict, "volname", (char *)words[2]); + } + break; + + case 4: + if (!strcmp (words[2], "all") && + !strcmp (words[3], "detail")) { + + cmd = GF_CLI_STATUS_ALL_DETAIL; + ret = 0; + + } else if (!strcmp (words[3], "detail")) { + cmd = GF_CLI_STATUS_VOL_DETAIL; + ret = dict_set_str (dict, "volname", (char *)words[2]); + + } else { + + cmd = GF_CLI_STATUS_BRICK; + ret = dict_set_str (dict, "volname", (char *)words[2]); + if (ret) + goto out; + ret = dict_set_str (dict, "brick", (char *)words[3]); + } + break; + + case 5: + if (strcmp (words[4], "detail")) + goto out; + + cmd = GF_CLI_STATUS_BRICK_DETAIL; + ret = dict_set_str (dict, "volname", (char *)words[2]); + if (ret) + goto out; + ret = dict_set_str (dict, "brick", (char *)words[3]); + break; + + default: + goto out; + } + + if (ret) + goto out; - ret = dict_set_str (dict, "volname", (char *)words[2]); + ret = dict_set_int32 (dict, "cmd", cmd); if (ret) goto out; diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c index 009896d9c..38c16797e 100644 --- a/cli/src/cli-cmd-volume.c +++ b/cli/src/cli-cmd-volume.c @@ -1344,39 +1344,177 @@ out: int cli_cmd_volume_status_cbk (struct cli_state *state, - struct cli_cmd_word *word, - const char **words, int wordcount) + struct cli_cmd_word *word, + const char **words, int wordcount) { int ret = -1; rpc_clnt_procedure_t *proc = NULL; call_frame_t *frame = NULL; dict_t *dict = NULL; + uint32_t cmd = 0; - if (wordcount != 3) { + ret = cli_cmd_volume_status_parse (words, wordcount, &dict); + + if (ret) { cli_usage_out (word->pattern); goto out; } - proc = &cli_rpc_prog->proctable[GLUSTER_CLI_STATUS_VOLUME]; + ret = dict_get_uint32 (dict, "cmd", &cmd); + if (ret) + goto out; + + if (!(cmd & GF_CLI_STATUS_ALL)) { + /* for one volume or brick */ + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_STATUS_VOLUME]; + } else { + /* volume status all or all detail */ + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_STATUS_ALL]; + } + + if (!proc->fn) + goto out; frame = create_frame (THIS, THIS->ctx->pool); if (!frame) goto out; - ret = cli_cmd_volume_status_parse (words, wordcount, &dict); + ret = proc->fn (frame, THIS, dict); + + out: + if (dict) + dict_unref (dict); + return ret; +} + + +int +cli_get_detail_status (dict_t *dict, int i, cli_volume_status_t *status) +{ + uint64_t free = -1; + uint64_t total = -1; + char key[1024] = {0}; + int ret = 0; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.free", i); + ret = dict_get_uint64 (dict, key, &free); if (ret) goto out; - if (proc->fn) - ret = proc->fn (frame, THIS, dict); + status->free = gf_uint64_2human_readable (free); + if (!status->free) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.total", i); + ret = dict_get_uint64 (dict, key, &total); + if (ret) + goto out; + + status->total = gf_uint64_2human_readable (total); + if (!status->total) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.device", i); + ret = dict_get_str (dict, key, &(status->device)); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.block_size", i); + ret = dict_get_uint64 (dict, key, &(status->block_size)); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.mnt_options", i); + ret = dict_get_str (dict, key, &(status->mount_options)); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.fs_name", i); + ret = dict_get_str (dict, key, &(status->fs_name)); + if (ret) + goto out; + + if (IS_EXT_FS(status->fs_name) || + !strcmp (status->fs_name, "xfs")) { + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.inode_size", i); + ret = dict_get_str (dict, key, &(status->inode_size)); + if (ret) + status->inode_size = NULL; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.total_inodes", i); + ret = dict_get_uint64 (dict, key, &(status->total_inodes)); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.free_inodes", i); + ret = dict_get_uint64 (dict, key, &(status->free_inodes)); + if (ret) + goto out; + + } else { + status->inode_size = NULL; + status->total_inodes = 0; + status->free_inodes = 0; + } out: return ret; } +void +cli_print_detailed_status (cli_volume_status_t *status) +{ + cli_out ("%-20s : %-20s", "Brick", status->brick); + cli_out ("%-20s : %-20d", "Port", status->port); + cli_out ("%-20s : %-20c", "Online", (status->online) ? 'Y' : 'N'); + cli_out ("%-20s : %-20s", "Pid", status->pid_str); + cli_out ("%-20s : %-20s", "File System", status->fs_name); + cli_out ("%-20s : %-20s", "Device", status->device); + + if (status->mount_options) { + cli_out ("%-20s : %-20s", "Mount Options", + status->mount_options); + } else { + cli_out ("%-20s : %-20s", "Mount Options", "N/A"); + } + + cli_out ("%-20s : %-20s", "Disk Space Free", status->free); + cli_out ("%-20s : %-20s", "Total Disk Space", status->total); + + if (status->inode_size) { + cli_out ("%-20s : %-20s", "Inode Size", + status->inode_size); + } else { + cli_out ("%-20s : %-20s", "Inode Size", "N/A"); + } + + if (status->total_inodes) { + cli_out ("%-20s : %-20ld", "Inode Count", + status->total_inodes); + } else { + cli_out ("%-20s : %-20s", "Inode Count", "N/A"); + } + + if (status->free_inodes) { + cli_out ("%-20s : %-20ld", "Free Inodes", + status->free_inodes); + } else { + cli_out ("%-20s : %-20s", "Free Inodes", "N/A"); + } +} int -cli_print_brick_status (char *brick, int port, int online, char *pid) +cli_print_brick_status (cli_volume_status_t *status) { int fieldlen = CLI_VOL_STATUS_BRICK_LEN; char buf[80] = {0,}; @@ -1385,22 +1523,24 @@ cli_print_brick_status (char *brick, int port, int online, char *pid) char *p = NULL; int num_tabs = 0; - bricklen = strlen (brick); - p = brick; + bricklen = strlen (status->brick); + p = status->brick; while (bricklen > 0) { if (bricklen > fieldlen) { i++; strncpy (buf, p, fieldlen); buf[strlen(buf) + 1] = '\0'; cli_out ("%s", buf); - p = brick + i * fieldlen; + p = status->brick + i * fieldlen; bricklen -= fieldlen; } else { num_tabs = (fieldlen - bricklen) / CLI_TAB_LENGTH + 1; printf ("%s", p); while (num_tabs-- != 0) printf ("\t"); - cli_out ("%d\t%c\t%s", port, online?'Y':'N', pid); + cli_out ("%d\t%c\t%s", + status->port, status->online?'Y':'N', + status->pid_str); bricklen = 0; } } @@ -1597,7 +1737,7 @@ struct cli_cmd volume_cmds[] = { cli_cmd_volume_top_cbk, "volume top operations"}, - { "volume status ", + { "volume status [all|] [brick] [detail]", cli_cmd_volume_status_cbk, "display status of specified volume"}, diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c index f6ae1d941..06c52dac1 100644 --- a/cli/src/cli-rpc-ops.c +++ b/cli/src/cli-rpc-ops.c @@ -3796,22 +3796,19 @@ out: static int gf_cli3_1_status_cbk (struct rpc_req *req, struct iovec *iov, - int count, void *myframe) + int count, void *myframe) { - gf_cli_rsp rsp = {0,}; - int ret = -1; - dict_t *dict = NULL; - char *hostname = NULL; - char *path = NULL; - int i = 0; - int port = 0; - int online = 0; - char key[1024] = {0,}; - int pid = -1; - char *pid_str = NULL; - char brick[8192] = {0,}; - char *volname = NULL; - + int ret = -1; + int i = 0; + int pid = -1; + uint32_t cmd = 0; + char key[1024] = {0,}; + char *hostname = NULL; + char *path = NULL; + char *volname = NULL; + dict_t *dict = NULL; + gf_cli_rsp rsp = {0,}; + cli_volume_status_t status = {0}; if (req->rpc_status == -1) goto out; @@ -3839,16 +3836,39 @@ gf_cli3_1_status_cbk (struct rpc_req *req, struct iovec *iov, if (ret) goto out; + ret = dict_get_uint32 (dict, "cmd", &cmd); + if (ret) + goto out; + + if ((cmd & GF_CLI_STATUS_ALL)) { + ((call_frame_t *)myframe)->local = dict; + ret = 0; + goto out; + } ret = dict_get_int32 (dict, "count", &count); if (ret) goto out; + if (count == 0) { + ret = -1; + goto out; + } + + status.brick = GF_CALLOC (1, PATH_MAX + 256, gf_common_mt_strdup); ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + + cli_out ("\nSTATUS OF VOLUME: %s", volname); + + if ((cmd & GF_CLI_STATUS_DETAIL) == 0) + cli_out ("BRICK\t\t\t\t\t\t\tPORT\tONLINE\tPID"); - cli_out ("Brick status for volume: %s", volname); - cli_out ("Brick\t\t\t\t\t\t\tPort\tOnline\tPID"); for (i = 0; i < count; i++) { + + cli_print_line (CLI_BRICK_STATUS_LINE_LEN); + memset (key, 0, sizeof (key)); snprintf (key, sizeof (key), "brick%d.hostname", i); ret = dict_get_str (dict, key, &hostname); @@ -3861,15 +3881,19 @@ gf_cli3_1_status_cbk (struct rpc_req *req, struct iovec *iov, if (ret) goto out; + memset (status.brick, 0, PATH_MAX + 255); + snprintf (status.brick, PATH_MAX + 255, "%s:%s", + hostname, path); + memset (key, 0, sizeof (key)); snprintf (key, sizeof (key), "brick%d.port", i); - ret = dict_get_int32 (dict, key, &port); + ret = dict_get_int32 (dict, key, &(status.port)); if (ret) goto out; memset (key, 0, sizeof (key)); snprintf (key, sizeof (key), "brick%d.status", i); - ret = dict_get_int32 (dict, key, &online); + ret = dict_get_int32 (dict, key, &(status.online)); if (ret) goto out; @@ -3879,40 +3903,44 @@ gf_cli3_1_status_cbk (struct rpc_req *req, struct iovec *iov, if (ret) goto out; if (pid == -1) - ret = gf_asprintf (&pid_str, "%s", "N/A"); + ret = gf_asprintf (&(status.pid_str), "%s", "N/A"); else - ret = gf_asprintf (&pid_str, "%d", pid); + ret = gf_asprintf (&(status.pid_str), "%d", pid); if (ret == -1) goto out; - snprintf (brick, sizeof (brick) -1, "%s:%s", hostname, path); + if ((cmd & GF_CLI_STATUS_DETAIL)) { + ret = cli_get_detail_status (dict, i, &status); + if (ret) + goto out; + cli_print_detailed_status (&status); - cli_print_line (CLI_BRICK_STATUS_LINE_LEN); - cli_print_brick_status (brick, port, online, pid_str); - if (pid_str) - GF_FREE (pid_str); + } else { + cli_print_brick_status (&status); + } } ret = rsp.op_ret; out: + if (status.brick) + GF_FREE (status.brick); + cli_cmd_broadcast_response (ret); return ret; } int32_t gf_cli3_1_status_volume (call_frame_t *frame, xlator_t *this, - void *data) + void *data) { gf_cli_req req = {{0,}}; - int ret = 0; - dict_t *dict = NULL; + int ret = -1; + dict_t *dict = NULL; - if (!frame || !this || !data) { - ret = -1; + if (!frame || !this || !data) goto out; - } dict = data; @@ -3920,7 +3948,7 @@ gf_cli3_1_status_volume (call_frame_t *frame, xlator_t *this, &req.dict.dict_val, (size_t *)&req.dict.dict_len); if (ret < 0) { - gf_log (this->name, GF_LOG_ERROR, + gf_log ("cli", GF_LOG_ERROR, "failed to serialize the data"); goto out; @@ -3935,6 +3963,80 @@ gf_cli3_1_status_volume (call_frame_t *frame, xlator_t *this, return ret; } +int +gf_cli_status_volume_all (call_frame_t *frame, xlator_t *this, void *data) +{ + int i = 0; + int ret = -1; + int vol_count = -1; + uint32_t cmd = 0; + char key[1024] = {0}; + char *volname = NULL; + dict_t *vol_dict = NULL; + dict_t *dict = NULL; + + dict = (dict_t *)data; + ret = dict_get_uint32 (dict, "cmd", &cmd); + if (ret) + goto out; + + ret = gf_cli3_1_status_volume (frame, this, data); + if (ret) + goto out; + + vol_dict = (dict_t *)(frame->local); + + ret = dict_get_int32 (vol_dict, "vol_count", &vol_count); + if (ret) { + cli_out ("Failed to get names of volumes"); + goto out; + } + + if (vol_count == 0) { + cli_out ("No volumes present"); + ret = 0; + goto out; + } + + /* remove the "all" flag in cmd */ + cmd &= ~GF_CLI_STATUS_ALL; + cmd |= GF_CLI_STATUS_VOL; + + for (i = 0; i < vol_count; i++) { + + dict = dict_new (); + if (!dict) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "vol%d", i); + ret = dict_get_str (vol_dict, key, &volname); + if (ret) + goto out; + + ret = dict_set_dynstr (dict, "volname", volname); + if (ret) + goto out; + + ret = dict_set_uint32 (dict, "cmd", cmd); + if (ret) + goto out; + + ret = gf_cli3_1_status_volume (frame, this, dict); + if (ret) + goto out; + + dict_unref (dict); + } + + out: + if (ret) + gf_log ("cli", GF_LOG_ERROR, "status all failed"); + if (ret && dict) + dict_unref (dict); + return ret; +} + static int gf_cli3_1_mount_cbk (struct rpc_req *req, struct iovec *iov, int count, void *myframe) @@ -4265,6 +4367,7 @@ struct rpc_clnt_procedure gluster_cli_actors[GLUSTER_CLI_MAXVALUE] = { [GLUSTER_CLI_TOP_VOLUME] = {"TOP_VOLUME", gf_cli3_1_top_volume}, [GLUSTER_CLI_GETWD] = {"GETWD", gf_cli3_1_getwd}, [GLUSTER_CLI_STATUS_VOLUME] = {"STATUS_VOLUME", gf_cli3_1_status_volume}, + [GLUSTER_CLI_STATUS_ALL] = {"STATUS_ALL", gf_cli_status_volume_all}, [GLUSTER_CLI_MOUNT] = {"MOUNT", gf_cli3_1_mount}, [GLUSTER_CLI_UMOUNT] = {"UMOUNT", gf_cli3_1_umount}, [GLUSTER_CLI_HEAL_VOLUME] = {"HEAL_VOLUME", gf_cli3_1_heal_volume}, diff --git a/cli/src/cli.h b/cli/src/cli.h index 1d2e06973..e091e7004 100644 --- a/cli/src/cli.h +++ b/cli/src/cli.h @@ -37,7 +37,7 @@ #define DEFAULT_CLI_LOG_FILE_DIRECTORY DATADIR "/log/glusterfs" #define CLI_VOL_STATUS_BRICK_LEN 55 #define CLI_TAB_LENGTH 8 -#define CLI_BRICK_STATUS_LINE_LEN 75 +#define CLI_BRICK_STATUS_LINE_LEN 78 enum argp_option_keys { ARGP_DEBUG_KEY = 133, @@ -124,6 +124,24 @@ struct cli_local { dict_t *dict; }; +struct cli_volume_status { + int port; + int online; + uint64_t block_size; + uint64_t total_inodes; + uint64_t free_inodes; + char *brick; + char *pid_str; + char *fs_name; + char *free; + char *total; + char *mount_options; + char *device; + char *inode_size; +}; + +typedef struct cli_volume_status cli_volume_status_t; + typedef struct cli_local cli_local_t; typedef ssize_t (*cli_serialize_t) (struct iovec outmsg, void *args); @@ -236,7 +254,13 @@ cli_cmd_volume_status_parse (const char **words, int wordcount, dict_t **options); int -cli_print_brick_status (char *brick, int port, int online, char *pid); +cli_print_brick_status (cli_volume_status_t *status); + +void +cli_print_detailed_status (cli_volume_status_t *status); + +int +cli_get_detail_status (dict_t *dict, int i, cli_volume_status_t *status); void cli_print_line (int len); -- cgit