diff options
| author | Mohammed Rafi KC <rkavunga@redhat.com> | 2015-02-23 17:28:47 +0530 | 
|---|---|---|
| committer | Vijay Bellur <vbellur@redhat.com> | 2015-03-18 00:07:55 -0700 | 
| commit | 260a6943849f99227248a8fc852a8c8fc3d1e289 (patch) | |
| tree | cf8d81b9e89a855975434638ac89abac7cde4696 /cli | |
| parent | c99c72b35fac16e08c4d170b6a46a786caaeef58 (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.c | 131 | ||||
| -rw-r--r-- | cli/src/cli-cmd-snapshot.c | 4 | ||||
| -rw-r--r-- | cli/src/cli-rpc-ops.c | 30 | 
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  | 
