From 944e5529078cff3fd0ecbc30f037eddcc9bb63ae Mon Sep 17 00:00:00 2001 From: Rajesh Joseph Date: Wed, 30 Oct 2013 10:50:45 +0530 Subject: snapshot: Snapshot restore GL-31: Ability to restore snapshot Implemented snapshot restore for thin logical volume. As of now snapshot restore for CG is not tested. Testing for snapshot restore of a volume is done by changing the snapshot create process to create a thick snapshot. This is done because --merge option to restore thin volume is not working in the latest kernel. Change-Id: Ia3ded7e6c4da5957a74e269a25ba3200e6fb2d8b Signed-off-by: Rajesh Joseph --- cli/src/cli-cmd-parser.c | 159 ++++++++++++++++++++++++++++++++++++++++----- cli/src/cli-cmd-snapshot.c | 8 ++- cli/src/cli-rpc-ops.c | 32 +++++++++ 3 files changed, 181 insertions(+), 18 deletions(-) (limited to 'cli/src') diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c index 352a2cc9b..44c497977 100644 --- a/cli/src/cli-cmd-parser.c +++ b/cli/src/cli-cmd-parser.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2010-2012 Red Hat, Inc. + Copyright (c) 2010-2013 Red Hat, Inc. This file is part of GlusterFS. This file is licensed to you under your choice of the GNU Lesser @@ -2797,7 +2797,7 @@ out: int32_t cli_snap_create_parse (dict_t *dict, const char **words, int wordcount, - int32_t cmdi) + unsigned int cmdi) { int32_t volcount = -1; int32_t no_of_wrds_in_desc = -1; @@ -3239,16 +3239,116 @@ out: } +/* Syntax: + * snapshot restore (-v | -c ) + */ +int +cli_snap_restore_parse (dict_t *dict, const char **words, int wordcount, + unsigned int cmdi) +{ + int ret = -1; /* Failure */ + const char* vol_name = NULL; + const char* snap_name = NULL; + const char* cg_name = NULL; + + GF_ASSERT (dict); + GF_ASSERT (words); + + /* At least CG_INDEX argument should be there for a valid command */ + if (wordcount <= cmdi) { + gf_log ("cli", GF_LOG_ERROR, "Invalid command: Not enough " + "arguments"); + goto out; + } + if (0 == strcmp (words[cmdi], "-v")) { + /* snapshot restore -v + * + * cmdi points to -v, therefore wordcount should be exactly + * equal to (cmdi + 2) + 1. +1 is added to convert index to + * count + */ + if ((cmdi + 3) != wordcount) { + gf_log ("cli", GF_LOG_ERROR, "Invalid argument count"); + goto out; + } + + vol_name = words[++cmdi]; + snap_name = words[++cmdi]; + + if ((NULL == vol_name) || (NULL == snap_name)) { + gf_log ("cli", GF_LOG_ERROR, "Volume or snap " + "name missing"); + goto out; + } + + /* Single volume should be represented by volcount 1 + * and a volname in dictionary + */ + ret = dict_set_int64 (dict, "volcount", 1); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to set " + "vol count"); + goto out; + } + + /* TODO: Change the index to 0 once Jarvis code is fixed */ + ret = dict_set_str (dict, "volname1", (char *)vol_name); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to set " + "volume name"); + goto out; + } + + ret = dict_set_str (dict, "snapname", (char *)snap_name); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to set " + "snap name"); + goto out; + } + } else if (0 == strcmp (words[cmdi], "-c")) { + /* If -c option is provided then command should look like + * snapshot restore -c + * + * cmdi points to -c, therefore wordcount should be exactly + * equal to (cmdi + 1) + 1. +1 is added to convert index to + * count + */ + if ((cmdi + 2) != wordcount) { + gf_log ("cli", GF_LOG_ERROR, "Invalid argument count"); + goto out; + } + cg_name = words[++cmdi]; + + ret = dict_set_str (dict, "cgname", (char *)cg_name); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to set " + "CG name"); + goto out; + } + } else { + gf_log ("cli", GF_LOG_ERROR, "Invalid (%s) option", + words[cmdi]); + goto out; + } + + ret = 0; /* Success */ +out: + return ret; +} + + int32_t cli_cmd_snapshot_parse (const char **words, int wordcount, dict_t **options) { int32_t ret = -1; dict_t *dict = NULL; gf1_cli_snapshot type = GF_SNAP_OPTION_TYPE_NONE; - int32_t cmdi = 0; - char *opwords[] = {"create", "list", "config", NULL}; + unsigned int cmdi = 0; char *w = NULL; int i = 0; + char *opwords[] = {"create", "delete", "restore", + "start", "stop", "list", "status", + "config", NULL}; GF_ASSERT (words); GF_ASSERT (options); @@ -3257,7 +3357,6 @@ cli_cmd_snapshot_parse (const char **words, int wordcount, dict_t **options) if (!dict) goto out; - /* Lowest wordcount possible */ if (wordcount < 2) { gf_log ("", GF_LOG_ERROR, @@ -3274,29 +3373,54 @@ 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 ] - */ + /*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 */ + /* 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 = cli_snap_create_parse (dict, words, - wordcount, cmdi); + ret = cli_snap_create_parse (dict, words, wordcount, cmdi); if (ret) { gf_log ("", GF_LOG_ERROR, "create command parsing failed."); goto out; } + } else if (strcmp (w, "delete") == 0) { + gf_log ("", GF_LOG_ERROR, "Operation Not supported"); + goto out; + } else if (strcmp (w, "restore") == 0) { + /* Syntax: + * snapshot restore (-v | -c ) + */ + type = GF_SNAP_OPTION_TYPE_RESTORE; + + /* Start parsing from the first option after "restore" */ + cmdi = 2; + + ret = cli_snap_restore_parse (dict, words, wordcount, cmdi); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to parse " + "restore command"); + goto out; + } + } else if (strcmp (w, "start") == 0) { + gf_log ("", GF_LOG_ERROR, "Operation Not supported"); + goto out; + } else if (strcmp (w, "stop") == 0) { + gf_log ("", GF_LOG_ERROR, "Operation Not supported"); + goto out; } else if (strcmp (w, "list") == 0) { - /* snapshot list [ | [-s ] - * | -c ] [-d] */ + /* snapshot list [ | [-s ] + * | -c ] [-d] */ /* check if arguments contains any Keyword */ cmdi = 2; for (i = cmdi ; i < wordcount ; i++) { @@ -3319,7 +3443,10 @@ cli_cmd_snapshot_parse (const char **words, int wordcount, dict_t **options) "list command parsing failed."); goto out; } - } else if (strcmp (w, "config") == 0){ + } else if (strcmp (w, "status") == 0) { + gf_log ("", GF_LOG_ERROR, "Operation Not supported"); + goto out; + } else if (strcmp (w, "config") == 0) { /* snapshot config [snap_max_limit ] */ type = GF_SNAP_OPTION_TYPE_CONFIG; diff --git a/cli/src/cli-cmd-snapshot.c b/cli/src/cli-cmd-snapshot.c index 6c2b3d5e5..9f52ab01b 100644 --- a/cli/src/cli-cmd-snapshot.c +++ b/cli/src/cli-cmd-snapshot.c @@ -77,11 +77,15 @@ struct cli_cmd snapshot_cmds[] = { cli_cmd_snapshot_help_cbk, "display help for snapshot commands" }, - {"snapshot create [-n ] [-d ]", + { "snapshot create [-n ] [-d ]", cli_cmd_snapshot_cbk, "Snapshot Create." }, - {"snapshot list [ | [-s ]" + { "snapshot restore (-v | -c )", + cli_cmd_snapshot_cbk, + "Snapshot Restore." + }, + { "snapshot list [ | [-s ]" " | -c ] [-d]", cli_cmd_snapshot_cbk, "Snapshot List." diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c index fdac00384..870588e9a 100644 --- a/cli/src/cli-rpc-ops.c +++ b/cli/src/cli-rpc-ops.c @@ -7889,6 +7889,38 @@ gf_cli_snapshot_cbk (struct rpc_req *req, struct iovec *iov, snap_name); } 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 + * get rsp.*/ + if (rsp.op_ret) { + cli_err("snapshot restore: 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, "cg-name", &cg_name); + if (ret) { + ret = dict_get_str (dict, "snap-name", &snap_name); + if (ret) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to get CG name or snap name"); + goto out; + } + } + + if (NULL != snap_name) { + cli_out ("Snapshot restore: %s: Snap restored " + "successfully", snap_name); + } else { + cli_out ("Snapshot restore: %s: Consistency group " + "restored successfully", cg_name); + } + + ret = 0; + break; case GF_SNAP_OPTION_TYPE_LIST: if (rsp.op_ret) { -- cgit