99
1010package org .elasticsearch .rest .action .admin .indices ;
1111
12+ import org .elasticsearch .ElasticsearchException ;
1213import org .elasticsearch .action .admin .indices .resolve .ResolveIndexAction ;
1314import org .elasticsearch .action .support .IndicesOptions ;
1415import org .elasticsearch .client .internal .node .NodeClient ;
16+ import org .elasticsearch .common .ParsingException ;
1517import org .elasticsearch .common .Strings ;
1618import org .elasticsearch .common .settings .Settings ;
1719import org .elasticsearch .index .IndexMode ;
2022import org .elasticsearch .rest .Scope ;
2123import org .elasticsearch .rest .ServerlessScope ;
2224import org .elasticsearch .rest .action .RestToXContentListener ;
25+ import org .elasticsearch .search .crossproject .CrossProjectModeDecider ;
26+ import org .elasticsearch .xcontent .XContentParser ;
2327
2428import java .io .IOException ;
2529import java .util .Arrays ;
2630import java .util .EnumSet ;
2731import java .util .List ;
2832import java .util .Set ;
33+ import java .util .concurrent .atomic .AtomicReference ;
2934
3035import static org .elasticsearch .rest .RestRequest .Method .GET ;
36+ import static org .elasticsearch .rest .RestRequest .Method .POST ;
3137
3238@ ServerlessScope (Scope .PUBLIC )
3339public class RestResolveIndexAction extends BaseRestHandler {
3440 private static final Set <String > CAPABILITIES = Set .of ("mode_filter" );
35- private final Settings settings ;
41+ private final CrossProjectModeDecider crossProjectModeDecider ;
3642
3743 public RestResolveIndexAction (Settings settings ) {
38- this .settings = settings ;
44+ this .crossProjectModeDecider = new CrossProjectModeDecider ( settings ) ;
3945 }
4046
4147 @ Override
@@ -45,7 +51,7 @@ public String getName() {
4551
4652 @ Override
4753 public List <Route > routes () {
48- return List .of (new Route (GET , "/_resolve/index/{name}" ));
54+ return List .of (new Route (GET , "/_resolve/index/{name}" ), new Route ( POST , "/_resolve/index/{name}" ) );
4955 }
5056
5157 @ Override
@@ -57,17 +63,28 @@ public Set<String> supportedCapabilities() {
5763 protected BaseRestHandler .RestChannelConsumer prepareRequest (RestRequest request , NodeClient client ) throws IOException {
5864 String [] indices = Strings .splitStringByCommaToArray (request .param ("name" ));
5965 String modeParam = request .param ("mode" );
60- final boolean crossProjectEnabled = settings != null && settings .getAsBoolean ("serverless.cross_project.enabled" , false );
61- String projectRouting = null ;
62- if (crossProjectEnabled ) {
63- projectRouting = request .param ("project_routing" );
64- }
66+
67+ final boolean crossProjectEnabled = crossProjectModeDecider .crossProjectEnabled ();
68+ AtomicReference <String > projectRouting = new AtomicReference <>();
6569 IndicesOptions indicesOptions = IndicesOptions .fromRequest (request , ResolveIndexAction .Request .DEFAULT_INDICES_OPTIONS );
70+
6671 if (crossProjectEnabled ) {
72+ request .withContentOrSourceParamParserOrNull (parser -> {
73+ try {
74+ // If parser is null, there's no request body. projectRouting will then yield `null`.
75+ if (parser != null ) {
76+ projectRouting .set (parseProjectRouting (parser ));
77+ }
78+ } catch (Exception e ) {
79+ throw new ElasticsearchException ("Couldn't parse request body" , e );
80+ }
81+ });
82+
6783 indicesOptions = IndicesOptions .builder (indicesOptions )
6884 .crossProjectModeOptions (new IndicesOptions .CrossProjectModeOptions (true ))
6985 .build ();
7086 }
87+
7188 ResolveIndexAction .Request resolveRequest = new ResolveIndexAction .Request (
7289 indices ,
7390 indicesOptions ,
@@ -76,8 +93,44 @@ protected BaseRestHandler.RestChannelConsumer prepareRequest(RestRequest request
7693 : Arrays .stream (modeParam .split ("," ))
7794 .map (IndexMode ::fromString )
7895 .collect (() -> EnumSet .noneOf (IndexMode .class ), EnumSet ::add , EnumSet ::addAll ),
79- projectRouting
96+ projectRouting . get ()
8097 );
8198 return channel -> client .admin ().indices ().resolveIndex (resolveRequest , new RestToXContentListener <>(channel ));
8299 }
100+
101+ private static String parseProjectRouting (XContentParser parser ) throws IOException {
102+ try {
103+ XContentParser .Token first = parser .nextToken ();
104+ if (first == null ) {
105+ return null ;
106+ }
107+
108+ if (first != XContentParser .Token .START_OBJECT ) {
109+ throw new ParsingException (
110+ parser .getTokenLocation (),
111+ "Expected [" + XContentParser .Token .START_OBJECT + "] but found [" + first + "]" ,
112+ parser .getTokenLocation ()
113+ );
114+ }
115+
116+ String projectRouting = null ;
117+ for (XContentParser .Token token = parser .nextToken (); token != XContentParser .Token .END_OBJECT ; token = parser .nextToken ()) {
118+ if (token == XContentParser .Token .FIELD_NAME ) {
119+ String currentName = parser .currentName ();
120+ if ("project_routing" .equals (currentName )) {
121+ parser .nextToken ();
122+ projectRouting = parser .text ();
123+ } else {
124+ throw new ParsingException (parser .getTokenLocation (), "request does not support [" + parser .currentName () + "]" );
125+ }
126+ }
127+ }
128+
129+ return projectRouting ;
130+ } catch (ParsingException e ) {
131+ throw e ;
132+ } catch (Exception e ) {
133+ throw new ParsingException (parser == null ? null : parser .getTokenLocation (), "Failed to parse" , e );
134+ }
135+ }
83136}
0 commit comments