diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesRequest.java b/core/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesRequest.java index e7393efd01c..07665e9ccf1 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesRequest.java +++ b/core/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesRequest.java @@ -59,9 +59,10 @@ import static org.elasticsearch.common.xcontent.ObjectParser.fromList; public class IndicesAliasesRequest extends AcknowledgedRequest { private List allAliasActions = new ArrayList<>(); - //indices options that require every specified index to exist, expand wildcards only to open indices and - //don't allow that no indices are resolved from wildcard expressions - private static final IndicesOptions INDICES_OPTIONS = IndicesOptions.fromOptions(false, false, true, false); + // indices options that require every specified index to exist, expand wildcards only to open + // indices, don't allow that no indices are resolved from wildcard expressions and resolve the + // expressions only against indices + private static final IndicesOptions INDICES_OPTIONS = IndicesOptions.fromOptions(false, false, true, false, true, false, true); public IndicesAliasesRequest() { diff --git a/core/src/main/java/org/elasticsearch/action/support/IndicesOptions.java b/core/src/main/java/org/elasticsearch/action/support/IndicesOptions.java index b82bfcc7170..9ab4ee80ccf 100644 --- a/core/src/main/java/org/elasticsearch/action/support/IndicesOptions.java +++ b/core/src/main/java/org/elasticsearch/action/support/IndicesOptions.java @@ -19,6 +19,7 @@ package org.elasticsearch.action.support; +import org.elasticsearch.Version; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.rest.RestRequest; @@ -43,6 +44,7 @@ public class IndicesOptions { private static final byte EXPAND_WILDCARDS_CLOSED = 8; private static final byte FORBID_ALIASES_TO_MULTIPLE_INDICES = 16; private static final byte FORBID_CLOSED_INDICES = 32; + private static final byte IGNORE_ALIASES = 64; private static final byte STRICT_EXPAND_OPEN = 6; private static final byte LENIENT_EXPAND_OPEN = 7; @@ -51,10 +53,10 @@ public class IndicesOptions { private static final byte STRICT_SINGLE_INDEX_NO_EXPAND_FORBID_CLOSED = 48; static { - byte max = 1 << 6; + short max = 1 << 7; VALUES = new IndicesOptions[max]; - for (byte id = 0; id < max; id++) { - VALUES[id] = new IndicesOptions(id); + for (short id = 0; id < max; id++) { + VALUES[id] = new IndicesOptions((byte)id); } } @@ -106,18 +108,31 @@ public class IndicesOptions { * @return whether aliases pointing to multiple indices are allowed */ public boolean allowAliasesToMultipleIndices() { - //true is default here, for bw comp we keep the first 16 values - //in the array same as before + the default value for the new flag + // true is default here, for bw comp we keep the first 16 values + // in the array same as before + the default value for the new flag return (id & FORBID_ALIASES_TO_MULTIPLE_INDICES) == 0; } + /** + * @return whether aliases should be ignored (when resolving a wildcard) + */ + public boolean ignoreAliases() { + return (id & IGNORE_ALIASES) != 0; + } + public void writeIndicesOptions(StreamOutput out) throws IOException { - out.write(id); + if (out.getVersion().onOrAfter(Version.V_6_0_0_alpha2)) { + out.write(id); + } else { + // if we are talking to a node that doesn't support the newly added flag (ignoreAliases) + // flip to 0 all the bits starting from the 7th + out.write(id & 0x3f); + } } public static IndicesOptions readIndicesOptions(StreamInput in) throws IOException { - //if we read from a node that doesn't support the newly added flag (allowAliasesToMultipleIndices) - //we just receive the old corresponding value with the new flag set to true (default) + //if we read from a node that doesn't support the newly added flag (ignoreAliases) + //we just receive the old corresponding value with the new flag set to false (default) byte id = in.readByte(); if (id >= VALUES.length) { throw new IllegalArgumentException("No valid missing index type id: " + id); @@ -133,8 +148,16 @@ public class IndicesOptions { return fromOptions(ignoreUnavailable, allowNoIndices, expandToOpenIndices, expandToClosedIndices, defaultOptions.allowAliasesToMultipleIndices(), defaultOptions.forbidClosedIndices()); } - static IndicesOptions fromOptions(boolean ignoreUnavailable, boolean allowNoIndices, boolean expandToOpenIndices, boolean expandToClosedIndices, boolean allowAliasesToMultipleIndices, boolean forbidClosedIndices) { - byte id = toByte(ignoreUnavailable, allowNoIndices, expandToOpenIndices, expandToClosedIndices, allowAliasesToMultipleIndices, forbidClosedIndices); + public static IndicesOptions fromOptions(boolean ignoreUnavailable, boolean allowNoIndices, boolean expandToOpenIndices, + boolean expandToClosedIndices, boolean allowAliasesToMultipleIndices, boolean forbidClosedIndices) { + return fromOptions(ignoreUnavailable, allowNoIndices, expandToOpenIndices, expandToClosedIndices, allowAliasesToMultipleIndices, + forbidClosedIndices, false); + } + + public static IndicesOptions fromOptions(boolean ignoreUnavailable, boolean allowNoIndices, boolean expandToOpenIndices, + boolean expandToClosedIndices, boolean allowAliasesToMultipleIndices, boolean forbidClosedIndices, boolean ignoreAliases) { + byte id = toByte(ignoreUnavailable, allowNoIndices, expandToOpenIndices, expandToClosedIndices, allowAliasesToMultipleIndices, + forbidClosedIndices, ignoreAliases); return VALUES[id]; } @@ -246,7 +269,7 @@ public class IndicesOptions { } private static byte toByte(boolean ignoreUnavailable, boolean allowNoIndices, boolean wildcardExpandToOpen, - boolean wildcardExpandToClosed, boolean allowAliasesToMultipleIndices, boolean forbidClosedIndices) { + boolean wildcardExpandToClosed, boolean allowAliasesToMultipleIndices, boolean forbidClosedIndices, boolean ignoreAliases) { byte id = 0; if (ignoreUnavailable) { id |= IGNORE_UNAVAILABLE; @@ -268,6 +291,9 @@ public class IndicesOptions { if (forbidClosedIndices) { id |= FORBID_CLOSED_INDICES; } + if (ignoreAliases) { + id |= IGNORE_ALIASES; + } return id; } @@ -281,6 +307,7 @@ public class IndicesOptions { ", expand_wildcards_closed=" + expandWildcardsClosed() + ", allow_aliases_to_multiple_indices=" + allowAliasesToMultipleIndices() + ", forbid_closed_indices=" + forbidClosedIndices() + + ", ignore_aliases=" + ignoreAliases() + ']'; } } 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 711d685c1d6..0841dd3c6bf 100644 --- a/core/src/main/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolver.java +++ b/core/src/main/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolver.java @@ -50,6 +50,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.SortedMap; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -104,7 +105,7 @@ public class IndexNameExpressionResolver extends AbstractComponent { return concreteIndexNames(context, indexExpressions); } - /** + /** * Translates the provided index expression into actual concrete indices, properly deduplicated. * * @param state the cluster state containing all the data to resolve to expressions to concrete indices @@ -181,7 +182,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) { + if (aliasOrIndex == null || (aliasOrIndex.isAlias() && context.getOptions().ignoreAliases())) { if (failNoIndices) { IndexNotFoundException infe = new IndexNotFoundException(expression); infe.setResources("index_expression", expression); @@ -638,7 +639,7 @@ public class IndexNameExpressionResolver extends AbstractComponent { } final IndexMetaData.State excludeState = excludeState(options); - final Map matches = matches(metaData, expression); + final Map matches = matches(context, metaData, expression); Set expand = expand(context, excludeState, matches); if (add) { result.addAll(expand); @@ -693,31 +694,44 @@ public class IndexNameExpressionResolver extends AbstractComponent { return excludeState; } - private static Map matches(MetaData metaData, String expression) { + public static Map matches(Context context, MetaData metaData, String expression) { if (Regex.isMatchAllPattern(expression)) { // Can only happen if the expressions was initially: '-*' - return metaData.getAliasAndIndexLookup(); + if (context.getOptions().ignoreAliases()) { + return metaData.getAliasAndIndexLookup().entrySet().stream() + .filter(e -> e.getValue().isAlias() == false) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } else { + return metaData.getAliasAndIndexLookup(); + } } else if (expression.indexOf("*") == expression.length() - 1) { - return suffixWildcard(metaData, expression); + return suffixWildcard(context, metaData, expression); } else { - return otherWildcard(metaData, expression); + return otherWildcard(context, metaData, expression); } } - private static Map suffixWildcard(MetaData metaData, String expression) { + private static Map suffixWildcard(Context context, MetaData metaData, String expression) { assert expression.length() >= 2 : "expression [" + expression + "] should have at least a length of 2"; String fromPrefix = expression.substring(0, expression.length() - 1); char[] toPrefixCharArr = fromPrefix.toCharArray(); toPrefixCharArr[toPrefixCharArr.length - 1]++; String toPrefix = new String(toPrefixCharArr); - return metaData.getAliasAndIndexLookup().subMap(fromPrefix, toPrefix); + SortedMap subMap = metaData.getAliasAndIndexLookup().subMap(fromPrefix, toPrefix); + if (context.getOptions().ignoreAliases()) { + return subMap.entrySet().stream() + .filter(entry -> entry.getValue().isAlias() == false) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + return subMap; } - private static Map otherWildcard(MetaData metaData, String expression) { + private static Map otherWildcard(Context context, MetaData metaData, String expression) { final String pattern = expression; return metaData.getAliasAndIndexLookup() .entrySet() .stream() + .filter(e -> context.getOptions().ignoreAliases() == false || e.getValue().isAlias() == false) .filter(e -> Regex.simpleMatch(pattern, e.getKey())) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } diff --git a/core/src/test/java/org/elasticsearch/action/support/IndicesOptionsTests.java b/core/src/test/java/org/elasticsearch/action/support/IndicesOptionsTests.java index c687fc6cabc..84acfa7fecd 100644 --- a/core/src/test/java/org/elasticsearch/action/support/IndicesOptionsTests.java +++ b/core/src/test/java/org/elasticsearch/action/support/IndicesOptionsTests.java @@ -32,7 +32,7 @@ public class IndicesOptionsTests extends ESTestCase { int iterations = randomIntBetween(5, 20); for (int i = 0; i < iterations; i++) { IndicesOptions indicesOptions = IndicesOptions.fromOptions( - randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean()); + randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean()); BytesStreamOutput output = new BytesStreamOutput(); Version outputVersion = randomVersion(random()); @@ -50,6 +50,12 @@ public class IndicesOptionsTests extends ESTestCase { assertThat(indicesOptions2.forbidClosedIndices(), equalTo(indicesOptions.forbidClosedIndices())); assertThat(indicesOptions2.allowAliasesToMultipleIndices(), equalTo(indicesOptions.allowAliasesToMultipleIndices())); + + if (output.getVersion().onOrAfter(Version.V_6_0_0_alpha2)) { + assertEquals(indicesOptions2.ignoreAliases(), indicesOptions.ignoreAliases()); + } else { + assertFalse(indicesOptions2.ignoreAliases()); + } } } @@ -62,9 +68,11 @@ public class IndicesOptionsTests extends ESTestCase { boolean expandToClosedIndices = randomBoolean(); boolean allowAliasesToMultipleIndices = randomBoolean(); boolean forbidClosedIndices = randomBoolean(); + boolean ignoreAliases = randomBoolean(); + IndicesOptions indicesOptions = IndicesOptions.fromOptions( ignoreUnavailable, allowNoIndices,expandToOpenIndices, expandToClosedIndices, - allowAliasesToMultipleIndices, forbidClosedIndices + allowAliasesToMultipleIndices, forbidClosedIndices, ignoreAliases ); assertThat(indicesOptions.ignoreUnavailable(), equalTo(ignoreUnavailable)); @@ -74,6 +82,7 @@ public class IndicesOptionsTests extends ESTestCase { assertThat(indicesOptions.allowAliasesToMultipleIndices(), equalTo(allowAliasesToMultipleIndices)); assertThat(indicesOptions.allowAliasesToMultipleIndices(), equalTo(allowAliasesToMultipleIndices)); assertThat(indicesOptions.forbidClosedIndices(), equalTo(forbidClosedIndices)); + assertEquals(ignoreAliases, indicesOptions.ignoreAliases()); } } } diff --git a/core/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java b/core/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java index e711117fb6e..5de9c211a6c 100644 --- a/core/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java +++ b/core/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java @@ -19,7 +19,6 @@ package org.elasticsearch.aliases; -import org.apache.lucene.search.join.ScoreMode; import org.elasticsearch.action.admin.indices.alias.Alias; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions; import org.elasticsearch.action.admin.indices.alias.exists.AliasesExistResponse; @@ -36,6 +35,7 @@ import org.elasticsearch.common.StopWatch; 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; @@ -63,7 +63,6 @@ import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_BLOCKS_ME import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_BLOCKS_READ; import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_BLOCKS_WRITE; import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_READ_ONLY; -import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.index.query.QueryBuilders.rangeQuery; import static org.elasticsearch.index.query.QueryBuilders.termQuery; import static org.elasticsearch.test.hamcrest.CollectionAssertions.hasKey; @@ -425,6 +424,23 @@ public class IndexAliasesIT extends ESIntegTestCase { AliasesExistResponse response = admin().indices().prepareAliasesExist(aliases).get(); assertThat(response.exists(), equalTo(false)); + + logger.info("--> creating index [foo_foo] and [bar_bar]"); + assertAcked(prepareCreate("foo_foo")); + assertAcked(prepareCreate("bar_bar")); + ensureGreen(); + + logger.info("--> adding [foo] alias to [foo_foo] and [bar_bar]"); + assertAcked(admin().indices().prepareAliases().addAlias("foo_foo", "foo")); + assertAcked(admin().indices().prepareAliases().addAlias("bar_bar", "foo")); + + assertAcked(admin().indices().prepareAliases().addAliasAction(AliasActions.remove().index("foo*").alias("foo")).execute().get()); + + 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() + .addAliasAction(AliasActions.remove().index("foo").alias("foo")).execute().actionGet()); } public void testWaitForAliasCreationMultipleShards() throws Exception { @@ -785,6 +801,21 @@ public class IndexAliasesIT extends ESIntegTestCase { } } + public void testAliasesCanBeAddedToIndicesOnly() throws Exception { + logger.info("--> creating index [2017-05-20]"); + assertAcked(prepareCreate("2017-05-20")); + ensureGreen(); + + 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() + .addAliasAction(AliasActions.add().index("week_20").alias("tmp")).execute().actionGet()); + assertEquals("week_20", infe.getIndex().getName()); + + assertAcked(admin().indices().prepareAliases().addAliasAction(AliasActions.add().index("2017-05-20").alias("tmp")).execute().get()); + } + // Before 2.0 alias filters were parsed at alias creation time, in order // for filters to work correctly ES required that fields mentioned in those // filters exist in the mapping. @@ -864,6 +895,26 @@ public class IndexAliasesIT extends ESIntegTestCase { } } + public void testAliasActionRemoveIndex() throws InterruptedException, ExecutionException { + assertAcked(prepareCreate("foo_foo")); + assertAcked(prepareCreate("bar_bar")); + assertAcked(admin().indices().prepareAliases().addAlias("foo_foo", "foo")); + assertAcked(admin().indices().prepareAliases().addAlias("bar_bar", "foo")); + + expectThrows(IndexNotFoundException.class, + () -> client().admin().indices().prepareAliases().removeIndex("foo").execute().actionGet()); + + assertAcked(client().admin().indices().prepareAliases().removeIndex("foo*").execute().get()); + assertFalse(client().admin().indices().prepareExists("foo_foo").execute().actionGet().isExists()); + assertTrue(admin().indices().prepareAliasesExist("foo").get().exists()); + assertTrue(client().admin().indices().prepareExists("bar_bar").execute().actionGet().isExists()); + assertTrue(admin().indices().prepareAliasesExist("foo").setIndices("bar_bar").get().exists()); + + assertAcked(client().admin().indices().prepareAliases().removeIndex("bar_bar")); + assertFalse(admin().indices().prepareAliasesExist("foo").get().exists()); + assertFalse(client().admin().indices().prepareExists("bar_bar").execute().actionGet().isExists()); + } + public void testRemoveIndexAndReplaceWithAlias() throws InterruptedException, ExecutionException { assertAcked(client().admin().indices().prepareCreate("test")); indexRandom(true, client().prepareIndex("test_2", "test", "test").setSource("test", "test")); 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 2143e5e67d4..31e421769c2 100644 --- a/core/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverTests.java +++ b/core/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverTests.java @@ -33,6 +33,7 @@ import org.elasticsearch.test.ESTestCase; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.List; import static org.elasticsearch.common.util.set.Sets.newHashSet; import static org.hamcrest.Matchers.arrayContaining; @@ -643,6 +644,60 @@ public class IndexNameExpressionResolverTests extends ESTestCase { assertEquals(0, indexNames.length); } + public void testConcreteIndicesWildcardAndAliases() { + 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"))); + ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build(); + + // when ignoreAliases option is set, concreteIndexNames resolves the provided expressions + // only against the defined indices + IndicesOptions ignoreAliasesOptions = IndicesOptions.fromOptions(false, false, true, false, true, false, true); + + String[] indexNamesIndexWildcard = indexNameExpressionResolver.concreteIndexNames(state, ignoreAliasesOptions, "foo*"); + + assertEquals(1, indexNamesIndexWildcard.length); + assertEquals("foo_foo", indexNamesIndexWildcard[0]); + + indexNamesIndexWildcard = indexNameExpressionResolver.concreteIndexNames(state, ignoreAliasesOptions, "*o"); + + assertEquals(1, indexNamesIndexWildcard.length); + assertEquals("foo_foo", indexNamesIndexWildcard[0]); + + indexNamesIndexWildcard = indexNameExpressionResolver.concreteIndexNames(state, ignoreAliasesOptions, "f*o"); + + assertEquals(1, indexNamesIndexWildcard.length); + assertEquals("foo_foo", indexNamesIndexWildcard[0]); + + IndexNotFoundException infe = expectThrows(IndexNotFoundException.class, + () -> indexNameExpressionResolver.concreteIndexNames(state, ignoreAliasesOptions, "foo")); + assertThat(infe.getIndex().getName(), equalTo("foo")); + + // when ignoreAliases option is not set, concreteIndexNames resolves the provided + // expressions against the defined indices and aliases + IndicesOptions indicesAndAliasesOptions = IndicesOptions.fromOptions(false, false, true, false, true, false, false); + + List indexNames = Arrays.asList(indexNameExpressionResolver.concreteIndexNames(state, indicesAndAliasesOptions, "foo*")); + assertEquals(2, indexNames.size()); + assertTrue(indexNames.contains("foo_foo")); + assertTrue(indexNames.contains("bar_bar")); + + indexNames = Arrays.asList(indexNameExpressionResolver.concreteIndexNames(state, indicesAndAliasesOptions, "*o")); + assertEquals(2, indexNames.size()); + assertTrue(indexNames.contains("foo_foo")); + assertTrue(indexNames.contains("bar_bar")); + + indexNames = Arrays.asList(indexNameExpressionResolver.concreteIndexNames(state, indicesAndAliasesOptions, "f*o")); + assertEquals(2, indexNames.size()); + assertTrue(indexNames.contains("foo_foo")); + assertTrue(indexNames.contains("bar_bar")); + + indexNames = Arrays.asList(indexNameExpressionResolver.concreteIndexNames(state, indicesAndAliasesOptions, "foo")); + assertEquals(2, indexNames.size()); + assertTrue(indexNames.contains("foo_foo")); + assertTrue(indexNames.contains("bar_bar")); + } + /** * test resolving _all pattern (null, empty array or "_all") for random IndicesOptions */ 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 2778525f7da..3c8b540f45c 100644 --- a/core/src/test/java/org/elasticsearch/cluster/metadata/WildcardExpressionResolverTests.java +++ b/core/src/test/java/org/elasticsearch/cluster/metadata/WildcardExpressionResolverTests.java @@ -23,6 +23,7 @@ import org.elasticsearch.Version; 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.test.ESTestCase; import java.util.Arrays; @@ -125,6 +126,59 @@ public class WildcardExpressionResolverTests extends ESTestCase { assertThat(newHashSet(resolver.resolve(context, Arrays.asList("_all"))), equalTo(newHashSet("testXXX", "testXYY", "testYYY"))); } + public void testConcreteIndicesWildcardAndAliases() { + 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"))); + ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build(); + + // when ignoreAliases option is not set, WildcardExpressionResolver resolves the provided + // expressions against the defined indices and aliases + IndicesOptions indicesAndAliasesOptions = IndicesOptions.fromOptions(false, false, true, false, true, false, false); + IndexNameExpressionResolver.Context indicesAndAliasesContext = new IndexNameExpressionResolver.Context(state, indicesAndAliasesOptions); + + // ignoreAliases option is set, WildcardExpressionResolver resolves the provided expressions + // only against the defined indices + 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())); + } + private 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/docs/reference/migration/migrate_6_0/indices.asciidoc b/docs/reference/migration/migrate_6_0/indices.asciidoc index 95d0253fe63..5ef42303a54 100644 --- a/docs/reference/migration/migrate_6_0/indices.asciidoc +++ b/docs/reference/migration/migrate_6_0/indices.asciidoc @@ -50,3 +50,9 @@ default when a provided wildcard expression doesn't match any closed/open index. Delete a document from non-existing index has been modified to not create the index. However if an external versioning is used the index will be created and the document will be marked for deletion. + +==== Indices aliases api resolves indices expressions only against indices + +The index parameter in the update-aliases, put-alias, and delete-alias APIs no +longer accepts alias names. Instead, it accepts only index names (or wildcards +which will expand to matching indices).