Skip to content

Commit dadf7aa

Browse files
committed
Protect against NPE in RestNodesAction (#29059)
* Protect against NPE in RestNodesAction
1 parent 28e2924 commit dadf7aa

File tree

2 files changed

+87
-9
lines changed

2 files changed

+87
-9
lines changed

core/src/main/java/org/elasticsearch/rest/action/cat/RestNodesAction.java

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ protected Table getTableWithHeader(final RestRequest request) {
232232
return table;
233233
}
234234

235-
private Table buildTable(boolean fullId, RestRequest req, ClusterStateResponse state, NodesInfoResponse nodesInfo,
235+
Table buildTable(boolean fullId, RestRequest req, ClusterStateResponse state, NodesInfoResponse nodesInfo,
236236
NodesStatsResponse nodesStats) {
237237

238238
DiscoveryNodes nodes = state.getState().nodes();
@@ -275,14 +275,24 @@ private Table buildTable(boolean fullId, RestRequest req, ClusterStateResponse s
275275
table.addCell(node.getVersion().toString());
276276
table.addCell(info == null ? null : info.getBuild().shortHash());
277277
table.addCell(jvmInfo == null ? null : jvmInfo.version());
278-
279-
long diskTotal = fsInfo.getTotal().getTotal().getBytes();
280-
long diskUsed = diskTotal - fsInfo.getTotal().getAvailable().getBytes();
281-
double diskUsedRatio = diskTotal == 0 ? 1.0 : (double) diskUsed / diskTotal;
282-
table.addCell(fsInfo == null ? null : fsInfo.getTotal().getTotal());
283-
table.addCell(fsInfo == null ? null : new ByteSizeValue(diskUsed));
284-
table.addCell(fsInfo == null ? null : fsInfo.getTotal().getAvailable());
285-
table.addCell(fsInfo == null ? null : String.format(Locale.ROOT, "%.2f", 100.0 * diskUsedRatio));
278+
279+
280+
ByteSizeValue diskTotal = null;
281+
ByteSizeValue diskUsed = null;
282+
ByteSizeValue diskAvailable = null;
283+
String diskUsedPercent = null;
284+
if (fsInfo != null) {
285+
diskTotal = fsInfo.getTotal().getTotal();
286+
diskAvailable = fsInfo.getTotal().getAvailable();
287+
diskUsed = new ByteSizeValue(diskTotal.getBytes() - diskAvailable.getBytes());
288+
289+
double diskUsedRatio = diskTotal.getBytes() == 0 ? 1.0 : (double) diskUsed.getBytes() / diskTotal.getBytes();
290+
diskUsedPercent = String.format(Locale.ROOT, "%.2f", 100.0 * diskUsedRatio);
291+
}
292+
table.addCell(diskTotal);
293+
table.addCell(diskUsed);
294+
table.addCell(diskAvailable);
295+
table.addCell(diskUsedPercent);
286296

287297
table.addCell(jvmStats == null ? null : jvmStats.getMem().getHeapUsed());
288298
table.addCell(jvmStats == null ? null : jvmStats.getMem().getHeapUsedPercent());
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.rest.action.cat;
21+
22+
import org.elasticsearch.Version;
23+
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
24+
import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse;
25+
import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse;
26+
import org.elasticsearch.cluster.ClusterName;
27+
import org.elasticsearch.cluster.ClusterState;
28+
import org.elasticsearch.cluster.node.DiscoveryNode;
29+
import org.elasticsearch.cluster.node.DiscoveryNodes;
30+
import org.elasticsearch.common.settings.Settings;
31+
import org.elasticsearch.common.transport.LocalTransportAddress;
32+
import org.elasticsearch.rest.RestController;
33+
import org.elasticsearch.test.ESTestCase;
34+
import org.elasticsearch.test.rest.FakeRestRequest;
35+
import org.junit.Before;
36+
37+
import java.util.Collections;
38+
39+
import static java.util.Collections.emptyMap;
40+
import static java.util.Collections.emptySet;
41+
import static org.mockito.Mockito.mock;
42+
import static org.mockito.Mockito.when;
43+
44+
public class RestNodesActionTests extends ESTestCase {
45+
46+
private RestNodesAction action;
47+
48+
@Before
49+
public void setUpAction() {
50+
action = new RestNodesAction(Settings.EMPTY,
51+
new RestController(Settings.EMPTY, Collections.emptySet(), null, null, null));
52+
}
53+
54+
public void testBuildTableDoesNotThrowGivenNullNodeInfoAndStats() {
55+
ClusterName clusterName = new ClusterName("cluster-1");
56+
DiscoveryNodes.Builder builder = DiscoveryNodes.builder();
57+
builder.add(new DiscoveryNode("node-1", LocalTransportAddress.buildUnique(), emptyMap(), emptySet(), Version.CURRENT));
58+
DiscoveryNodes discoveryNodes = builder.build();
59+
ClusterState clusterState = mock(ClusterState.class);
60+
when(clusterState.nodes()).thenReturn(discoveryNodes);
61+
62+
ClusterStateResponse clusterStateResponse = new ClusterStateResponse(clusterName, clusterState);
63+
NodesInfoResponse nodesInfoResponse = new NodesInfoResponse(clusterName, Collections.emptyList(), Collections.emptyList());
64+
NodesStatsResponse nodesStatsResponse = new NodesStatsResponse(clusterName, Collections.emptyList(), Collections.emptyList());
65+
66+
action.buildTable(false, new FakeRestRequest(), clusterStateResponse, nodesInfoResponse, nodesStatsResponse);
67+
}
68+
}

0 commit comments

Comments
 (0)