Skip to content

Commit b334d62

Browse files
authored
Return error when remote indices are locally resolved (#74556)
We support the cluster:index syntax in all the API that support cross-cluster calls. Those API will extract remote indices, properly resolve them, and resolve locally the local indices. API that don't support this syntax though end up attempting to resolve such indices locally, which in most cases leads to an index not found exception depending on how ignore_unavailable is configured for the API. The reason for treating these index names as local is that we used to support ':' in index names, but that is no longer supported since 7.x. That means that 7.x may still have indices with ':' in their names from 6.x, but 8.x won't. We can then switch 8.0 to throw a more specific error in place of the index not found, to signal that remote indices have been requested in the context of an API that does not support cross cluster calls. relates to #26247
1 parent c6f0fb8 commit b334d62

File tree

3 files changed

+46
-9
lines changed

3 files changed

+46
-9
lines changed

server/src/internalClusterTest/java/org/elasticsearch/get/GetActionIT.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@
1919
import org.elasticsearch.action.get.MultiGetResponse;
2020
import org.elasticsearch.action.index.IndexResponse;
2121
import org.elasticsearch.action.support.DefaultShardOperationFailedException;
22-
import org.elasticsearch.core.Nullable;
2322
import org.elasticsearch.common.Strings;
2423
import org.elasticsearch.common.bytes.BytesReference;
2524
import org.elasticsearch.common.lucene.uid.Versions;
2625
import org.elasticsearch.common.settings.Settings;
2726
import org.elasticsearch.common.xcontent.XContentFactory;
2827
import org.elasticsearch.common.xcontent.XContentType;
28+
import org.elasticsearch.core.Nullable;
2929
import org.elasticsearch.index.IndexModule;
3030
import org.elasticsearch.index.engine.EngineTestCase;
3131
import org.elasticsearch.index.engine.VersionConflictEngineException;
@@ -781,6 +781,12 @@ void indexSingleDocumentWithStringFieldsGeneratedFromText(boolean stored, boolea
781781
index("test", "1", doc);
782782
}
783783

784+
public void testGetRemoteIndex() {
785+
IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> client().prepareGet("cluster:index", "id").get());
786+
assertEquals("Cross-cluster calls are not supported in this context but remote indices were requested: [cluster:index]",
787+
iae.getMessage());
788+
}
789+
784790
private void assertGetFieldsAlwaysWorks(String index, String docId, String[] fields) {
785791
assertGetFieldsAlwaysWorks(index, docId, fields, null);
786792
}

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

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import org.elasticsearch.action.support.IndicesOptions;
1515
import org.elasticsearch.cluster.ClusterState;
1616
import org.elasticsearch.cluster.metadata.IndexAbstraction.Type;
17-
import org.elasticsearch.core.Nullable;
1817
import org.elasticsearch.common.Strings;
1918
import org.elasticsearch.common.collect.ImmutableOpenMap;
2019
import org.elasticsearch.common.logging.DeprecationCategory;
@@ -26,6 +25,7 @@
2625
import org.elasticsearch.common.util.CollectionUtils;
2726
import org.elasticsearch.common.util.concurrent.ThreadContext;
2827
import org.elasticsearch.common.util.set.Sets;
28+
import org.elasticsearch.core.Nullable;
2929
import org.elasticsearch.index.Index;
3030
import org.elasticsearch.index.IndexNotFoundException;
3131
import org.elasticsearch.indices.IndexClosedException;
@@ -112,7 +112,7 @@ public Index[] concreteIndices(ClusterState state, IndicesRequest request) {
112112
* provided indices options in the context don't allow such a case, or if the final result of the indices resolution
113113
* contains no indices and the indices options in the context don't allow such a case.
114114
* @throws IllegalArgumentException if one of the aliases resolve to multiple indices and the provided
115-
* indices options in the context don't allow such a case.
115+
* indices options in the context don't allow such a case; if a remote index is requested.
116116
*/
117117
public String[] concreteIndexNames(ClusterState state, IndicesOptions options, String... indexExpressions) {
118118
Context context = new Context(state, options, getSystemIndexAccessLevel(),
@@ -167,7 +167,7 @@ public List<String> dataStreamNames(ClusterState state, IndicesOptions options,
167167
* provided indices options in the context don't allow such a case, or if the final result of the indices resolution
168168
* contains no indices and the indices options in the context don't allow such a case.
169169
* @throws IllegalArgumentException if one of the aliases resolve to multiple indices and the provided
170-
* indices options in the context don't allow such a case.
170+
* indices options in the context don't allow such a case; if a remote index is requested.
171171
*/
172172
public Index[] concreteIndices(ClusterState state, IndicesOptions options, String... indexExpressions) {
173173
return concreteIndices(state, options, false, indexExpressions);
@@ -189,7 +189,7 @@ public Index[] concreteIndices(ClusterState state, IndicesOptions options, boole
189189
* provided indices options in the context don't allow such a case, or if the final result of the indices resolution
190190
* contains no indices and the indices options in the context don't allow such a case.
191191
* @throws IllegalArgumentException if one of the aliases resolve to multiple indices and the provided
192-
* indices options in the context don't allow such a case.
192+
* indices options in the context don't allow such a case; if a remote index is requested.
193193
*/
194194
public Index[] concreteIndices(ClusterState state, IndicesRequest request, long startTime) {
195195
Context context = new Context(state, request.indicesOptions(), startTime, false, false, request.includeDataStreams(), false,
@@ -207,11 +207,20 @@ String[] concreteIndexNames(Context context, String... indexExpressions) {
207207
}
208208

209209
Index[] concreteIndices(Context context, String... indexExpressions) {
210+
Metadata metadata = context.getState().metadata();
211+
IndicesOptions options = context.getOptions();
210212
if (indexExpressions == null || indexExpressions.length == 0) {
211213
indexExpressions = new String[]{Metadata.ALL};
214+
} else {
215+
if (options.ignoreUnavailable() == false) {
216+
List<String> crossClusterIndices = Arrays.stream(indexExpressions)
217+
.filter(index -> index.contains(":")).collect(Collectors.toList());
218+
if (crossClusterIndices.size() > 0) {
219+
throw new IllegalArgumentException("Cross-cluster calls are not supported in this context but remote indices " +
220+
"were requested: " + crossClusterIndices);
221+
}
222+
}
212223
}
213-
Metadata metadata = context.getState().metadata();
214-
IndicesOptions options = context.getOptions();
215224
// If only one index is specified then whether we fail a request if an index is missing depends on the allow_no_indices
216225
// option. At some point we should change this, because there shouldn't be a reason why whether a single index
217226
// or multiple indices are specified yield different behaviour.
@@ -396,7 +405,7 @@ private static IllegalArgumentException aliasesNotSupportedException(String expr
396405
* @param state the cluster state containing all the data to resolve to expression to a concrete index
397406
* @param request The request that defines how the an alias or an index need to be resolved to a concrete index
398407
* and the expression that can be resolved to an alias or an index name.
399-
* @throws IllegalArgumentException if the index resolution lead to more than one index
408+
* @throws IllegalArgumentException if the index resolution returns more than one index; if a remote index is requested.
400409
* @return the concrete index obtained as a result of the index resolution
401410
*/
402411
public Index concreteSingleIndex(ClusterState state, IndicesRequest request) {
@@ -433,7 +442,8 @@ public Index concreteWriteIndex(ClusterState state, IndicesRequest request) {
433442
* @param index index that can be resolved to alias or index name.
434443
* @param allowNoIndices whether to allow resolve to no index
435444
* @param includeDataStreams Whether data streams should be included in the evaluation.
436-
* @throws IllegalArgumentException if the index resolution does not lead to an index, or leads to more than one index
445+
* @throws IllegalArgumentException if the index resolution does not lead to an index, or leads to more than one index, as well as
446+
* if a remote index is requested.
437447
* @return the write index obtained as a result of the index resolution or null if no index
438448
*/
439449
public Index concreteWriteIndex(ClusterState state, IndicesOptions options, String index, boolean allowNoIndices,

server/src/test/java/org/elasticsearch/cluster/metadata/IndexNameExpressionResolverTests.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2411,6 +2411,27 @@ public void testMathExpressionSupportWithOlderDate() {
24112411

24122412
assertEquals(resolved, "older-date-2020-12");
24132413
}
2414+
2415+
public void testRemoteIndex() {
2416+
Metadata.Builder mdBuilder = Metadata.builder();
2417+
ClusterState state = ClusterState.builder(new ClusterName("_name")).metadata(mdBuilder).build();
2418+
2419+
{
2420+
IndicesOptions options = IndicesOptions.fromOptions(false, randomBoolean(), randomBoolean(), randomBoolean(), randomBoolean());
2421+
IndexNameExpressionResolver.Context context = new IndexNameExpressionResolver.Context(state, options, NONE);
2422+
IllegalArgumentException iae = expectThrows(IllegalArgumentException.class,
2423+
() -> indexNameExpressionResolver.concreteIndexNames(context, "cluster:index", "local"));
2424+
assertEquals("Cross-cluster calls are not supported in this context but remote indices were requested: [cluster:index]",
2425+
iae.getMessage());
2426+
}
2427+
{
2428+
IndicesOptions options = IndicesOptions.fromOptions(true, true, randomBoolean(), randomBoolean(), randomBoolean());
2429+
IndexNameExpressionResolver.Context context = new IndexNameExpressionResolver.Context(state, options, NONE);
2430+
String[] indexNames = indexNameExpressionResolver.concreteIndexNames(context, "cluster:index", "local");
2431+
assertEquals(0, indexNames.length);
2432+
}
2433+
}
2434+
24142435
private ClusterState systemIndexTestClusterState() {
24152436
Settings settings = Settings.builder().build();
24162437
Metadata.Builder mdBuilder = Metadata.builder()

0 commit comments

Comments
 (0)