Implement hidden aliases (#52547)

This commit introduces hidden aliases. These are similar to hidden
indices, in that they are not visible by default, unless explicitly
specified by name or by indicating that hidden indices/aliases are
desired.

The new alias property, `is_hidden` is implemented similarly to
`is_write_index`, except that it must be consistent across all indices
with a given alias - that is, all indices with a given alias must
specify the alias as either hidden, or all specify it as non-hidden,
either explicitly or by omitting the `is_hidden` property.
This commit is contained in:
Gordon Brown 2020-03-06 16:02:38 -07:00 committed by GitHub
parent 7c9641ef9d
commit ff9b8bda63
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 839 additions and 58 deletions

View File

@ -106,6 +106,13 @@ include::{docdir}/rest-api/common-parms.asciidoc[tag=index-alias-filter]
+
See <<filtered>> for an example.
`is_hidden`::
(Optional, boolean)
If `true`, the alias will be excluded from wildcard expressions by default,
unless overriden in the request using the `expand_wildcards` parameter,
similar to <<index-hidden,hidden indices>>. This property must be set to the
same value on all indices that share an alias. Defaults to `false`.
`is_write_index`::
(Optional, boolean)
If `true`, assigns the index as an alias's write index.

View File

@ -50,6 +50,7 @@ public class Alias implements Writeable, ToXContentFragment {
private static final ParseField INDEX_ROUTING = new ParseField("index_routing", "indexRouting", "index-routing");
private static final ParseField SEARCH_ROUTING = new ParseField("search_routing", "searchRouting", "search-routing");
private static final ParseField IS_WRITE_INDEX = new ParseField("is_write_index");
private static final ParseField IS_HIDDEN = new ParseField("is_hidden");
private String name;
@ -65,6 +66,9 @@ public class Alias implements Writeable, ToXContentFragment {
@Nullable
private Boolean writeIndex;
@Nullable
private Boolean isHidden;
public Alias(StreamInput in) throws IOException {
name = in.readString();
filter = in.readOptionalString();
@ -75,6 +79,11 @@ public class Alias implements Writeable, ToXContentFragment {
} else {
writeIndex = null;
}
if (in.getVersion().onOrAfter(Version.V_7_7_0)) {
isHidden = in.readOptionalBoolean();
} else {
isHidden = null;
}
}
public Alias(String name) {
@ -194,6 +203,21 @@ public class Alias implements Writeable, ToXContentFragment {
return this;
}
/**
* @return whether this alias is hidden or not
*/
public Boolean isHidden() {
return isHidden;
}
/**
* Sets whether this alias is hidden
*/
public Alias isHidden(@Nullable Boolean isHidden) {
this.isHidden = isHidden;
return this;
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeString(name);
@ -203,6 +227,9 @@ public class Alias implements Writeable, ToXContentFragment {
if (out.getVersion().onOrAfter(Version.V_6_4_0)) {
out.writeOptionalBoolean(writeIndex);
}
if (out.getVersion().onOrAfter(Version.V_7_7_0)) {
out.writeOptionalBoolean(isHidden);
}
}
/**
@ -235,6 +262,8 @@ public class Alias implements Writeable, ToXContentFragment {
} else if (token == XContentParser.Token.VALUE_BOOLEAN) {
if (IS_WRITE_INDEX.match(currentFieldName, parser.getDeprecationHandler())) {
alias.writeIndex(parser.booleanValue());
} else if (IS_HIDDEN.match(currentFieldName, parser.getDeprecationHandler())) {
alias.isHidden(parser.booleanValue());
}
}
}
@ -264,6 +293,10 @@ public class Alias implements Writeable, ToXContentFragment {
builder.field(IS_WRITE_INDEX.getPreferredName(), writeIndex);
if (isHidden != null) {
builder.field(IS_HIDDEN.getPreferredName(), isHidden);
}
builder.endObject();
return builder;
}

View File

@ -97,6 +97,7 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
private static final ParseField INDEX_ROUTING = new ParseField("index_routing", "indexRouting", "index-routing");
private static final ParseField SEARCH_ROUTING = new ParseField("search_routing", "searchRouting", "search-routing");
private static final ParseField IS_WRITE_INDEX = new ParseField("is_write_index");
private static final ParseField IS_HIDDEN = new ParseField("is_hidden");
private static final ParseField ADD = new ParseField("add");
private static final ParseField REMOVE = new ParseField("remove");
@ -193,6 +194,7 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
ADD_PARSER.declareField(AliasActions::indexRouting, XContentParser::text, INDEX_ROUTING, ValueType.INT);
ADD_PARSER.declareField(AliasActions::searchRouting, XContentParser::text, SEARCH_ROUTING, ValueType.INT);
ADD_PARSER.declareField(AliasActions::writeIndex, XContentParser::booleanValue, IS_WRITE_INDEX, ValueType.BOOLEAN);
ADD_PARSER.declareField(AliasActions::isHidden, XContentParser::booleanValue, IS_HIDDEN, ValueType.BOOLEAN);
}
private static final ObjectParser<AliasActions, Void> REMOVE_PARSER = parser(REMOVE.getPreferredName(), AliasActions::remove);
private static final ObjectParser<AliasActions, Void> REMOVE_INDEX_PARSER = parser(REMOVE_INDEX.getPreferredName(),
@ -231,6 +233,7 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
private String indexRouting;
private String searchRouting;
private Boolean writeIndex;
private Boolean isHidden;
public AliasActions(AliasActions.Type type) {
this.type = type;
@ -250,9 +253,13 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
if (in.getVersion().onOrAfter(Version.V_6_4_0)) {
writeIndex = in.readOptionalBoolean();
}
if (in.getVersion().onOrAfter(Version.V_7_7_0)) { //TODO fix for backport of https://github.com/elastic/elasticsearch/pull/52547
isHidden = in.readOptionalBoolean();
}
if (in.getVersion().onOrAfter(Version.V_7_0_0)) {
originalAliases = in.readStringArray();
}
}
@Override
@ -267,6 +274,9 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
if (out.getVersion().onOrAfter(Version.V_6_4_0)) {
out.writeOptionalBoolean(writeIndex);
}
if (out.getVersion().onOrAfter(Version.V_7_7_0)) { //TODO fix for backport https://github.com/elastic/elasticsearch/pull/52547
out.writeOptionalBoolean(isHidden);
}
if (out.getVersion().onOrAfter(Version.V_7_0_0)) {
out.writeStringArray(originalAliases);
}
@ -442,6 +452,18 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
return writeIndex;
}
public AliasActions isHidden(Boolean isHidden) {
if (type != AliasActions.Type.ADD) {
throw new IllegalArgumentException("[" + IS_HIDDEN.getPreferredName() + "] is unsupported for [" + type + "]");
}
this.isHidden = isHidden;
return this;
}
public Boolean isHidden() {
return isHidden;
}
@Override
public String[] aliases() {
return aliases;
@ -500,6 +522,9 @@ public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesReq
if (null != writeIndex) {
builder.field(IS_WRITE_INDEX.getPreferredName(), writeIndex);
}
if (null != isHidden) {
builder.field(IS_HIDDEN.getPreferredName(), isHidden);
}
builder.endObject();
builder.endObject();
return builder;

View File

@ -125,7 +125,7 @@ public class TransportIndicesAliasesAction extends TransportMasterNodeAction<Ind
case ADD:
for (String alias : concreteAliases(action, state.metaData(), index.getName())) {
finalActions.add(new AliasAction.Add(index.getName(), alias, action.filter(), action.indexRouting(),
action.searchRouting(), action.writeIndex()));
action.searchRouting(), action.writeIndex(), action.isHidden()));
}
break;
case REMOVE:

View File

@ -214,11 +214,11 @@ public class TransportRolloverAction extends TransportMasterNodeAction<RolloverR
boolean explicitWriteIndex) {
if (explicitWriteIndex) {
return unmodifiableList(Arrays.asList(
new AliasAction.Add(newIndex, request.getAlias(), null, null, null, true),
new AliasAction.Add(oldIndex, request.getAlias(), null, null, null, false)));
new AliasAction.Add(newIndex, request.getAlias(), null, null, null, true, null),
new AliasAction.Add(oldIndex, request.getAlias(), null, null, null, false, null)));
} else {
return unmodifiableList(Arrays.asList(
new AliasAction.Add(newIndex, request.getAlias(), null, null, null, null),
new AliasAction.Add(newIndex, request.getAlias(), null, null, null, null, null),
new AliasAction.Remove(oldIndex, request.getAlias())));
}
}

View File

@ -85,11 +85,13 @@ public abstract class AliasAction {
@Nullable
private final Boolean writeIndex;
@Nullable final Boolean isHidden;
/**
* Build the operation.
*/
public Add(String index, String alias, @Nullable String filter, @Nullable String indexRouting,
@Nullable String searchRouting, @Nullable Boolean writeIndex) {
public Add(String index, String alias, @Nullable String filter, @Nullable String indexRouting, @Nullable String searchRouting,
@Nullable Boolean writeIndex, @Nullable Boolean isHidden) {
super(index);
if (false == Strings.hasText(alias)) {
throw new IllegalArgumentException("[alias] is required");
@ -99,6 +101,7 @@ public abstract class AliasAction {
this.indexRouting = indexRouting;
this.searchRouting = searchRouting;
this.writeIndex = writeIndex;
this.isHidden = isHidden;
}
/**
@ -112,6 +115,11 @@ public abstract class AliasAction {
return writeIndex;
}
@Nullable
public Boolean isHidden() {
return isHidden;
}
@Override
boolean removeIndex() {
return false;
@ -122,7 +130,7 @@ public abstract class AliasAction {
aliasValidator.validate(alias, indexRouting, filter, writeIndex);
AliasMetaData newAliasMd = AliasMetaData.newAliasMetaDataBuilder(alias).filter(filter).indexRouting(indexRouting)
.searchRouting(searchRouting).writeIndex(writeIndex).build();
.searchRouting(searchRouting).writeIndex(writeIndex).isHidden(isHidden).build();
// Check if this alias already exists
AliasMetaData currentAliasMd = index.getAliases().get(alias);

View File

@ -41,6 +41,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import static java.util.Collections.emptySet;
@ -60,7 +61,11 @@ public class AliasMetaData extends AbstractDiffable<AliasMetaData> implements To
@Nullable
private final Boolean writeIndex;
private AliasMetaData(String alias, CompressedXContent filter, String indexRouting, String searchRouting, Boolean writeIndex) {
@Nullable
private final Boolean isHidden;
private AliasMetaData(String alias, CompressedXContent filter, String indexRouting, String searchRouting, Boolean writeIndex,
@Nullable Boolean isHidden) {
this.alias = alias;
this.filter = filter;
this.indexRouting = indexRouting;
@ -71,10 +76,12 @@ public class AliasMetaData extends AbstractDiffable<AliasMetaData> implements To
searchRoutingValues = emptySet();
}
this.writeIndex = writeIndex;
this.isHidden = isHidden;
}
private AliasMetaData(AliasMetaData aliasMetaData, String alias) {
this(alias, aliasMetaData.filter(), aliasMetaData.indexRouting(), aliasMetaData.searchRouting(), aliasMetaData.writeIndex());
this(alias, aliasMetaData.filter(), aliasMetaData.indexRouting(), aliasMetaData.searchRouting(), aliasMetaData.writeIndex(),
aliasMetaData.isHidden);
}
public String alias() {
@ -121,6 +128,11 @@ public class AliasMetaData extends AbstractDiffable<AliasMetaData> implements To
return writeIndex;
}
@Nullable
public Boolean isHidden() {
return isHidden;
}
public static Builder builder(String alias) {
return new Builder(alias);
}
@ -143,11 +155,12 @@ public class AliasMetaData extends AbstractDiffable<AliasMetaData> implements To
final AliasMetaData that = (AliasMetaData) o;
if (alias != null ? !alias.equals(that.alias) : that.alias != null) return false;
if (filter != null ? !filter.equals(that.filter) : that.filter != null) return false;
if (indexRouting != null ? !indexRouting.equals(that.indexRouting) : that.indexRouting != null) return false;
if (searchRouting != null ? !searchRouting.equals(that.searchRouting) : that.searchRouting != null) return false;
if (writeIndex != null ? writeIndex != that.writeIndex : that.writeIndex != null) return false;
if (Objects.equals(alias, that.alias) == false) return false;
if (Objects.equals(filter, that.filter) == false) return false;
if (Objects.equals(indexRouting, that.indexRouting) == false) return false;
if (Objects.equals(searchRouting, that.searchRouting) == false) return false;
if (Objects.equals(writeIndex, that.writeIndex) == false) return false;
if (Objects.equals(isHidden, that.isHidden) == false) return false;
return true;
}
@ -187,6 +200,10 @@ public class AliasMetaData extends AbstractDiffable<AliasMetaData> implements To
if (out.getVersion().onOrAfter(Version.V_6_4_0)) {
out.writeOptionalBoolean(writeIndex());
}
if (out.getVersion().onOrAfter(Version.V_7_7_0)) {
out.writeOptionalBoolean(isHidden());
}
}
public AliasMetaData(StreamInput in) throws IOException {
@ -213,6 +230,12 @@ public class AliasMetaData extends AbstractDiffable<AliasMetaData> implements To
} else {
writeIndex = null;
}
if (in.getVersion().onOrAfter(Version.V_7_7_0)) {
isHidden = in.readOptionalBoolean();
} else {
isHidden = null;
}
}
public static Diff<AliasMetaData> readDiffFrom(StreamInput in) throws IOException {
@ -243,6 +266,8 @@ public class AliasMetaData extends AbstractDiffable<AliasMetaData> implements To
@Nullable
private Boolean writeIndex;
@Nullable
private Boolean isHidden;
public Builder(String alias) {
this.alias = alias;
@ -300,8 +325,13 @@ public class AliasMetaData extends AbstractDiffable<AliasMetaData> implements To
return this;
}
public Builder isHidden(@Nullable Boolean isHidden) {
this.isHidden = isHidden;
return this;
}
public AliasMetaData build() {
return new AliasMetaData(alias, filter, indexRouting, searchRouting, writeIndex);
return new AliasMetaData(alias, filter, indexRouting, searchRouting, writeIndex, isHidden);
}
public static void toXContent(AliasMetaData aliasMetaData, XContentBuilder builder, ToXContent.Params params) throws IOException {
@ -327,6 +357,10 @@ public class AliasMetaData extends AbstractDiffable<AliasMetaData> implements To
builder.field("is_write_index", aliasMetaData.writeIndex());
}
if (aliasMetaData.isHidden != null) {
builder.field("is_hidden", aliasMetaData.isHidden());
}
builder.endObject();
}
@ -366,6 +400,8 @@ public class AliasMetaData extends AbstractDiffable<AliasMetaData> implements To
} else if (token == XContentParser.Token.VALUE_BOOLEAN) {
if ("is_write_index".equals(currentFieldName)) {
builder.writeIndex(parser.booleanValue());
} else if ("is_hidden".equals(currentFieldName)) {
builder.isHidden(parser.booleanValue());
}
}
}

View File

@ -28,8 +28,12 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import static org.elasticsearch.cluster.metadata.IndexMetaData.INDEX_HIDDEN_SETTING;
/**
* Encapsulates the {@link IndexMetaData} instances of a concrete index or indices an alias is pointing to.
*/
@ -46,6 +50,11 @@ public interface AliasOrIndex {
*/
List<IndexMetaData> getIndices();
/**
* @return whether this alias/index is hidden or not
*/
boolean isHidden();
/**
* Represents an concrete index and encapsulates its {@link IndexMetaData}
*/
@ -66,6 +75,11 @@ public interface AliasOrIndex {
public List<IndexMetaData> getIndices() {
return Collections.singletonList(concreteIndex);
}
@Override
public boolean isHidden() {
return INDEX_HIDDEN_SETTING.get(concreteIndex.getSettings());
}
}
/**
@ -76,11 +90,13 @@ public interface AliasOrIndex {
private final String aliasName;
private final List<IndexMetaData> referenceIndexMetaDatas;
private final SetOnce<IndexMetaData> writeIndex = new SetOnce<>();
private final boolean isHidden;
public Alias(AliasMetaData aliasMetaData, IndexMetaData indexMetaData) {
this.aliasName = aliasMetaData.getAlias();
this.referenceIndexMetaDatas = new ArrayList<>();
this.referenceIndexMetaDatas.add(indexMetaData);
this.isHidden = aliasMetaData.isHidden() == null ? false : aliasMetaData.isHidden();
}
@Override
@ -103,6 +119,11 @@ public interface AliasOrIndex {
return writeIndex.get();
}
@Override
public boolean isHidden() {
return isHidden;
}
/**
* Returns the unique alias metadata per concrete index.
*
@ -135,7 +156,8 @@ public interface AliasOrIndex {
this.referenceIndexMetaDatas.add(indexMetaData);
}
public void computeAndValidateWriteIndex() {
public void computeAndValidateAliasProperties() {
// Validate write indices
List<IndexMetaData> writeIndices = referenceIndexMetaDatas.stream()
.filter(idxMeta -> Boolean.TRUE.equals(idxMeta.getAliases().get(aliasName).writeIndex()))
.collect(Collectors.toList());
@ -153,6 +175,24 @@ public interface AliasOrIndex {
throw new IllegalStateException("alias [" + aliasName + "] has more than one write index [" +
Strings.collectionToCommaDelimitedString(writeIndicesStrings) + "]");
}
// Validate hidden status
final Map<Boolean, List<IndexMetaData>> groupedByHiddenStatus = referenceIndexMetaDatas.stream()
.collect(Collectors.groupingBy(idxMeta -> Boolean.TRUE.equals(idxMeta.getAliases().get(aliasName).isHidden())));
if (isNonEmpty(groupedByHiddenStatus.get(true)) && isNonEmpty(groupedByHiddenStatus.get(false))) {
List<String> hiddenOn = groupedByHiddenStatus.get(true).stream()
.map(idx -> idx.getIndex().getName()).collect(Collectors.toList());
List<String> nonHiddenOn = groupedByHiddenStatus.get(false).stream()
.map(idx -> idx.getIndex().getName()).collect(Collectors.toList());
throw new IllegalStateException("alias [" + aliasName + "] has is_hidden set to true on indices [" +
Strings.collectionToCommaDelimitedString(hiddenOn) + "] but does not have is_hidden set to true on indices [" +
Strings.collectionToCommaDelimitedString(nonHiddenOn) + "]; alias must have the same is_hidden setting " +
"on all indices");
}
}
private boolean isNonEmpty(List<IndexMetaData> idxMetas) {
return (Objects.isNull(idxMetas) || idxMetas.isEmpty()) == false;
}
}
}

View File

@ -723,7 +723,7 @@ public class IndexNameExpressionResolver {
// add all the previous ones...
result = new HashSet<>(expressions.subList(0, i));
}
if (!Regex.isSimpleMatchPattern(expression)) {
if (Regex.isSimpleMatchPattern(expression) == false) {
//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);
@ -842,27 +842,29 @@ public class IndexNameExpressionResolver {
String expression, boolean includeHidden) {
Set<String> expand = new HashSet<>();
for (Map.Entry<String, AliasOrIndex> entry : matches.entrySet()) {
String aliasOrIndexName = entry.getKey();
AliasOrIndex aliasOrIndex = entry.getValue();
if (context.isPreserveAliases() && aliasOrIndex.isAlias()) {
expand.add(entry.getKey());
} else {
for (IndexMetaData meta : aliasOrIndex.getIndices()) {
if (excludeState == null || meta.getState() != excludeState) {
if (includeHidden) {
expand.add(meta.getIndex().getName());
} else if (IndexMetaData.INDEX_HIDDEN_SETTING.get(meta.getSettings()) == false) {
expand.add(meta.getIndex().getName());
} else if (meta.getIndex().getName().startsWith(".") &&
expression.startsWith(".") && Regex.isSimpleMatchPattern(expression)) {
if (aliasOrIndex.isHidden() == false || includeHidden || implicitHiddenMatch(aliasOrIndexName, expression)) {
if (context.isPreserveAliases() && aliasOrIndex.isAlias()) {
expand.add(aliasOrIndexName);
} else {
for (IndexMetaData meta : aliasOrIndex.getIndices()) {
if (excludeState == null || meta.getState() != excludeState) {
expand.add(meta.getIndex().getName());
}
}
}
}
}
return expand;
}
private static boolean implicitHiddenMatch(String itemName, String expression) {
return itemName.startsWith(".") && expression.startsWith(".") && Regex.isSimpleMatchPattern(expression);
}
private boolean isEmptyOrTrivialWildcard(List<String> expressions) {
return expressions.isEmpty() || (expressions.size() == 1 && (MetaData.ALL.equals(expressions.get(0)) ||
Regex.isMatchAllPattern(expressions.get(0))));

View File

@ -1342,7 +1342,7 @@ public class MetaData implements Iterable<IndexMetaData>, Diffable<MetaData>, To
}
}
aliasAndIndexLookup.values().stream().filter(AliasOrIndex::isAlias)
.forEach(alias -> ((AliasOrIndex.Alias) alias).computeAndValidateWriteIndex());
.forEach(alias -> ((AliasOrIndex.Alias) alias).computeAndValidateAliasProperties());
return aliasAndIndexLookup;
}

View File

@ -587,7 +587,8 @@ public class MetaDataCreateIndexService {
aliasValidator.validateAliasFilter(alias.name(), alias.filter(), queryShardContext, xContentRegistry);
}
AliasMetaData aliasMetaData = AliasMetaData.builder(alias.name()).filter(alias.filter())
.indexRouting(alias.indexRouting()).searchRouting(alias.searchRouting()).writeIndex(alias.writeIndex()).build();
.indexRouting(alias.indexRouting()).searchRouting(alias.searchRouting()).writeIndex(alias.writeIndex())
.isHidden(alias.isHidden()).build();
resolvedAliases.add(aliasMetaData);
}

View File

@ -115,6 +115,7 @@ public class AliasActionsTests extends ESTestCase {
Object searchRouting = randomBoolean() ? randomRouting() : null;
Object indexRouting = randomBoolean() ? randomBoolean() ? searchRouting : randomRouting() : null;
boolean writeIndex = randomBoolean();
boolean isHidden = randomBoolean();
XContentBuilder b = XContentBuilder.builder(randomFrom(XContentType.values()).xContent());
b.startObject();
{
@ -144,6 +145,7 @@ public class AliasActionsTests extends ESTestCase {
b.field("index_routing", indexRouting);
}
b.field("is_write_index", writeIndex);
b.field("is_hidden", isHidden);
}
b.endObject();
}
@ -162,6 +164,7 @@ public class AliasActionsTests extends ESTestCase {
assertEquals(Objects.toString(searchRouting, null), action.searchRouting());
assertEquals(Objects.toString(indexRouting, null), action.indexRouting());
assertEquals(writeIndex, action.writeIndex());
assertEquals(isHidden, action.isHidden());
}
}

View File

@ -28,7 +28,9 @@ import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.AliasOrIndex;
@ -54,6 +56,7 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
@ -79,6 +82,7 @@ import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitC
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.emptyArray;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.lessThan;
import static org.hamcrest.Matchers.notNullValue;
@ -926,7 +930,8 @@ public class IndexAliasesIT extends ESIntegTestCase {
.addMapping("type", "field", "type=text")
.addAlias(new Alias("alias1"))
.addAlias(new Alias("alias2").filter(QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery("field"))))
.addAlias(new Alias("alias3").indexRouting("index").searchRouting("search")));
.addAlias(new Alias("alias3").indexRouting("index").searchRouting("search"))
.addAlias(new Alias("alias4").isHidden(true)));
checkAliases();
}
@ -936,7 +941,8 @@ public class IndexAliasesIT extends ESIntegTestCase {
" \"aliases\" : {\n" +
" \"alias1\" : {},\n" +
" \"alias2\" : {\"filter\" : {\"match_all\": {}}},\n" +
" \"alias3\" : { \"index_routing\" : \"index\", \"search_routing\" : \"search\"}\n" +
" \"alias3\" : { \"index_routing\" : \"index\", \"search_routing\" : \"search\"},\n" +
" \"alias4\" : {\"is_hidden\": true}\n" +
" }\n" +
"}", XContentType.JSON));
@ -949,7 +955,8 @@ public class IndexAliasesIT extends ESIntegTestCase {
.setAliases("{\n" +
" \"alias1\" : {},\n" +
" \"alias2\" : {\"filter\" : {\"term\": {\"field\":\"value\"}}},\n" +
" \"alias3\" : { \"index_routing\" : \"index\", \"search_routing\" : \"search\"}\n" +
" \"alias3\" : { \"index_routing\" : \"index\", \"search_routing\" : \"search\"},\n" +
" \"alias4\" : {\"is_hidden\": true}\n" +
"}"));
checkAliases();
@ -1136,6 +1143,104 @@ public class IndexAliasesIT extends ESIntegTestCase {
assertHitCount(client().prepareSearch("test").get(), 1);
}
public void testHiddenAliasesMustBeConsistent() {
final String index1 = randomAlphaOfLength(5).toLowerCase(Locale.ROOT);
final String index2 = randomAlphaOfLength(6).toLowerCase(Locale.ROOT);
final String alias = randomAlphaOfLength(7).toLowerCase(Locale.ROOT);
createIndex(index1, index2);
assertAcked(admin().indices().prepareAliases().addAliasAction(AliasActions.add().index(index1).alias(alias)));
IllegalStateException ex = expectThrows(IllegalStateException.class, () -> {
AcknowledgedResponse res = admin().indices().prepareAliases()
.addAliasAction(AliasActions.add().index(index2).alias(alias).isHidden(true)).get();
});
logger.error("exception: {}", ex.getMessage());
assertThat(ex.getMessage(), containsString("has is_hidden set to true on indices"));
assertAcked(admin().indices().prepareAliases().addAliasAction(AliasActions.remove().index(index1).alias(alias)));
assertAcked(admin().indices().prepareAliases().addAliasAction(AliasActions.add().index(index1).alias(alias).isHidden(false)));
expectThrows(IllegalStateException.class,
() -> admin().indices().prepareAliases().addAliasAction(AliasActions.add().index(index2).alias(alias).isHidden(true)).get());
assertAcked(admin().indices().prepareAliases().addAliasAction(AliasActions.remove().index(index1).alias(alias)));
assertAcked(admin().indices().prepareAliases().addAliasAction(AliasActions.add().index(index1).alias(alias).isHidden(true)));
expectThrows(IllegalStateException.class,
() -> admin().indices().prepareAliases().addAliasAction(AliasActions.add().index(index2).alias(alias).isHidden(false)).get());
expectThrows(IllegalStateException.class,
() -> admin().indices().prepareAliases().addAliasAction(AliasActions.add().index(index2).alias(alias)).get());
// Both visible
assertAcked(admin().indices().prepareAliases().addAliasAction(AliasActions.remove().index(index1).alias(alias)));
assertAcked(admin().indices().prepareAliases().addAliasAction(AliasActions.add().index(index1).alias(alias).isHidden(false)));
assertAcked(admin().indices().prepareAliases().addAliasAction(AliasActions.add().index(index2).alias(alias).isHidden(false)));
// Both hidden
assertAcked(admin().indices().prepareAliases()
.addAliasAction(AliasActions.remove().index(index1).alias(alias))
.addAliasAction(AliasActions.remove().index(index2).alias(alias)));
assertAcked(admin().indices().prepareAliases().addAliasAction(AliasActions.add().index(index1).alias(alias).isHidden(true)));
assertAcked(admin().indices().prepareAliases().addAliasAction(AliasActions.add().index(index2).alias(alias).isHidden(true)));
// Visible on one, then update it to hidden & add to a second as hidden simultaneously
assertAcked(admin().indices().prepareAliases()
.addAliasAction(AliasActions.remove().index(index1).alias(alias))
.addAliasAction(AliasActions.remove().index(index2).alias(alias)));
assertAcked(admin().indices().prepareAliases()
.addAliasAction(AliasActions.add().index(index2).alias(alias).isHidden(false)));
assertAcked(admin().indices().prepareAliases()
.addAliasAction(AliasActions.add().index(index1).alias(alias).isHidden(true))
.addAliasAction(AliasActions.add().index(index2).alias(alias).isHidden(true)));
}
public void testIndexingAndQueryingHiddenAliases() throws Exception {
final String writeIndex = randomAlphaOfLength(5).toLowerCase(Locale.ROOT);
final String nonWriteIndex = randomAlphaOfLength(6).toLowerCase(Locale.ROOT);
final String alias = "alias-" + randomAlphaOfLength(7).toLowerCase(Locale.ROOT);
createIndex(writeIndex, nonWriteIndex);
assertAcked(admin().indices().prepareAliases()
.addAliasAction(AliasActions.add().index(writeIndex).alias(alias).isHidden(true).writeIndex(true))
.addAliasAction(AliasActions.add().index(nonWriteIndex).alias(alias).isHidden(true)));
ensureGreen();
// Put a couple docs in each index directly
IndexResponse res = client().index(indexRequest(nonWriteIndex).id("1").source(source("1", "nonwrite"), XContentType.JSON)).get();
assertThat(res.status().getStatus(), equalTo(201));
res = client().index(indexRequest(writeIndex).id("2").source(source("2", "writeindex"), XContentType.JSON)).get();
assertThat(res.status().getStatus(), equalTo(201));
// And through the alias
res = client().index(indexRequest(alias).id("3").source(source("3", "through alias"), XContentType.JSON)).get();
assertThat(res.status().getStatus(), equalTo(201));
refresh(writeIndex, nonWriteIndex);
// Make sure that the doc written to the alias made it
SearchResponse searchResponse = client().prepareSearch(writeIndex).setQuery(QueryBuilders.matchAllQuery()).get();
assertHits(searchResponse.getHits(), "2", "3");
// Ensure that all docs can be gotten through the alias
searchResponse = client().prepareSearch(alias).setQuery(QueryBuilders.matchAllQuery()).get();
assertHits(searchResponse.getHits(), "1", "2", "3");
// And querying using a wildcard with indices options set to expand hidden
searchResponse = client().prepareSearch("alias*")
.setQuery(QueryBuilders.matchAllQuery())
.setIndicesOptions(IndicesOptions.fromOptions(false, false, true, false, true, true, true, false, false)).get();
assertHits(searchResponse.getHits(), "1", "2", "3");
// And that querying the alias with a wildcard and no expand options fails
searchResponse = client().prepareSearch("alias*").setQuery(QueryBuilders.matchAllQuery()).get();
assertThat(searchResponse.getHits().getHits(), emptyArray());
}
public void testGetAliasAndAliasExistsForHiddenAliases() {
final String writeIndex = randomAlphaOfLength(5).toLowerCase(Locale.ROOT);
final String nonWriteIndex = randomAlphaOfLength(6).toLowerCase(Locale.ROOT);
final String alias = "alias-" + randomAlphaOfLength(7).toLowerCase(Locale.ROOT);
}
private void checkAliases() {
GetAliasesResponse getAliasesResponse = admin().indices().prepareGetAliases("alias1").get();
assertThat(getAliasesResponse.getAliases().get("test").size(), equalTo(1));
@ -1144,6 +1249,7 @@ public class IndexAliasesIT extends ESIntegTestCase {
assertThat(aliasMetaData.filter(), nullValue());
assertThat(aliasMetaData.indexRouting(), nullValue());
assertThat(aliasMetaData.searchRouting(), nullValue());
assertThat(aliasMetaData.isHidden(), nullValue());
getAliasesResponse = admin().indices().prepareGetAliases("alias2").get();
assertThat(getAliasesResponse.getAliases().get("test").size(), equalTo(1));
@ -1152,6 +1258,7 @@ public class IndexAliasesIT extends ESIntegTestCase {
assertThat(aliasMetaData.filter(), notNullValue());
assertThat(aliasMetaData.indexRouting(), nullValue());
assertThat(aliasMetaData.searchRouting(), nullValue());
assertThat(aliasMetaData.isHidden(), nullValue());
getAliasesResponse = admin().indices().prepareGetAliases("alias3").get();
assertThat(getAliasesResponse.getAliases().get("test").size(), equalTo(1));
@ -1160,6 +1267,16 @@ public class IndexAliasesIT extends ESIntegTestCase {
assertThat(aliasMetaData.filter(), nullValue());
assertThat(aliasMetaData.indexRouting(), equalTo("index"));
assertThat(aliasMetaData.searchRouting(), equalTo("search"));
assertThat(aliasMetaData.isHidden(), nullValue());
getAliasesResponse = admin().indices().prepareGetAliases("alias4").get();
assertThat(getAliasesResponse.getAliases().get("test").size(), equalTo(1));
aliasMetaData = getAliasesResponse.getAliases().get("test").get(0);
assertThat(aliasMetaData.alias(), equalTo("alias4"));
assertThat(aliasMetaData.filter(), nullValue());
assertThat(aliasMetaData.indexRouting(), nullValue());
assertThat(aliasMetaData.searchRouting(), nullValue());
assertThat(aliasMetaData.isHidden(), equalTo(true));
}
private void assertHits(SearchHits hits, String... ids) {

View File

@ -42,6 +42,7 @@ public class AliasMetaDataTests extends AbstractXContentTestCase<AliasMetaData>
.routing("routing")
.searchRouting("trim,tw , ltw , lw")
.writeIndex(randomBoolean() ? null : randomBoolean())
.isHidden(randomBoolean() ? null : randomBoolean())
.build();
assertThat(before.searchRoutingValues(), equalTo(Sets.newHashSet("trim", "tw ", " ltw ", " lw")));
@ -64,6 +65,7 @@ public class AliasMetaDataTests extends AbstractXContentTestCase<AliasMetaData>
.indexRouting(expectedInstance.indexRouting())
.searchRouting(expectedInstance.searchRouting())
.writeIndex(randomBoolean() ? null : randomBoolean())
.isHidden(randomBoolean() ? null : randomBoolean())
.build();
}
assertEquals(expectedInstance, newInstance);
@ -112,6 +114,10 @@ public class AliasMetaDataTests extends AbstractXContentTestCase<AliasMetaData>
builder.filter("{\"term\":{\"year\":2016}}");
}
builder.writeIndex(randomBoolean());
if (randomBoolean()) {
builder.isHidden(randomBoolean());
}
return builder.build();
}

View File

@ -0,0 +1,132 @@
/*
*
* * Licensed to Elasticsearch under one or more contributor
* * license agreements. See the NOTICE file distributed with
* * this work for additional information regarding copyright
* * ownership. Elasticsearch licenses this file to you under
* * the Apache License, Version 2.0 (the "License"); you may
* * not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * http://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing,
* * software distributed under the License is distributed on an
* * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* * KIND, either express or implied. See the License for the
* * specific language governing permissions and limitations
* * under the License.
*
*/
package org.elasticsearch.cluster.metadata;
import org.elasticsearch.Version;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.test.ESTestCase;
import java.util.Objects;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsString;
public class AliasOrIndexTests extends ESTestCase {
public void testHiddenAliasValidation() {
final String hiddenAliasName = "hidden_alias";
AliasMetaData hiddenAliasMetadata = new AliasMetaData.Builder(hiddenAliasName).isHidden(true).build();
IndexMetaData hidden1 = buildIndexWithAlias("hidden1", hiddenAliasName, true);
IndexMetaData hidden2 = buildIndexWithAlias("hidden2", hiddenAliasName, true);
IndexMetaData hidden3 = buildIndexWithAlias("hidden3", hiddenAliasName, true);
IndexMetaData indexWithNonHiddenAlias = buildIndexWithAlias("nonhidden1", hiddenAliasName, false);
IndexMetaData indexWithUnspecifiedAlias = buildIndexWithAlias("nonhidden2", hiddenAliasName, null);
{
AliasOrIndex.Alias allHidden = new AliasOrIndex.Alias(hiddenAliasMetadata, hidden1);
allHidden.addIndex(hidden2);
allHidden.addIndex(hidden3);
allHidden.computeAndValidateAliasProperties(); // Should be ok
}
{
AliasOrIndex.Alias allVisible;
if (randomBoolean()) {
allVisible = new AliasOrIndex.Alias(hiddenAliasMetadata, indexWithNonHiddenAlias);
allVisible.addIndex(indexWithUnspecifiedAlias);
} else {
allVisible = new AliasOrIndex.Alias(hiddenAliasMetadata, indexWithUnspecifiedAlias);
allVisible.addIndex(indexWithNonHiddenAlias);
}
allVisible.computeAndValidateAliasProperties(); // Should be ok
}
{
AliasOrIndex.Alias oneNonHidden = new AliasOrIndex.Alias(hiddenAliasMetadata, hidden1);
oneNonHidden.addIndex(hidden2);
oneNonHidden.addIndex(hidden3);
oneNonHidden.addIndex(indexWithNonHiddenAlias);
IllegalStateException exception = expectThrows(IllegalStateException.class,
() -> oneNonHidden.computeAndValidateAliasProperties());
assertThat(exception.getMessage(), containsString("alias [" + hiddenAliasName +
"] has is_hidden set to true on indices ["));
assertThat(exception.getMessage(), allOf(containsString(hidden1.getIndex().getName()),
containsString(hidden2.getIndex().getName()),
containsString(hidden3.getIndex().getName())));
assertThat(exception.getMessage(), containsString("but does not have is_hidden set to true on indices [" +
indexWithNonHiddenAlias.getIndex().getName() + "]; alias must have the same is_hidden setting on all indices"));
}
{
AliasOrIndex.Alias oneUnspecified = new AliasOrIndex.Alias(hiddenAliasMetadata, hidden1);
oneUnspecified.addIndex(hidden2);
oneUnspecified.addIndex(hidden3);
oneUnspecified.addIndex(indexWithUnspecifiedAlias);
IllegalStateException exception = expectThrows(IllegalStateException.class,
() -> oneUnspecified.computeAndValidateAliasProperties());
assertThat(exception.getMessage(), containsString("alias [" + hiddenAliasName +
"] has is_hidden set to true on indices ["));
assertThat(exception.getMessage(), allOf(containsString(hidden1.getIndex().getName()),
containsString(hidden2.getIndex().getName()),
containsString(hidden3.getIndex().getName())));
assertThat(exception.getMessage(), containsString("but does not have is_hidden set to true on indices [" +
indexWithUnspecifiedAlias.getIndex().getName() + "]; alias must have the same is_hidden setting on all indices"));
}
{
AliasOrIndex.Alias mostlyVisibleOneHidden;
if (randomBoolean()) {
mostlyVisibleOneHidden = new AliasOrIndex.Alias(hiddenAliasMetadata, indexWithNonHiddenAlias);
mostlyVisibleOneHidden.addIndex(indexWithUnspecifiedAlias);
} else {
mostlyVisibleOneHidden = new AliasOrIndex.Alias(hiddenAliasMetadata, indexWithUnspecifiedAlias);
mostlyVisibleOneHidden.addIndex(indexWithNonHiddenAlias);
}
final IndexMetaData hiddenIndex = randomFrom(hidden1, hidden2, hidden3);
mostlyVisibleOneHidden.addIndex(hiddenIndex);
IllegalStateException exception = expectThrows(IllegalStateException.class,
() -> mostlyVisibleOneHidden.computeAndValidateAliasProperties());
assertThat(exception.getMessage(), containsString("alias [" + hiddenAliasName + "] has is_hidden set to true on " +
"indices [" + hiddenIndex.getIndex().getName() + "] but does not have is_hidden set to true on indices ["));
assertThat(exception.getMessage(), allOf(containsString(indexWithUnspecifiedAlias.getIndex().getName()),
containsString(indexWithNonHiddenAlias.getIndex().getName())));
assertThat(exception.getMessage(), containsString("but does not have is_hidden set to true on indices ["));
}
}
private IndexMetaData buildIndexWithAlias(String indexName, String aliasName, @Nullable Boolean aliasIsHidden) {
final AliasMetaData.Builder aliasMetaData = new AliasMetaData.Builder(aliasName);
if (Objects.nonNull(aliasIsHidden) || randomBoolean()) {
aliasMetaData.isHidden(aliasIsHidden);
}
return new IndexMetaData.Builder(indexName)
.settings(settings(Version.CURRENT))
.numberOfShards(1)
.numberOfReplicas(0)
.putAlias(aliasMetaData)
.build();
}
}

View File

@ -49,11 +49,14 @@ import java.util.List;
import java.util.Set;
import java.util.function.Function;
import static org.elasticsearch.cluster.metadata.IndexMetaData.INDEX_HIDDEN_SETTING;
import static org.elasticsearch.common.util.set.Sets.newHashSet;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
import static org.hamcrest.Matchers.arrayWithSize;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.emptyArray;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.equalTo;
@ -883,6 +886,170 @@ public class IndexNameExpressionResolverTests extends ESTestCase {
assertTrue(indexNames.contains("bar_bar"));
}
public void testHiddenAliasAndHiddenIndexResolution() {
final String visibleIndex = "visible_index";
final String hiddenIndex = "hidden_index";
final String visibleAlias = "visible_alias";
final String hiddenAlias = "hidden_alias";
final String dottedHiddenAlias = ".hidden_alias";
final String dottedHiddenIndex = ".hidden_index";
IndicesOptions excludeHiddenOptions = IndicesOptions.fromOptions(false, false, true, false, false, true, false, false, false);
IndicesOptions includeHiddenOptions = IndicesOptions.fromOptions(false, false, true, false, true, true, false, false, false);
{
// A visible index with a visible alias and a hidden index with a hidden alias
MetaData.Builder mdBuilder = MetaData.builder()
.put(indexBuilder(visibleIndex).state(State.OPEN).putAlias(AliasMetaData.builder(visibleAlias)))
.put(indexBuilder(hiddenIndex, Settings.builder().put(INDEX_HIDDEN_SETTING.getKey(), true).build())
.state(State.OPEN)
.putAlias(AliasMetaData.builder(hiddenAlias).isHidden(true)));
ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build();
// A total wildcard should only be resolved to visible indices
String[] indexNames;
indexNames = indexNameExpressionResolver.concreteIndexNames(state, excludeHiddenOptions, "*");
assertThat(Arrays.asList(indexNames), containsInAnyOrder(visibleIndex));
// Unless hidden is specified in the options
indexNames = indexNameExpressionResolver.concreteIndexNames(state, includeHiddenOptions, "*");
assertThat(Arrays.asList(indexNames), containsInAnyOrder(visibleIndex, hiddenIndex));
// Both hidden indices and hidden aliases should not be included in wildcard resolution
indexNames = indexNameExpressionResolver.concreteIndexNames(state, excludeHiddenOptions, "hidden*", "visible*");
assertThat(Arrays.asList(indexNames), containsInAnyOrder(visibleIndex));
// unless it's specified in the options
indexNames = indexNameExpressionResolver.concreteIndexNames(state, includeHiddenOptions, "hidden*", "visible*");
assertThat(Arrays.asList(indexNames), containsInAnyOrder(visibleIndex, hiddenIndex));
// Only visible aliases should be included in wildcard resolution
indexNames = indexNameExpressionResolver.concreteIndexNames(state, excludeHiddenOptions, "*_alias");
assertThat(Arrays.asList(indexNames), containsInAnyOrder(visibleIndex));
// unless, again, it's specified in the options
indexNames = indexNameExpressionResolver.concreteIndexNames(state, includeHiddenOptions, "*_alias");
assertThat(Arrays.asList(indexNames), containsInAnyOrder(visibleIndex, hiddenIndex));
// If we specify a hidden alias by name, the options shouldn't matter.
indexNames = indexNameExpressionResolver.concreteIndexNames(state, includeHiddenOptions, hiddenAlias);
assertThat(Arrays.asList(indexNames), containsInAnyOrder(hiddenIndex));
indexNames = indexNameExpressionResolver.concreteIndexNames(state, excludeHiddenOptions, hiddenAlias);
assertThat(Arrays.asList(indexNames), containsInAnyOrder(hiddenIndex));
}
{
// A visible alias that points to one hidden and one visible index
MetaData.Builder mdBuilder = MetaData.builder()
.put(indexBuilder(visibleIndex).state(State.OPEN).putAlias(AliasMetaData.builder(visibleAlias)))
.put(indexBuilder(hiddenIndex, Settings.builder().put(INDEX_HIDDEN_SETTING.getKey(), true).build())
.state(State.OPEN)
.putAlias(AliasMetaData.builder(visibleAlias)));
ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build();
// If the alias is resolved to concrete indices, it should resolve to all the indices it points to, hidden or not.
String[] indexNames;
indexNames = indexNameExpressionResolver.concreteIndexNames(state, excludeHiddenOptions, "*_alias");
assertThat(Arrays.asList(indexNames), containsInAnyOrder(visibleIndex, hiddenIndex));
indexNames = indexNameExpressionResolver.concreteIndexNames(state, includeHiddenOptions, "*_alias");
assertThat(Arrays.asList(indexNames), containsInAnyOrder(visibleIndex, hiddenIndex));
indexNames = indexNameExpressionResolver.concreteIndexNames(state, includeHiddenOptions, visibleAlias);
assertThat(Arrays.asList(indexNames), containsInAnyOrder(visibleIndex, hiddenIndex));
indexNames = indexNameExpressionResolver.concreteIndexNames(state, includeHiddenOptions, visibleAlias);
assertThat(Arrays.asList(indexNames), containsInAnyOrder(visibleIndex, hiddenIndex));
// A total wildcards does not resolve the hidden index in this case
indexNames = indexNameExpressionResolver.concreteIndexNames(state, excludeHiddenOptions, "*");
assertThat(Arrays.asList(indexNames), containsInAnyOrder(visibleIndex));
}
{
// A hidden alias that points to one hidden and one visible index
MetaData.Builder mdBuilder = MetaData.builder()
.put(indexBuilder(visibleIndex).state(State.OPEN).putAlias(AliasMetaData.builder(hiddenAlias).isHidden(true)))
.put(indexBuilder(hiddenIndex, Settings.builder().put(INDEX_HIDDEN_SETTING.getKey(), true).build())
.state(State.OPEN)
.putAlias(AliasMetaData.builder(hiddenAlias).isHidden(true)));
ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build();
String[] indexNames;
indexNames = indexNameExpressionResolver.concreteIndexNames(state, excludeHiddenOptions, "*");
assertThat(Arrays.asList(indexNames), containsInAnyOrder(visibleIndex));
indexNames = indexNameExpressionResolver.concreteIndexNames(state, includeHiddenOptions, "*");
assertThat(Arrays.asList(indexNames), containsInAnyOrder(visibleIndex, hiddenIndex));
// A query that only matches the hidden alias should throw
expectThrows(IndexNotFoundException.class,
() -> indexNameExpressionResolver.concreteIndexNames(state, excludeHiddenOptions, "*_alias"));
// But if we include hidden it should be resolved to both indices
indexNames = indexNameExpressionResolver.concreteIndexNames(state, includeHiddenOptions, "*_alias");
assertThat(Arrays.asList(indexNames), containsInAnyOrder(visibleIndex, hiddenIndex));
// If we specify the alias by name it should resolve to both indices, regardless of if the options specify hidden
indexNames = indexNameExpressionResolver.concreteIndexNames(state, excludeHiddenOptions, hiddenAlias);
assertThat(Arrays.asList(indexNames), containsInAnyOrder(visibleIndex, hiddenIndex));
indexNames = indexNameExpressionResolver.concreteIndexNames(state, includeHiddenOptions, hiddenAlias);
assertThat(Arrays.asList(indexNames), containsInAnyOrder(visibleIndex, hiddenIndex));
}
{
// A hidden alias with a dot-prefixed name that points to one hidden index with a dot prefix, and one hidden index without
MetaData.Builder mdBuilder = MetaData.builder()
.put(indexBuilder(dottedHiddenIndex, Settings.builder().put(INDEX_HIDDEN_SETTING.getKey(), true).build())
.state(State.OPEN)
.putAlias(AliasMetaData.builder(dottedHiddenAlias).isHidden(true)))
.put(indexBuilder(hiddenIndex, Settings.builder().put(INDEX_HIDDEN_SETTING.getKey(), true).build())
.state(State.OPEN)
.putAlias(AliasMetaData.builder(dottedHiddenAlias).isHidden(true)));
ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build();
String[] indexNames;
// A dot-prefixed pattern that includes only the hidden alias should resolve to both, regardless of the options
indexNames = indexNameExpressionResolver.concreteIndexNames(state, includeHiddenOptions, ".hidden_a*");
assertThat(Arrays.asList(indexNames), containsInAnyOrder(dottedHiddenIndex, hiddenIndex));
indexNames = indexNameExpressionResolver.concreteIndexNames(state, excludeHiddenOptions, ".hidden_a*");
assertThat(Arrays.asList(indexNames), containsInAnyOrder(dottedHiddenIndex, hiddenIndex));
// A query that doesn't include the dot should fail if the options don't include hidden
expectThrows(IndexNotFoundException.class,
() -> indexNameExpressionResolver.concreteIndexNames(state, excludeHiddenOptions, "*_alias"));
// But should include both indices if the options do include hidden
indexNames = indexNameExpressionResolver.concreteIndexNames(state, includeHiddenOptions, "*_alias");
assertThat(Arrays.asList(indexNames), containsInAnyOrder(dottedHiddenIndex, hiddenIndex));
}
}
public void testHiddenIndexWithVisibleAliasOverlappingNameResolution() {
final String hiddenIndex = "my-hidden-index";
final String hiddenAlias = "my-hidden-alias";
final String visibleAlias = "my-visible-alias";
IndicesOptions excludeHiddenOptions = IndicesOptions.fromOptions(false, true, true, false, false, true, false, false, false);
IndicesOptions includeHiddenOptions = IndicesOptions.fromOptions(false, true, true, false, true, true, false, false, false);
MetaData.Builder mdBuilder = MetaData.builder()
.put(indexBuilder(hiddenIndex, Settings.builder().put(INDEX_HIDDEN_SETTING.getKey(), true).build())
.state(State.OPEN)
.putAlias(AliasMetaData.builder(hiddenAlias).isHidden(true))
.putAlias(AliasMetaData.builder(visibleAlias).build()));
ClusterState state = ClusterState.builder(new ClusterName("_name")).metaData(mdBuilder).build();
String[] indexNames;
indexNames = indexNameExpressionResolver.concreteIndexNames(state, excludeHiddenOptions, "my-*");
assertThat(Arrays.asList(indexNames), containsInAnyOrder(hiddenIndex));
indexNames = indexNameExpressionResolver.concreteIndexNames(state, excludeHiddenOptions, "my-hidden*");
assertThat(Arrays.asList(indexNames), empty());
indexNames = indexNameExpressionResolver.concreteIndexNames(state, excludeHiddenOptions, "my-*", "-my-visible*");
assertThat(Arrays.asList(indexNames), empty());
indexNames = indexNameExpressionResolver.concreteIndexNames(state, includeHiddenOptions, "my-hidden*", "-my-hidden-a*");
assertThat(Arrays.asList(indexNames), empty());
}
/**
* test resolving _all pattern (null, empty array or "_all") for random IndicesOptions
*/

View File

@ -39,6 +39,7 @@ import java.util.Set;
import static java.util.Collections.singletonList;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.startsWith;
import static org.mockito.Matchers.any;
@ -73,7 +74,8 @@ public class MetaDataIndexAliasesServiceTests extends ESTestCase {
ClusterState before = createIndex(ClusterState.builder(ClusterName.DEFAULT).build(), index);
// Add an alias to it
ClusterState after = service.applyAliasActions(before, singletonList(new AliasAction.Add(index, "test", null, null, null, null)));
ClusterState after = service.applyAliasActions(before, singletonList(new AliasAction.Add(index, "test", null, null, null, null,
null)));
AliasOrIndex alias = after.metaData().getAliasAndIndexLookup().get("test");
assertNotNull(alias);
assertTrue(alias.isAlias());
@ -84,7 +86,7 @@ public class MetaDataIndexAliasesServiceTests extends ESTestCase {
before = after;
after = service.applyAliasActions(before, Arrays.asList(
new AliasAction.Remove(index, "test"),
new AliasAction.Add(index, "test_2", null, null, null, null)));
new AliasAction.Add(index, "test_2", null, null, null, null, null)));
assertNull(after.metaData().getAliasAndIndexLookup().get("test"));
alias = after.metaData().getAliasAndIndexLookup().get("test_2");
assertNotNull(alias);
@ -108,7 +110,7 @@ public class MetaDataIndexAliasesServiceTests extends ESTestCase {
for (int i = 0; i < length; i++) {
final String index = randomValueOtherThanMany(v -> indices.add(v) == false, () -> randomAlphaOfLength(8));
before = createIndex(before, index);
addActions.add(new AliasAction.Add(index, "alias-" + index, null, null, null, null));
addActions.add(new AliasAction.Add(index, "alias-" + index, null, null, null, null, null));
}
final ClusterState afterAddingAliasesToAll = service.applyAliasActions(before, addActions);
assertAliasesVersionIncreased(indices.toArray(new String[0]), before, afterAddingAliasesToAll);
@ -118,7 +120,7 @@ public class MetaDataIndexAliasesServiceTests extends ESTestCase {
final List<AliasAction> randomAddActions = new ArrayList<>(length);
for (String index : indices) {
if (randomBoolean()) {
randomAddActions.add(new AliasAction.Add(index, "random-alias-" + index, null, null, null, null));
randomAddActions.add(new AliasAction.Add(index, "random-alias-" + index, null, null, null, null, null));
randomIndices.add(index);
}
}
@ -135,17 +137,18 @@ public class MetaDataIndexAliasesServiceTests extends ESTestCase {
final ClusterState before = createIndex(ClusterState.builder(ClusterName.DEFAULT).build(), index);
final ClusterState afterAddWriteAlias =
service.applyAliasActions(before, singletonList(new AliasAction.Add(index, "test", null, null, null, true)));
service.applyAliasActions(before, singletonList(new AliasAction.Add(index, "test", null, null, null, true, null)));
assertAliasesVersionIncreased(index, before, afterAddWriteAlias);
final ClusterState afterChangeWriteAliasToNonWriteAlias =
service.applyAliasActions(afterAddWriteAlias, singletonList(new AliasAction.Add(index, "test", null, null, null, false)));
service.applyAliasActions(afterAddWriteAlias, singletonList(new AliasAction.Add(index, "test", null, null, null, false,
null)));
assertAliasesVersionIncreased(index, afterAddWriteAlias, afterChangeWriteAliasToNonWriteAlias);
final ClusterState afterChangeNonWriteAliasToWriteAlias =
service.applyAliasActions(
afterChangeWriteAliasToNonWriteAlias,
singletonList(new AliasAction.Add(index, "test", null, null, null, true)));
singletonList(new AliasAction.Add(index, "test", null, null, null, true, null)));
assertAliasesVersionIncreased(index, afterChangeWriteAliasToNonWriteAlias, afterChangeNonWriteAliasToWriteAlias);
}
@ -157,7 +160,7 @@ public class MetaDataIndexAliasesServiceTests extends ESTestCase {
final int length = randomIntBetween(2, 8);
final List<AliasAction> addActions = new ArrayList<>(length);
for (int i = 0; i < length; i++) {
addActions.add(new AliasAction.Add(index, "test", null, null, null, null));
addActions.add(new AliasAction.Add(index, "test", null, null, null, null, null));
}
final ClusterState afterAddingAliases = service.applyAliasActions(before, addActions);
@ -174,7 +177,7 @@ public class MetaDataIndexAliasesServiceTests extends ESTestCase {
final List<AliasAction> addActions = new ArrayList<>(length);
for (int i = 0; i < length; i++) {
final String aliasName = randomValueOtherThanMany(v -> aliasNames.add(v) == false, () -> randomAlphaOfLength(8));
addActions.add(new AliasAction.Add(index, aliasName, null, null, null, null));
addActions.add(new AliasAction.Add(index, aliasName, null, null, null, null, null));
}
final ClusterState afterAddingAlias = service.applyAliasActions(before, addActions);
@ -182,7 +185,7 @@ public class MetaDataIndexAliasesServiceTests extends ESTestCase {
final List<AliasAction> removeAndAddActions = new ArrayList<>(2 * length);
for (final String aliasName : aliasNames) {
removeAndAddActions.add(new AliasAction.Remove(index, aliasName));
removeAndAddActions.add(new AliasAction.Add(index, aliasName, null, null, null, null));
removeAndAddActions.add(new AliasAction.Add(index, aliasName, null, null, null, null, null));
}
final ClusterState afterRemoveAndAddAlias = service.applyAliasActions(afterAddingAlias, removeAndAddActions);
assertAliasesVersionUnchanged(index, afterAddingAlias, afterRemoveAndAddAlias);
@ -195,7 +198,7 @@ public class MetaDataIndexAliasesServiceTests extends ESTestCase {
// Now remove "test" and add an alias to "test" to "test_2" in one go
ClusterState after = service.applyAliasActions(before, Arrays.asList(
new AliasAction.Add("test_2", "test", null, null, null, null),
new AliasAction.Add("test_2", "test", null, null, null, null, null),
new AliasAction.RemoveIndex("test")));
AliasOrIndex alias = after.metaData().getAliasAndIndexLookup().get("test");
assertNotNull(alias);
@ -210,7 +213,7 @@ public class MetaDataIndexAliasesServiceTests extends ESTestCase {
// Attempt to add an alias to "test" at the same time as we remove it
IndexNotFoundException e = expectThrows(IndexNotFoundException.class, () -> service.applyAliasActions(before, Arrays.asList(
new AliasAction.Add("test", "alias", null, null, null, null),
new AliasAction.Add("test", "alias", null, null, null, null, null),
new AliasAction.RemoveIndex("test"))));
assertEquals("test", e.getIndex().getName());
}
@ -230,20 +233,20 @@ public class MetaDataIndexAliasesServiceTests extends ESTestCase {
ClusterState before = createIndex(ClusterState.builder(ClusterName.DEFAULT).build(), "test");
ClusterState after = service.applyAliasActions(before, Arrays.asList(
new AliasAction.Add("test", "alias", null, null, null, false)));
new AliasAction.Add("test", "alias", null, null, null, false, null)));
assertFalse(after.metaData().index("test").getAliases().get("alias").writeIndex());
assertNull(((AliasOrIndex.Alias) after.metaData().getAliasAndIndexLookup().get("alias")).getWriteIndex());
assertAliasesVersionIncreased("test", before, after);
after = service.applyAliasActions(before, Arrays.asList(
new AliasAction.Add("test", "alias", null, null, null, null)));
new AliasAction.Add("test", "alias", null, null, null, null, null)));
assertNull(after.metaData().index("test").getAliases().get("alias").writeIndex());
assertThat(((AliasOrIndex.Alias) after.metaData().getAliasAndIndexLookup().get("alias")).getWriteIndex(),
equalTo(after.metaData().index("test")));
assertAliasesVersionIncreased("test", before, after);
after = service.applyAliasActions(before, Arrays.asList(
new AliasAction.Add("test", "alias", null, null, null, true)));
new AliasAction.Add("test", "alias", null, null, null, true, null)));
assertTrue(after.metaData().index("test").getAliases().get("alias").writeIndex());
assertThat(((AliasOrIndex.Alias) after.metaData().getAliasAndIndexLookup().get("alias")).getWriteIndex(),
equalTo(after.metaData().index("test")));
@ -260,7 +263,7 @@ public class MetaDataIndexAliasesServiceTests extends ESTestCase {
.metaData(MetaData.builder().put(indexMetaData).put(indexMetaData2)).build();
ClusterState after = service.applyAliasActions(before, Arrays.asList(
new AliasAction.Add("test", "alias", null, null, null, null)));
new AliasAction.Add("test", "alias", null, null, null, null, null)));
assertNull(after.metaData().index("test").getAliases().get("alias").writeIndex());
assertThat(((AliasOrIndex.Alias) after.metaData().getAliasAndIndexLookup().get("alias")).getWriteIndex(),
equalTo(after.metaData().index("test2")));
@ -268,7 +271,7 @@ public class MetaDataIndexAliasesServiceTests extends ESTestCase {
assertAliasesVersionUnchanged("test2", before, after);
Exception exception = expectThrows(IllegalStateException.class, () -> service.applyAliasActions(before, Arrays.asList(
new AliasAction.Add("test", "alias", null, null, null, true))));
new AliasAction.Add("test", "alias", null, null, null, true, null))));
assertThat(exception.getMessage(), startsWith("alias [alias] has more than one write index ["));
}
@ -283,8 +286,8 @@ public class MetaDataIndexAliasesServiceTests extends ESTestCase {
Boolean unsetValue = randomBoolean() ? null : false;
List<AliasAction> swapActions = Arrays.asList(
new AliasAction.Add("test", "alias", null, null, null, unsetValue),
new AliasAction.Add("test2", "alias", null, null, null, true)
new AliasAction.Add("test", "alias", null, null, null, unsetValue, null),
new AliasAction.Add("test2", "alias", null, null, null, true, null)
);
Collections.shuffle(swapActions, random());
ClusterState after = service.applyAliasActions(before, swapActions);
@ -311,7 +314,7 @@ public class MetaDataIndexAliasesServiceTests extends ESTestCase {
assertNull(((AliasOrIndex.Alias) before.metaData().getAliasAndIndexLookup().get("alias")).getWriteIndex());
ClusterState after = service.applyAliasActions(before, Arrays.asList(
new AliasAction.Add("test3", "alias", null, null, null, true)));
new AliasAction.Add("test3", "alias", null, null, null, true, null)));
assertTrue(after.metaData().index("test3").getAliases().get("alias").writeIndex());
assertThat(((AliasOrIndex.Alias) after.metaData().getAliasAndIndexLookup().get("alias")).getWriteIndex(),
equalTo(after.metaData().index("test3")));
@ -350,12 +353,108 @@ public class MetaDataIndexAliasesServiceTests extends ESTestCase {
.metaData(MetaData.builder().put(indexMetaData).put(indexMetaData2)).build();
Exception exception = expectThrows(IllegalStateException.class, () -> service.applyAliasActions(before, Arrays.asList(
new AliasAction.Add("test", "alias", null, null, null, true),
new AliasAction.Add("test2", "alias", null, null, null, true)
new AliasAction.Add("test", "alias", null, null, null, true, null),
new AliasAction.Add("test2", "alias", null, null, null, true, null)
)));
assertThat(exception.getMessage(), startsWith("alias [alias] has more than one write index ["));
}
public void testHiddenPropertyValidation() {
ClusterState originalState = ClusterState.EMPTY_STATE;
originalState = createIndex(originalState, "test1");
originalState = createIndex(originalState, "test2");
{
// Add a non-hidden alias to one index
ClusterState testState = service.applyAliasActions(originalState, Collections.singletonList(
new AliasAction.Add("test1", "alias", null, null, null, null, randomFrom(false, null))
));
// Adding the same alias as hidden to another index should throw
Exception ex = expectThrows(IllegalStateException.class, () -> // Add a non-hidden alias to one index
service.applyAliasActions(testState, Collections.singletonList(
new AliasAction.Add("test2", "alias", null, null, null, null, true)
)));
assertThat(ex.getMessage(), containsString("alias [alias] has is_hidden set to true on indices"));
}
{
// Add a hidden alias to one index
ClusterState testState = service.applyAliasActions(originalState, Collections.singletonList(
new AliasAction.Add("test1", "alias", null, null, null, null, true)
));
// Adding the same alias as non-hidden to another index should throw
Exception ex = expectThrows(IllegalStateException.class, () -> // Add a non-hidden alias to one index
service.applyAliasActions(testState, Collections.singletonList(
new AliasAction.Add("test2", "alias", null, null, null, null, randomFrom(false, null))
)));
assertThat(ex.getMessage(), containsString("alias [alias] has is_hidden set to true on indices"));
}
{
// Add a non-hidden alias to one index
ClusterState testState = service.applyAliasActions(originalState, Collections.singletonList(
new AliasAction.Add("test1", "alias", null, null, null, null, randomFrom(false, null))
));
// Adding the same alias as non-hidden should be OK
service.applyAliasActions(testState, Collections.singletonList(
new AliasAction.Add("test2", "alias", null, null, null, null, randomFrom(false, null))
));
}
{
// Add a hidden alias to one index
ClusterState testState = service.applyAliasActions(originalState, Collections.singletonList(
new AliasAction.Add("test1", "alias", null, null, null, null, true)
));
// Adding the same alias as hidden should be OK
service.applyAliasActions(testState, Collections.singletonList(
new AliasAction.Add("test2", "alias", null, null, null, null, true)
));
}
}
public void testSimultaneousHiddenPropertyValidation() {
IndexMetaData.Builder indexMetaData = IndexMetaData.builder("test")
.settings(settings(Version.CURRENT)).numberOfShards(1).numberOfReplicas(1);
IndexMetaData.Builder indexMetaData2 = IndexMetaData.builder("test2")
.settings(settings(Version.CURRENT)).numberOfShards(1).numberOfReplicas(1);
ClusterState before = ClusterState.builder(ClusterName.DEFAULT)
.metaData(MetaData.builder().put(indexMetaData).put(indexMetaData2)).build();
{
// These should all be fine
applyHiddenAliasMix(before, null, null);
applyHiddenAliasMix(before, false, false);
applyHiddenAliasMix(before, false, null);
applyHiddenAliasMix(before, null, false);
applyHiddenAliasMix(before, true, true);
}
{
Exception exception = expectThrows(IllegalStateException.class,
() -> applyHiddenAliasMix(before, true, randomFrom(false, null)));
assertThat(exception.getMessage(), startsWith("alias [alias] has is_hidden set to true on indices ["));
}
{
Exception exception = expectThrows(IllegalStateException.class,
() -> applyHiddenAliasMix(before, randomFrom(false, null), true));
assertThat(exception.getMessage(), startsWith("alias [alias] has is_hidden set to true on indices ["));
}
}
private ClusterState applyHiddenAliasMix(ClusterState before, Boolean isHidden1, Boolean isHidden2) {
return service.applyAliasActions(before, Arrays.asList(
new AliasAction.Add("test", "alias", null, null, null, null, isHidden1),
new AliasAction.Add("test2", "alias", null, null, null, null, isHidden2)
));
}
private ClusterState createIndex(ClusterState state, String index) {
IndexMetaData indexMetaData = IndexMetaData.builder(index)
.settings(Settings.builder().put("index.version.created", VersionUtils.randomVersion(random())))

View File

@ -226,6 +226,39 @@ public class MetaDataTests extends ESTestCase {
assertThat(exception.getMessage(), startsWith("alias [" + alias + "] has more than one write index ["));
}
public void testValidateHiddenAliasConsistency() {
String alias = randomAlphaOfLength(5);
String indexA = randomAlphaOfLength(6);
String indexB = randomAlphaOfLength(7);
{
Exception ex = expectThrows(IllegalStateException.class,
() -> buildMetadataWithHiddenIndexMix(alias, indexA, true, indexB, randomFrom(false, null)).build());
assertThat(ex.getMessage(), containsString("has is_hidden set to true on indices"));
}
{
Exception ex = expectThrows(IllegalStateException.class,
() -> buildMetadataWithHiddenIndexMix(alias, indexA, randomFrom(false, null), indexB, true).build());
assertThat(ex.getMessage(), containsString("has is_hidden set to true on indices"));
}
}
private MetaData.Builder buildMetadataWithHiddenIndexMix(String aliasName, String indexAName, Boolean indexAHidden,
String indexBName, Boolean indexBHidden) {
IndexMetaData.Builder indexAMeta = IndexMetaData.builder(indexAName)
.settings(Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT))
.numberOfShards(1)
.numberOfReplicas(0)
.putAlias(AliasMetaData.builder(aliasName).isHidden(indexAHidden).build());
IndexMetaData.Builder indexBMeta = IndexMetaData.builder(indexBName)
.settings(Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT))
.numberOfShards(1)
.numberOfReplicas(0)
.putAlias(AliasMetaData.builder(aliasName).isHidden(indexBHidden).build());
return MetaData.builder().put(indexAMeta).put(indexBMeta);
}
public void testResolveIndexRouting() {
IndexMetaData.Builder builder = IndexMetaData.builder("index")
.settings(Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT))

View File

@ -85,6 +85,9 @@ public final class RandomAliasActionsGenerator {
if (randomBoolean()) {
action.writeIndex(randomBoolean());
}
if (randomBoolean()) {
action.isHidden(randomBoolean());
}
}
return action;
}

View File

@ -424,15 +424,21 @@ class IndicesAndAliasesResolver {
private static boolean isIndexVisible(String expression, String index, IndicesOptions indicesOptions, MetaData metaData,
boolean dateMathExpression) {
AliasOrIndex aliasOrIndex = metaData.getAliasAndIndexLookup().get(index);
final boolean isHidden = aliasOrIndex.isHidden();
if (aliasOrIndex.isAlias()) {
//it's an alias, ignore expandWildcardsOpen and expandWildcardsClosed.
//complicated to support those options with aliases pointing to multiple indices...
//TODO investigate supporting expandWildcards option for aliases too, like es core does.
return indicesOptions.ignoreAliases() == false;
if (indicesOptions.ignoreAliases()) {
return false;
} else if (isHidden == false || indicesOptions.expandWildcardsHidden() || isVisibleDueToImplicitHidden(expression, index)) {
return true;
} else {
return false;
}
}
assert aliasOrIndex.getIndices().size() == 1 : "concrete index must point to a single index";
IndexMetaData indexMetaData = aliasOrIndex.getIndices().get(0);
final boolean isHidden = IndexMetaData.INDEX_HIDDEN_SETTING.get(indexMetaData.getSettings());
if (isHidden && indicesOptions.expandWildcardsHidden() == false && isVisibleDueToImplicitHidden(expression, index) == false) {
return false;
}

View File

@ -148,6 +148,15 @@ public class IndicesAndAliasesResolverTests extends ESTestCase {
.settings(Settings.builder().put(settings).put("index.hidden", true).build()))
.put(indexBuilder("hidden-closed").state(State.CLOSE)
.settings(Settings.builder().put(settings).put("index.hidden", true).build()))
.put(indexBuilder("hidden-w-aliases").settings(Settings.builder().put(settings).put("index.hidden", true).build())
.putAlias(AliasMetaData.builder("alias-hidden").isHidden(true).build())
.putAlias(AliasMetaData.builder(".alias-hidden").isHidden(true).build())
.putAlias(AliasMetaData.builder("alias-visible-mixed").isHidden(false).build()))
.put(indexBuilder("hidden-w-visible-alias").settings(Settings.builder().put(settings).put("index.hidden", true).build())
.putAlias(AliasMetaData.builder("alias-visible").build()))
.put(indexBuilder("visible-w-aliases").settings(Settings.builder().put(settings).build())
.putAlias(AliasMetaData.builder("alias-visible").build())
.putAlias(AliasMetaData.builder("alias-visible-mixed").isHidden(false).build()))
.put(indexBuilder(securityIndexName).settings(settings)).build();
if (withAlias) {
@ -171,6 +180,13 @@ public class IndicesAndAliasesResolverTests extends ESTestCase {
roleMap.put("alias_read_write", new RoleDescriptor("alias_read_write", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("barbaz", "foofoobar").privileges("read", "write").build() },
null));
roleMap.put("hidden_alias_test", new RoleDescriptor("hidden_alias_test", null,
new IndicesPrivileges[] {
IndicesPrivileges.builder()
.indices("alias-visible", "alias-visible-mixed", "alias-hidden", ".alias-hidden", "hidden-open")
.privileges("all")
.build()
}, null));
roleMap.put(ReservedRolesStore.SUPERUSER_ROLE_DESCRIPTOR.getName(), ReservedRolesStore.SUPERUSER_ROLE_DESCRIPTOR);
final FieldPermissionsCache fieldPermissionsCache = new FieldPermissionsCache(Settings.EMPTY);
doAnswer((i) -> {
@ -1412,7 +1428,6 @@ public class IndicesAndAliasesResolverTests extends ESTestCase {
// open + hidden
searchRequest = new SearchRequest();
searchRequest.indicesOptions(IndicesOptions.fromOptions(false, false, true, false, true));
authorizedIndices = buildAuthorizedIndices(user, SearchAction.NAME);
resolvedIndices = defaultIndicesResolver.resolveIndicesAndAliases(searchRequest, metaData, authorizedIndices);
assertThat(resolvedIndices.getLocal(),
containsInAnyOrder("bar", "foofoobar", "foobarfoo", "foofoo", "hidden-open", ".hidden-open"));
@ -1451,6 +1466,54 @@ public class IndicesAndAliasesResolverTests extends ESTestCase {
assertThat(resolvedIndices.getRemote(), emptyIterable());
}
public void testHiddenAliasesResolution() {
final User user = new User("hidden-alias-tester", "hidden_alias_test");
final List<String> authorizedIndices = buildAuthorizedIndices(user, SearchAction.NAME);
// Visible only
SearchRequest searchRequest = new SearchRequest();
searchRequest.indicesOptions(IndicesOptions.fromOptions(false, false, true, false, false));
ResolvedIndices resolvedIndices = defaultIndicesResolver.resolveIndicesAndAliases(searchRequest, metaData, authorizedIndices);
assertThat(resolvedIndices.getLocal(), containsInAnyOrder("alias-visible", "alias-visible-mixed"));
assertThat(resolvedIndices.getRemote(), emptyIterable());
// Include hidden explicitly
searchRequest = new SearchRequest();
searchRequest.indicesOptions(IndicesOptions.fromOptions(false, false, true, false, true));
resolvedIndices = defaultIndicesResolver.resolveIndicesAndAliases(searchRequest, metaData, authorizedIndices);
assertThat(resolvedIndices.getLocal(),
containsInAnyOrder("alias-visible", "alias-visible-mixed", "alias-hidden", ".alias-hidden", "hidden-open"));
assertThat(resolvedIndices.getRemote(), emptyIterable());
// Include hidden with a wildcard
searchRequest = new SearchRequest("alias-h*");
searchRequest.indicesOptions(IndicesOptions.fromOptions(false, false, true, false, true));
resolvedIndices = defaultIndicesResolver.resolveIndicesAndAliases(searchRequest, metaData, authorizedIndices);
assertThat(resolvedIndices.getLocal(), containsInAnyOrder("alias-hidden"));
assertThat(resolvedIndices.getRemote(), emptyIterable());
// Dot prefix, implicitly including hidden
searchRequest = new SearchRequest(".a*");
searchRequest.indicesOptions(IndicesOptions.fromOptions(false, false, true, false, false));
resolvedIndices = defaultIndicesResolver.resolveIndicesAndAliases(searchRequest, metaData, authorizedIndices);
assertThat(resolvedIndices.getLocal(), containsInAnyOrder(".alias-hidden"));
assertThat(resolvedIndices.getRemote(), emptyIterable());
// Make sure ignoring aliases works (visible only)
searchRequest = new SearchRequest();
searchRequest.indicesOptions(IndicesOptions.fromOptions(false, true, true, false, false, true, false, true, false));
resolvedIndices = defaultIndicesResolver.resolveIndicesAndAliases(searchRequest, metaData, authorizedIndices);
assertThat(resolvedIndices.getLocal(), contains("-*"));
assertThat(resolvedIndices.getRemote(), emptyIterable());
// Make sure ignoring aliases works (including hidden)
searchRequest = new SearchRequest();
searchRequest.indicesOptions(IndicesOptions.fromOptions(false, false, true, false, true, true, false, true, false));
resolvedIndices = defaultIndicesResolver.resolveIndicesAndAliases(searchRequest, metaData, authorizedIndices);
assertThat(resolvedIndices.getLocal(), containsInAnyOrder("hidden-open"));
assertThat(resolvedIndices.getRemote(), emptyIterable());
}
private List<String> buildAuthorizedIndices(User user, String action) {
PlainActionFuture<Role> rolesListener = new PlainActionFuture<>();
final Authentication authentication =