Snapshot/Restore: Add ability to restore indices without their aliases
Closes #6457
This commit is contained in:
parent
f7a88fdd3e
commit
60b317caa4
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue