From 260a6943849f99227248a8fc852a8c8fc3d1e289 Mon Sep 17 00:00:00 2001 From: Mohammed Rafi KC Date: Mon, 23 Feb 2015 17:28:47 +0530 Subject: Snapshot/clone: clone of a snapshot that will act as a regular volume snapshot clone will allow us to take a snpahot of a snapshot. Newly created clone volume will be a regular volume with read/write permissions. CLI command snapshot clone Change-Id: Icadb993fa42fff787a330f8f49452da54e9db7de BUG: 1199894 Signed-off-by: Mohammed Rafi KC Reviewed-on: http://review.gluster.org/9750 Tested-by: Gluster Build System Reviewed-by: Rajesh Joseph Reviewed-by: Vijay Bellur --- cli/src/cli-cmd-parser.c | 131 ++++++++++++++++++++++++++++++++++++++++++--- cli/src/cli-cmd-snapshot.c | 4 ++ cli/src/cli-rpc-ops.c | 30 +++++++++++ 3 files changed, 159 insertions(+), 6 deletions(-) (limited to 'cli') diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c index b2ef1d77104..aa512738784 100644 --- a/cli/src/cli-cmd-parser.c +++ b/cli/src/cli-cmd-parser.c @@ -3358,6 +3358,83 @@ out: return ret; } +/* snapshot clone + * @arg-0, dict : Request Dictionary to be sent to server side. + * @arg-1, words : Contains individual words of CLI command. + * @arg-2, wordcount: Contains number of words present in the CLI command. + * + * return value : -1 on failure + * 0 on success + */ +int +cli_snap_clone_parse (dict_t *dict, const char **words, int wordcount) { + uint64_t i = 0; + int ret = -1; + char key[PATH_MAX] = ""; + char *clonename = NULL; + unsigned int cmdi = 2; + int flags = 0; + /* cmdi is command index, here cmdi is "2" (gluster snapshot clone)*/ + + GF_ASSERT (words); + GF_ASSERT (dict); + + if (wordcount == cmdi + 1) { + cli_err ("Invalid Syntax."); + gf_log ("cli", GF_LOG_ERROR, + "Invalid number of words for snap clone command"); + goto out; + } + + if (strlen(words[cmdi]) >= GLUSTERD_MAX_SNAP_NAME) { + cli_err ("snapshot clone: failed: clonename cannot exceed " + "255 characters."); + gf_log ("cli", GF_LOG_ERROR, "Clone name too long"); + + goto out; + } + + clonename = (char *) words[cmdi]; + for (i = 0 ; i < strlen (clonename); i++) { + /* Following volume name convention */ + if (!isalnum (clonename[i]) && (clonename[i] != '_' + && (clonename[i] != '-'))) { + /* TODO : Is this message enough?? */ + cli_err ("Clonename can contain only alphanumeric, " + "\"-\" and \"_\" characters"); + goto out; + } + } + + ret = dict_set_int32 (dict, "volcount", 1); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not save volcount"); + goto out; + } + + ret = dict_set_str (dict, "clonename", (char *)words[cmdi]); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not save clone " + "name(%s)", (char *)words[cmdi]); + goto out; + } + + /* Filling snap name in the dictionary */ + ret = dict_set_str (dict, "snapname", (char *)words[cmdi+1]); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Could not " + "save snap name(%s)", (char *)words[cmdi+1]); + goto out; + } + + + ret = 0; + +out: + return ret; +} + + /* snapshot create [description ] * [force] * @arg-0, dict : Request Dictionary to be sent to server side. @@ -4223,16 +4300,16 @@ out: } int -validate_snapname (const char *snapname, char **opwords) { +validate_op_name (const char *op, const char *opname, char **opwords) { int ret = -1; int i = 0; - GF_ASSERT (snapname); + GF_ASSERT (opname); GF_ASSERT (opwords); for (i = 0 ; opwords[i] != NULL; i++) { - if (strcmp (opwords[i], snapname) == 0) { - cli_out ("\"%s\" cannot be a snapname", snapname); + if (strcmp (opwords[i], opname) == 0) { + cli_out ("\"%s\" cannot be a %s", opname, op); goto out; } } @@ -4251,9 +4328,19 @@ cli_cmd_snapshot_parse (const char **words, int wordcount, dict_t **options, char *w = NULL; char *opwords[] = {"create", "delete", "restore", "activate", "deactivate", "list", - "status", "config", "info", NULL}; + "status", "config", "info", "clone", + NULL}; char *invalid_snapnames[] = {"description", "force", "volume", "all", NULL}; + char *invalid_volnames[] = {"volume", "type", + "subvolumes", "option", + "end-volume", "all", + "volume_not_in_ring", + "description", "force", + "snap-max-hard-limit", + "snap-max-soft-limit", + "auto-delete", + "activate-on-create", NULL}; GF_ASSERT (words); GF_ASSERT (options); @@ -4295,6 +4382,8 @@ cli_cmd_snapshot_parse (const char **words, int wordcount, dict_t **options, type = GF_SNAP_OPTION_TYPE_ACTIVATE; } else if (!strcmp (w, "deactivate")) { type = GF_SNAP_OPTION_TYPE_DEACTIVATE; + } else if (!strcmp(w, "clone")) { + type = GF_SNAP_OPTION_TYPE_CLONE; } if (type != GF_SNAP_OPTION_TYPE_CONFIG && @@ -4339,7 +4428,8 @@ cli_cmd_snapshot_parse (const char **words, int wordcount, dict_t **options, goto out; } - ret = validate_snapname (words[2], invalid_snapnames); + ret = validate_op_name ("snapname", words[2], + invalid_snapnames); if (ret) { goto out; } @@ -4352,6 +4442,35 @@ cli_cmd_snapshot_parse (const char **words, int wordcount, dict_t **options, } break; + case GF_SNAP_OPTION_TYPE_CLONE: + /* Syntax : + * gluster snapshot clone + */ + /* In cases where the clonename is not given then + * parsing fails & snapname cannot be "description", + * "force" and "volume", that check is made here + */ + if (wordcount == 2) { + ret = -1; + gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax"); + goto out; + } + + ret = validate_op_name ("clonename", words[2], + invalid_volnames); + if (ret) { + goto out; + } + + ret = cli_snap_clone_parse (dict, words, wordcount); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "clone command parsing failed."); + goto out; + } + break; + + case GF_SNAP_OPTION_TYPE_INFO: /* Syntax : * gluster snapshot info [(snapname] | [vol )] diff --git a/cli/src/cli-cmd-snapshot.c b/cli/src/cli-cmd-snapshot.c index 7c6a52e0a88..e885a641de2 100644 --- a/cli/src/cli-cmd-snapshot.c +++ b/cli/src/cli-cmd-snapshot.c @@ -87,6 +87,10 @@ struct cli_cmd snapshot_cmds[] = { cli_cmd_snapshot_cbk, "Snapshot Create." }, + { "snapshot clone ", + cli_cmd_snapshot_cbk, + "Snapshot Clone." + }, { "snapshot restore ", cli_cmd_snapshot_cbk, "Snapshot Restore." diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c index 8ea43f824bc..a02761d5e6e 100644 --- a/cli/src/cli-rpc-ops.c +++ b/cli/src/cli-rpc-ops.c @@ -8870,6 +8870,7 @@ gf_cli_snapshot_cbk (struct rpc_req *req, struct iovec *iov, gf_cli_rsp rsp = {0, }; dict_t *dict = NULL; char *snap_name = NULL; + char *clone_name = NULL; int32_t type = 0; call_frame_t *frame = NULL; gf_boolean_t snap_driven = _gf_false; @@ -8961,6 +8962,35 @@ gf_cli_snapshot_cbk (struct rpc_req *req, struct iovec *iov, ret = 0; break; + case GF_SNAP_OPTION_TYPE_CLONE: + if (rsp.op_ret) { + cli_err("snapshot clone: failed: %s", + rsp.op_errstr ? rsp.op_errstr : + "Please check log file for details"); + ret = rsp.op_ret; + goto out; + } + + ret = dict_get_str (dict, "clonename", &clone_name); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Failed to get clone name"); + goto out; + } + + ret = dict_get_str (dict, "snapname", &snap_name); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Failed to get snapname name"); + goto out; + } + + cli_out ("snapshot clone: success: Clone %s created " + "successfully", clone_name); + + ret = 0; + break; + case GF_SNAP_OPTION_TYPE_RESTORE: /* TODO: Check if rsp.op_ret needs to be checked here. Or is * it ok to check this in the start of the function where we -- cgit