summaryrefslogtreecommitdiffstats
path: root/cli
diff options
context:
space:
mode:
authorMohammed Rafi KC <rkavunga@redhat.com>2015-02-23 17:28:47 +0530
committerVijay Bellur <vbellur@redhat.com>2015-03-18 00:07:55 -0700
commit260a6943849f99227248a8fc852a8c8fc3d1e289 (patch)
treecf8d81b9e89a855975434638ac89abac7cde4696 /cli
parentc99c72b35fac16e08c4d170b6a46a786caaeef58 (diff)
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 <clonename> <snapname> Change-Id: Icadb993fa42fff787a330f8f49452da54e9db7de BUG: 1199894 Signed-off-by: Mohammed Rafi KC <rkavunga@redhat.com> Reviewed-on: http://review.gluster.org/9750 Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Rajesh Joseph <rjoseph@redhat.com> Reviewed-by: Vijay Bellur <vbellur@redhat.com>
Diffstat (limited to 'cli')
-rw-r--r--cli/src/cli-cmd-parser.c131
-rw-r--r--cli/src/cli-cmd-snapshot.c4
-rw-r--r--cli/src/cli-rpc-ops.c30
3 files changed, 159 insertions, 6 deletions
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 <clonename> <snapname>
+ * @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 <snapname> <vol-name(s)> [description <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 <clonename> <snapname>
+ */
+ /* 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 <volname>)]
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 <clonename> <snapname>",
+ cli_cmd_snapshot_cbk,
+ "Snapshot Clone."
+ },
{ "snapshot restore <snapname>",
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