summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSachin Pandit <spandit@redhat.com>2014-06-23 09:35:52 +0530
committerKaushal M <kaushal@redhat.com>2014-07-25 03:23:44 -0700
commit35c6ca05d8ee0e1be1b67ac64d32c21b195aaeea (patch)
treeb8ded335e06ec1dc12b13e25d37475a093d039b3
parentfb730072c27c9ae1b99ff41dbff45e721017d543 (diff)
feature/snapshot : Interface to delete all snapshots belonging
to a system as-well-as to a particular volume. Problem : With the current design we can only delete a single snapshot. And the deletion of volume which contains snapshot is not allowed. Because of that user might be forced to delete all the snapshots manually before he is allowed to delete a volume. Solution: Following is the interface with which user can delete all the snapshots of a system or belonging to a particular volume. Syntax : gluster snapshot delete all *To delete all the snapshots present in a system Syntax : gluster snapshot delete volume <volname> *To deletes all the snapshot present in a volume specified. ======================================================================== Sample Output: Case 1 : Deleting a single snapshot. [root@snapshot-24 glusterfs]# gluster snapshot delete snap1 Deleting snap will erase all the information about the snap. Do you still want to continue? (y/n) y snapshot delete: snap1: snap removed successfully ----------------------------------------------------------------- Case 2 : Deleting all the snapshots in a Volume. [root@snapshot-24 glusterfs]# gluster snapshot delete volume vol1 Volume (vol1) contains 9 snapshot(s). Do you still want to continue and delete them? (y/n) y snapshot delete: snap2: snap removed successfully snapshot delete: snap3: snap removed successfully snapshot delete: snap4: snap removed successfully snapshot delete: snap5: snap removed successfully . . . ----------------------------------------------------------------- Case 3 : Deleting all the snapshots in a system. [root@snapshot-24 glusterfs]# gluster snapshot delete all System contains 4 snapshot(s). Do you still want to continue and delete them? (y/n) y snapshot delete: snap7: snap removed successfully snapshot delete: snap8: snap removed successfully snapshot delete: snap9: snap removed successfully snapshot delete: snap10: snap removed successfully ======================================================================== Change-Id: Ifec8e128ab2011cbbba208376b9c92cfbe7d8d71 BUG: 1112613 Signed-off-by: Sachin Pandit <spandit@redhat.com> Reviewed-on: http://review.gluster.org/8162 Reviewed-by: Atin Mukherjee <amukherj@redhat.com> Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Avra Sengupta <asengupt@redhat.com> Reviewed-by: Raghavendra Bhat <raghavendra@redhat.com> Reviewed-by: Kaushal M <kaushal@redhat.com>
-rw-r--r--cli/src/cli-cmd-parser.c73
-rw-r--r--cli/src/cli-cmd-snapshot.c2
-rw-r--r--cli/src/cli-rpc-ops.c216
-rw-r--r--rpc/xdr/src/cli1-xdr.x6
-rw-r--r--tests/bugs/bug-1087203.t61
-rw-r--r--tests/bugs/bug-1112613.t49
-rwxr-xr-xtests/snapshot.rc66
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-snapshot.c211
8 files changed, 588 insertions, 96 deletions
diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c
index 85a916e380c..a0b873d2358 100644
--- a/cli/src/cli-cmd-parser.c
+++ b/cli/src/cli-cmd-parser.c
@@ -3424,7 +3424,7 @@ cli_snap_info_parse (dict_t *dict, const char **words, int wordcount)
GF_ASSERT (dict);
if (wordcount > 4 || wordcount < cmdi) {
- gf_log ("", GF_LOG_ERROR, "Invalid syntax");
+ gf_log ("cli", GF_LOG_ERROR, "Invalid syntax");
goto out;
}
@@ -3475,7 +3475,7 @@ cli_snap_info_parse (dict_t *dict, const char **words, int wordcount)
ret = dict_set_str (dict, "volname", (char *)words[wordcount - 1]);
if (ret) {
- gf_log ("", GF_LOG_ERROR, "Count not save "
+ gf_log ("cli", GF_LOG_ERROR, "Could not save "
"volume name %s", words[wordcount - 1]);
goto out;
}
@@ -3636,34 +3636,71 @@ cli_snap_delete_parse (dict_t *dict, const char **words, int wordcount,
int ret = -1;
const char *question = NULL;
+ int32_t cmd = -1;
+ unsigned int cmdi = 2;
gf_answer_t answer = GF_ANSWER_NO;
- question = "Deleting snap will erase all the information about "
- "the snap. Do you still want to continue?";
-
GF_ASSERT (words);
GF_ASSERT (dict);
- if (wordcount != 3) {
+ if (wordcount > 4 || wordcount <= cmdi) {
gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax");
goto out;
}
- ret = dict_set_str (dict, "snapname", (char *)words[2]);
- if (ret) {
- gf_log ("cli", GF_LOG_ERROR, "Unable to save snapname %s",
- words[2]);
- goto out;
+ question = "Deleting snap will erase all the information about "
+ "the snap. Do you still want to continue?";
+
+ if (strcmp (words [cmdi], "all") == 0) {
+ ret = 0;
+ cmd = GF_SNAP_DELETE_TYPE_ALL;
+ } else if (strcmp (words [cmdi], "volume") == 0) {
+ if (++cmdi == wordcount) {
+ ret = -1;
+ gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax");
+ goto out;
+ }
+
+ ret = dict_set_str (dict, "volname",
+ (char *)words[cmdi]);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not save "
+ "volume name %s", words[wordcount - 1]);
+ goto out;
+ }
+ cmd = GF_SNAP_DELETE_TYPE_VOL;
+ } else {
+ ret = dict_set_str (dict, "snapname", (char *)words[cmdi]);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Unable to save "
+ "snapname %s", words[2]);
+ goto out;
+ }
+ cmd = GF_SNAP_DELETE_TYPE_SNAP;
}
- answer = cli_cmd_get_confirmation (state, question);
- if (GF_ANSWER_NO == answer) {
- ret = 1;
- gf_log ("cli", GF_LOG_DEBUG, "User cancelled "
- "snapshot delete operation for snap %s",
- (char *)words[2]);
+ if ((cmdi + 1) != wordcount) {
+ ret = -1;
+ gf_log ("cli", GF_LOG_ERROR, "Invalid Syntax");
goto out;
}
+
+ if (cmd == GF_SNAP_DELETE_TYPE_SNAP) {
+ answer = cli_cmd_get_confirmation (state, question);
+ if (GF_ANSWER_NO == answer) {
+ ret = 1;
+ gf_log ("cli", GF_LOG_DEBUG, "User cancelled "
+ "snapshot delete operation for snap %s",
+ (char *)words[2]);
+ goto out;
+ }
+ }
+
+ ret = dict_set_int32 (dict, "delete-cmd", cmd);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not save "
+ "type of snapshot delete");
+ }
out:
return ret;
}
@@ -4002,7 +4039,7 @@ cli_cmd_snapshot_parse (const char **words, int wordcount, dict_t **options,
"activate", "deactivate", "list",
"status", "config", "info", NULL};
char *invalid_snapnames[] = {"description", "force",
- "volume", NULL};
+ "volume", "all", NULL};
GF_ASSERT (words);
GF_ASSERT (options);
diff --git a/cli/src/cli-cmd-snapshot.c b/cli/src/cli-cmd-snapshot.c
index 1fb4e5e634c..07d04595b06 100644
--- a/cli/src/cli-cmd-snapshot.c
+++ b/cli/src/cli-cmd-snapshot.c
@@ -108,7 +108,7 @@ struct cli_cmd snapshot_cmds[] = {
cli_cmd_snapshot_cbk,
"Snapshot Config."
},
- {"snapshot delete <snapname>",
+ {"snapshot delete (all | snapname | volume <volname>)",
cli_cmd_snapshot_cbk,
"Snapshot Delete."
},
diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c
index 6728c9c4e6e..187fcc1bee4 100644
--- a/cli/src/cli-rpc-ops.c
+++ b/cli/src/cli-rpc-ops.c
@@ -7721,11 +7721,14 @@ out:
}
int32_t
-cli_snapshot_remove_reply (gf_cli_rsp *rsp, dict_t *dict)
+cli_snapshot_remove_reply (gf_cli_rsp *rsp, dict_t *dict, call_frame_t *frame)
{
- int32_t ret = -1;
- char *snap_name = NULL;
+ int32_t ret = -1;
+ char *snap_name = NULL;
+ int32_t delete_cmd = -1;
+ cli_local_t *local = NULL;
+ GF_ASSERT (frame);
GF_ASSERT (rsp);
GF_ASSERT (dict);
@@ -7737,6 +7740,31 @@ cli_snapshot_remove_reply (gf_cli_rsp *rsp, dict_t *dict)
goto out;
}
+ ret = dict_get_int32 (dict, "delete-cmd", &delete_cmd);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not get delete-cmd");
+ goto out;
+ }
+
+ if (delete_cmd == GF_SNAP_DELETE_TYPE_ALL ||
+ delete_cmd == GF_SNAP_DELETE_TYPE_VOL) {
+ local = ((call_frame_t *) frame) -> local;
+ if (!local) {
+ ret = -1;
+ gf_log ("cli", GF_LOG_ERROR, "frame->local is NULL");
+ goto out;
+ }
+
+ /* During first call back of snapshot delete of type
+ * ALL and VOL, We will get the snapcount and snapnames.
+ * Hence to make the subsequent rpc calls for individual
+ * snapshot delete, We need to save it in local dictionary.
+ */
+ dict_copy (dict, local->dict);
+ ret = 0;
+ goto out;
+ }
+
ret = dict_get_str (dict, "snapname", &snap_name);
if (ret) {
gf_log ("cli", GF_LOG_ERROR, "Failed to get snapname");
@@ -8455,6 +8483,60 @@ out:
return ret;
}
+int32_t
+cli_populate_req_dict_for_delete (dict_t *snap_dict, dict_t *dict, size_t index)
+{
+ int32_t ret = -1;
+ char key[PATH_MAX] = "";
+ char *buffer = NULL;
+ int type = 0;
+ int snapcount = 0;
+
+ GF_ASSERT (snap_dict);
+ GF_ASSERT (dict);
+
+ ret = dict_set_int32 (snap_dict, "delete-cmd",
+ GF_SNAP_DELETE_TYPE_SNAP);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not save command "
+ "type in snap dictionary");
+ goto out;
+ }
+
+ ret = snprintf (key, sizeof (key), "snapname%lu", index);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = dict_get_str (dict, key, &buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get snapname");
+ goto out;
+ }
+
+ ret = dict_set_dynstr_with_alloc (snap_dict, "snapname", buffer);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to save snapname");
+ goto out;
+ }
+
+ ret = dict_set_int32 (snap_dict, "type", GF_SNAP_OPTION_TYPE_DELETE);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to save command type");
+ goto out;
+ }
+
+ ret = dict_set_dynstr_with_alloc (snap_dict, "cmd-str",
+ "snapshot delete");
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR,
+ "Could not save command string as delete");
+ goto out;
+ }
+out:
+ return ret;
+}
+
int
cli_populate_req_dict_for_status (dict_t *snap_dict, dict_t *dict, int index) {
int ret = -1;
@@ -8818,7 +8900,7 @@ gf_cli_snapshot_cbk (struct rpc_req *req, struct iovec *iov,
break;
case GF_SNAP_OPTION_TYPE_DELETE:
- ret = cli_snapshot_remove_reply (&rsp, dict);
+ ret = cli_snapshot_remove_reply (&rsp, dict, frame);
if (ret) {
gf_log ("cli", GF_LOG_ERROR,
"Failed to delete snap");
@@ -8852,6 +8934,123 @@ out:
}
int32_t
+gf_cli_snapshot_for_delete (call_frame_t *frame, xlator_t *this,
+ void *data)
+{
+ gf_cli_req req = {{0,}};
+ dict_t *options = NULL;
+ int32_t ret = -1;
+ int32_t cmd = -1;
+ cli_local_t *local = NULL;
+ dict_t *snap_dict = NULL;
+ int32_t snapcount = 0;
+ int i = 0;
+ char question[PATH_MAX] = "";
+ char *volname = NULL;
+ gf_answer_t answer = GF_ANSWER_NO;
+
+ GF_VALIDATE_OR_GOTO ("cli", frame, out);
+ GF_VALIDATE_OR_GOTO ("cli", frame->local, out);
+ GF_VALIDATE_OR_GOTO ("cli", this, out);
+ GF_VALIDATE_OR_GOTO ("cli", data, out);
+
+ local = frame->local;
+
+ options = data;
+
+ ret = dict_get_int32 (local->dict, "delete-cmd", &cmd);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get "
+ "delete-cmd");
+ goto out;
+ }
+
+ /* No need multiple RPCs for individual snapshot delete*/
+ if (cmd == GF_SNAP_DELETE_TYPE_SNAP) {
+ ret = 0;
+ goto out;
+ }
+
+ ret = dict_get_int32 (local->dict, "snapcount",
+ &snapcount);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not get "
+ "snapcount");
+ goto out;
+ }
+
+ if (snapcount == 0) {
+ cli_out ("No snapshots present");
+ goto out;
+ }
+
+ if (cmd == GF_SNAP_DELETE_TYPE_ALL) {
+ snprintf (question, sizeof (question), "System contains %d "
+ "snapshot(s).\nDo you still "
+ "want to continue and delete them? ",
+ snapcount);
+ } else {
+ ret = dict_get_str (local->dict, "volname", &volname);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to fetch "
+ "volname from local dictionary");
+ goto out;
+ }
+
+ snprintf (question, sizeof (question), "Volume (%s) contains "
+ "%d snapshot(s).\nDo you still want to "
+ "continue and delete them? ", volname,
+ snapcount);
+ }
+
+ answer = cli_cmd_get_confirmation (global_state, question);
+ if (GF_ANSWER_NO == answer) {
+ ret = 0;
+ gf_log ("cli", GF_LOG_DEBUG, "User cancelled "
+ "snapshot delete operation for snap delete");
+ goto out;
+ }
+
+ for (i = 1 ; i <= snapcount ; i++) {
+ ret = -1;
+
+ snap_dict = dict_new();
+ if (!snap_dict)
+ goto out;
+
+ ret = cli_populate_req_dict_for_delete (snap_dict,
+ local->dict, i);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Could not "
+ "populate snap request dictionary");
+ goto out;
+ }
+
+ ret = cli_to_glusterd (&req, frame,
+ gf_cli_snapshot_cbk,
+ (xdrproc_t) xdr_gf_cli_req, snap_dict,
+ GLUSTER_CLI_SNAP, this, cli_rpc_prog,
+ NULL);
+ if (ret) {
+ /* Fail the operation if deleting one of the
+ * snapshots is failed
+ */
+ gf_log ("cli", GF_LOG_ERROR, "cli_to_glusterd "
+ "for snapshot delete failed");
+ goto out;
+ }
+ dict_unref (snap_dict);
+ snap_dict = NULL;
+ }
+
+out:
+ if (snap_dict)
+ dict_unref (snap_dict);
+
+ return ret;
+}
+
+int32_t
gf_cli_snapshot_for_status (call_frame_t *frame, xlator_t *this,
void *data)
{
@@ -9005,6 +9204,15 @@ gf_cli_snapshot (call_frame_t *frame, xlator_t *this,
}
}
+ if (GF_SNAP_OPTION_TYPE_DELETE == type) {
+ ret = gf_cli_snapshot_for_delete (frame, this, data);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "cli to glusterd "
+ "for snapshot delete command failed");
+ goto out;
+ }
+ }
+
ret = 0;
out:
diff --git a/rpc/xdr/src/cli1-xdr.x b/rpc/xdr/src/cli1-xdr.x
index 3a9841934cb..f7bfcf469d5 100644
--- a/rpc/xdr/src/cli1-xdr.x
+++ b/rpc/xdr/src/cli1-xdr.x
@@ -172,6 +172,12 @@ enum gf1_cli_snapshot_status {
GF_SNAP_STATUS_TYPE_VOL
};
+enum gf1_cli_snapshot_delete {
+ GF_SNAP_DELETE_TYPE_ALL = 0,
+ GF_SNAP_DELETE_TYPE_SNAP = 1,
+ GF_SNAP_DELETE_TYPE_VOL = 2
+};
+
struct gf_cli_req {
opaque dict<>;
};
diff --git a/tests/bugs/bug-1087203.t b/tests/bugs/bug-1087203.t
index 585ecf440ac..e41d601fb66 100644
--- a/tests/bugs/bug-1087203.t
+++ b/tests/bugs/bug-1087203.t
@@ -5,50 +5,12 @@
. $(dirname $0)/../snapshot.rc
. $(dirname $0)/../cluster.rc
-function config_validate ()
-{
- local var=$1
- $CLI_1 snapshot config | grep "^$var" | sed 's/.*: //'
-}
-
-function snap_create ()
-{
- local limit=$1;
- local i=0
- while [ $i -lt $limit ]
- do
- $CLI_1 snapshot create snap$i ${V0}
- i=$[$i+1]
- done
-}
-
-function snap_delete ()
-{
- local limit=$1;
- local i=0
- while [ $i -lt $limit ]
- do
- $CLI_1 snapshot delete snap$i
- i=$[$i+1]
- done
-}
-
-function get_snap_count ()
-{
- $CLI_1 snapshot list | wc -l
-}
-
function get_volume_info ()
{
local var=$1
$CLI_1 volume info $V0 | grep "^$var" | sed 's/.*: //'
}
-function is_snapshot_present ()
-{
- $CLI_1 snapshot list
-}
-
cleanup;
TEST verify_lvm_version
@@ -94,7 +56,7 @@ TEST $CLI_1 snapshot config $V0 snap-max-hard-limit 10
# Validating auto-delete feature
# Make sure auto-delete is disabled by default
-EXPECT 'disable' config_validate 'auto-delete'
+EXPECT 'disable' snap_config CLI_1 'auto-delete'
# Test for invalid value for auto-delete
TEST ! $CLI_1 snapshot config auto-delete test
@@ -103,36 +65,39 @@ TEST $CLI_1 snapshot config snap-max-hard-limit 6
TEST $CLI_1 snapshot config snap-max-soft-limit 50
# Create 4 snapshots
-TEST snap_create 4;
+snap_index=1
+snap_count=4
+TEST snap_create CLI_1 $V0 $snap_index $snap_count
# If auto-delete is disabled then oldest snapshot
# should not be deleted automatically.
-EXPECT '4' get_snap_count;
+EXPECT '4' get_snap_count CLI_1;
-TEST snap_delete 4;
+TEST snap_delete CLI_1 $snap_index $snap_count;
# After all those 4 snaps are deleted, There will not be any snaps present
-EXPECT 'No snapshots present' is_snapshot_present;
+EXPECT '0' get_snap_count CLI_1;
TEST $CLI_1 snapshot config auto-delete enable
+
# auto-delete is already enabled, Hence expect a failure.
TEST ! $CLI_1 snapshot config auto-delete on
# Testing other boolean values with auto-delete
TEST $CLI_1 snapshot config auto-delete off
-EXPECT 'off' config_validate 'auto-delete'
+EXPECT 'off' snap_config CLI_1 'auto-delete'
TEST $CLI_1 snapshot config auto-delete true
-EXPECT 'true' config_validate 'auto-delete'
+EXPECT 'true' snap_config CLI_1 'auto-delete'
# Try to create 4 snaps again, As auto-delete is enabled
# oldest snap should be deleted and snapcount should be 3
-TEST snap_create 4;
-EXPECT '3' get_snap_count;
+TEST snap_create CLI_1 $V0 $snap_index $snap_count;
+EXPECT '3' get_snap_count CLI_1;
TEST $CLI_1 snapshot config auto-delete disable
-EXPECT 'disable' config_validate 'auto-delete'
+EXPECT 'disable' snap_config CLI_1 'auto-delete'
cleanup;
diff --git a/tests/bugs/bug-1112613.t b/tests/bugs/bug-1112613.t
new file mode 100644
index 00000000000..17302eaa427
--- /dev/null
+++ b/tests/bugs/bug-1112613.t
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+. $(dirname $0)/../include.rc
+. $(dirname $0)/../volume.rc
+. $(dirname $0)/../snapshot.rc
+. $(dirname $0)/../cluster.rc
+
+cleanup;
+
+V1="patchy2"
+
+TEST verify_lvm_version;
+TEST launch_cluster 2
+TEST setup_lvm 2
+
+TEST $CLI_1 peer probe $H2
+EXPECT_WITHIN $PROBE_TIMEOUT 1 peer_count
+
+TEST $CLI_1 volume create $V0 $H1:$L1
+TEST $CLI_1 volume start $V0
+TEST $CLI_1 volume create $V1 $H2:$L2
+TEST $CLI_1 volume start $V1
+
+# Create 3 snapshots for volume $V0
+snap_count=3
+snap_index=1
+TEST snap_create CLI_1 $V0 $snap_index $snap_count;
+
+# Create 3 snapshots for volume $V1
+snap_count=4
+snap_index=11
+TEST snap_create CLI_1 $V1 $snap_index $snap_count;
+
+EXPECT '3' get_snap_count CLI_1 $V0;
+EXPECT '4' get_snap_count CLI_1 $V1;
+EXPECT '7' get_snap_count CLI_1
+
+TEST $CLI_1 snapshot delete volume $V0
+EXPECT '0' get_snap_count CLI_1 $V0;
+EXPECT '4' get_snap_count CLI_1 $V1;
+EXPECT '4' get_snap_count CLI_1
+
+TEST $CLI_1 snapshot delete all
+EXPECT '0' get_snap_count CLI_1 $V0;
+EXPECT '0' get_snap_count CLI_1 $V1;
+EXPECT '0' get_snap_count CLI_1
+
+cleanup;
+
diff --git a/tests/snapshot.rc b/tests/snapshot.rc
index a208fa3d410..408b5a72a0c 100755
--- a/tests/snapshot.rc
+++ b/tests/snapshot.rc
@@ -318,3 +318,69 @@ function volume_exists() {
return 0
fi
}
+
+# arg-1 : From which node the command should be trigerred
+# Ex : $CLI_1, $CLI_2, etc.
+# arg-2 : Volume name
+# arg-3 : Starting index for the snapname "snap$i"
+# arg-4 : Number of snapshots to be taken
+function snap_create()
+{
+ eval local cli_index=\$$1
+ local volname=$2
+ local i=$3
+ local limit=$[$i + $4]
+
+ while [ $i -lt $limit ]
+ do
+ $cli_index snapshot create snap$i $volname
+ i=$[$i+1]
+ done
+}
+
+# arg-1 : From which node the command should be trigerred
+# Ex : $CLI_1. $CLI_2, etc.
+# arg-2 : Volume name.
+function get_snap_count()
+{
+ eval local cli_index=\$$1
+ local volname=$2
+
+
+ if [ -z "$2" ]
+ then
+ $cli_index snapshot list | grep -v "No snapshots present"\
+ | wc -l
+ else
+ $cli_index snapshot list $volname\
+ | grep -v "No snapshots present"\
+ | wc -l
+ fi
+}
+
+# arg-1 : From which node the command should be trigerred
+# Ex : $CLI_1, $CLI_2, etc.
+# arg-2 : Starting index for the snapname "snap$i"
+# arg-3 : Number of snapshots to be deleted.
+function snap_delete()
+{
+ eval local cli_index=\$$1
+ local i=$2
+ local limit=$[$i + $3]
+
+ while [ $i -lt $limit ]
+ do
+ $cli_index snapshot delete snap$i
+ i=$[$i+1]
+ done
+}
+
+# arg-1 : From which node the command should be triggered
+# Ex : $CLI_1, $CLI_2, etc.
+# arg-2 : key value
+function snap_config()
+{
+ eval local cli_index=\$$1
+ local var=$2
+ $cli_index snapshot config | grep "^$var" | sed 's/.*: //'
+}
diff --git a/xlators/mgmt/glusterd/src/glusterd-snapshot.c b/xlators/mgmt/glusterd/src/glusterd-snapshot.c
index b40d7abc408..2f9f68e97e1 100644
--- a/xlators/mgmt/glusterd/src/glusterd-snapshot.c
+++ b/xlators/mgmt/glusterd/src/glusterd-snapshot.c
@@ -3123,15 +3123,10 @@ glusterd_snapshot_get_vol_snapnames (dict_t *dict, glusterd_volinfo_t *volinfo)
list_for_each_entry_safe (snap_vol, tmp_vol,
&volinfo->snap_volumes, snapvol_list) {
snapcount++;
- snapname = gf_strdup (snap_vol->snapshot->snapname);
- if (!snapname) {
- gf_log (this->name, GF_LOG_ERROR,
- "strdup failed");
- ret = -1;
- goto out;
- }
snprintf (key, sizeof (key), "snapname%d", snapcount);
- ret = dict_set_dynstr (dict, key, snapname);
+
+ ret = dict_set_dynstr_with_alloc (dict, key,
+ snap_vol->snapshot->snapname);
if (ret) {
gf_log (this->name, GF_LOG_ERROR, "Failed to "
"set %s", key);
@@ -4472,23 +4467,104 @@ out:
return ret;
}
-/* This is a snapshot remove handler function. This function will be
- * executed in the originator node. This function is responsible for
- * calling mgmt v3 framework to do the actual remove on all the bricks
- *
- * @param req RPC request object
- * @param op gluster operation
- * @param dict dictionary containing snapshot remove request
- * @param err_str In case of an err this string should be populated
- * @param len length of err_str buffer
- *
- * @return Negative value on Failure and 0 in success
- */
-int
-glusterd_handle_snapshot_remove (rpcsvc_request_t *req, glusterd_op_t op,
- dict_t *dict, char *err_str, size_t len)
+int32_t
+glusterd_handle_snapshot_delete_vol (dict_t *dict, char *err_str, int len)
{
- int ret = -1;
+ int32_t ret = -1;
+ int32_t i = 0;
+ glusterd_volinfo_t *snap_volinfo = NULL;
+ glusterd_volinfo_t *volinfo = NULL;
+ glusterd_volinfo_t *temp_volinfo = NULL;
+ char key[PATH_MAX] = "";
+ xlator_t *this = NULL;
+ char *volname = NULL;
+
+ this = THIS;
+ GF_ASSERT (this);
+ GF_ASSERT (dict);
+
+ ret = dict_get_str (dict, "volname", &volname);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to get "
+ "volume name");
+ goto out;
+ }
+
+ ret = glusterd_volinfo_find (volname, &volinfo);
+ if (ret) {
+ snprintf (err_str, len, "Volume (%s) does not exist", volname);
+ gf_log (this->name, GF_LOG_ERROR, "Failed to get volinfo of "
+ "volume %s", volname);
+ goto out;
+ }
+
+ ret = glusterd_snapshot_get_vol_snapnames (dict, volinfo);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "Failed to get snapshot list for volume %s", volname);
+ goto out;
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+int32_t
+glusterd_handle_snapshot_delete_all (dict_t *dict)
+{
+ int32_t ret = -1;
+ int32_t i = 0;
+ char key[PATH_MAX] = "";
+ glusterd_conf_t *priv = NULL;
+ glusterd_snap_t *snap = NULL;
+ glusterd_snap_t *tmp_snap = NULL;
+ xlator_t *this = NULL;
+
+ this = THIS;
+ GF_ASSERT (this);
+ priv = this->private;
+ GF_ASSERT (priv);
+
+ GF_ASSERT (dict);
+
+ list_for_each_entry_safe (snap, tmp_snap, &priv->snapshots, snap_list) {
+ /* indexing from 1 to n, to keep it uniform with other code
+ * paths
+ */
+ i++;
+ ret = snprintf (key, sizeof (key), "snapname%d", i);
+ if (ret < 0) {
+ goto out;
+ }
+
+ ret = dict_set_dynstr_with_alloc (dict, key, snap->snapname);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Could not save "
+ "snap name");
+ goto out;
+ }
+ }
+
+ ret = dict_set_int32 (dict, "snapcount", i);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Could not save snapcount");
+ goto out;
+ }
+
+ ret = 0;
+
+out:
+ return ret;
+}
+
+int32_t
+glusterd_handle_snapshot_delete_type_snap (rpcsvc_request_t *req,
+ glusterd_op_t op,
+ dict_t *dict, char *err_str,
+ size_t len)
+{
+ int32_t ret = -1;
int64_t volcount = 0;
char *snapname = NULL;
char *volname = NULL;
@@ -4499,6 +4575,7 @@ glusterd_handle_snapshot_remove (rpcsvc_request_t *req, glusterd_op_t op,
xlator_t *this = NULL;
this = THIS;
+ GF_ASSERT (this);
GF_ASSERT (req);
GF_ASSERT (dict);
@@ -4553,6 +4630,90 @@ glusterd_handle_snapshot_remove (rpcsvc_request_t *req, glusterd_op_t op,
}
ret = 0;
+
+out :
+ return ret;
+}
+
+/* This is a snapshot remove handler function. This function will be
+ * executed in the originator node. This function is responsible for
+ * calling mgmt v3 framework to do the actual remove on all the bricks
+ *
+ * @param req RPC request object
+ * @param op gluster operation
+ * @param dict dictionary containing snapshot remove request
+ * @param err_str In case of an err this string should be populated
+ * @param len length of err_str buffer
+ *
+ * @return Negative value on Failure and 0 in success
+ */
+int
+glusterd_handle_snapshot_delete (rpcsvc_request_t *req, glusterd_op_t op,
+ dict_t *dict, char *err_str, size_t len)
+{
+ int ret = -1;
+ xlator_t *this = NULL;
+ int32_t delete_cmd = -1;
+
+ this = THIS;
+
+ GF_ASSERT (this);
+
+ GF_ASSERT (req);
+ GF_ASSERT (dict);
+ GF_ASSERT (err_str);
+
+ ret = dict_get_int32 (dict, "delete-cmd", &delete_cmd);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to get delete-cmd");
+ goto out;
+ }
+
+ switch (delete_cmd) {
+ case GF_SNAP_DELETE_TYPE_SNAP:
+ ret = glusterd_handle_snapshot_delete_type_snap (req, op, dict,
+ err_str, len);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to handle "
+ "snapshot delete for type SNAP");
+ goto out;
+ }
+ break;
+
+ case GF_SNAP_DELETE_TYPE_ALL:
+ ret = glusterd_handle_snapshot_delete_all (dict);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to handle "
+ "snapshot delete for type ALL");
+ goto out;
+ }
+ break;
+
+ case GF_SNAP_DELETE_TYPE_VOL:
+ ret = glusterd_handle_snapshot_delete_vol (dict, err_str, len);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to handle "
+ "snapshot delete for type VOL");
+ goto out;
+ }
+ break;
+
+ default:
+ gf_log (this->name, GF_LOG_ERROR, "Wrong snapshot delete type");
+ break;
+ }
+
+ if ( ret == 0 && (delete_cmd == GF_SNAP_DELETE_TYPE_ALL ||
+ delete_cmd == GF_SNAP_DELETE_TYPE_VOL)) {
+ ret = glusterd_op_send_cli_response (op, 0, 0, req, dict,
+ err_str);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to send cli "
+ "response");
+ goto out;
+ }
+ }
+ ret = 0;
out:
return ret;
}
@@ -7343,7 +7504,7 @@ glusterd_handle_snapshot_fn (rpcsvc_request_t *req)
}
break;
case GF_SNAP_OPTION_TYPE_DELETE:
- ret = glusterd_handle_snapshot_remove (req, cli_op, dict,
+ ret = glusterd_handle_snapshot_delete (req, cli_op, dict,
err_str,
sizeof (err_str));
if (ret) {