Skip to content

Commit 72e6970

Browse files
authored
Integrate with the new resolve_cross_project IndicesOptions (#136463)
This PR builds on top of #135470 to set the new resolve_cross_project indicesOptions for resolveIndex and search requests when CPS is enabled Relates: ES-13173 Relates: #135346 Relates: #135470
1 parent e65110c commit 72e6970

File tree

5 files changed

+102
-11
lines changed

5 files changed

+102
-11
lines changed

server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestResolveIndexAction.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,20 @@ public Set<String> supportedCapabilities() {
5757
protected BaseRestHandler.RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
5858
String[] indices = Strings.splitStringByCommaToArray(request.param("name"));
5959
String modeParam = request.param("mode");
60-
if (settings != null && settings.getAsBoolean("serverless.cross_project.enabled", false)) {
60+
final boolean crossProjectEnabled = settings != null && settings.getAsBoolean("serverless.cross_project.enabled", false);
61+
if (crossProjectEnabled) {
6162
// accept but drop project_routing param until fully supported
6263
request.param("project_routing");
6364
}
65+
IndicesOptions indicesOptions = IndicesOptions.fromRequest(request, ResolveIndexAction.Request.DEFAULT_INDICES_OPTIONS);
66+
if (crossProjectEnabled) {
67+
indicesOptions = IndicesOptions.builder(indicesOptions)
68+
.crossProjectModeOptions(new IndicesOptions.CrossProjectModeOptions(true))
69+
.build();
70+
}
6471
ResolveIndexAction.Request resolveRequest = new ResolveIndexAction.Request(
6572
indices,
66-
IndicesOptions.fromRequest(request, ResolveIndexAction.Request.DEFAULT_INDICES_OPTIONS),
73+
indicesOptions,
6774
modeParam == null
6875
? null
6976
: Arrays.stream(modeParam.split(","))

server/src/main/java/org/elasticsearch/rest/action/search/RestSearchAction.java

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC
109109
// this might be set by old clients
110110
request.param("min_compatible_shard_node");
111111

112-
if (settings != null && settings.getAsBoolean("serverless.cross_project.enabled", false)) {
112+
final boolean crossProjectEnabled = settings != null && settings.getAsBoolean("serverless.cross_project.enabled", false);
113+
if (crossProjectEnabled) {
113114
// accept but drop project_routing param until fully supported
114115
request.param("project_routing");
115116
}
@@ -128,7 +129,15 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC
128129
*/
129130
IntConsumer setSize = size -> searchRequest.source().size(size);
130131
request.withContentOrSourceParamParserOrNull(
131-
parser -> parseSearchRequest(searchRequest, request, parser, clusterSupportsFeature, setSize, searchUsageHolder)
132+
parser -> parseSearchRequest(
133+
searchRequest,
134+
request,
135+
parser,
136+
clusterSupportsFeature,
137+
setSize,
138+
searchUsageHolder,
139+
crossProjectEnabled
140+
)
132141
);
133142

134143
return channel -> {
@@ -157,6 +166,17 @@ public static void parseSearchRequest(
157166
parseSearchRequest(searchRequest, request, requestContentParser, clusterSupportsFeature, setSize, null);
158167
}
159168

169+
public static void parseSearchRequest(
170+
SearchRequest searchRequest,
171+
RestRequest request,
172+
@Nullable XContentParser requestContentParser,
173+
Predicate<NodeFeature> clusterSupportsFeature,
174+
IntConsumer setSize,
175+
@Nullable SearchUsageHolder searchUsageHolder
176+
) throws IOException {
177+
parseSearchRequest(searchRequest, request, requestContentParser, clusterSupportsFeature, setSize, searchUsageHolder, false);
178+
}
179+
160180
/**
161181
* Parses the rest request on top of the SearchRequest, preserving values that are not overridden by the rest request.
162182
*
@@ -167,14 +187,16 @@ public static void parseSearchRequest(
167187
* @param clusterSupportsFeature used to check if certain features are available in this cluster
168188
* @param setSize how the size url parameter is handled. {@code udpate_by_query} and regular search differ here.
169189
* @param searchUsageHolder the holder of search usage stats
190+
* @param crossProjectEnabled whether serverless.cross_project.enabled is set to true
170191
*/
171192
public static void parseSearchRequest(
172193
SearchRequest searchRequest,
173194
RestRequest request,
174195
@Nullable XContentParser requestContentParser,
175196
Predicate<NodeFeature> clusterSupportsFeature,
176197
IntConsumer setSize,
177-
@Nullable SearchUsageHolder searchUsageHolder
198+
@Nullable SearchUsageHolder searchUsageHolder,
199+
boolean crossProjectEnabled
178200
) throws IOException {
179201
if (searchRequest.source() == null) {
180202
searchRequest.source(new SearchSourceBuilder());
@@ -222,7 +244,13 @@ public static void parseSearchRequest(
222244
}
223245
searchRequest.routing(request.param("routing"));
224246
searchRequest.preference(request.param("preference"));
225-
searchRequest.indicesOptions(IndicesOptions.fromRequest(request, searchRequest.indicesOptions()));
247+
IndicesOptions indicesOptions = IndicesOptions.fromRequest(request, searchRequest.indicesOptions());
248+
if (crossProjectEnabled) {
249+
indicesOptions = IndicesOptions.builder(indicesOptions)
250+
.crossProjectModeOptions(new IndicesOptions.CrossProjectModeOptions(true))
251+
.build();
252+
}
253+
searchRequest.indicesOptions(indicesOptions);
226254

227255
validateSearchRequest(request, searchRequest);
228256

server/src/main/java/org/elasticsearch/search/crossproject/CrossProjectIndexResolutionValidator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,10 @@ public static ElasticsearchException validate(
167167
}
168168

169169
public static IndicesOptions indicesOptionsForCrossProjectFanout(IndicesOptions indicesOptions) {
170-
// TODO set resolveCrossProject=false here once we have an IndicesOptions flag for that
171170
return IndicesOptions.builder(indicesOptions)
172171
.concreteTargetOptions(new IndicesOptions.ConcreteTargetOptions(true))
173172
.wildcardOptions(IndicesOptions.WildcardOptions.builder(indicesOptions.wildcardOptions()).allowEmptyExpressions(true).build())
173+
.crossProjectModeOptions(IndicesOptions.CrossProjectModeOptions.DEFAULT)
174174
.build();
175175
}
176176

server/src/main/java/org/elasticsearch/search/crossproject/CrossProjectModeDecider.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
import org.elasticsearch.action.IndicesRequest;
1313
import org.elasticsearch.common.settings.Settings;
14-
import org.elasticsearch.core.Booleans;
1514

1615
/**
1716
* Utility class to determine whether Cross-Project Search (CPS) applies to an inbound request.
@@ -49,8 +48,7 @@ public boolean resolvesCrossProject(IndicesRequest.Replaceable request) {
4948
if (crossProjectEnabled == false) {
5049
return false;
5150
}
52-
// TODO this needs to be based on the IndicesOptions flag instead, once available
53-
final boolean indicesOptionsResolveCrossProject = Booleans.parseBoolean(System.getProperty("cps.resolve_cross_project", "false"));
54-
return request.allowsCrossProject() && indicesOptionsResolveCrossProject;
51+
// TODO: The following check can be an method on the request itself
52+
return request.allowsCrossProject() && request.indicesOptions().resolveCrossProjectIndexExpression();
5553
}
5654
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
package org.elasticsearch.rest.action.admin.indices;
10+
11+
import org.elasticsearch.action.ActionListener;
12+
import org.elasticsearch.action.ActionRequest;
13+
import org.elasticsearch.action.ActionResponse;
14+
import org.elasticsearch.action.ActionType;
15+
import org.elasticsearch.action.admin.indices.resolve.ResolveIndexAction;
16+
import org.elasticsearch.client.internal.node.NodeClient;
17+
import org.elasticsearch.cluster.project.TestProjectResolvers;
18+
import org.elasticsearch.common.settings.Settings;
19+
import org.elasticsearch.rest.RestRequest;
20+
import org.elasticsearch.test.ESTestCase;
21+
import org.elasticsearch.test.rest.FakeRestChannel;
22+
import org.elasticsearch.test.rest.FakeRestRequest;
23+
import org.elasticsearch.threadpool.ThreadPool;
24+
25+
import java.util.List;
26+
27+
import static org.hamcrest.Matchers.equalTo;
28+
import static org.mockito.Mockito.mock;
29+
30+
public class RestResolveIndexActionTests extends ESTestCase {
31+
32+
public void testAddResolveCrossProjectBasedOnSettingValue() throws Exception {
33+
final boolean cpsEnabled = randomBoolean();
34+
final Settings settings = Settings.builder().put("serverless.cross_project.enabled", cpsEnabled).build();
35+
final var action = new RestResolveIndexAction(settings);
36+
final var request = new FakeRestRequest.Builder(xContentRegistry()).withMethod(RestRequest.Method.GET)
37+
.withPath("/_resolve/index/foo")
38+
.build();
39+
40+
final NodeClient nodeClient = new NodeClient(settings, mock(ThreadPool.class), TestProjectResolvers.DEFAULT_PROJECT_ONLY) {
41+
@SuppressWarnings("unchecked")
42+
@Override
43+
public <Request extends ActionRequest, Response extends ActionResponse> void doExecute(
44+
ActionType<Response> action,
45+
Request request,
46+
ActionListener<Response> listener
47+
) {
48+
final var resolveIndexRequest = asInstanceOf(ResolveIndexAction.Request.class, request);
49+
assertThat(resolveIndexRequest.indicesOptions().resolveCrossProjectIndexExpression(), equalTo(cpsEnabled));
50+
listener.onResponse((Response) new ResolveIndexAction.Response(List.of(), List.of(), List.of()));
51+
}
52+
};
53+
54+
final var restChannel = new FakeRestChannel(request, true, 1);
55+
action.handleRequest(request, restChannel, nodeClient);
56+
assertThat(restChannel.responses().get(), equalTo(1));
57+
}
58+
}

0 commit comments

Comments
 (0)