Browse Source

Snapshot/Restore: Add ability to restore indices without their aliases

Closes #6457
Igor Motov 11 years ago
parent
commit
60b317caa4

+ 2 - 1
docs/reference/modules/snapshots.asciidoc

@@ -189,6 +189,7 @@ should be restored as well as prevent global cluster state from being restored b
 <<search-multi-index-type,multi index syntax>>. The `rename_pattern` and `rename_replacement` options can be also used to
 rename index on restore using regular expression that supports referencing the original text as explained
 http://docs.oracle.com/javase/6/docs/api/java/util/regex/Matcher.html#appendReplacement(java.lang.StringBuffer,%20java.lang.String)[here].
+Set `include_aliases` to `false` to prevent aliases from being restored together with associated indices coming[1.3.0].
 
 [source,js]
 -----------------------------------
@@ -210,7 +211,7 @@ persistent settings are added to the existing persistent settings.
 [float]
 === Partial restore
 
-added[1.3.0]
+coming[1.3.0]
 
 By default, entire restore operation will fail if one or more indices participating in the operation don't have
 snapshots of all shards available. It can occur if some shards failed to snapshot for example. It is still possible to

+ 26 - 0
src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequest.java

@@ -70,6 +70,8 @@ public class RestoreSnapshotRequest extends MasterNodeOperationRequest<RestoreSn
 
     private boolean partial = false;
 
+    private boolean includeAliases = true;
+
     private Settings settings = EMPTY_SETTINGS;
 
     RestoreSnapshotRequest() {
@@ -384,6 +386,26 @@ public class RestoreSnapshotRequest extends MasterNodeOperationRequest<RestoreSn
         return includeGlobalState;
     }
 
+    /**
+     * If set to true the restore procedure will restore aliases
+     *
+     * @param includeAliases true if aliases should be restored from the snapshot
+     * @return this request
+     */
+    public RestoreSnapshotRequest includeAliases(boolean includeAliases) {
+        this.includeAliases = includeAliases;
+        return this;
+    }
+
+    /**
+     * Returns true if aliases should be restored from this snapshot
+     *
+     * @return true if aliases should be restored
+     */
+    public boolean includeAliases() {
+        return includeAliases;
+    }
+
     /**
      * Parses restore definition
      *
@@ -437,6 +459,8 @@ public class RestoreSnapshotRequest extends MasterNodeOperationRequest<RestoreSn
                 settings((Map<String, Object>) entry.getValue());
             } else if (name.equals("include_global_state")) {
                 includeGlobalState = nodeBooleanValue(entry.getValue());
+            } else if (name.equals("include_aliases")) {
+                includeAliases = nodeBooleanValue(entry.getValue());
             } else if (name.equals("rename_pattern")) {
                 if (entry.getValue() instanceof String) {
                     renamePattern((String) entry.getValue());
@@ -538,6 +562,7 @@ public class RestoreSnapshotRequest extends MasterNodeOperationRequest<RestoreSn
         includeGlobalState = in.readBoolean();
         if (in.getVersion().onOrAfter(Version.V_1_3_0)) {
             partial = in.readBoolean();
+            includeAliases = in.readBoolean();
         }
         settings = readSettingsFromStream(in);
     }
@@ -555,6 +580,7 @@ public class RestoreSnapshotRequest extends MasterNodeOperationRequest<RestoreSn
         out.writeBoolean(includeGlobalState);
         if (out.getVersion().onOrAfter(Version.V_1_3_0)) {
             out.writeBoolean(partial);
+            out.writeBoolean(includeAliases);
         }
         writeSettingsToStream(settings, out);
     }

+ 15 - 4
src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequestBuilder.java

@@ -95,7 +95,7 @@ public class RestoreSnapshotRequestBuilder extends MasterNodeOperationRequestBui
      * For example indices that don't exist.
      *
      * @param indicesOptions the desired behaviour regarding indices to ignore and wildcard indices expressions
-     * @return this request
+     * @return this builder
      */
     public RestoreSnapshotRequestBuilder setIndicesOptions(IndicesOptions indicesOptions) {
         request.indicesOptions(indicesOptions);
@@ -124,7 +124,7 @@ public class RestoreSnapshotRequestBuilder extends MasterNodeOperationRequestBui
      * See {@link #setRenamePattern(String)} for more information.
      *
      * @param renameReplacement rename replacement
-     * @return
+     * @return this builder
      */
     public RestoreSnapshotRequestBuilder setRenameReplacement(String renameReplacement) {
         request.renameReplacement(renameReplacement);
@@ -201,7 +201,7 @@ public class RestoreSnapshotRequestBuilder extends MasterNodeOperationRequestBui
      * The global cluster state includes persistent settings and index template definitions.
      *
      * @param restoreGlobalState true if global state should be restored from the snapshot
-     * @return this request
+     * @return this builder
      */
     public RestoreSnapshotRequestBuilder setRestoreGlobalState(boolean restoreGlobalState) {
         request.includeGlobalState(restoreGlobalState);
@@ -212,13 +212,24 @@ public class RestoreSnapshotRequestBuilder extends MasterNodeOperationRequestBui
      * If set to true the restore procedure will restore partially snapshotted indices
      *
      * @param partial true if partially snapshotted indices should be restored
-     * @return this request
+     * @return this builder
      */
     public RestoreSnapshotRequestBuilder setPartial(boolean partial) {
         request.partial(partial);
         return this;
     }
 
+    /**
+     * If set to true the restore procedure will restore aliases
+     *
+     * @param restoreAliases true if aliases should be restored from the snapshot
+     * @return this builder
+     */
+    public RestoreSnapshotRequestBuilder setIncludeAliases(boolean restoreAliases) {
+        request.includeAliases(restoreAliases);
+        return this;
+    }
+
     @Override
     protected void doExecute(ActionListener<RestoreSnapshotResponse> listener) {
         client.restoreSnapshot(request, listener);

+ 2 - 1
src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/TransportRestoreSnapshotAction.java

@@ -78,7 +78,8 @@ public class TransportRestoreSnapshotAction extends TransportMasterNodeOperation
         RestoreService.RestoreRequest restoreRequest = new RestoreService.RestoreRequest(
                 "restore_snapshot[" + request.snapshot() + "]", request.repository(), request.snapshot(),
                 request.indices(), request.indicesOptions(), request.renamePattern(), request.renameReplacement(),
-                request.settings(), request.masterNodeTimeout(), request.includeGlobalState(), request.partial());
+                request.settings(), request.masterNodeTimeout(), request.includeGlobalState(), request.partial(), request.includeAliases());
+
         restoreService.restoreSnapshot(restoreRequest, new RestoreSnapshotListener() {
             @Override
             public void onResponse(RestoreInfo restoreInfo) {

+ 5 - 0
src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java

@@ -509,6 +509,11 @@ public class IndexMetaData {
             return this;
         }
 
+        public Builder removeAllAliases() {
+            aliases.clear();
+            return this;
+        }
+
         public Builder putCustom(String type, Custom customIndexMetaData) {
             this.customs.put(type, customIndexMetaData);
             return this;

+ 27 - 1
src/main/java/org/elasticsearch/snapshots/RestoreService.java

@@ -161,6 +161,10 @@ public class RestoreService extends AbstractComponent implements ClusterStateLis
                                 // Make sure that the index we are about to create has a validate name
                                 createIndexService.validateIndexName(renamedIndex, currentState);
                                 IndexMetaData.Builder indexMdBuilder = IndexMetaData.builder(snapshotIndexMetaData).state(IndexMetaData.State.OPEN).index(renamedIndex);
+                                if (!request.includeAliases() && !snapshotIndexMetaData.aliases().isEmpty()) {
+                                    // Remove all aliases - they shouldn't be restored
+                                    indexMdBuilder.removeAllAliases();
+                                }
                                 IndexMetaData updatedIndexMetaData = indexMdBuilder.build();
                                 if (partial) {
                                     populateIgnoredShards(index, ignoreShards);
@@ -172,6 +176,16 @@ public class RestoreService extends AbstractComponent implements ClusterStateLis
                                 // Index exists and it's closed - open it in metadata and start recovery
                                 IndexMetaData.Builder indexMdBuilder = IndexMetaData.builder(snapshotIndexMetaData).state(IndexMetaData.State.OPEN);
                                 indexMdBuilder.version(Math.max(snapshotIndexMetaData.version(), currentIndexMetaData.version() + 1));
+                                if (!request.includeAliases()) {
+                                    // Remove all snapshot aliases
+                                    if (!snapshotIndexMetaData.aliases().isEmpty()) {
+                                        indexMdBuilder.removeAllAliases();
+                                    }
+                                    /// Add existing aliases
+                                    for (ObjectCursor<AliasMetaData> alias : currentIndexMetaData.aliases().values()) {
+                                        indexMdBuilder.putAlias(alias.value);
+                                    }
+                                }
                                 IndexMetaData updatedIndexMetaData = indexMdBuilder.index(renamedIndex).build();
                                 rtBuilder.addAsRestore(updatedIndexMetaData, restoreSource);
                                 blocks.removeIndexBlock(renamedIndex, INDEX_CLOSED_BLOCK);
@@ -553,6 +567,8 @@ public class RestoreService extends AbstractComponent implements ClusterStateLis
 
         final private boolean partial;
 
+        final private boolean includeAliases;
+
         /**
          * Constructs new restore request
          *
@@ -570,7 +586,7 @@ public class RestoreService extends AbstractComponent implements ClusterStateLis
          */
         public RestoreRequest(String cause, String repository, String name, String[] indices, IndicesOptions indicesOptions,
                               String renamePattern, String renameReplacement, Settings settings,
-                              TimeValue masterNodeTimeout, boolean includeGlobalState, boolean partial) {
+                              TimeValue masterNodeTimeout, boolean includeGlobalState, boolean partial, boolean includeAliases) {
             this.cause = cause;
             this.name = name;
             this.repository = repository;
@@ -582,6 +598,7 @@ public class RestoreService extends AbstractComponent implements ClusterStateLis
             this.masterNodeTimeout = masterNodeTimeout;
             this.includeGlobalState = includeGlobalState;
             this.partial = partial;
+            this.includeAliases = includeAliases;
         }
 
         /**
@@ -674,6 +691,15 @@ public class RestoreService extends AbstractComponent implements ClusterStateLis
             return partial;
         }
 
+        /**
+         * Returns true if aliases should be restore during this restore operation
+         *
+         * @return restore aliases state flag
+         */
+        public boolean includeAliases() {
+            return includeAliases;
+        }
+
         /**
          * Return master node timeout
          *

+ 57 - 0
src/test/java/org/elasticsearch/snapshots/SharedClusterSnapshotRestoreTests.java

@@ -200,6 +200,63 @@ public class SharedClusterSnapshotRestoreTests extends AbstractSnapshotTests {
         assertThat(client.admin().cluster().prepareGetSnapshots("test-repo").setSnapshots("test-snap").get().getSnapshots().get(0).state(), equalTo(SnapshotState.SUCCESS));
     }
 
+    @Test
+    public void restoreAliasesTest() throws Exception {
+        Client client = client();
+
+        logger.info("-->  creating repository");
+        assertAcked(client.admin().cluster().preparePutRepository("test-repo")
+                .setType("fs").setSettings(ImmutableSettings.settingsBuilder().put("location", newTempDir())));
+
+        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());
+
+    }
+
     @Test
     public void restoreTemplatesTest() throws Exception {
         Client client = client();

+ 15 - 0
src/test/java/org/elasticsearch/test/hamcrest/ElasticsearchAssertions.java

@@ -38,6 +38,7 @@ import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
 import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
 import org.elasticsearch.action.admin.cluster.node.info.PluginInfo;
 import org.elasticsearch.action.admin.cluster.node.info.PluginsInfo;
+import org.elasticsearch.action.admin.indices.alias.exists.AliasesExistResponse;
 import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequestBuilder;
 import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;
 import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
@@ -364,6 +365,20 @@ public class ElasticsearchAssertions {
         assertThat(templateNames, hasItem(name));
     }
 
+    /**
+     * Assert that aliases are missing
+     */
+    public static void assertAliasesMissing(AliasesExistResponse aliasesExistResponse) {
+        assertFalse("Aliases shouldn't exist", aliasesExistResponse.exists());
+    }
+
+    /**
+     * Assert that aliases exist
+     */
+    public static void assertAliasesExist(AliasesExistResponse aliasesExistResponse) {
+        assertTrue("Aliases should exist", aliasesExistResponse.exists());
+    }
+
     /*
      * matchers
      */