From 5c5d723b8623bf00d7e58a827e477ae9d98281f5 Mon Sep 17 00:00:00 2001 From: Luca Cavanna Date: Tue, 18 Jul 2017 15:40:17 +0200 Subject: [PATCH] Improve error message when aliases are not supported (#25728) With #23997 and #25268 we have changed put alias, delete alias, update aliases and delete index to not accept aliases. Instead concrete indices should be provided as their index parameter. This commit improves the error message in case aliases are provided, from an IndexNotFoundException (404 status code) with "no such index" message, to an IllegalArgumentException (400 status code) with "The provided expression [alias] matches an alias, specify the corresponding concrete indices instead." message. Note that there is no specific error message for the case where wildcard expressions match one or more aliases. In fact, aliases are simply ignored when expanding wildcards for such APIs. An error is thrown only when the expression ends up matching no indices at all, and allow_no_indices is set to false. In that case the error is still the generic "404 - no such index". --- .../metadata/IndexNameExpressionResolver.java | 39 ++-- .../elasticsearch/aliases/IndexAliasesIT.java | 16 +- .../IndexNameExpressionResolverTests.java | 38 ++-- .../WildcardExpressionResolverTests.java | 170 ++++++++++++------ .../test/indices.delete/10_basic.yml | 4 +- 5 files changed, 181 insertions(+), 86 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolver.java b/core/src/main/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolver.java index 5f9bf5e370a..17b43efdf9d 100644 --- a/core/src/main/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolver.java +++ b/core/src/main/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolver.java @@ -175,7 +175,7 @@ public class IndexNameExpressionResolver extends AbstractComponent { final Set concreteIndices = new HashSet<>(expressions.size()); for (String expression : expressions) { AliasOrIndex aliasOrIndex = metaData.getAliasAndIndexLookup().get(expression); - if (aliasOrIndex == null || (aliasOrIndex.isAlias() && context.getOptions().ignoreAliases())) { + if (aliasOrIndex == null ) { if (failNoIndices) { IndexNotFoundException infe = new IndexNotFoundException(expression); infe.setResources("index_expression", expression); @@ -183,6 +183,12 @@ public class IndexNameExpressionResolver extends AbstractComponent { } else { continue; } + } else if (aliasOrIndex.isAlias() && context.getOptions().ignoreAliases()) { + if (failNoIndices) { + throw aliasesNotSupportedException(expression); + } else { + continue; + } } Collection resolvedIndices = aliasOrIndex.getIndices(); @@ -192,7 +198,8 @@ public class IndexNameExpressionResolver extends AbstractComponent { for (IndexMetaData indexMetaData : resolvedIndices) { indexNames[i++] = indexMetaData.getIndex().getName(); } - throw new IllegalArgumentException("Alias [" + expression + "] has more than one indices associated with it [" + Arrays.toString(indexNames) + "], can't execute a single index op"); + throw new IllegalArgumentException("Alias [" + expression + "] has more than one indices associated with it [" + + Arrays.toString(indexNames) + "], can't execute a single index op"); } for (IndexMetaData index : resolvedIndices) { @@ -220,6 +227,11 @@ public class IndexNameExpressionResolver extends AbstractComponent { return concreteIndices.toArray(new Index[concreteIndices.size()]); } + private static IllegalArgumentException aliasesNotSupportedException(String expression) { + return new IllegalArgumentException("The provided expression [" + expression + "] matches an " + + "alias, specify the corresponding concrete indices instead."); + } + /** * Utility method that allows to resolve an index expression to its corresponding single concrete index. * Callers should make sure they provide proper {@link org.elasticsearch.action.support.IndicesOptions} @@ -270,8 +282,7 @@ public class IndexNameExpressionResolver extends AbstractComponent { } /** - * Iterates through the list of indices and selects the effective list of required aliases for the - * given index. + * Iterates through the list of indices and selects the effective list of required aliases for the given index. *

Only aliases where the given predicate tests successfully are returned. If the indices list contains a non-required reference to * the index itself - null is returned. Returns null if no filtering is required. */ @@ -588,7 +599,7 @@ public class IndexNameExpressionResolver extends AbstractComponent { for (int i = 0; i < expressions.size(); i++) { String expression = expressions.get(i); if (Strings.isEmpty(expression)) { - throw infe(expression); + throw indexNotFoundException(expression); } if (aliasOrIndexExists(options, metaData, expression)) { if (result != null) { @@ -608,8 +619,14 @@ public class IndexNameExpressionResolver extends AbstractComponent { result = new HashSet<>(expressions.subList(0, i)); } if (!Regex.isSimpleMatchPattern(expression)) { - if (!unavailableIgnoredOrExists(options, metaData, expression)) { - throw infe(expression); + //TODO why does wildcard resolver throw exceptions regarding non wildcarded expressions? This should not be done here. + if (options.ignoreUnavailable() == false) { + AliasOrIndex aliasOrIndex = metaData.getAliasAndIndexLookup().get(expression); + if (aliasOrIndex == null) { + throw indexNotFoundException(expression); + } else if (aliasOrIndex.isAlias() && options.ignoreAliases()) { + throw aliasesNotSupportedException(expression); + } } if (add) { result.add(expression); @@ -628,7 +645,7 @@ public class IndexNameExpressionResolver extends AbstractComponent { result.removeAll(expand); } if (options.allowNoIndices() == false && matches.isEmpty()) { - throw infe(expression); + throw indexNotFoundException(expression); } if (Regex.isSimpleMatchPattern(expression)) { wildcardSeen = true; @@ -637,17 +654,13 @@ public class IndexNameExpressionResolver extends AbstractComponent { return result; } - private static boolean unavailableIgnoredOrExists(IndicesOptions options, MetaData metaData, String expression) { - return options.ignoreUnavailable() || aliasOrIndexExists(options, metaData, expression); - } - private static boolean aliasOrIndexExists(IndicesOptions options, MetaData metaData, String expression) { AliasOrIndex aliasOrIndex = metaData.getAliasAndIndexLookup().get(expression); //treat aliases as unavailable indices when ignoreAliases is set to true (e.g. delete index and update aliases api) return aliasOrIndex != null && (options.ignoreAliases() == false || aliasOrIndex.isAlias() == false); } - private static IndexNotFoundException infe(String expression) { + private static IndexNotFoundException indexNotFoundException(String expression) { IndexNotFoundException infe = new IndexNotFoundException(expression); infe.setResources("index_or_alias", expression); return infe; diff --git a/core/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java b/core/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java index 9526b5b97e6..8bf074be551 100644 --- a/core/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java +++ b/core/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java @@ -33,11 +33,9 @@ import org.elasticsearch.cluster.metadata.AliasMetaData; import org.elasticsearch.cluster.metadata.AliasOrIndex; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.common.StopWatch; -import org.elasticsearch.common.Strings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.XContentType; -import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.rest.action.admin.indices.AliasesNotFoundException; @@ -442,8 +440,10 @@ public class IndexAliasesIT extends ESIntegTestCase { assertTrue(admin().indices().prepareAliasesExist("foo").get().exists()); assertFalse(admin().indices().prepareAliasesExist("foo").setIndices("foo_foo").get().exists()); assertTrue(admin().indices().prepareAliasesExist("foo").setIndices("bar_bar").get().exists()); - expectThrows(IndexNotFoundException.class, () -> admin().indices().prepareAliases() + IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> admin().indices().prepareAliases() .addAliasAction(AliasActions.remove().index("foo").alias("foo")).execute().actionGet()); + assertEquals("The provided expression [foo] matches an alias, specify the corresponding concrete indices instead.", + iae.getMessage()); } public void testWaitForAliasCreationMultipleShards() throws Exception { @@ -824,10 +824,10 @@ public class IndexAliasesIT extends ESIntegTestCase { logger.info("--> adding [week_20] alias to [2017-05-20]"); assertAcked(admin().indices().prepareAliases().addAlias("2017-05-20", "week_20")); - IndexNotFoundException infe = expectThrows(IndexNotFoundException.class, () -> admin().indices().prepareAliases() + IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> admin().indices().prepareAliases() .addAliasAction(AliasActions.add().index("week_20").alias("tmp")).execute().actionGet()); - assertEquals("week_20", infe.getIndex().getName()); - + assertEquals("The provided expression [week_20] matches an alias, specify the corresponding concrete indices instead.", + iae.getMessage()); assertAcked(admin().indices().prepareAliases().addAliasAction(AliasActions.add().index("2017-05-20").alias("tmp")).execute().get()); } @@ -916,8 +916,10 @@ public class IndexAliasesIT extends ESIntegTestCase { assertAcked(admin().indices().prepareAliases().addAlias("foo_foo", "foo")); assertAcked(admin().indices().prepareAliases().addAlias("bar_bar", "foo")); - expectThrows(IndexNotFoundException.class, + IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> client().admin().indices().prepareAliases().removeIndex("foo").execute().actionGet()); + assertEquals("The provided expression [foo] matches an alias, specify the corresponding concrete indices instead.", + iae.getMessage()); assertAcked(client().admin().indices().prepareAliases().removeIndex("foo*").execute().get()); assertFalse(client().admin().indices().prepareExists("foo_foo").execute().actionGet().isExists()); diff --git a/core/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverTests.java b/core/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverTests.java index 0f543daa626..5e047145522 100644 --- a/core/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverTests.java +++ b/core/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverTests.java @@ -657,9 +657,10 @@ public class IndexNameExpressionResolverTests extends ESTestCase { assertEquals(1, indexNamesIndexWildcard.length); assertEquals("foo_foo", indexNamesIndexWildcard[0]); - IndexNotFoundException infe = expectThrows(IndexNotFoundException.class, + IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> indexNameExpressionResolver.concreteIndexNames(state, ignoreAliasesOptions, "foo")); - assertThat(infe.getIndex().getName(), equalTo("foo")); + assertEquals("The provided expression [foo] matches an alias, specify the corresponding concrete indices instead.", + iae.getMessage()); // when ignoreAliases option is not set, concreteIndexNames resolves the provided // expressions against the defined indices and aliases @@ -1005,11 +1006,13 @@ public class IndexNameExpressionResolverTests extends ESTestCase { IndexNotFoundException infe = expectThrows(IndexNotFoundException.class, () -> indexNameExpressionResolver.concreteIndexNames(state, new DeleteIndexRequest("does_not_exist"))); assertEquals("does_not_exist", infe.getIndex().getName()); + assertEquals("no such index", infe.getMessage()); } { - IndexNotFoundException infe = expectThrows(IndexNotFoundException.class, + IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> indexNameExpressionResolver.concreteIndexNames(state, new DeleteIndexRequest("test-alias"))); - assertEquals("test-alias", infe.getIndex().getName()); + assertEquals("The provided expression [test-alias] matches an alias, " + + "specify the corresponding concrete indices instead.", iae.getMessage()); } { DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("test-alias"); @@ -1049,11 +1052,16 @@ public class IndexNameExpressionResolverTests extends ESTestCase { ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build(); { IndicesAliasesRequest.AliasActions aliasActions = IndicesAliasesRequest.AliasActions.add().index("test-alias"); - expectThrows(IndexNotFoundException.class, () -> indexNameExpressionResolver.concreteIndexNames(state, aliasActions)); + IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, + () -> indexNameExpressionResolver.concreteIndexNames(state, aliasActions)); + assertEquals("The provided expression [test-alias] matches an alias, " + + "specify the corresponding concrete indices instead.", iae.getMessage()); } { IndicesAliasesRequest.AliasActions aliasActions = IndicesAliasesRequest.AliasActions.add().index("test-a*"); - expectThrows(IndexNotFoundException.class, () -> indexNameExpressionResolver.concreteIndexNames(state, aliasActions)); + IndexNotFoundException infe = expectThrows(IndexNotFoundException.class, + () -> indexNameExpressionResolver.concreteIndexNames(state, aliasActions)); + assertEquals("test-a*", infe.getIndex().getName()); } { IndicesAliasesRequest.AliasActions aliasActions = IndicesAliasesRequest.AliasActions.add().index("test-index"); @@ -1069,11 +1077,16 @@ public class IndexNameExpressionResolverTests extends ESTestCase { } { IndicesAliasesRequest.AliasActions aliasActions = IndicesAliasesRequest.AliasActions.remove().index("test-alias"); - expectThrows(IndexNotFoundException.class, () -> indexNameExpressionResolver.concreteIndexNames(state, aliasActions)); + IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, + () -> indexNameExpressionResolver.concreteIndexNames(state, aliasActions)); + assertEquals("The provided expression [test-alias] matches an alias, " + + "specify the corresponding concrete indices instead.", iae.getMessage()); } { IndicesAliasesRequest.AliasActions aliasActions = IndicesAliasesRequest.AliasActions.remove().index("test-a*"); - expectThrows(IndexNotFoundException.class, () -> indexNameExpressionResolver.concreteIndexNames(state, aliasActions)); + IndexNotFoundException infe = expectThrows(IndexNotFoundException.class, + () -> indexNameExpressionResolver.concreteIndexNames(state, aliasActions)); + assertEquals("test-a*", infe.getIndex().getName()); } { IndicesAliasesRequest.AliasActions aliasActions = IndicesAliasesRequest.AliasActions.remove().index("test-index"); @@ -1089,11 +1102,16 @@ public class IndexNameExpressionResolverTests extends ESTestCase { } { IndicesAliasesRequest.AliasActions aliasActions = IndicesAliasesRequest.AliasActions.removeIndex().index("test-alias"); - expectThrows(IndexNotFoundException.class, () -> indexNameExpressionResolver.concreteIndexNames(state, aliasActions)); + IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, + () -> indexNameExpressionResolver.concreteIndexNames(state, aliasActions)); + assertEquals("The provided expression [test-alias] matches an alias, " + + "specify the corresponding concrete indices instead.", iae.getMessage()); } { IndicesAliasesRequest.AliasActions aliasActions = IndicesAliasesRequest.AliasActions.removeIndex().index("test-a*"); - expectThrows(IndexNotFoundException.class, () -> indexNameExpressionResolver.concreteIndexNames(state, aliasActions)); + IndexNotFoundException infe = expectThrows(IndexNotFoundException.class, + () -> indexNameExpressionResolver.concreteIndexNames(state, aliasActions)); + assertEquals("test-a*", infe.getIndex().getName()); } { IndicesAliasesRequest.AliasActions aliasActions = IndicesAliasesRequest.AliasActions.removeIndex().index("test-index"); diff --git a/core/src/test/java/org/elasticsearch/cluster/metadata/WildcardExpressionResolverTests.java b/core/src/test/java/org/elasticsearch/cluster/metadata/WildcardExpressionResolverTests.java index e918f2acd4f..cb2913e5820 100644 --- a/core/src/test/java/org/elasticsearch/cluster/metadata/WildcardExpressionResolverTests.java +++ b/core/src/test/java/org/elasticsearch/cluster/metadata/WildcardExpressionResolverTests.java @@ -24,11 +24,16 @@ import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.cluster.ClusterName; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.metadata.IndexMetaData.State; +import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.test.ESTestCase; import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Set; import static org.elasticsearch.common.util.set.Sets.newHashSet; +import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.equalTo; public class WildcardExpressionResolverTests extends ESTestCase { @@ -42,13 +47,13 @@ public class WildcardExpressionResolverTests extends ESTestCase { IndexNameExpressionResolver.WildcardExpressionResolver resolver = new IndexNameExpressionResolver.WildcardExpressionResolver(); IndexNameExpressionResolver.Context context = new IndexNameExpressionResolver.Context(state, IndicesOptions.lenientExpandOpen()); - assertThat(newHashSet(resolver.resolve(context, Arrays.asList("testXXX"))), equalTo(newHashSet("testXXX"))); + assertThat(newHashSet(resolver.resolve(context, Collections.singletonList("testXXX"))), equalTo(newHashSet("testXXX"))); assertThat(newHashSet(resolver.resolve(context, Arrays.asList("testXXX", "testYYY"))), equalTo(newHashSet("testXXX", "testYYY"))); assertThat(newHashSet(resolver.resolve(context, Arrays.asList("testXXX", "ku*"))), equalTo(newHashSet("testXXX", "kuku"))); - assertThat(newHashSet(resolver.resolve(context, Arrays.asList("test*"))), equalTo(newHashSet("testXXX", "testXYY", "testYYY"))); - assertThat(newHashSet(resolver.resolve(context, Arrays.asList("testX*"))), equalTo(newHashSet("testXXX", "testXYY"))); + assertThat(newHashSet(resolver.resolve(context, Collections.singletonList("test*"))), equalTo(newHashSet("testXXX", "testXYY", "testYYY"))); + assertThat(newHashSet(resolver.resolve(context, Collections.singletonList("testX*"))), equalTo(newHashSet("testXXX", "testXYY"))); assertThat(newHashSet(resolver.resolve(context, Arrays.asList("testX*", "kuku"))), equalTo(newHashSet("testXXX", "testXYY", "kuku"))); - assertThat(newHashSet(resolver.resolve(context, Arrays.asList("*"))), equalTo(newHashSet("testXXX", "testXYY", "testYYY", "kuku"))); + assertThat(newHashSet(resolver.resolve(context, Collections.singletonList("*"))), equalTo(newHashSet("testXXX", "testXYY", "testYYY", "kuku"))); assertThat(newHashSet(resolver.resolve(context, Arrays.asList("*", "-kuku"))), equalTo(newHashSet("testXXX", "testXYY", "testYYY"))); assertThat(newHashSet(resolver.resolve(context, Arrays.asList("testXXX", "testYYY"))), equalTo(newHashSet("testXXX", "testYYY"))); assertThat(newHashSet(resolver.resolve(context, Arrays.asList("testXXX", "-testXXX"))), equalTo(newHashSet("testXXX", "-testXXX"))); @@ -67,7 +72,7 @@ public class WildcardExpressionResolverTests extends ESTestCase { IndexNameExpressionResolver.Context context = new IndexNameExpressionResolver.Context(state, IndicesOptions.lenientExpandOpen()); assertThat(newHashSet(resolver.resolve(context, Arrays.asList("testYY*", "alias*"))), equalTo(newHashSet("testXXX", "testXYY", "testYYY"))); - assertThat(newHashSet(resolver.resolve(context, Arrays.asList("-kuku"))), equalTo(newHashSet("-kuku"))); + assertThat(newHashSet(resolver.resolve(context, Collections.singletonList("-kuku"))), equalTo(newHashSet("-kuku"))); assertThat(newHashSet(resolver.resolve(context, Arrays.asList("test*", "-testYYY"))), equalTo(newHashSet("testXXX", "testXYY"))); assertThat(newHashSet(resolver.resolve(context, Arrays.asList("testX*", "testYYY"))), equalTo(newHashSet("testXXX", "testXYY", "testYYY"))); assertThat(newHashSet(resolver.resolve(context, Arrays.asList("testYYY", "testX*"))), equalTo(newHashSet("testXXX", "testXYY", "testYYY"))); @@ -85,11 +90,11 @@ public class WildcardExpressionResolverTests extends ESTestCase { IndexNameExpressionResolver.WildcardExpressionResolver resolver = new IndexNameExpressionResolver.WildcardExpressionResolver(); IndexNameExpressionResolver.Context context = new IndexNameExpressionResolver.Context(state, IndicesOptions.fromOptions(true, true, true, true)); - assertThat(newHashSet(resolver.resolve(context, Arrays.asList("testX*"))), equalTo(newHashSet("testXXX", "testXXY", "testXYY"))); + assertThat(newHashSet(resolver.resolve(context, Collections.singletonList("testX*"))), equalTo(newHashSet("testXXX", "testXXY", "testXYY"))); context = new IndexNameExpressionResolver.Context(state, IndicesOptions.fromOptions(true, true, false, true)); - assertThat(newHashSet(resolver.resolve(context, Arrays.asList("testX*"))), equalTo(newHashSet("testXYY"))); + assertThat(newHashSet(resolver.resolve(context, Collections.singletonList("testX*"))), equalTo(newHashSet("testXYY"))); context = new IndexNameExpressionResolver.Context(state, IndicesOptions.fromOptions(true, true, true, false)); - assertThat(newHashSet(resolver.resolve(context, Arrays.asList("testX*"))), equalTo(newHashSet("testXXX", "testXXY"))); + assertThat(newHashSet(resolver.resolve(context, Collections.singletonList("testX*"))), equalTo(newHashSet("testXXX", "testXXY"))); } // issue #13334 @@ -106,12 +111,12 @@ public class WildcardExpressionResolverTests extends ESTestCase { IndexNameExpressionResolver.WildcardExpressionResolver resolver = new IndexNameExpressionResolver.WildcardExpressionResolver(); IndexNameExpressionResolver.Context context = new IndexNameExpressionResolver.Context(state, IndicesOptions.lenientExpandOpen()); - assertThat(newHashSet(resolver.resolve(context, Arrays.asList("test*X*"))), equalTo(newHashSet("testXXX", "testXXY", "testXYY"))); - assertThat(newHashSet(resolver.resolve(context, Arrays.asList("test*X*Y"))), equalTo(newHashSet("testXXY", "testXYY"))); - assertThat(newHashSet(resolver.resolve(context, Arrays.asList("kuku*Y*"))), equalTo(newHashSet("kukuYYY"))); - assertThat(newHashSet(resolver.resolve(context, Arrays.asList("*Y*"))), equalTo(newHashSet("testXXY", "testXYY", "testYYY", "kukuYYY"))); - assertThat(newHashSet(resolver.resolve(context, Arrays.asList("test*Y*X"))).size(), equalTo(0)); - assertThat(newHashSet(resolver.resolve(context, Arrays.asList("*Y*X"))).size(), equalTo(0)); + assertThat(newHashSet(resolver.resolve(context, Collections.singletonList("test*X*"))), equalTo(newHashSet("testXXX", "testXXY", "testXYY"))); + assertThat(newHashSet(resolver.resolve(context, Collections.singletonList("test*X*Y"))), equalTo(newHashSet("testXXY", "testXYY"))); + assertThat(newHashSet(resolver.resolve(context, Collections.singletonList("kuku*Y*"))), equalTo(newHashSet("kukuYYY"))); + assertThat(newHashSet(resolver.resolve(context, Collections.singletonList("*Y*"))), equalTo(newHashSet("testXXY", "testXYY", "testYYY", "kukuYYY"))); + assertThat(newHashSet(resolver.resolve(context, Collections.singletonList("test*Y*X"))).size(), equalTo(0)); + assertThat(newHashSet(resolver.resolve(context, Collections.singletonList("*Y*X"))).size(), equalTo(0)); } public void testAll() { @@ -123,13 +128,75 @@ public class WildcardExpressionResolverTests extends ESTestCase { IndexNameExpressionResolver.WildcardExpressionResolver resolver = new IndexNameExpressionResolver.WildcardExpressionResolver(); IndexNameExpressionResolver.Context context = new IndexNameExpressionResolver.Context(state, IndicesOptions.lenientExpandOpen()); - assertThat(newHashSet(resolver.resolve(context, Arrays.asList("_all"))), equalTo(newHashSet("testXXX", "testXYY", "testYYY"))); + assertThat(newHashSet(resolver.resolve(context, Collections.singletonList("_all"))), equalTo(newHashSet("testXXX", "testXYY", "testYYY"))); } - public void testConcreteIndicesWildcardAndAliases() { + public void testResolveAliases() { MetaData.Builder mdBuilder = MetaData.builder() - .put(indexBuilder("foo_foo").state(State.OPEN).putAlias(AliasMetaData.builder("foo"))) - .put(indexBuilder("bar_bar").state(State.OPEN).putAlias(AliasMetaData.builder("foo"))); + .put(indexBuilder("foo_foo").state(State.OPEN)) + .put(indexBuilder("bar_bar").state(State.OPEN)) + .put(indexBuilder("foo_index").state(State.OPEN).putAlias(AliasMetaData.builder("foo_alias"))) + .put(indexBuilder("bar_index").state(State.OPEN).putAlias(AliasMetaData.builder("foo_alias"))); + ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build(); + IndexNameExpressionResolver.WildcardExpressionResolver resolver = new IndexNameExpressionResolver.WildcardExpressionResolver(); + // when ignoreAliases option is not set, WildcardExpressionResolver resolves the provided + // expressions against the defined indices and aliases + IndicesOptions indicesAndAliasesOptions = IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), true, false, true, false, false); + IndexNameExpressionResolver.Context indicesAndAliasesContext = new IndexNameExpressionResolver.Context(state, indicesAndAliasesOptions); + // ignoreAliases option is set, WildcardExpressionResolver throws error when + IndicesOptions skipAliasesIndicesOptions = IndicesOptions.fromOptions(true, true, true, false, true, false, true); + IndexNameExpressionResolver.Context skipAliasesLenientContext = new IndexNameExpressionResolver.Context(state, skipAliasesIndicesOptions); + // ignoreAliases option is set, WildcardExpressionResolver resolves the provided expressions only against the defined indices + IndicesOptions errorOnAliasIndicesOptions = IndicesOptions.fromOptions(false, false, true, false, true, false, true); + IndexNameExpressionResolver.Context skipAliasesStrictContext = new IndexNameExpressionResolver.Context(state, errorOnAliasIndicesOptions); + + { + List indices = resolver.resolve(indicesAndAliasesContext, Collections.singletonList("foo_a*")); + assertThat(indices, containsInAnyOrder("foo_index", "bar_index")); + } + { + List indices = resolver.resolve(skipAliasesLenientContext, Collections.singletonList("foo_a*")); + assertEquals(0, indices.size()); + } + { + IndexNotFoundException infe = expectThrows(IndexNotFoundException.class, + () -> resolver.resolve(skipAliasesStrictContext, Collections.singletonList("foo_a*"))); + assertEquals("foo_a*", infe.getIndex().getName()); + } + { + List indices = resolver.resolve(indicesAndAliasesContext, Collections.singletonList("foo*")); + assertThat(indices, containsInAnyOrder("foo_foo", "foo_index", "bar_index")); + } + { + List indices = resolver.resolve(skipAliasesLenientContext, Collections.singletonList("foo*")); + assertThat(indices, containsInAnyOrder("foo_foo", "foo_index")); + } + { + List indices = resolver.resolve(skipAliasesStrictContext, Collections.singletonList("foo*")); + assertThat(indices, containsInAnyOrder("foo_foo", "foo_index")); + } + { + List indices = resolver.resolve(indicesAndAliasesContext, Collections.singletonList("foo_alias")); + assertThat(indices, containsInAnyOrder("foo_alias")); + } + { + List indices = resolver.resolve(skipAliasesLenientContext, Collections.singletonList("foo_alias")); + assertThat(indices, containsInAnyOrder("foo_alias")); + } + { + IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, + () -> resolver.resolve(skipAliasesStrictContext, Collections.singletonList("foo_alias"))); + assertEquals("The provided expression [foo_alias] matches an alias, " + + "specify the corresponding concrete indices instead.", iae.getMessage()); + } + } + + public void testMatchesConcreteIndicesWildcardAndAliases() { + MetaData.Builder mdBuilder = MetaData.builder() + .put(indexBuilder("foo_foo").state(State.OPEN)) + .put(indexBuilder("bar_bar").state(State.OPEN)) + .put(indexBuilder("foo_index").state(State.OPEN).putAlias(AliasMetaData.builder("foo_alias"))) + .put(indexBuilder("bar_index").state(State.OPEN).putAlias(AliasMetaData.builder("foo_alias"))); ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build(); // when ignoreAliases option is not set, WildcardExpressionResolver resolves the provided @@ -142,44 +209,39 @@ public class WildcardExpressionResolverTests extends ESTestCase { IndicesOptions onlyIndicesOptions = IndicesOptions.fromOptions(false, false, true, false, true, false, true); IndexNameExpressionResolver.Context onlyIndicesContext = new IndexNameExpressionResolver.Context(state, onlyIndicesOptions); - assertThat( - IndexNameExpressionResolver.WildcardExpressionResolver - .matches(indicesAndAliasesContext, state.getMetaData(), "*").keySet(), - equalTo(newHashSet("bar_bar", "foo_foo", "foo"))); - assertThat( - IndexNameExpressionResolver.WildcardExpressionResolver - .matches(onlyIndicesContext, state.getMetaData(), "*").keySet(), - equalTo(newHashSet("bar_bar", "foo_foo"))); - - assertThat( - IndexNameExpressionResolver.WildcardExpressionResolver - .matches(indicesAndAliasesContext, state.getMetaData(), "foo*").keySet(), - equalTo(newHashSet("foo", "foo_foo"))); - assertThat( - IndexNameExpressionResolver.WildcardExpressionResolver - .matches(onlyIndicesContext, state.getMetaData(), "foo*").keySet(), - equalTo(newHashSet("foo_foo"))); - - assertThat( - IndexNameExpressionResolver.WildcardExpressionResolver - .matches(indicesAndAliasesContext, state.getMetaData(), "f*o").keySet(), - equalTo(newHashSet("foo", "foo_foo"))); - assertThat( - IndexNameExpressionResolver.WildcardExpressionResolver - .matches(onlyIndicesContext, state.getMetaData(), "f*o").keySet(), - equalTo(newHashSet("foo_foo"))); - - assertThat( - IndexNameExpressionResolver.WildcardExpressionResolver - .matches(indicesAndAliasesContext, state.getMetaData(), "foo").keySet(), - equalTo(newHashSet("foo"))); - assertThat( - IndexNameExpressionResolver.WildcardExpressionResolver - .matches(onlyIndicesContext, state.getMetaData(), "foo").keySet(), - equalTo(newHashSet())); + { + Set matches = IndexNameExpressionResolver.WildcardExpressionResolver.matches(indicesAndAliasesContext, + state.getMetaData(), "*").keySet(); + assertEquals(newHashSet("bar_bar", "foo_foo", "foo_index", "bar_index", "foo_alias"), matches); + } + { + Set matches = IndexNameExpressionResolver.WildcardExpressionResolver.matches(onlyIndicesContext, + state.getMetaData(), "*").keySet(); + assertEquals(newHashSet("bar_bar", "foo_foo", "foo_index", "bar_index"), matches); + } + { + Set matches = IndexNameExpressionResolver.WildcardExpressionResolver.matches(indicesAndAliasesContext, + state.getMetaData(), "foo*").keySet(); + assertEquals(newHashSet("foo_foo", "foo_index", "foo_alias"), matches); + } + { + Set matches = IndexNameExpressionResolver.WildcardExpressionResolver.matches(onlyIndicesContext, + state.getMetaData(), "foo*").keySet(); + assertEquals(newHashSet("foo_foo", "foo_index"), matches); + } + { + Set matches = IndexNameExpressionResolver.WildcardExpressionResolver.matches(indicesAndAliasesContext, + state.getMetaData(), "foo_alias").keySet(); + assertEquals(newHashSet("foo_alias"), matches); + } + { + Set matches = IndexNameExpressionResolver.WildcardExpressionResolver.matches(onlyIndicesContext, + state.getMetaData(), "foo_alias").keySet(); + assertEquals(newHashSet(), matches); + } } - private IndexMetaData.Builder indexBuilder(String index) { + private static IndexMetaData.Builder indexBuilder(String index) { return IndexMetaData.builder(index).settings(settings(Version.CURRENT).put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1).put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0)); } } diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/indices.delete/10_basic.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/indices.delete/10_basic.yml index 29cd2e8b5d2..40486da9e7e 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/indices.delete/10_basic.yml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/indices.delete/10_basic.yml @@ -14,7 +14,7 @@ setup: version: " - 5.99.0" reason: delete index doesn't support aliases only from 6.0.0 on - do: - catch: missing + catch: request indices.delete: index: alias - do: @@ -42,7 +42,7 @@ setup: version: " - 5.99.0" reason: delete index doesn't support aliases only from 6.0.0 on - do: - catch: missing + catch: request indices.delete: index: alias,index2 - do: