1212import org .elasticsearch .action .admin .cluster .allocation .ClusterAllocationExplainRequest ;
1313import org .elasticsearch .action .admin .cluster .allocation .TransportClusterAllocationExplainAction ;
1414import org .elasticsearch .client .internal .node .NodeClient ;
15+ import org .elasticsearch .common .util .set .Sets ;
1516import org .elasticsearch .rest .BaseRestHandler ;
1617import org .elasticsearch .rest .RestRequest ;
1718import org .elasticsearch .rest .RestUtils ;
2122import org .elasticsearch .xcontent .XContentParser ;
2223
2324import java .io .IOException ;
25+ import java .util .Iterator ;
2426import java .util .List ;
27+ import java .util .Set ;
2528
2629import static org .elasticsearch .rest .RestRequest .Method .GET ;
2730import static org .elasticsearch .rest .RestRequest .Method .POST ;
@@ -47,23 +50,85 @@ public boolean allowSystemIndexAccessByDefault() {
4750 return true ;
4851 }
4952
53+ @ Override
54+ public Set <String > allSupportedParameters () {
55+ return ClusterAllocationExplainRequest .ALL_SUPPORTED_PARAMETERS ;
56+ }
57+
58+ @ Override
59+ public Set <String > supportedQueryParameters () {
60+ return ClusterAllocationExplainRequest .QUERY_PARAMETERS ;
61+ }
62+
5063 @ Override
5164 public RestChannelConsumer prepareRequest (final RestRequest request , final NodeClient client ) throws IOException {
52- final var req = new ClusterAllocationExplainRequest (RestUtils .getMasterNodeTimeout (request ));
53- if (request .hasContentOrSourceParam ()) {
54- try (XContentParser parser = request .contentOrSourceParamParser ()) {
55- ClusterAllocationExplainRequest .parse (req , parser );
65+ /*
66+ https://github.com/elastic/elasticsearch/issues/127028 introduces dual behaviour for this API.
67+ We now support either, but not a mix of:
68+ 1. Parameters being passed in the URL
69+ 2. The legacy behaviour of passing parameters in the body of the request
70+ */
71+
72+ // boolean userPassedParametersInPath = !request.params().isEmpty();
73+
74+ boolean userPassedParametersInPath = isPathParameterProvided (request .params ().keySet ());
75+ final var clusterAllocationExplainRequest = new ClusterAllocationExplainRequest (RestUtils .getMasterNodeTimeout (request ));
76+
77+ if (userPassedParametersInPath ) {
78+ String index = request .param (ClusterAllocationExplainRequest .INDEX_PARAMETER_NAME );
79+ if (index == null ) {
80+ throw new IllegalArgumentException ("The index parameter cannot be blank." );
81+ }
82+ clusterAllocationExplainRequest .setIndex (index );
83+
84+ String shard = request .param (ClusterAllocationExplainRequest .SHARD_PARAMETER_NAME );
85+ if (shard == null ) {
86+ throw new IllegalArgumentException ("The shard parameter cannot be blank." );
5687 }
57- } // else ok, an empty body means "explain the first unassigned shard you find"
58- req .includeYesDecisions (request .paramAsBoolean ("include_yes_decisions" , false ));
59- req .includeDiskInfo (request .paramAsBoolean ("include_disk_info" , false ));
88+ clusterAllocationExplainRequest .setShard (Integer .parseInt (shard ));
89+
90+ String primary = request .param (ClusterAllocationExplainRequest .PRIMARY_PARAMETER_NAME );
91+ if (primary == null ) {
92+ throw new IllegalArgumentException ("The primary parameter cannot be blank." );
93+ }
94+ clusterAllocationExplainRequest .setPrimary (Boolean .parseBoolean (primary ));
95+
96+ String current_node = request .param (ClusterAllocationExplainRequest .CURRENT_NODE_PARAMETER_NAME );
97+ if (current_node == null ) {
98+ throw new IllegalArgumentException ("The current_node parameter cannot be blank." );
99+ }
100+ clusterAllocationExplainRequest .setCurrentNode (current_node );
101+
102+ // TODO - include_yes_decisions and include_disk_info
103+ } else {
104+ if (request .hasContentOrSourceParam ()) {
105+ try (XContentParser parser = request .contentOrSourceParamParser ()) {
106+ ClusterAllocationExplainRequest .parse (clusterAllocationExplainRequest , parser );
107+ }
108+ } // else ok, an empty body means "explain the first unassigned shard you find"
109+ // TODO - Set all 4 params to being consumed
110+
111+ // TODO - Can we move this outside the IF statement so it runs for both?
112+ clusterAllocationExplainRequest .includeYesDecisions (request .paramAsBoolean ("include_yes_decisions" , false ));
113+ clusterAllocationExplainRequest .includeDiskInfo (request .paramAsBoolean ("include_disk_info" , false ));
114+ }
115+
60116 return channel -> client .execute (
61117 TransportClusterAllocationExplainAction .TYPE ,
62- req ,
118+ clusterAllocationExplainRequest ,
63119 new RestRefCountedChunkedToXContentListener <>(channel )
64120 );
65121 }
66122
123+ private boolean isPathParameterProvided (Set <String > parameters ) {
124+ for (String parameter : parameters ) {
125+ if (ClusterAllocationExplainRequest .PATH_PARAMETERS .contains (parameter )) {
126+ return true ;
127+ }
128+ }
129+ return false ;
130+ }
131+
67132 @ Override
68133 public boolean canTripCircuitBreaker () {
69134 return false ;
0 commit comments