Skip to content

Commit fc9c0ce

Browse files
Add level parameter validation in REST layer (#94136)
Relates #93981
1 parent ab1d891 commit fc9c0ce

File tree

21 files changed

+303
-72
lines changed

21 files changed

+303
-72
lines changed

docs/changelog/94136.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 94136
2+
summary: Add level parameter validation in REST layer
3+
area: Infra/REST API
4+
type: bug
5+
issues: [93981]
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.action;
10+
11+
import org.elasticsearch.xcontent.ToXContent;
12+
13+
public enum ClusterStatsLevel {
14+
CLUSTER("cluster"),
15+
INDICES("indices"),
16+
SHARDS("shards");
17+
18+
private final String level;
19+
20+
ClusterStatsLevel(String level) {
21+
this.level = level;
22+
}
23+
24+
public String getLevel() {
25+
return level;
26+
}
27+
28+
public static ClusterStatsLevel of(String level) {
29+
for (ClusterStatsLevel value : values()) {
30+
if (value.getLevel().equalsIgnoreCase(level)) {
31+
return value;
32+
}
33+
}
34+
throw new IllegalArgumentException("level parameter must be one of [cluster] or [indices] or [shards] but was [" + level + "]");
35+
}
36+
37+
public static ClusterStatsLevel of(ToXContent.Params params, ClusterStatsLevel defaultLevel) {
38+
return ClusterStatsLevel.of(params.param("level", defaultLevel.getLevel()));
39+
}
40+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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 and the Server Side Public License, v 1; you may not use this file except
5+
* in compliance with, at your election, the Elastic License 2.0 or the Server
6+
* Side Public License, v 1.
7+
*/
8+
9+
package org.elasticsearch.action;
10+
11+
import org.elasticsearch.xcontent.ToXContent;
12+
13+
public enum NodeStatsLevel {
14+
NODE("node"),
15+
INDICES("indices"),
16+
SHARDS("shards");
17+
18+
private final String level;
19+
20+
NodeStatsLevel(String level) {
21+
this.level = level;
22+
}
23+
24+
public String getLevel() {
25+
return level;
26+
}
27+
28+
public static NodeStatsLevel of(String level) {
29+
for (NodeStatsLevel value : values()) {
30+
if (value.getLevel().equalsIgnoreCase(level)) {
31+
return value;
32+
}
33+
}
34+
throw new IllegalArgumentException("level parameter must be one of [node] or [indices] or [shards] but was [" + level + "]");
35+
}
36+
37+
public static NodeStatsLevel of(ToXContent.Params params, NodeStatsLevel defaultLevel) {
38+
return NodeStatsLevel.of(params.param("level", defaultLevel.getLevel()));
39+
}
40+
}

server/src/main/java/org/elasticsearch/action/admin/cluster/health/ClusterHealthRequest.java

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import org.elasticsearch.core.TimeValue;
2121

2222
import java.io.IOException;
23-
import java.util.Objects;
2423
import java.util.concurrent.TimeUnit;
2524

2625
public class ClusterHealthRequest extends MasterNodeReadRequest<ClusterHealthRequest> implements IndicesRequest.Replaceable {
@@ -34,11 +33,6 @@ public class ClusterHealthRequest extends MasterNodeReadRequest<ClusterHealthReq
3433
private ActiveShardCount waitForActiveShards = ActiveShardCount.NONE;
3534
private String waitForNodes = "";
3635
private Priority waitForEvents = null;
37-
/**
38-
* Only used by the high-level REST Client. Controls the details level of the health information returned.
39-
* The default value is 'cluster'.
40-
*/
41-
private Level level = Level.CLUSTER;
4236

4337
public ClusterHealthRequest() {}
4438

@@ -232,30 +226,8 @@ public Priority waitForEvents() {
232226
return this.waitForEvents;
233227
}
234228

235-
/**
236-
* Set the level of detail for the health information to be returned.
237-
* Only used by the high-level REST Client.
238-
*/
239-
public void level(Level level) {
240-
this.level = Objects.requireNonNull(level, "level must not be null");
241-
}
242-
243-
/**
244-
* Get the level of detail for the health information to be returned.
245-
* Only used by the high-level REST Client.
246-
*/
247-
public Level level() {
248-
return level;
249-
}
250-
251229
@Override
252230
public ActionRequestValidationException validate() {
253231
return null;
254232
}
255-
256-
public enum Level {
257-
CLUSTER,
258-
INDICES,
259-
SHARDS
260-
}
261233
}

server/src/main/java/org/elasticsearch/action/admin/cluster/health/ClusterHealthResponse.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
package org.elasticsearch.action.admin.cluster.health;
1010

1111
import org.elasticsearch.action.ActionResponse;
12+
import org.elasticsearch.action.ClusterStatsLevel;
1213
import org.elasticsearch.cluster.ClusterState;
1314
import org.elasticsearch.cluster.health.ClusterHealthStatus;
1415
import org.elasticsearch.cluster.health.ClusterIndexHealth;
@@ -356,8 +357,8 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
356357
builder.humanReadableField(TASK_MAX_WAIT_TIME_IN_QUEUE_IN_MILLIS, TASK_MAX_WAIT_TIME_IN_QUEUE, getTaskMaxWaitingTime());
357358
builder.percentageField(ACTIVE_SHARDS_PERCENT_AS_NUMBER, ACTIVE_SHARDS_PERCENT, getActiveShardsPercent());
358359

359-
String level = params.param("level", "cluster");
360-
boolean outputIndices = "indices".equals(level) || "shards".equals(level);
360+
ClusterStatsLevel level = ClusterStatsLevel.of(params, ClusterStatsLevel.CLUSTER);
361+
boolean outputIndices = level == ClusterStatsLevel.INDICES || level == ClusterStatsLevel.SHARDS;
361362

362363
if (outputIndices) {
363364
builder.startObject(INDICES);

server/src/main/java/org/elasticsearch/action/admin/cluster/node/stats/NodesStatsRequest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ public enum Metric {
178178
INGEST("ingest"),
179179
ADAPTIVE_SELECTION("adaptive_selection"),
180180
SCRIPT_CACHE("script_cache"),
181-
INDEXING_PRESSURE("indexing_pressure"),;
181+
INDEXING_PRESSURE("indexing_pressure");
182182

183183
private String metricName;
184184

server/src/main/java/org/elasticsearch/action/admin/indices/stats/IndicesStatsResponse.java

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
package org.elasticsearch.action.admin.indices.stats;
1010

1111
import org.elasticsearch.TransportVersion;
12+
import org.elasticsearch.action.ClusterStatsLevel;
1213
import org.elasticsearch.action.admin.indices.stats.IndexStats.IndexStatsBuilder;
1314
import org.elasticsearch.action.support.DefaultShardOperationFailedException;
1415
import org.elasticsearch.action.support.broadcast.ChunkedBroadcastResponse;
@@ -178,14 +179,8 @@ public void writeTo(StreamOutput out) throws IOException {
178179

179180
@Override
180181
protected Iterator<ToXContent> customXContentChunks(ToXContent.Params params) {
181-
final String level = params.param("level", "indices");
182-
final boolean isLevelValid = "cluster".equalsIgnoreCase(level)
183-
|| "indices".equalsIgnoreCase(level)
184-
|| "shards".equalsIgnoreCase(level);
185-
if (isLevelValid == false) {
186-
throw new IllegalArgumentException("level parameter must be one of [cluster] or [indices] or [shards] but was [" + level + "]");
187-
}
188-
if ("indices".equalsIgnoreCase(level) || "shards".equalsIgnoreCase(level)) {
182+
final ClusterStatsLevel level = ClusterStatsLevel.of(params, ClusterStatsLevel.INDICES);
183+
if (level == ClusterStatsLevel.INDICES || level == ClusterStatsLevel.SHARDS) {
189184
return Iterators.concat(Iterators.single(((builder, p) -> {
190185
commonStats(builder, p);
191186
return builder.startObject(Fields.INDICES);
@@ -206,7 +201,7 @@ protected Iterator<ToXContent> customXContentChunks(ToXContent.Params params) {
206201
indexStats.getTotal().toXContent(builder, p);
207202
builder.endObject();
208203

209-
if ("shards".equalsIgnoreCase(level)) {
204+
if (level == ClusterStatsLevel.SHARDS) {
210205
builder.startObject(Fields.SHARDS);
211206
for (IndexShardStats indexShardStats : indexStats) {
212207
builder.startArray(Integer.toString(indexShardStats.getShardId().id()));

server/src/main/java/org/elasticsearch/cluster/health/ClusterIndexHealth.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
package org.elasticsearch.cluster.health;
1010

11+
import org.elasticsearch.action.ClusterStatsLevel;
1112
import org.elasticsearch.cluster.metadata.IndexMetadata;
1213
import org.elasticsearch.cluster.routing.IndexRoutingTable;
1314
import org.elasticsearch.cluster.routing.IndexShardRoutingTable;
@@ -267,7 +268,8 @@ public XContentBuilder toXContent(final XContentBuilder builder, final Params pa
267268
builder.field(INITIALIZING_SHARDS, getInitializingShards());
268269
builder.field(UNASSIGNED_SHARDS, getUnassignedShards());
269270

270-
if ("shards".equals(params.param("level", "indices"))) {
271+
ClusterStatsLevel level = ClusterStatsLevel.of(params, ClusterStatsLevel.INDICES);
272+
if (level == ClusterStatsLevel.SHARDS) {
271273
builder.startObject(SHARDS);
272274
for (ClusterShardHealth shardHealth : shards.values()) {
273275
shardHealth.toXContent(builder, params);

server/src/main/java/org/elasticsearch/indices/NodeIndicesStats.java

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
package org.elasticsearch.indices;
1010

1111
import org.elasticsearch.TransportVersion;
12+
import org.elasticsearch.action.NodeStatsLevel;
1213
import org.elasticsearch.action.admin.indices.stats.CommonStats;
1314
import org.elasticsearch.action.admin.indices.stats.IndexShardStats;
1415
import org.elasticsearch.action.admin.indices.stats.ShardStats;
@@ -216,19 +217,13 @@ public int hashCode() {
216217

217218
@Override
218219
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
219-
final String level = params.param("level", "node");
220-
final boolean isLevelValid = "indices".equalsIgnoreCase(level)
221-
|| "node".equalsIgnoreCase(level)
222-
|| "shards".equalsIgnoreCase(level);
223-
if (isLevelValid == false) {
224-
throw new IllegalArgumentException("level parameter must be one of [indices] or [node] or [shards] but was [" + level + "]");
225-
}
220+
final NodeStatsLevel level = NodeStatsLevel.of(params, NodeStatsLevel.NODE);
226221

227222
// "node" level
228223
builder.startObject(Fields.INDICES);
229224
stats.toXContent(builder, params);
230225

231-
if ("indices".equals(level)) {
226+
if (level == NodeStatsLevel.INDICES) {
232227
Map<Index, CommonStats> indexStats = createCommonStatsByIndex();
233228
builder.startObject(Fields.INDICES);
234229
for (Map.Entry<Index, CommonStats> entry : indexStats.entrySet()) {
@@ -237,8 +232,8 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
237232
builder.endObject();
238233
}
239234
builder.endObject();
240-
} else if ("shards".equals(level)) {
241-
builder.startObject("shards");
235+
} else if (level == NodeStatsLevel.SHARDS) {
236+
builder.startObject(Fields.SHARDS);
242237
for (Map.Entry<Index, List<IndexShardStats>> entry : statsByShard.entrySet()) {
243238
builder.startArray(entry.getKey().getName());
244239
for (IndexShardStats indexShardStats : entry.getValue()) {
@@ -285,5 +280,6 @@ public List<IndexShardStats> getShardStats(Index index) {
285280

286281
static final class Fields {
287282
static final String INDICES = "indices";
283+
static final String SHARDS = "shards";
288284
}
289285
}

server/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestClusterHealthAction.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
package org.elasticsearch.rest.action.admin.cluster;
1010

11+
import org.elasticsearch.action.ClusterStatsLevel;
1112
import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest;
1213
import org.elasticsearch.action.support.ActiveShardCount;
1314
import org.elasticsearch.action.support.IndicesOptions;
@@ -81,6 +82,8 @@ public static ClusterHealthRequest fromRequest(final RestRequest request) {
8182
if (request.param("wait_for_events") != null) {
8283
clusterHealthRequest.waitForEvents(Priority.valueOf(request.param("wait_for_events").toUpperCase(Locale.ROOT)));
8384
}
85+
// level parameter validation
86+
ClusterStatsLevel.of(request, ClusterStatsLevel.CLUSTER);
8487
return clusterHealthRequest;
8588
}
8689

0 commit comments

Comments
 (0)