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

Closes #6457
This commit is contained in:
Igor Motov 2014-07-02 12:42:39 -04:00
parent f7a88fdd3e
commit 60b317caa4
8 changed files with 149 additions and 7 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -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) {

View File

@ -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;

View File

@ -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
*

View File

@ -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();

View File

@ -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
*/