Skip to content

Commit 0d5f395

Browse files
olcbeanjavanna
authored andcommitted
Expand index expressions against indices only when managing aliases (#23997)
The index parameter in the update-aliases, put-alias, and delete-alias APIs no longer accepts alias names. Instead, it accepts only index names (or wildcards which will expand to matching indices). Closes #23960
1 parent 4a8759e commit 0d5f395

File tree

8 files changed

+245
-28
lines changed

8 files changed

+245
-28
lines changed

core/src/main/java/org/elasticsearch/action/admin/indices/alias/IndicesAliasesRequest.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,10 @@
5959
public class IndicesAliasesRequest extends AcknowledgedRequest<IndicesAliasesRequest> {
6060
private List<AliasActions> allAliasActions = new ArrayList<>();
6161

62-
//indices options that require every specified index to exist, expand wildcards only to open indices and
63-
//don't allow that no indices are resolved from wildcard expressions
64-
private static final IndicesOptions INDICES_OPTIONS = IndicesOptions.fromOptions(false, false, true, false);
62+
// indices options that require every specified index to exist, expand wildcards only to open
63+
// indices, don't allow that no indices are resolved from wildcard expressions and resolve the
64+
// expressions only against indices
65+
private static final IndicesOptions INDICES_OPTIONS = IndicesOptions.fromOptions(false, false, true, false, true, false, true);
6566

6667
public IndicesAliasesRequest() {
6768

core/src/main/java/org/elasticsearch/action/support/IndicesOptions.java

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
package org.elasticsearch.action.support;
2020

2121

22+
import org.elasticsearch.Version;
2223
import org.elasticsearch.common.io.stream.StreamInput;
2324
import org.elasticsearch.common.io.stream.StreamOutput;
2425
import org.elasticsearch.rest.RestRequest;
@@ -43,6 +44,7 @@ public class IndicesOptions {
4344
private static final byte EXPAND_WILDCARDS_CLOSED = 8;
4445
private static final byte FORBID_ALIASES_TO_MULTIPLE_INDICES = 16;
4546
private static final byte FORBID_CLOSED_INDICES = 32;
47+
private static final byte IGNORE_ALIASES = 64;
4648

4749
private static final byte STRICT_EXPAND_OPEN = 6;
4850
private static final byte LENIENT_EXPAND_OPEN = 7;
@@ -51,10 +53,10 @@ public class IndicesOptions {
5153
private static final byte STRICT_SINGLE_INDEX_NO_EXPAND_FORBID_CLOSED = 48;
5254

5355
static {
54-
byte max = 1 << 6;
56+
short max = 1 << 7;
5557
VALUES = new IndicesOptions[max];
56-
for (byte id = 0; id < max; id++) {
57-
VALUES[id] = new IndicesOptions(id);
58+
for (short id = 0; id < max; id++) {
59+
VALUES[id] = new IndicesOptions((byte)id);
5860
}
5961
}
6062

@@ -106,18 +108,31 @@ public boolean forbidClosedIndices() {
106108
* @return whether aliases pointing to multiple indices are allowed
107109
*/
108110
public boolean allowAliasesToMultipleIndices() {
109-
//true is default here, for bw comp we keep the first 16 values
110-
//in the array same as before + the default value for the new flag
111+
// true is default here, for bw comp we keep the first 16 values
112+
// in the array same as before + the default value for the new flag
111113
return (id & FORBID_ALIASES_TO_MULTIPLE_INDICES) == 0;
112114
}
113115

116+
/**
117+
* @return whether aliases should be ignored (when resolving a wildcard)
118+
*/
119+
public boolean ignoreAliases() {
120+
return (id & IGNORE_ALIASES) != 0;
121+
}
122+
114123
public void writeIndicesOptions(StreamOutput out) throws IOException {
115-
out.write(id);
124+
if (out.getVersion().onOrAfter(Version.V_6_0_0_alpha2)) {
125+
out.write(id);
126+
} else {
127+
// if we are talking to a node that doesn't support the newly added flag (ignoreAliases)
128+
// flip to 0 all the bits starting from the 7th
129+
out.write(id & 0x3f);
130+
}
116131
}
117132

118133
public static IndicesOptions readIndicesOptions(StreamInput in) throws IOException {
119-
//if we read from a node that doesn't support the newly added flag (allowAliasesToMultipleIndices)
120-
//we just receive the old corresponding value with the new flag set to true (default)
134+
//if we read from a node that doesn't support the newly added flag (ignoreAliases)
135+
//we just receive the old corresponding value with the new flag set to false (default)
121136
byte id = in.readByte();
122137
if (id >= VALUES.length) {
123138
throw new IllegalArgumentException("No valid missing index type id: " + id);
@@ -133,8 +148,16 @@ public static IndicesOptions fromOptions(boolean ignoreUnavailable, boolean allo
133148
return fromOptions(ignoreUnavailable, allowNoIndices, expandToOpenIndices, expandToClosedIndices, defaultOptions.allowAliasesToMultipleIndices(), defaultOptions.forbidClosedIndices());
134149
}
135150

136-
static IndicesOptions fromOptions(boolean ignoreUnavailable, boolean allowNoIndices, boolean expandToOpenIndices, boolean expandToClosedIndices, boolean allowAliasesToMultipleIndices, boolean forbidClosedIndices) {
137-
byte id = toByte(ignoreUnavailable, allowNoIndices, expandToOpenIndices, expandToClosedIndices, allowAliasesToMultipleIndices, forbidClosedIndices);
151+
public static IndicesOptions fromOptions(boolean ignoreUnavailable, boolean allowNoIndices, boolean expandToOpenIndices,
152+
boolean expandToClosedIndices, boolean allowAliasesToMultipleIndices, boolean forbidClosedIndices) {
153+
return fromOptions(ignoreUnavailable, allowNoIndices, expandToOpenIndices, expandToClosedIndices, allowAliasesToMultipleIndices,
154+
forbidClosedIndices, false);
155+
}
156+
157+
public static IndicesOptions fromOptions(boolean ignoreUnavailable, boolean allowNoIndices, boolean expandToOpenIndices,
158+
boolean expandToClosedIndices, boolean allowAliasesToMultipleIndices, boolean forbidClosedIndices, boolean ignoreAliases) {
159+
byte id = toByte(ignoreUnavailable, allowNoIndices, expandToOpenIndices, expandToClosedIndices, allowAliasesToMultipleIndices,
160+
forbidClosedIndices, ignoreAliases);
138161
return VALUES[id];
139162
}
140163

@@ -246,7 +269,7 @@ public static IndicesOptions lenientExpandOpen() {
246269
}
247270

248271
private static byte toByte(boolean ignoreUnavailable, boolean allowNoIndices, boolean wildcardExpandToOpen,
249-
boolean wildcardExpandToClosed, boolean allowAliasesToMultipleIndices, boolean forbidClosedIndices) {
272+
boolean wildcardExpandToClosed, boolean allowAliasesToMultipleIndices, boolean forbidClosedIndices, boolean ignoreAliases) {
250273
byte id = 0;
251274
if (ignoreUnavailable) {
252275
id |= IGNORE_UNAVAILABLE;
@@ -268,6 +291,9 @@ private static byte toByte(boolean ignoreUnavailable, boolean allowNoIndices, bo
268291
if (forbidClosedIndices) {
269292
id |= FORBID_CLOSED_INDICES;
270293
}
294+
if (ignoreAliases) {
295+
id |= IGNORE_ALIASES;
296+
}
271297
return id;
272298
}
273299

@@ -281,6 +307,7 @@ public String toString() {
281307
", expand_wildcards_closed=" + expandWildcardsClosed() +
282308
", allow_aliases_to_multiple_indices=" + allowAliasesToMultipleIndices() +
283309
", forbid_closed_indices=" + forbidClosedIndices() +
310+
", ignore_aliases=" + ignoreAliases() +
284311
']';
285312
}
286313
}

core/src/main/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolver.java

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
import java.util.Locale;
5151
import java.util.Map;
5252
import java.util.Set;
53+
import java.util.SortedMap;
5354
import java.util.function.Predicate;
5455
import java.util.stream.Collectors;
5556

@@ -104,7 +105,7 @@ public String[] concreteIndexNames(ClusterState state, IndicesOptions options, S
104105
return concreteIndexNames(context, indexExpressions);
105106
}
106107

107-
/**
108+
/**
108109
* Translates the provided index expression into actual concrete indices, properly deduplicated.
109110
*
110111
* @param state the cluster state containing all the data to resolve to expressions to concrete indices
@@ -181,7 +182,7 @@ Index[] concreteIndices(Context context, String... indexExpressions) {
181182
final Set<Index> concreteIndices = new HashSet<>(expressions.size());
182183
for (String expression : expressions) {
183184
AliasOrIndex aliasOrIndex = metaData.getAliasAndIndexLookup().get(expression);
184-
if (aliasOrIndex == null) {
185+
if (aliasOrIndex == null || (aliasOrIndex.isAlias() && context.getOptions().ignoreAliases())) {
185186
if (failNoIndices) {
186187
IndexNotFoundException infe = new IndexNotFoundException(expression);
187188
infe.setResources("index_expression", expression);
@@ -638,7 +639,7 @@ private Set<String> innerResolve(Context context, List<String> expressions, Indi
638639
}
639640

640641
final IndexMetaData.State excludeState = excludeState(options);
641-
final Map<String, AliasOrIndex> matches = matches(metaData, expression);
642+
final Map<String, AliasOrIndex> matches = matches(context, metaData, expression);
642643
Set<String> expand = expand(context, excludeState, matches);
643644
if (add) {
644645
result.addAll(expand);
@@ -693,31 +694,44 @@ private static IndexMetaData.State excludeState(IndicesOptions options) {
693694
return excludeState;
694695
}
695696

696-
private static Map<String, AliasOrIndex> matches(MetaData metaData, String expression) {
697+
public static Map<String, AliasOrIndex> matches(Context context, MetaData metaData, String expression) {
697698
if (Regex.isMatchAllPattern(expression)) {
698699
// Can only happen if the expressions was initially: '-*'
699-
return metaData.getAliasAndIndexLookup();
700+
if (context.getOptions().ignoreAliases()) {
701+
return metaData.getAliasAndIndexLookup().entrySet().stream()
702+
.filter(e -> e.getValue().isAlias() == false)
703+
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
704+
} else {
705+
return metaData.getAliasAndIndexLookup();
706+
}
700707
} else if (expression.indexOf("*") == expression.length() - 1) {
701-
return suffixWildcard(metaData, expression);
708+
return suffixWildcard(context, metaData, expression);
702709
} else {
703-
return otherWildcard(metaData, expression);
710+
return otherWildcard(context, metaData, expression);
704711
}
705712
}
706713

707-
private static Map<String, AliasOrIndex> suffixWildcard(MetaData metaData, String expression) {
714+
private static Map<String, AliasOrIndex> suffixWildcard(Context context, MetaData metaData, String expression) {
708715
assert expression.length() >= 2 : "expression [" + expression + "] should have at least a length of 2";
709716
String fromPrefix = expression.substring(0, expression.length() - 1);
710717
char[] toPrefixCharArr = fromPrefix.toCharArray();
711718
toPrefixCharArr[toPrefixCharArr.length - 1]++;
712719
String toPrefix = new String(toPrefixCharArr);
713-
return metaData.getAliasAndIndexLookup().subMap(fromPrefix, toPrefix);
720+
SortedMap<String,AliasOrIndex> subMap = metaData.getAliasAndIndexLookup().subMap(fromPrefix, toPrefix);
721+
if (context.getOptions().ignoreAliases()) {
722+
return subMap.entrySet().stream()
723+
.filter(entry -> entry.getValue().isAlias() == false)
724+
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
725+
}
726+
return subMap;
714727
}
715728

716-
private static Map<String, AliasOrIndex> otherWildcard(MetaData metaData, String expression) {
729+
private static Map<String, AliasOrIndex> otherWildcard(Context context, MetaData metaData, String expression) {
717730
final String pattern = expression;
718731
return metaData.getAliasAndIndexLookup()
719732
.entrySet()
720733
.stream()
734+
.filter(e -> context.getOptions().ignoreAliases() == false || e.getValue().isAlias() == false)
721735
.filter(e -> Regex.simpleMatch(pattern, e.getKey()))
722736
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
723737
}

core/src/test/java/org/elasticsearch/action/support/IndicesOptionsTests.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public void testSerialization() throws Exception {
3232
int iterations = randomIntBetween(5, 20);
3333
for (int i = 0; i < iterations; i++) {
3434
IndicesOptions indicesOptions = IndicesOptions.fromOptions(
35-
randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean());
35+
randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean());
3636

3737
BytesStreamOutput output = new BytesStreamOutput();
3838
Version outputVersion = randomVersion(random());
@@ -50,6 +50,12 @@ public void testSerialization() throws Exception {
5050

5151
assertThat(indicesOptions2.forbidClosedIndices(), equalTo(indicesOptions.forbidClosedIndices()));
5252
assertThat(indicesOptions2.allowAliasesToMultipleIndices(), equalTo(indicesOptions.allowAliasesToMultipleIndices()));
53+
54+
if (output.getVersion().onOrAfter(Version.V_6_0_0_alpha2)) {
55+
assertEquals(indicesOptions2.ignoreAliases(), indicesOptions.ignoreAliases());
56+
} else {
57+
assertFalse(indicesOptions2.ignoreAliases());
58+
}
5359
}
5460
}
5561

@@ -62,9 +68,11 @@ public void testFromOptions() {
6268
boolean expandToClosedIndices = randomBoolean();
6369
boolean allowAliasesToMultipleIndices = randomBoolean();
6470
boolean forbidClosedIndices = randomBoolean();
71+
boolean ignoreAliases = randomBoolean();
72+
6573
IndicesOptions indicesOptions = IndicesOptions.fromOptions(
6674
ignoreUnavailable, allowNoIndices,expandToOpenIndices, expandToClosedIndices,
67-
allowAliasesToMultipleIndices, forbidClosedIndices
75+
allowAliasesToMultipleIndices, forbidClosedIndices, ignoreAliases
6876
);
6977

7078
assertThat(indicesOptions.ignoreUnavailable(), equalTo(ignoreUnavailable));
@@ -74,6 +82,7 @@ public void testFromOptions() {
7482
assertThat(indicesOptions.allowAliasesToMultipleIndices(), equalTo(allowAliasesToMultipleIndices));
7583
assertThat(indicesOptions.allowAliasesToMultipleIndices(), equalTo(allowAliasesToMultipleIndices));
7684
assertThat(indicesOptions.forbidClosedIndices(), equalTo(forbidClosedIndices));
85+
assertEquals(ignoreAliases, indicesOptions.ignoreAliases());
7786
}
7887
}
7988
}

core/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
package org.elasticsearch.aliases;
2121

22-
import org.apache.lucene.search.join.ScoreMode;
2322
import org.elasticsearch.action.admin.indices.alias.Alias;
2423
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
2524
import org.elasticsearch.action.admin.indices.alias.exists.AliasesExistResponse;
@@ -36,6 +35,7 @@
3635
import org.elasticsearch.common.settings.Settings;
3736
import org.elasticsearch.common.unit.TimeValue;
3837
import org.elasticsearch.common.xcontent.XContentType;
38+
import org.elasticsearch.index.IndexNotFoundException;
3939
import org.elasticsearch.index.query.QueryBuilder;
4040
import org.elasticsearch.index.query.QueryBuilders;
4141
import org.elasticsearch.rest.action.admin.indices.AliasesNotFoundException;
@@ -63,7 +63,6 @@
6363
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_BLOCKS_READ;
6464
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_BLOCKS_WRITE;
6565
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_READ_ONLY;
66-
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
6766
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
6867
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
6968
import static org.elasticsearch.test.hamcrest.CollectionAssertions.hasKey;
@@ -425,6 +424,23 @@ public void testDeleteAliases() throws Exception {
425424

426425
AliasesExistResponse response = admin().indices().prepareAliasesExist(aliases).get();
427426
assertThat(response.exists(), equalTo(false));
427+
428+
logger.info("--> creating index [foo_foo] and [bar_bar]");
429+
assertAcked(prepareCreate("foo_foo"));
430+
assertAcked(prepareCreate("bar_bar"));
431+
ensureGreen();
432+
433+
logger.info("--> adding [foo] alias to [foo_foo] and [bar_bar]");
434+
assertAcked(admin().indices().prepareAliases().addAlias("foo_foo", "foo"));
435+
assertAcked(admin().indices().prepareAliases().addAlias("bar_bar", "foo"));
436+
437+
assertAcked(admin().indices().prepareAliases().addAliasAction(AliasActions.remove().index("foo*").alias("foo")).execute().get());
438+
439+
assertTrue(admin().indices().prepareAliasesExist("foo").get().exists());
440+
assertFalse(admin().indices().prepareAliasesExist("foo").setIndices("foo_foo").get().exists());
441+
assertTrue(admin().indices().prepareAliasesExist("foo").setIndices("bar_bar").get().exists());
442+
expectThrows(IndexNotFoundException.class, () -> admin().indices().prepareAliases()
443+
.addAliasAction(AliasActions.remove().index("foo").alias("foo")).execute().actionGet());
428444
}
429445

430446
public void testWaitForAliasCreationMultipleShards() throws Exception {
@@ -785,6 +801,21 @@ public void testCreateIndexWithAliasesFilterNotValid() {
785801
}
786802
}
787803

804+
public void testAliasesCanBeAddedToIndicesOnly() throws Exception {
805+
logger.info("--> creating index [2017-05-20]");
806+
assertAcked(prepareCreate("2017-05-20"));
807+
ensureGreen();
808+
809+
logger.info("--> adding [week_20] alias to [2017-05-20]");
810+
assertAcked(admin().indices().prepareAliases().addAlias("2017-05-20", "week_20"));
811+
812+
IndexNotFoundException infe = expectThrows(IndexNotFoundException.class, () -> admin().indices().prepareAliases()
813+
.addAliasAction(AliasActions.add().index("week_20").alias("tmp")).execute().actionGet());
814+
assertEquals("week_20", infe.getIndex().getName());
815+
816+
assertAcked(admin().indices().prepareAliases().addAliasAction(AliasActions.add().index("2017-05-20").alias("tmp")).execute().get());
817+
}
818+
788819
// Before 2.0 alias filters were parsed at alias creation time, in order
789820
// for filters to work correctly ES required that fields mentioned in those
790821
// filters exist in the mapping.
@@ -864,6 +895,26 @@ public void testAliasesWithBlocks() {
864895
}
865896
}
866897

898+
public void testAliasActionRemoveIndex() throws InterruptedException, ExecutionException {
899+
assertAcked(prepareCreate("foo_foo"));
900+
assertAcked(prepareCreate("bar_bar"));
901+
assertAcked(admin().indices().prepareAliases().addAlias("foo_foo", "foo"));
902+
assertAcked(admin().indices().prepareAliases().addAlias("bar_bar", "foo"));
903+
904+
expectThrows(IndexNotFoundException.class,
905+
() -> client().admin().indices().prepareAliases().removeIndex("foo").execute().actionGet());
906+
907+
assertAcked(client().admin().indices().prepareAliases().removeIndex("foo*").execute().get());
908+
assertFalse(client().admin().indices().prepareExists("foo_foo").execute().actionGet().isExists());
909+
assertTrue(admin().indices().prepareAliasesExist("foo").get().exists());
910+
assertTrue(client().admin().indices().prepareExists("bar_bar").execute().actionGet().isExists());
911+
assertTrue(admin().indices().prepareAliasesExist("foo").setIndices("bar_bar").get().exists());
912+
913+
assertAcked(client().admin().indices().prepareAliases().removeIndex("bar_bar"));
914+
assertFalse(admin().indices().prepareAliasesExist("foo").get().exists());
915+
assertFalse(client().admin().indices().prepareExists("bar_bar").execute().actionGet().isExists());
916+
}
917+
867918
public void testRemoveIndexAndReplaceWithAlias() throws InterruptedException, ExecutionException {
868919
assertAcked(client().admin().indices().prepareCreate("test"));
869920
indexRandom(true, client().prepareIndex("test_2", "test", "test").setSource("test", "test"));

0 commit comments

Comments
 (0)