From da3a265c36b1326405dafce98b29d7c72001a7e9 Mon Sep 17 00:00:00 2001 From: Sachin Pandit Date: Tue, 15 Oct 2013 15:41:56 +0530 Subject: CLI : snapshot list cli interface $gluster snapshot list *prints snaps of all volume* $gluster snapshot list -d *prints snaps of all volume with details* $gluster snapshot list vol1 *prints snaps of volume "vol1"* $gluster snapshot list vol1 -d *prints snaps of volume "vol1" with details* $gluster snapshot list vol1 vol2 *prints snaps of volume "vol1" & "vol2" $gluster snapshot list vol1 vol2 -d *prints snaps of volume "vol1" & "vol2" with details* $gluster snapshot list -c cgname *prints snaps of all volume present in the group "cgname"* $gluster snapshot list -c cgname -d *prints snaps of all volume present in the group "cgname" with details* ** As of now you wont be able to see any output as actual snap create is not integrated ** Change-Id: I60eeafc715a51f1c564a270bb4124368038012b1 Signed-off-by: Sachin Pandit --- cli/src/cli-cmd-parser.c | 193 ++++++++++++++++++++++-- cli/src/cli-cmd-snapshot.c | 10 +- cli/src/cli-rpc-ops.c | 369 ++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 518 insertions(+), 54 deletions(-) diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c index 87d29972b..b05fad315 100644 --- a/cli/src/cli-cmd-parser.c +++ b/cli/src/cli-cmd-parser.c @@ -2972,6 +2972,142 @@ out: return ret; } +/* snapshot list [ | -s | -c ] [-d] + * cmdi is command index which contains number of standard arguments in + * command, here cmdi is 2 i.e "gluster snapshot list" + */ +int +cli_snap_list_parse (dict_t *dict, const char **words, int wordcount, int cmdi) +{ + int ret = -1; + int i = 0; + int64_t vol_count = 0; + int vol_start_index = -1; + int8_t snap_details = 0; + char *snap_name = NULL; + char *cg_name = NULL; + char *vol_name = NULL; + char key[256] = ""; + + GF_ASSERT (dict); + GF_ASSERT (words); + GF_ASSERT (wordcount >= cmdi); + /* if command is "gluster snapshot list*/ + if (wordcount == cmdi) { + ret = 0; + goto out; + } + + for (i = cmdi; i < wordcount; ++i) { + if (strcmp (words[i], "-d") == 0) { + if (snap_details == 1) { + /* If option is already set */ + gf_log("", GF_LOG_ERROR, + "snap_details already set"); + goto out; + } + snap_details = 1; + } else if (strcmp (words[i], "-s") == 0) { + if ((wordcount - 1) == i || (snap_name != NULL) + || vol_count != 1 || strcmp (words[++i], "-d") == 0 + || strcmp (words[i], "-c") == 0) { + /* if -s is not followed by a valid snap_name + * or if snap_name is already parsed + * or number of volname specified + * is not equal to 1 + */ + gf_log("", GF_LOG_ERROR, "Invalid snap_name" + " or snap_name already parsed" + " or volname specified is not equal 1"); + goto out; + } + snap_name = words[i]; // word followed by -s is snapname + } else if (strcmp (words[i], "-c") == 0) { + if ((wordcount - 1) == i || (cg_name != NULL) + || strcmp (words[++i], "-d") == 0 + || strcmp (words[i], "-s") == 0) { + /* if -c is not followed by a valid cg_name + * or if cg_name is already parsed + */ + gf_log("", GF_LOG_ERROR, "Invalid cg_name" + " or cg_name already parsed"); + goto out; + } + cg_name = words[i]; + } else { + if (vol_count != 0) { + /* if vol names already set */ + gf_log("", GF_LOG_ERROR, + "Vol Names already set"); + goto out; + } + + vol_start_index = i; + vol_count = 1; + + while (++i < wordcount) { + if ((strcmp (words[i], "-d") == 0) || + (strcmp (words[i], "-s") == 0) || + (strcmp (words[i], "-c") == 0)) { + /*if option -d, -s or -c is given after volname + *then go back in index to parse this option + *again + */ + --i; + break; + } + ++vol_count; + } + } + } + + /* if CG name is present in the command then fill it to dictionary */ + if (cg_name != NULL) { + if (snap_name != NULL || vol_count != 0) { + /* When -s option or volume name is given along + * with -c option. Details of single snap belonging + * to a CG is not supported. + */ + gf_log("", GF_LOG_ERROR, "details of single snap" + " belonging to a CG is not supported"); + goto out; + } + ret = dict_set_str(dict, "cg_name", cg_name); + if (ret) { + gf_log("", GF_LOG_ERROR, "Failed to set cg_name"); + goto out; + } + } else { + /* if snap name is present in the command + * then fill it to dictionary + */ + if (snap_name != NULL) { + ret = dict_set_str (dict, "snap_name", snap_name); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Failed to set snap_name"); + goto out; + } + } + + ret = dict_set_int64 (dict, "vol_count", vol_count); + /* fill volume name in dictionary */ + for (i = 0; i < vol_count; ++i) { + vol_name = words[vol_start_index + i]; + snprintf (key, sizeof (key), "vol%d", i); + ret = dict_set_str (dict, key, vol_name); + if (ret) { + gf_log("", GF_LOG_ERROR, + "Failed to set vol_name"); + goto out; + } + } + } +out: + return ret; +} + + int32_t cli_cmd_snapshot_parse (const char **words, int wordcount, dict_t **options) { @@ -2979,8 +3115,9 @@ cli_cmd_snapshot_parse (const char **words, int wordcount, dict_t **options) dict_t *dict = NULL; gf1_cli_snapshot type = GF_SNAP_OPTION_TYPE_NONE; int32_t cmdi = 0; - char *opwords[] = {"create", NULL}; + char *opwords[] = {"create", "list", NULL}; char *w = NULL; + int i = 0; GF_ASSERT (words); GF_ASSERT (options); @@ -2989,23 +3126,14 @@ cli_cmd_snapshot_parse (const char **words, int wordcount, dict_t **options) if (!dict) goto out; - /* syntax: - * snapshot create [-n ] [-d ] - */ /* Lowest wordcount possible */ if (wordcount < 2) { - gf_log ("", GF_LOG_ERROR, "Invalid command: Not enough arguments"); + gf_log ("", GF_LOG_ERROR, + "Invalid command: Not enough arguments"); goto out; } - /* In cases where the vol-name is not given - * parsing fails. volname cannot be an opword. - * and that is what this check verifies */ - w = str_getunamb (words[2], opwords); - if (w) - goto out; - w = str_getunamb (words[1], opwords); if (!w) { /* Checks if the operation is a valid operation */ @@ -3015,6 +3143,16 @@ cli_cmd_snapshot_parse (const char **words, int wordcount, dict_t **options) /* Check which op is intended */ if (strcmp (w, "create") == 0) { + /*syntax: + *snapshot create [-n ] [-d ] + */ + + /* In cases where the vol-name is not given + * parsing fails. volname cannot be an opword. + * and that is what this check verifies */ + w = str_getunamb (words[2], opwords); + if (w) + goto out; type = GF_SNAP_OPTION_TYPE_CREATE; cmdi = 1; ret = dict_set_int32 (dict, "type", type); @@ -3031,6 +3169,37 @@ cli_cmd_snapshot_parse (const char **words, int wordcount, dict_t **options) "create command parsing failed."); goto out; } + } else if (strcmp (w, "list") == 0) { + /* snapshot list [ | [-s ] + * | -c ] [-d] */ + /* check if arguments contains any Keyword */ + cmdi = 2; + for (i = cmdi ; i < wordcount ; i++) { + w = str_getunamb (words[i], opwords); + if (w) { + /*Checks if the operation is a valid operation*/ + cli_out ("Usage of Keyword in wrong place"); + gf_log ("", GF_LOG_ERROR, "Opword Mismatch"); + goto out; + } + } + type = GF_SNAP_OPTION_TYPE_LIST; + ret = dict_set_int32 (dict, "type" , type); + + if (ret) { + gf_log ("" , GF_LOG_ERROR, + "Failed to set type."); + goto out; + } + + ret = cli_snap_list_parse (dict, words, + wordcount, cmdi); + + if (ret) { + gf_log ("", GF_LOG_ERROR, + "list command parsing failed."); + goto out; + } } else { gf_log ("", GF_LOG_ERROR, "Opword Mismatch"); goto out; diff --git a/cli/src/cli-cmd-snapshot.c b/cli/src/cli-cmd-snapshot.c index cc1fb3c90..afe8bf901 100644 --- a/cli/src/cli-cmd-snapshot.c +++ b/cli/src/cli-cmd-snapshot.c @@ -75,13 +75,17 @@ out: struct cli_cmd snapshot_cmds[] = { { "snapshot help", cli_cmd_snapshot_help_cbk, - "display help for snapshot commands"}, - + "display help for snapshot commands" + }, {"snapshot create [-n ] [-d ]", cli_cmd_snapshot_cbk, "Snapshot Create." }, - + {"snapshot list [ | [-s ]" + " | -c ] [-d]", + cli_cmd_snapshot_cbk, + "Snapshot List." + }, { NULL, NULL, NULL } }; diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c index b100f2d62..50eeda3d2 100644 --- a/cli/src/cli-rpc-ops.c +++ b/cli/src/cli-rpc-ops.c @@ -7518,18 +7518,282 @@ out: return ret; } + +/*Function to list the snap "gluster snapshot list" */ +static int +list_snap_of_volume (dict_t *dict_n, char *prefix_str) { + int64_t snapcount = -1 ; + char buffer[PATH_MAX] = "" ; + char *get_buffer = NULL; + int8_t detail = 0 ; + int64_t i = 0 ; + int ret = -1 ; + + GF_ASSERT (dict_n); + GF_ASSERT (prefix_str); + + if (!dict_n) { + ret = -1; + goto out; + } + + /* Check if volname is present. + * if volume not present then display that volume doesnot exist + * and try to fetch next volume mentioned + */ + ret = snprintf (buffer, sizeof(buffer), "%s.vol_name", prefix_str); + if (ret < 0) { /* Negative value is an error */ + goto out; + } + ret = dict_get_str (dict_n, buffer, &get_buffer); + if (get_buffer == NULL){ + cli_out ("Volume doesnot exist"); + goto out; + } + cli_out ("Vol Name : %s", get_buffer); + /* if Volume is present then get the snapcount. + * string is "snaplist.vol{0..}.snap_count. + */ + ret = snprintf (buffer, sizeof(buffer), + "%s.snap_count", prefix_str); + if (ret < 0) { /* Negative value is an error */ + goto out; + } + ret = dict_get_int64 (dict_n, buffer, &snapcount); + if (ret) { + gf_log("", GF_LOG_ERROR, "Could not fetch snapcount"); + goto out; + } + + /* To check if the user has given "-d" option */ + ret = dict_get_int8 (dict_n, "snap_details", &detail); + if (ret) { + gf_log ("",GF_LOG_ERROR, "could not get snap_details status"); + goto out; + } + + cli_out ("Number of Snaps Taken : %ld", snapcount); + for (i = 0 ; i < snapcount; i++) { + /* get snapname "snaplist.vol{0..}.snap{0..}.snap_name" */ + ret = snprintf (buffer, sizeof(buffer), + "%s.snap%ld.snap_name", prefix_str,i); + if (ret < 0) { /* Negative value is an error */ + goto out; + } + ret = dict_get_str (dict_n, buffer, &get_buffer); + if (!ret) + cli_out ("\tSnap Name : %s",get_buffer); + else + cli_out ("\tSnap Name : %s","Does not exist"); + + ret = snprintf (buffer, sizeof(buffer), + "%s.snap%ld.snap_time", prefix_str, i); + if (ret < 0) { /* Negative value is an error */ + goto out; + } + ret = dict_get_str (dict_n, buffer, &get_buffer); + if (!ret) + cli_out ("\tSnap Time : %s",get_buffer); + else + cli_out ("\tSnap Time : %s","Does not exist"); + + + ret = snprintf (buffer, sizeof(buffer), "%s.snap%ld.snap_id" + , prefix_str, i); + if (ret < 0) { /* Negative value is an error */ + goto out; + } + ret = dict_get_str (dict_n, buffer, &get_buffer); + if (!ret) + cli_out("\tSnap ID : %s",get_buffer); + else + cli_out("\tSnap ID : %s","Does not exist"); + + if(detail == 0) { + /* if snap_details is set to zero + * then we can skip the additional information part + */ + continue; + } + ret = snprintf (buffer, sizeof(buffer), + "%s.snap%ld.cg_name", prefix_str, i); + if (ret < 0) { /* Negative value is an error */ + goto out; + } + ret = dict_get_str (dict_n, buffer, &get_buffer); + if (!ret) + cli_out("\tCG Name : %s",get_buffer); + else + cli_out("\tCG Name : %s","Does not exist"); + + ret = snprintf (buffer, sizeof(buffer), + "%s.snap%ld.cg_id", prefix_str, i); + if (ret < 0) { /* Negative value is an error */ + goto out; + } + ret = dict_get_str (dict_n, buffer, &get_buffer); + if (!ret) + cli_out("\tCG ID : %s",get_buffer); + else + cli_out("\tCG ID : %s","Does not exist"); + + ret = snprintf (buffer, sizeof(buffer), + "%s.snap%ld.snap_desc", prefix_str, i); + if (ret < 0) { /* Negative value is an error */ + goto out; + } + ret = dict_get_str (dict_n, buffer, &get_buffer); + if (!ret) + cli_out ("\tSnap Description : %s",get_buffer); + else + cli_out ("\tSnap Description : %s", + "Description not present"); + + ret = snprintf (buffer, sizeof(buffer), + "%s.snap%ld.snap_status", prefix_str, i); + if (ret < 0) { /* Negative value is an error */ + goto out; + } + ret = dict_get_str (dict_n, buffer, &get_buffer); + if (!ret) + cli_out ("\tSnap Status : %s",get_buffer); + else + cli_out ("\tSnap Status : %s","Does not exist"); + ret = 0; + } + +out : + return ret; +} + +/* Function to list snap present in CG */ +static int +list_snap_of_cg (dict_t *dict) { + int ret = -1 ; + int8_t detail = 0 ; + char *get_buffer = NULL; + char cg_name_list[PATH_MAX] = "" ; + int64_t cg_volcount = -1 ; + int64_t i = -1 ; + + GF_ASSERT(dict); + + /* As listing snaps of single CG is supported as of now + * the string "snaplist.cg0" is directly included + * or else we can keep that string in some variable + * and use the same variable every where + */ + ret = dict_get_int8 (dict, "snap_details", &detail); + if (ret) { + gf_log ("", GF_LOG_ERROR, "could not get snap_details status"); + goto out; + } + + ret = dict_get_str (dict, "snaplist.cg0.cg_name", &get_buffer); + if (ret) { + /* if cg_name is not present then exit, it is not necessary + * to check other details if cg_name is not present + */ + cli_out ("CG Name : %s","Does not exist"); + gf_log ("", GF_LOG_ERROR, "Could not get cg_name"); + goto out; + } + cli_out ("CG Name : %s", get_buffer); + + ret = dict_get_str (dict, "snaplist.cg0.cg_id", &get_buffer); + if (!ret) + cli_out ("CG ID : %s",get_buffer); + else + cli_out ("CG ID : %s","Does not exist"); + + if (detail == 1) { + ret = dict_get_str (dict, "snaplist.cg0.cg_desc", &get_buffer); + if (!ret) + cli_out ("CG Description : %s", + get_buffer); + else + cli_out ("CG Description : %s", + "Does not exist"); + + ret = dict_get_str (dict, "snaplist.cg0.cg_status", + &get_buffer); + if (!ret) + cli_out ("CG Status : %s", get_buffer); + else + cli_out ("CG Status : %s", + "Does not exist"); + + } + + ret = dict_get_int64 (dict, "snaplist.cg0.vol_count", &cg_volcount); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Could not fetch cg_volcount"); + goto out; + } + /* list the snaps of each volume present in a CG*/ + for (i = 0 ; i < cg_volcount ; i++){ + ret = snprintf (cg_name_list, sizeof(cg_name_list), + "snaplist.cg0.vol%ld",i); + if (ret < 0) { /* Negative value is an error */ + goto out; + } + ret = list_snap_of_volume (dict, cg_name_list); + if (ret) { + gf_log("", GF_LOG_ERROR, "Failed to list the" + " information of snaps of volume present in CG"); + } + } +out : + return ret; +} + +/* This function calls list_snap_of_volume */ +static int +call_list_snap_of_volume(dict_t *dict){ + int ret = -1; + int64_t volcount = -1; + int i = -1; + char vol_name_prefix[PATH_MAX] = ""; + + ret = dict_get_int64 (dict, "snaplist.vol_count", &volcount); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Could not fetch volcount"); + goto out; + } + for (i = 0 ; i < volcount ; i++) { + /* list the snap of each volume + * vol_name_prefix = "snaplist.vol{0..}" + */ + ret = snprintf (vol_name_prefix, sizeof(vol_name_prefix), + "snaplist.vol%d", i); + if (ret < 0) { /* Negative value is an error */ + goto out; + } + ret = list_snap_of_volume (dict, vol_name_prefix); + if (ret) { + gf_log("", GF_LOG_ERROR, + "Failed to list information of snaps of volume"); + } + /* If we fail to print information of one volume + * then try to fetch information of next volume + */ + } +out : + return ret; +} + int gf_cli_snapshot_cbk (struct rpc_req *req, struct iovec *iov, int count, void *myframe) { - int ret = -1; - gf_cli_rsp rsp = {0, }; - dict_t *dict = NULL; - char *snap_name = NULL; - char *cg_name = NULL; - int32_t type = 0; - int32_t volcount = 0; - call_frame_t *frame = NULL; + int ret = -1; + gf_cli_rsp rsp = {0, }; + dict_t *dict = NULL; + char *snap_name = NULL; + char *cg_name = NULL; + int32_t type = 0; + int64_t volcount = -1; + call_frame_t *frame = NULL; if (req->rpc_status == -1) { ret = -1; @@ -7564,47 +7828,74 @@ gf_cli_snapshot_cbk (struct rpc_req *req, struct iovec *iov, } switch (type) { - case GF_SNAP_OPTION_TYPE_CREATE: - if (rsp.op_ret) { - cli_err("snapshot create: failed: %s", - rsp.op_errstr ? rsp.op_errstr : - "Please check log file for details"); - ret = rsp.op_ret; - goto out; - } + case GF_SNAP_OPTION_TYPE_CREATE: + if (rsp.op_ret) { + cli_err("snapshot create: failed: %s", + rsp.op_errstr ? rsp.op_errstr : + "Please check log file for details"); + ret = rsp.op_ret; + goto out; + } - ret = dict_get_int32 (dict, "volcount", &volcount); - if (ret) { - gf_log (frame->this->name, GF_LOG_ERROR, - "failed to get volcount"); - goto out; - } + ret = dict_get_int64 (dict, "volcount", &volcount); + if (ret) { + gf_log (frame->this->name, GF_LOG_ERROR, + "failed to get volcount"); + goto out; + } - if (volcount > 1) { - if (dict_get_str (dict, "cg-name", - &cg_name) != 0) - cg_name = "???"; + if (volcount > 1) { + if (dict_get_str (dict, "cg-name", + &cg_name) != 0) + cg_name = "???"; - cli_out ("snapshot create: %s: consistency " - "group created successfully", - cg_name); - } else { - if (dict_get_str (dict, "snap-name", - &snap_name) != 0) - snap_name = "???"; + cli_out ("snapshot create: %s: consistency " + "group created successfully", + cg_name); + } else { + if (dict_get_str (dict, "snap-name", + &snap_name) != 0) + snap_name = "???"; - cli_out ("snapshot create: %s: " - "snap created successfully", - snap_name); + cli_out ("snapshot create: %s: " + "snap created successfully", + snap_name); } break; - default: - cli_err ("Unknown command executed"); + case GF_SNAP_OPTION_TYPE_LIST: + if (rsp.op_ret) { + cli_err ("Snapshot list : failed: %s", + rsp.op_errstr ? rsp.op_errstr : + "Please check log file for details"); + ret = rsp.op_ret; + goto out; + } + + /* get the vol_count + * if vol_count = 0, then there must be presence of CG + */ + ret = dict_get_int64 (dict, "snaplist.vol_count", &volcount); + if (ret){ + gf_log("", GF_LOG_ERROR, "Could not fetch volcount"); ret = -1; goto out; - } + } + if (volcount >= 1) { + ret = call_list_snap_of_volume (dict); + } else { + /* get the volumes present in CG + * and list snap of each volume + */ + ret = list_snap_of_cg (dict); + } + break; + default: + cli_err ("Unknown command executed"); + ret = -1; + goto out; + } out: if (dict) dict_unref (dict); -- cgit