Skip to content

Commit ca90117

Browse files
committed
Protect against NPE in RestNodesAction (#29059)
* Protect against NPE in RestNodesAction
1 parent ba1883f commit ca90117

File tree

2 files changed

+88
-9
lines changed

2 files changed

+88
-9
lines changed

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

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ protected Table getTableWithHeader(final RestRequest request) {
236236
return table;
237237
}
238238

239-
private Table buildTable(boolean fullId, RestRequest req, ClusterStateResponse state, NodesInfoResponse nodesInfo,
239+
Table buildTable(boolean fullId, RestRequest req, ClusterStateResponse state, NodesInfoResponse nodesInfo,
240240
NodesStatsResponse nodesStats) {
241241

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

283293
table.addCell(jvmStats == null ? null : jvmStats.getMem().getHeapUsed());
284294
table.addCell(jvmStats == null ? null : jvmStats.getMem().getHeapUsedPercent());
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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.rest.RestController;
32+
import org.elasticsearch.test.ESTestCase;
33+
import org.elasticsearch.test.rest.FakeRestRequest;
34+
import org.elasticsearch.usage.UsageService;
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+
UsageService usageService = new UsageService(Settings.EMPTY);
51+
action = new RestNodesAction(Settings.EMPTY,
52+
new RestController(Settings.EMPTY, Collections.emptySet(), null, null, null, usageService));
53+
}
54+
55+
public void testBuildTableDoesNotThrowGivenNullNodeInfoAndStats() {
56+
ClusterName clusterName = new ClusterName("cluster-1");
57+
DiscoveryNodes.Builder builder = DiscoveryNodes.builder();
58+
builder.add(new DiscoveryNode("node-1", buildNewFakeTransportAddress(), emptyMap(), emptySet(), Version.CURRENT));
59+
DiscoveryNodes discoveryNodes = builder.build();
60+
ClusterState clusterState = mock(ClusterState.class);
61+
when(clusterState.nodes()).thenReturn(discoveryNodes);
62+
63+
ClusterStateResponse clusterStateResponse = new ClusterStateResponse(clusterName, clusterState, randomNonNegativeLong());
64+
NodesInfoResponse nodesInfoResponse = new NodesInfoResponse(clusterName, Collections.emptyList(), Collections.emptyList());
65+
NodesStatsResponse nodesStatsResponse = new NodesStatsResponse(clusterName, Collections.emptyList(), Collections.emptyList());
66+
67+
action.buildTable(false, new FakeRestRequest(), clusterStateResponse, nodesInfoResponse, nodesStatsResponse);
68+
}
69+
}

0 commit comments

Comments
 (0)