Skip to content

Commit 27f5fac

Browse files
authored
[CPS] Create Cross Project IndicesOptions (#135470)
An initial IndicesOptions for CrossProject. This will be used to identify when the index must be resolved for a cross-project search. It currently always defaults to false so we can start reading the value, and a later commit will handle enabling it.
1 parent 915742f commit 27f5fac

File tree

7 files changed

+97
-16
lines changed

7 files changed

+97
-16
lines changed

server/src/main/java/org/elasticsearch/action/admin/indices/rollover/TransportRolloverAction.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,8 @@ protected ClusterBlockException checkBlock(RolloverRequest request, ClusterState
159159
.matchOpen(request.indicesOptions().expandWildcardsOpen())
160160
.matchClosed(request.indicesOptions().expandWildcardsClosed())
161161
.build(),
162-
IndicesOptions.GatekeeperOptions.DEFAULT
162+
IndicesOptions.GatekeeperOptions.DEFAULT,
163+
IndicesOptions.CrossProjectModeOptions.DEFAULT
163164
);
164165
ResolvedExpression resolvedRolloverTarget = SelectorResolver.parseExpression(request.getRolloverTarget(), request.indicesOptions());
165166
final IndexAbstraction indexAbstraction = projectMetadata.getIndicesLookup().get(resolvedRolloverTarget.resource());
@@ -255,7 +256,8 @@ protected void masterOperation(
255256
final var statsIndicesOptions = new IndicesOptions(
256257
IndicesOptions.ConcreteTargetOptions.ALLOW_UNAVAILABLE_TARGETS,
257258
IndicesOptions.WildcardOptions.builder().matchClosed(true).allowEmptyExpressions(false).build(),
258-
IndicesOptions.GatekeeperOptions.DEFAULT
259+
IndicesOptions.GatekeeperOptions.DEFAULT,
260+
IndicesOptions.CrossProjectModeOptions.DEFAULT
259261
);
260262
// Make sure to recombine any selectors on the stats request
261263
IndicesStatsRequest statsRequest = new IndicesStatsRequest().indices(resolvedRolloverTarget.combined())

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

Lines changed: 67 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
package org.elasticsearch.action.support;
1010

1111
import org.elasticsearch.ElasticsearchParseException;
12+
import org.elasticsearch.TransportVersion;
1213
import org.elasticsearch.TransportVersions;
1314
import org.elasticsearch.common.io.stream.StreamInput;
1415
import org.elasticsearch.common.io.stream.StreamOutput;
16+
import org.elasticsearch.common.io.stream.Writeable;
1517
import org.elasticsearch.common.logging.DeprecationCategory;
1618
import org.elasticsearch.common.logging.DeprecationLogger;
1719
import org.elasticsearch.core.Nullable;
@@ -45,11 +47,14 @@
4547
* @param gatekeeperOptions, applies to all the resolved indices and defines if throttled will be included and if certain type of
4648
* aliases or indices are allowed, or they will throw an error. It acts as a gatekeeper when an action
4749
* does not support certain options.
50+
* @param crossProjectModeOptions, applies to all the indices and adds logic specific for cross-project search. These options are
51+
* internal-only and can change over the lifetime of a single request.
4852
*/
4953
public record IndicesOptions(
5054
ConcreteTargetOptions concreteTargetOptions,
5155
WildcardOptions wildcardOptions,
52-
GatekeeperOptions gatekeeperOptions
56+
GatekeeperOptions gatekeeperOptions,
57+
CrossProjectModeOptions crossProjectModeOptions
5358
) implements ToXContentFragment {
5459

5560
public static IndicesOptions.Builder builder() {
@@ -413,6 +418,37 @@ public static Builder builder(GatekeeperOptions gatekeeperOptions) {
413418
}
414419
}
415420

421+
/**
422+
* The cross-project mode options are internal-only options that apply on all indices that have been selected by the other Options.
423+
* These options may contextually change over the lifetime of the request.
424+
* @param resolveIndexExpression determines that the index expression must be resolved for cross-project requests, defaults to false.
425+
*/
426+
public record CrossProjectModeOptions(boolean resolveIndexExpression) implements Writeable {
427+
428+
public static final CrossProjectModeOptions DEFAULT = new CrossProjectModeOptions(false);
429+
430+
private static final TransportVersion INDICES_OPTIONS_RESOLUTION_MODE = TransportVersion.fromName(
431+
"indices_options_resolution_mode"
432+
);
433+
434+
private static final String INDEX_EXPRESSION_NAME = "resolve_cross_project_index_expression";
435+
436+
@Override
437+
public void writeTo(StreamOutput out) throws IOException {
438+
if (out.getTransportVersion().supports(INDICES_OPTIONS_RESOLUTION_MODE)) {
439+
out.writeBoolean(resolveIndexExpression);
440+
}
441+
}
442+
443+
public static CrossProjectModeOptions readFrom(StreamInput in) throws IOException {
444+
if (in.getTransportVersion().supports(INDICES_OPTIONS_RESOLUTION_MODE)) {
445+
return new CrossProjectModeOptions(in.readBoolean());
446+
} else {
447+
return CrossProjectModeOptions.DEFAULT;
448+
}
449+
}
450+
}
451+
416452
/**
417453
* This class is maintained for backwards compatibility and performance purposes. We use it for serialisation along with {@link Option}.
418454
*/
@@ -463,7 +499,8 @@ private enum Option {
463499
public static final IndicesOptions DEFAULT = new IndicesOptions(
464500
ConcreteTargetOptions.ERROR_WHEN_UNAVAILABLE_TARGETS,
465501
WildcardOptions.DEFAULT,
466-
GatekeeperOptions.DEFAULT
502+
GatekeeperOptions.DEFAULT,
503+
CrossProjectModeOptions.DEFAULT
467504
);
468505

469506
public static final IndicesOptions STRICT_EXPAND_OPEN = IndicesOptions.builder()
@@ -857,6 +894,13 @@ public boolean ignoreThrottled() {
857894
return gatekeeperOptions().ignoreThrottled();
858895
}
859896

897+
/**
898+
* @return whether indices will resolve to the cross-project "flat world" expression
899+
*/
900+
public boolean resolveCrossProjectIndexExpression() {
901+
return crossProjectModeOptions().resolveIndexExpression();
902+
}
903+
860904
public void writeIndicesOptions(StreamOutput out) throws IOException {
861905
EnumSet<Option> backwardsCompatibleOptions = EnumSet.noneOf(Option.class);
862906
if (allowNoIndices()) {
@@ -902,6 +946,7 @@ public void writeIndicesOptions(StreamOutput out) throws IOException {
902946
out.writeBoolean(true);
903947
out.writeBoolean(false);
904948
}
949+
out.writeWriteable(crossProjectModeOptions);
905950
}
906951

907952
public static IndicesOptions readIndicesOptions(StreamInput in) throws IOException {
@@ -930,14 +975,16 @@ public static IndicesOptions readIndicesOptions(StreamInput in) throws IOExcepti
930975
? ConcreteTargetOptions.ALLOW_UNAVAILABLE_TARGETS
931976
: ConcreteTargetOptions.ERROR_WHEN_UNAVAILABLE_TARGETS,
932977
wildcardOptions,
933-
gatekeeperOptions
978+
gatekeeperOptions,
979+
CrossProjectModeOptions.readFrom(in)
934980
);
935981
}
936982

937983
public static class Builder {
938984
private ConcreteTargetOptions concreteTargetOptions;
939985
private WildcardOptions wildcardOptions;
940986
private GatekeeperOptions gatekeeperOptions;
987+
private CrossProjectModeOptions crossProjectModeOptions;
941988

942989
Builder() {
943990
this(DEFAULT);
@@ -947,6 +994,7 @@ public static class Builder {
947994
concreteTargetOptions = indicesOptions.concreteTargetOptions;
948995
wildcardOptions = indicesOptions.wildcardOptions;
949996
gatekeeperOptions = indicesOptions.gatekeeperOptions;
997+
crossProjectModeOptions = indicesOptions.crossProjectModeOptions;
950998
}
951999

9521000
public Builder concreteTargetOptions(ConcreteTargetOptions concreteTargetOptions) {
@@ -974,8 +1022,13 @@ public Builder gatekeeperOptions(GatekeeperOptions.Builder generalOptions) {
9741022
return this;
9751023
}
9761024

1025+
public Builder crossProjectModeOptions(CrossProjectModeOptions crossProjectModeOptions) {
1026+
this.crossProjectModeOptions = crossProjectModeOptions;
1027+
return this;
1028+
}
1029+
9771030
public IndicesOptions build() {
978-
return new IndicesOptions(concreteTargetOptions, wildcardOptions, gatekeeperOptions);
1031+
return new IndicesOptions(concreteTargetOptions, wildcardOptions, gatekeeperOptions, crossProjectModeOptions);
9791032
}
9801033
}
9811034

@@ -1077,7 +1130,8 @@ public static IndicesOptions fromOptions(
10771130
return new IndicesOptions(
10781131
ignoreUnavailable ? ConcreteTargetOptions.ALLOW_UNAVAILABLE_TARGETS : ConcreteTargetOptions.ERROR_WHEN_UNAVAILABLE_TARGETS,
10791132
wildcards,
1080-
gatekeeperOptions
1133+
gatekeeperOptions,
1134+
CrossProjectModeOptions.DEFAULT
10811135
);
10821136
}
10831137

@@ -1148,14 +1202,18 @@ public static IndicesOptions fromParameters(
11481202
return defaultSettings;
11491203
}
11501204

1151-
WildcardOptions wildcards = WildcardOptions.parseParameters(wildcardsString, allowNoIndicesString, defaultSettings.wildcardOptions);
1152-
GatekeeperOptions gatekeeperOptions = GatekeeperOptions.parseParameter(ignoreThrottled, defaultSettings.gatekeeperOptions);
1205+
var wildcards = WildcardOptions.parseParameters(wildcardsString, allowNoIndicesString, defaultSettings.wildcardOptions);
1206+
var gatekeeperOptions = GatekeeperOptions.parseParameter(ignoreThrottled, defaultSettings.gatekeeperOptions);
1207+
var crossProjectModeOptions = defaultSettings.crossProjectModeOptions != null
1208+
? defaultSettings.crossProjectModeOptions
1209+
: CrossProjectModeOptions.DEFAULT;
11531210

11541211
// note that allowAliasesToMultipleIndices is not exposed, always true (only for internal use)
11551212
return IndicesOptions.builder()
11561213
.concreteTargetOptions(ConcreteTargetOptions.fromParameter(ignoreUnavailableString, defaultSettings.concreteTargetOptions))
11571214
.wildcardOptions(wildcards)
11581215
.gatekeeperOptions(gatekeeperOptions)
1216+
.crossProjectModeOptions(crossProjectModeOptions)
11591217
.build();
11601218
}
11611219

@@ -1421,6 +1479,8 @@ public String toString() {
14211479
+ allowSelectors()
14221480
+ ", include_failure_indices="
14231481
+ includeFailureIndices()
1482+
+ ", resolve_cross_project_index_expression="
1483+
+ resolveCrossProjectIndexExpression()
14241484
+ ']';
14251485
}
14261486
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
9192000
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
add_cross_cluster_api_key_signature,9191000
1+
indices_options_resolution_mode,9192000

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
package org.elasticsearch.action.support;
1111

1212
import org.elasticsearch.action.support.IndicesOptions.ConcreteTargetOptions;
13+
import org.elasticsearch.action.support.IndicesOptions.CrossProjectModeOptions;
1314
import org.elasticsearch.action.support.IndicesOptions.GatekeeperOptions;
1415
import org.elasticsearch.action.support.IndicesOptions.WildcardOptions;
1516
import org.elasticsearch.common.bytes.BytesReference;
@@ -57,6 +58,7 @@ public void testSerialization() throws Exception {
5758
.allowClosedIndices(randomBoolean())
5859
.allowSelectors(randomBoolean())
5960
)
61+
.crossProjectModeOptions(new CrossProjectModeOptions(randomBoolean()))
6062
.build();
6163

6264
BytesStreamOutput output = new BytesStreamOutput();
@@ -102,6 +104,7 @@ public void testFromOptions() {
102104
assertThat(indicesOptions.forbidClosedIndices(), equalTo(forbidClosedIndices));
103105
assertEquals(ignoreAliases, indicesOptions.ignoreAliases());
104106
assertEquals(ignoreThrottled, indicesOptions.ignoreThrottled());
107+
assertEquals(indicesOptions.resolveCrossProjectIndexExpression(), CrossProjectModeOptions.DEFAULT.resolveIndexExpression());
105108
}
106109

107110
public void testFromOptionsWithDefaultOptions() {
@@ -138,6 +141,7 @@ public void testFromOptionsWithDefaultOptions() {
138141
assertEquals(defaultOptions.allowAliasesToMultipleIndices(), indicesOptions.allowAliasesToMultipleIndices());
139142
assertEquals(defaultOptions.forbidClosedIndices(), indicesOptions.forbidClosedIndices());
140143
assertEquals(defaultOptions.ignoreAliases(), indicesOptions.ignoreAliases());
144+
assertEquals(defaultOptions.resolveCrossProjectIndexExpression(), indicesOptions.resolveCrossProjectIndexExpression());
141145
}
142146

143147
public void testFromParameters() {
@@ -201,6 +205,7 @@ public void testFromParameters() {
201205
assertEquals(defaultOptions.allowAliasesToMultipleIndices(), updatedOptions.allowAliasesToMultipleIndices());
202206
assertEquals(defaultOptions.forbidClosedIndices(), updatedOptions.forbidClosedIndices());
203207
assertEquals(defaultOptions.ignoreAliases(), updatedOptions.ignoreAliases());
208+
assertEquals(defaultOptions.resolveCrossProjectIndexExpression(), updatedOptions.resolveCrossProjectIndexExpression());
204209
}
205210

206211
public void testEqualityAndHashCode() {
@@ -330,6 +335,7 @@ public void testFromMap() {
330335
assertEquals(ignoreUnavailable == null ? defaults.ignoreUnavailable() : ignoreUnavailable, fromMap.ignoreUnavailable());
331336
assertEquals(allowNoIndices == null ? defaults.allowNoIndices() : allowNoIndices, fromMap.allowNoIndices());
332337
assertEquals(ignoreThrottled == null ? defaults.ignoreThrottled() : ignoreThrottled, fromMap.ignoreThrottled());
338+
assertEquals(fromMap.resolveCrossProjectIndexExpression(), CrossProjectModeOptions.DEFAULT.resolveIndexExpression());
333339
}
334340

335341
public void testToXContent() throws IOException {
@@ -348,8 +354,14 @@ public void testToXContent() throws IOException {
348354
randomBoolean(),
349355
randomBoolean()
350356
);
357+
CrossProjectModeOptions crossProjectModeOptions = new CrossProjectModeOptions(randomBoolean());
351358

352-
IndicesOptions indicesOptions = new IndicesOptions(concreteTargetOptions, wildcardOptions, gatekeeperOptions);
359+
IndicesOptions indicesOptions = new IndicesOptions(
360+
concreteTargetOptions,
361+
wildcardOptions,
362+
gatekeeperOptions,
363+
crossProjectModeOptions
364+
);
353365

354366
XContentType type = randomFrom(XContentType.values());
355367
BytesReference xContentBytes = toXContentBytes(indicesOptions, type);
@@ -423,6 +435,7 @@ public void testFromXContentWithWildcardSpecialValues() throws IOException {
423435
assertTrue(fromXContentOptions.expandWildcardsClosed());
424436
assertTrue(fromXContentOptions.expandWildcardsHidden());
425437
assertTrue(fromXContentOptions.expandWildcardsOpen());
438+
assertFalse(fromXContentOptions.resolveCrossProjectIndexExpression());
426439

427440
try (XContentBuilder builder = XContentFactory.contentBuilder(type)) {
428441
builder.startObject();
@@ -441,6 +454,7 @@ public void testFromXContentWithWildcardSpecialValues() throws IOException {
441454
assertFalse(fromXContentOptions.expandWildcardsClosed());
442455
assertFalse(fromXContentOptions.expandWildcardsHidden());
443456
assertFalse(fromXContentOptions.expandWildcardsOpen());
457+
assertFalse(fromXContentOptions.resolveCrossProjectIndexExpression());
444458
}
445459

446460
public void testFromXContentWithDefaults() throws Exception {
@@ -494,6 +508,7 @@ public void testFromXContentWithDefaults() throws Exception {
494508
}
495509
assertEquals(ignoreUnavailable, fromXContentOptions.ignoreUnavailable());
496510
assertEquals(expectedWildcardStates, fromXContentOptions.wildcardOptions());
511+
assertFalse(fromXContentOptions.resolveCrossProjectIndexExpression());
497512
}
498513

499514
private BytesReference toXContentBytes(IndicesOptions indicesOptions, XContentType type) throws IOException {

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2371,7 +2371,8 @@ public void testIgnoreThrottled() {
23712371
new IndicesOptions(
23722372
IndicesOptions.ConcreteTargetOptions.ERROR_WHEN_UNAVAILABLE_TARGETS,
23732373
IndicesOptions.WildcardOptions.DEFAULT,
2374-
IndicesOptions.GatekeeperOptions.builder().ignoreThrottled(true).build()
2374+
IndicesOptions.GatekeeperOptions.builder().ignoreThrottled(true).build(),
2375+
IndicesOptions.CrossProjectModeOptions.DEFAULT
23752376
),
23762377
"ind*",
23772378
"test-index"

x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/datafeed/DatafeedNodeSelectorTests.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,8 @@ public void testIndexDoesntExist() {
349349
+ "indices_options [IndicesOptions[ignore_unavailable=false, allow_no_indices=true, expand_wildcards_open=true, "
350350
+ "expand_wildcards_closed=false, expand_wildcards_hidden=false, allow_aliases_to_multiple_indices=true, "
351351
+ "forbid_closed_indices=true, ignore_aliases=false, ignore_throttled=true, "
352-
+ "allow_selectors=true, include_failure_indices=false]] with exception [no such index [not_foo]]"
352+
+ "allow_selectors=true, include_failure_indices=false, resolve_cross_project_index_expression=false]] "
353+
+ "with exception [no such index [not_foo]]"
353354
)
354355
)
355356
);
@@ -383,8 +384,8 @@ public void testIndexDoesntExist() {
383384
+ "indices given [not_foo] and indices_options [IndicesOptions[ignore_unavailable=false, allow_no_indices=true, "
384385
+ "expand_wildcards_open=true, expand_wildcards_closed=false, expand_wildcards_hidden=false, "
385386
+ "allow_aliases_to_multiple_indices=true, forbid_closed_indices=true, ignore_aliases=false, "
386-
+ "ignore_throttled=true, allow_selectors=true, include_failure_indices=false]] with exception "
387-
+ "[no such index [not_foo]]]"
387+
+ "ignore_throttled=true, allow_selectors=true, include_failure_indices=false,"
388+
+ " resolve_cross_project_index_expression=false]] with exception [no such index [not_foo]]]"
388389
)
389390
)
390391
);
@@ -561,7 +562,8 @@ public void testSelectNode_GivenJobOpeningAndIndexDoesNotExist() {
561562
+ "indices_options [IndicesOptions[ignore_unavailable=false, allow_no_indices=true, expand_wildcards_open=true, "
562563
+ "expand_wildcards_closed=false, expand_wildcards_hidden=false, allow_aliases_to_multiple_indices=true, "
563564
+ "forbid_closed_indices=true, ignore_aliases=false, ignore_throttled=true, "
564-
+ "allow_selectors=true, include_failure_indices=false]] with exception [no such index [not_foo]]]"
565+
+ "allow_selectors=true, include_failure_indices=false, resolve_cross_project_index_expression=false]]"
566+
+ " with exception [no such index [not_foo]]]"
565567
)
566568
)
567569
);

0 commit comments

Comments
 (0)