diff --git a/server/src/internalClusterTest/java/org/elasticsearch/snapshots/ConcurrentSnapshotsIT.java b/server/src/internalClusterTest/java/org/elasticsearch/snapshots/ConcurrentSnapshotsIT.java
index d13a8419321..da3f8f7d9f7 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/snapshots/ConcurrentSnapshotsIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/snapshots/ConcurrentSnapshotsIT.java
@@ -1319,12 +1319,6 @@ public class ConcurrentSnapshotsIT extends AbstractSnapshotIntegTestCase {
         return false;
     }
 
-    private static SnapshotInfo assertSuccessful(ActionFuture<CreateSnapshotResponse> future) throws Exception {
-        final SnapshotInfo snapshotInfo = future.get().getSnapshotInfo();
-        assertThat(snapshotInfo.state(), is(SnapshotState.SUCCESS));
-        return snapshotInfo;
-    }
-
     private void corruptIndexN(Path repoPath, long generation) throws IOException {
         logger.info("--> corrupting [index-{}] in [{}]", generation, repoPath);
         Path indexNBlob = repoPath.resolve(BlobStoreRepository.INDEX_FILE_PREFIX + generation);
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/snapshots/CorruptedBlobStoreRepositoryIT.java b/server/src/internalClusterTest/java/org/elasticsearch/snapshots/CorruptedBlobStoreRepositoryIT.java
index 70e642bca0d..4d87c26ca5b 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/snapshots/CorruptedBlobStoreRepositoryIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/snapshots/CorruptedBlobStoreRepositoryIT.java
@@ -21,6 +21,9 @@ package org.elasticsearch.snapshots;
 import org.elasticsearch.Version;
 import org.elasticsearch.action.ActionRunnable;
 import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotResponse;
+import org.elasticsearch.action.admin.cluster.snapshots.restore.RestoreSnapshotResponse;
+import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusResponse;
+import org.elasticsearch.action.index.IndexRequestBuilder;
 import org.elasticsearch.action.support.PlainActionFuture;
 import org.elasticsearch.client.Client;
 import org.elasticsearch.cluster.ClusterState;
@@ -32,6 +35,7 @@ import org.elasticsearch.common.bytes.BytesReference;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.unit.ByteSizeUnit;
 import org.elasticsearch.common.xcontent.XContentFactory;
+import org.elasticsearch.core.internal.io.IOUtils;
 import org.elasticsearch.repositories.IndexId;
 import org.elasticsearch.repositories.IndexMetaDataGenerations;
 import org.elasticsearch.repositories.RepositoriesService;
@@ -43,20 +47,25 @@ import org.elasticsearch.repositories.blobstore.BlobStoreRepository;
 import org.elasticsearch.threadpool.ThreadPool;
 
 import java.io.IOException;
+import java.nio.channels.SeekableByteChannel;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.StandardOpenOption;
 import java.util.Collections;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.function.Function;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertFileExists;
+import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertRequestBuilderThrows;
 import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.is;
 
 public class CorruptedBlobStoreRepositoryIT extends AbstractSnapshotIntegTestCase {
@@ -424,6 +433,285 @@ public class CorruptedBlobStoreRepositoryIT extends AbstractSnapshotIntegTestCas
         createFullSnapshot(repoName, "snapshot-2");
     }
 
+    /**
+     * Tests that a shard snapshot with a corrupted shard index file can still be used for restore and incremental snapshots.
+     */
+    public void testSnapshotWithCorruptedShardIndexFile() throws Exception {
+        final Client client = client();
+        final Path repo = randomRepoPath();
+        final String indexName = "test-idx";
+        final int nDocs = randomIntBetween(1, 10);
+
+        logger.info("-->  creating index [{}] with [{}] documents in it", indexName, nDocs);
+        assertAcked(prepareCreate(indexName).setSettings(indexSettingsNoReplicas(1)));
+
+        final IndexRequestBuilder[] documents = new IndexRequestBuilder[nDocs];
+        for (int j = 0; j < nDocs; j++) {
+            documents[j] = client.prepareIndex(indexName, "_doc").setSource("foo", "bar");
+        }
+        indexRandom(true, documents);
+        flushAndRefresh();
+
+        createRepository("test-repo", "fs", repo);
+
+        final String snapshot1 = "test-snap-1";
+        final SnapshotInfo snapshotInfo = createFullSnapshot("test-repo", snapshot1);
+        assertThat(snapshotInfo.indices(), hasSize(1));
+
+        final RepositoryData repositoryData = getRepositoryData("test-repo");
+        final Map<String, IndexId> indexIds = repositoryData.getIndices();
+        assertThat(indexIds.size(), equalTo(1));
+
+        final IndexId corruptedIndex = indexIds.get(indexName);
+        final Path shardIndexFile = repo.resolve("indices")
+                .resolve(corruptedIndex.getId()).resolve("0")
+                .resolve("index-" + repositoryData.shardGenerations().getShardGen(corruptedIndex, 0));
+
+        logger.info("-->  truncating shard index file [{}]", shardIndexFile);
+        try (SeekableByteChannel outChan = Files.newByteChannel(shardIndexFile, StandardOpenOption.WRITE)) {
+            outChan.truncate(randomInt(10));
+        }
+
+        logger.info("-->  verifying snapshot state for [{}]", snapshot1);
+        List<SnapshotInfo> snapshotInfos = clusterAdmin().prepareGetSnapshots("test-repo").get().getSnapshots();
+        assertThat(snapshotInfos.size(), equalTo(1));
+        assertThat(snapshotInfos.get(0).state(), equalTo(SnapshotState.SUCCESS));
+        assertThat(snapshotInfos.get(0).snapshotId().getName(), equalTo(snapshot1));
+
+        logger.info("-->  deleting index [{}]", indexName);
+        assertAcked(client().admin().indices().prepareDelete(indexName));
+
+        logger.info("-->  restoring snapshot [{}]", snapshot1);
+        clusterAdmin().prepareRestoreSnapshot("test-repo", snapshot1)
+                .setRestoreGlobalState(randomBoolean())
+                .setWaitForCompletion(true)
+                .get();
+        ensureGreen();
+
+        assertDocCount(indexName, nDocs);
+
+        logger.info("-->  indexing [{}] more documents into [{}]", nDocs, indexName);
+        for (int j = 0; j < nDocs; j++) {
+            documents[j] = client.prepareIndex(indexName, "_doc").setSource("foo2", "bar2");
+        }
+        indexRandom(true, documents);
+
+        final String snapshot2 = "test-snap-2";
+        logger.info("-->  creating snapshot [{}]", snapshot2);
+        final SnapshotInfo snapshotInfo2 = clusterAdmin().prepareCreateSnapshot("test-repo", snapshot2)
+                .setWaitForCompletion(true)
+                .get()
+                .getSnapshotInfo();
+        assertThat(snapshotInfo2.state(), equalTo(SnapshotState.PARTIAL));
+        assertThat(snapshotInfo2.failedShards(), equalTo(1));
+        assertThat(snapshotInfo2.successfulShards(), equalTo(snapshotInfo.totalShards() - 1));
+        assertThat(snapshotInfo2.indices(), hasSize(1));
+    }
+
+    public void testDeleteSnapshotWithMissingIndexAndShardMetadata() throws Exception {
+        Client client = client();
+
+        Path repo = randomRepoPath();
+        createRepository("test-repo", "fs", repo);
+
+        final String[] indices = {"test-idx-1", "test-idx-2"};
+        createIndex(indices);
+        logger.info("--> indexing some data");
+        indexRandom(true,
+                client().prepareIndex("test-idx-1", "_doc").setSource("foo", "bar"),
+                client().prepareIndex("test-idx-2", "_doc").setSource("foo", "bar"));
+
+        logger.info("--> creating snapshot");
+        CreateSnapshotResponse createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap-1")
+                .setWaitForCompletion(true).setIndices(indices).get();
+        final SnapshotInfo snapshotInfo = createSnapshotResponse.getSnapshotInfo();
+        assertThat(snapshotInfo.successfulShards(), greaterThan(0));
+        assertThat(snapshotInfo.successfulShards(), equalTo(snapshotInfo.totalShards()));
+
+        final Map<String, IndexId> indexIds = getRepositoryData("test-repo").getIndices();
+        final Path indicesPath = repo.resolve("indices");
+
+        logger.info("--> delete index metadata and shard metadata");
+        for (String index : indices) {
+            Path shardZero = indicesPath.resolve(indexIds.get(index).getId()).resolve("0");
+            if (randomBoolean()) {
+                Files.delete(shardZero.resolve("index-" + getRepositoryData("test-repo").shardGenerations()
+                        .getShardGen(indexIds.get(index), 0)));
+            }
+            Files.delete(shardZero.resolve("snap-" + snapshotInfo.snapshotId().getUUID() + ".dat"));
+        }
+
+        startDeleteSnapshot("test-repo", "test-snap-1").get();
+
+        logger.info("--> make sure snapshot doesn't exist");
+
+        expectThrows(SnapshotMissingException.class, () -> client.admin().cluster().prepareGetSnapshots("test-repo")
+                .addSnapshots("test-snap-1").get());
+
+        for (String index : indices) {
+            assertTrue(Files.notExists(indicesPath.resolve(indexIds.get(index).getId())));
+        }
+    }
+
+    public void testDeleteSnapshotWithMissingMetadata() throws Exception {
+        Client client = client();
+
+        Path repo = randomRepoPath();
+        createRepository("test-repo", "fs", repo);
+
+        createIndex("test-idx-1", "test-idx-2");
+        logger.info("--> indexing some data");
+        indexRandom(true,
+                client().prepareIndex("test-idx-1", "_doc").setSource("foo", "bar"),
+                client().prepareIndex("test-idx-2", "_doc").setSource("foo", "bar"));
+
+        logger.info("--> creating snapshot");
+        CreateSnapshotResponse createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap-1")
+                .setWaitForCompletion(true).setIndices("test-idx-*").get();
+        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
+        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
+                equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));
+
+        logger.info("--> delete global state metadata");
+        Path metadata = repo.resolve("meta-" + createSnapshotResponse.getSnapshotInfo().snapshotId().getUUID() + ".dat");
+        Files.delete(metadata);
+
+        startDeleteSnapshot("test-repo", "test-snap-1").get();
+
+        logger.info("--> make sure snapshot doesn't exist");
+        expectThrows(SnapshotMissingException.class, () -> client.admin().cluster().prepareGetSnapshots("test-repo")
+                .addSnapshots("test-snap-1").get());
+    }
+
+    public void testDeleteSnapshotWithCorruptedSnapshotFile() throws Exception {
+        Client client = client();
+
+        Path repo = randomRepoPath();
+        createRepository("test-repo", "fs", Settings.builder()
+                .put("location", repo).put("compress", false)
+                .put("chunk_size", randomIntBetween(100, 1000), ByteSizeUnit.BYTES));
+
+        createIndex("test-idx-1", "test-idx-2");
+        logger.info("--> indexing some data");
+        indexRandom(true,
+                client().prepareIndex("test-idx-1", "_doc").setSource("foo", "bar"),
+                client().prepareIndex("test-idx-2", "_doc").setSource("foo", "bar"));
+
+        logger.info("--> creating snapshot");
+        CreateSnapshotResponse createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap-1")
+                .setWaitForCompletion(true).setIndices("test-idx-*").get();
+        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
+        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
+                equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));
+
+        logger.info("--> truncate snapshot file to make it unreadable");
+        Path snapshotPath = repo.resolve("snap-" + createSnapshotResponse.getSnapshotInfo().snapshotId().getUUID() + ".dat");
+        try(SeekableByteChannel outChan = Files.newByteChannel(snapshotPath, StandardOpenOption.WRITE)) {
+            outChan.truncate(randomInt(10));
+        }
+        startDeleteSnapshot("test-repo", "test-snap-1").get();
+
+        logger.info("--> make sure snapshot doesn't exist");
+        expectThrows(SnapshotMissingException.class,
+                () -> client.admin().cluster().prepareGetSnapshots("test-repo").addSnapshots("test-snap-1").get().getSnapshots());
+
+        logger.info("--> make sure that we can create the snapshot again");
+        createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap-1")
+                .setWaitForCompletion(true).setIndices("test-idx-*").get();
+        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
+        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
+                equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));
+    }
+
+    /** Tests that a snapshot with a corrupted global state file can still be deleted */
+    public void testDeleteSnapshotWithCorruptedGlobalState() throws Exception {
+        final Path repo = randomRepoPath();
+
+        createRepository("test-repo", "fs", Settings.builder()
+                .put("location", repo)
+                .put("chunk_size", randomIntBetween(100, 1000), ByteSizeUnit.BYTES));
+
+        createIndex("test-idx-1", "test-idx-2");
+        indexRandom(true,
+                client().prepareIndex("test-idx-1", "_doc").setSource("foo", "bar"),
+                client().prepareIndex("test-idx-2", "_doc").setSource("foo", "bar"),
+                client().prepareIndex("test-idx-2", "_doc").setSource("foo", "bar"));
+        flushAndRefresh("test-idx-1", "test-idx-2");
+
+        SnapshotInfo snapshotInfo = createFullSnapshot("test-repo", "test-snap");
+
+        final Path globalStatePath = repo.resolve("meta-" + snapshotInfo.snapshotId().getUUID() + ".dat");
+        if (randomBoolean()) {
+            // Delete the global state metadata file
+            IOUtils.deleteFilesIgnoringExceptions(globalStatePath);
+        } else {
+            // Truncate the global state metadata file
+            try (SeekableByteChannel outChan = Files.newByteChannel(globalStatePath, StandardOpenOption.WRITE)) {
+                outChan.truncate(randomInt(10));
+            }
+        }
+
+        List<SnapshotInfo> snapshotInfos = clusterAdmin().prepareGetSnapshots("test-repo").get().getSnapshots();
+        assertThat(snapshotInfos.size(), equalTo(1));
+        assertThat(snapshotInfos.get(0).state(), equalTo(SnapshotState.SUCCESS));
+        assertThat(snapshotInfos.get(0).snapshotId().getName(), equalTo("test-snap"));
+
+        SnapshotsStatusResponse snapshotStatusResponse =
+                clusterAdmin().prepareSnapshotStatus("test-repo").setSnapshots("test-snap").get();
+        assertThat(snapshotStatusResponse.getSnapshots(), hasSize(1));
+        assertThat(snapshotStatusResponse.getSnapshots().get(0).getSnapshot().getSnapshotId().getName(), equalTo("test-snap"));
+
+        assertAcked(startDeleteSnapshot("test-repo", "test-snap").get());
+        expectThrows(SnapshotMissingException.class, () -> clusterAdmin()
+                .prepareGetSnapshots("test-repo").addSnapshots("test-snap").get());
+        assertRequestBuilderThrows(clusterAdmin().prepareSnapshotStatus("test-repo").addSnapshots("test-snap"),
+                SnapshotMissingException.class);
+
+        createFullSnapshot("test-repo", "test-snap");
+    }
+
+    public void testSnapshotWithMissingShardLevelIndexFile() throws Exception {
+        disableRepoConsistencyCheck("This test uses a purposely broken repository so it would fail consistency checks");
+
+        Path repo = randomRepoPath();
+        createRepository("test-repo", "fs", repo);
+
+        createIndex("test-idx-1", "test-idx-2");
+        logger.info("--> indexing some data");
+        indexRandom(true,
+                client().prepareIndex("test-idx-1", "_doc").setSource("foo", "bar"),
+                client().prepareIndex("test-idx-2", "_doc").setSource("foo", "bar"));
+
+        logger.info("--> creating snapshot");
+        clusterAdmin().prepareCreateSnapshot("test-repo", "test-snap-1")
+                .setWaitForCompletion(true).setIndices("test-idx-*").get();
+
+        logger.info("--> deleting shard level index file");
+        final Path indicesPath = repo.resolve("indices");
+        for (IndexId indexId : getRepositoryData("test-repo").getIndices().values()) {
+            final Path shardGen;
+            try (Stream<Path> shardFiles = Files.list(indicesPath.resolve(indexId.getId()).resolve("0"))) {
+                shardGen = shardFiles.filter(file -> file.getFileName().toString().startsWith(BlobStoreRepository.INDEX_FILE_PREFIX))
+                        .findFirst().orElseThrow(() -> new AssertionError("Failed to find shard index blob"));
+            }
+            Files.delete(shardGen);
+        }
+
+        logger.info("--> creating another snapshot");
+        CreateSnapshotResponse createSnapshotResponse =
+                clusterAdmin().prepareCreateSnapshot("test-repo", "test-snap-2")
+                        .setWaitForCompletion(true).setIndices("test-idx-1").get();
+        assertEquals(createSnapshotResponse.getSnapshotInfo().successfulShards(),
+                createSnapshotResponse.getSnapshotInfo().totalShards() - 1);
+
+        logger.info("--> restoring the first snapshot, the repository should not have lost any shard data despite deleting index-N, " +
+                "because it uses snap-*.data files and not the index-N to determine what files to restore");
+        client().admin().indices().prepareDelete("test-idx-1", "test-idx-2").get();
+        RestoreSnapshotResponse restoreSnapshotResponse =
+                clusterAdmin().prepareRestoreSnapshot("test-repo", "test-snap-1").setWaitForCompletion(true).get();
+        assertEquals(0, restoreSnapshotResponse.getRestoreInfo().failedShards());
+    }
+
     private void assertRepositoryBlocked(Client client, String repo, String existingSnapshot) {
         logger.info("--> try to delete snapshot");
         final RepositoryException repositoryException3 = expectThrows(RepositoryException.class,
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/snapshots/RestoreSnapshotIT.java b/server/src/internalClusterTest/java/org/elasticsearch/snapshots/RestoreSnapshotIT.java
new file mode 100644
index 00000000000..07a2d7a1fe3
--- /dev/null
+++ b/server/src/internalClusterTest/java/org/elasticsearch/snapshots/RestoreSnapshotIT.java
@@ -0,0 +1,750 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch 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.elasticsearch.snapshots;
+
+import org.elasticsearch.action.ActionFuture;
+import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotResponse;
+import org.elasticsearch.action.admin.cluster.snapshots.restore.RestoreSnapshotResponse;
+import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse;
+import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
+import org.elasticsearch.action.index.IndexRequestBuilder;
+import org.elasticsearch.client.Client;
+import org.elasticsearch.cluster.block.ClusterBlocks;
+import org.elasticsearch.cluster.metadata.IndexMetadata;
+import org.elasticsearch.cluster.metadata.MappingMetadata;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.unit.ByteSizeUnit;
+import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.common.xcontent.XContentFactory;
+import org.elasticsearch.indices.InvalidIndexNameException;
+import org.elasticsearch.repositories.RepositoriesService;
+import org.elasticsearch.rest.RestStatus;
+
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import static org.elasticsearch.cluster.metadata.IndexMetadata.SETTING_NUMBER_OF_REPLICAS;
+import static org.elasticsearch.cluster.metadata.IndexMetadata.SETTING_NUMBER_OF_SHARDS;
+import static org.elasticsearch.index.IndexSettings.INDEX_REFRESH_INTERVAL_SETTING;
+import static org.elasticsearch.index.IndexSettings.INDEX_SOFT_DELETES_SETTING;
+import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
+import static org.elasticsearch.indices.recovery.RecoverySettings.INDICES_RECOVERY_MAX_BYTES_PER_SEC_SETTING;
+import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
+import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
+import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertIndexTemplateExists;
+import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertIndexTemplateMissing;
+import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertRequestBuilderThrows;
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
+
+public class RestoreSnapshotIT extends AbstractSnapshotIntegTestCase {
+
+    public void testParallelRestoreOperations() {
+        String indexName1 = "testindex1";
+        String indexName2 = "testindex2";
+        String repoName = "test-restore-snapshot-repo";
+        String snapshotName1 = "test-restore-snapshot1";
+        String snapshotName2 = "test-restore-snapshot2";
+        Path absolutePath = randomRepoPath().toAbsolutePath();
+        logger.info("Path [{}]", absolutePath);
+        String restoredIndexName1 = indexName1 + "-restored";
+        String restoredIndexName2 = indexName2 + "-restored";
+        String expectedValue = "expected";
+
+        Client client = client();
+        // Write a document
+        String docId = Integer.toString(randomInt());
+        index(indexName1, "_doc", docId, "value", expectedValue);
+
+        String docId2 = Integer.toString(randomInt());
+        index(indexName2, "_doc", docId2, "value", expectedValue);
+
+        createRepository(repoName, "fs", absolutePath);
+
+        logger.info("--> snapshot");
+        CreateSnapshotResponse createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot(repoName, snapshotName1)
+                .setWaitForCompletion(true)
+                .setIndices(indexName1)
+                .get();
+        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
+        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
+                equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));
+        assertThat(createSnapshotResponse.getSnapshotInfo().state(), equalTo(SnapshotState.SUCCESS));
+
+        CreateSnapshotResponse createSnapshotResponse2 = client.admin().cluster().prepareCreateSnapshot(repoName, snapshotName2)
+                .setWaitForCompletion(true)
+                .setIndices(indexName2)
+                .get();
+        assertThat(createSnapshotResponse2.getSnapshotInfo().successfulShards(), greaterThan(0));
+        assertThat(createSnapshotResponse2.getSnapshotInfo().successfulShards(),
+                equalTo(createSnapshotResponse2.getSnapshotInfo().totalShards()));
+        assertThat(createSnapshotResponse2.getSnapshotInfo().state(), equalTo(SnapshotState.SUCCESS));
+
+        RestoreSnapshotResponse restoreSnapshotResponse1 = client.admin().cluster().prepareRestoreSnapshot(repoName, snapshotName1)
+                .setWaitForCompletion(false)
+                .setRenamePattern(indexName1)
+                .setRenameReplacement(restoredIndexName1)
+                .get();
+        RestoreSnapshotResponse restoreSnapshotResponse2 = client.admin().cluster().prepareRestoreSnapshot(repoName, snapshotName2)
+                .setWaitForCompletion(false)
+                .setRenamePattern(indexName2)
+                .setRenameReplacement(restoredIndexName2)
+                .get();
+        assertThat(restoreSnapshotResponse1.status(), equalTo(RestStatus.ACCEPTED));
+        assertThat(restoreSnapshotResponse2.status(), equalTo(RestStatus.ACCEPTED));
+        ensureGreen(restoredIndexName1, restoredIndexName2);
+        assertThat(client.prepareGet(restoredIndexName1, "_doc", docId).get().isExists(), equalTo(true));
+        assertThat(client.prepareGet(restoredIndexName2, "_doc", docId2).get().isExists(), equalTo(true));
+    }
+
+    public void testParallelRestoreOperationsFromSingleSnapshot() throws Exception {
+        String indexName1 = "testindex1";
+        String indexName2 = "testindex2";
+        String repoName = "test-restore-snapshot-repo";
+        String snapshotName = "test-restore-snapshot";
+        Path absolutePath = randomRepoPath().toAbsolutePath();
+        logger.info("Path [{}]", absolutePath);
+        String restoredIndexName1 = indexName1 + "-restored";
+        String restoredIndexName2 = indexName2 + "-restored";
+        String expectedValue = "expected";
+
+        Client client = client();
+        // Write a document
+        String docId = Integer.toString(randomInt());
+        index(indexName1, "_doc", docId, "value", expectedValue);
+
+        String docId2 = Integer.toString(randomInt());
+        index(indexName2, "_doc", docId2, "value", expectedValue);
+
+        createRepository(repoName, "fs", absolutePath);
+
+        logger.info("--> snapshot");
+        CreateSnapshotResponse createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot(repoName, snapshotName)
+                .setWaitForCompletion(true)
+                .setIndices(indexName1, indexName2)
+                .get();
+        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
+        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
+                equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));
+        assertThat(createSnapshotResponse.getSnapshotInfo().state(), equalTo(SnapshotState.SUCCESS));
+
+        ActionFuture<RestoreSnapshotResponse> restoreSnapshotResponse1 = client.admin().cluster()
+                .prepareRestoreSnapshot(repoName, snapshotName)
+                .setIndices(indexName1)
+                .setRenamePattern(indexName1)
+                .setRenameReplacement(restoredIndexName1)
+                .execute();
+
+        boolean sameSourceIndex = randomBoolean();
+
+        ActionFuture<RestoreSnapshotResponse> restoreSnapshotResponse2 = client.admin().cluster()
+                .prepareRestoreSnapshot(repoName, snapshotName)
+                .setIndices(sameSourceIndex ? indexName1 : indexName2)
+                .setRenamePattern(sameSourceIndex ? indexName1 : indexName2)
+                .setRenameReplacement(restoredIndexName2)
+                .execute();
+        assertThat(restoreSnapshotResponse1.get().status(), equalTo(RestStatus.ACCEPTED));
+        assertThat(restoreSnapshotResponse2.get().status(), equalTo(RestStatus.ACCEPTED));
+        ensureGreen(restoredIndexName1, restoredIndexName2);
+        assertThat(client.prepareGet(restoredIndexName1, "_doc", docId).get().isExists(), equalTo(true));
+        assertThat(client.prepareGet(restoredIndexName2, "_doc", sameSourceIndex ? docId : docId2).get().isExists(), equalTo(true));
+    }
+
+    public void testRestoreIncreasesPrimaryTerms() {
+        final String indexName = randomAlphaOfLengthBetween(5, 10).toLowerCase(Locale.ROOT);
+        createIndex(indexName, indexSettingsNoReplicas(2).build());
+        ensureGreen(indexName);
+
+        if (randomBoolean()) {
+            // open and close the index to increase the primary terms
+            for (int i = 0; i < randomInt(3); i++) {
+                assertAcked(client().admin().indices().prepareClose(indexName));
+                assertAcked(client().admin().indices().prepareOpen(indexName));
+            }
+        }
+
+        final IndexMetadata indexMetadata = clusterAdmin().prepareState().clear().setIndices(indexName)
+                .setMetadata(true).get().getState().metadata().index(indexName);
+        assertThat(indexMetadata.getSettings().get(IndexMetadata.SETTING_HISTORY_UUID), nullValue());
+        final int numPrimaries = getNumShards(indexName).numPrimaries;
+        final Map<Integer, Long> primaryTerms = IntStream.range(0, numPrimaries)
+                .boxed().collect(Collectors.toMap(shardId -> shardId, indexMetadata::primaryTerm));
+
+        createRepository("test-repo", "fs");
+        final CreateSnapshotResponse createSnapshotResponse = clusterAdmin().prepareCreateSnapshot("test-repo", "test-snap")
+                .setWaitForCompletion(true).setIndices(indexName).get();
+        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), equalTo(numPrimaries));
+        assertThat(createSnapshotResponse.getSnapshotInfo().failedShards(), equalTo(0));
+
+        assertAcked(client().admin().indices().prepareClose(indexName));
+
+        final RestoreSnapshotResponse restoreSnapshotResponse = clusterAdmin().prepareRestoreSnapshot("test-repo", "test-snap")
+                .setWaitForCompletion(true).get();
+        assertThat(restoreSnapshotResponse.getRestoreInfo().successfulShards(), equalTo(numPrimaries));
+        assertThat(restoreSnapshotResponse.getRestoreInfo().failedShards(), equalTo(0));
+
+        final IndexMetadata restoredIndexMetadata = clusterAdmin().prepareState().clear().setIndices(indexName)
+                .setMetadata(true).get().getState().metadata().index(indexName);
+        for (int shardId = 0; shardId < numPrimaries; shardId++) {
+            assertThat(restoredIndexMetadata.primaryTerm(shardId), greaterThan(primaryTerms.get(shardId)));
+        }
+        assertThat(restoredIndexMetadata.getSettings().get(IndexMetadata.SETTING_HISTORY_UUID), notNullValue());
+    }
+
+    public void testRestoreWithDifferentMappingsAndSettings() throws Exception {
+        createRepository("test-repo", "fs");
+
+        logger.info("--> create index with baz field");
+        assertAcked(prepareCreate("test-idx", 2, Settings.builder()
+                .put(indexSettings()).put(SETTING_NUMBER_OF_REPLICAS, between(0, 1)).put("refresh_interval", 10, TimeUnit.SECONDS)));
+
+        NumShards numShards = getNumShards("test-idx");
+
+        assertAcked(client().admin().indices().preparePutMapping("test-idx").setType("_doc").setSource("baz", "type=text"));
+        ensureGreen();
+
+        logger.info("--> snapshot it");
+        CreateSnapshotResponse createSnapshotResponse = clusterAdmin().prepareCreateSnapshot("test-repo", "test-snap")
+                .setWaitForCompletion(true).setIndices("test-idx").get();
+        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
+        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
+                equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));
+
+        logger.info("--> delete the index and recreate it with foo field");
+        cluster().wipeIndices("test-idx");
+        assertAcked(prepareCreate("test-idx", 2, Settings.builder()
+                .put(SETTING_NUMBER_OF_SHARDS, numShards.numPrimaries).put(SETTING_NUMBER_OF_REPLICAS, between(0, 1))
+                .put("refresh_interval", 5, TimeUnit.SECONDS)));
+        assertAcked(client().admin().indices().preparePutMapping("test-idx").setType("_doc").setSource("foo", "type=text"));
+        ensureGreen();
+
+        logger.info("--> close index");
+        client().admin().indices().prepareClose("test-idx").get();
+
+        logger.info("--> restore all indices from the snapshot");
+        RestoreSnapshotResponse restoreSnapshotResponse = clusterAdmin().prepareRestoreSnapshot("test-repo", "test-snap")
+                .setWaitForCompletion(true).execute().actionGet();
+        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
+
+        logger.info("--> assert that old mapping is restored");
+        MappingMetadata mappings = clusterAdmin().prepareState().get().getState().getMetadata()
+                .getIndices().get("test-idx").mapping();
+        assertThat(mappings.sourceAsMap().toString(), containsString("baz"));
+        assertThat(mappings.sourceAsMap().toString(), not(containsString("foo")));
+
+        logger.info("--> assert that old settings are restored");
+        GetSettingsResponse getSettingsResponse = client().admin().indices().prepareGetSettings("test-idx").execute().actionGet();
+        assertThat(getSettingsResponse.getSetting("test-idx", "index.refresh_interval"), equalTo("10s"));
+    }
+
+    public void testRestoreAliases() throws Exception {
+        createRepository("test-repo", "fs");
+
+        logger.info("--> create test indices");
+        createIndex("test-idx-1", "test-idx-2", "test-idx-3");
+        ensureGreen();
+
+        logger.info("--> create aliases");
+        assertAcked(client().admin().indices().prepareAliases()
+                .addAlias("test-idx-1", "alias-123")
+                .addAlias("test-idx-2", "alias-123")
+                .addAlias("test-idx-3", "alias-123")
+                .addAlias("test-idx-1", "alias-1")
+                .get());
+
+        assertFalse(client().admin().indices().prepareGetAliases("alias-123").get().getAliases().isEmpty());
+
+        logger.info("--> snapshot");
+        assertThat(clusterAdmin().prepareCreateSnapshot("test-repo", "test-snap")
+                        .setIndices().setWaitForCompletion(true).get().getSnapshotInfo().state(),
+                equalTo(SnapshotState.SUCCESS));
+
+        logger.info("-->  delete all indices");
+        cluster().wipeIndices("test-idx-1", "test-idx-2", "test-idx-3");
+        assertTrue(client().admin().indices().prepareGetAliases("alias-123").get().getAliases().isEmpty());
+        assertTrue(client().admin().indices().prepareGetAliases("alias-1").get().getAliases().isEmpty());
+
+        logger.info("--> restore snapshot with aliases");
+        RestoreSnapshotResponse restoreSnapshotResponse = clusterAdmin().prepareRestoreSnapshot("test-repo", "test-snap")
+                .setWaitForCompletion(true).setRestoreGlobalState(true).execute().actionGet();
+        // We don't restore any indices here
+        assertThat(restoreSnapshotResponse.getRestoreInfo().successfulShards(), allOf(greaterThan(0),
+                equalTo(restoreSnapshotResponse.getRestoreInfo().totalShards())));
+
+        logger.info("--> check that aliases are restored");
+        assertFalse(client().admin().indices().prepareGetAliases("alias-123").get().getAliases().isEmpty());
+        assertFalse(client().admin().indices().prepareGetAliases("alias-1").get().getAliases().isEmpty());
+
+        logger.info("-->  update aliases");
+        assertAcked(client().admin().indices().prepareAliases().removeAlias("test-idx-3", "alias-123"));
+        assertAcked(client().admin().indices().prepareAliases().addAlias("test-idx-3", "alias-3"));
+
+        logger.info("-->  delete and close indices");
+        cluster().wipeIndices("test-idx-1", "test-idx-2");
+        assertAcked(client().admin().indices().prepareClose("test-idx-3"));
+        assertTrue(client().admin().indices().prepareGetAliases("alias-123").get().getAliases().isEmpty());
+        assertTrue(client().admin().indices().prepareGetAliases("alias-1").get().getAliases().isEmpty());
+
+        logger.info("--> restore snapshot without aliases");
+        restoreSnapshotResponse = clusterAdmin().prepareRestoreSnapshot("test-repo", "test-snap").setWaitForCompletion(true)
+                .setRestoreGlobalState(true).setIncludeAliases(false).execute().actionGet();
+        // We don't restore any indices here
+        assertThat(restoreSnapshotResponse.getRestoreInfo().successfulShards(), allOf(greaterThan(0),
+                equalTo(restoreSnapshotResponse.getRestoreInfo().totalShards())));
+
+        logger.info("--> check that aliases are not restored and existing aliases still exist");
+        assertTrue(client().admin().indices().prepareGetAliases("alias-123").get().getAliases().isEmpty());
+        assertTrue(client().admin().indices().prepareGetAliases("alias-1").get().getAliases().isEmpty());
+        assertFalse(client().admin().indices().prepareGetAliases("alias-3").get().getAliases().isEmpty());
+    }
+
+    public void testRestoreTemplates() throws Exception {
+        createRepository("test-repo", "fs");
+
+        logger.info("-->  creating test template");
+        assertThat(client().admin().indices()
+                .preparePutTemplate("test-template")
+                .setPatterns(Collections.singletonList("te*"))
+                .addMapping("_doc", XContentFactory.jsonBuilder()
+                        .startObject()
+                        .startObject("_doc")
+                        .startObject("properties")
+                        .startObject("field1")
+                        .field("type", "text")
+                        .field("store", true)
+                        .endObject()
+                        .startObject("field2")
+                        .field("type", "keyword")
+                        .field("store", true)
+                        .endObject()
+                        .endObject()
+                        .endObject()
+                        .endObject())
+                .get().isAcknowledged(), equalTo(true));
+
+        logger.info("--> snapshot");
+        final SnapshotInfo snapshotInfo = assertSuccessful(clusterAdmin().prepareCreateSnapshot("test-repo", "test-snap")
+                .setIndices().setWaitForCompletion(true).execute());
+        assertThat(snapshotInfo.totalShards(), equalTo(0));
+        assertThat(snapshotInfo.successfulShards(), equalTo(0));
+        assertThat(getSnapshot("test-repo", "test-snap").state(), equalTo(SnapshotState.SUCCESS));
+
+        logger.info("-->  delete test template");
+        assertThat(client().admin().indices().prepareDeleteTemplate("test-template").get().isAcknowledged(), equalTo(true));
+        GetIndexTemplatesResponse getIndexTemplatesResponse = client().admin().indices().prepareGetTemplates().get();
+        assertIndexTemplateMissing(getIndexTemplatesResponse, "test-template");
+
+        logger.info("--> restore cluster state");
+        RestoreSnapshotResponse restoreSnapshotResponse = clusterAdmin().prepareRestoreSnapshot("test-repo", "test-snap")
+                .setWaitForCompletion(true).setRestoreGlobalState(true).execute().actionGet();
+        // We don't restore any indices here
+        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), equalTo(0));
+
+        logger.info("--> check that template is restored");
+        getIndexTemplatesResponse = client().admin().indices().prepareGetTemplates().get();
+        assertIndexTemplateExists(getIndexTemplatesResponse, "test-template");
+    }
+
+
+    public void testRenameOnRestore() throws Exception {
+        Client client = client();
+
+        createRepository("test-repo", "fs");
+
+        createIndex("test-idx-1", "test-idx-2", "test-idx-3");
+        ensureGreen();
+
+        assertAcked(client.admin().indices().prepareAliases()
+                .addAlias("test-idx-1", "alias-1", false)
+                .addAlias("test-idx-2", "alias-2", false)
+                .addAlias("test-idx-3", "alias-3", false)
+        );
+
+        indexRandomDocs("test-idx-1", 100);
+        indexRandomDocs("test-idx-2", 100);
+
+        logger.info("--> snapshot");
+        CreateSnapshotResponse createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap")
+                .setWaitForCompletion(true).setIndices("test-idx-1", "test-idx-2").get();
+        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
+        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
+                equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));
+
+        logger.info("--> restore indices with different names");
+        RestoreSnapshotResponse restoreSnapshotResponse = client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap")
+                .setRenamePattern("(.+)").setRenameReplacement("$1-copy").setWaitForCompletion(true).execute().actionGet();
+        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
+
+        assertDocCount("test-idx-1-copy", 100L);
+        assertDocCount("test-idx-2-copy", 100L);
+
+        logger.info("--> close just restored indices");
+        client.admin().indices().prepareClose("test-idx-1-copy", "test-idx-2-copy").get();
+
+        logger.info("--> and try to restore these indices again");
+        restoreSnapshotResponse = client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap")
+                .setRenamePattern("(.+)").setRenameReplacement("$1-copy").setWaitForCompletion(true).execute().actionGet();
+        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
+
+        assertDocCount("test-idx-1-copy", 100L);
+        assertDocCount("test-idx-2-copy", 100L);
+
+        logger.info("--> close indices");
+        assertAcked(client.admin().indices().prepareClose("test-idx-1", "test-idx-2-copy"));
+
+        logger.info("--> restore indices with different names");
+        restoreSnapshotResponse = client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap")
+                .setRenamePattern("(.+-2)").setRenameReplacement("$1-copy").setWaitForCompletion(true).execute().actionGet();
+        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
+
+        logger.info("--> delete indices");
+        cluster().wipeIndices("test-idx-1", "test-idx-1-copy", "test-idx-2", "test-idx-2-copy");
+
+        logger.info("--> try renaming indices using the same name");
+        try {
+            client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap").setRenamePattern("(.+)")
+                    .setRenameReplacement("same-name").setWaitForCompletion(true).execute().actionGet();
+            fail("Shouldn't be here");
+        } catch (SnapshotRestoreException ex) {
+            // Expected
+        }
+
+        logger.info("--> try renaming indices using the same name");
+        try {
+            client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap").setRenamePattern("test-idx-2")
+                    .setRenameReplacement("test-idx-1").setWaitForCompletion(true).execute().actionGet();
+            fail("Shouldn't be here");
+        } catch (SnapshotRestoreException ex) {
+            // Expected
+        }
+
+        logger.info("--> try renaming indices using invalid index name");
+        try {
+            client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap").setIndices("test-idx-1").setRenamePattern(".+")
+                    .setRenameReplacement("__WRONG__").setWaitForCompletion(true).execute().actionGet();
+            fail("Shouldn't be here");
+        } catch (InvalidIndexNameException ex) {
+            // Expected
+        }
+
+        logger.info("--> try renaming indices into existing alias name");
+        try {
+            client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap").setIndices("test-idx-1").setRenamePattern(".+")
+                    .setRenameReplacement("alias-3").setWaitForCompletion(true).execute().actionGet();
+            fail("Shouldn't be here");
+        } catch (InvalidIndexNameException ex) {
+            // Expected
+        }
+
+        logger.info("--> try renaming indices into existing alias of itself");
+        try {
+            client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap").setIndices("test-idx-1").setRenamePattern("test-idx")
+                    .setRenameReplacement("alias").setWaitForCompletion(true).execute().actionGet();
+            fail("Shouldn't be here");
+        } catch (SnapshotRestoreException ex) {
+            // Expected
+        }
+
+        logger.info("--> try renaming indices into existing alias of another restored index");
+        try {
+            client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap").setIndices("test-idx-1", "test-idx-2")
+                    .setRenamePattern("test-idx-1").setRenameReplacement("alias-2").setWaitForCompletion(true).execute().actionGet();
+            fail("Shouldn't be here");
+        } catch (SnapshotRestoreException ex) {
+            // Expected
+        }
+
+        logger.info("--> try renaming indices into existing alias of itself, but don't restore aliases ");
+        restoreSnapshotResponse = client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap")
+                .setIndices("test-idx-1").setRenamePattern("test-idx").setRenameReplacement("alias")
+                .setWaitForCompletion(true).setIncludeAliases(false).execute().actionGet();
+        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
+    }
+
+    public void testDynamicRestoreThrottling() throws Exception {
+        Client client = client();
+
+        createRepository("test-repo", "fs", Settings.builder()
+                .put("location", randomRepoPath()).put("compress", randomBoolean())
+                .put("chunk_size", 100, ByteSizeUnit.BYTES));
+
+        createIndexWithRandomDocs("test-idx", 100);
+
+        logger.info("--> snapshot");
+        client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap")
+                .setWaitForCompletion(true).setIndices("test-idx").get();
+
+        logger.info("--> delete index");
+        cluster().wipeIndices("test-idx");
+
+        logger.info("--> restore index");
+        client.admin().cluster().prepareUpdateSettings().setTransientSettings(Settings.builder()
+                .put(INDICES_RECOVERY_MAX_BYTES_PER_SEC_SETTING.getKey(), "100b").build()).get();
+        ActionFuture<RestoreSnapshotResponse> restoreSnapshotResponse = client.admin().cluster()
+                .prepareRestoreSnapshot("test-repo", "test-snap").setWaitForCompletion(true).execute();
+
+        // check if throttling is active
+        assertBusy(() -> {
+            long restorePause = 0L;
+            for (RepositoriesService repositoriesService : internalCluster().getDataNodeInstances(RepositoriesService.class)) {
+                restorePause += repositoriesService.repository("test-repo").getRestoreThrottleTimeInNanos();
+            }
+            assertThat(restorePause, greaterThan(TimeValue.timeValueSeconds(randomIntBetween(1, 5)).nanos()));
+            assertFalse(restoreSnapshotResponse.isDone());
+        }, 30, TimeUnit.SECONDS);
+
+        // run at full speed again
+        client.admin().cluster().prepareUpdateSettings().setTransientSettings(Settings.builder()
+                .putNull(INDICES_RECOVERY_MAX_BYTES_PER_SEC_SETTING.getKey()).build()).get();
+
+        // check that restore now completes quickly (i.e. within 10 seconds)
+        assertBusy(() -> assertTrue(restoreSnapshotResponse.isDone()));
+
+        assertThat(restoreSnapshotResponse.get().getRestoreInfo().totalShards(), greaterThan(0));
+        assertDocCount("test-idx", 100L);
+    }
+
+    public void testChangeSettingsOnRestore() throws Exception {
+        Client client = client();
+
+        createRepository("test-repo", "fs");
+
+        logger.info("--> create test index with case-preserving search analyzer");
+
+        Settings.Builder indexSettings = Settings.builder()
+                .put(indexSettings())
+                .put(SETTING_NUMBER_OF_REPLICAS, between(0, 1))
+                .put(INDEX_REFRESH_INTERVAL_SETTING.getKey(), "10s")
+                .put("index.analysis.analyzer.my_analyzer.type", "custom")
+                .put("index.analysis.analyzer.my_analyzer.tokenizer", "standard");
+
+        assertAcked(prepareCreate("test-idx", 2, indexSettings));
+
+        int numberOfShards = getNumShards("test-idx").numPrimaries;
+        assertAcked(client().admin().indices().preparePutMapping("test-idx").setType("_doc")
+                .setSource("field1", "type=text,analyzer=standard,search_analyzer=my_analyzer"));
+        final int numdocs = randomIntBetween(10, 100);
+        IndexRequestBuilder[] builders = new IndexRequestBuilder[numdocs];
+        for (int i = 0; i < builders.length; i++) {
+            builders[i] = client().prepareIndex("test-idx", "_doc").setId(Integer.toString(i)).setSource("field1", "Foo bar " + i);
+        }
+        indexRandom(true, builders);
+        flushAndRefresh();
+
+        assertHitCount(client.prepareSearch("test-idx").setSize(0).setQuery(matchQuery("field1", "foo")).get(), numdocs);
+        assertHitCount(client.prepareSearch("test-idx").setSize(0).setQuery(matchQuery("field1", "Foo")).get(), 0);
+        assertHitCount(client.prepareSearch("test-idx").setSize(0).setQuery(matchQuery("field1", "bar")).get(), numdocs);
+
+        logger.info("--> snapshot it");
+        CreateSnapshotResponse createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap")
+                .setWaitForCompletion(true).setIndices("test-idx").get();
+        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
+        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
+                equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));
+
+        logger.info("--> delete the index and recreate it while changing refresh interval and analyzer");
+        cluster().wipeIndices("test-idx");
+
+        Settings newIndexSettings = Settings.builder()
+                .put("refresh_interval", "5s")
+                .put("index.analysis.analyzer.my_analyzer.type", "standard")
+                .build();
+
+        Settings newIncorrectIndexSettings = Settings.builder()
+                .put(newIndexSettings)
+                .put(SETTING_NUMBER_OF_SHARDS, numberOfShards + 100)
+                .build();
+
+        logger.info("--> try restoring while changing the number of shards - should fail");
+        assertRequestBuilderThrows(client.admin().cluster()
+                .prepareRestoreSnapshot("test-repo", "test-snap")
+                .setIgnoreIndexSettings("index.analysis.*")
+                .setIndexSettings(newIncorrectIndexSettings)
+                .setWaitForCompletion(true), SnapshotRestoreException.class);
+
+        logger.info("--> try restoring while changing the number of replicas to a negative number - should fail");
+        Settings newIncorrectReplicasIndexSettings = Settings.builder()
+                .put(newIndexSettings)
+                .put(SETTING_NUMBER_OF_REPLICAS.substring(IndexMetadata.INDEX_SETTING_PREFIX.length()), randomIntBetween(-10, -1))
+                .build();
+        assertRequestBuilderThrows(client.admin().cluster()
+                .prepareRestoreSnapshot("test-repo", "test-snap")
+                .setIgnoreIndexSettings("index.analysis.*")
+                .setIndexSettings(newIncorrectReplicasIndexSettings)
+                .setWaitForCompletion(true), IllegalArgumentException.class);
+
+        logger.info("--> restore index with correct settings from the snapshot");
+        RestoreSnapshotResponse restoreSnapshotResponse = client.admin().cluster()
+                .prepareRestoreSnapshot("test-repo", "test-snap")
+                .setIgnoreIndexSettings("index.analysis.*")
+                .setIndexSettings(newIndexSettings)
+                .setWaitForCompletion(true).execute().actionGet();
+        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
+
+        logger.info("--> assert that correct settings are restored");
+        GetSettingsResponse getSettingsResponse = client.admin().indices().prepareGetSettings("test-idx").execute().actionGet();
+        assertThat(getSettingsResponse.getSetting("test-idx", INDEX_REFRESH_INTERVAL_SETTING.getKey()), equalTo("5s"));
+        // Make sure that number of shards didn't change
+        assertThat(getSettingsResponse.getSetting("test-idx", SETTING_NUMBER_OF_SHARDS), equalTo("" + numberOfShards));
+        assertThat(getSettingsResponse.getSetting("test-idx", "index.analysis.analyzer.my_analyzer.type"), equalTo("standard"));
+
+        assertHitCount(client.prepareSearch("test-idx").setSize(0).setQuery(matchQuery("field1", "Foo")).get(), numdocs);
+        assertHitCount(client.prepareSearch("test-idx").setSize(0).setQuery(matchQuery("field1", "bar")).get(), numdocs);
+
+        logger.info("--> delete the index and recreate it while deleting all index settings");
+        cluster().wipeIndices("test-idx");
+
+        logger.info("--> restore index with correct settings from the snapshot");
+        restoreSnapshotResponse = client.admin().cluster()
+                .prepareRestoreSnapshot("test-repo", "test-snap")
+                .setIgnoreIndexSettings("*") // delete everything we can delete
+                .setIndexSettings(newIndexSettings)
+                .setWaitForCompletion(true).execute().actionGet();
+        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
+
+        logger.info("--> assert that correct settings are restored and index is still functional");
+        getSettingsResponse = client.admin().indices().prepareGetSettings("test-idx").execute().actionGet();
+        assertThat(getSettingsResponse.getSetting("test-idx", INDEX_REFRESH_INTERVAL_SETTING.getKey()), equalTo("5s"));
+        // Make sure that number of shards didn't change
+        assertThat(getSettingsResponse.getSetting("test-idx", SETTING_NUMBER_OF_SHARDS), equalTo("" + numberOfShards));
+
+        assertHitCount(client.prepareSearch("test-idx").setSize(0).setQuery(matchQuery("field1", "Foo")).get(), numdocs);
+        assertHitCount(client.prepareSearch("test-idx").setSize(0).setQuery(matchQuery("field1", "bar")).get(), numdocs);
+    }
+
+    public void testRecreateBlocksOnRestore() throws Exception {
+        Client client = client();
+
+        createRepository("test-repo", "fs");
+
+        Settings.Builder indexSettings = Settings.builder()
+                .put(indexSettings())
+                .put(SETTING_NUMBER_OF_REPLICAS, between(0, 1))
+                .put(INDEX_REFRESH_INTERVAL_SETTING.getKey(), "10s");
+
+        logger.info("--> create index");
+        assertAcked(prepareCreate("test-idx", 2, indexSettings));
+
+        try {
+            List<String> initialBlockSettings = randomSubsetOf(randomInt(3),
+                    IndexMetadata.SETTING_BLOCKS_WRITE, IndexMetadata.SETTING_BLOCKS_METADATA, IndexMetadata.SETTING_READ_ONLY);
+            Settings.Builder initialSettingsBuilder = Settings.builder();
+            for (String blockSetting : initialBlockSettings) {
+                initialSettingsBuilder.put(blockSetting, true);
+            }
+            Settings initialSettings = initialSettingsBuilder.build();
+            logger.info("--> using initial block settings {}", initialSettings);
+
+            if (!initialSettings.isEmpty()) {
+                logger.info("--> apply initial blocks to index");
+                client().admin().indices().prepareUpdateSettings("test-idx").setSettings(initialSettingsBuilder).get();
+            }
+
+            logger.info("--> snapshot index");
+            CreateSnapshotResponse createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap")
+                    .setWaitForCompletion(true).setIndices("test-idx").get();
+            assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
+            assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
+                    equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));
+
+            logger.info("--> remove blocks and delete index");
+            disableIndexBlock("test-idx", IndexMetadata.SETTING_BLOCKS_METADATA);
+            disableIndexBlock("test-idx", IndexMetadata.SETTING_READ_ONLY);
+            disableIndexBlock("test-idx", IndexMetadata.SETTING_BLOCKS_WRITE);
+            disableIndexBlock("test-idx", IndexMetadata.SETTING_BLOCKS_READ);
+            cluster().wipeIndices("test-idx");
+
+            logger.info("--> restore index with additional block changes");
+            List<String> changeBlockSettings = randomSubsetOf(randomInt(4),
+                    IndexMetadata.SETTING_BLOCKS_METADATA, IndexMetadata.SETTING_BLOCKS_WRITE,
+                    IndexMetadata.SETTING_READ_ONLY, IndexMetadata.SETTING_BLOCKS_READ);
+            Settings.Builder changedSettingsBuilder = Settings.builder();
+            for (String blockSetting : changeBlockSettings) {
+                changedSettingsBuilder.put(blockSetting, randomBoolean());
+            }
+            Settings changedSettings = changedSettingsBuilder.build();
+            logger.info("--> applying changed block settings {}", changedSettings);
+
+            RestoreSnapshotResponse restoreSnapshotResponse = client.admin().cluster()
+                    .prepareRestoreSnapshot("test-repo", "test-snap")
+                    .setIndexSettings(changedSettings)
+                    .setWaitForCompletion(true).execute().actionGet();
+            assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
+
+            ClusterBlocks blocks = client.admin().cluster().prepareState().clear().setBlocks(true).get().getState().blocks();
+            // compute current index settings (as we cannot query them if they contain SETTING_BLOCKS_METADATA)
+            Settings mergedSettings = Settings.builder()
+                    .put(initialSettings)
+                    .put(changedSettings)
+                    .build();
+            logger.info("--> merged block settings {}", mergedSettings);
+
+            logger.info("--> checking consistency between settings and blocks");
+            assertThat(mergedSettings.getAsBoolean(IndexMetadata.SETTING_BLOCKS_METADATA, false),
+                    is(blocks.hasIndexBlock("test-idx", IndexMetadata.INDEX_METADATA_BLOCK)));
+            assertThat(mergedSettings.getAsBoolean(IndexMetadata.SETTING_BLOCKS_READ, false),
+                    is(blocks.hasIndexBlock("test-idx", IndexMetadata.INDEX_READ_BLOCK)));
+            assertThat(mergedSettings.getAsBoolean(IndexMetadata.SETTING_BLOCKS_WRITE, false),
+                    is(blocks.hasIndexBlock("test-idx", IndexMetadata.INDEX_WRITE_BLOCK)));
+            assertThat(mergedSettings.getAsBoolean(IndexMetadata.SETTING_READ_ONLY, false),
+                    is(blocks.hasIndexBlock("test-idx", IndexMetadata.INDEX_READ_ONLY_BLOCK)));
+        } finally {
+            logger.info("--> cleaning up blocks");
+            disableIndexBlock("test-idx", IndexMetadata.SETTING_BLOCKS_METADATA);
+            disableIndexBlock("test-idx", IndexMetadata.SETTING_READ_ONLY);
+            disableIndexBlock("test-idx", IndexMetadata.SETTING_BLOCKS_WRITE);
+            disableIndexBlock("test-idx", IndexMetadata.SETTING_BLOCKS_READ);
+        }
+    }
+
+    public void testForbidDisableSoftDeletesDuringRestore() throws Exception {
+        createRepository("test-repo", "fs");
+        final Settings.Builder settings = Settings.builder();
+        if (randomBoolean()) {
+            settings.put(INDEX_SOFT_DELETES_SETTING.getKey(), true);
+        }
+        createIndex("test-index", settings.build());
+        ensureGreen();
+        if (randomBoolean()) {
+            indexRandomDocs("test-index", between(0, 100));
+            flush("test-index");
+        }
+        clusterAdmin().prepareCreateSnapshot("test-repo", "snapshot-0")
+                .setIndices("test-index").setWaitForCompletion(true).get();
+        final SnapshotRestoreException restoreError = expectThrows(SnapshotRestoreException.class,
+                () -> clusterAdmin().prepareRestoreSnapshot("test-repo", "snapshot-0")
+                        .setIndexSettings(Settings.builder().put(INDEX_SOFT_DELETES_SETTING.getKey(), false))
+                        .setRenamePattern("test-index").setRenameReplacement("new-index")
+                        .get());
+        assertThat(restoreError.getMessage(), containsString("cannot disable setting [index.soft_deletes.enabled] on restore"));
+    }
+}
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/snapshots/SharedClusterSnapshotRestoreIT.java b/server/src/internalClusterTest/java/org/elasticsearch/snapshots/SharedClusterSnapshotRestoreIT.java
index be049ac92ce..66076a62ef3 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/snapshots/SharedClusterSnapshotRestoreIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/snapshots/SharedClusterSnapshotRestoreIT.java
@@ -34,24 +34,17 @@ import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotIndexStat
 import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotStatus;
 import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusResponse;
 import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
-import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptResponse;
 import org.elasticsearch.action.admin.indices.flush.FlushResponse;
-import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse;
 import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
 import org.elasticsearch.action.admin.indices.stats.ShardStats;
-import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
 import org.elasticsearch.action.index.IndexRequestBuilder;
-import org.elasticsearch.action.ingest.DeletePipelineRequest;
-import org.elasticsearch.action.ingest.GetPipelineResponse;
 import org.elasticsearch.action.support.ActiveShardCount;
 import org.elasticsearch.action.support.IndicesOptions;
 import org.elasticsearch.client.Client;
 import org.elasticsearch.cluster.ClusterState;
 import org.elasticsearch.cluster.RestoreInProgress;
 import org.elasticsearch.cluster.SnapshotsInProgress.State;
-import org.elasticsearch.cluster.block.ClusterBlocks;
 import org.elasticsearch.cluster.metadata.IndexMetadata;
-import org.elasticsearch.cluster.metadata.MappingMetadata;
 import org.elasticsearch.cluster.metadata.MetadataIndexStateService;
 import org.elasticsearch.cluster.routing.IndexRoutingTable;
 import org.elasticsearch.cluster.routing.RecoverySource;
@@ -60,16 +53,9 @@ import org.elasticsearch.cluster.routing.ShardRoutingState;
 import org.elasticsearch.cluster.routing.UnassignedInfo;
 import org.elasticsearch.cluster.service.ClusterService;
 import org.elasticsearch.common.Numbers;
-import org.elasticsearch.common.Strings;
-import org.elasticsearch.common.bytes.BytesArray;
-import org.elasticsearch.common.bytes.BytesReference;
-import org.elasticsearch.common.collect.ImmutableOpenMap;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.unit.ByteSizeUnit;
 import org.elasticsearch.common.unit.TimeValue;
-import org.elasticsearch.common.xcontent.XContentFactory;
-import org.elasticsearch.common.xcontent.XContentType;
-import org.elasticsearch.core.internal.io.IOUtils;
 import org.elasticsearch.index.Index;
 import org.elasticsearch.index.IndexService;
 import org.elasticsearch.index.engine.Engine;
@@ -77,17 +63,11 @@ import org.elasticsearch.index.engine.EngineTestCase;
 import org.elasticsearch.index.shard.IndexShard;
 import org.elasticsearch.index.shard.ShardId;
 import org.elasticsearch.indices.IndicesService;
-import org.elasticsearch.indices.InvalidIndexNameException;
-import org.elasticsearch.ingest.IngestTestPlugin;
-import org.elasticsearch.plugins.Plugin;
 import org.elasticsearch.repositories.IndexId;
 import org.elasticsearch.repositories.RepositoriesService;
 import org.elasticsearch.repositories.RepositoryData;
 import org.elasticsearch.repositories.RepositoryException;
 import org.elasticsearch.repositories.blobstore.BlobStoreRepository;
-import org.elasticsearch.rest.RestStatus;
-import org.elasticsearch.script.MockScriptEngine;
-import org.elasticsearch.script.StoredScriptsIT;
 import org.elasticsearch.snapshots.mockstore.MockRepository;
 import org.elasticsearch.threadpool.ThreadPool;
 
@@ -97,38 +77,24 @@ import java.nio.file.Path;
 import java.nio.file.StandardOpenOption;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
-import java.util.stream.Collectors;
 import java.util.stream.IntStream;
-import java.util.stream.Stream;
 
-import static org.elasticsearch.cluster.metadata.IndexMetadata.SETTING_NUMBER_OF_REPLICAS;
 import static org.elasticsearch.cluster.metadata.IndexMetadata.SETTING_NUMBER_OF_SHARDS;
 import static org.elasticsearch.cluster.routing.allocation.decider.MaxRetryAllocationDecider.SETTING_ALLOCATION_MAX_RETRY;
-import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
-import static org.elasticsearch.index.IndexSettings.INDEX_REFRESH_INTERVAL_SETTING;
 import static org.elasticsearch.index.IndexSettings.INDEX_SOFT_DELETES_SETTING;
-import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
 import static org.elasticsearch.index.shard.IndexShardTests.getEngineFromShard;
 import static org.elasticsearch.indices.recovery.RecoverySettings.INDICES_RECOVERY_MAX_BYTES_PER_SEC_SETTING;
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
-import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAliasesExist;
-import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAliasesMissing;
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAllSuccessful;
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
-import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertIndexTemplateExists;
-import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertIndexTemplateMissing;
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertRequestBuilderThrows;
-import static org.hamcrest.Matchers.allOf;
 import static org.hamcrest.Matchers.anyOf;
 import static org.hamcrest.Matchers.containsInAnyOrder;
 import static org.hamcrest.Matchers.containsString;
@@ -147,13 +113,6 @@ import static org.hamcrest.Matchers.nullValue;
 @LuceneTestCase.SuppressFileSystems(value = "WindowsFS")
 public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCase {
 
-    @Override
-    protected Collection<Class<? extends Plugin>> nodePlugins() {
-        return Arrays.asList(IngestTestPlugin.class,
-            StoredScriptsIT.CustomScriptPlugin.class,
-            MockRepository.Plugin.class);
-    }
-
     @Override
     protected Settings nodeSettings(int nodeOrdinal) {
         return Settings.builder().put(super.nodeSettings(nodeOrdinal))
@@ -377,52 +336,6 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
             copyRestoreUUID.equals(originalIndexUUID));
     }
 
-    public void testRestoreWithDifferentMappingsAndSettings() throws Exception {
-        createRepository("test-repo", "fs");
-
-        logger.info("--> create index with foo type");
-        assertAcked(prepareCreate("test-idx", 2, Settings.builder()
-                .put(indexSettings()).put(SETTING_NUMBER_OF_REPLICAS, between(0, 1)).put("refresh_interval", 10, TimeUnit.SECONDS)));
-
-        NumShards numShards = getNumShards("test-idx");
-
-        assertAcked(client().admin().indices().preparePutMapping("test-idx").setType("foo").setSource("baz", "type=text"));
-        ensureGreen();
-
-        logger.info("--> snapshot it");
-        CreateSnapshotResponse createSnapshotResponse = client().admin().cluster().prepareCreateSnapshot("test-repo", "test-snap")
-            .setWaitForCompletion(true).setIndices("test-idx").get();
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
-            equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));
-
-        logger.info("--> delete the index and recreate it with bar type");
-        cluster().wipeIndices("test-idx");
-        assertAcked(prepareCreate("test-idx", 2, Settings.builder()
-                .put(SETTING_NUMBER_OF_SHARDS, numShards.numPrimaries).put(SETTING_NUMBER_OF_REPLICAS, between(0, 1))
-                .put("refresh_interval", 5, TimeUnit.SECONDS)));
-        assertAcked(client().admin().indices().preparePutMapping("test-idx").setType("bar").setSource("baz", "type=text"));
-        ensureGreen();
-
-        logger.info("--> close index");
-        client().admin().indices().prepareClose("test-idx").get();
-
-        logger.info("--> restore all indices from the snapshot");
-        RestoreSnapshotResponse restoreSnapshotResponse = client().admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap")
-            .setWaitForCompletion(true).execute().actionGet();
-        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
-
-        logger.info("--> assert that old mapping is restored");
-        ImmutableOpenMap<String, MappingMetadata> mappings = client().admin().cluster().prepareState().get().getState().getMetadata()
-            .getIndices().get("test-idx").getMappings();
-        assertThat(mappings.get("foo"), notNullValue());
-        assertThat(mappings.get("bar"), nullValue());
-
-        logger.info("--> assert that old settings are restored");
-        GetSettingsResponse getSettingsResponse = client().admin().indices().prepareGetSettings("test-idx").execute().actionGet();
-        assertThat(getSettingsResponse.getSetting("test-idx", "index.refresh_interval"), equalTo("10s"));
-    }
-
     public void testEmptySnapshot() throws Exception {
         createRepository("test-repo", "fs");
 
@@ -436,289 +349,6 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
                 .getSnapshots().get(0).state(), equalTo(SnapshotState.SUCCESS));
     }
 
-    public void testRestoreAliases() throws Exception {
-        Client client = client();
-
-        createRepository("test-repo", "fs");
-
-        logger.info("--> create test indices");
-        createIndex("test-idx-1", "test-idx-2", "test-idx-3");
-        ensureGreen();
-
-        logger.info("--> create aliases");
-        assertAcked(client.admin().indices().prepareAliases()
-                .addAlias("test-idx-1", "alias-123")
-                .addAlias("test-idx-2", "alias-123")
-                .addAlias("test-idx-3", "alias-123")
-                .addAlias("test-idx-1", "alias-1")
-                .get());
-        assertAliasesExist(client.admin().indices().prepareAliasesExist("alias-123").get());
-
-        logger.info("--> snapshot");
-        assertThat(client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap")
-            .setIndices().setWaitForCompletion(true).get().getSnapshotInfo().state(),
-            equalTo(SnapshotState.SUCCESS));
-
-        logger.info("-->  delete all indices");
-        cluster().wipeIndices("test-idx-1", "test-idx-2", "test-idx-3");
-        assertAliasesMissing(client.admin().indices().prepareAliasesExist("alias-123", "alias-1").get());
-
-        logger.info("--> restore snapshot with aliases");
-        RestoreSnapshotResponse restoreSnapshotResponse = client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap")
-            .setWaitForCompletion(true).setRestoreGlobalState(true).execute().actionGet();
-        // We don't restore any indices here
-        assertThat(restoreSnapshotResponse.getRestoreInfo().successfulShards(), allOf(greaterThan(0),
-            equalTo(restoreSnapshotResponse.getRestoreInfo().totalShards())));
-
-        logger.info("--> check that aliases are restored");
-        assertAliasesExist(client.admin().indices().prepareAliasesExist("alias-123", "alias-1").get());
-
-        logger.info("-->  update aliases");
-        assertAcked(client.admin().indices().prepareAliases().removeAlias("test-idx-3", "alias-123"));
-        assertAcked(client.admin().indices().prepareAliases().addAlias("test-idx-3", "alias-3"));
-
-        logger.info("-->  delete and close indices");
-        cluster().wipeIndices("test-idx-1", "test-idx-2");
-        assertAcked(client.admin().indices().prepareClose("test-idx-3"));
-        assertAliasesMissing(client.admin().indices().prepareAliasesExist("alias-123", "alias-1").get());
-
-        logger.info("--> restore snapshot without aliases");
-        restoreSnapshotResponse = client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap").setWaitForCompletion(true)
-            .setRestoreGlobalState(true).setIncludeAliases(false).execute().actionGet();
-        // We don't restore any indices here
-        assertThat(restoreSnapshotResponse.getRestoreInfo().successfulShards(), allOf(greaterThan(0),
-            equalTo(restoreSnapshotResponse.getRestoreInfo().totalShards())));
-
-        logger.info("--> check that aliases are not restored and existing aliases still exist");
-        assertAliasesMissing(client.admin().indices().prepareAliasesExist("alias-123", "alias-1").get());
-        assertAliasesExist(client.admin().indices().prepareAliasesExist("alias-3").get());
-    }
-
-    public void testRestoreTemplates() throws Exception {
-        Client client = client();
-
-        createRepository("test-repo", "fs");
-
-        logger.info("-->  creating test template");
-        assertThat(client.admin().indices()
-            .preparePutTemplate("test-template")
-                .setPatterns(Collections.singletonList("te*"))
-                .addMapping("test-mapping", XContentFactory.jsonBuilder()
-                    .startObject()
-                        .startObject("test-mapping")
-                            .startObject("properties")
-                                .startObject("field1")
-                                    .field("type", "text")
-                                    .field("store", true)
-                                .endObject()
-                                .startObject("field2")
-                                    .field("type", "keyword")
-                                    .field("store", true)
-                                .endObject()
-                            .endObject()
-                        .endObject()
-                    .endObject())
-            .get().isAcknowledged(), equalTo(true));
-
-        logger.info("--> snapshot");
-        CreateSnapshotResponse createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap")
-            .setIndices().setWaitForCompletion(true).get();
-        assertThat(createSnapshotResponse.getSnapshotInfo().totalShards(), equalTo(0));
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), equalTo(0));
-        assertThat(client.admin().cluster().prepareGetSnapshots("test-repo").setSnapshots("test-snap").get().getSnapshots().get(0).state(),
-            equalTo(SnapshotState.SUCCESS));
-
-        logger.info("-->  delete test template");
-        assertThat(client.admin().indices().prepareDeleteTemplate("test-template").get().isAcknowledged(), equalTo(true));
-        GetIndexTemplatesResponse getIndexTemplatesResponse = client().admin().indices().prepareGetTemplates().get();
-        assertIndexTemplateMissing(getIndexTemplatesResponse, "test-template");
-
-        logger.info("--> restore cluster state");
-        RestoreSnapshotResponse restoreSnapshotResponse = client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap")
-            .setWaitForCompletion(true).setRestoreGlobalState(true).execute().actionGet();
-        // We don't restore any indices here
-        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), equalTo(0));
-
-        logger.info("--> check that template is restored");
-        getIndexTemplatesResponse = client().admin().indices().prepareGetTemplates().get();
-        assertIndexTemplateExists(getIndexTemplatesResponse, "test-template");
-    }
-
-    public void testIncludeGlobalState() throws Exception {
-        Client client = client();
-
-        createRepository("test-repo", "fs");
-
-        boolean testTemplate = randomBoolean();
-        boolean testPipeline = randomBoolean();
-        boolean testScript = (testTemplate == false && testPipeline == false) || randomBoolean(); // At least something should be stored
-
-        if(testTemplate) {
-            logger.info("-->  creating test template");
-            assertThat(client.admin().indices()
-                .preparePutTemplate("test-template")
-                .setPatterns(Collections.singletonList("te*"))
-                .addMapping("_doc", XContentFactory.jsonBuilder()
-                    .startObject()
-                        .startObject("_doc")
-                            .startObject("properties")
-                                .startObject("field1")
-                                    .field("type", "text")
-                                    .field("store", true)
-                                .endObject()
-                                .startObject("field2")
-                                    .field("type", "keyword")
-                                    .field("store", true)
-                                .endObject()
-                            .endObject()
-                        .endObject()
-                    .endObject())
-                .get().isAcknowledged(), equalTo(true));
-        }
-
-        if(testPipeline) {
-            logger.info("-->  creating test pipeline");
-            BytesReference pipelineSource = BytesReference.bytes(jsonBuilder().startObject()
-                .field("description", "my_pipeline")
-                .startArray("processors")
-                .startObject()
-                .startObject("test")
-                .endObject()
-                .endObject()
-                .endArray()
-                .endObject());
-            assertAcked(client().admin().cluster().preparePutPipeline("barbaz", pipelineSource, XContentType.JSON).get());
-        }
-
-        if(testScript) {
-            logger.info("-->  creating test script");
-            assertAcked(client().admin().cluster().preparePutStoredScript()
-                .setId("foobar")
-                .setContent(new BytesArray(
-                    "{\"script\": { \"lang\": \"" + MockScriptEngine.NAME + "\", \"source\": \"1\"} }"), XContentType.JSON));
-        }
-
-        logger.info("--> snapshot without global state");
-        CreateSnapshotResponse createSnapshotResponse = client.admin().cluster()
-            .prepareCreateSnapshot("test-repo", "test-snap-no-global-state").setIndices().setIncludeGlobalState(false)
-            .setWaitForCompletion(true).get();
-        assertThat(createSnapshotResponse.getSnapshotInfo().totalShards(), equalTo(0));
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), equalTo(0));
-        assertThat(client.admin().cluster().prepareGetSnapshots("test-repo").setSnapshots("test-snap-no-global-state")
-            .get().getSnapshots().get(0).state(),
-            equalTo(SnapshotState.SUCCESS));
-        SnapshotsStatusResponse snapshotsStatusResponse = client.admin().cluster().prepareSnapshotStatus("test-repo")
-            .addSnapshots("test-snap-no-global-state").get();
-        assertThat(snapshotsStatusResponse.getSnapshots().size(), equalTo(1));
-        SnapshotStatus snapshotStatus = snapshotsStatusResponse.getSnapshots().get(0);
-        assertThat(snapshotStatus.includeGlobalState(), equalTo(false));
-
-        logger.info("--> snapshot with global state");
-        createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap-with-global-state")
-            .setIndices().setIncludeGlobalState(true).setWaitForCompletion(true).get();
-        assertThat(createSnapshotResponse.getSnapshotInfo().totalShards(), equalTo(0));
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), equalTo(0));
-        assertThat(client.admin().cluster().prepareGetSnapshots("test-repo").setSnapshots("test-snap-with-global-state")
-            .get().getSnapshots().get(0).state(),
-            equalTo(SnapshotState.SUCCESS));
-        snapshotsStatusResponse = client.admin().cluster().prepareSnapshotStatus("test-repo")
-            .addSnapshots("test-snap-with-global-state").get();
-        assertThat(snapshotsStatusResponse.getSnapshots().size(), equalTo(1));
-        snapshotStatus = snapshotsStatusResponse.getSnapshots().get(0);
-        assertThat(snapshotStatus.includeGlobalState(), equalTo(true));
-
-        if (testTemplate) {
-            logger.info("-->  delete test template");
-            cluster().wipeTemplates("test-template");
-            GetIndexTemplatesResponse getIndexTemplatesResponse = client().admin().indices().prepareGetTemplates().get();
-            assertIndexTemplateMissing(getIndexTemplatesResponse, "test-template");
-        }
-
-        if (testPipeline) {
-            logger.info("-->  delete test pipeline");
-            assertAcked(client().admin().cluster().deletePipeline(new DeletePipelineRequest("barbaz")).get());
-        }
-
-        if (testScript) {
-            logger.info("-->  delete test script");
-            assertAcked(client().admin().cluster().prepareDeleteStoredScript("foobar").get());
-        }
-
-        logger.info("--> try restoring cluster state from snapshot without global state");
-        RestoreSnapshotResponse restoreSnapshotResponse = client.admin().cluster()
-            .prepareRestoreSnapshot("test-repo", "test-snap-no-global-state")
-            .setWaitForCompletion(true).setRestoreGlobalState(true).execute().actionGet();
-        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), equalTo(0));
-
-        logger.info("--> check that template wasn't restored");
-        GetIndexTemplatesResponse getIndexTemplatesResponse = client().admin().indices().prepareGetTemplates().get();
-        assertIndexTemplateMissing(getIndexTemplatesResponse, "test-template");
-
-        logger.info("--> restore cluster state");
-        restoreSnapshotResponse = client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap-with-global-state")
-            .setWaitForCompletion(true).setRestoreGlobalState(true).execute().actionGet();
-        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), equalTo(0));
-
-        if (testTemplate) {
-            logger.info("--> check that template is restored");
-            getIndexTemplatesResponse = client().admin().indices().prepareGetTemplates().get();
-            assertIndexTemplateExists(getIndexTemplatesResponse, "test-template");
-        }
-
-        if (testPipeline) {
-            logger.info("--> check that pipeline is restored");
-            GetPipelineResponse getPipelineResponse = client().admin().cluster().prepareGetPipeline("barbaz").get();
-            assertTrue(getPipelineResponse.isFound());
-        }
-
-        if (testScript) {
-            logger.info("--> check that script is restored");
-            GetStoredScriptResponse getStoredScriptResponse = client().admin().cluster().prepareGetStoredScript("foobar").get();
-            assertNotNull(getStoredScriptResponse.getSource());
-        }
-
-        createIndexWithRandomDocs("test-idx", 100);
-
-        logger.info("--> snapshot without global state but with indices");
-        createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap-no-global-state-with-index")
-            .setIndices("test-idx").setIncludeGlobalState(false).setWaitForCompletion(true).get();
-        assertThat(createSnapshotResponse.getSnapshotInfo().totalShards(), greaterThan(0));
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
-            equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));
-        assertThat(client.admin().cluster().prepareGetSnapshots("test-repo").setSnapshots("test-snap-no-global-state-with-index")
-                .get().getSnapshots().get(0).state(),
-            equalTo(SnapshotState.SUCCESS));
-
-        logger.info("-->  delete global state and index ");
-        cluster().wipeIndices("test-idx");
-        if (testTemplate) {
-            cluster().wipeTemplates("test-template");
-        }
-        if (testPipeline) {
-            assertAcked(client().admin().cluster().deletePipeline(new DeletePipelineRequest("barbaz")).get());
-        }
-
-        if (testScript) {
-            assertAcked(client().admin().cluster().prepareDeleteStoredScript("foobar").get());
-        }
-
-        getIndexTemplatesResponse = client().admin().indices().prepareGetTemplates().get();
-        assertIndexTemplateMissing(getIndexTemplatesResponse, "test-template");
-
-        logger.info("--> try restoring index and cluster state from snapshot without global state");
-        restoreSnapshotResponse = client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap-no-global-state-with-index")
-            .setWaitForCompletion(true).setRestoreGlobalState(true).execute().actionGet();
-        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
-        assertThat(restoreSnapshotResponse.getRestoreInfo().failedShards(), equalTo(0));
-
-        logger.info("--> check that global state wasn't restored but index was");
-        getIndexTemplatesResponse = client().admin().indices().prepareGetTemplates().get();
-        assertIndexTemplateMissing(getIndexTemplatesResponse, "test-template");
-        assertFalse(client().admin().cluster().prepareGetPipeline("barbaz").get().isFound());
-        assertNull(client().admin().cluster().prepareGetStoredScript("foobar").get().getSource());
-        assertDocCount("test-idx", 100L);
-    }
-
     public void testSnapshotFileFailureDuringSnapshot() throws InterruptedException {
         disableRepoConsistencyCheck("This test uses a purposely broken repository so it would fail consistency checks");
         Client client = client();
@@ -1188,212 +818,6 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
         assertFileCount(repo, numberOfFiles[0]);
     }
 
-    public void testDeleteSnapshotWithMissingIndexAndShardMetadata() throws Exception {
-        Client client = client();
-
-        Path repo = randomRepoPath();
-        createRepository("test-repo", "fs", repo);
-
-        final String[] indices = {"test-idx-1", "test-idx-2"};
-        createIndex(indices);
-        logger.info("--> indexing some data");
-        indexRandom(true,
-                client().prepareIndex("test-idx-1", "_doc").setSource("foo", "bar"),
-                client().prepareIndex("test-idx-2", "_doc").setSource("foo", "bar"));
-
-        logger.info("--> creating snapshot");
-        CreateSnapshotResponse createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap-1")
-            .setWaitForCompletion(true).setIndices(indices).get();
-        final SnapshotInfo snapshotInfo = createSnapshotResponse.getSnapshotInfo();
-        assertThat(snapshotInfo.successfulShards(), greaterThan(0));
-        assertThat(snapshotInfo.successfulShards(), equalTo(snapshotInfo.totalShards()));
-
-        final Map<String, IndexId> indexIds = getRepositoryData("test-repo").getIndices();
-        final Path indicesPath = repo.resolve("indices");
-
-        logger.info("--> delete index metadata and shard metadata");
-        for (String index : indices) {
-            Path shardZero = indicesPath.resolve(indexIds.get(index).getId()).resolve("0");
-            if (randomBoolean()) {
-                Files.delete(
-                    shardZero.resolve("index-" + getRepositoryData("test-repo").shardGenerations().getShardGen(indexIds.get(index), 0)));
-            }
-            Files.delete(shardZero.resolve("snap-" + snapshotInfo.snapshotId().getUUID() + ".dat"));
-        }
-
-        logger.info("--> delete snapshot");
-        client.admin().cluster().prepareDeleteSnapshot("test-repo", "test-snap-1").get();
-
-        logger.info("--> make sure snapshot doesn't exist");
-        assertRequestBuilderThrows(client.admin().cluster().prepareGetSnapshots("test-repo")
-                                             .addSnapshots("test-snap-1"), SnapshotMissingException.class);
-
-        for (String index : indices) {
-            assertTrue(Files.notExists(indicesPath.resolve(indexIds.get(index).getId())));
-        }
-    }
-
-    public void testDeleteSnapshotWithMissingMetadata() throws Exception {
-        Client client = client();
-
-        Path repo = randomRepoPath();
-        createRepository("test-repo", "fs", repo);
-
-        createIndex("test-idx-1", "test-idx-2");
-        logger.info("--> indexing some data");
-        indexRandom(true,
-                client().prepareIndex("test-idx-1", "_doc").setSource("foo", "bar"),
-                client().prepareIndex("test-idx-2", "_doc").setSource("foo", "bar"));
-
-        logger.info("--> creating snapshot");
-        CreateSnapshotResponse createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap-1")
-            .setWaitForCompletion(true).setIndices("test-idx-*").get();
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
-            equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));
-
-        logger.info("--> delete global state metadata");
-        Path metadata = repo.resolve("meta-" + createSnapshotResponse.getSnapshotInfo().snapshotId().getUUID() + ".dat");
-        Files.delete(metadata);
-
-        logger.info("--> delete snapshot");
-        client.admin().cluster().prepareDeleteSnapshot("test-repo", "test-snap-1").get();
-
-        logger.info("--> make sure snapshot doesn't exist");
-        assertRequestBuilderThrows(client.admin().cluster().prepareGetSnapshots("test-repo")
-                                             .addSnapshots("test-snap-1"), SnapshotMissingException.class);
-    }
-
-    public void testDeleteSnapshotWithCorruptedSnapshotFile() throws Exception {
-        Client client = client();
-
-        Path repo = randomRepoPath();
-        createRepository("test-repo", "fs", Settings.builder()
-            .put("location", repo).put("compress", false)
-            .put("chunk_size", randomIntBetween(100, 1000), ByteSizeUnit.BYTES));
-
-        createIndex("test-idx-1", "test-idx-2");
-        logger.info("--> indexing some data");
-        indexRandom(true,
-                client().prepareIndex("test-idx-1", "_doc").setSource("foo", "bar"),
-                client().prepareIndex("test-idx-2", "_doc").setSource("foo", "bar"));
-
-        logger.info("--> creating snapshot");
-        CreateSnapshotResponse createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap-1")
-            .setWaitForCompletion(true).setIndices("test-idx-*").get();
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
-            equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));
-
-        logger.info("--> truncate snapshot file to make it unreadable");
-        Path snapshotPath = repo.resolve("snap-" + createSnapshotResponse.getSnapshotInfo().snapshotId().getUUID() + ".dat");
-        try(SeekableByteChannel outChan = Files.newByteChannel(snapshotPath, StandardOpenOption.WRITE)) {
-            outChan.truncate(randomInt(10));
-        }
-        logger.info("--> delete snapshot");
-        client.admin().cluster().prepareDeleteSnapshot("test-repo", "test-snap-1").get();
-
-        logger.info("--> make sure snapshot doesn't exist");
-        assertRequestBuilderThrows(client.admin().cluster().prepareGetSnapshots("test-repo").addSnapshots("test-snap-1"),
-            SnapshotMissingException.class);
-
-        logger.info("--> make sure that we can create the snapshot again");
-        createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap-1")
-            .setWaitForCompletion(true).setIndices("test-idx-*").get();
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
-            equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));
-    }
-
-    /** Tests that a snapshot with a corrupted global state file can still be deleted */
-    public void testDeleteSnapshotWithCorruptedGlobalState() throws Exception {
-        final Path repo = randomRepoPath();
-
-        createRepository("test-repo", "fs", Settings.builder()
-            .put("location", repo)
-            .put("chunk_size", randomIntBetween(100, 1000), ByteSizeUnit.BYTES));
-
-        createIndex("test-idx-1", "test-idx-2");
-        indexRandom(true,
-            client().prepareIndex("test-idx-1", "_doc").setSource("foo", "bar"),
-            client().prepareIndex("test-idx-2", "_doc").setSource("foo", "bar"),
-            client().prepareIndex("test-idx-2", "_doc").setSource("foo", "bar"));
-        flushAndRefresh("test-idx-1", "test-idx-2");
-
-        SnapshotInfo snapshotInfo = createFullSnapshot("test-repo", "test-snap");
-
-        final Path globalStatePath = repo.resolve("meta-" + snapshotInfo.snapshotId().getUUID() + ".dat");
-        if (randomBoolean()) {
-            // Delete the global state metadata file
-            IOUtils.deleteFilesIgnoringExceptions(globalStatePath);
-        } else {
-            // Truncate the global state metadata file
-            try (SeekableByteChannel outChan = Files.newByteChannel(globalStatePath, StandardOpenOption.WRITE)) {
-                outChan.truncate(randomInt(10));
-            }
-        }
-
-        List<SnapshotInfo> snapshotInfos = client().admin().cluster().prepareGetSnapshots("test-repo").get().getSnapshots();
-        assertThat(snapshotInfos.size(), equalTo(1));
-        assertThat(snapshotInfos.get(0).state(), equalTo(SnapshotState.SUCCESS));
-        assertThat(snapshotInfos.get(0).snapshotId().getName(), equalTo("test-snap"));
-
-        SnapshotsStatusResponse snapshotStatusResponse =
-            client().admin().cluster().prepareSnapshotStatus("test-repo").setSnapshots("test-snap").get();
-        assertThat(snapshotStatusResponse.getSnapshots(), hasSize(1));
-        assertThat(snapshotStatusResponse.getSnapshots().get(0).getSnapshot().getSnapshotId().getName(), equalTo("test-snap"));
-
-        assertAcked(client().admin().cluster().prepareDeleteSnapshot("test-repo", "test-snap").get());
-        assertRequestBuilderThrows(client().admin().cluster().prepareGetSnapshots("test-repo").addSnapshots("test-snap"),
-            SnapshotMissingException.class);
-        assertRequestBuilderThrows(client().admin().cluster().prepareSnapshotStatus("test-repo").addSnapshots("test-snap"),
-            SnapshotMissingException.class);
-
-        createFullSnapshot("test-repo", "test-snap");
-    }
-
-    public void testSnapshotWithMissingShardLevelIndexFile() throws Exception {
-        disableRepoConsistencyCheck("This test uses a purposely broken repository so it would fail consistency checks");
-
-        Path repo = randomRepoPath();
-        createRepository("test-repo", "fs", repo);
-
-        createIndex("test-idx-1", "test-idx-2");
-        logger.info("--> indexing some data");
-        indexRandom(true,
-            client().prepareIndex("test-idx-1", "_doc").setSource("foo", "bar"),
-            client().prepareIndex("test-idx-2", "_doc").setSource("foo", "bar"));
-
-        logger.info("--> creating snapshot");
-        client().admin().cluster().prepareCreateSnapshot("test-repo", "test-snap-1")
-            .setWaitForCompletion(true).setIndices("test-idx-*").get();
-
-        logger.info("--> deleting shard level index file");
-        final Path indicesPath = repo.resolve("indices");
-        for (IndexId indexId : getRepositoryData("test-repo").getIndices().values()) {
-            final Path shardGen;
-            try (Stream<Path> shardFiles = Files.list(indicesPath.resolve(indexId.getId()).resolve("0"))) {
-                shardGen = shardFiles.filter(file -> file.getFileName().toString().startsWith(BlobStoreRepository.INDEX_FILE_PREFIX))
-                        .findFirst().orElseThrow(() -> new AssertionError("Failed to find shard index blob"));
-            }
-            Files.delete(shardGen);
-        }
-
-        logger.info("--> creating another snapshot");
-        CreateSnapshotResponse createSnapshotResponse =
-            client().admin().cluster().prepareCreateSnapshot("test-repo", "test-snap-2")
-                .setWaitForCompletion(true).setIndices("test-idx-1").get();
-        assertEquals(createSnapshotResponse.getSnapshotInfo().successfulShards(),
-            createSnapshotResponse.getSnapshotInfo().totalShards() - 1);
-
-        logger.info("--> restoring the first snapshot, the repository should not have lost any shard data despite deleting index-N, " +
-                        "because it uses snap-*.data files and not the index-N to determine what files to restore");
-        client().admin().indices().prepareDelete("test-idx-1", "test-idx-2").get();
-        RestoreSnapshotResponse restoreSnapshotResponse =
-            client().admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap-1").setWaitForCompletion(true).get();
-        assertEquals(0, restoreSnapshotResponse.getRestoreInfo().failedShards());
-    }
-
     public void testSnapshotClosedIndex() throws Exception {
         Client client = client();
 
@@ -1414,121 +838,6 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
         assertThat(createSnapshotResponse.getSnapshotInfo().shardFailures().size(), equalTo(0));
     }
 
-    public void testRenameOnRestore() throws Exception {
-        Client client = client();
-
-        createRepository("test-repo", "fs");
-
-        createIndex("test-idx-1", "test-idx-2", "test-idx-3");
-        ensureGreen();
-
-        assertAcked(client.admin().indices().prepareAliases()
-                        .addAlias("test-idx-1", "alias-1", false)
-                        .addAlias("test-idx-2", "alias-2", false)
-                        .addAlias("test-idx-3", "alias-3", false)
-        );
-
-        indexRandomDocs("test-idx-1", 100);
-        indexRandomDocs("test-idx-2", 100);
-
-        logger.info("--> snapshot");
-        CreateSnapshotResponse createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap")
-            .setWaitForCompletion(true).setIndices("test-idx-1", "test-idx-2").get();
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
-            equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));
-
-        logger.info("--> restore indices with different names");
-        RestoreSnapshotResponse restoreSnapshotResponse = client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap")
-                .setRenamePattern("(.+)").setRenameReplacement("$1-copy").setWaitForCompletion(true).execute().actionGet();
-        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
-
-        assertDocCount("test-idx-1-copy", 100L);
-        assertDocCount("test-idx-2-copy", 100L);
-
-        logger.info("--> close just restored indices");
-        client.admin().indices().prepareClose("test-idx-1-copy", "test-idx-2-copy").get();
-
-        logger.info("--> and try to restore these indices again");
-        restoreSnapshotResponse = client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap")
-                .setRenamePattern("(.+)").setRenameReplacement("$1-copy").setWaitForCompletion(true).execute().actionGet();
-        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
-
-        assertDocCount("test-idx-1-copy", 100L);
-        assertDocCount("test-idx-2-copy", 100L);
-
-        logger.info("--> close indices");
-        assertAcked(client.admin().indices().prepareClose("test-idx-1", "test-idx-2-copy"));
-
-        logger.info("--> restore indices with different names");
-        restoreSnapshotResponse = client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap")
-                .setRenamePattern("(.+-2)").setRenameReplacement("$1-copy").setWaitForCompletion(true).execute().actionGet();
-        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
-
-        logger.info("--> delete indices");
-        cluster().wipeIndices("test-idx-1", "test-idx-1-copy", "test-idx-2", "test-idx-2-copy");
-
-        logger.info("--> try renaming indices using the same name");
-        try {
-            client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap").setRenamePattern("(.+)")
-                .setRenameReplacement("same-name").setWaitForCompletion(true).execute().actionGet();
-            fail("Shouldn't be here");
-        } catch (SnapshotRestoreException ex) {
-            // Expected
-        }
-
-        logger.info("--> try renaming indices using the same name");
-        try {
-            client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap").setRenamePattern("test-idx-2")
-                .setRenameReplacement("test-idx-1").setWaitForCompletion(true).execute().actionGet();
-            fail("Shouldn't be here");
-        } catch (SnapshotRestoreException ex) {
-            // Expected
-        }
-
-        logger.info("--> try renaming indices using invalid index name");
-        try {
-            client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap").setIndices("test-idx-1").setRenamePattern(".+")
-                .setRenameReplacement("__WRONG__").setWaitForCompletion(true).execute().actionGet();
-            fail("Shouldn't be here");
-        } catch (InvalidIndexNameException ex) {
-            // Expected
-        }
-
-        logger.info("--> try renaming indices into existing alias name");
-        try {
-            client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap").setIndices("test-idx-1").setRenamePattern(".+")
-                .setRenameReplacement("alias-3").setWaitForCompletion(true).execute().actionGet();
-            fail("Shouldn't be here");
-        } catch (InvalidIndexNameException ex) {
-            // Expected
-        }
-
-        logger.info("--> try renaming indices into existing alias of itself");
-        try {
-            client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap").setIndices("test-idx-1").setRenamePattern("test-idx")
-                .setRenameReplacement("alias").setWaitForCompletion(true).execute().actionGet();
-            fail("Shouldn't be here");
-        } catch (SnapshotRestoreException ex) {
-            // Expected
-        }
-
-        logger.info("--> try renaming indices into existing alias of another restored index");
-        try {
-            client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap").setIndices("test-idx-1", "test-idx-2")
-                .setRenamePattern("test-idx-1").setRenameReplacement("alias-2").setWaitForCompletion(true).execute().actionGet();
-            fail("Shouldn't be here");
-        } catch (SnapshotRestoreException ex) {
-            // Expected
-        }
-
-        logger.info("--> try renaming indices into existing alias of itself, but don't restore aliases ");
-        restoreSnapshotResponse = client.admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap")
-                .setIndices("test-idx-1").setRenamePattern("test-idx").setRenameReplacement("alias")
-                .setWaitForCompletion(true).setIncludeAliases(false).execute().actionGet();
-        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
-    }
-
     public void testMoveShardWhileSnapshotting() throws Exception {
         Client client = client();
         Path repositoryLocation = randomRepoPath();
@@ -1756,49 +1065,6 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
             .putNull(INDICES_RECOVERY_MAX_BYTES_PER_SEC_SETTING.getKey()).build()).get();
     }
 
-    public void testDynamicRestoreThrottling() throws Exception {
-        Client client = client();
-
-        createRepository("test-repo", "fs", Settings.builder()
-            .put("location", randomRepoPath()).put("compress", randomBoolean())
-            .put("chunk_size", 100, ByteSizeUnit.BYTES));
-
-        createIndexWithRandomDocs("test-idx", 100);
-
-        logger.info("--> snapshot");
-        client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap")
-            .setWaitForCompletion(true).setIndices("test-idx").get();
-
-        logger.info("--> delete index");
-        cluster().wipeIndices("test-idx");
-
-        logger.info("--> restore index");
-        client.admin().cluster().prepareUpdateSettings().setTransientSettings(Settings.builder()
-            .put(INDICES_RECOVERY_MAX_BYTES_PER_SEC_SETTING.getKey(), "100b").build()).get();
-        ActionFuture<RestoreSnapshotResponse> restoreSnapshotResponse = client.admin().cluster()
-            .prepareRestoreSnapshot("test-repo", "test-snap").setWaitForCompletion(true).execute();
-
-        // check if throttling is active
-        assertBusy(() -> {
-            long restorePause = 0L;
-            for (RepositoriesService repositoriesService : internalCluster().getDataNodeInstances(RepositoriesService.class)) {
-                restorePause += repositoriesService.repository("test-repo").getRestoreThrottleTimeInNanos();
-            }
-            assertThat(restorePause, greaterThan(TimeValue.timeValueSeconds(randomIntBetween(1, 5)).nanos()));
-            assertFalse(restoreSnapshotResponse.isDone());
-        }, 30, TimeUnit.SECONDS);
-
-        // run at full speed again
-        client.admin().cluster().prepareUpdateSettings().setTransientSettings(Settings.builder()
-            .putNull(INDICES_RECOVERY_MAX_BYTES_PER_SEC_SETTING.getKey()).build()).get();
-
-        // check that restore now completes quickly (i.e. within 10 seconds)
-        assertBusy(() -> assertTrue(restoreSnapshotResponse.isDone()));
-
-        assertThat(restoreSnapshotResponse.get().getRestoreInfo().totalShards(), greaterThan(0));
-        assertDocCount("test-idx", 100L);
-    }
-
     public void testSnapshotStatus() throws Exception {
         Client client = client();
         createRepository("test-repo", "mock",
@@ -2006,199 +1272,6 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
         }
     }
 
-    public void testChangeSettingsOnRestore() throws Exception {
-        Client client = client();
-
-        createRepository("test-repo", "fs");
-
-        logger.info("--> create test index with case-preserving search analyzer");
-
-        Settings.Builder indexSettings = Settings.builder()
-                .put(indexSettings())
-                .put(SETTING_NUMBER_OF_REPLICAS, between(0, 1))
-                .put(INDEX_REFRESH_INTERVAL_SETTING.getKey(), "10s")
-                .put("index.analysis.analyzer.my_analyzer.type", "custom")
-                .put("index.analysis.analyzer.my_analyzer.tokenizer", "standard");
-
-        assertAcked(prepareCreate("test-idx", 2, indexSettings));
-
-        int numberOfShards = getNumShards("test-idx").numPrimaries;
-        assertAcked(client().admin().indices().preparePutMapping("test-idx").setType("type1")
-            .setSource("field1", "type=text,analyzer=standard,search_analyzer=my_analyzer"));
-        final int numdocs = randomIntBetween(10, 100);
-        IndexRequestBuilder[] builders = new IndexRequestBuilder[numdocs];
-        for (int i = 0; i < builders.length; i++) {
-            builders[i] = client().prepareIndex("test-idx", "type1", Integer.toString(i)).setSource("field1", "Foo bar " + i);
-        }
-        indexRandom(true, builders);
-        flushAndRefresh();
-
-        assertHitCount(client.prepareSearch("test-idx").setSize(0).setQuery(matchQuery("field1", "foo")).get(), numdocs);
-        assertHitCount(client.prepareSearch("test-idx").setSize(0).setQuery(matchQuery("field1", "Foo")).get(), 0);
-        assertHitCount(client.prepareSearch("test-idx").setSize(0).setQuery(matchQuery("field1", "bar")).get(), numdocs);
-
-        logger.info("--> snapshot it");
-        CreateSnapshotResponse createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap")
-            .setWaitForCompletion(true).setIndices("test-idx").get();
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
-            equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));
-
-        logger.info("--> delete the index and recreate it while changing refresh interval and analyzer");
-        cluster().wipeIndices("test-idx");
-
-        Settings newIndexSettings = Settings.builder()
-                .put("refresh_interval", "5s")
-                .put("index.analysis.analyzer.my_analyzer.type", "standard")
-                .build();
-
-        Settings newIncorrectIndexSettings = Settings.builder()
-                .put(newIndexSettings)
-                .put(SETTING_NUMBER_OF_SHARDS, numberOfShards + 100)
-                .build();
-
-        logger.info("--> try restoring while changing the number of shards - should fail");
-        assertRequestBuilderThrows(client.admin().cluster()
-                .prepareRestoreSnapshot("test-repo", "test-snap")
-                .setIgnoreIndexSettings("index.analysis.*")
-                .setIndexSettings(newIncorrectIndexSettings)
-                .setWaitForCompletion(true), SnapshotRestoreException.class);
-
-        logger.info("--> try restoring while changing the number of replicas to a negative number - should fail");
-        Settings newIncorrectReplicasIndexSettings = Settings.builder()
-            .put(newIndexSettings)
-            .put(SETTING_NUMBER_OF_REPLICAS.substring(IndexMetadata.INDEX_SETTING_PREFIX.length()), randomIntBetween(-10, -1))
-            .build();
-        assertRequestBuilderThrows(client.admin().cluster()
-            .prepareRestoreSnapshot("test-repo", "test-snap")
-            .setIgnoreIndexSettings("index.analysis.*")
-            .setIndexSettings(newIncorrectReplicasIndexSettings)
-            .setWaitForCompletion(true), IllegalArgumentException.class);
-
-        logger.info("--> restore index with correct settings from the snapshot");
-        RestoreSnapshotResponse restoreSnapshotResponse = client.admin().cluster()
-                .prepareRestoreSnapshot("test-repo", "test-snap")
-                .setIgnoreIndexSettings("index.analysis.*")
-                .setIndexSettings(newIndexSettings)
-                .setWaitForCompletion(true).execute().actionGet();
-        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
-
-        logger.info("--> assert that correct settings are restored");
-        GetSettingsResponse getSettingsResponse = client.admin().indices().prepareGetSettings("test-idx").execute().actionGet();
-        assertThat(getSettingsResponse.getSetting("test-idx", INDEX_REFRESH_INTERVAL_SETTING.getKey()), equalTo("5s"));
-        // Make sure that number of shards didn't change
-        assertThat(getSettingsResponse.getSetting("test-idx", SETTING_NUMBER_OF_SHARDS), equalTo("" + numberOfShards));
-        assertThat(getSettingsResponse.getSetting("test-idx", "index.analysis.analyzer.my_analyzer.type"), equalTo("standard"));
-
-        assertHitCount(client.prepareSearch("test-idx").setSize(0).setQuery(matchQuery("field1", "Foo")).get(), numdocs);
-        assertHitCount(client.prepareSearch("test-idx").setSize(0).setQuery(matchQuery("field1", "bar")).get(), numdocs);
-
-        logger.info("--> delete the index and recreate it while deleting all index settings");
-        cluster().wipeIndices("test-idx");
-
-        logger.info("--> restore index with correct settings from the snapshot");
-        restoreSnapshotResponse = client.admin().cluster()
-                .prepareRestoreSnapshot("test-repo", "test-snap")
-                .setIgnoreIndexSettings("*") // delete everything we can delete
-                .setIndexSettings(newIndexSettings)
-                .setWaitForCompletion(true).execute().actionGet();
-        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
-
-        logger.info("--> assert that correct settings are restored and index is still functional");
-        getSettingsResponse = client.admin().indices().prepareGetSettings("test-idx").execute().actionGet();
-        assertThat(getSettingsResponse.getSetting("test-idx", INDEX_REFRESH_INTERVAL_SETTING.getKey()), equalTo("5s"));
-        // Make sure that number of shards didn't change
-        assertThat(getSettingsResponse.getSetting("test-idx", SETTING_NUMBER_OF_SHARDS), equalTo("" + numberOfShards));
-
-        assertHitCount(client.prepareSearch("test-idx").setSize(0).setQuery(matchQuery("field1", "Foo")).get(), numdocs);
-        assertHitCount(client.prepareSearch("test-idx").setSize(0).setQuery(matchQuery("field1", "bar")).get(), numdocs);
-    }
-
-    public void testRecreateBlocksOnRestore() throws Exception {
-        Client client = client();
-
-        createRepository("test-repo", "fs");
-
-        Settings.Builder indexSettings = Settings.builder()
-                .put(indexSettings())
-                .put(SETTING_NUMBER_OF_REPLICAS, between(0, 1))
-                .put(INDEX_REFRESH_INTERVAL_SETTING.getKey(), "10s");
-
-        logger.info("--> create index");
-        assertAcked(prepareCreate("test-idx", 2, indexSettings));
-
-        try {
-            List<String> initialBlockSettings = randomSubsetOf(randomInt(3),
-                    IndexMetadata.SETTING_BLOCKS_WRITE, IndexMetadata.SETTING_BLOCKS_METADATA, IndexMetadata.SETTING_READ_ONLY);
-            Settings.Builder initialSettingsBuilder = Settings.builder();
-            for (String blockSetting : initialBlockSettings) {
-                initialSettingsBuilder.put(blockSetting, true);
-            }
-            Settings initialSettings = initialSettingsBuilder.build();
-            logger.info("--> using initial block settings {}", initialSettings);
-
-            if (!initialSettings.isEmpty()) {
-                logger.info("--> apply initial blocks to index");
-                client().admin().indices().prepareUpdateSettings("test-idx").setSettings(initialSettingsBuilder).get();
-            }
-
-            logger.info("--> snapshot index");
-            CreateSnapshotResponse createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot("test-repo", "test-snap")
-                    .setWaitForCompletion(true).setIndices("test-idx").get();
-            assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
-            assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
-                equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));
-
-            logger.info("--> remove blocks and delete index");
-            disableIndexBlock("test-idx", IndexMetadata.SETTING_BLOCKS_METADATA);
-            disableIndexBlock("test-idx", IndexMetadata.SETTING_READ_ONLY);
-            disableIndexBlock("test-idx", IndexMetadata.SETTING_BLOCKS_WRITE);
-            disableIndexBlock("test-idx", IndexMetadata.SETTING_BLOCKS_READ);
-            cluster().wipeIndices("test-idx");
-
-            logger.info("--> restore index with additional block changes");
-            List<String> changeBlockSettings = randomSubsetOf(randomInt(4),
-                    IndexMetadata.SETTING_BLOCKS_METADATA, IndexMetadata.SETTING_BLOCKS_WRITE,
-                    IndexMetadata.SETTING_READ_ONLY, IndexMetadata.SETTING_BLOCKS_READ);
-            Settings.Builder changedSettingsBuilder = Settings.builder();
-            for (String blockSetting : changeBlockSettings) {
-                changedSettingsBuilder.put(blockSetting, randomBoolean());
-            }
-            Settings changedSettings = changedSettingsBuilder.build();
-            logger.info("--> applying changed block settings {}", changedSettings);
-
-            RestoreSnapshotResponse restoreSnapshotResponse = client.admin().cluster()
-                    .prepareRestoreSnapshot("test-repo", "test-snap")
-                    .setIndexSettings(changedSettings)
-                    .setWaitForCompletion(true).execute().actionGet();
-            assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
-
-            ClusterBlocks blocks = client.admin().cluster().prepareState().clear().setBlocks(true).get().getState().blocks();
-            // compute current index settings (as we cannot query them if they contain SETTING_BLOCKS_METADATA)
-            Settings mergedSettings = Settings.builder()
-                    .put(initialSettings)
-                    .put(changedSettings)
-                    .build();
-            logger.info("--> merged block settings {}", mergedSettings);
-
-            logger.info("--> checking consistency between settings and blocks");
-            assertThat(mergedSettings.getAsBoolean(IndexMetadata.SETTING_BLOCKS_METADATA, false),
-                    is(blocks.hasIndexBlock("test-idx", IndexMetadata.INDEX_METADATA_BLOCK)));
-            assertThat(mergedSettings.getAsBoolean(IndexMetadata.SETTING_BLOCKS_READ, false),
-                    is(blocks.hasIndexBlock("test-idx", IndexMetadata.INDEX_READ_BLOCK)));
-            assertThat(mergedSettings.getAsBoolean(IndexMetadata.SETTING_BLOCKS_WRITE, false),
-                    is(blocks.hasIndexBlock("test-idx", IndexMetadata.INDEX_WRITE_BLOCK)));
-            assertThat(mergedSettings.getAsBoolean(IndexMetadata.SETTING_READ_ONLY, false),
-                    is(blocks.hasIndexBlock("test-idx", IndexMetadata.INDEX_READ_ONLY_BLOCK)));
-        } finally {
-            logger.info("--> cleaning up blocks");
-            disableIndexBlock("test-idx", IndexMetadata.SETTING_BLOCKS_METADATA);
-            disableIndexBlock("test-idx", IndexMetadata.SETTING_READ_ONLY);
-            disableIndexBlock("test-idx", IndexMetadata.SETTING_BLOCKS_WRITE);
-            disableIndexBlock("test-idx", IndexMetadata.SETTING_BLOCKS_READ);
-        }
-    }
-
     public void testCloseOrDeleteIndexDuringSnapshot() throws Exception {
         disableRepoConsistencyCheck("This test intentionally leaves a broken repository");
 
@@ -2546,81 +1619,6 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
         assertAcked(client().admin().cluster().prepareDeleteSnapshot("test-repo", snapshotInfo.snapshotId().getName()).get());
     }
 
-    /**
-     * Tests that a shard snapshot with a corrupted shard index file can still be used for restore and incremental snapshots.
-     */
-    public void testSnapshotWithCorruptedShardIndexFile() throws Exception {
-        final Client client = client();
-        final Path repo = randomRepoPath();
-        final String indexName = "test-idx";
-        final int nDocs = randomIntBetween(1, 10);
-
-        logger.info("-->  creating index [{}] with [{}] documents in it", indexName, nDocs);
-        assertAcked(prepareCreate(indexName).setSettings(indexSettingsNoReplicas(1)));
-
-        final IndexRequestBuilder[] documents = new IndexRequestBuilder[nDocs];
-        for (int j = 0; j < nDocs; j++) {
-            documents[j] = client.prepareIndex(indexName, "_doc").setSource("foo", "bar");
-        }
-        indexRandom(true, documents);
-        flushAndRefresh();
-
-        createRepository("test-repo", "fs", repo);
-
-        final String snapshot1 = "test-snap-1";
-        final SnapshotInfo snapshotInfo = createFullSnapshot("test-repo", snapshot1);
-        assertThat(snapshotInfo.indices(), hasSize(1));
-
-        final RepositoryData repositoryData = getRepositoryData("test-repo");
-        final Map<String, IndexId> indexIds = repositoryData.getIndices();
-        assertThat(indexIds.size(), equalTo(1));
-
-        final IndexId corruptedIndex = indexIds.get(indexName);
-        final Path shardIndexFile = repo.resolve("indices")
-            .resolve(corruptedIndex.getId()).resolve("0")
-            .resolve("index-" + repositoryData.shardGenerations().getShardGen(corruptedIndex, 0));
-
-        logger.info("-->  truncating shard index file [{}]", shardIndexFile);
-        try (SeekableByteChannel outChan = Files.newByteChannel(shardIndexFile, StandardOpenOption.WRITE)) {
-            outChan.truncate(randomInt(10));
-        }
-
-        logger.info("-->  verifying snapshot state for [{}]", snapshot1);
-        List<SnapshotInfo> snapshotInfos = client().admin().cluster().prepareGetSnapshots("test-repo").get().getSnapshots();
-        assertThat(snapshotInfos.size(), equalTo(1));
-        assertThat(snapshotInfos.get(0).state(), equalTo(SnapshotState.SUCCESS));
-        assertThat(snapshotInfos.get(0).snapshotId().getName(), equalTo(snapshot1));
-
-        logger.info("-->  deleting index [{}]", indexName);
-        assertAcked(client().admin().indices().prepareDelete(indexName));
-
-        logger.info("-->  restoring snapshot [{}]", snapshot1);
-        client().admin().cluster().prepareRestoreSnapshot("test-repo", snapshot1)
-            .setRestoreGlobalState(randomBoolean())
-            .setWaitForCompletion(true)
-            .get();
-        ensureGreen();
-
-        assertDocCount(indexName, nDocs);
-
-        logger.info("-->  indexing [{}] more documents into [{}]", nDocs, indexName);
-        for (int j = 0; j < nDocs; j++) {
-            documents[j] = client.prepareIndex(indexName, "_doc").setSource("foo2", "bar2");
-        }
-        indexRandom(true, documents);
-
-        final String snapshot2 = "test-snap-2";
-        logger.info("-->  creating snapshot [{}]", snapshot2);
-        final SnapshotInfo snapshotInfo2 = client().admin().cluster().prepareCreateSnapshot("test-repo", snapshot2)
-            .setWaitForCompletion(true)
-            .get()
-            .getSnapshotInfo();
-        assertThat(snapshotInfo2.state(), equalTo(SnapshotState.PARTIAL));
-        assertThat(snapshotInfo2.failedShards(), equalTo(1));
-        assertThat(snapshotInfo2.successfulShards(), equalTo(snapshotInfo.totalShards() - 1));
-        assertThat(snapshotInfo2.indices(), hasSize(1));
-    }
-
     public void testCannotCreateSnapshotsWithSameName() throws Exception {
         final String repositoryName = "test-repo";
         final String snapshotName = "test-snap";
@@ -2675,141 +1673,6 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
         assertThat(createSnapshotResponse.getSnapshotInfo().snapshotId().getName(), equalTo(snapshotName));
     }
 
-    public void testGetSnapshotsRequest() throws Exception {
-        final String repositoryName = "test-repo";
-        final String indexName = "test-idx";
-        final Client client = client();
-
-        createRepository(repositoryName, "mock", Settings.builder()
-            .put("location", randomRepoPath()).put("compress", false)
-            .put("chunk_size", randomIntBetween(100, 1000), ByteSizeUnit.BYTES).put("wait_after_unblock", 200));
-
-        logger.info("--> get snapshots on an empty repository");
-        expectThrows(SnapshotMissingException.class, () -> client.admin()
-                                                                 .cluster()
-                                                                 .prepareGetSnapshots(repositoryName)
-                                                                 .addSnapshots("non-existent-snapshot")
-                                                                 .get());
-        // with ignore unavailable set to true, should not throw an exception
-        GetSnapshotsResponse getSnapshotsResponse = client.admin()
-                                                          .cluster()
-                                                          .prepareGetSnapshots(repositoryName)
-                                                          .setIgnoreUnavailable(true)
-                                                          .addSnapshots("non-existent-snapshot")
-                                                          .get();
-        assertThat(getSnapshotsResponse.getSnapshots().size(), equalTo(0));
-
-        logger.info("--> creating an index and indexing documents");
-        // Create index on 2 nodes and make sure each node has a primary by setting no replicas
-        assertAcked(prepareCreate(indexName, 1, Settings.builder().put("number_of_replicas", 0)));
-        ensureGreen();
-        indexRandomDocs(indexName, 10);
-
-        // make sure we return only the in-progress snapshot when taking the first snapshot on a clean repository
-        // take initial snapshot with a block, making sure we only get 1 in-progress snapshot returned
-        // block a node so the create snapshot operation can remain in progress
-        final String initialBlockedNode = blockNodeWithIndex(repositoryName, indexName);
-        client.admin().cluster().prepareCreateSnapshot(repositoryName, "snap-on-empty-repo")
-                .setWaitForCompletion(false)
-                .setIndices(indexName)
-                .get();
-        waitForBlock(initialBlockedNode, repositoryName, TimeValue.timeValueSeconds(60)); // wait for block to kick in
-        getSnapshotsResponse = client.admin().cluster()
-                                   .prepareGetSnapshots("test-repo")
-                                   .setSnapshots(randomFrom("_all", "_current", "snap-on-*", "*-on-empty-repo", "snap-on-empty-repo"))
-                                   .get();
-        assertEquals(1, getSnapshotsResponse.getSnapshots().size());
-        assertEquals("snap-on-empty-repo", getSnapshotsResponse.getSnapshots().get(0).snapshotId().getName());
-        unblockNode(repositoryName, initialBlockedNode); // unblock node
-        client.admin().cluster().prepareDeleteSnapshot(repositoryName, "snap-on-empty-repo").get();
-
-        final int numSnapshots = randomIntBetween(1, 3) + 1;
-        logger.info("--> take {} snapshot(s)", numSnapshots - 1);
-        final String[] snapshotNames = new String[numSnapshots];
-        for (int i = 0; i < numSnapshots - 1; i++) {
-            final String snapshotName = randomAlphaOfLength(8).toLowerCase(Locale.ROOT);
-            CreateSnapshotResponse createSnapshotResponse = client.admin()
-                                                                  .cluster()
-                                                                  .prepareCreateSnapshot(repositoryName, snapshotName)
-                                                                  .setWaitForCompletion(true)
-                                                                  .setIndices(indexName)
-                                                                  .get();
-            assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
-            snapshotNames[i] = snapshotName;
-        }
-        logger.info("--> take another snapshot to be in-progress");
-        // add documents so there are data files to block on
-        for (int i = 10; i < 20; i++) {
-            index(indexName, "_doc", Integer.toString(i), "foo", "bar" + i);
-        }
-        refresh();
-
-        final String inProgressSnapshot = randomAlphaOfLength(8).toLowerCase(Locale.ROOT);
-        snapshotNames[numSnapshots - 1] = inProgressSnapshot;
-        // block a node so the create snapshot operation can remain in progress
-        final String blockedNode = blockNodeWithIndex(repositoryName, indexName);
-        client.admin().cluster().prepareCreateSnapshot(repositoryName, inProgressSnapshot)
-                                .setWaitForCompletion(false)
-                                .setIndices(indexName)
-                                .get();
-        waitForBlock(blockedNode, repositoryName, TimeValue.timeValueSeconds(60)); // wait for block to kick in
-
-        logger.info("--> get all snapshots with a current in-progress");
-        // with ignore unavailable set to true, should not throw an exception
-        final List<String> snapshotsToGet = new ArrayList<>();
-        if (randomBoolean()) {
-            // use _current plus the individual names of the finished snapshots
-            snapshotsToGet.add("_current");
-            for (int i = 0; i < numSnapshots - 1; i++) {
-                snapshotsToGet.add(snapshotNames[i]);
-            }
-        } else {
-            snapshotsToGet.add("_all");
-        }
-        getSnapshotsResponse = client.admin().cluster()
-                                             .prepareGetSnapshots(repositoryName)
-                                             .setSnapshots(snapshotsToGet.toArray(Strings.EMPTY_ARRAY))
-                                             .get();
-        List<String> sortedNames = Arrays.asList(snapshotNames);
-        Collections.sort(sortedNames);
-        assertThat(getSnapshotsResponse.getSnapshots().size(), equalTo(numSnapshots));
-        assertThat(getSnapshotsResponse.getSnapshots().stream()
-                                                      .map(s -> s.snapshotId().getName())
-                                                      .sorted()
-                                                      .collect(Collectors.toList()), equalTo(sortedNames));
-
-        getSnapshotsResponse = client.admin().cluster()
-                                   .prepareGetSnapshots(repositoryName)
-                                   .addSnapshots(snapshotNames)
-                                   .get();
-        sortedNames = Arrays.asList(snapshotNames);
-        Collections.sort(sortedNames);
-        assertThat(getSnapshotsResponse.getSnapshots().size(), equalTo(numSnapshots));
-        assertThat(getSnapshotsResponse.getSnapshots().stream()
-                                                      .map(s -> s.snapshotId().getName())
-                                                      .sorted()
-                                                      .collect(Collectors.toList()), equalTo(sortedNames));
-
-        logger.info("--> make sure duplicates are not returned in the response");
-        String regexName = snapshotNames[randomIntBetween(0, numSnapshots - 1)];
-        final int splitPos = regexName.length() / 2;
-        final String firstRegex = regexName.substring(0, splitPos) + "*";
-        final String secondRegex = "*" + regexName.substring(splitPos);
-        getSnapshotsResponse = client.admin().cluster()
-                                             .prepareGetSnapshots(repositoryName)
-                                             .addSnapshots(snapshotNames)
-                                             .addSnapshots(firstRegex, secondRegex)
-                                             .get();
-        assertThat(getSnapshotsResponse.getSnapshots().size(), equalTo(numSnapshots));
-        assertThat(getSnapshotsResponse.getSnapshots().stream()
-                                                      .map(s -> s.snapshotId().getName())
-                                                      .sorted()
-                                                      .collect(Collectors.toList()), equalTo(sortedNames));
-
-        unblockNode(repositoryName, blockedNode); // unblock node
-        waitForCompletion(repositoryName, inProgressSnapshot, TimeValue.timeValueSeconds(60));
-    }
-
     /**
      * This test ensures that when a shard is removed from a node (perhaps due to the node
      * leaving the cluster, then returning), all snapshotting of that shard is aborted, so
@@ -2916,23 +1779,6 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
         assertEquals(SnapshotState.SUCCESS, getSnapshotsResponse.getSnapshots().get(0).state());
     }
 
-    public void testSnapshotStatusOnFailedSnapshot() throws Exception {
-        String repoName = "test-repo";
-        createRepository(repoName, "fs");
-        final String snapshot = "test-snap-1";
-        addBwCFailedSnapshot(repoName, snapshot, Collections.emptyMap());
-
-        logger.info("--> creating good index");
-        assertAcked(prepareCreate("test-idx-good").setSettings(indexSettingsNoReplicas(1)));
-        ensureGreen();
-        indexRandomDocs("test-idx-good", randomIntBetween(1, 5));
-
-        final SnapshotsStatusResponse snapshotsStatusResponse =
-                client().admin().cluster().prepareSnapshotStatus(repoName).setSnapshots(snapshot).get();
-        assertEquals(1, snapshotsStatusResponse.getSnapshots().size());
-        assertEquals(State.FAILED, snapshotsStatusResponse.getSnapshots().get(0).getState());
-    }
-
     public void testGetSnapshotsFromIndexBlobOnly() throws Exception {
         logger.info("--> creating repository");
         final Path repoPath = randomRepoPath();
@@ -3072,160 +1918,6 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
         assertThat(shardStats.getSeqNoStats().getMaxSeqNo(), equalTo(15L));
     }
 
-    public void testParallelRestoreOperations() {
-        String indexName1 = "testindex1";
-        String indexName2 = "testindex2";
-        String repoName = "test-restore-snapshot-repo";
-        String snapshotName1 = "test-restore-snapshot1";
-        String snapshotName2 = "test-restore-snapshot2";
-        Path absolutePath = randomRepoPath().toAbsolutePath();
-        logger.info("Path [{}]", absolutePath);
-        String restoredIndexName1 = indexName1 + "-restored";
-        String restoredIndexName2 = indexName2 + "-restored";
-        String typeName = "actions";
-        String expectedValue = "expected";
-
-        Client client = client();
-        // Write a document
-        String docId = Integer.toString(randomInt());
-        index(indexName1, typeName, docId, "value", expectedValue);
-
-        String docId2 = Integer.toString(randomInt());
-        index(indexName2, typeName, docId2, "value", expectedValue);
-
-        createRepository(repoName, "fs", absolutePath);
-
-        logger.info("--> snapshot");
-        CreateSnapshotResponse createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot(repoName, snapshotName1)
-            .setWaitForCompletion(true)
-            .setIndices(indexName1)
-            .get();
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
-            equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));
-        assertThat(createSnapshotResponse.getSnapshotInfo().state(), equalTo(SnapshotState.SUCCESS));
-
-        CreateSnapshotResponse createSnapshotResponse2 = client.admin().cluster().prepareCreateSnapshot(repoName, snapshotName2)
-            .setWaitForCompletion(true)
-            .setIndices(indexName2)
-            .get();
-        assertThat(createSnapshotResponse2.getSnapshotInfo().successfulShards(), greaterThan(0));
-        assertThat(createSnapshotResponse2.getSnapshotInfo().successfulShards(),
-            equalTo(createSnapshotResponse2.getSnapshotInfo().totalShards()));
-        assertThat(createSnapshotResponse2.getSnapshotInfo().state(), equalTo(SnapshotState.SUCCESS));
-
-        RestoreSnapshotResponse restoreSnapshotResponse1 = client.admin().cluster().prepareRestoreSnapshot(repoName, snapshotName1)
-            .setWaitForCompletion(false)
-            .setRenamePattern(indexName1)
-            .setRenameReplacement(restoredIndexName1)
-            .get();
-        RestoreSnapshotResponse restoreSnapshotResponse2 = client.admin().cluster().prepareRestoreSnapshot(repoName, snapshotName2)
-            .setWaitForCompletion(false)
-            .setRenamePattern(indexName2)
-            .setRenameReplacement(restoredIndexName2)
-            .get();
-        assertThat(restoreSnapshotResponse1.status(), equalTo(RestStatus.ACCEPTED));
-        assertThat(restoreSnapshotResponse2.status(), equalTo(RestStatus.ACCEPTED));
-        ensureGreen(restoredIndexName1, restoredIndexName2);
-        assertThat(client.prepareGet(restoredIndexName1, typeName, docId).get().isExists(), equalTo(true));
-        assertThat(client.prepareGet(restoredIndexName2, typeName, docId2).get().isExists(), equalTo(true));
-    }
-
-    public void testParallelRestoreOperationsFromSingleSnapshot() throws Exception {
-        String indexName1 = "testindex1";
-        String indexName2 = "testindex2";
-        String repoName = "test-restore-snapshot-repo";
-        String snapshotName = "test-restore-snapshot";
-        Path absolutePath = randomRepoPath().toAbsolutePath();
-        logger.info("Path [{}]", absolutePath);
-        String restoredIndexName1 = indexName1 + "-restored";
-        String restoredIndexName2 = indexName2 + "-restored";
-        String typeName = "actions";
-        String expectedValue = "expected";
-
-        Client client = client();
-        // Write a document
-        String docId = Integer.toString(randomInt());
-        index(indexName1, typeName, docId, "value", expectedValue);
-
-        String docId2 = Integer.toString(randomInt());
-        index(indexName2, typeName, docId2, "value", expectedValue);
-
-        createRepository(repoName, "fs", absolutePath);
-
-        logger.info("--> snapshot");
-        CreateSnapshotResponse createSnapshotResponse = client.admin().cluster().prepareCreateSnapshot(repoName, snapshotName)
-            .setWaitForCompletion(true)
-            .setIndices(indexName1, indexName2)
-            .get();
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
-            equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));
-        assertThat(createSnapshotResponse.getSnapshotInfo().state(), equalTo(SnapshotState.SUCCESS));
-
-        ActionFuture<RestoreSnapshotResponse> restoreSnapshotResponse1 = client.admin().cluster()
-            .prepareRestoreSnapshot(repoName, snapshotName)
-            .setIndices(indexName1)
-            .setRenamePattern(indexName1)
-            .setRenameReplacement(restoredIndexName1)
-            .execute();
-
-        boolean sameSourceIndex = randomBoolean();
-
-        ActionFuture<RestoreSnapshotResponse> restoreSnapshotResponse2 = client.admin().cluster()
-            .prepareRestoreSnapshot(repoName, snapshotName)
-            .setIndices(sameSourceIndex ? indexName1 : indexName2)
-            .setRenamePattern(sameSourceIndex ? indexName1 : indexName2)
-            .setRenameReplacement(restoredIndexName2)
-            .execute();
-        assertThat(restoreSnapshotResponse1.get().status(), equalTo(RestStatus.ACCEPTED));
-        assertThat(restoreSnapshotResponse2.get().status(), equalTo(RestStatus.ACCEPTED));
-        ensureGreen(restoredIndexName1, restoredIndexName2);
-        assertThat(client.prepareGet(restoredIndexName1, typeName, docId).get().isExists(), equalTo(true));
-        assertThat(client.prepareGet(restoredIndexName2, typeName, sameSourceIndex ? docId : docId2).get().isExists(), equalTo(true));
-    }
-
-    public void testRestoreIncreasesPrimaryTerms() {
-        final String indexName = randomAlphaOfLengthBetween(5, 10).toLowerCase(Locale.ROOT);
-        createIndex(indexName, indexSettingsNoReplicas(2).build());
-        ensureGreen(indexName);
-
-        if (randomBoolean()) {
-            // open and close the index to increase the primary terms
-            for (int i = 0; i < randomInt(3); i++) {
-                assertAcked(client().admin().indices().prepareClose(indexName));
-                assertAcked(client().admin().indices().prepareOpen(indexName));
-            }
-        }
-
-        final IndexMetadata indexMetadata = client().admin().cluster().prepareState().clear().setIndices(indexName)
-            .setMetadata(true).get().getState().metadata().index(indexName);
-        assertThat(indexMetadata.getSettings().get(IndexMetadata.SETTING_HISTORY_UUID), nullValue());
-        final int numPrimaries = getNumShards(indexName).numPrimaries;
-        final Map<Integer, Long> primaryTerms = IntStream.range(0, numPrimaries)
-            .boxed().collect(Collectors.toMap(shardId -> shardId, indexMetadata::primaryTerm));
-
-        createRepository("test-repo", "fs");
-        final CreateSnapshotResponse createSnapshotResponse = client().admin().cluster().prepareCreateSnapshot("test-repo", "test-snap")
-            .setWaitForCompletion(true).setIndices(indexName).get();
-        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), equalTo(numPrimaries));
-        assertThat(createSnapshotResponse.getSnapshotInfo().failedShards(), equalTo(0));
-
-        assertAcked(client().admin().indices().prepareClose(indexName));
-
-        final RestoreSnapshotResponse restoreSnapshotResponse = client().admin().cluster().prepareRestoreSnapshot("test-repo", "test-snap")
-            .setWaitForCompletion(true).get();
-        assertThat(restoreSnapshotResponse.getRestoreInfo().successfulShards(), equalTo(numPrimaries));
-        assertThat(restoreSnapshotResponse.getRestoreInfo().failedShards(), equalTo(0));
-
-        final IndexMetadata restoredIndexMetadata = client().admin().cluster().prepareState().clear().setIndices(indexName)
-            .setMetadata(true).get().getState().metadata().index(indexName);
-        for (int shardId = 0; shardId < numPrimaries; shardId++) {
-            assertThat(restoredIndexMetadata.primaryTerm(shardId), greaterThan(primaryTerms.get(shardId)));
-        }
-        assertThat(restoredIndexMetadata.getSettings().get(IndexMetadata.SETTING_HISTORY_UUID), notNullValue());
-    }
-
     public void testSnapshotDifferentIndicesBySameName() throws InterruptedException {
         String indexName = "testindex";
         String repoName = "test-repo";
@@ -3459,51 +2151,6 @@ public class SharedClusterSnapshotRestoreIT extends AbstractSnapshotIntegTestCas
         assertEquals(getRepositoryData(repoName).getGenId(), repoGenInIndexLatest3);
     }
 
-    public void testAllowEnableSoftDeletesDuringRestore() throws Exception {
-        createRepository("test-repo", "fs");
-        final Settings.Builder settings = Settings.builder();
-        settings.put(INDEX_SOFT_DELETES_SETTING.getKey(), false);
-        createIndex("test-index", settings.build());
-        ensureGreen();
-        int numDocs = 0;
-        if (randomBoolean()) {
-            numDocs = between(1, 100);
-            indexRandomDocs("test-index", numDocs);
-            flush("test-index");
-        }
-        client().admin().cluster().prepareCreateSnapshot("test-repo", "test-snapshot")
-            .setIndices("test-index").setWaitForCompletion(true).get();
-        client().admin().cluster().prepareRestoreSnapshot("test-repo", "test-snapshot")
-            .setIndexSettings(Settings.builder().put(INDEX_SOFT_DELETES_SETTING.getKey(), true))
-            .setRenamePattern("test-index").setRenameReplacement("new-index")
-            .setWaitForCompletion(true)
-            .get();
-        ensureGreen("new-index");
-        assertDocCount("new-index", numDocs);
-    }
-
-    public void testForbidDisableSoftDeletesDuringRestore() throws Exception {
-        createRepository("test-repo", "fs");
-        final Settings.Builder settings = Settings.builder();
-        if (randomBoolean()) {
-            settings.put(INDEX_SOFT_DELETES_SETTING.getKey(), true);
-        }
-        createIndex("test-index", settings.build());
-        ensureGreen();
-        if (randomBoolean()) {
-            indexRandomDocs("test-index", between(0, 100));
-            flush("test-index");
-        }
-        client().admin().cluster().prepareCreateSnapshot("test-repo", "snapshot-0")
-            .setIndices("test-index").setWaitForCompletion(true).get();
-        final SnapshotRestoreException restoreError = expectThrows(SnapshotRestoreException.class,
-            () -> client().admin().cluster().prepareRestoreSnapshot("test-repo", "snapshot-0")
-                .setIndexSettings(Settings.builder().put(INDEX_SOFT_DELETES_SETTING.getKey(), false))
-                .setRenamePattern("test-index").setRenameReplacement("new-index")
-                .get());
-        assertThat(restoreError.getMessage(), containsString("cannot disable setting [index.soft_deletes.enabled] on restore"));
-    }
-
     private void verifySnapshotInfo(final GetSnapshotsResponse response, final Map<String, List<String>> indicesPerSnapshot) {
         for (SnapshotInfo snapshotInfo : response.getSnapshots()) {
             final List<String> expected = snapshotInfo.indices();
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/snapshots/SnapshotCustomPluginStateIT.java b/server/src/internalClusterTest/java/org/elasticsearch/snapshots/SnapshotCustomPluginStateIT.java
new file mode 100644
index 00000000000..d54a97bb852
--- /dev/null
+++ b/server/src/internalClusterTest/java/org/elasticsearch/snapshots/SnapshotCustomPluginStateIT.java
@@ -0,0 +1,223 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch 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.elasticsearch.snapshots;
+
+import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotResponse;
+import org.elasticsearch.action.admin.cluster.snapshots.restore.RestoreSnapshotResponse;
+import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotStatus;
+import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusResponse;
+import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptResponse;
+import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
+import org.elasticsearch.action.ingest.DeletePipelineRequest;
+import org.elasticsearch.action.ingest.GetPipelineResponse;
+import org.elasticsearch.common.bytes.BytesArray;
+import org.elasticsearch.common.bytes.BytesReference;
+import org.elasticsearch.common.xcontent.XContentFactory;
+import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.ingest.IngestTestPlugin;
+import org.elasticsearch.plugins.Plugin;
+import org.elasticsearch.script.MockScriptEngine;
+import org.elasticsearch.script.StoredScriptsIT;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
+import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
+import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertIndexTemplateExists;
+import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertIndexTemplateMissing;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.greaterThan;
+
+public class SnapshotCustomPluginStateIT extends AbstractSnapshotIntegTestCase {
+
+    @Override
+    protected Collection<Class<? extends Plugin>> nodePlugins() {
+        return Arrays.asList(IngestTestPlugin.class, StoredScriptsIT.CustomScriptPlugin.class);
+    }
+
+    public void testIncludeGlobalState() throws Exception {
+        createRepository("test-repo", "fs");
+
+        boolean testTemplate = randomBoolean();
+        boolean testPipeline = randomBoolean();
+        boolean testScript = (testTemplate == false && testPipeline == false) || randomBoolean(); // At least something should be stored
+
+        if(testTemplate) {
+            logger.info("-->  creating test template");
+            assertThat(client().admin().indices()
+                    .preparePutTemplate("test-template")
+                    .setPatterns(Collections.singletonList("te*"))
+                    .addMapping("_doc", XContentFactory.jsonBuilder()
+                            .startObject()
+                            .startObject("_doc")
+                            .startObject("properties")
+                            .startObject("field1")
+                            .field("type", "text")
+                            .field("store", true)
+                            .endObject()
+                            .startObject("field2")
+                            .field("type", "keyword")
+                            .field("store", true)
+                            .endObject()
+                            .endObject()
+                            .endObject()
+                            .endObject())
+                    .get().isAcknowledged(), equalTo(true));
+        }
+
+        if(testPipeline) {
+            logger.info("-->  creating test pipeline");
+            BytesReference pipelineSource = BytesReference.bytes(jsonBuilder().startObject()
+                    .field("description", "my_pipeline")
+                    .startArray("processors")
+                    .startObject()
+                    .startObject("test")
+                    .endObject()
+                    .endObject()
+                    .endArray()
+                    .endObject());
+            assertAcked(clusterAdmin().preparePutPipeline("barbaz", pipelineSource, XContentType.JSON).get());
+        }
+
+        if(testScript) {
+            logger.info("-->  creating test script");
+            assertAcked(clusterAdmin().preparePutStoredScript()
+                    .setId("foobar")
+                    .setContent(new BytesArray(
+                            "{\"script\": { \"lang\": \"" + MockScriptEngine.NAME + "\", \"source\": \"1\"} }"), XContentType.JSON));
+        }
+
+        logger.info("--> snapshot without global state");
+        CreateSnapshotResponse createSnapshotResponse = clusterAdmin()
+                .prepareCreateSnapshot("test-repo", "test-snap-no-global-state").setIndices().setIncludeGlobalState(false)
+                .setWaitForCompletion(true).get();
+        assertThat(createSnapshotResponse.getSnapshotInfo().totalShards(), equalTo(0));
+        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), equalTo(0));
+        assertThat(getSnapshot("test-repo", "test-snap-no-global-state").state(), equalTo(SnapshotState.SUCCESS));
+        SnapshotsStatusResponse snapshotsStatusResponse = clusterAdmin().prepareSnapshotStatus("test-repo")
+                .addSnapshots("test-snap-no-global-state").get();
+        assertThat(snapshotsStatusResponse.getSnapshots().size(), equalTo(1));
+        SnapshotStatus snapshotStatus = snapshotsStatusResponse.getSnapshots().get(0);
+        assertThat(snapshotStatus.includeGlobalState(), equalTo(false));
+
+        logger.info("--> snapshot with global state");
+        createSnapshotResponse = clusterAdmin().prepareCreateSnapshot("test-repo", "test-snap-with-global-state")
+                .setIndices().setIncludeGlobalState(true).setWaitForCompletion(true).get();
+        assertThat(createSnapshotResponse.getSnapshotInfo().totalShards(), equalTo(0));
+        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), equalTo(0));
+        assertThat(getSnapshot("test-repo", "test-snap-with-global-state").state(), equalTo(SnapshotState.SUCCESS));
+        snapshotsStatusResponse = clusterAdmin().prepareSnapshotStatus("test-repo")
+                .addSnapshots("test-snap-with-global-state").get();
+        assertThat(snapshotsStatusResponse.getSnapshots().size(), equalTo(1));
+        snapshotStatus = snapshotsStatusResponse.getSnapshots().get(0);
+        assertThat(snapshotStatus.includeGlobalState(), equalTo(true));
+
+        if (testTemplate) {
+            logger.info("-->  delete test template");
+            cluster().wipeTemplates("test-template");
+            GetIndexTemplatesResponse getIndexTemplatesResponse = client().admin().indices().prepareGetTemplates().get();
+            assertIndexTemplateMissing(getIndexTemplatesResponse, "test-template");
+        }
+
+        if (testPipeline) {
+            logger.info("-->  delete test pipeline");
+            assertAcked(clusterAdmin().deletePipeline(new DeletePipelineRequest("barbaz")).get());
+        }
+
+        if (testScript) {
+            logger.info("-->  delete test script");
+            assertAcked(clusterAdmin().prepareDeleteStoredScript("foobar").get());
+        }
+
+        logger.info("--> try restoring cluster state from snapshot without global state");
+        RestoreSnapshotResponse restoreSnapshotResponse = clusterAdmin()
+                .prepareRestoreSnapshot("test-repo", "test-snap-no-global-state")
+                .setWaitForCompletion(true).setRestoreGlobalState(true).execute().actionGet();
+        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), equalTo(0));
+
+        logger.info("--> check that template wasn't restored");
+        GetIndexTemplatesResponse getIndexTemplatesResponse = client().admin().indices().prepareGetTemplates().get();
+        assertIndexTemplateMissing(getIndexTemplatesResponse, "test-template");
+
+        logger.info("--> restore cluster state");
+        restoreSnapshotResponse = clusterAdmin().prepareRestoreSnapshot("test-repo", "test-snap-with-global-state")
+                .setWaitForCompletion(true).setRestoreGlobalState(true).execute().actionGet();
+        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), equalTo(0));
+
+        if (testTemplate) {
+            logger.info("--> check that template is restored");
+            getIndexTemplatesResponse = client().admin().indices().prepareGetTemplates().get();
+            assertIndexTemplateExists(getIndexTemplatesResponse, "test-template");
+        }
+
+        if (testPipeline) {
+            logger.info("--> check that pipeline is restored");
+            GetPipelineResponse getPipelineResponse = clusterAdmin().prepareGetPipeline("barbaz").get();
+            assertTrue(getPipelineResponse.isFound());
+        }
+
+        if (testScript) {
+            logger.info("--> check that script is restored");
+            GetStoredScriptResponse getStoredScriptResponse = clusterAdmin().prepareGetStoredScript("foobar").get();
+            assertNotNull(getStoredScriptResponse.getSource());
+        }
+
+        createIndexWithRandomDocs("test-idx", 100);
+
+        logger.info("--> snapshot without global state but with indices");
+        createSnapshotResponse = clusterAdmin().prepareCreateSnapshot("test-repo", "test-snap-no-global-state-with-index")
+                .setIndices("test-idx").setIncludeGlobalState(false).setWaitForCompletion(true).get();
+        assertThat(createSnapshotResponse.getSnapshotInfo().totalShards(), greaterThan(0));
+        assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(),
+                equalTo(createSnapshotResponse.getSnapshotInfo().totalShards()));
+        assertThat(getSnapshot("test-repo", "test-snap-no-global-state-with-index").state(), equalTo(SnapshotState.SUCCESS));
+
+        logger.info("-->  delete global state and index ");
+        cluster().wipeIndices("test-idx");
+        if (testTemplate) {
+            cluster().wipeTemplates("test-template");
+        }
+        if (testPipeline) {
+            assertAcked(clusterAdmin().deletePipeline(new DeletePipelineRequest("barbaz")).get());
+        }
+
+        if (testScript) {
+            assertAcked(clusterAdmin().prepareDeleteStoredScript("foobar").get());
+        }
+
+        getIndexTemplatesResponse = client().admin().indices().prepareGetTemplates().get();
+        assertIndexTemplateMissing(getIndexTemplatesResponse, "test-template");
+
+        logger.info("--> try restoring index and cluster state from snapshot without global state");
+        restoreSnapshotResponse = clusterAdmin().prepareRestoreSnapshot("test-repo", "test-snap-no-global-state-with-index")
+                .setWaitForCompletion(true).setRestoreGlobalState(true).execute().actionGet();
+        assertThat(restoreSnapshotResponse.getRestoreInfo().totalShards(), greaterThan(0));
+        assertThat(restoreSnapshotResponse.getRestoreInfo().failedShards(), equalTo(0));
+
+        logger.info("--> check that global state wasn't restored but index was");
+        getIndexTemplatesResponse = client().admin().indices().prepareGetTemplates().get();
+        assertIndexTemplateMissing(getIndexTemplatesResponse, "test-template");
+        assertFalse(clusterAdmin().prepareGetPipeline("barbaz").get().isFound());
+        assertNull(clusterAdmin().prepareGetStoredScript("foobar").get().getSource());
+        assertDocCount("test-idx", 100L);
+    }
+}
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/snapshots/SnapshotStatusApisIT.java b/server/src/internalClusterTest/java/org/elasticsearch/snapshots/SnapshotStatusApisIT.java
index 0e159546a78..bf27e1a57fa 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/snapshots/SnapshotStatusApisIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/snapshots/SnapshotStatusApisIT.java
@@ -22,23 +22,34 @@ import org.elasticsearch.Version;
 import org.elasticsearch.action.ActionFuture;
 import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotResponse;
 import org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsRequest;
+import org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsResponse;
 import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotIndexShardStage;
 import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotIndexShardStatus;
 import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotStats;
 import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotStatus;
 import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRequest;
+import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusResponse;
 import org.elasticsearch.client.Client;
 import org.elasticsearch.cluster.SnapshotsInProgress;
+import org.elasticsearch.common.Strings;
 import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.unit.ByteSizeUnit;
 import org.elasticsearch.common.unit.TimeValue;
 import org.elasticsearch.core.internal.io.IOUtils;
 import org.elasticsearch.repositories.blobstore.BlobStoreRepository;
+import org.elasticsearch.threadpool.ThreadPool;
 
 import java.io.IOException;
 import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
+import java.util.Locale;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
+import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.greaterThan;
 import static org.hamcrest.Matchers.hasSize;
@@ -46,6 +57,13 @@ import static org.hamcrest.Matchers.is;
 
 public class SnapshotStatusApisIT extends AbstractSnapshotIntegTestCase {
 
+    @Override
+    protected Settings nodeSettings(int nodeOrdinal) {
+        return Settings.builder().put(super.nodeSettings(nodeOrdinal))
+                .put(ThreadPool.ESTIMATED_TIME_INTERVAL_SETTING.getKey(), 0) // We have tests that check by-timestamp order
+                .build();
+    }
+
     public void testStatusApiConsistency() {
         Client client = client();
 
@@ -264,6 +282,158 @@ public class SnapshotStatusApisIT extends AbstractSnapshotIntegTestCase {
         assertThat(responseSnapshotTwo.get().getSnapshotInfo().state(), is(SnapshotState.SUCCESS));
     }
 
+    public void testSnapshotStatusOnFailedSnapshot() throws Exception {
+        String repoName = "test-repo";
+        createRepository(repoName, "fs");
+        final String snapshot = "test-snap-1";
+        addBwCFailedSnapshot(repoName, snapshot, Collections.emptyMap());
+
+        logger.info("--> creating good index");
+        assertAcked(prepareCreate("test-idx-good").setSettings(indexSettingsNoReplicas(1)));
+        ensureGreen();
+        indexRandomDocs("test-idx-good", randomIntBetween(1, 5));
+
+        final SnapshotsStatusResponse snapshotsStatusResponse =
+                client().admin().cluster().prepareSnapshotStatus(repoName).setSnapshots(snapshot).get();
+        assertEquals(1, snapshotsStatusResponse.getSnapshots().size());
+        assertEquals(SnapshotsInProgress.State.FAILED, snapshotsStatusResponse.getSnapshots().get(0).getState());
+    }
+
+    public void testGetSnapshotsRequest() throws Exception {
+        final String repositoryName = "test-repo";
+        final String indexName = "test-idx";
+        final Client client = client();
+
+        createRepository(repositoryName, "mock", Settings.builder()
+                .put("location", randomRepoPath()).put("compress", false)
+                .put("chunk_size", randomIntBetween(100, 1000), ByteSizeUnit.BYTES).put("wait_after_unblock", 200));
+
+        logger.info("--> get snapshots on an empty repository");
+        expectThrows(SnapshotMissingException.class, () -> client.admin()
+                .cluster()
+                .prepareGetSnapshots(repositoryName)
+                .addSnapshots("non-existent-snapshot")
+                .get());
+        // with ignore unavailable set to true, should not throw an exception
+        GetSnapshotsResponse getSnapshotsResponse = client.admin()
+                .cluster()
+                .prepareGetSnapshots(repositoryName)
+                .setIgnoreUnavailable(true)
+                .addSnapshots("non-existent-snapshot")
+                .get();
+        assertThat(getSnapshotsResponse.getSnapshots().size(), equalTo(0));
+
+        logger.info("--> creating an index and indexing documents");
+        // Create index on 2 nodes and make sure each node has a primary by setting no replicas
+        assertAcked(prepareCreate(indexName, 1, Settings.builder().put("number_of_replicas", 0)));
+        ensureGreen();
+        indexRandomDocs(indexName, 10);
+
+        // make sure we return only the in-progress snapshot when taking the first snapshot on a clean repository
+        // take initial snapshot with a block, making sure we only get 1 in-progress snapshot returned
+        // block a node so the create snapshot operation can remain in progress
+        final String initialBlockedNode = blockNodeWithIndex(repositoryName, indexName);
+        client.admin().cluster().prepareCreateSnapshot(repositoryName, "snap-on-empty-repo")
+                .setWaitForCompletion(false)
+                .setIndices(indexName)
+                .get();
+        waitForBlock(initialBlockedNode, repositoryName, TimeValue.timeValueSeconds(60)); // wait for block to kick in
+        getSnapshotsResponse = client.admin().cluster()
+                .prepareGetSnapshots("test-repo")
+                .setSnapshots(randomFrom("_all", "_current", "snap-on-*", "*-on-empty-repo", "snap-on-empty-repo"))
+                .get();
+        assertEquals(1, getSnapshotsResponse.getSnapshots().size());
+        assertEquals("snap-on-empty-repo", getSnapshotsResponse.getSnapshots().get(0).snapshotId().getName());
+        unblockNode(repositoryName, initialBlockedNode); // unblock node
+        admin().cluster().prepareDeleteSnapshot(repositoryName, "snap-on-empty-repo").get();
+
+        final int numSnapshots = randomIntBetween(1, 3) + 1;
+        logger.info("--> take {} snapshot(s)", numSnapshots - 1);
+        final String[] snapshotNames = new String[numSnapshots];
+        for (int i = 0; i < numSnapshots - 1; i++) {
+            final String snapshotName = randomAlphaOfLength(8).toLowerCase(Locale.ROOT);
+            CreateSnapshotResponse createSnapshotResponse = client.admin()
+                    .cluster()
+                    .prepareCreateSnapshot(repositoryName, snapshotName)
+                    .setWaitForCompletion(true)
+                    .setIndices(indexName)
+                    .get();
+            assertThat(createSnapshotResponse.getSnapshotInfo().successfulShards(), greaterThan(0));
+            snapshotNames[i] = snapshotName;
+        }
+        logger.info("--> take another snapshot to be in-progress");
+        // add documents so there are data files to block on
+        for (int i = 10; i < 20; i++) {
+            index(indexName, "_doc", Integer.toString(i), "foo", "bar" + i);
+        }
+        refresh();
+
+        final String inProgressSnapshot = randomAlphaOfLength(8).toLowerCase(Locale.ROOT);
+        snapshotNames[numSnapshots - 1] = inProgressSnapshot;
+        // block a node so the create snapshot operation can remain in progress
+        final String blockedNode = blockNodeWithIndex(repositoryName, indexName);
+        client.admin().cluster().prepareCreateSnapshot(repositoryName, inProgressSnapshot)
+                .setWaitForCompletion(false)
+                .setIndices(indexName)
+                .get();
+        waitForBlock(blockedNode, repositoryName, TimeValue.timeValueSeconds(60)); // wait for block to kick in
+
+        logger.info("--> get all snapshots with a current in-progress");
+        // with ignore unavailable set to true, should not throw an exception
+        final List<String> snapshotsToGet = new ArrayList<>();
+        if (randomBoolean()) {
+            // use _current plus the individual names of the finished snapshots
+            snapshotsToGet.add("_current");
+            for (int i = 0; i < numSnapshots - 1; i++) {
+                snapshotsToGet.add(snapshotNames[i]);
+            }
+        } else {
+            snapshotsToGet.add("_all");
+        }
+        getSnapshotsResponse = client.admin().cluster()
+                .prepareGetSnapshots(repositoryName)
+                .setSnapshots(snapshotsToGet.toArray(Strings.EMPTY_ARRAY))
+                .get();
+        List<String> sortedNames = Arrays.asList(snapshotNames);
+        Collections.sort(sortedNames);
+        assertThat(getSnapshotsResponse.getSnapshots().size(), equalTo(numSnapshots));
+        assertThat(getSnapshotsResponse.getSnapshots().stream()
+                .map(s -> s.snapshotId().getName())
+                .sorted()
+                .collect(Collectors.toList()), equalTo(sortedNames));
+
+        getSnapshotsResponse = client.admin().cluster()
+                .prepareGetSnapshots(repositoryName)
+                .addSnapshots(snapshotNames)
+                .get();
+        sortedNames = Arrays.asList(snapshotNames);
+        Collections.sort(sortedNames);
+        assertThat(getSnapshotsResponse.getSnapshots().size(), equalTo(numSnapshots));
+        assertThat(getSnapshotsResponse.getSnapshots().stream()
+                .map(s -> s.snapshotId().getName())
+                .sorted()
+                .collect(Collectors.toList()), equalTo(sortedNames));
+
+        logger.info("--> make sure duplicates are not returned in the response");
+        String regexName = snapshotNames[randomIntBetween(0, numSnapshots - 1)];
+        final int splitPos = regexName.length() / 2;
+        final String firstRegex = regexName.substring(0, splitPos) + "*";
+        final String secondRegex = "*" + regexName.substring(splitPos);
+        getSnapshotsResponse = client.admin().cluster()
+                .prepareGetSnapshots(repositoryName)
+                .addSnapshots(snapshotNames)
+                .addSnapshots(firstRegex, secondRegex)
+                .get();
+        assertThat(getSnapshotsResponse.getSnapshots().size(), equalTo(numSnapshots));
+        assertThat(getSnapshotsResponse.getSnapshots().stream()
+                .map(s -> s.snapshotId().getName())
+                .sorted()
+                .collect(Collectors.toList()), equalTo(sortedNames));
+
+        unblockNode(repositoryName, blockedNode); // unblock node
+        waitForCompletion(repositoryName, inProgressSnapshot, TimeValue.timeValueSeconds(60));
+    }
+
     private static SnapshotIndexShardStatus stateFirstShard(SnapshotStatus snapshotStatus, String indexName) {
         return snapshotStatus.getIndices().get(indexName).getShards().get(0);
     }
diff --git a/test/framework/src/main/java/org/elasticsearch/snapshots/AbstractSnapshotIntegTestCase.java b/test/framework/src/main/java/org/elasticsearch/snapshots/AbstractSnapshotIntegTestCase.java
index 5236780a575..548674eb164 100644
--- a/test/framework/src/main/java/org/elasticsearch/snapshots/AbstractSnapshotIntegTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/snapshots/AbstractSnapshotIntegTestCase.java
@@ -19,11 +19,13 @@
 package org.elasticsearch.snapshots;
 
 import org.elasticsearch.Version;
+import org.elasticsearch.action.ActionFuture;
 import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotResponse;
 import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
 import org.elasticsearch.action.index.IndexRequestBuilder;
 import org.elasticsearch.action.search.SearchRequest;
 import org.elasticsearch.action.support.PlainActionFuture;
+import org.elasticsearch.action.support.master.AcknowledgedResponse;
 import org.elasticsearch.cluster.ClusterState;
 import org.elasticsearch.cluster.ClusterStateObserver;
 import org.elasticsearch.cluster.SnapshotDeletionsInProgress;
@@ -81,6 +83,7 @@ import java.util.function.Predicate;
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
 import static org.hamcrest.Matchers.empty;
 import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.is;
 
 public abstract class AbstractSnapshotIntegTestCase extends ESIntegTestCase {
@@ -444,6 +447,11 @@ public abstract class AbstractSnapshotIntegTestCase extends ESIntegTestCase {
         awaitClusterState(internalCluster().getMasterName(), statePredicate);
     }
 
+    protected ActionFuture<AcknowledgedResponse> startDeleteSnapshot(String repoName, String snapshotName) {
+        logger.info("--> deleting snapshot [{}] from repo [{}]", snapshotName, repoName);
+        return clusterAdmin().prepareDeleteSnapshot(repoName, snapshotName).execute();
+    }
+
     protected void awaitClusterState(String viaNode, Predicate<ClusterState> statePredicate) throws Exception {
         final ClusterService clusterService = internalCluster().getInstance(ClusterService.class, viaNode);
         final ThreadPool threadPool = internalCluster().getInstance(ThreadPool.class, viaNode);
@@ -469,4 +477,17 @@ public abstract class AbstractSnapshotIntegTestCase extends ESIntegTestCase {
             future.get(30L, TimeUnit.SECONDS);
         }
     }
+
+    protected static SnapshotInfo assertSuccessful(ActionFuture<CreateSnapshotResponse> future) throws Exception {
+        final SnapshotInfo snapshotInfo = future.get().getSnapshotInfo();
+        assertThat(snapshotInfo.state(), is(SnapshotState.SUCCESS));
+        return snapshotInfo;
+    }
+
+    protected SnapshotInfo getSnapshot(String repository, String snapshot) {
+        final List<SnapshotInfo> snapshotInfos = clusterAdmin().prepareGetSnapshots(repository).setSnapshots(snapshot)
+                .get().getSnapshots();
+        assertThat(snapshotInfos, hasSize(1));
+        return snapshotInfos.get(0);
+    }
 }
diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java
index d9b685f13ce..ae1b9049b3a 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java
@@ -59,6 +59,7 @@ import org.elasticsearch.action.support.DefaultShardOperationFailedException;
 import org.elasticsearch.action.support.IndicesOptions;
 import org.elasticsearch.client.AdminClient;
 import org.elasticsearch.client.Client;
+import org.elasticsearch.client.ClusterAdminClient;
 import org.elasticsearch.client.Requests;
 import org.elasticsearch.client.RestClient;
 import org.elasticsearch.client.RestClientBuilder;
@@ -1428,6 +1429,13 @@ public abstract class ESIntegTestCase extends ESTestCase {
         return client().admin();
     }
 
+    /**
+     * Returns a random cluster admin client. This client can be pointing to any of the nodes in the cluster.
+     */
+    protected ClusterAdminClient clusterAdmin() {
+        return admin().cluster();
+    }
+
     /**
      * Convenience method that forwards to {@link #indexRandom(boolean, List)}.
      */