From 9c4a5bbe7ed2c423df8eb561ccc876b63a981bcb Mon Sep 17 00:00:00 2001 From: javanna Date: Fri, 4 Mar 2016 14:15:49 +0100 Subject: [PATCH] adapt cluster stats api to node.client setting removal The cluster stats api now returns counts for each node role. The `master_data`, `master_only`, `data_only` and `client` fields have been removed from the response in favour of `master`, `data`, `ingest` and `coordinating_only`. The same node can have multiple roles, hence contribute to multiple roles counts. Every node is implicitly a coordinating node, so whenever a node has no explicit roles, it will be counted as coordinating only. --- .../cluster/stats/ClusterStatsNodes.java | 74 ++++++++----------- .../cluster/stats/RestClusterStatsAction.java | 3 +- .../admin/cluster/stats/ClusterStatsIT.java | 66 ++++++++++++----- docs/reference/cluster/stats.asciidoc | 8 +- .../test/cluster.stats/10_basic.yaml | 26 +++++++ 5 files changed, 107 insertions(+), 70 deletions(-) create mode 100644 rest-api-spec/src/main/resources/rest-api-spec/test/cluster.stats/10_basic.yaml diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/stats/ClusterStatsNodes.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/stats/ClusterStatsNodes.java index 5604616ed39..5f9f824b81e 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/cluster/stats/ClusterStatsNodes.java +++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/stats/ClusterStatsNodes.java @@ -41,7 +41,9 @@ import org.elasticsearch.plugins.PluginInfo; import java.io.IOException; import java.net.InetAddress; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; public class ClusterStatsNodes implements ToXContent, Streamable { @@ -213,25 +215,29 @@ public class ClusterStatsNodes implements ToXContent, Streamable { } public static class Counts implements Streamable, ToXContent { - int total; - int masterOnly; - int dataOnly; - int masterData; - int client; + static final String COORDINATING_ONLY = "coordinating_only"; + + private int total; + private Map roles; + + Counts() { + roles = new HashMap<>(); + for (DiscoveryNode.Role role : DiscoveryNode.Role.values()) { + roles.put(role.getRoleName(), 0); + } + roles.put(COORDINATING_ONLY, 0); + } public void addNodeInfo(NodeInfo nodeInfo) { total++; - DiscoveryNode node = nodeInfo.getNode(); - if (node.masterNode()) { - if (node.dataNode()) { - masterData++; - } else { - masterOnly++; + if (nodeInfo.getNode().getRoles().size() == 0) { + Integer count = roles.get(COORDINATING_ONLY); + roles.put(COORDINATING_ONLY, ++count); + } else { + for (DiscoveryNode.Role role : nodeInfo.getNode().getRoles()) { + Integer count = roles.get(role.getRoleName()); + roles.put(role.getRoleName(), ++count); } - } else if (node.dataNode()) { - dataOnly++; - } else if (node.clientNode()) { - client++; } } @@ -239,20 +245,8 @@ public class ClusterStatsNodes implements ToXContent, Streamable { return total; } - public int getMasterOnly() { - return masterOnly; - } - - public int getDataOnly() { - return dataOnly; - } - - public int getMasterData() { - return masterData; - } - - public int getClient() { - return client; + public Map getRoles() { + return roles; } public static Counts readCounts(StreamInput in) throws IOException { @@ -262,38 +256,28 @@ public class ClusterStatsNodes implements ToXContent, Streamable { } @Override + @SuppressWarnings("unchecked") public void readFrom(StreamInput in) throws IOException { total = in.readVInt(); - masterOnly = in.readVInt(); - dataOnly = in.readVInt(); - masterData = in.readVInt(); - client = in.readVInt(); + roles = (Map)in.readGenericValue(); } @Override public void writeTo(StreamOutput out) throws IOException { out.writeVInt(total); - out.writeVInt(masterOnly); - out.writeVInt(dataOnly); - out.writeVInt(masterData); - out.writeVInt(client); + out.writeGenericValue(roles); } static final class Fields { static final XContentBuilderString TOTAL = new XContentBuilderString("total"); - static final XContentBuilderString MASTER_ONLY = new XContentBuilderString("master_only"); - static final XContentBuilderString DATA_ONLY = new XContentBuilderString("data_only"); - static final XContentBuilderString MASTER_DATA = new XContentBuilderString("master_data"); - static final XContentBuilderString CLIENT = new XContentBuilderString("client"); } @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.field(Fields.TOTAL, total); - builder.field(Fields.MASTER_ONLY, masterOnly); - builder.field(Fields.DATA_ONLY, dataOnly); - builder.field(Fields.MASTER_DATA, masterData); - builder.field(Fields.CLIENT, client); + for (Map.Entry entry : roles.entrySet()) { + builder.field(entry.getKey(), entry.getValue()); + } return builder; } } diff --git a/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/stats/RestClusterStatsAction.java b/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/stats/RestClusterStatsAction.java index a09820e71b6..a02dcfccb98 100644 --- a/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/stats/RestClusterStatsAction.java +++ b/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/stats/RestClusterStatsAction.java @@ -20,7 +20,6 @@ package org.elasticsearch.rest.action.admin.cluster.stats; import org.elasticsearch.action.admin.cluster.stats.ClusterStatsRequest; -import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse; import org.elasticsearch.client.Client; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; @@ -47,6 +46,6 @@ public class RestClusterStatsAction extends BaseRestHandler { public void handleRequest(final RestRequest request, final RestChannel channel, final Client client) { ClusterStatsRequest clusterStatsRequest = new ClusterStatsRequest().nodesIds(request.paramAsStringArray("nodeId", null)); clusterStatsRequest.timeout(request.param("timeout")); - client.admin().cluster().clusterStats(clusterStatsRequest, new RestToXContentListener(channel)); + client.admin().cluster().clusterStats(clusterStatsRequest, new RestToXContentListener<>(channel)); } } diff --git a/core/src/test/java/org/elasticsearch/action/admin/cluster/stats/ClusterStatsIT.java b/core/src/test/java/org/elasticsearch/action/admin/cluster/stats/ClusterStatsIT.java index 20e66361ab7..b0db0c97226 100644 --- a/core/src/test/java/org/elasticsearch/action/admin/cluster/stats/ClusterStatsIT.java +++ b/core/src/test/java/org/elasticsearch/action/admin/cluster/stats/ClusterStatsIT.java @@ -23,6 +23,7 @@ import org.elasticsearch.Version; import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; import org.elasticsearch.client.Requests; import org.elasticsearch.cluster.health.ClusterHealthStatus; +import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.common.Priority; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.EsExecutors; @@ -34,6 +35,8 @@ import org.elasticsearch.test.ESIntegTestCase.Scope; import org.hamcrest.Matchers; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; import static org.elasticsearch.common.settings.Settings.settingsBuilder; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; @@ -43,12 +46,9 @@ import static org.hamcrest.Matchers.is; @ClusterScope(scope = Scope.SUITE, numDataNodes = 1, numClientNodes = 0) public class ClusterStatsIT extends ESIntegTestCase { - private void assertCounts(ClusterStatsNodes.Counts counts, int total, int masterOnly, int dataOnly, int masterData, int client) { - assertThat(counts.getTotal(), Matchers.equalTo(total)); - assertThat(counts.getMasterOnly(), Matchers.equalTo(masterOnly)); - assertThat(counts.getDataOnly(), Matchers.equalTo(dataOnly)); - assertThat(counts.getMasterData(), Matchers.equalTo(masterData)); - assertThat(counts.getClient(), Matchers.equalTo(client)); + private void assertCounts(ClusterStatsNodes.Counts counts, int total, Map roles) { + assertThat(counts.getTotal(), equalTo(total)); + assertThat(counts.getRoles(), equalTo(roles)); } private void waitForNodes(int numNodes) { @@ -58,25 +58,53 @@ public class ClusterStatsIT extends ESIntegTestCase { } public void testNodeCounts() { + int total = 1; + Map expectedCounts = new HashMap<>(); + expectedCounts.put(DiscoveryNode.Role.DATA.getRoleName(), 1); + expectedCounts.put(DiscoveryNode.Role.MASTER.getRoleName(), 1); + expectedCounts.put(DiscoveryNode.Role.INGEST.getRoleName(), 1); + expectedCounts.put(ClusterStatsNodes.Counts.COORDINATING_ONLY, 0); + int numNodes = randomIntBetween(1, 5); ClusterStatsResponse response = client().admin().cluster().prepareClusterStats().get(); - assertCounts(response.getNodesStats().getCounts(), 1, 0, 0, 1, 0); + assertCounts(response.getNodesStats().getCounts(), total, expectedCounts); - internalCluster().startNode(Settings.builder().put(Node.NODE_DATA_SETTING.getKey(), false)); - waitForNodes(2); - response = client().admin().cluster().prepareClusterStats().get(); - assertCounts(response.getNodesStats().getCounts(), 2, 1, 0, 1, 0); + for (int i = 0; i < numNodes; i++) { + boolean isDataNode = randomBoolean(); + boolean isMasterNode = randomBoolean(); + boolean isIngestNode = randomBoolean(); + Settings settings = Settings.builder().put(Node.NODE_DATA_SETTING.getKey(), isDataNode) + .put(Node.NODE_MASTER_SETTING.getKey(), isMasterNode).put(Node.NODE_INGEST_SETTING.getKey(), isIngestNode) + .build(); + internalCluster().startNode(settings); + total++; + waitForNodes(total); - internalCluster().startNode(Settings.builder().put(Node.NODE_MASTER_SETTING.getKey(), false)); - waitForNodes(3); - response = client().admin().cluster().prepareClusterStats().get(); - assertCounts(response.getNodesStats().getCounts(), 3, 1, 1, 1, 0); + if (isDataNode) { + incrementCountForRole(DiscoveryNode.Role.DATA.getRoleName(), expectedCounts); + } + if (isMasterNode) { + incrementCountForRole(DiscoveryNode.Role.MASTER.getRoleName(), expectedCounts); + } + if (isIngestNode) { + incrementCountForRole(DiscoveryNode.Role.INGEST.getRoleName(), expectedCounts); + } + if (!isDataNode && !isMasterNode && !isIngestNode) { + incrementCountForRole(ClusterStatsNodes.Counts.COORDINATING_ONLY, expectedCounts); + } - internalCluster().startNode(Settings.builder().put(Node.NODE_CLIENT_SETTING.getKey(), true)); - waitForNodes(4); - response = client().admin().cluster().prepareClusterStats().get(); - assertCounts(response.getNodesStats().getCounts(), 4, 1, 1, 1, 1); + response = client().admin().cluster().prepareClusterStats().get(); + assertCounts(response.getNodesStats().getCounts(), total, expectedCounts); + } } + private static void incrementCountForRole(String role, Map counts) { + Integer count = counts.get(role); + if (count == null) { + counts.put(role, 1); + } else { + counts.put(role, ++count); + } + } private void assertShardStats(ClusterStatsIndices.ShardStats stats, int indices, int total, int primaries, double replicationFactor) { assertThat(stats.getIndices(), Matchers.equalTo(indices)); diff --git a/docs/reference/cluster/stats.asciidoc b/docs/reference/cluster/stats.asciidoc index 3f36ad6df25..b45dcbfd2c1 100644 --- a/docs/reference/cluster/stats.asciidoc +++ b/docs/reference/cluster/stats.asciidoc @@ -92,10 +92,10 @@ Will return, for example: "nodes": { "count": { "total": 2, - "master_only": 0, - "data_only": 0, - "master_data": 2, - "client": 0 + "master": 2, + "data": 2, + "ingest": 2, + "coordinating_only": 0 }, "versions": [ "{version}" diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/cluster.stats/10_basic.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/cluster.stats/10_basic.yaml new file mode 100644 index 00000000000..7124c082a97 --- /dev/null +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/cluster.stats/10_basic.yaml @@ -0,0 +1,26 @@ +--- +"cluster stats test": + - do: + cluster.stats: {} + + - is_true: timestamp + - is_true: cluster_name + - match: {status: green} + - gte: { indices.count: 0} + - is_true: indices.docs + - is_true: indices.store + - is_true: indices.fielddata + - is_true: indices.query_cache + - is_true: indices.completion + - is_true: indices.segments + - is_true: indices.percolate + - gte: { nodes.count.total: 1} + - gte: { nodes.count.master: 1} + - gte: { nodes.count.data: 1} + - gte: { nodes.count.ingest: 0} + - gte: { nodes.count.coordinating_only: 0} + - is_true: nodes.os + - is_true: nodes.process + - is_true: nodes.jvm + - is_true: nodes.fs + - is_true: nodes.plugins