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:
parent
7c9641ef9d
commit
ff9b8bda63
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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())));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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())))
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -85,6 +85,9 @@ public final class RandomAliasActionsGenerator {
|
|||
if (randomBoolean()) {
|
||||
action.writeIndex(randomBoolean());
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
action.isHidden(randomBoolean());
|
||||
}
|
||||
}
|
||||
return action;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 =
|
||||
|
|
Loading…
Reference in New Issue