Browse Source

Expand index expressions against indices only when managing aliases (#23997)

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).

Closes #23960
olcbean 8 years ago
parent
commit
0d5f3958e7

+ 4 - 3
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<IndicesAliasesRequest> {
     private List<AliasActions> 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() {
 

+ 38 - 11
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() +
                 ']';
     }
 }

+ 24 - 10
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<Index> 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<String, AliasOrIndex> matches = matches(metaData, expression);
+                final Map<String, AliasOrIndex> matches = matches(context, metaData, expression);
                 Set<String> expand = expand(context, excludeState, matches);
                 if (add) {
                     result.addAll(expand);
@@ -693,31 +694,44 @@ public class IndexNameExpressionResolver extends AbstractComponent {
             return excludeState;
         }
 
-        private static Map<String, AliasOrIndex> matches(MetaData metaData, String expression) {
+        public static Map<String, AliasOrIndex> 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<String, AliasOrIndex> suffixWildcard(MetaData metaData, String expression) {
+        private static Map<String, AliasOrIndex> 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<String,AliasOrIndex> 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<String, AliasOrIndex> otherWildcard(MetaData metaData, String expression) {
+        private static Map<String, AliasOrIndex> 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));
         }

+ 11 - 2
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());
         }
     }
 }

+ 53 - 2
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"));

+ 55 - 0
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<String> 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
      */

+ 54 - 0
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));
     }

+ 6 - 0
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).