Allow reindexing into write alias (#41677)

Fixes an issue where reindex currently fails if the destination is an alias pointing to multiple indices,
even it is using a write index.

Closes #41667
This commit is contained in:
Yannick Welsch 2019-05-08 09:27:06 +02:00
parent 5b71baa100
commit 785ae09101
2 changed files with 30 additions and 8 deletions

View File

@ -186,7 +186,7 @@ public class TransportReindexAction extends HandledTransportAction<ReindexReques
* it. This is the same sort of dance that TransportIndexRequest * it. This is the same sort of dance that TransportIndexRequest
* uses to decide to autocreate the index. * uses to decide to autocreate the index.
*/ */
target = indexNameExpressionResolver.concreteIndexNames(clusterState, destination)[0]; target = indexNameExpressionResolver.concreteWriteIndex(clusterState, destination).getName();
} }
for (String sourceIndex : indexNameExpressionResolver.concreteIndexNames(clusterState, source)) { for (String sourceIndex : indexNameExpressionResolver.concreteIndexNames(clusterState, source)) {
if (sourceIndex.equals(target)) { if (sourceIndex.equals(target)) {

View File

@ -30,6 +30,7 @@ import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
@ -48,6 +49,9 @@ public class ReindexSourceTargetValidationTests extends ESTestCase {
private static final ClusterState STATE = ClusterState.builder(new ClusterName("test")).metaData(MetaData.builder() private static final ClusterState STATE = ClusterState.builder(new ClusterName("test")).metaData(MetaData.builder()
.put(index("target", "target_alias", "target_multi"), true) .put(index("target", "target_alias", "target_multi"), true)
.put(index("target2", "target_multi"), true) .put(index("target2", "target_multi"), true)
.put(index("target_with_write_index", true, "target_multi_with_write_index"), true)
.put(index("target2_without_write_index", "target_multi_with_write_index"), true)
.put(index("qux", false, "target_alias_with_write_index_disabled"), true)
.put(index("foo"), true) .put(index("foo"), true)
.put(index("bar"), true) .put(index("bar"), true)
.put(index("baz"), true) .put(index("baz"), true)
@ -78,12 +82,26 @@ public class ReindexSourceTargetValidationTests extends ESTestCase {
succeeds("target", "source", "source2", "source_multi"); succeeds("target", "source", "source2", "source_multi");
} }
public void testTargetIsAlias() { public void testTargetIsAliasToMultipleIndicesWithoutWriteAlias() {
Exception e = expectThrows(IllegalArgumentException.class, () -> succeeds("target_multi", "foo")); Exception e = expectThrows(IllegalArgumentException.class, () -> succeeds("target_multi", "foo"));
assertThat(e.getMessage(), containsString("Alias [target_multi] has more than one indices associated with it [[")); assertThat(e.getMessage(), containsString("no write index is defined for alias [target_multi]. The write index may be explicitly " +
// The index names can come in either order "disabled using is_write_index=false or the alias points to multiple indices without one being designated as a " +
assertThat(e.getMessage(), containsString("target")); "write index"));
assertThat(e.getMessage(), containsString("target2")); }
public void testTargetIsAliasWithWriteIndexDisabled() {
Exception e = expectThrows(IllegalArgumentException.class, () -> succeeds("target_alias_with_write_index_disabled", "foo"));
assertThat(e.getMessage(), containsString("no write index is defined for alias [target_alias_with_write_index_disabled]. " +
"The write index may be explicitly disabled using is_write_index=false or the alias points to multiple indices without one " +
"being designated as a write index"));
succeeds("qux", "foo"); // writing directly into the index of which this is the alias works though
}
public void testTargetIsWriteAlias() {
succeeds("target_multi_with_write_index", "foo");
succeeds("target_multi_with_write_index", "target2_without_write_index");
fails("target_multi_with_write_index", "target_multi_with_write_index");
fails("target_multi_with_write_index", "target_with_write_index");
} }
public void testRemoteInfoSkipsValidation() { public void testRemoteInfoSkipsValidation() {
@ -97,7 +115,7 @@ public class ReindexSourceTargetValidationTests extends ESTestCase {
private void fails(String target, String... sources) { private void fails(String target, String... sources) {
Exception e = expectThrows(ActionRequestValidationException.class, () -> succeeds(target, sources)); Exception e = expectThrows(ActionRequestValidationException.class, () -> succeeds(target, sources));
assertThat(e.getMessage(), containsString("reindex cannot write into an index its reading from [target]")); assertThat(e.getMessage(), containsString("reindex cannot write into an index its reading from"));
} }
private void succeeds(String target, String... sources) { private void succeeds(String target, String... sources) {
@ -110,12 +128,16 @@ public class ReindexSourceTargetValidationTests extends ESTestCase {
} }
private static IndexMetaData index(String name, String... aliases) { private static IndexMetaData index(String name, String... aliases) {
return index(name, null, aliases);
}
private static IndexMetaData index(String name, @Nullable Boolean writeIndex, String... aliases) {
IndexMetaData.Builder builder = IndexMetaData.builder(name).settings(Settings.builder() IndexMetaData.Builder builder = IndexMetaData.builder(name).settings(Settings.builder()
.put("index.version.created", Version.CURRENT.id) .put("index.version.created", Version.CURRENT.id)
.put("index.number_of_shards", 1) .put("index.number_of_shards", 1)
.put("index.number_of_replicas", 1)); .put("index.number_of_replicas", 1));
for (String alias: aliases) { for (String alias: aliases) {
builder.putAlias(AliasMetaData.builder(alias).build()); builder.putAlias(AliasMetaData.builder(alias).writeIndex(writeIndex).build());
} }
return builder.build(); return builder.build();
} }