Skip to content

Commit

Permalink
Snapshot/Restore: Add ability to restore indices without their aliases
Browse files Browse the repository at this point in the history
Closes #6457
  • Loading branch information
imotov committed Jul 13, 2014
1 parent 9b12752 commit 86292a4
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 7 deletions.
3 changes: 2 additions & 1 deletion docs/reference/modules/snapshots.asciidoc
Expand Up @@ -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]
-----------------------------------
Expand All @@ -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
Expand Down
Expand Up @@ -70,6 +70,8 @@ public class RestoreSnapshotRequest extends MasterNodeOperationRequest<RestoreSn

private boolean partial = false;

private boolean includeAliases = true;

private Settings settings = EMPTY_SETTINGS;

RestoreSnapshotRequest() {
Expand Down Expand Up @@ -384,6 +386,26 @@ public boolean includeGlobalState() {
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
*
Expand Down Expand Up @@ -437,6 +459,8 @@ public RestoreSnapshotRequest source(Map source) {
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());
Expand Down Expand Up @@ -538,6 +562,7 @@ public void readFrom(StreamInput in) throws IOException {
includeGlobalState = in.readBoolean();
if (in.getVersion().onOrAfter(Version.V_1_3_0)) {
partial = in.readBoolean();
includeAliases = in.readBoolean();
}
settings = readSettingsFromStream(in);
}
Expand All @@ -555,6 +580,7 @@ public void writeTo(StreamOutput out) throws IOException {
out.writeBoolean(includeGlobalState);
if (out.getVersion().onOrAfter(Version.V_1_3_0)) {
out.writeBoolean(partial);
out.writeBoolean(includeAliases);
}
writeSettingsToStream(settings, out);
}
Expand Down
Expand Up @@ -95,7 +95,7 @@ public RestoreSnapshotRequestBuilder setIndices(String... indices) {
* 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);
Expand Down Expand Up @@ -124,7 +124,7 @@ public RestoreSnapshotRequestBuilder setRenamePattern(String renamePattern) {
* See {@link #setRenamePattern(String)} for more information.
*
* @param renameReplacement rename replacement
* @return
* @return this builder
*/
public RestoreSnapshotRequestBuilder setRenameReplacement(String renameReplacement) {
request.renameReplacement(renameReplacement);
Expand Down Expand Up @@ -201,7 +201,7 @@ public RestoreSnapshotRequestBuilder setWaitForCompletion(boolean waitForComplet
* 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);
Expand All @@ -212,13 +212,24 @@ public RestoreSnapshotRequestBuilder setRestoreGlobalState(boolean restoreGlobal
* 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);
Expand Down
Expand Up @@ -78,7 +78,8 @@ protected void masterOperation(final RestoreSnapshotRequest request, ClusterStat
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) {
Expand Down
Expand Up @@ -509,6 +509,11 @@ public Builder removeAlias(String alias) {
return this;
}

public Builder removeAllAliases() {
aliases.clear();
return this;
}

public Builder putCustom(String type, Custom customIndexMetaData) {
this.customs.put(type, customIndexMetaData);
return this;
Expand Down
28 changes: 27 additions & 1 deletion src/main/java/org/elasticsearch/snapshots/RestoreService.java
Expand Up @@ -161,6 +161,10 @@ public ClusterState execute(ClusterState currentState) {
// 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);
Expand All @@ -172,6 +176,16 @@ public ClusterState execute(ClusterState currentState) {
// 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);
Expand Down Expand Up @@ -553,6 +567,8 @@ public static class RestoreRequest {

final private boolean partial;

final private boolean includeAliases;

/**
* Constructs new restore request
*
Expand All @@ -570,7 +586,7 @@ public static class RestoreRequest {
*/
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;
Expand All @@ -582,6 +598,7 @@ public RestoreRequest(String cause, String repository, String name, String[] ind
this.masterNodeTimeout = masterNodeTimeout;
this.includeGlobalState = includeGlobalState;
this.partial = partial;
this.includeAliases = includeAliases;
}

/**
Expand Down Expand Up @@ -674,6 +691,15 @@ public boolean partial() {
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
*
Expand Down
Expand Up @@ -200,6 +200,63 @@ public void emptySnapshotTest() throws Exception {
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();
Expand Down
Expand Up @@ -38,6 +38,7 @@
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;
Expand Down Expand Up @@ -364,6 +365,20 @@ public static void assertIndexTemplateExists(GetIndexTemplatesResponse templates
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
*/
Expand Down

0 comments on commit 86292a4

Please sign in to comment.