You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by pp...@apache.org on 2022/02/22 21:05:24 UTC

[ignite] branch master updated: IGNITE-15450 Added a special option to run snapshot commands synchronously using control.sh (#9760)

This is an automated email from the ASF dual-hosted git repository.

ppa pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new aade8eb  IGNITE-15450 Added a special option to run snapshot commands synchronously using control.sh (#9760)
aade8eb is described below

commit aade8eb625df0e4217aabb3a8a78e3b60cb6ed93
Author: Pavel Pereslegin <xx...@gmail.com>
AuthorDate: Wed Feb 23 00:04:36 2022 +0300

    IGNITE-15450 Added a special option to run snapshot commands synchronously using control.sh (#9760)
---
 docs/_docs/snapshots/snapshots.adoc                |  16 ++-
 .../snapshot/SnapshotCancelCommand.java            |  38 ++++++
 .../commandline/snapshot/SnapshotCheckCommand.java |  44 +++++++
 .../commandline/snapshot/SnapshotCommand.java      |  99 ++-------------
 .../snapshot/SnapshotCreateCommand.java            |  74 ++++++++++++
 .../snapshot/SnapshotCreateCommandOption.java      |  64 ++++++++++
 .../snapshot/SnapshotRestoreCommand.java           | 134 +++++++++++++++++++++
 .../snapshot/SnapshotRestoreCommandOption.java     |  72 +++++++++++
 .../commandline/snapshot/SnapshotSubcommand.java   | 100 +++++++++------
 .../commandline/snapshot/SnapshotSubcommands.java  |  76 ++++++++++++
 .../apache/ignite/util/GridCommandHandlerTest.java | 125 +++++++++++++++++--
 .../snapshot/SnapshotRestoreProcess.java           |   3 +-
 .../visor/snapshot/VisorSnapshotCancelTask.java    |   3 +-
 .../visor/snapshot/VisorSnapshotCheckTask.java     |   3 +-
 .../visor/snapshot/VisorSnapshotCreateTask.java    |  25 ++--
 ...askArg.java => VisorSnapshotCreateTaskArg.java} |  46 +++----
 .../visor/snapshot/VisorSnapshotOneNodeTask.java   |  38 ++++++
 .../visor/snapshot/VisorSnapshotRestoreTask.java   |  11 +-
 .../snapshot/VisorSnapshotRestoreTaskAction.java   |  18 ---
 .../snapshot/VisorSnapshotRestoreTaskArg.java      |  27 ++---
 .../visor/snapshot/VisorSnapshotTaskResult.java    |  75 ++++++++++++
 .../main/resources/META-INF/classnames.properties  |   2 +
 ...ridCommandHandlerClusterByClassTest_help.output |   6 +-
 ...andHandlerClusterByClassWithSSLTest_help.output |   6 +-
 24 files changed, 868 insertions(+), 237 deletions(-)

diff --git a/docs/_docs/snapshots/snapshots.adoc b/docs/_docs/snapshots/snapshots.adoc
index 621d3f3..4764fc2 100644
--- a/docs/_docs/snapshots/snapshots.adoc
+++ b/docs/_docs/snapshots/snapshots.adoc
@@ -105,9 +105,12 @@ Ignite ships the link:tools/control-script[Control Script] that supports snapsho
 
 [source,shell]
 ----
-#Create a cluster snapshot:
+#Create a cluster snapshot in the background:
 control.(sh|bat) --snapshot create snapshot_name
 
+#Create a cluster snapshot (wait for the entire operation to complete):
+control.(sh|bat) --snapshot create snapshot_name --sync
+
 #Cancel a running snapshot:
 control.(sh|bat) --snapshot cancel snapshot_name
 
@@ -207,7 +210,7 @@ tab:CLI[]
 [source,shell]
 ----
 # Restore cache group "snapshot-cache" from the snapshot "snapshot_02092020".
-control.(sh|bat) --snapshot restore snapshot_02092020 --start snapshot-cache
+control.(sh|bat) --snapshot restore snapshot_02092020 --start --groups snapshot-cache
 ----
 --
 
@@ -216,11 +219,14 @@ The `control.sh|bat` script provides the ability to start, stop, and get the sta
 
 [source,shell]
 ----
-# Start restoring all user-created cache groups from the snapshot "snapshot_09062021".
+# Start restoring all user-created cache groups from the snapshot "snapshot_09062021" in the background.
 control.(sh|bat) --snapshot restore snapshot_09062021 --start
 
-# Start restoring only "cache-group1" and "cache-group2" from the snapshot "snapshot_09062021".
-control.(sh|bat) --snapshot restore snapshot_09062021 --start cache-group1,cache-group2
+# Start restoring all user-created cache groups from the snapshot "snapshot_09062021" and wait for the entire operation to complete.
+control.(sh|bat) --snapshot restore snapshot_09062021 --start --sync
+
+# Start restoring only "cache-group1" and "cache-group2" from the snapshot "snapshot_09062021" in the background.
+control.(sh|bat) --snapshot restore snapshot_09062021 --start --groups cache-group1,cache-group2
 
 # Get the status of the restore operation for "snapshot_09062021".
 control.(sh|bat) --snapshot restore snapshot_09062021 --status
diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotCancelCommand.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotCancelCommand.java
new file mode 100644
index 0000000..5c29e9e
--- /dev/null
+++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotCancelCommand.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline.snapshot;
+
+import java.util.logging.Logger;
+import org.apache.ignite.internal.visor.snapshot.VisorSnapshotCancelTask;
+
+import static org.apache.ignite.internal.commandline.CommandList.SNAPSHOT;
+
+/**
+ * Sub-command to cancel running snapshot.
+ */
+public class SnapshotCancelCommand extends SnapshotSubcommand {
+    /** Default constructor. */
+    protected SnapshotCancelCommand() {
+        super("cancel", VisorSnapshotCancelTask.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void printUsage(Logger log) {
+        usage(log, "Cancel running snapshot:", SNAPSHOT, generalUsageOptions(), name(), SNAPSHOT_NAME_ARG);
+    }
+}
diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotCheckCommand.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotCheckCommand.java
new file mode 100644
index 0000000..9bbf9ea
--- /dev/null
+++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotCheckCommand.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline.snapshot;
+
+import java.util.logging.Logger;
+import org.apache.ignite.internal.processors.cache.verify.IdleVerifyResultV2;
+import org.apache.ignite.internal.visor.snapshot.VisorSnapshotCheckTask;
+
+import static org.apache.ignite.internal.commandline.CommandList.SNAPSHOT;
+
+/**
+ * Sub-command to check snapshot.
+ */
+public class SnapshotCheckCommand extends SnapshotSubcommand {
+    /** Default constructor. */
+    protected SnapshotCheckCommand() {
+        super("check", VisorSnapshotCheckTask.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void printUsage(Logger log) {
+        usage(log, "Check snapshot:", SNAPSHOT, generalUsageOptions(), name(), SNAPSHOT_NAME_ARG);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void printResult(Object res, Logger log) {
+        ((IdleVerifyResultV2)res).print(log::info, true);
+    }
+}
diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotCommand.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotCommand.java
index 5e023f2..c6fc97e 100644
--- a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotCommand.java
+++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotCommand.java
@@ -17,31 +17,14 @@
 
 package org.apache.ignite.internal.commandline.snapshot;
 
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
 import java.util.logging.Logger;
-import org.apache.ignite.internal.client.GridClient;
 import org.apache.ignite.internal.client.GridClientConfiguration;
 import org.apache.ignite.internal.commandline.AbstractCommand;
-import org.apache.ignite.internal.commandline.Command;
 import org.apache.ignite.internal.commandline.CommandArgIterator;
-import org.apache.ignite.internal.commandline.CommandLogger;
 import org.apache.ignite.internal.processors.cache.persistence.snapshot.IgniteSnapshotManager;
-import org.apache.ignite.internal.processors.cache.verify.IdleVerifyResultV2;
-import org.apache.ignite.internal.visor.snapshot.VisorSnapshotRestoreTaskAction;
-import org.apache.ignite.internal.visor.snapshot.VisorSnapshotRestoreTaskArg;
 import org.apache.ignite.mxbean.SnapshotMXBean;
 
 import static org.apache.ignite.internal.commandline.CommandList.SNAPSHOT;
-import static org.apache.ignite.internal.commandline.CommandLogger.optional;
-import static org.apache.ignite.internal.commandline.TaskExecutor.executeTaskByNameOnNode;
-import static org.apache.ignite.internal.commandline.snapshot.SnapshotSubcommand.CANCEL;
-import static org.apache.ignite.internal.commandline.snapshot.SnapshotSubcommand.CHECK;
-import static org.apache.ignite.internal.commandline.snapshot.SnapshotSubcommand.CREATE;
-import static org.apache.ignite.internal.commandline.snapshot.SnapshotSubcommand.RESTORE;
-import static org.apache.ignite.internal.commandline.snapshot.SnapshotSubcommand.of;
 
 /**
  * control.sh Snapshot command.
@@ -50,103 +33,35 @@ import static org.apache.ignite.internal.commandline.snapshot.SnapshotSubcommand
  * @see IgniteSnapshotManager
  */
 public class SnapshotCommand extends AbstractCommand<Object> {
-    /** Command argument. */
-    private Object cmdArg;
-
     /** Snapshot sub-command to execute. */
     private SnapshotSubcommand cmd;
 
     /** {@inheritDoc} */
     @Override public Object execute(GridClientConfiguration clientCfg, Logger log) throws Exception {
-        try (GridClient client = Command.startClient(clientCfg)) {
-            Object res = executeTaskByNameOnNode(
-                client,
-                cmd.taskName(),
-                arg(),
-                null,
-                clientCfg
-            );
-
-            if (cmd == CHECK)
-                ((IdleVerifyResultV2)res).print(log::info, true);
-
-            if (cmd == RESTORE)
-                log.info(String.valueOf(res));
-
-            return res;
-        }
-        catch (Throwable e) {
-            log.severe("Failed to perform operation.");
-            log.severe(CommandLogger.errorMessage(e));
-
-            throw e;
-        }
+        return cmd.execute(clientCfg, log);
     }
 
     /** {@inheritDoc} */
     @Override public Object arg() {
-        return cmdArg;
+        return cmd.arg();
     }
 
     /** {@inheritDoc} */
     @Override public void parseArguments(CommandArgIterator argIter) {
-        cmd = of(argIter.nextArg("Expected snapshot action."));
-        String snpName = argIter.nextArg("Expected snapshot name.");
-
-        if (cmd != RESTORE) {
-            cmdArg = snpName;
-
-            return;
-        }
-
-        VisorSnapshotRestoreTaskAction cmdAction =
-            VisorSnapshotRestoreTaskAction.fromCmdArg(argIter.nextArg("Restore action expected."));
-
-        Set<String> grpNames = null;
-
-        if (argIter.hasNextSubArg()) {
-            String arg = argIter.nextArg("");
+        cmd = SnapshotSubcommands.of(argIter.nextArg("Expected snapshot action.")).subCommand();
 
-            if (cmdAction != VisorSnapshotRestoreTaskAction.START)
-                throw new IllegalArgumentException("Invalid argument \"" + arg + "\", no more arguments expected.");
-
-            grpNames = argIter.parseStringSet(arg);
-        }
-
-        cmdArg = new VisorSnapshotRestoreTaskArg(cmdAction, snpName, grpNames);
+        cmd.parseArguments(argIter);
     }
 
     /** {@inheritDoc} */
     @Override public void printUsage(Logger log) {
-        Map<String, String> commonParams = Collections.singletonMap("snapshot_name", "Snapshot name.");
-
-        usage(log, "Create cluster snapshot:", SNAPSHOT, commonParams, CREATE.toString(), "snapshot_name");
-        usage(log, "Cancel running snapshot:", SNAPSHOT, commonParams, CANCEL.toString(), "snapshot_name");
-        usage(log, "Check snapshot:", SNAPSHOT, commonParams, CHECK.toString(), "snapshot_name");
-
-        Map<String, String> startParams = new LinkedHashMap<>(commonParams);
-
-        startParams.put("group1,...groupN", "Cache group names.");
-
-        usage(log, "Restore snapshot:", SNAPSHOT, startParams, RESTORE.toString(),
-            "snapshot_name", VisorSnapshotRestoreTaskAction.START.cmdName(), optional("group1,...groupN"));
-
-        usage(log, "Snapshot restore operation status:", SNAPSHOT, commonParams, RESTORE.toString(),
-            "snapshot_name", VisorSnapshotRestoreTaskAction.STATUS.cmdName());
-
-        usage(log, "Cancel snapshot restore operation:", SNAPSHOT, commonParams, RESTORE.toString(),
-            "snapshot_name", VisorSnapshotRestoreTaskAction.CANCEL.cmdName());
+        for (SnapshotSubcommands cmd : SnapshotSubcommands.values())
+            cmd.subCommand().printUsage(log);
     }
 
     /** {@inheritDoc} */
     @Override public String confirmationPrompt() {
-        if (cmd != RESTORE)
-            return null;
-
-        VisorSnapshotRestoreTaskArg arg = (VisorSnapshotRestoreTaskArg)cmdArg;
-
-        return arg.jobAction() == VisorSnapshotRestoreTaskAction.START && arg.groupNames() != null ? null :
-            "Warning: command will restore ALL PUBLIC CACHE GROUPS from the snapshot " + arg.snapshotName() + '.';
+        return cmd == null ? null : cmd.confirmationPrompt();
     }
 
     /** {@inheritDoc} */
diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotCreateCommand.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotCreateCommand.java
new file mode 100644
index 0000000..6c2e10a
--- /dev/null
+++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotCreateCommand.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline.snapshot;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.logging.Logger;
+import org.apache.ignite.internal.commandline.CommandArgIterator;
+import org.apache.ignite.internal.commandline.argument.CommandArgUtils;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.visor.snapshot.VisorSnapshotCreateTask;
+import org.apache.ignite.internal.visor.snapshot.VisorSnapshotCreateTaskArg;
+
+import static org.apache.ignite.internal.commandline.CommandList.SNAPSHOT;
+import static org.apache.ignite.internal.commandline.CommandLogger.optional;
+import static org.apache.ignite.internal.commandline.snapshot.SnapshotCreateCommandOption.SYNC;
+
+/**
+ * Sub-command to create a cluster snapshot.
+ */
+public class SnapshotCreateCommand extends SnapshotSubcommand {
+    /** Default constructor. */
+    protected SnapshotCreateCommand() {
+        super("create", VisorSnapshotCreateTask.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void parseArguments(CommandArgIterator argIter) {
+        String snpName = argIter.nextArg("Expected snapshot name.");
+        boolean sync = false;
+
+        while (argIter.hasNextSubArg()) {
+            String arg = argIter.nextArg(null);
+
+            SnapshotCreateCommandOption option = CommandArgUtils.of(arg, SnapshotCreateCommandOption.class);
+
+            if (option == null) {
+                throw new IllegalArgumentException("Invalid argument: " + arg + ". " +
+                    "Possible options: " + F.concat(F.asList(SnapshotCreateCommandOption.values()), ", ") + '.');
+            }
+
+            // The snapshot create command currently supports only one optional argument.
+            assert option == SYNC;
+
+            sync = true;
+        }
+
+        cmdArg = new VisorSnapshotCreateTaskArg(snpName, sync);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void printUsage(Logger log) {
+        Map<String, String> params = new LinkedHashMap<>(generalUsageOptions());
+
+        params.put(SYNC.optionName(), SYNC.description());
+
+        usage(log, "Create cluster snapshot:", SNAPSHOT, params, name(), SNAPSHOT_NAME_ARG, optional(SYNC.argName()));
+    }
+}
diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotCreateCommandOption.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotCreateCommandOption.java
new file mode 100644
index 0000000..4647a48
--- /dev/null
+++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotCreateCommandOption.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline.snapshot;
+
+import org.apache.ignite.internal.commandline.argument.CommandArg;
+
+/**
+ * Snapshot create command options.
+ */
+public enum SnapshotCreateCommandOption implements CommandArg {
+    /** Synchronous execution flag. */
+    SYNC("sync", "Run the operation synchronously, the command will wait for the entire operation to complete. " +
+        "Otherwise, it will be performed in the background, and the command will immediately return control.");
+
+    /** Option name. */
+    private final String name;
+
+    /** Option description. */
+    private final String desc;
+
+    /**
+     * @param name Option name.
+     * @param desc Option description.
+     */
+    SnapshotCreateCommandOption(String name, String desc) {
+        this.name = name;
+        this.desc = desc;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String argName() {
+        return "--" + name;
+    }
+
+    /** @return Option name. */
+    public String optionName() {
+        return name;
+    }
+
+    /** @return Option description. */
+    public String description() {
+        return desc;
+    }
+
+    /** @return Argument name. */
+    @Override public String toString() {
+        return argName();
+    }
+}
diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotRestoreCommand.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotRestoreCommand.java
new file mode 100644
index 0000000..c183c11
--- /dev/null
+++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotRestoreCommand.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline.snapshot;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
+import org.apache.ignite.internal.client.GridClientConfiguration;
+import org.apache.ignite.internal.commandline.CommandArgIterator;
+import org.apache.ignite.internal.commandline.argument.CommandArgUtils;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.visor.snapshot.VisorSnapshotRestoreTask;
+import org.apache.ignite.internal.visor.snapshot.VisorSnapshotRestoreTaskAction;
+import org.apache.ignite.internal.visor.snapshot.VisorSnapshotRestoreTaskArg;
+
+import static org.apache.ignite.internal.commandline.CommandList.SNAPSHOT;
+import static org.apache.ignite.internal.commandline.CommandLogger.optional;
+import static org.apache.ignite.internal.commandline.snapshot.SnapshotRestoreCommandOption.GROUPS;
+import static org.apache.ignite.internal.commandline.snapshot.SnapshotRestoreCommandOption.SYNC;
+import static org.apache.ignite.internal.commandline.snapshot.SnapshotSubcommands.RESTORE;
+
+/**
+ * Sub-command to restore snapshot.
+ */
+public class SnapshotRestoreCommand extends SnapshotSubcommand {
+    /** Default constructor. */
+    protected SnapshotRestoreCommand() {
+        super("restore", VisorSnapshotRestoreTask.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public Object execute(GridClientConfiguration clientCfg, Logger log) throws Exception {
+        Object res = super.execute(clientCfg, log);
+
+        log.info(String.valueOf(res));
+
+        return res;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void parseArguments(CommandArgIterator argIter) {
+        String snpName = argIter.nextArg("Expected snapshot name.");
+        VisorSnapshotRestoreTaskAction restoreAction = parseAction(argIter);
+        Set<String> grpNames = null;
+        boolean sync = false;
+
+        while (argIter.hasNextSubArg()) {
+            String arg = argIter.nextArg(null);
+
+            if (restoreAction != VisorSnapshotRestoreTaskAction.START) {
+                throw new IllegalArgumentException("Invalid argument: " + arg + ". " +
+                    "Action \"--" + restoreAction.name().toLowerCase() + "\" does not support specified option.");
+            }
+
+            SnapshotRestoreCommandOption option = CommandArgUtils.of(arg, SnapshotRestoreCommandOption.class);
+
+            if (option == null) {
+                throw new IllegalArgumentException("Invalid argument: " + arg + ". " +
+                    "Possible options: " + F.concat(F.asList(SnapshotRestoreCommandOption.values()), ", ") + '.');
+            }
+            else if (option == SnapshotRestoreCommandOption.GROUPS) {
+                String argDesc = "a comma-separated list of cache group names.";
+
+                grpNames = argIter.nextStringSet(argDesc);
+
+                if (grpNames.isEmpty())
+                    throw new IllegalArgumentException("Expected " + argDesc);
+            }
+            else if (option == SYNC)
+                sync = true;
+        }
+
+        cmdArg = new VisorSnapshotRestoreTaskArg(snpName, sync, restoreAction, grpNames);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void printUsage(Logger log) {
+        Map<String, String> params = generalUsageOptions();
+        Map<String, String> startParams = new LinkedHashMap<String, String>(params) {{
+            put(GROUPS.optionName(), GROUPS.description());
+            put(SYNC.optionName(), SYNC.description());
+        }};
+
+        usage(log, "Restore snapshot:", SNAPSHOT, startParams, RESTORE.toString(), SNAPSHOT_NAME_ARG, "--start",
+            optional(GROUPS.argName(), GROUPS.optionName()), optional(SYNC.argName()));
+        usage(log, "Snapshot restore operation status:", SNAPSHOT, params, RESTORE.toString(), SNAPSHOT_NAME_ARG, "--status");
+        usage(log, "Cancel snapshot restore operation:", SNAPSHOT, params, RESTORE.toString(), SNAPSHOT_NAME_ARG, "--cancel");
+    }
+
+    /** {@inheritDoc} */
+    @Override public String confirmationPrompt() {
+        VisorSnapshotRestoreTaskArg arg = (VisorSnapshotRestoreTaskArg)cmdArg;
+
+        return arg.jobAction() != VisorSnapshotRestoreTaskAction.START || arg.groupNames() != null ? null :
+            "Warning: command will restore ALL USER-CREATED CACHE GROUPS from the snapshot " + arg.snapshotName() + '.';
+    }
+
+    /**
+     * @param argIter Argument iterator.
+     * @return Snapshot restore operation management action.
+     */
+    private VisorSnapshotRestoreTaskAction parseAction(CommandArgIterator argIter) {
+        Collection<String> cmdNames =
+            F.viewReadOnly(F.asList(VisorSnapshotRestoreTaskAction.values()), v -> "--" + v.toString().toLowerCase());
+
+        String actionErrMsg = "One of " + cmdNames + " is expected.";
+
+        String action = argIter.nextArg(actionErrMsg);
+
+        for (VisorSnapshotRestoreTaskAction val : VisorSnapshotRestoreTaskAction.values()) {
+            if (action.toLowerCase().equals("--" + val.name().toLowerCase()))
+                return val;
+        }
+
+        throw new IllegalArgumentException("Invalid argument: " + action + ". " + actionErrMsg);
+    }
+}
diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotRestoreCommandOption.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotRestoreCommandOption.java
new file mode 100644
index 0000000..b558a6b
--- /dev/null
+++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotRestoreCommandOption.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline.snapshot;
+
+import org.apache.ignite.internal.commandline.argument.CommandArg;
+
+/**
+ * Snapshot restore command options.
+ */
+public enum SnapshotRestoreCommandOption implements CommandArg {
+    /** Cache group names. */
+    GROUPS("--groups", "group1,...groupN", "Cache group names."),
+
+    /** Synchronous execution flag. */
+    SYNC(SnapshotCreateCommandOption.SYNC.argName(), SnapshotCreateCommandOption.SYNC.optionName(),
+        SnapshotCreateCommandOption.SYNC.description());
+
+    /** Argument name. */
+    private final String argName;
+
+    /** Option name. */
+    private final String optionName;
+
+    /** Option description. */
+    private final String desc;
+
+    /**
+     * @param argName Argument name.
+     * @param optionName Option name.
+     * @param desc Option description.
+     */
+    SnapshotRestoreCommandOption(String argName, String optionName, String desc) {
+        this.argName = argName;
+        this.optionName = optionName;
+        this.desc = desc;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String argName() {
+        return argName;
+    }
+
+    /** @return Option name. */
+    public String optionName() {
+        return optionName;
+    }
+
+    /** @return Option description. */
+    public String description() {
+        return desc;
+    }
+
+    /** @return Argument name. */
+    @Override public String toString() {
+        return argName();
+    }
+}
diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotSubcommand.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotSubcommand.java
index 55526a2..44f9e7d 100644
--- a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotSubcommand.java
+++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotSubcommand.java
@@ -17,64 +17,86 @@
 
 package org.apache.ignite.internal.commandline.snapshot;
 
-import org.apache.ignite.internal.visor.snapshot.VisorSnapshotCancelTask;
-import org.apache.ignite.internal.visor.snapshot.VisorSnapshotCheckTask;
-import org.apache.ignite.internal.visor.snapshot.VisorSnapshotCreateTask;
-import org.apache.ignite.internal.visor.snapshot.VisorSnapshotRestoreTask;
-import org.jetbrains.annotations.Nullable;
+import java.util.Map;
+import java.util.logging.Logger;
+import org.apache.ignite.internal.client.GridClient;
+import org.apache.ignite.internal.client.GridClientConfiguration;
+import org.apache.ignite.internal.commandline.AbstractCommand;
+import org.apache.ignite.internal.commandline.Command;
+import org.apache.ignite.internal.commandline.CommandArgIterator;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.visor.snapshot.VisorSnapshotTaskResult;
+
+import static org.apache.ignite.internal.commandline.TaskExecutor.executeTaskByNameOnNode;
 
 /**
- * Set of snapshot sub-commands.
- *
- * @see SnapshotCommand
+ * Snapshot sub-command base.
  */
-public enum SnapshotSubcommand {
-    /** Sub-command to create a cluster snapshot. */
-    CREATE("create", VisorSnapshotCreateTask.class.getName()),
-
-    /** Sub-command to cancel running snapshot. */
-    CANCEL("cancel", VisorSnapshotCancelTask.class.getName()),
-
-    /** Sub-command to check snapshot. */
-    CHECK("check", VisorSnapshotCheckTask.class.getName()),
+public abstract class SnapshotSubcommand extends AbstractCommand<Object> {
+    /** Snapshot name argument. */
+    protected static final String SNAPSHOT_NAME_ARG = "snapshot_name";
 
-    /** Sub-command to restore snapshot. */
-    RESTORE("restore", VisorSnapshotRestoreTask.class.getName());
+    /** Command argument. */
+    protected Object cmdArg;
 
     /** Sub-command name. */
     private final String name;
 
-    /** Task class name to execute. */
-    private final String taskName;
+    /** Snapshot visor task class. */
+    private final Class<?> taskCls;
 
-    /** @param name Snapshot sub-command name. */
-    SnapshotSubcommand(String name, String taskName) {
+    /**
+     * @param name Sub-command name.
+     * @param taskCls Visor compute task class.
+     */
+    protected SnapshotSubcommand(String name, Class<?> taskCls) {
         this.name = name;
-        this.taskName = taskName;
+        this.taskCls = taskCls;
     }
 
-    /**
-     * @param text Command text (case insensitive).
-     * @return Command for the text. {@code Null} if there is no such command.
-     */
-    @Nullable public static SnapshotSubcommand of(String text) {
-        for (SnapshotSubcommand cmd : values()) {
-            if (cmd.name.equalsIgnoreCase(text))
-                return cmd;
+    /** {@inheritDoc} */
+    @Override public Object execute(GridClientConfiguration clientCfg, Logger log) throws Exception {
+        try (GridClient client = Command.startClient(clientCfg)) {
+            VisorSnapshotTaskResult taskRes = executeTaskByNameOnNode(client, taskCls.getName(), arg(), null, clientCfg);
+
+            printResult(taskRes.result(), log);
+
+            return taskRes.result();
         }
+    }
 
-        throw new IllegalArgumentException("Expected correct action: " + text);
+    /** {@inheritDoc} */
+    @Override public Object arg() {
+        return cmdArg;
     }
 
-    /**
-     * @return Task class name to execute.
-     */
-    public String taskName() {
-        return taskName;
+    /** {@inheritDoc} */
+    @Override public void parseArguments(CommandArgIterator argIter) {
+        cmdArg = argIter.nextArg("Expected snapshot name.");
+
+        if (argIter.hasNextSubArg())
+            throw new IllegalArgumentException("Unexpected argument: " + argIter.peekNextArg() + '.');
     }
 
     /** {@inheritDoc} */
-    @Override public String toString() {
+    @Override public String name() {
         return name;
     }
+
+    /**
+     * @return General usage options.
+     */
+    protected Map<String, String> generalUsageOptions() {
+        return F.asMap(SNAPSHOT_NAME_ARG, "Snapshot name.");
+    }
+
+    /**
+     * Prints result of command execution.
+     *
+     * @param res Task result.
+     * @param log Logger.
+     */
+    protected void printResult(Object res, Logger log) {
+        log.info(String.valueOf(res));
+    }
 }
diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotSubcommands.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotSubcommands.java
new file mode 100644
index 0000000..c26b5ad
--- /dev/null
+++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/snapshot/SnapshotSubcommands.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline.snapshot;
+
+import org.apache.ignite.internal.util.typedef.F;
+
+/**
+ * Set of snapshot sub-commands.
+ *
+ * @see SnapshotCommand
+ * @see SnapshotSubcommand
+ */
+public enum SnapshotSubcommands {
+    /** Sub-command to create a cluster snapshot. */
+    CREATE(new SnapshotCreateCommand()),
+
+    /** Sub-command to cancel running snapshot. */
+    CANCEL(new SnapshotCancelCommand()),
+
+    /** Sub-command to check snapshot. */
+    CHECK(new SnapshotCheckCommand()),
+
+    /** Sub-command to restore snapshot. */
+    RESTORE(new SnapshotRestoreCommand());
+
+    /** Sub-command. */
+    private final SnapshotSubcommand cmd;
+
+    /** @param cmd Sub-command. */
+    SnapshotSubcommands(SnapshotSubcommand cmd) {
+        this.cmd = cmd;
+    }
+
+    /**
+     * @param name Command name (case insensitive).
+     * @return Command for the specified name.
+     */
+    public static SnapshotSubcommands of(String name) {
+        SnapshotSubcommands[] cmds = values();
+
+        for (SnapshotSubcommands cmd : cmds) {
+            if (cmd.subCommand().name().equalsIgnoreCase(name))
+                return cmd;
+        }
+
+        throw new IllegalArgumentException(
+            "Invalid argument: " + name + ". One of " + F.asList(cmds) + " is expected.");
+    }
+
+    /**
+     * @return Sub-command.
+     */
+    public SnapshotSubcommand subCommand() {
+        return cmd;
+    }
+
+    /** @return Sub-command name. */
+    @Override public String toString() {
+        return cmd.name();
+    }
+}
diff --git a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java
index 809d78a..b3ed65a 100644
--- a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java
+++ b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerTest.java
@@ -45,6 +45,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.LongAdder;
+import java.util.function.BooleanSupplier;
 import java.util.function.Function;
 import java.util.function.UnaryOperator;
 import java.util.regex.Matcher;
@@ -107,6 +108,7 @@ import org.apache.ignite.internal.processors.cluster.GridClusterStateProcessor;
 import org.apache.ignite.internal.util.future.IgniteFinishedFutureImpl;
 import org.apache.ignite.internal.util.lang.GridAbsPredicate;
 import org.apache.ignite.internal.util.lang.GridFunc;
+import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.G;
 import org.apache.ignite.internal.util.typedef.X;
 import org.apache.ignite.internal.util.typedef.internal.CU;
@@ -2995,6 +2997,20 @@ public class GridCommandHandlerTest extends GridCommandHandlerClusterPerMethodAb
     /** @throws Exception If failed. */
     @Test
     public void testClusterSnapshotCreate() throws Exception {
+        doClusterSnapshotCreate(false);
+    }
+
+    /** @throws Exception If failed. */
+    @Test
+    public void testClusterSnapshotCreateSynchronously() throws Exception {
+        doClusterSnapshotCreate(true);
+    }
+
+    /**
+     * @param syncMode Execute operation synchrnously.
+     * @throws Exception If failed.
+     */
+    private void doClusterSnapshotCreate(boolean syncMode) throws Exception {
         int keysCnt = 100;
         String snpName = "snapshot_02052020";
 
@@ -3003,15 +3019,33 @@ public class GridCommandHandlerTest extends GridCommandHandlerClusterPerMethodAb
 
         createCacheAndPreload(ig, keysCnt);
 
+        injectTestSystemOut();
+
         CommandHandler h = new CommandHandler();
 
-        assertEquals(EXIT_CODE_OK, execute(h, "--snapshot", "create", snpName));
+        // Invalid command syntax check.
+        assertEquals(EXIT_CODE_INVALID_ARGUMENTS, execute(h, "--snapshot", "create", snpName, "blah"));
+        assertContains(log, testOut.toString(), "Invalid argument: blah. Possible options: --sync.");
+
+        assertEquals(EXIT_CODE_INVALID_ARGUMENTS, execute(h, "--snapshot", "create", snpName, "--sync", "blah"));
+        assertContains(log, testOut.toString(), "Invalid argument: blah.");
+
+        List<String> args = new ArrayList<>(F.asList("--snapshot", "create", snpName));
+
+        if (syncMode)
+            args.add("--sync");
+
+        assertEquals(EXIT_CODE_OK, execute(h, args));
+
+        LongMetric opEndTimeMetric = ig.context().metric().registry(SNAPSHOT_METRICS).findMetric("LastSnapshotEndTime");
+        BooleanSupplier endTimeMetricPredicate = () -> opEndTimeMetric.value() > 0;
 
-        assertTrue("Waiting for snapshot operation end failed.",
-            waitForCondition(() ->
-                    ig.context().metric().registry(SNAPSHOT_METRICS)
-                        .<LongMetric>findMetric("LastSnapshotEndTime").value() > 0,
-                getTestTimeout()));
+        if (syncMode)
+            assertTrue(endTimeMetricPredicate.getAsBoolean());
+        else {
+            assertTrue("Waiting for snapshot operation end failed.",
+                waitForCondition(endTimeMetricPredicate::getAsBoolean, getTestTimeout()));
+        }
 
         assertContains(log, (String)h.getLastOperationResult(), snpName);
 
@@ -3084,7 +3118,71 @@ public class GridCommandHandlerTest extends GridCommandHandlerClusterPerMethodAb
 
     /** @throws Exception If fails. */
     @Test
+    public void testSnapshotRestoreSynchronously() throws Exception {
+        String snpName = "snapshot_02052020";
+        int keysCnt = 100;
+
+        IgniteEx ig = startGrids(2);
+
+        ig.cluster().state(ACTIVE);
+
+        injectTestSystemOut();
+
+        String cacheName = "test-cache";
+
+        createCacheAndPreload(ig, cacheName, keysCnt, 32, null);
+
+        ig.snapshot().createSnapshot(snpName).get(getTestTimeout());
+
+        CommandHandler h = new CommandHandler();
+
+        autoConfirmation = false;
+
+        // Invalid command syntax checks.
+        assertEquals(EXIT_CODE_INVALID_ARGUMENTS, execute(h, "--snapshot", "restore", snpName));
+        assertContains(log, testOut.toString(), "One of [--start, --cancel, --status] is expected.");
+
+        assertEquals(EXIT_CODE_INVALID_ARGUMENTS, execute(h, "--snapshot", "restore", snpName, "--cancel", "--sync"));
+        assertContains(log, testOut.toString(), "Invalid argument: --sync.");
+
+        assertEquals(EXIT_CODE_INVALID_ARGUMENTS, execute(h, "--snapshot", "restore", snpName, "blah"));
+        assertContains(log, testOut.toString(), "Invalid argument: blah. One of [--start, --cancel, --status] is expected.");
+
+        assertEquals(EXIT_CODE_INVALID_ARGUMENTS, execute(h, "--snapshot", "restore", snpName, "--status", "--sync"));
+        assertContains(log, testOut.toString(), "Invalid argument: --sync. Action \"--status\" does not support specified option.");
+
+        assertEquals(EXIT_CODE_INVALID_ARGUMENTS, execute(h, "--snapshot", "restore", snpName, "--sync", "--start"));
+        assertContains(log, testOut.toString(), "Invalid argument: --sync.");
+
+        assertEquals(EXIT_CODE_INVALID_ARGUMENTS, execute(h, "--snapshot", "restore", snpName, "--start", "blah"));
+        assertContains(log, testOut.toString(), "Invalid argument: blah. Possible options: --groups, --sync.");
+
+        autoConfirmation = true;
+
+        // Cache exists.
+        assertEquals(EXIT_CODE_UNEXPECTED_ERROR, execute(h, "--snapshot", "restore", snpName, "--start", "--sync"));
+        assertContains(log, testOut.toString(), "Unable to restore cache group - directory is not empty. " +
+            "Cache group should be destroyed manually before perform restore operation [group=" + cacheName);
+
+        ig.cache(cacheName).destroy();
+        awaitPartitionMapExchange();
+
+        assertEquals(EXIT_CODE_OK, execute(h, "--snapshot", "restore", snpName, "--start", "--sync"));
+        assertContains(log, testOut.toString(), "Snapshot cache group restore operation completed successfully");
+
+        IgniteCache<Object, Object> cache = ig.cache(cacheName);
+
+        assertNotNull(cache);
+
+        for (int i = 0; i < keysCnt; i++)
+            assertEquals("key=" + i, i, cache.get(i));
+    }
+
+    /** @throws Exception If fails. */
+    @Test
     public void testSnapshotRestore() throws Exception {
+        autoConfirmation = false;
+
         int keysCnt = 100;
         String snpName = "snapshot_02052020";
         String cacheName1 = "cache1";
@@ -3096,6 +3194,7 @@ public class GridCommandHandlerTest extends GridCommandHandlerClusterPerMethodAb
         ig.cluster().state(ACTIVE);
 
         injectTestSystemOut();
+        injectTestSystemIn(CONFIRM_MSG);
 
         createCacheAndPreload(ig, cacheName1, keysCnt, 32, null);
         createCacheAndPreload(ig, cacheName2, keysCnt, 32, null);
@@ -3119,8 +3218,11 @@ public class GridCommandHandlerTest extends GridCommandHandlerClusterPerMethodAb
 
         CommandHandler h = new CommandHandler();
 
+        assertEquals(EXIT_CODE_INVALID_ARGUMENTS, execute(h, "--snapshot", "restore", snpName, "--start", cacheName1));
+        assertContains(log, testOut.toString(), "Invalid argument: " + cacheName1 + ". Possible options: --groups, --sync.");
+
         // Restore single cache group.
-        assertEquals(EXIT_CODE_OK, execute(h, "--snapshot", "restore", snpName, "--start", cacheName1));
+        assertEquals(EXIT_CODE_OK, execute(h, "--snapshot", "restore", snpName, "--start", "--groups", cacheName1));
         assertContains(log, testOut.toString(),
             "Snapshot cache group restore operation started [snapshot=" + snpName + ", group(s)=" + cacheName1 + ']');
 
@@ -3141,8 +3243,10 @@ public class GridCommandHandlerTest extends GridCommandHandlerClusterPerMethodAb
         assertNull(ig.cache(cacheName2));
         assertNull(ig.cache(cacheName3));
 
+        String cacheNames = cacheName1 + ',' + cacheName2;
+
         // Restore two (of three) groups of caches.
-        assertEquals(EXIT_CODE_OK, execute(h, "--snapshot", "restore", snpName, "--start", cacheName1 + ',' + cacheName2));
+        assertEquals(EXIT_CODE_OK, execute(h, "--snapshot", "restore", snpName, "--start", "--groups", cacheNames));
         assertContains(log, testOut.toString(),
             "Snapshot cache group restore operation started [snapshot=" + snpName + ", group(s)=");
 
@@ -3171,8 +3275,9 @@ public class GridCommandHandlerTest extends GridCommandHandlerClusterPerMethodAb
 
         // Restore all public cache groups.
         assertEquals(EXIT_CODE_OK, execute(h, "--snapshot", "restore", snpName, "--start"));
-        assertContains(log, testOut.toString(),
-            "Snapshot cache group restore operation started [snapshot=" + snpName + ']');
+        String out = testOut.toString();
+        assertContains(log, out, "Warning: command will restore ALL USER-CREATED CACHE GROUPS from the snapshot");
+        assertContains(log, out, "Snapshot cache group restore operation started [snapshot=" + snpName + ']');
 
         waitForCondition(() -> ig.cache(cacheName1) != null, getTestTimeout());
         waitForCondition(() -> ig.cache(cacheName2) != null, getTestTimeout());
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/SnapshotRestoreProcess.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/SnapshotRestoreProcess.java
index b54e372..98d70fb 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/SnapshotRestoreProcess.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/SnapshotRestoreProcess.java
@@ -680,7 +680,8 @@ public class SnapshotRestoreProcess {
                     }
 
                     if (cacheDir.list().length > 0) {
-                        throw new IgniteCheckedException("Unable to restore cache group, directory is not empty " +
+                        throw new IgniteCheckedException("Unable to restore cache group - directory is not empty. " +
+                            "Cache group should be destroyed manually before perform restore operation " +
                             "[group=" + grpName + ", dir=" + cacheDir + ']');
                     }
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotCancelTask.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotCancelTask.java
index 217ce66..3903215 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotCancelTask.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotCancelTask.java
@@ -22,13 +22,12 @@ import org.apache.ignite.IgniteSnapshot;
 import org.apache.ignite.internal.processors.cache.persistence.snapshot.SnapshotMXBeanImpl;
 import org.apache.ignite.internal.processors.task.GridInternal;
 import org.apache.ignite.internal.visor.VisorJob;
-import org.apache.ignite.internal.visor.VisorOneNodeTask;
 
 /**
  * @see IgniteSnapshot#cancelSnapshot(String)
  */
 @GridInternal
-public class VisorSnapshotCancelTask extends VisorOneNodeTask<String, String> {
+public class VisorSnapshotCancelTask extends VisorSnapshotOneNodeTask<String, String> {
     /** Serial version uid. */
     private static final long serialVersionUID = 0L;
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotCheckTask.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotCheckTask.java
index 7b0615d2..5bd01d0 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotCheckTask.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotCheckTask.java
@@ -23,13 +23,12 @@ import org.apache.ignite.internal.processors.cache.verify.IdleVerifyResultV2;
 import org.apache.ignite.internal.processors.task.GridInternal;
 import org.apache.ignite.internal.util.future.IgniteFutureImpl;
 import org.apache.ignite.internal.visor.VisorJob;
-import org.apache.ignite.internal.visor.VisorOneNodeTask;
 
 /**
  * @see IgniteSnapshotManager#checkSnapshot(String)
  */
 @GridInternal
-public class VisorSnapshotCheckTask extends VisorOneNodeTask<String, IdleVerifyResultV2> {
+public class VisorSnapshotCheckTask extends VisorSnapshotOneNodeTask<String, IdleVerifyResultV2> {
     /** Serial version uid. */
     private static final long serialVersionUID = 0L;
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotCreateTask.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotCreateTask.java
index d86ec1b..45232bc 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotCreateTask.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotCreateTask.java
@@ -19,42 +19,45 @@ package org.apache.ignite.internal.visor.snapshot;
 
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.IgniteSnapshot;
-import org.apache.ignite.internal.processors.cache.persistence.snapshot.SnapshotMXBeanImpl;
 import org.apache.ignite.internal.processors.task.GridInternal;
 import org.apache.ignite.internal.visor.VisorJob;
-import org.apache.ignite.internal.visor.VisorOneNodeTask;
+import org.apache.ignite.lang.IgniteFuture;
 
 /**
  * @see IgniteSnapshot#createSnapshot(String)
  */
 @GridInternal
-public class VisorSnapshotCreateTask extends VisorOneNodeTask<String, String> {
+public class VisorSnapshotCreateTask extends VisorSnapshotOneNodeTask<VisorSnapshotCreateTaskArg, String> {
     /** Serial version uid. */
     private static final long serialVersionUID = 0L;
 
     /** {@inheritDoc} */
-    @Override protected VisorJob<String, String> job(String arg) {
+    @Override protected VisorJob<VisorSnapshotCreateTaskArg, String> job(VisorSnapshotCreateTaskArg arg) {
         return new VisorSnapshotCreateJob(arg, debug);
     }
 
     /** */
-    private static class VisorSnapshotCreateJob extends VisorJob<String, String> {
+    private static class VisorSnapshotCreateJob extends VisorJob<VisorSnapshotCreateTaskArg, String> {
         /** Serial version uid. */
         private static final long serialVersionUID = 0L;
 
         /**
-         * @param name Snapshot name.
+         * @param arg Snapshot create task argument.
          * @param debug Flag indicating whether debug information should be printed into node log.
          */
-        protected VisorSnapshotCreateJob(String name, boolean debug) {
-            super(name, debug);
+        protected VisorSnapshotCreateJob(VisorSnapshotCreateTaskArg arg, boolean debug) {
+            super(arg, debug);
         }
 
         /** {@inheritDoc} */
-        @Override protected String run(String name) throws IgniteException {
-            new SnapshotMXBeanImpl(ignite.context()).createSnapshot(name);
+        @Override protected String run(VisorSnapshotCreateTaskArg arg) throws IgniteException {
+            IgniteFuture<Void> fut = ignite.snapshot().createSnapshot(arg.snapshotName());
 
-            return "Snapshot operation started: " + name;
+            if (arg.sync() || fut.isDone())
+                fut.get();
+
+            return "Snapshot operation " +
+                (arg.sync() ? "completed successfully" : "started") + ": " + arg.snapshotName();
         }
     }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotRestoreTaskArg.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotCreateTaskArg.java
similarity index 60%
copy from modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotRestoreTaskArg.java
copy to modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotCreateTaskArg.java
index 0f5bc10..0485525 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotRestoreTaskArg.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotCreateTaskArg.java
@@ -20,46 +20,35 @@ package org.apache.ignite.internal.visor.snapshot;
 import java.io.IOException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
-import java.util.Collection;
 import org.apache.ignite.internal.dto.IgniteDataTransferObject;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.U;
-import org.jetbrains.annotations.Nullable;
 
 /**
- * Argument for the task to manage snapshot restore operation.
+ * Argument for the task to create snapshot.
  */
-public class VisorSnapshotRestoreTaskArg extends IgniteDataTransferObject {
+public class VisorSnapshotCreateTaskArg extends IgniteDataTransferObject {
     /** Serial version uid. */
     private static final long serialVersionUID = 0L;
 
     /** Snapshot name. */
     private String snpName;
 
-    /** Cache group names. */
-    private Collection<String> grpNames;
-
-    /** Snapshot restore operation management action. */
-    private VisorSnapshotRestoreTaskAction action;
+    /** Synchronous execution flag. */
+    private boolean sync;
 
     /** Default constructor. */
-    public VisorSnapshotRestoreTaskArg() {
+    public VisorSnapshotCreateTaskArg() {
         // No-op.
     }
 
     /**
-     * @param action Snapshot restore operation management action.
      * @param snpName Snapshot name.
-     * @param grpNames Cache group names.
+     * @param sync Synchronous execution flag.
      */
-    public VisorSnapshotRestoreTaskArg(
-        VisorSnapshotRestoreTaskAction action,
-        String snpName,
-        @Nullable Collection<String> grpNames
-    ) {
+    public VisorSnapshotCreateTaskArg(String snpName, boolean sync) {
         this.snpName = snpName;
-        this.grpNames = grpNames;
-        this.action = action;
+        this.sync = sync;
     }
 
     /** @return Snapshot name. */
@@ -67,32 +56,25 @@ public class VisorSnapshotRestoreTaskArg extends IgniteDataTransferObject {
         return snpName;
     }
 
-    /** @return Cache group names. */
-    public Collection<String> groupNames() {
-        return grpNames;
-    }
-
-    /** @return Snapshot restore operation management action. */
-    public VisorSnapshotRestoreTaskAction jobAction() {
-        return action;
+    /** @return Synchronous execution flag. */
+    public boolean sync() {
+        return sync;
     }
 
     /** {@inheritDoc} */
     @Override protected void writeExternalData(ObjectOutput out) throws IOException {
-        U.writeEnum(out, action);
         U.writeString(out, snpName);
-        U.writeCollection(out, grpNames);
+        out.writeBoolean(sync);
     }
 
     /** {@inheritDoc} */
     @Override protected void readExternalData(byte ver, ObjectInput in) throws IOException, ClassNotFoundException {
-        action = U.readEnum(in, VisorSnapshotRestoreTaskAction.class);
         snpName = U.readString(in);
-        grpNames = U.readCollection(in);
+        sync = in.readBoolean();
     }
 
     /** {@inheritDoc} */
     @Override public String toString() {
-        return S.toString(VisorSnapshotRestoreTaskArg.class, this);
+        return S.toString(VisorSnapshotCreateTaskArg.class, this);
     }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotOneNodeTask.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotOneNodeTask.java
new file mode 100644
index 0000000..fd2438b
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotOneNodeTask.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.visor.snapshot;
+
+import java.util.List;
+import org.apache.ignite.compute.ComputeJobResult;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.visor.VisorMultiNodeTask;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Base class for single node visor snapshot task.
+ */
+public abstract class VisorSnapshotOneNodeTask<A, R> extends VisorMultiNodeTask<A, VisorSnapshotTaskResult, R> {
+    /** {@inheritDoc} */
+    @Nullable @Override protected VisorSnapshotTaskResult reduce0(List<ComputeJobResult> results) {
+        assert results.size() == 1 : results.size();
+
+        ComputeJobResult res = F.first(results);
+
+        return new VisorSnapshotTaskResult(res.getData(), res.getException());
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotRestoreTask.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotRestoreTask.java
index 83c7497..56d35b5 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotRestoreTask.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotRestoreTask.java
@@ -21,14 +21,13 @@ import org.apache.ignite.IgniteException;
 import org.apache.ignite.internal.processors.task.GridInternal;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.visor.VisorJob;
-import org.apache.ignite.internal.visor.VisorOneNodeTask;
 import org.apache.ignite.lang.IgniteFuture;
 
 /**
  * Visor snapshot restore task.
  */
 @GridInternal
-public class VisorSnapshotRestoreTask extends VisorOneNodeTask<VisorSnapshotRestoreTaskArg, String> {
+public class VisorSnapshotRestoreTask extends VisorSnapshotOneNodeTask<VisorSnapshotRestoreTaskArg, String> {
     /** Serial version uid. */
     private static final long serialVersionUID = 0L;
 
@@ -67,11 +66,13 @@ public class VisorSnapshotRestoreTask extends VisorOneNodeTask<VisorSnapshotRest
             IgniteFuture<Void> fut =
                 ignite.context().cache().context().snapshotMgr().restoreSnapshot(arg.snapshotName(), arg.groupNames());
 
-            if (fut.isDone())
+            if (arg.sync() || fut.isDone())
                 fut.get();
+            
+            String msgSuff = arg.sync() ? "completed successfully" : "started";
+            String msgGrps = arg.groupNames() == null ? "" : ", group(s)=" + F.concat(arg.groupNames(), ",");
 
-            return "Snapshot cache group restore operation started [snapshot=" + arg.snapshotName() +
-                (arg.groupNames() == null ? "" : ", group(s)=" + F.concat(arg.groupNames(), ",")) + ']';
+            return "Snapshot cache group restore operation " + msgSuff + " [snapshot=" + arg.snapshotName() + msgGrps + ']';
         }
     }
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotRestoreTaskAction.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotRestoreTaskAction.java
index 4ca3e14..ad10155 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotRestoreTaskAction.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotRestoreTaskAction.java
@@ -27,22 +27,4 @@ public enum VisorSnapshotRestoreTaskAction {
 
     /** Status of the snapshot restore operation. */
     STATUS;
-
-    /**
-     * @param cmdArg Command line argument.
-     * @return Snapshot restore operation management action.
-     */
-    public static VisorSnapshotRestoreTaskAction fromCmdArg(String cmdArg) {
-        for (VisorSnapshotRestoreTaskAction val : values()) {
-            if (cmdArg.equalsIgnoreCase(val.cmdName()))
-                return val;
-        }
-
-        throw new IllegalArgumentException("Unexpected command line argument \"" + cmdArg + "\"");
-    }
-
-    /** @return Command line argument name. */
-    public String cmdName() {
-        return "--" + name().toLowerCase();
-    }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotRestoreTaskArg.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotRestoreTaskArg.java
index 0f5bc10..efad1bf 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotRestoreTaskArg.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotRestoreTaskArg.java
@@ -21,7 +21,6 @@ import java.io.IOException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
 import java.util.Collection;
-import org.apache.ignite.internal.dto.IgniteDataTransferObject;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.jetbrains.annotations.Nullable;
@@ -29,13 +28,10 @@ import org.jetbrains.annotations.Nullable;
 /**
  * Argument for the task to manage snapshot restore operation.
  */
-public class VisorSnapshotRestoreTaskArg extends IgniteDataTransferObject {
+public class VisorSnapshotRestoreTaskArg extends VisorSnapshotCreateTaskArg {
     /** Serial version uid. */
     private static final long serialVersionUID = 0L;
 
-    /** Snapshot name. */
-    private String snpName;
-
     /** Cache group names. */
     private Collection<String> grpNames;
 
@@ -48,23 +44,21 @@ public class VisorSnapshotRestoreTaskArg extends IgniteDataTransferObject {
     }
 
     /**
-     * @param action Snapshot restore operation management action.
      * @param snpName Snapshot name.
+     * @param sync Synchronous execution flag.
+     * @param action Snapshot restore operation management action.
      * @param grpNames Cache group names.
      */
     public VisorSnapshotRestoreTaskArg(
-        VisorSnapshotRestoreTaskAction action,
         String snpName,
+        boolean sync,
+        VisorSnapshotRestoreTaskAction action,
         @Nullable Collection<String> grpNames
     ) {
-        this.snpName = snpName;
-        this.grpNames = grpNames;
-        this.action = action;
-    }
+        super(snpName, sync);
 
-    /** @return Snapshot name. */
-    public String snapshotName() {
-        return snpName;
+        this.action = action;
+        this.grpNames = grpNames;
     }
 
     /** @return Cache group names. */
@@ -77,17 +71,18 @@ public class VisorSnapshotRestoreTaskArg extends IgniteDataTransferObject {
         return action;
     }
 
+
     /** {@inheritDoc} */
     @Override protected void writeExternalData(ObjectOutput out) throws IOException {
+        super.writeExternalData(out);
         U.writeEnum(out, action);
-        U.writeString(out, snpName);
         U.writeCollection(out, grpNames);
     }
 
     /** {@inheritDoc} */
     @Override protected void readExternalData(byte ver, ObjectInput in) throws IOException, ClassNotFoundException {
+        super.readExternalData(ver, in);
         action = U.readEnum(in, VisorSnapshotRestoreTaskAction.class);
-        snpName = U.readString(in);
         grpNames = U.readCollection(in);
     }
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotTaskResult.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotTaskResult.java
new file mode 100644
index 0000000..aa0237c
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/snapshot/VisorSnapshotTaskResult.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.visor.snapshot;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import org.apache.ignite.internal.dto.IgniteDataTransferObject;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Snapshot task result wrapper.
+ */
+public class VisorSnapshotTaskResult extends IgniteDataTransferObject {
+    /** Serial version UID. */
+    private static final long serialVersionUID = 0L;
+
+    /** Task result. */
+    private @Nullable Object res;
+
+    /** Error. */
+    private @Nullable Exception err;
+
+    /** Default constructor. */
+    public VisorSnapshotTaskResult() {
+        // No-op.
+    }
+
+    /**
+     * @param res Task result.
+     * @param err Error.
+     */
+    public VisorSnapshotTaskResult(@Nullable Object res, @Nullable Exception err) {
+        this.err = err;
+        this.res = res;
+    }
+
+    /**
+     * @return Task result.
+     * @throws Exception if the job was completed with an error.
+     */
+    public @Nullable Object result() throws Exception {
+        if (err != null)
+            throw err;
+
+        return res;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void writeExternalData(ObjectOutput out) throws IOException {
+        out.writeObject(res);
+        out.writeObject(err);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void readExternalData(byte ver, ObjectInput in) throws IOException, ClassNotFoundException {
+        res = in.readObject();
+        err = (Exception)in.readObject();
+    }
+}
diff --git a/modules/core/src/main/resources/META-INF/classnames.properties b/modules/core/src/main/resources/META-INF/classnames.properties
index efec71d..3def5d9 100644
--- a/modules/core/src/main/resources/META-INF/classnames.properties
+++ b/modules/core/src/main/resources/META-INF/classnames.properties
@@ -2276,10 +2276,12 @@ org.apache.ignite.internal.visor.snapshot.VisorSnapshotCreateTask
 org.apache.ignite.internal.visor.snapshot.VisorSnapshotCreateTask$VisorSnapshotCreateJob
 org.apache.ignite.internal.visor.snapshot.VisorSnapshotCancelTask
 org.apache.ignite.internal.visor.snapshot.VisorSnapshotCancelTask$VisorSnapshotCancelJob
+org.apache.ignite.internal.visor.snapshot.VisorSnapshotTaskResult
 org.apache.ignite.internal.visor.snapshot.VisorSnapshotRestoreTask
 org.apache.ignite.internal.visor.snapshot.VisorSnapshotRestoreTask$VisorSnapshotStartRestoreJob
 org.apache.ignite.internal.visor.snapshot.VisorSnapshotRestoreTask$VisorSnapshotRestoreCancelJob
 org.apache.ignite.internal.visor.snapshot.VisorSnapshotRestoreTask$VisorSnapshotRestoreStatusJob
+org.apache.ignite.internal.visor.snapshot.VisorSnapshotCreateTaskArg
 org.apache.ignite.internal.visor.snapshot.VisorSnapshotRestoreTaskArg
 org.apache.ignite.internal.visor.snapshot.VisorSnapshotRestoreTaskAction
 org.apache.ignite.internal.visor.tx.FetchNearXidVersionTask
diff --git a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output
index a5e628b..b70f295 100644
--- a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output
+++ b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output
@@ -140,10 +140,11 @@ This utility can do the following commands:
       snapshot_name  - Snapshot name.
 
   Create cluster snapshot:
-    control.(sh|bat) --snapshot create snapshot_name
+    control.(sh|bat) --snapshot create snapshot_name [--sync]
 
     Parameters:
       snapshot_name  - Snapshot name.
+      sync           - Run the operation synchronously, the command will wait for the entire operation to complete. Otherwise, it will be performed in the background, and the command will immediately return control.
 
   Cancel running snapshot:
     control.(sh|bat) --snapshot cancel snapshot_name
@@ -158,11 +159,12 @@ This utility can do the following commands:
       snapshot_name  - Snapshot name.
 
   Restore snapshot:
-    control.(sh|bat) --snapshot restore snapshot_name --start [group1,...groupN]
+    control.(sh|bat) --snapshot restore snapshot_name --start [--groups group1,...groupN] [--sync]
 
     Parameters:
       snapshot_name     - Snapshot name.
       group1,...groupN  - Cache group names.
+      sync              - Run the operation synchronously, the command will wait for the entire operation to complete. Otherwise, it will be performed in the background, and the command will immediately return control.
 
   Snapshot restore operation status:
     control.(sh|bat) --snapshot restore snapshot_name --status
diff --git a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output
index a5e628b..b70f295 100644
--- a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output
+++ b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output
@@ -140,10 +140,11 @@ This utility can do the following commands:
       snapshot_name  - Snapshot name.
 
   Create cluster snapshot:
-    control.(sh|bat) --snapshot create snapshot_name
+    control.(sh|bat) --snapshot create snapshot_name [--sync]
 
     Parameters:
       snapshot_name  - Snapshot name.
+      sync           - Run the operation synchronously, the command will wait for the entire operation to complete. Otherwise, it will be performed in the background, and the command will immediately return control.
 
   Cancel running snapshot:
     control.(sh|bat) --snapshot cancel snapshot_name
@@ -158,11 +159,12 @@ This utility can do the following commands:
       snapshot_name  - Snapshot name.
 
   Restore snapshot:
-    control.(sh|bat) --snapshot restore snapshot_name --start [group1,...groupN]
+    control.(sh|bat) --snapshot restore snapshot_name --start [--groups group1,...groupN] [--sync]
 
     Parameters:
       snapshot_name     - Snapshot name.
       group1,...groupN  - Cache group names.
+      sync              - Run the operation synchronously, the command will wait for the entire operation to complete. Otherwise, it will be performed in the background, and the command will immediately return control.
 
   Snapshot restore operation status:
     control.(sh|bat) --snapshot restore snapshot_name --status