Core: Also check if indices resolved via aliases resolution aren't closed and deal with this according to IndicesOptions.

Closes #9057
This commit is contained in:
Martijn van Groningen 2014-12-24 12:14:55 +01:00
parent b0b61ee0c3
commit dedaf9387e
4 changed files with 105 additions and 15 deletions

View File

@ -39,7 +39,8 @@ Controls whether to fail if a wildcard indices expressions results into no
concrete indices. Either `true` or `false` can be specified. For example if
the wildcard expression `foo*` is specified and no indices are available that
start with `foo` then depending on this setting the request will fail. This
setting is also applicable when `_all`, `*` or no index has been specified.
setting is also applicable when `_all`, `*` or no index has been specified. This
settings also applies for aliases, in case an alias points to a closed index.
`expand_wildcards`::

View File

@ -19,7 +19,6 @@
package org.elasticsearch.action.support;
import org.elasticsearch.ElasticsearchIllegalArgumentException;
import org.elasticsearch.Version;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
@ -72,6 +71,8 @@ public class IndicesOptions {
/**
* @return Whether to ignore if a wildcard expression resolves to no concrete indices.
* The `_all` string or empty list of indices count as wildcard expressions too.
* Also when an alias points to a closed index this option decides if no concrete indices
* are allowed.
*/
public boolean allowNoIndices() {
return (id & ALLOW_NO_INDICES) != 0;

View File

@ -679,7 +679,7 @@ public class MetaData implements Iterable<IndexMetaData> {
// optimize for single element index (common case)
if (aliasesOrIndices.length == 1) {
return concreteIndices(aliasesOrIndices[0], indicesOptions, indicesOptions.allowNoIndices());
return concreteIndices(aliasesOrIndices[0], indicesOptions, !indicesOptions.allowNoIndices());
}
// check if its a possible aliased index, if not, just return the passed array
@ -712,7 +712,7 @@ public class MetaData implements Iterable<IndexMetaData> {
Set<String> actualIndices = new HashSet<>();
for (String aliasOrIndex : aliasesOrIndices) {
String[] indices = concreteIndices(aliasOrIndex, indicesOptions, indicesOptions.ignoreUnavailable());
String[] indices = concreteIndices(aliasOrIndex, indicesOptions, !indicesOptions.ignoreUnavailable());
Collections.addAll(actualIndices, indices);
}
@ -760,24 +760,53 @@ public class MetaData implements Iterable<IndexMetaData> {
}
// not an actual index, fetch from an alias
String[] indices = aliasAndIndexToIndexMap.getOrDefault(aliasOrIndex, Strings.EMPTY_ARRAY);
if (indices.length == 0 && !failNoIndices) {
if (indices.length == 0 && failNoIndices) {
throw new IndexMissingException(new Index(aliasOrIndex));
}
if (indices.length > 1 && !options.allowAliasesToMultipleIndices()) {
throw new ElasticsearchIllegalArgumentException("Alias [" + aliasOrIndex + "] has more than one indices associated with it [" + Arrays.toString(indices) + "], can't execute a single index op");
}
indexMetaData = this.indices.get(aliasOrIndex);
if (indexMetaData != null && indexMetaData.getState() == IndexMetaData.State.CLOSE) {
if (failClosed) {
throw new IndexClosedException(new Index(aliasOrIndex));
} else {
if (options.forbidClosedIndices()) {
return Strings.EMPTY_ARRAY;
}
}
// No need to check whether indices referred by aliases are closed, because there are no closed indices.
if (allClosedIndices.length == 0) {
return indices;
}
switch (indices.length) {
case 0:
return indices;
case 1:
indexMetaData = this.indices.get(indices[0]);
if (indexMetaData != null && indexMetaData.getState() == IndexMetaData.State.CLOSE) {
if (failClosed) {
throw new IndexClosedException(new Index(indexMetaData.getIndex()));
} else {
if (options.forbidClosedIndices()) {
return Strings.EMPTY_ARRAY;
}
}
}
return indices;
default:
ObjectArrayList<String> concreteIndices = new ObjectArrayList<>();
for (String index : indices) {
indexMetaData = this.indices.get(index);
if (indexMetaData != null) {
if (indexMetaData.getState() == IndexMetaData.State.CLOSE) {
if (failClosed) {
throw new IndexClosedException(new Index(indexMetaData.getIndex()));
} else if (!options.forbidClosedIndices()) {
concreteIndices.add(index);
}
} else if (indexMetaData.getState() == IndexMetaData.State.OPEN) {
concreteIndices.add(index);
} else {
throw new IllegalStateException("index state [" + indexMetaData.getState() + "] not supported");
}
}
}
return concreteIndices.toArray(String.class);
}
return indices;
}
/**

View File

@ -718,6 +718,65 @@ public class MetaDataTests extends ElasticsearchTestCase {
assertThat(metaData.isPatternMatchingAllIndices(indicesOrAliases, concreteIndices), equalTo(false));
}
@Test
public void testIndexOptions_failClosedIndicesAndAliases() {
MetaData.Builder mdBuilder = MetaData.builder()
.put(indexBuilder("foo1-closed").state(IndexMetaData.State.CLOSE).putAlias(AliasMetaData.builder("foobar1-closed")).putAlias(AliasMetaData.builder("foobar2-closed")))
.put(indexBuilder("foo2-closed").state(IndexMetaData.State.CLOSE).putAlias(AliasMetaData.builder("foobar2-closed")))
.put(indexBuilder("foo3").putAlias(AliasMetaData.builder("foobar2-closed")));
MetaData md = mdBuilder.build();
IndicesOptions options = IndicesOptions.strictExpandOpenAndForbidClosed();
try {
md.concreteIndices(options, "foo1-closed");
fail("foo1-closed should be closed, but it is open");
} catch (IndexClosedException e) {
// expected
}
try {
md.concreteIndices(options, "foobar1-closed");
fail("foo1-closed should be closed, but it is open");
} catch (IndexClosedException e) {
// expected
}
options = IndicesOptions.fromOptions(true, options.allowNoIndices(), options.expandWildcardsOpen(), options.expandWildcardsClosed(), options);
String[] results = md.concreteIndices(options, "foo1-closed");
assertThat(results, emptyArray());
results = md.concreteIndices(options, "foobar1-closed");
assertThat(results, emptyArray());
options = IndicesOptions.lenientExpandOpen();
results = md.concreteIndices(options, "foo1-closed");
assertThat(results, arrayWithSize(1));
assertThat(results, arrayContaining("foo1-closed"));
results = md.concreteIndices(options, "foobar1-closed");
assertThat(results, arrayWithSize(1));
assertThat(results, arrayContaining("foo1-closed"));
// testing an alias pointing to three indices:
options = IndicesOptions.strictExpandOpenAndForbidClosed();
try {
md.concreteIndices(options, "foobar2-closed");
fail("foo2-closed should be closed, but it is open");
} catch (IndexClosedException e) {
// expected
}
options = IndicesOptions.fromOptions(true, options.allowNoIndices(), options.expandWildcardsOpen(), options.expandWildcardsClosed(), options);
results = md.concreteIndices(options, "foobar2-closed");
assertThat(results, arrayWithSize(1));
assertThat(results, arrayContaining("foo3"));
options = IndicesOptions.lenientExpandOpen();
results = md.concreteIndices(options, "foobar2-closed");
assertThat(results, arrayWithSize(3));
assertThat(results, arrayContainingInAnyOrder("foo1-closed", "foo2-closed", "foo3"));
}
private MetaData metaDataBuilder(String... indices) {
MetaData.Builder mdBuilder = MetaData.builder();
for (String concreteIndex : indices) {