From 88765050e4234cc907885afc19fa3964334a284c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Fri, 13 Apr 2018 15:54:33 +0200 Subject: [PATCH 01/47] SOLR-8207: First mock version of the new nodes tab --- solr/webapp/web/css/angular/cloud.css | 39 +++++++ solr/webapp/web/index.html | 5 +- .../web/js/angular/controllers/cloud.js | 101 +++++++++++++++++- solr/webapp/web/js/angular/services.js | 6 ++ solr/webapp/web/partials/cloud.html | 48 +++++++++ 5 files changed, 193 insertions(+), 6 deletions(-) diff --git a/solr/webapp/web/css/angular/cloud.css b/solr/webapp/web/css/angular/cloud.css index d90df8d09522..f7a5491c3d4b 100644 --- a/solr/webapp/web/css/angular/cloud.css +++ b/solr/webapp/web/css/angular/cloud.css @@ -434,3 +434,42 @@ limitations under the License. { stroke: #e9e9e9; } + +/* Nodes tab */ +#nodes-table { + border-collapse: collapse; +} + +#nodes-table td, #nodes-table th { + border: 1px solid #ddd; + padding: 8px; +} +#nodes-table th { + font-weight: bolder; + font-stretch: extra-expanded; +} +#content #cloud #nodes-content #nodes-table +{ + border-top: 1px solid #c0c0c0; + margin-top: 10px; + padding-top: 10px; +} + +#content #cloud #nodes-content .node-name a +{ + font-weight: bold; + font-size: larger; +} +#content #cloud #nodes-content .node-spec +{ + font-style: italic; +} +#content #cloud #nodes-content .node-uptime, +#content #cloud #nodes-content .node-load, +#content #cloud #nodes-content .node-cpu, +#content #cloud #nodes-content .node-ram, +#content #cloud #nodes-content .node-disk +{ + font-weight: bolder; + font-size: 25px; +} diff --git a/solr/webapp/web/index.html b/solr/webapp/web/index.html index 0f9ff84d0a5b..68afb44ab8c4 100644 --- a/solr/webapp/web/index.html +++ b/solr/webapp/web/index.html @@ -145,10 +145,11 @@

Connection recovered...

-
  • Cloud

    +
  • Cluster

    diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index 80e7d03da4a2..6342d68d6171 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -16,7 +16,7 @@ */ solrAdminApp.controller('CloudController', - function($scope, $location, Zookeeper, Constants) { + function($scope, $location, Zookeeper, Constants, Nodes, Collections) { $scope.showDebug = false; @@ -26,9 +26,9 @@ solrAdminApp.controller('CloudController', $scope.closeDebug = function() { $scope.showDebug = false; - } + }; - var view = $location.search().view ? $location.search().view : "graph"; + var view = $location.search().view ? $location.search().view : "nodes"; if (view == "tree") { $scope.resetMenu("cloud-tree", Constants.IS_ROOT_PAGE); treeSubController($scope, Zookeeper); @@ -38,10 +38,103 @@ solrAdminApp.controller('CloudController', } else if (view == "graph") { $scope.resetMenu("cloud-graph", Constants.IS_ROOT_PAGE); graphSubController($scope, Zookeeper, false); + } else if (view == "nodes") { + $scope.resetMenu("cloud-nodes", Constants.IS_ROOT_PAGE); + nodesSubController($scope, Zookeeper, Nodes, Collections); } } ); +function getOrCreateObj(name, object) { + if (name in object) { + entry = object[name]; + } else { + entry = {}; + object[name] = entry; + } + return entry; +} + +function getOrCreateList(name, object) { + if (name in object) { + entry = object[name]; + } else { + entry = []; + object[name] = entry; + } + return entry; +} + +function ensureInList(string, list) { + if (list.indexOf(string) === -1) { + list.push(string); + } +} + +var nodesSubController = function($scope, Zookeeper, Nodes, Collections) { + $scope.showNodes = true; + $scope.showTree = false; + $scope.showGraph = false; + $scope.showData = false; + + // Collections.status({}, function(data) { + // console.log("Clusterstatus: " + JSON.stringify(data, undefined, 2)); + // }); + + Collections.status(function (data) { + var nodes = {}; + var hosts = {}; + + for (var name in data.cluster.collections) { + var collection = data.cluster.collections[name]; + collection.name = name; + var shards = collection.shards; + collection.shards = []; + for (var shardName in shards) { + var shard = shards[shardName]; + shard.name = shardName; + shard.collection = collection.name; + var replicas = shard.replicas; + shard.replicas = []; + for (var replicaName in replicas) { + var core = replicas[replicaName]; + core.name = replicaName; + core.collection = collection.name; + core.shard = shard.name; + core.shard_state = shard.state; + + var node_name = core['node_name']; + var node = getOrCreateObj(node_name, nodes); + var cores = getOrCreateList("cores", node); + cores.push(core); + node['base_url'] = core.base_url; + var collections = getOrCreateList("collections", node); + ensureInList(core.collection, collections); + var host_name = node_name.split(":")[0]; + var host = getOrCreateObj(host_name, hosts); + var host_nodes = getOrCreateList("nodes", host); + ensureInList(node_name, host_nodes); + } + } + } + + console.log("Nodes:\n" + JSON.stringify(nodes, undefined, 2)); + // console.log("Hosts:\n" + JSON.stringify(hosts, undefined, 2)); + + $scope.live_nodes = data.cluster.live_nodes; + all_nodes = []; + for (n in data.cluster.live_nodes) { + if (!(data.cluster.live_nodes[n] in nodes)) { + nodes[data.cluster.live_nodes[n]] = {}; + } + } + $scope.nodes = nodes; + $scope.hosts = hosts; + + }); + +}; + var treeSubController = function($scope, Zookeeper) { $scope.showTree = true; $scope.showGraph = false; @@ -114,7 +207,7 @@ var graphSubController = function ($scope, Zookeeper, isRadial) { live_nodes[data.tree[0].children[c].data.title] = true; } - var params = {view: "graph"}; + var params = {view: "nodes"}; if ($scope.rows) { params.start = $scope.pos; params.rows = $scope.rows; diff --git a/solr/webapp/web/js/angular/services.js b/solr/webapp/web/js/angular/services.js index 4d89347a39c4..81de0dcdc9cb 100644 --- a/solr/webapp/web/js/angular/services.js +++ b/solr/webapp/web/js/angular/services.js @@ -59,6 +59,12 @@ solrAdminServices.factory('System', "setLevel": {} }); }]) +.factory('Nodes', + ['$resource', function($resource) { + return $resource('/api/cluster/nodes', {'wt':'json', '_':Date.now()}, { + "list": {} + }); + }]) .factory('Zookeeper', ['$resource', function($resource) { return $resource('admin/zookeeper', {wt:'json', _:Date.now()}, { diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index ea1c6a0d670f..c8f837d6b0cf 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -48,6 +48,54 @@ +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NodeUptimeLoadCPUHeapDiskCollectionsCores
    NANANANANANANANA
    + +
    Ubuntu 8cpu 64Gb Uptime: 3d
    +
    5h
    1.3
    12%
    +
    60%
    +
    30%
    +
    + {{ c }} +
    +
    +
    + {{ core.core }} ({{core.leader ? "leader" : "replica"}}) +
    +
    +
    +
    From a2aabdf64e68f54f2ddcfd80a53160025740a2d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Wed, 18 Apr 2018 10:40:00 +0200 Subject: [PATCH 02/47] Proxy request to node WIP --- .../solr/handler/admin/SystemInfoHandler.java | 66 ++++++++++++++++++- .../web/js/angular/controllers/cloud.js | 50 +++++++++----- solr/webapp/web/js/angular/services.js | 17 ++++- solr/webapp/web/partials/cloud.html | 2 +- 4 files changed, 114 insertions(+), 21 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java index 8a2786c8d10b..bf3e3bba0076 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java @@ -25,6 +25,7 @@ import java.lang.management.OperatingSystemMXBean; import java.lang.management.RuntimeMXBean; import java.net.InetAddress; +import java.net.URL; import java.nio.charset.Charset; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; @@ -32,11 +33,21 @@ import java.util.LinkedList; import java.util.List; import java.util.Locale; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import com.codahale.metrics.Gauge; import org.apache.commons.io.IOUtils; import org.apache.lucene.LucenePackage; import org.apache.lucene.util.Constants; +import org.apache.solr.client.solrj.SolrRequest; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.impl.HttpSolrClient; +import org.apache.solr.client.solrj.request.GenericSolrRequest; +import org.apache.solr.common.SolrException; +import org.apache.solr.common.params.ModifiableSolrParams; +import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.core.CoreContainer; import org.apache.solr.core.SolrCore; @@ -61,13 +72,14 @@ public class SystemInfoHandler extends RequestHandlerBase { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + private static final String PARAM_NODE = "node"; public static String REDACT_STRING = RedactionUtils.getRedactString(); /** *

    * Undocumented expert level system property to prevent doing a reverse lookup of our hostname. - * This property ill be logged as a suggested workaround if any probems are noticed when doing reverse + * This property will be logged as a suggested workaround if any problems are noticed when doing reverse * lookup. *

    * @@ -130,6 +142,10 @@ private void initHostname() { @Override public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { + rsp.setHttpCaching(false); + if (proxyRequestToNode(req, rsp)) { + return; // Request was proxied to other node + } SolrCore core = req.getCore(); if (core != null) rsp.add( "core", getCoreInfo( core, req.getSchema() ) ); boolean solrCloudMode = getCoreContainer(req, core).isZooKeeperAware(); @@ -142,7 +158,53 @@ public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throw rsp.add( "lucene", getLuceneInfo() ); rsp.add( "jvm", getJvmInfo() ); rsp.add( "system", getSystemInfo() ); - rsp.setHttpCaching(false); + if (solrCloudMode) { + rsp.add("node", getCoreContainer(req, core).getZkController().getNodeName()); + } + } + + // Proxy this request to a different remote node if 'node' parameter is provided + private boolean proxyRequestToNode(SolrQueryRequest req, SolrQueryResponse rsp) + throws IOException, SolrServerException, InterruptedException, TimeoutException, ExecutionException { + String nodeName = req.getParams().get(PARAM_NODE); + + if (nodeName == null || nodeName.isEmpty()) { + return false; // local request + } + + SolrCore core = req.getCore(); + CoreContainer container = getCoreContainer(req, core); + boolean solrCloudMode = container.isZooKeeperAware(); + + log.debug("node parameter {} specified on sysetm info request"); + if (!solrCloudMode) { + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Parameter 'node' only supported in Cloud mode"); + } + if (!nodeName.matches("^[^/:]+:\\d+_[\\w/]+$")) { + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Parameter 'node' has wrong format"); + } + + if (nodeName.equals(container.getZkController().getNodeName())) { + log.debug("Node parameter equals local node, not proxying"); + return false; + } + + if (!container.getZkController().zkStateReader.getClusterState().getLiveNodes().contains(nodeName)){ + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Requested node not part of cluster"); + } + + log.debug("Proxying /api/node/system request to node {}", nodeName); + URL url = new URL(container.getZkController().zkStateReader.getBaseUrlForNodeName(nodeName)); + String baseUrl = url.getProtocol() + "://" + url.getHost() + ":" + url.getPort(); + log.debug("baseURL = {}", baseUrl); + try (HttpSolrClient solr = new HttpSolrClient.Builder(baseUrl).build()) { + SolrRequest proxyReq = new GenericSolrRequest(SolrRequest.METHOD.GET, "/api/node/system", new ModifiableSolrParams()); + HttpSolrClient.HttpUriRequestResponse proxyResp = solr.httpUriRequest(proxyReq); + NamedList actualResponse = proxyResp.future.get(20, TimeUnit.SECONDS); + rsp.setAllValues(actualResponse); + log.info("Proxied /api/node/system request to node {}", nodeName); + } + return true; } private CoreContainer getCoreContainer(SolrQueryRequest req, SolrCore core) { diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index 6342d68d6171..0d9d5738b2fc 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -16,7 +16,7 @@ */ solrAdminApp.controller('CloudController', - function($scope, $location, Zookeeper, Constants, Nodes, Collections) { + function($scope, $location, Zookeeper, Constants, Nodes, Collections, SystemRemote) { $scope.showDebug = false; @@ -40,7 +40,7 @@ solrAdminApp.controller('CloudController', graphSubController($scope, Zookeeper, false); } else if (view == "nodes") { $scope.resetMenu("cloud-nodes", Constants.IS_ROOT_PAGE); - nodesSubController($scope, Zookeeper, Nodes, Collections); + nodesSubController($scope, Zookeeper, Nodes, Collections, SystemRemote); } } ); @@ -71,20 +71,21 @@ function ensureInList(string, list) { } } -var nodesSubController = function($scope, Zookeeper, Nodes, Collections) { +var nodesSubController = function($scope, Zookeeper, Nodes, Collections, SystemRemote) { $scope.showNodes = true; $scope.showTree = false; $scope.showGraph = false; $scope.showData = false; - - // Collections.status({}, function(data) { - // console.log("Clusterstatus: " + JSON.stringify(data, undefined, 2)); - // }); - + Collections.status(function (data) { var nodes = {}; var hosts = {}; - + var live_nodes = []; + $scope.nodes = nodes; + $scope.hosts = hosts; + $scope.live_nodes = live_nodes; + + // Fetch cluster state from collections API and invert to a nodes structure for (var name in data.cluster.collections) { var collection = data.cluster.collections[name]; collection.name = name; @@ -118,21 +119,36 @@ var nodesSubController = function($scope, Zookeeper, Nodes, Collections) { } } - console.log("Nodes:\n" + JSON.stringify(nodes, undefined, 2)); - // console.log("Hosts:\n" + JSON.stringify(hosts, undefined, 2)); - - $scope.live_nodes = data.cluster.live_nodes; - all_nodes = []; + live_nodes = data.cluster.live_nodes; for (n in data.cluster.live_nodes) { if (!(data.cluster.live_nodes[n] in nodes)) { nodes[data.cluster.live_nodes[n]] = {}; } } - $scope.nodes = nodes; - $scope.hosts = hosts; + for (var n in live_nodes) { + var nodeName = live_nodes[n]; + var $data; + + // SystemRemote.info(nodeName, function(result) { + // console.log("Inner result: " + JSON.stringify(result, undefined, 2)); + // $scope.nodes[nodeName]['info'] = result; + // $scope.nodes[nodeName]['solr_version'] = result.lucene.solr-spec-version; + // $scope.nodes[nodeName]['java_version'] = result.jvm.jre.version; + // }); + + console.log("Getting results for node " + nodeName); + var result = SystemRemote.info(nodeName); + + console.log("Result: " + JSON.stringify(result, undefined, 2)); + // $scope.nodes[nodeName]['info'] = result; + // $scope.nodes[nodeName]['solr_version'] = result.lucene.solr-spec-version; + // $scope.nodes[nodeName]['java_version'] = result.jvm.jre.version; + } + + console.log("Nodes=" + JSON.stringify(nodes, undefined, 2)); + console.log("Livenodes=" + JSON.stringify(live_nodes, undefined, 2)); }); - }; var treeSubController = function($scope, Zookeeper) { diff --git a/solr/webapp/web/js/angular/services.js b/solr/webapp/web/js/angular/services.js index 81de0dcdc9cb..5765685aebd0 100644 --- a/solr/webapp/web/js/angular/services.js +++ b/solr/webapp/web/js/angular/services.js @@ -21,6 +21,13 @@ solrAdminServices.factory('System', ['$resource', function($resource) { return $resource('admin/info/system', {"wt":"json", "_":Date.now()}); }]) +.factory('SystemRemote', function($resource) { + return { + info: function (nodeName) { + return $resource('admin/info/system', {"wt": "json", "node": nodeName, "_": Date.now()}); + } + } +}) .factory('Collections', ['$resource', function($resource) { return $resource('admin/collections', @@ -259,4 +266,12 @@ solrAdminServices.factory('System', return $resource(':core/config', {wt: 'json', core: '@core', _:Date.now()}, { get: {method: "GET"} }) -}]); +}]) +.factory('RemoteGet', function($http, myUrl) { + var getData = function() { + return $http({method:"GET", url: myUrl}).then(function(result){ + return result.data; + }); + }; + return { getData: getData }; +}); diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index c8f837d6b0cf..c587a0942f31 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -89,7 +89,7 @@
    - {{ core.core }} ({{core.leader ? "leader" : "replica"}}) + {{ core.core }} {{core.leader ? "(leader)" : ""}}
    From 256ae42c14d5128248a63e71112b7825c7ba92ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Sat, 21 Apr 2018 01:55:54 +0200 Subject: [PATCH 03/47] Proxying system info call to all live nodes and fill some data in table --- .../solr/handler/admin/SystemInfoHandler.java | 54 +++++++++++++++---- .../web/js/angular/controllers/cloud.js | 46 +++++++--------- solr/webapp/web/js/angular/services.js | 28 ++++------ solr/webapp/web/partials/cloud.html | 18 ++++--- 4 files changed, 85 insertions(+), 61 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java index bf3e3bba0076..aada86ce5726 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java @@ -30,10 +30,14 @@ import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Date; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; +import java.util.Map; +import java.util.Set; import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -41,6 +45,7 @@ import org.apache.commons.io.IOUtils; import org.apache.lucene.LucenePackage; import org.apache.lucene.util.Constants; +import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrRequest; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.impl.HttpSolrClient; @@ -48,6 +53,7 @@ import org.apache.solr.common.SolrException; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.util.NamedList; +import org.apache.solr.common.util.Pair; import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.core.CoreContainer; import org.apache.solr.core.SolrCore; @@ -180,6 +186,29 @@ private boolean proxyRequestToNode(SolrQueryRequest req, SolrQueryResponse rsp) if (!solrCloudMode) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Parameter 'node' only supported in Cloud mode"); } + if (nodeName.equals("all")) { + log.debug("Requesting info from all live nodes"); + Set liveNodes = container.getZkController().zkStateReader.getClusterState().getLiveNodes(); + Map>, SolrClient>> responses = new HashMap<>(); + for (String node : liveNodes) { + responses.put(node, getRemoteSystemInfo(node, container)); + } + + for (Map.Entry>, SolrClient>> entry : responses.entrySet()) { + try { + NamedList resp = entry.getValue().first().get(10, TimeUnit.SECONDS); + entry.getValue().second().close(); + rsp.add(entry.getKey(), resp); + } catch (ExecutionException ee) { + log.warn("Exception when fetching result from node {}", entry.getKey(), ee); + } catch (TimeoutException te) { + log.warn("Timeout when fetching result from node {}", entry.getKey(), te); + } + } + log.info("Fetched response from {} live nodes: {}", responses.keySet().size(), responses.keySet()); + return true; + } + if (!nodeName.matches("^[^/:]+:\\d+_[\\w/]+$")) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Parameter 'node' has wrong format"); } @@ -192,19 +221,26 @@ private boolean proxyRequestToNode(SolrQueryRequest req, SolrQueryResponse rsp) if (!container.getZkController().zkStateReader.getClusterState().getLiveNodes().contains(nodeName)){ throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Requested node not part of cluster"); } - + + Pair>, SolrClient> localResponse = getRemoteSystemInfo(nodeName, container); + NamedList resp = localResponse.first().get(10, TimeUnit.SECONDS); + rsp.setAllValues(resp); + localResponse.second().close(); + log.info("Proxied /api/node/system request to node {}", nodeName); + return true; + } + + // Makes a remote request and returns a future and the solr client. The caller is responsible for closing the client + private Pair>, SolrClient> getRemoteSystemInfo(String nodeName, CoreContainer container) + throws IOException, SolrServerException { log.debug("Proxying /api/node/system request to node {}", nodeName); URL url = new URL(container.getZkController().zkStateReader.getBaseUrlForNodeName(nodeName)); String baseUrl = url.getProtocol() + "://" + url.getHost() + ":" + url.getPort(); log.debug("baseURL = {}", baseUrl); - try (HttpSolrClient solr = new HttpSolrClient.Builder(baseUrl).build()) { - SolrRequest proxyReq = new GenericSolrRequest(SolrRequest.METHOD.GET, "/api/node/system", new ModifiableSolrParams()); - HttpSolrClient.HttpUriRequestResponse proxyResp = solr.httpUriRequest(proxyReq); - NamedList actualResponse = proxyResp.future.get(20, TimeUnit.SECONDS); - rsp.setAllValues(actualResponse); - log.info("Proxied /api/node/system request to node {}", nodeName); - } - return true; + HttpSolrClient solr = new HttpSolrClient.Builder(baseUrl).build(); + SolrRequest proxyReq = new GenericSolrRequest(SolrRequest.METHOD.GET, "/api/node/system", new ModifiableSolrParams()); + HttpSolrClient.HttpUriRequestResponse proxyResp = solr.httpUriRequest(proxyReq); + return new Pair<>(proxyResp.future, solr); } private CoreContainer getCoreContainer(SolrQueryRequest req, SolrCore core) { diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index 0d9d5738b2fc..33d2999ae817 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -16,7 +16,7 @@ */ solrAdminApp.controller('CloudController', - function($scope, $location, Zookeeper, Constants, Nodes, Collections, SystemRemote) { + function($scope, $location, Zookeeper, Constants, Collections, SystemAll) { $scope.showDebug = false; @@ -40,7 +40,7 @@ solrAdminApp.controller('CloudController', graphSubController($scope, Zookeeper, false); } else if (view == "nodes") { $scope.resetMenu("cloud-nodes", Constants.IS_ROOT_PAGE); - nodesSubController($scope, Zookeeper, Nodes, Collections, SystemRemote); + nodesSubController($scope, Zookeeper, Collections, SystemAll); } } ); @@ -71,7 +71,7 @@ function ensureInList(string, list) { } } -var nodesSubController = function($scope, Zookeeper, Nodes, Collections, SystemRemote) { +var nodesSubController = function($scope, Zookeeper, Collections, SystemAll) { $scope.showNodes = true; $scope.showTree = false; $scope.showGraph = false; @@ -81,9 +81,6 @@ var nodesSubController = function($scope, Zookeeper, Nodes, Collections, SystemR var nodes = {}; var hosts = {}; var live_nodes = []; - $scope.nodes = nodes; - $scope.hosts = hosts; - $scope.live_nodes = live_nodes; // Fetch cluster state from collections API and invert to a nodes structure for (var name in data.cluster.collections) { @@ -126,28 +123,23 @@ var nodesSubController = function($scope, Zookeeper, Nodes, Collections, SystemR } } - for (var n in live_nodes) { - var nodeName = live_nodes[n]; - var $data; - - // SystemRemote.info(nodeName, function(result) { - // console.log("Inner result: " + JSON.stringify(result, undefined, 2)); - // $scope.nodes[nodeName]['info'] = result; - // $scope.nodes[nodeName]['solr_version'] = result.lucene.solr-spec-version; - // $scope.nodes[nodeName]['java_version'] = result.jvm.jre.version; - // }); - - console.log("Getting results for node " + nodeName); - var result = SystemRemote.info(nodeName); - - console.log("Result: " + JSON.stringify(result, undefined, 2)); - // $scope.nodes[nodeName]['info'] = result; - // $scope.nodes[nodeName]['solr_version'] = result.lucene.solr-spec-version; - // $scope.nodes[nodeName]['java_version'] = result.jvm.jre.version; - } + SystemAll.get(function(systemResponse) { + for (var node in systemResponse) { + console.log("Checking node " + node + " exist in " + nodes); + if (node in nodes) { + nodes[node]['system'] = systemResponse[node]; + } else { + console.log("Skipping node " + node); + } + } + }); + + $scope.nodes = nodes; + $scope.hosts = hosts; + $scope.live_nodes = live_nodes; - console.log("Nodes=" + JSON.stringify(nodes, undefined, 2)); - console.log("Livenodes=" + JSON.stringify(live_nodes, undefined, 2)); + // console.log("Nodes=" + JSON.stringify($scope.nodes, undefined, 2)); + // console.log("Livenodes=" + JSON.stringify(live_nodes, undefined, 2)); }); }; diff --git a/solr/webapp/web/js/angular/services.js b/solr/webapp/web/js/angular/services.js index 5765685aebd0..cdf1217c8b1e 100644 --- a/solr/webapp/web/js/angular/services.js +++ b/solr/webapp/web/js/angular/services.js @@ -21,12 +21,16 @@ solrAdminServices.factory('System', ['$resource', function($resource) { return $resource('admin/info/system', {"wt":"json", "_":Date.now()}); }]) +.factory('SystemAll', + ['$resource', function($resource) { + return $resource('admin/info/system', {"wt":"json", "node": "all", "_":Date.now()}); + }]) .factory('SystemRemote', function($resource) { - return { - info: function (nodeName) { - return $resource('admin/info/system', {"wt": "json", "node": nodeName, "_": Date.now()}); - } + return { + "info": function (nodeName) { + return $resource('admin/info/system', {"wt": "json", "node": nodeName, "_": Date.now()}); } + } }) .factory('Collections', ['$resource', function($resource) { @@ -66,12 +70,6 @@ solrAdminServices.factory('System', "setLevel": {} }); }]) -.factory('Nodes', - ['$resource', function($resource) { - return $resource('/api/cluster/nodes', {'wt':'json', '_':Date.now()}, { - "list": {} - }); - }]) .factory('Zookeeper', ['$resource', function($resource) { return $resource('admin/zookeeper', {wt:'json', _:Date.now()}, { @@ -266,12 +264,4 @@ solrAdminServices.factory('System', return $resource(':core/config', {wt: 'json', core: '@core', _:Date.now()}, { get: {method: "GET"} }) -}]) -.factory('RemoteGet', function($http, myUrl) { - var getData = function() { - return $http({method:"GET", url: myUrl}).then(function(result){ - return result.data; - }); - }; - return { getData: getData }; -}); +}]); diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index c587a0942f31..8ad4c975aafd 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -73,15 +73,21 @@ -
    Ubuntu 8cpu 64Gb Uptime: 3d
    +
    + {{n.system.system.name}} {{n.system.system.version}} + {{n.system.system.availableProcessors}}cpu + {{n.system.system.totalPhysicalMemorySize / 1024 / 1024 / 1024}}Gb + Java {{n.system.jvm.spec.version}} + Solr {{n.system.lucene['solr-spec-version']}} +
    -
    5h
    -
    1.3
    -
    12%
    +
    {{n.system.jvm.jmx.upTimeMS}}
    +
    {{n.system.system.systemLoadAverage}}
    +
    {{n.system.system.availableProcessors}}
    -
    60%
    +
    {{n.system.jvm.memory.used}}
    -
    30%
    +
    2G
    {{ c }} From 779af18d82e8279e72363039d9c6c0ce13833608 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Mon, 23 Apr 2018 12:32:53 +0200 Subject: [PATCH 04/47] Get back graphs --- solr/webapp/web/js/angular/controllers/cloud.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index 33d2999ae817..5308184d48d0 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -215,7 +215,7 @@ var graphSubController = function ($scope, Zookeeper, isRadial) { live_nodes[data.tree[0].children[c].data.title] = true; } - var params = {view: "nodes"}; + var params = {view: "graph"}; if ($scope.rows) { params.start = $scope.pos; params.rows = $scope.rows; From b39fe7e2554f6ddd7f373f20053416804edcf743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Mon, 23 Apr 2018 12:33:11 +0200 Subject: [PATCH 05/47] More mouseover info in table --- solr/webapp/web/partials/cloud.html | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index 8ad4c975aafd..fc681e38bed9 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -73,19 +73,20 @@ -
    - {{n.system.system.name}} {{n.system.system.version}} + + {{n.system.system.name}} {{n.system.system.version}} {{n.system.system.availableProcessors}}cpu - {{n.system.system.totalPhysicalMemorySize / 1024 / 1024 / 1024}}Gb - Java {{n.system.jvm.spec.version}} - Solr {{n.system.lucene['solr-spec-version']}} + {{n.system.system.totalPhysicalMemorySize / 1024 / 1024 / 1024}}Gb + Java {{n.system.jvm.spec.version}} + Solr {{n.system.lucene['solr-spec-version']}}
    -
    {{n.system.jvm.jmx.upTimeMS}}
    -
    {{n.system.system.systemLoadAverage}}
    -
    {{n.system.system.availableProcessors}}
    +
    {{("" + (n.system.jvm.jmx.upTimeMS / 1000 / 60)).substr(0,5)}}m
    +
    {{(n.system.system.systemLoadAverage + "").substr(0,5)}}
    +
    {{(n.system.system.processCpuLoad + "").substr(0,5)}}
    -
    {{n.system.jvm.memory.used}}
    +
    + {{(n.system.jvm.memory.raw.used * 100 / n.system.jvm.memory.raw.total + "").substr(0,4)}}%
    2G
    From 792d4b7d06fa8fde5eb35ea797fd1a72f1c1c138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Mon, 23 Apr 2018 12:39:39 +0200 Subject: [PATCH 06/47] Icon for the nodes entry --- solr/webapp/web/css/angular/menu.css | 2 +- solr/webapp/web/index.html | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/solr/webapp/web/css/angular/menu.css b/solr/webapp/web/css/angular/menu.css index 549d737f96cc..ba5e0b6a42ab 100644 --- a/solr/webapp/web/css/angular/menu.css +++ b/solr/webapp/web/css/angular/menu.css @@ -260,9 +260,9 @@ limitations under the License. #menu #cloud.global p a { background-image: url( ../../img/ico/network-cloud.png ); } #menu #cloud.global .tree a { background-image: url( ../../img/ico/folder-tree.png ); } +#menu #cloud.global .nodes a { background-image: url( ../../img/solr-ico.png ); } #menu #cloud.global .graph a { background-image: url( ../../img/ico/molecule.png ); } #menu #cloud.global .rgraph a { background-image: url( ../../img/ico/asterisk.png ); } -#menu #cloud.global .dump a { background-image: url( ../../img/ico/download-cloud.png ); } .sub-menu .ping.error a { diff --git a/solr/webapp/web/index.html b/solr/webapp/web/index.html index 68afb44ab8c4..536f3143889e 100644 --- a/solr/webapp/web/index.html +++ b/solr/webapp/web/index.html @@ -150,8 +150,6 @@

    Connection recovered...

  • Nodes
  • Tree
  • Graph
  • -
  • Graph (Radial)
  • - From ba9cf1054471b9b56aaa81a76ca73eceb2acdecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Mon, 23 Apr 2018 13:29:05 +0200 Subject: [PATCH 07/47] Refactored proxying to external nodes into separate class --- .../handler/admin/AdminHandlersProxy.java | 124 ++++++++++++++++++ .../solr/handler/admin/SystemInfoHandler.java | 95 +------------- 2 files changed, 126 insertions(+), 93 deletions(-) create mode 100644 solr/core/src/java/org/apache/solr/handler/admin/AdminHandlersProxy.java diff --git a/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlersProxy.java b/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlersProxy.java new file mode 100644 index 000000000000..3979f1de7b12 --- /dev/null +++ b/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlersProxy.java @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.solr.handler.admin; + +import java.io.IOException; +import java.lang.invoke.MethodHandles; +import java.net.URL; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.apache.solr.client.solrj.SolrClient; +import org.apache.solr.client.solrj.SolrRequest; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.impl.HttpSolrClient; +import org.apache.solr.client.solrj.request.GenericSolrRequest; +import org.apache.solr.cloud.ZkController; +import org.apache.solr.common.SolrException; +import org.apache.solr.common.params.ModifiableSolrParams; +import org.apache.solr.common.util.NamedList; +import org.apache.solr.common.util.Pair; +import org.apache.solr.core.CoreContainer; +import org.apache.solr.request.SolrQueryRequest; +import org.apache.solr.response.SolrQueryResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Static methods to proxy calls to an Admin (GET) API to other nodes in the cluster and return a combined response + */ +public class AdminHandlersProxy { + private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + private static final String PARAM_NODES = "nodes"; + + // Proxy this request to a different remote node if 'node' parameter is provided + public static boolean proxyRequestToNode(SolrQueryRequest req, SolrQueryResponse rsp, CoreContainer container) + throws IOException, SolrServerException, InterruptedException, TimeoutException, ExecutionException { + String pathStr = req.getPath(); + String nodeNames = req.getParams().get(PARAM_NODES); + Set nodes; + + if (nodeNames == null || nodeNames.isEmpty()) { + return false; // local request + } + + Set liveNodes = container.getZkController().zkStateReader.getClusterState().getLiveNodes(); + + if (nodeNames.equals("all")) { + nodes = liveNodes; + log.debug("All live nodes requested"); + } else { + nodes = new HashSet<>(Arrays.asList(nodeNames.split(","))); + for (String nodeName : nodes) { + if (!nodeName.matches("^[^/:]+:\\d+_[\\w/]+$")) { + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Parameter " + PARAM_NODES + " has wrong format"); + } + + if (!liveNodes.contains(nodeName)) { + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Requested node " + nodeName + " is not part of cluster"); + } + } + log.debug("Nodes requested: {}", nodes); + } + + boolean solrCloudMode = container.isZooKeeperAware(); + + log.debug(PARAM_NODES + " parameter {} specified on {} request", nodeNames, pathStr); + if (!solrCloudMode) { + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Parameter " + PARAM_NODES + " only supported in Cloud mode"); + } + Map>, SolrClient>> responses = new HashMap<>(); + for (String node : nodes) { + responses.put(node, callRemoteNode(node, pathStr, container.getZkController())); + } + + for (Map.Entry>, SolrClient>> entry : responses.entrySet()) { + try { + NamedList resp = entry.getValue().first().get(10, TimeUnit.SECONDS); + entry.getValue().second().close(); + rsp.add(entry.getKey(), resp); + } catch (ExecutionException ee) { + log.warn("Exception when fetching result from node {}", entry.getKey(), ee); + } catch (TimeoutException te) { + log.warn("Timeout when fetching result from node {}", entry.getKey(), te); + } + } + log.info("Fetched response from {} nodes: {}", responses.keySet().size(), responses.keySet()); + return true; + } + + /** + * Makes a remote request and returns a future and the solr client. The caller is responsible for closing the client + */ + public static Pair>, SolrClient> callRemoteNode(String nodeName, String endpoint, ZkController zkController) + throws IOException, SolrServerException { + log.debug("Proxying {} request to node {}", endpoint, nodeName); + URL baseUrl = new URL(zkController.zkStateReader.getBaseUrlForNodeName(nodeName)); + HttpSolrClient solr = new HttpSolrClient.Builder(baseUrl.toString()).build(); + SolrRequest proxyReq = new GenericSolrRequest(SolrRequest.METHOD.GET, endpoint, new ModifiableSolrParams()); + HttpSolrClient.HttpUriRequestResponse proxyResp = solr.httpUriRequest(proxyReq); + return new Pair<>(proxyResp.future, solr); + } +} diff --git a/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java index aada86ce5726..1683a3a4a4ac 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java @@ -25,35 +25,18 @@ import java.lang.management.OperatingSystemMXBean; import java.lang.management.RuntimeMXBean; import java.net.InetAddress; -import java.net.URL; import java.nio.charset.Charset; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.Date; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import com.codahale.metrics.Gauge; import org.apache.commons.io.IOUtils; import org.apache.lucene.LucenePackage; import org.apache.lucene.util.Constants; -import org.apache.solr.client.solrj.SolrClient; -import org.apache.solr.client.solrj.SolrRequest; -import org.apache.solr.client.solrj.SolrServerException; -import org.apache.solr.client.solrj.impl.HttpSolrClient; -import org.apache.solr.client.solrj.request.GenericSolrRequest; -import org.apache.solr.common.SolrException; -import org.apache.solr.common.params.ModifiableSolrParams; -import org.apache.solr.common.util.NamedList; -import org.apache.solr.common.util.Pair; import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.core.CoreContainer; import org.apache.solr.core.SolrCore; @@ -149,10 +132,10 @@ private void initHostname() { public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { rsp.setHttpCaching(false); - if (proxyRequestToNode(req, rsp)) { + SolrCore core = req.getCore(); + if (AdminHandlersProxy.proxyRequestToNode(req, rsp, getCoreContainer(req, core))) { return; // Request was proxied to other node } - SolrCore core = req.getCore(); if (core != null) rsp.add( "core", getCoreInfo( core, req.getSchema() ) ); boolean solrCloudMode = getCoreContainer(req, core).isZooKeeperAware(); rsp.add( "mode", solrCloudMode ? "solrcloud" : "std"); @@ -169,80 +152,6 @@ public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throw } } - // Proxy this request to a different remote node if 'node' parameter is provided - private boolean proxyRequestToNode(SolrQueryRequest req, SolrQueryResponse rsp) - throws IOException, SolrServerException, InterruptedException, TimeoutException, ExecutionException { - String nodeName = req.getParams().get(PARAM_NODE); - - if (nodeName == null || nodeName.isEmpty()) { - return false; // local request - } - - SolrCore core = req.getCore(); - CoreContainer container = getCoreContainer(req, core); - boolean solrCloudMode = container.isZooKeeperAware(); - - log.debug("node parameter {} specified on sysetm info request"); - if (!solrCloudMode) { - throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Parameter 'node' only supported in Cloud mode"); - } - if (nodeName.equals("all")) { - log.debug("Requesting info from all live nodes"); - Set liveNodes = container.getZkController().zkStateReader.getClusterState().getLiveNodes(); - Map>, SolrClient>> responses = new HashMap<>(); - for (String node : liveNodes) { - responses.put(node, getRemoteSystemInfo(node, container)); - } - - for (Map.Entry>, SolrClient>> entry : responses.entrySet()) { - try { - NamedList resp = entry.getValue().first().get(10, TimeUnit.SECONDS); - entry.getValue().second().close(); - rsp.add(entry.getKey(), resp); - } catch (ExecutionException ee) { - log.warn("Exception when fetching result from node {}", entry.getKey(), ee); - } catch (TimeoutException te) { - log.warn("Timeout when fetching result from node {}", entry.getKey(), te); - } - } - log.info("Fetched response from {} live nodes: {}", responses.keySet().size(), responses.keySet()); - return true; - } - - if (!nodeName.matches("^[^/:]+:\\d+_[\\w/]+$")) { - throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Parameter 'node' has wrong format"); - } - - if (nodeName.equals(container.getZkController().getNodeName())) { - log.debug("Node parameter equals local node, not proxying"); - return false; - } - - if (!container.getZkController().zkStateReader.getClusterState().getLiveNodes().contains(nodeName)){ - throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Requested node not part of cluster"); - } - - Pair>, SolrClient> localResponse = getRemoteSystemInfo(nodeName, container); - NamedList resp = localResponse.first().get(10, TimeUnit.SECONDS); - rsp.setAllValues(resp); - localResponse.second().close(); - log.info("Proxied /api/node/system request to node {}", nodeName); - return true; - } - - // Makes a remote request and returns a future and the solr client. The caller is responsible for closing the client - private Pair>, SolrClient> getRemoteSystemInfo(String nodeName, CoreContainer container) - throws IOException, SolrServerException { - log.debug("Proxying /api/node/system request to node {}", nodeName); - URL url = new URL(container.getZkController().zkStateReader.getBaseUrlForNodeName(nodeName)); - String baseUrl = url.getProtocol() + "://" + url.getHost() + ":" + url.getPort(); - log.debug("baseURL = {}", baseUrl); - HttpSolrClient solr = new HttpSolrClient.Builder(baseUrl).build(); - SolrRequest proxyReq = new GenericSolrRequest(SolrRequest.METHOD.GET, "/api/node/system", new ModifiableSolrParams()); - HttpSolrClient.HttpUriRequestResponse proxyResp = solr.httpUriRequest(proxyReq); - return new Pair<>(proxyResp.future, solr); - } - private CoreContainer getCoreContainer(SolrQueryRequest req, SolrCore core) { CoreContainer coreContainer; if (core != null) { From 26b8e5b4d06d837cf90e9ac5127dbb43ebe71dd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Mon, 23 Apr 2018 13:40:02 +0200 Subject: [PATCH 08/47] Added "nodes" support also to MetricsHandler --- .../org/apache/solr/handler/admin/AdminHandlersProxy.java | 8 ++++---- .../org/apache/solr/handler/admin/MetricsHandler.java | 4 ++++ .../org/apache/solr/handler/admin/SystemInfoHandler.java | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlersProxy.java b/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlersProxy.java index 3979f1de7b12..86a0f60299f0 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlersProxy.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlersProxy.java @@ -54,16 +54,16 @@ public class AdminHandlersProxy { private static final String PARAM_NODES = "nodes"; // Proxy this request to a different remote node if 'node' parameter is provided - public static boolean proxyRequestToNode(SolrQueryRequest req, SolrQueryResponse rsp, CoreContainer container) - throws IOException, SolrServerException, InterruptedException, TimeoutException, ExecutionException { - String pathStr = req.getPath(); + public static boolean maybeProxyToNodes(SolrQueryRequest req, SolrQueryResponse rsp, CoreContainer container) + throws IOException, SolrServerException, InterruptedException { String nodeNames = req.getParams().get(PARAM_NODES); - Set nodes; if (nodeNames == null || nodeNames.isEmpty()) { return false; // local request } + Set nodes; + String pathStr = req.getPath(); Set liveNodes = container.getZkController().zkStateReader.getClusterState().getLiveNodes(); if (nodeNames.equals("all")) { diff --git a/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java index ed1e4747e7fc..8605db83411f 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java @@ -89,6 +89,10 @@ public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throw throw new SolrException(SolrException.ErrorCode.INVALID_STATE, "Core container instance not initialized"); } + if (AdminHandlersProxy.maybeProxyToNodes(req, rsp, container)) { + return; // Request was proxied to other node + } + boolean compact = req.getParams().getBool(COMPACT_PARAM, true); String[] keys = req.getParams().getParams(KEY_PARAM); if (keys != null && keys.length > 0) { diff --git a/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java index 1683a3a4a4ac..d8e10ab32e36 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java @@ -133,7 +133,7 @@ public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throw { rsp.setHttpCaching(false); SolrCore core = req.getCore(); - if (AdminHandlersProxy.proxyRequestToNode(req, rsp, getCoreContainer(req, core))) { + if (AdminHandlersProxy.maybeProxyToNodes(req, rsp, getCoreContainer(req, core))) { return; // Request was proxied to other node } if (core != null) rsp.add( "core", getCoreInfo( core, req.getSchema() ) ); From 59965c2b5a29985fc0ac355c19c76fe3bc37448b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Mon, 23 Apr 2018 15:23:18 +0200 Subject: [PATCH 09/47] Adding disk space and request rate metrics to table Moved calculations from HTML to cloud.js --- solr/webapp/web/css/angular/cloud.css | 6 +- .../web/js/angular/controllers/cloud.js | 79 +++++++++++++++++-- solr/webapp/web/js/angular/services.js | 13 ++- solr/webapp/web/partials/cloud.html | 26 +++--- 4 files changed, 100 insertions(+), 24 deletions(-) diff --git a/solr/webapp/web/css/angular/cloud.css b/solr/webapp/web/css/angular/cloud.css index f7a5491c3d4b..7f79dcdf5f71 100644 --- a/solr/webapp/web/css/angular/cloud.css +++ b/solr/webapp/web/css/angular/cloud.css @@ -464,7 +464,11 @@ limitations under the License. { font-style: italic; } -#content #cloud #nodes-content .node-uptime, +#content #cloud #nodes-content .node-uptime +{ + font-weight: bolder; + font-size: 20px; +} #content #cloud #nodes-content .node-load, #content #cloud #nodes-content .node-cpu, #content #cloud #nodes-content .node-ram, diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index 5308184d48d0..8a4869200257 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -16,7 +16,7 @@ */ solrAdminApp.controller('CloudController', - function($scope, $location, Zookeeper, Constants, Collections, SystemAll) { + function($scope, $location, Zookeeper, Constants, Collections, SystemAll, MetricsAll) { $scope.showDebug = false; @@ -40,7 +40,7 @@ solrAdminApp.controller('CloudController', graphSubController($scope, Zookeeper, false); } else if (view == "nodes") { $scope.resetMenu("cloud-nodes", Constants.IS_ROOT_PAGE); - nodesSubController($scope, Zookeeper, Collections, SystemAll); + nodesSubController($scope, Zookeeper, Collections, SystemAll, MetricsAll); } } ); @@ -71,7 +71,7 @@ function ensureInList(string, list) { } } -var nodesSubController = function($scope, Zookeeper, Collections, SystemAll) { +var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, MetricsAll) { $scope.showNodes = true; $scope.showTree = false; $scope.showGraph = false; @@ -127,18 +127,65 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll) { for (var node in systemResponse) { console.log("Checking node " + node + " exist in " + nodes); if (node in nodes) { - nodes[node]['system'] = systemResponse[node]; + var s = systemResponse[node]; + nodes[node]['system'] = s; + var memTotal = s.system.totalPhysicalMemorySize; + var memFree = s.system.freePhysicalMemorySize; + var memPercentage = Math.floor((memTotal - memFree) / memTotal * 100); + nodes[node]['memUsedPct'] = memPercentage + "%"; + nodes[node]['memTotal'] = Math.floor(memTotal / 1024 / 1024 / 1024) + "Gb"; + nodes[node]['memFree'] = Math.floor(memFree / 1024 / 1024 / 1024) + "Gb"; + + var heapTotal = s.jvm.memory.raw.total; + var heapFree = s.jvm.memory.raw.free + var heapPercentage = Math.floor((heapTotal - heapFree) / heapTotal * 100); + nodes[node]['heapUsedPct'] = heapPercentage + "%"; + nodes[node]['heapTotal'] = Math.floor(heapTotal / 1024 / 1024 / 1024) + "Gb"; + nodes[node]['heapFree'] = Math.floor(heapFree / 1024 / 1024 / 1024) + "Gb"; + + var jvmUptime = s.jvm.jmx.upTimeMS / 1000; // Seconds + nodes[node]['jvmUptime'] = secondsForHumans(jvmUptime); + + nodes[node]['loadAvg'] = Math.round(s.system.systemLoadAverage * 100) / 100; + nodes[node]['cpuPct'] = Math.ceil(s.system.processCpuLoad) + "%"; } else { console.log("Skipping node " + node); } } }); + MetricsAll.get(function(metricsResponse) { + for (var node in metricsResponse) { + console.log("Checking node " + node + " exist in " + nodes); + if (node in nodes) { + var m = metricsResponse[node]; + nodes[node]['metrics'] = m; + var diskTotal = m.metrics['solr.node']['CONTAINER.fs.totalSpace']; + var diskFree = m.metrics['solr.node']['CONTAINER.fs.usableSpace']; + var diskPercentage = Math.floor((diskTotal - diskFree) / diskTotal * 100); + nodes[node]['diskUsedPct'] = diskPercentage + "%"; + nodes[node]['diskTotal'] = Math.floor(diskTotal / 1024 / 1024 / 1024) + "Gb"; + nodes[node]['diskFree'] = Math.floor(diskFree / 1024 / 1024 / 1024) + "Gb"; + + var r = m.metrics['solr.jetty']['org.eclipse.jetty.server.handler.DefaultHandler.get-requests']; + nodes[node]['req'] = r.count; + nodes[node]['req1minRate'] = Math.floor(r['1minRate'] * 100) / 100; + nodes[node]['req5minRate'] = Math.floor(r['5minRate'] * 100) / 100; + nodes[node]['req15minRate'] = Math.floor(r['15minRate'] * 100) / 100; + nodes[node]['reqp75_ms'] = Math.floor(r['p75_ms']); + nodes[node]['reqp95_ms'] = Math.floor(r['p95_ms']); + nodes[node]['reqp99_ms'] = Math.floor(r['p99_ms']); + } else { + console.log("Skipping node " + node); + } + } + }); + $scope.nodes = nodes; $scope.hosts = hosts; $scope.live_nodes = live_nodes; - // console.log("Nodes=" + JSON.stringify($scope.nodes, undefined, 2)); + console.log("Nodes=" + JSON.stringify($scope.nodes, undefined, 2)); // console.log("Livenodes=" + JSON.stringify(live_nodes, undefined, 2)); }); }; @@ -179,6 +226,28 @@ var treeSubController = function($scope, Zookeeper) { $scope.initTree(); }; +/** + * Translates seconds into human readable format of seconds, minutes, hours, days, and years + * + * @param {number} seconds The number of seconds to be processed + * @return {string} The phrase describing the the amount of time + */ +function secondsForHumans ( seconds ) { + var levels = [ + [Math.floor(seconds / 31536000), 'y'], + [Math.floor((seconds % 31536000) / 86400), 'd'], + [Math.floor(((seconds % 31536000) % 86400) / 3600), 'h'], + [Math.floor((((seconds % 31536000) % 86400) % 3600) / 60), 'm'] + ]; + var returntext = ''; + + for (var i = 0, max = levels.length; i < max; i++) { + if ( levels[i][0] === 0 ) continue; + returntext += ' ' + levels[i][0] + levels[i][1]; + } + return returntext.trim() === '' ? '0m' : returntext.trim(); +} + var graphSubController = function ($scope, Zookeeper, isRadial) { $scope.showTree = false; $scope.showGraph = true; diff --git a/solr/webapp/web/js/angular/services.js b/solr/webapp/web/js/angular/services.js index cdf1217c8b1e..307dd9485047 100644 --- a/solr/webapp/web/js/angular/services.js +++ b/solr/webapp/web/js/angular/services.js @@ -23,15 +23,12 @@ solrAdminServices.factory('System', }]) .factory('SystemAll', ['$resource', function($resource) { - return $resource('admin/info/system', {"wt":"json", "node": "all", "_":Date.now()}); + return $resource('admin/info/system', {"wt":"json", "nodes": "all", "_":Date.now()}); + }]) +.factory('MetricsAll', + ['$resource', function($resource) { + return $resource('admin/metrics', {"wt":"json", "nodes": "all", "_":Date.now()}); }]) -.factory('SystemRemote', function($resource) { - return { - "info": function (nodeName) { - return $resource('admin/info/system', {"wt": "json", "node": nodeName, "_": Date.now()}); - } - } -}) .factory('Collections', ['$resource', function($resource) { return $resource('admin/collections', diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index fc681e38bed9..422d1d9c0ce8 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -48,15 +48,16 @@ -
    + - + + @@ -69,6 +70,7 @@ + - - - + + + + + - + @@ -71,6 +72,7 @@ + + From 94f5dd575fd803f039ba0d94c9009ec744800a27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 3 May 2018 12:34:17 +0200 Subject: [PATCH 11/47] Details view with disk usage graphs --- solr/webapp/web/css/angular/cloud.css | 67 +++++ .../web/js/angular/controllers/cloud.js | 257 +++++++++++------- solr/webapp/web/partials/cloud.html | 47 +++- 3 files changed, 267 insertions(+), 104 deletions(-) diff --git a/solr/webapp/web/css/angular/cloud.css b/solr/webapp/web/css/angular/cloud.css index 9bd3b2210a78..734ebefba4dd 100644 --- a/solr/webapp/web/css/angular/cloud.css +++ b/solr/webapp/web/css/angular/cloud.css @@ -477,3 +477,70 @@ limitations under the License. font-weight: bolder; font-size: 25px; } + +/* Styling of reload and details buttons */ +#content #cloud #controls +{ + display: block; + height: 30px; +} + +#content #cloud .reload +{ + background-image: url( ../../img/ico/arrow-circle.png ); + padding-left: 21px; + float: left; +} + +#content #cloud .reload.loader +{ + padding-left: 0; +} + +#content #cloud .details-button +{ + background-image: url(../../img/ico/ui-check-box-uncheck.png); + background-position: 0 50%; + color: #8D8D8D; + margin-top: 7px; + margin-left: 10px; + padding-left: 21px; + width: 30px; +} + +#content #cloud .details-button.on +{ + background-image: url( ../../img/ico/ui-check-box.png ); + color: #333; +} + +#content #cloud #nodes-content .more +{ + font-style: italic; + text-underline: #0000fa; +} + +/* Disk usage details d3 chart bars style */ +.chart { + background: #eee; + padding: 1px; +} +.chart div { + width:90%; +} +.chart div div { + display:inline-block; +} +.chart div div.rect { + transition: all 0.5s ease-out; + -moz-transition: all 0.5s ease-out; + -webkit-transition: all 0.5s ease-out; + width:0; + font: 10px sans-serif; + background-color: #4CAF50; + text-align: left; + padding: 3px; + margin: 2px; + color: #000000; + box-shadow: 1px 1px 1px #666; +} diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index ac3fe5996d89..5f41b972fbb0 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -71,131 +71,198 @@ function ensureInList(string, list) { } } +// from http://scratch99.com/web-development/javascript/convert-bytes-to-mb-kb/ +function bytesToSize(bytes) { + var sizes = ['b', 'Kb', 'Mb', 'Gb', 'Tb']; + if (bytes == 0) return 'n/a'; + var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); + if (i == 0) return bytes + '' + sizes[i]; + return (bytes / Math.pow(1024, i)).toFixed(1) + '' + sizes[i]; +} + var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, MetricsAll) { $scope.showNodes = true; $scope.showTree = false; $scope.showGraph = false; $scope.showData = false; + $scope.showDetails = false; + + $scope.toggleDetails = function() { + $scope.showDetails = !$scope.showDetails; + } - Collections.status(function (data) { + $scope.reload = function() { + Collections.status(function (data) { var nodes = {}; var hosts = {}; var live_nodes = []; - + // Fetch cluster state from collections API and invert to a nodes structure for (var name in data.cluster.collections) { - var collection = data.cluster.collections[name]; - collection.name = name; - var shards = collection.shards; - collection.shards = []; - for (var shardName in shards) { - var shard = shards[shardName]; - shard.name = shardName; - shard.collection = collection.name; - var replicas = shard.replicas; - shard.replicas = []; - for (var replicaName in replicas) { - var core = replicas[replicaName]; - core.name = replicaName; - core.collection = collection.name; - core.shard = shard.name; - core.shard_state = shard.state; - - var node_name = core['node_name']; - var node = getOrCreateObj(node_name, nodes); - var cores = getOrCreateList("cores", node); - cores.push(core); - node['base_url'] = core.base_url; - var collections = getOrCreateList("collections", node); - ensureInList(core.collection, collections); - var host_name = node_name.split(":")[0]; - var host = getOrCreateObj(host_name, hosts); - var host_nodes = getOrCreateList("nodes", host); - ensureInList(node_name, host_nodes); - } + var collection = data.cluster.collections[name]; + collection.name = name; + var shards = collection.shards; + collection.shards = []; + for (var shardName in shards) { + var shard = shards[shardName]; + shard.name = shardName; + shard.collection = collection.name; + var replicas = shard.replicas; + shard.replicas = []; + for (var replicaName in replicas) { + var core = replicas[replicaName]; + core.name = replicaName; + core.collection = collection.name; + core.shard = shard.name; + core.shard_state = shard.state; + + var node_name = core['node_name']; + var node = getOrCreateObj(node_name, nodes); + var cores = getOrCreateList("cores", node); + cores.push(core); + node['base_url'] = core.base_url; + node['id'] = core.base_url.replace(/[^\w\d]/g, ''); + var collections = getOrCreateList("collections", node); + ensureInList(core.collection, collections); + var host_name = node_name.split(":")[0]; + var host = getOrCreateObj(host_name, hosts); + var host_nodes = getOrCreateList("nodes", host); + ensureInList(node_name, host_nodes); } + } } live_nodes = data.cluster.live_nodes; for (n in data.cluster.live_nodes) { - if (!(data.cluster.live_nodes[n] in nodes)) { - nodes[data.cluster.live_nodes[n]] = {}; - } + if (!(data.cluster.live_nodes[n] in nodes)) { + nodes[data.cluster.live_nodes[n]] = {}; + } } - - SystemAll.get(function(systemResponse) { + + SystemAll.get(function (systemResponse) { for (var node in systemResponse) { - console.log("Checking node " + node + " exist in " + nodes); - if (node in nodes) { - var s = systemResponse[node]; - nodes[node]['system'] = s; - var memTotal = s.system.totalPhysicalMemorySize; - var memFree = s.system.freePhysicalMemorySize; - var memPercentage = Math.floor((memTotal - memFree) / memTotal * 100); - nodes[node]['memUsedPct'] = memPercentage + "%"; - nodes[node]['memTotal'] = Math.floor(memTotal / 1024 / 1024 / 1024) + "Gb"; - nodes[node]['memFree'] = Math.floor(memFree / 1024 / 1024 / 1024) + "Gb"; - - var heapTotal = s.jvm.memory.raw.total; - var heapFree = s.jvm.memory.raw.free; - var heapPercentage = Math.floor((heapTotal - heapFree) / heapTotal * 100); - nodes[node]['heapUsedPct'] = heapPercentage + "%"; - nodes[node]['heapTotal'] = Math.floor(heapTotal / 1024 / 1024 / 1024) + "Gb"; - nodes[node]['heapFree'] = Math.floor(heapFree / 1024 / 1024 / 1024) + "Gb"; - - var jvmUptime = s.jvm.jmx.upTimeMS / 1000; // Seconds - nodes[node]['jvmUptime'] = secondsForHumans(jvmUptime); - nodes[node]['jvmUptimeSec'] = jvmUptime; - - nodes[node]['loadAvg'] = Math.round(s.system.systemLoadAverage * 100) / 100; - nodes[node]['cpuPct'] = Math.ceil(s.system.processCpuLoad) + "%"; - } else { - console.log("Skipping node " + node); - } + if (node in nodes) { + var s = systemResponse[node]; + nodes[node]['system'] = s; + var memTotal = s.system.totalPhysicalMemorySize; + var memFree = s.system.freePhysicalMemorySize; + var memPercentage = Math.floor((memTotal - memFree) / memTotal * 100); + nodes[node]['memUsedPct'] = memPercentage + "%"; + nodes[node]['memTotal'] = bytesToSize(memTotal); + nodes[node]['memFree'] = bytesToSize(memFree); + nodes[node]['memUsed'] = bytesToSize(memTotal - memFree); + + var heapTotal = s.jvm.memory.raw.total; + var heapFree = s.jvm.memory.raw.free; + var heapPercentage = Math.floor((heapTotal - heapFree) / heapTotal * 100); + nodes[node]['heapUsed'] = bytesToSize(heapTotal - heapFree); + nodes[node]['heapUsedPct'] = heapPercentage + "%"; + nodes[node]['heapTotal'] = bytesToSize(heapTotal); + nodes[node]['heapFree'] = bytesToSize(heapFree); + + var jvmUptime = s.jvm.jmx.upTimeMS / 1000; // Seconds + nodes[node]['jvmUptime'] = secondsForHumans(jvmUptime); + nodes[node]['jvmUptimeSec'] = jvmUptime; + + nodes[node]['uptime'] = s.system.uptime.replace(/.*up (.*?),.*/, "$1") + nodes[node]['loadAvg'] = Math.round(s.system.systemLoadAverage * 100) / 100; + nodes[node]['cpuPct'] = Math.ceil(s.system.processCpuLoad) + "%"; + } } }); - MetricsAll.get(function(metricsResponse) { + MetricsAll.get(function (metricsResponse) { for (var node in metricsResponse) { - console.log("Checking node " + node + " exist in " + nodes); if (node in nodes) { - var m = metricsResponse[node]; - nodes[node]['metrics'] = m; - var diskTotal = m.metrics['solr.node']['CONTAINER.fs.totalSpace']; - var diskFree = m.metrics['solr.node']['CONTAINER.fs.usableSpace']; - var diskPercentage = Math.floor((diskTotal - diskFree) / diskTotal * 100); - nodes[node]['diskUsedPct'] = diskPercentage + "%"; - nodes[node]['diskTotal'] = Math.floor(diskTotal / 1024 / 1024 / 1024) + "Gb"; - nodes[node]['diskFree'] = Math.floor(diskFree / 1024 / 1024 / 1024) + "Gb"; - - var r = m.metrics['solr.jetty']['org.eclipse.jetty.server.handler.DefaultHandler.get-requests']; - nodes[node]['req'] = r.count; - nodes[node]['req1minRate'] = Math.floor(r['1minRate'] * 100) / 100; - nodes[node]['req5minRate'] = Math.floor(r['5minRate'] * 100) / 100; - nodes[node]['req15minRate'] = Math.floor(r['15minRate'] * 100) / 100; - nodes[node]['reqp75_ms'] = Math.floor(r['p75_ms']); - nodes[node]['reqp95_ms'] = Math.floor(r['p95_ms']); - nodes[node]['reqp99_ms'] = Math.floor(r['p99_ms']); - - nodes[node]['gcMajorCount'] = m.metrics['solr.jvm']['gc.ConcurrentMarkSweep.count']; - nodes[node]['gcMajorTime'] = m.metrics['solr.jvm']['gc.ConcurrentMarkSweep.time']; - nodes[node]['gcMinorCount'] = m.metrics['solr.jvm']['gc.ParNew.count']; - nodes[node]['gcMinorTime'] = m.metrics['solr.jvm']['gc.ParNew.time']; - } else { - console.log("Skipping node " + node); + var m = metricsResponse[node]; + nodes[node]['metrics'] = m; + var diskTotal = m.metrics['solr.node']['CONTAINER.fs.totalSpace']; + var diskFree = m.metrics['solr.node']['CONTAINER.fs.usableSpace']; + var diskPercentage = Math.floor((diskTotal - diskFree) / diskTotal * 100); + nodes[node]['diskUsedPct'] = diskPercentage + "%"; + nodes[node]['diskTotal'] = bytesToSize(diskTotal); + nodes[node]['diskFree'] = bytesToSize(diskFree); + + var r = m.metrics['solr.jetty']['org.eclipse.jetty.server.handler.DefaultHandler.get-requests']; + nodes[node]['req'] = r.count; + nodes[node]['req1minRate'] = Math.floor(r['1minRate'] * 100) / 100; + nodes[node]['req5minRate'] = Math.floor(r['5minRate'] * 100) / 100; + nodes[node]['req15minRate'] = Math.floor(r['15minRate'] * 100) / 100; + nodes[node]['reqp75_ms'] = Math.floor(r['p75_ms']); + nodes[node]['reqp95_ms'] = Math.floor(r['p95_ms']); + nodes[node]['reqp99_ms'] = Math.floor(r['p99_ms']); + + nodes[node]['gcMajorCount'] = m.metrics['solr.jvm']['gc.ConcurrentMarkSweep.count']; + nodes[node]['gcMajorTime'] = m.metrics['solr.jvm']['gc.ConcurrentMarkSweep.time']; + nodes[node]['gcMinorCount'] = m.metrics['solr.jvm']['gc.ParNew.count']; + nodes[node]['gcMinorTime'] = m.metrics['solr.jvm']['gc.ParNew.time']; + + var cores = nodes[node]['cores']; + var indexSizeTotal = 0; + var graphData = []; + if (cores) { + for (coreId in cores) { + var core = cores[coreId]; + var keyName = "solr.core." + core['core'].replace('_', '.').replace('_', '.'); + var nodeMetric = m.metrics[keyName]; + var size = nodeMetric['INDEX.sizeInBytes']; + core['sizeInBytes'] = size; + core['size'] = bytesToSize(size); + core['sizeLabel'] = core['core'].replace('_shard', '_s').replace(/_replica_./, 'r'); + indexSizeTotal += size; + } + for (coreId in cores) { + var core = cores[coreId]; + var graphObj = {}; + graphObj['label'] = core['sizeLabel']; + graphObj['size'] = core['sizeInBytes']; + graphObj['sizeHuman'] = core['size']; + graphObj['pct'] = (core['sizeInBytes'] / indexSizeTotal) * 100; + graphData.push(graphObj); + } + } + cores.sort(function (a, b) { + return b.sizeInBytes - a.sizeInBytes + }); + graphData.sort(function (a, b) { + return b.size - a.size + }); + nodes[node]['graphData'] = graphData; + nodes[node]['sizeInBytes'] = indexSizeTotal; + nodes[node]['size'] = bytesToSize(indexSizeTotal); + + // Add the div containing the whole chart + $('#chart'+nodes[node]['id']).empty(); + var chart = d3.select('#chart'+nodes[node]['id']).append('div').attr('class', 'chart'); + + // Add one div per bar which will group together both labels and bars + var g = chart.selectAll('div') + .data(nodes[node]['graphData']).enter() + .append('div'); + + // Add the bars + var bars = g.append("div") + .attr("class", "rect") + .text(function (d) { return d.label + ':\u00A0\u00A0' + d.sizeHuman; }); + + // Execute the transition to show the bars + bars.transition() + .ease('elastic') + .style('width', function (d) { + return d.pct + '%'; + }); } } }); - + $scope.nodes = nodes; $scope.hosts = hosts; - $scope.live_nodes = live_nodes; + $scope.live_nodes = live_nodes; $scope.Math = window.Math; - - console.log("Nodes=" + JSON.stringify($scope.nodes, undefined, 2)); - // console.log("Livenodes=" + JSON.stringify(live_nodes, undefined, 2)); - }); + }) + }; + $scope.reload(); }; var treeSubController = function($scope, Zookeeper) { diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index d16d336aae59..b5702fd40a0f 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -49,9 +49,15 @@ +
    NodeUptimeUptime (jvm) Load CPU Heap DiskRequests Collections Cores
    NA NA NANA
    @@ -76,19 +78,23 @@ {{n.system.system.name}} {{n.system.system.version}} {{n.system.system.availableProcessors}}cpu - {{n.system.system.totalPhysicalMemorySize / 1024 / 1024 / 1024}}Gb + {{n.memTotal}} Java {{n.system.jvm.spec.version}} Solr {{n.system.lucene['solr-spec-version']}} - +
    {{("" + (n.system.jvm.jmx.upTimeMS / 1000 / 60)).substr(0,5)}}m
    {{(n.system.system.systemLoadAverage + "").substr(0,5)}}
    {{(n.system.system.processCpuLoad + "").substr(0,5)}}
    {{n.jvmUptime}}
    {{n.loadAvg}}
    {{n.cpuPct}}
    -
    - {{(n.system.jvm.memory.raw.used * 100 / n.system.jvm.memory.raw.total + "").substr(0,4)}}%
    +
    + {{n.heapUsedPct}}
    +
    + {{n.diskUsedPct}}
    + RPM: {{n.req1minRate}}
    p95: {{n.reqp95_ms}}ms
    2G
    {{ c }} From 33f4cab0e1c2fd8c6f35ac2a35073ea0ce27183d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Mon, 23 Apr 2018 16:25:50 +0200 Subject: [PATCH 10/47] Added GC to the table --- solr/webapp/web/css/angular/cloud.css | 2 +- solr/webapp/web/js/angular/controllers/cloud.js | 10 +++++++++- solr/webapp/web/partials/cloud.html | 10 +++++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/solr/webapp/web/css/angular/cloud.css b/solr/webapp/web/css/angular/cloud.css index 7f79dcdf5f71..9bd3b2210a78 100644 --- a/solr/webapp/web/css/angular/cloud.css +++ b/solr/webapp/web/css/angular/cloud.css @@ -471,7 +471,7 @@ limitations under the License. } #content #cloud #nodes-content .node-load, #content #cloud #nodes-content .node-cpu, -#content #cloud #nodes-content .node-ram, +#content #cloud #nodes-content .node-heap, #content #cloud #nodes-content .node-disk { font-weight: bolder; diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index 8a4869200257..ac3fe5996d89 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -137,7 +137,7 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met nodes[node]['memFree'] = Math.floor(memFree / 1024 / 1024 / 1024) + "Gb"; var heapTotal = s.jvm.memory.raw.total; - var heapFree = s.jvm.memory.raw.free + var heapFree = s.jvm.memory.raw.free; var heapPercentage = Math.floor((heapTotal - heapFree) / heapTotal * 100); nodes[node]['heapUsedPct'] = heapPercentage + "%"; nodes[node]['heapTotal'] = Math.floor(heapTotal / 1024 / 1024 / 1024) + "Gb"; @@ -145,6 +145,7 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met var jvmUptime = s.jvm.jmx.upTimeMS / 1000; // Seconds nodes[node]['jvmUptime'] = secondsForHumans(jvmUptime); + nodes[node]['jvmUptimeSec'] = jvmUptime; nodes[node]['loadAvg'] = Math.round(s.system.systemLoadAverage * 100) / 100; nodes[node]['cpuPct'] = Math.ceil(s.system.processCpuLoad) + "%"; @@ -175,6 +176,11 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met nodes[node]['reqp75_ms'] = Math.floor(r['p75_ms']); nodes[node]['reqp95_ms'] = Math.floor(r['p95_ms']); nodes[node]['reqp99_ms'] = Math.floor(r['p99_ms']); + + nodes[node]['gcMajorCount'] = m.metrics['solr.jvm']['gc.ConcurrentMarkSweep.count']; + nodes[node]['gcMajorTime'] = m.metrics['solr.jvm']['gc.ConcurrentMarkSweep.time']; + nodes[node]['gcMinorCount'] = m.metrics['solr.jvm']['gc.ParNew.count']; + nodes[node]['gcMinorTime'] = m.metrics['solr.jvm']['gc.ParNew.time']; } else { console.log("Skipping node " + node); } @@ -185,6 +191,8 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met $scope.hosts = hosts; $scope.live_nodes = live_nodes; + $scope.Math = window.Math; + console.log("Nodes=" + JSON.stringify($scope.nodes, undefined, 2)); // console.log("Livenodes=" + JSON.stringify(live_nodes, undefined, 2)); }); diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index 422d1d9c0ce8..d16d336aae59 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -57,6 +57,7 @@
    CPU Heap DiskGC Requests Collections CoresNA NA NANA
    @@ -87,11 +89,17 @@
    {{n.loadAvg}}
    {{n.cpuPct}}
    -
    +
    {{n.heapUsedPct}}
    {{n.diskUsedPct}}
    +
    + Major: {{Math.round(n.gcMajorCount / n.jvmUptimeSec * 60 * 5 * 100) / 100}}/5m
    + Minor: {{Math.round(n.gcMinorCount / n.jvmUptimeSec * 60 * 5 * 100) / 100}}/5m +
    +
    RPM: {{n.req1minRate}}
    p95: {{n.reqp95_ms}}ms
    - + @@ -77,23 +83,44 @@ + -
    NodeNode Uptime (jvm) Load CPU
    - - {{n.system.system.name}} {{n.system.system.version}} + + {{n.system.system.name}} {{n.system.system.availableProcessors}}cpu {{n.memTotal}} Java {{n.system.jvm.spec.version}} Solr {{n.system.lucene['solr-spec-version']}} +
    + {{n.system.system.name}} {{n.system.system.version}}, {{n.system.system.availableProcessors}}cpu
    + Uptime: {{n.uptime}}
    + RAM: {{n.memTotal}} (used: {{n.memUsed}} free: {{n.memFree}})
    + Java: {{n.system.jvm.jre.vendor}} {{n.system.jvm.jre.version}}
    + Solr: {{n.system.lucene['solr-impl-version'].split(" ")[0]}} +
    {{n.jvmUptime}}
    {{n.loadAvg}}
    {{n.cpuPct}}
    - {{n.heapUsedPct}}
    + {{n.heapUsedPct}} + +
    + Used: {{n.heapUsed}} +
    +
    + Total: {{n.heapTotal}}
    + Free: {{n.heapFree}} +
    +
    +
    + {{n.diskUsedPct}}
    +
    + Total: {{n.size}} +
    +
    - {{n.diskUsedPct}}
    Major: {{Math.round(n.gcMajorCount / n.jvmUptimeSec * 60 * 5 * 100) / 100}}/5m
    @@ -104,14 +131,16 @@ RPM: {{n.req1minRate}}
    p95: {{n.reqp95_ms}}ms
    -
    +
    {{ c }}
    +
    ({{n.collections.length - 2}} more...)
    -
    +
    {{ core.core }} {{core.leader ? "(leader)" : ""}} -
    +
    +
    ({{n.cores.length - 2}} more...)
    From 51af4d71296adba1b79f45b8ff94e9c9c4f9df67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 3 May 2018 13:49:17 +0200 Subject: [PATCH 12/47] Use shortform core name and bold to mark leader and display #docs after core name Show total number of docs and avg doc size in disk column In details view, show deletedDocs and warmupTime for each core --- solr/webapp/web/css/angular/cloud.css | 11 ++++++++ .../web/js/angular/controllers/cloud.js | 28 +++++++++++++++---- solr/webapp/web/partials/cloud.html | 11 ++++++-- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/solr/webapp/web/css/angular/cloud.css b/solr/webapp/web/css/angular/cloud.css index 734ebefba4dd..f10d4521477d 100644 --- a/solr/webapp/web/css/angular/cloud.css +++ b/solr/webapp/web/css/angular/cloud.css @@ -544,3 +544,14 @@ limitations under the License. color: #000000; box-shadow: 1px 1px 1px #666; } + +#content #nodes-content .leader +{ + font-weight: bold; +} + +#content #nodes-content .core-details +{ + padding-left: 21px; +} + diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index 5f41b972fbb0..e118e1f3c6a2 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -74,12 +74,20 @@ function ensureInList(string, list) { // from http://scratch99.com/web-development/javascript/convert-bytes-to-mb-kb/ function bytesToSize(bytes) { var sizes = ['b', 'Kb', 'Mb', 'Gb', 'Tb']; - if (bytes == 0) return 'n/a'; + if (bytes === 0) return 'n/a'; var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); - if (i == 0) return bytes + '' + sizes[i]; + if (bytes === 0) return bytes + '' + sizes[i]; return (bytes / Math.pow(1024, i)).toFixed(1) + '' + sizes[i]; } +function numDocsHuman(docs) { + var sizes = ['', 'k', 'mn', 'bn', 'tn']; + if (docs === 0) return 'n/a'; + var i = parseInt(Math.floor(Math.log(docs) / Math.log(1000))); + if (i === 0) return docs + '' + sizes[i]; + return (docs / Math.pow(1000, i)).toFixed(1) + '' + sizes[i]; +} + var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, MetricsAll) { $scope.showNodes = true; $scope.showTree = false; @@ -164,7 +172,7 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met nodes[node]['jvmUptime'] = secondsForHumans(jvmUptime); nodes[node]['jvmUptimeSec'] = jvmUptime; - nodes[node]['uptime'] = s.system.uptime.replace(/.*up (.*?),.*/, "$1") + nodes[node]['uptime'] = s.system.uptime.replace(/.*up (.*?,.*?),.*/, "$1") nodes[node]['loadAvg'] = Math.round(s.system.systemLoadAverage * 100) / 100; nodes[node]['cpuPct'] = Math.ceil(s.system.processCpuLoad) + "%"; } @@ -199,6 +207,7 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met var cores = nodes[node]['cores']; var indexSizeTotal = 0; + var docsTotal = 0; var graphData = []; if (cores) { for (coreId in cores) { @@ -208,13 +217,20 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met var size = nodeMetric['INDEX.sizeInBytes']; core['sizeInBytes'] = size; core['size'] = bytesToSize(size); - core['sizeLabel'] = core['core'].replace('_shard', '_s').replace(/_replica_./, 'r'); + core['label'] = core['core'].replace('_shard', '_s').replace(/_replica_./, 'r'); indexSizeTotal += size; + core['numDocs'] = nodeMetric['SEARCHER.searcher.numDocs']; + core['numDocsHuman'] = numDocsHuman(nodeMetric['SEARCHER.searcher.numDocs']); + core['deletedDocs'] = nodeMetric['SEARCHER.searcher.deletedDocs']; + core['deletedDocsHuman'] = numDocsHuman(nodeMetric['SEARCHER.searcher.deletedDocs']); + core['indexVersion'] = nodeMetric['SEARCHER.searcher.indexVersion']; + core['warmupTime'] = nodeMetric['SEARCHER.searcher.warmupTime']; + docsTotal += core['numDocs']; } for (coreId in cores) { var core = cores[coreId]; var graphObj = {}; - graphObj['label'] = core['sizeLabel']; + graphObj['label'] = core['label']; graphObj['size'] = core['sizeInBytes']; graphObj['sizeHuman'] = core['size']; graphObj['pct'] = (core['sizeInBytes'] / indexSizeTotal) * 100; @@ -228,8 +244,10 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met return b.size - a.size }); nodes[node]['graphData'] = graphData; + nodes[node]['numDocs'] = numDocsHuman(docsTotal); nodes[node]['sizeInBytes'] = indexSizeTotal; nodes[node]['size'] = bytesToSize(indexSizeTotal); + nodes[node]['sizePerDoc'] = bytesToSize(indexSizeTotal / docsTotal); // Add the div containing the whole chart $('#chart'+nodes[node]['id']).empty(); diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index b5702fd40a0f..170484bd64cb 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -119,6 +119,10 @@
    Total: {{n.size}}
    +
    + Total #docs: {{n.numDocs}}
    + Avg size/doc: {{n.sizePerDoc}} +
    @@ -132,13 +136,16 @@
    - {{ c }} + {{ c }}
    ({{n.collections.length - 2}} more...)
    - {{ core.core }} {{core.leader ? "(leader)" : ""}} + {{ core.label }} (docs={{core.numDocsHuman}}) +
      +
    • deleted: {{core.deletedDocsHuman}}. warmupTime: {{core.warmupTime}}
    • +
    ({{n.cores.length - 2}} more...)
    From 430ff47847c54919ce94b648cdd67882f8ecc1ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 3 May 2018 14:09:23 +0200 Subject: [PATCH 13/47] Possible to toggle details per row, and also expand all --- .../web/js/angular/controllers/cloud.js | 19 +++++++++--- solr/webapp/web/partials/cloud.html | 30 +++++++++---------- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index e118e1f3c6a2..be0ce0e409f1 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -93,11 +93,22 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met $scope.showTree = false; $scope.showGraph = false; $scope.showData = false; - $scope.showDetails = false; + $scope.showAllDetails = false; - $scope.toggleDetails = function() { - $scope.showDetails = !$scope.showDetails; - } + $scope.toggleAllDetails = function() { + for (var node in $scope.nodes) { + $scope.nodes[node]['showDetails'] = !$scope.showAllDetails; + } + $scope.showAllDetails = !$scope.showAllDetails; + }; + + $scope.toggleDetails = function(key) { + if ($scope.nodes[key]['showDetails'] === true) { + $scope.nodes[key]['showDetails'] = false; + } else { + $scope.nodes[key]['showDetails'] = true; + } + }; $scope.reload = function() { Collections.status(function (data) { diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index 170484bd64cb..8eeaa5435374 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -51,8 +51,8 @@ @@ -80,17 +80,17 @@ - +
    NA NA
    - + {{n.system.system.name}} {{n.system.system.availableProcessors}}cpu {{n.memTotal}} Java {{n.system.jvm.spec.version}} Solr {{n.system.lucene['solr-spec-version']}} -
    +
    {{n.system.system.name}} {{n.system.system.version}}, {{n.system.system.availableProcessors}}cpu
    Uptime: {{n.uptime}}
    RAM: {{n.memTotal}} (used: {{n.memUsed}} free: {{n.memFree}})
    @@ -106,9 +106,9 @@ {{n.heapUsedPct}}
    - Used: {{n.heapUsed}} + Used: {{n.heapUsed}}
    -
    +
    Total: {{n.heapTotal}}
    Free: {{n.heapFree}}
    @@ -117,13 +117,13 @@
    {{n.diskUsedPct}}
    - Total: {{n.size}} + Total: {{n.size}}
    -
    +
    Total #docs: {{n.numDocs}}
    Avg size/doc: {{n.sizePerDoc}}
    -
    +
    @@ -135,19 +135,19 @@ RPM: {{n.req1minRate}}
    p95: {{n.reqp95_ms}}ms
    -
    + -
    ({{n.collections.length - 2}} more...)
    +
    ({{n.collections.length - 2}} more...)
    -
    +
    {{ core.label }} (docs={{core.numDocsHuman}}) -
      +
      • deleted: {{core.deletedDocsHuman}}. warmupTime: {{core.warmupTime}}
    -
    ({{n.cores.length - 2}} more...)
    +
    ({{n.cores.length - 2}} more...)
    From bff2af37c0def3a00f2f95feb20dc527e71690b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 3 May 2018 14:23:46 +0200 Subject: [PATCH 14/47] Added file descriptorcount to node detail view --- solr/webapp/web/js/angular/controllers/cloud.js | 2 ++ solr/webapp/web/partials/cloud.html | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index be0ce0e409f1..0efcc12bb67d 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -186,6 +186,8 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met nodes[node]['uptime'] = s.system.uptime.replace(/.*up (.*?,.*?),.*/, "$1") nodes[node]['loadAvg'] = Math.round(s.system.systemLoadAverage * 100) / 100; nodes[node]['cpuPct'] = Math.ceil(s.system.processCpuLoad) + "%"; + nodes[node]['maxFileDescriptorCount'] = s.system.maxFileDescriptorCount; + nodes[node]['openFileDescriptorCount'] = s.system.openFileDescriptorCount; } } }); diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index 8eeaa5435374..86747267c998 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -95,7 +95,8 @@ Uptime: {{n.uptime}}
    RAM: {{n.memTotal}} (used: {{n.memUsed}} free: {{n.memFree}})
    Java: {{n.system.jvm.jre.vendor}} {{n.system.jvm.jre.version}}
    - Solr: {{n.system.lucene['solr-impl-version'].split(" ")[0]}} + Solr: {{n.system.lucene['solr-impl-version'].split(" ")[0]}}
    + File descriptors: {{n.openFileDescriptorCount}}/{{n.maxFileDescriptorCount}}
    {{n.jvmUptime}}
    From 66a8ae9a47b84e190000d2842a1a23833e7b13d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Fri, 4 May 2018 01:13:58 +0200 Subject: [PATCH 15/47] Group by host. Expand details per row. Scrollbar for large content --- solr/webapp/web/css/angular/cloud.css | 23 +++++ .../web/js/angular/controllers/cloud.js | 28 +++--- solr/webapp/web/partials/cloud.html | 93 ++++++++++--------- 3 files changed, 84 insertions(+), 60 deletions(-) diff --git a/solr/webapp/web/css/angular/cloud.css b/solr/webapp/web/css/angular/cloud.css index f10d4521477d..1acde134fa92 100644 --- a/solr/webapp/web/css/angular/cloud.css +++ b/solr/webapp/web/css/angular/cloud.css @@ -443,10 +443,12 @@ limitations under the License. #nodes-table td, #nodes-table th { border: 1px solid #ddd; padding: 8px; + vertical-align: top; } #nodes-table th { font-weight: bolder; font-stretch: extra-expanded; + background: #F8F8F8; } #content #cloud #nodes-content #nodes-table { @@ -455,11 +457,13 @@ limitations under the License. padding-top: 10px; } +#content #cloud #nodes-content .host-name, #content #cloud #nodes-content .node-name a { font-weight: bold; font-size: larger; } +#content #cloud #nodes-content .host-spec, #content #cloud #nodes-content .node-spec { font-style: italic; @@ -550,8 +554,27 @@ limitations under the License. font-weight: bold; } +#content #nodes-content .scroll-height-250 +{ + max-height: 250px; + overflow-scrolling: auto; + overflow: auto; + overflow-y: scroll; +} + #content #nodes-content .core-details { padding-left: 21px; } + +::-webkit-scrollbar { + -webkit-appearance: none; + width: 7px; +} + +::-webkit-scrollbar-thumb { + border-radius: 4px; + background-color: rgba(0,0,0,.5); + -webkit-box-shadow: 0 0 1px rgba(255,255,255,.5); +} \ No newline at end of file diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index 0efcc12bb67d..e928e91f2665 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -94,20 +94,17 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met $scope.showGraph = false; $scope.showData = false; $scope.showAllDetails = false; + $scope.showDetails = {}; $scope.toggleAllDetails = function() { + $scope.showAllDetails = !$scope.showAllDetails; for (var node in $scope.nodes) { - $scope.nodes[node]['showDetails'] = !$scope.showAllDetails; + $scope.showDetails[node] = $scope.showAllDetails; } - $scope.showAllDetails = !$scope.showAllDetails; }; $scope.toggleDetails = function(key) { - if ($scope.nodes[key]['showDetails'] === true) { - $scope.nodes[key]['showDetails'] = false; - } else { - $scope.nodes[key]['showDetails'] = true; - } + $scope.showDetails[key] = !$scope.showDetails[key] === true; }; $scope.reload = function() { @@ -143,10 +140,11 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met node['id'] = core.base_url.replace(/[^\w\d]/g, ''); var collections = getOrCreateList("collections", node); ensureInList(core.collection, collections); - var host_name = node_name.split(":")[0]; - var host = getOrCreateObj(host_name, hosts); - var host_nodes = getOrCreateList("nodes", host); - ensureInList(node_name, host_nodes); + var hostName = node_name.split(":")[0]; + var host = getOrCreateObj(hostName, hosts); + var hostNodes = getOrCreateList("nodes", host); + node['host'] = hostName; + ensureInList(node_name, hostNodes); } } } @@ -236,7 +234,6 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met core['numDocsHuman'] = numDocsHuman(nodeMetric['SEARCHER.searcher.numDocs']); core['deletedDocs'] = nodeMetric['SEARCHER.searcher.deletedDocs']; core['deletedDocsHuman'] = numDocsHuman(nodeMetric['SEARCHER.searcher.deletedDocs']); - core['indexVersion'] = nodeMetric['SEARCHER.searcher.indexVersion']; core['warmupTime'] = nodeMetric['SEARCHER.searcher.warmupTime']; docsTotal += core['numDocs']; } @@ -285,11 +282,14 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met } } }); - + // Make sure nodes are sorted alphabetically to align with rowspan in table + for (var host in hosts) { + hosts[host].nodes.sort(); + } $scope.nodes = nodes; $scope.hosts = hosts; $scope.live_nodes = live_nodes; - + $scope.Math = window.Math; }) }; diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index 86747267c998..afa09baca43d 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -56,10 +56,10 @@ + - - - + + @@ -68,63 +68,60 @@ - - - - - - - - - - - - + + - + - - +
    NodeUptime (jvm)LoadHostNode CPU Heap DiskCollections Cores
    NANANANANANANANANANA
    - - + + +
    {{n.host}}
    + {{n.system.system.name}} - {{n.system.system.availableProcessors}}cpu {{n.memTotal}} Java {{n.system.jvm.spec.version}} - Solr {{n.system.lucene['solr-spec-version']}} +
    Load: {{n.loadAvg}}
    -
    +
    {{n.system.system.name}} {{n.system.system.version}}, {{n.system.system.availableProcessors}}cpu
    Uptime: {{n.uptime}}
    - RAM: {{n.memTotal}} (used: {{n.memUsed}} free: {{n.memFree}})
    - Java: {{n.system.jvm.jre.vendor}} {{n.system.jvm.jre.version}}
    - Solr: {{n.system.lucene['solr-impl-version'].split(" ")[0]}}
    - File descriptors: {{n.openFileDescriptorCount}}/{{n.maxFileDescriptorCount}} + RAM: {{n.memTotal}}
    + (used: {{n.memUsed}} free: {{n.memFree}})
    + File descriptors: {{n.openFileDescriptorCount}}/{{n.maxFileDescriptorCount}}
    + Load: {{n.loadAvg}} +
    +
    + Uptime: {{n.jvmUptime}}
    +
    + Java {{n.system.jvm.jre.version}}
    + Solr {{n.system.lucene['solr-impl-version'].split(" ")[0]}}
    {{n.jvmUptime}}
    {{n.loadAvg}}
    {{n.cpuPct}}
    {{n.heapUsedPct}}
    - Used: {{n.heapUsed}} + Used: {{n.heapUsed}}
    -
    +
    Total: {{n.heapTotal}}
    Free: {{n.heapFree}}
    -
    - {{n.diskUsedPct}}
    -
    - Total: {{n.size}} -
    -
    - Total #docs: {{n.numDocs}}
    - Avg size/doc: {{n.sizePerDoc}} +
    +
    + {{n.diskUsedPct}}
    +
    + Total: {{n.size}} +
    +
    + Total #docs: {{n.numDocs}}
    + Avg size/doc: {{n.sizePerDoc}} +
    +
    -
    @@ -136,21 +133,25 @@ RPM: {{n.req1minRate}}
    p95: {{n.reqp95_ms}}ms
    -
    + -
    ({{n.collections.length - 2}} more...)
    +
    ({{n.collections.length - 2}} more...)
    -
    - {{ core.label }} (docs={{core.numDocsHuman}}) -
      -
    • deleted: {{core.deletedDocsHuman}}. warmupTime: {{core.warmupTime}}
    • -
    +
    +
    + {{ core.label }} ({{core.numDocsHuman}} docs) +
      +
    • deleted: {{core.deletedDocsHuman}}
    • +
    • warmupTime: {{core.warmupTime}}
    • +
    +
    +
    ({{n.cores.length - 2}} more...)
    -
    ({{n.cores.length - 2}} more...)
    From 97f89bd96b5ce436bbaf99130c15537a8479d0ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Sun, 6 May 2018 23:00:21 +0200 Subject: [PATCH 16/47] Proxy parameters too --- .../solr/handler/admin/AdminHandlersProxy.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlersProxy.java b/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlersProxy.java index 86a0f60299f0..421c4147d585 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlersProxy.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlersProxy.java @@ -37,7 +37,8 @@ import org.apache.solr.client.solrj.request.GenericSolrRequest; import org.apache.solr.cloud.ZkController; import org.apache.solr.common.SolrException; -import org.apache.solr.common.params.ModifiableSolrParams; +import org.apache.solr.common.params.MapSolrParams; +import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.Pair; import org.apache.solr.core.CoreContainer; @@ -64,6 +65,10 @@ public static boolean maybeProxyToNodes(SolrQueryRequest req, SolrQueryResponse Set nodes; String pathStr = req.getPath(); + + Map paramsMap = req.getParams().toMap(new HashMap<>()); + paramsMap.remove(PARAM_NODES); + SolrParams params = new MapSolrParams(paramsMap); Set liveNodes = container.getZkController().zkStateReader.getClusterState().getLiveNodes(); if (nodeNames.equals("all")) { @@ -91,7 +96,7 @@ public static boolean maybeProxyToNodes(SolrQueryRequest req, SolrQueryResponse } Map>, SolrClient>> responses = new HashMap<>(); for (String node : nodes) { - responses.put(node, callRemoteNode(node, pathStr, container.getZkController())); + responses.put(node, callRemoteNode(node, pathStr, params, container.getZkController())); } for (Map.Entry>, SolrClient>> entry : responses.entrySet()) { @@ -112,12 +117,13 @@ public static boolean maybeProxyToNodes(SolrQueryRequest req, SolrQueryResponse /** * Makes a remote request and returns a future and the solr client. The caller is responsible for closing the client */ - public static Pair>, SolrClient> callRemoteNode(String nodeName, String endpoint, ZkController zkController) + public static Pair>, SolrClient> callRemoteNode(String nodeName, String endpoint, + SolrParams params, ZkController zkController) throws IOException, SolrServerException { log.debug("Proxying {} request to node {}", endpoint, nodeName); URL baseUrl = new URL(zkController.zkStateReader.getBaseUrlForNodeName(nodeName)); HttpSolrClient solr = new HttpSolrClient.Builder(baseUrl.toString()).build(); - SolrRequest proxyReq = new GenericSolrRequest(SolrRequest.METHOD.GET, endpoint, new ModifiableSolrParams()); + SolrRequest proxyReq = new GenericSolrRequest(SolrRequest.METHOD.GET, endpoint, params); HttpSolrClient.HttpUriRequestResponse proxyResp = solr.httpUriRequest(proxyReq); return new Pair<>(proxyResp.future, solr); } From a5a0fc6adda008013d837fb8e39de9cbe012d7d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Mon, 7 May 2018 11:40:25 +0200 Subject: [PATCH 17/47] Lots of improvements: * Clickable links change background colour when hovered, and also has a thin dotted underline * Percentage numbers change colour: <60%: green, 60-80%: orange, >80%: red * Minimum width of the last "cores" column, prevents funny line wrap * Removed GC column (see SOLR-12318) * Pulls only necessary data from Metrics API (parameterised prefix) * Uses standard "System" angularJS service, but parameterised for "nodes" * Clicking host cell now toggles details for all nodes on that host * Renamed "reload" button to "Refresh" * Changed heading "Disk" to "Disk usage" to clarify that the percentage is used, not free * Now showing req15minRate instead of req1minRate for the RPM (this is all requests, on all handlers, i.e. search, update, admin..) --- solr/webapp/web/css/angular/cloud.css | 42 ++++++++++++ .../web/js/angular/controllers/cloud.js | 65 +++++++++++++------ solr/webapp/web/js/angular/services.js | 11 +--- solr/webapp/web/partials/cloud.html | 45 ++++++------- 4 files changed, 112 insertions(+), 51 deletions(-) diff --git a/solr/webapp/web/css/angular/cloud.css b/solr/webapp/web/css/angular/cloud.css index 1acde134fa92..90b8c5449b12 100644 --- a/solr/webapp/web/css/angular/cloud.css +++ b/solr/webapp/web/css/angular/cloud.css @@ -463,6 +463,22 @@ limitations under the License. font-weight: bold; font-size: larger; } + +#content #cloud #nodes-content a, +#content #cloud #nodes-content a:hover, +#content #cloud #nodes-content a.hover +{ + text-decoration: underline; + text-decoration-style: dotted; + text-decoration-color: #beebff; +} + +#content #cloud #nodes-content a:hover, +#content #cloud #nodes-content a.hover +{ + background-color: #beebff; +} + #content #cloud #nodes-content .host-spec, #content #cloud #nodes-content .node-spec { @@ -482,6 +498,21 @@ limitations under the License. font-size: 25px; } +#content #cloud #nodes-content .pct-normal +{ + color: darkgreen; +} + +#content #cloud #nodes-content .pct-warn +{ + color: orange; +} + +#content #cloud #nodes-content .pct-critical +{ + color: red; +} + /* Styling of reload and details buttons */ #content #cloud #controls { @@ -562,12 +593,23 @@ limitations under the License. overflow-y: scroll; } +#content #nodes-content .min-width-150 +{ + min-width: 150px; +} + +#content #cloud #nodes-content .node-cores +{ + min-width: 150px; +} + #content #nodes-content .core-details { padding-left: 21px; } + ::-webkit-scrollbar { -webkit-appearance: none; width: 7px; diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index e928e91f2665..dcc10832118a 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -16,7 +16,7 @@ */ solrAdminApp.controller('CloudController', - function($scope, $location, Zookeeper, Constants, Collections, SystemAll, MetricsAll) { + function($scope, $location, Zookeeper, Constants, Collections, System, Metrics) { $scope.showDebug = false; @@ -40,7 +40,7 @@ solrAdminApp.controller('CloudController', graphSubController($scope, Zookeeper, false); } else if (view == "nodes") { $scope.resetMenu("cloud-nodes", Constants.IS_ROOT_PAGE); - nodesSubController($scope, Zookeeper, Collections, SystemAll, MetricsAll); + nodesSubController($scope, Collections, System, Metrics); } } ); @@ -88,7 +88,14 @@ function numDocsHuman(docs) { return (docs / Math.pow(1000, i)).toFixed(1) + '' + sizes[i]; } -var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, MetricsAll) { +/* Returns a style class depending on percentage */ +var styleForPct = function (pct) { + if (pct < 60) return "pct-normal"; + if (pct < 80) return "pct-warn"; + return "pct-critical" +}; + +var nodesSubController = function($scope, Collections, System, Metrics) { $scope.showNodes = true; $scope.showTree = false; $scope.showGraph = false; @@ -101,11 +108,22 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met for (var node in $scope.nodes) { $scope.showDetails[node] = $scope.showAllDetails; } + for (var host in $scope.hosts) { + $scope.showDetails[host] = $scope.showAllDetails; + } }; $scope.toggleDetails = function(key) { $scope.showDetails[key] = !$scope.showDetails[key] === true; }; + + $scope.toggleHostDetails = function(key) { + $scope.showDetails[key] = !$scope.showDetails[key] === true; + for (var nodeId in $scope.hosts[key].nodes) { + var node = $scope.hosts[key].nodes[nodeId]; + $scope.showDetails[node] = $scope.showDetails[key]; + } + }; $scope.reload = function() { Collections.status(function (data) { @@ -156,7 +174,7 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met } } - SystemAll.get(function (systemResponse) { + System.get({"nodes":"all"}, function (systemResponse) { for (var node in systemResponse) { if (node in nodes) { var s = systemResponse[node]; @@ -165,6 +183,7 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met var memFree = s.system.freePhysicalMemorySize; var memPercentage = Math.floor((memTotal - memFree) / memTotal * 100); nodes[node]['memUsedPct'] = memPercentage + "%"; + nodes[node]['memUsedPctStyle'] = styleForPct(memPercentage); nodes[node]['memTotal'] = bytesToSize(memTotal); nodes[node]['memFree'] = bytesToSize(memFree); nodes[node]['memUsed'] = bytesToSize(memTotal - memFree); @@ -174,6 +193,7 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met var heapPercentage = Math.floor((heapTotal - heapFree) / heapTotal * 100); nodes[node]['heapUsed'] = bytesToSize(heapTotal - heapFree); nodes[node]['heapUsedPct'] = heapPercentage + "%"; + nodes[node]['heapUsedPctStyle'] = styleForPct(heapPercentage); nodes[node]['heapTotal'] = bytesToSize(heapTotal); nodes[node]['heapFree'] = bytesToSize(heapFree); @@ -181,16 +201,18 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met nodes[node]['jvmUptime'] = secondsForHumans(jvmUptime); nodes[node]['jvmUptimeSec'] = jvmUptime; - nodes[node]['uptime'] = s.system.uptime.replace(/.*up (.*?,.*?),.*/, "$1") + nodes[node]['uptime'] = s.system.uptime.replace(/.*up (.*?,.*?),.*/, "$1"); nodes[node]['loadAvg'] = Math.round(s.system.systemLoadAverage * 100) / 100; nodes[node]['cpuPct'] = Math.ceil(s.system.processCpuLoad) + "%"; + nodes[node]['cpuPctStyle'] = styleForPct(Math.ceil(s.system.processCpuLoad)); nodes[node]['maxFileDescriptorCount'] = s.system.maxFileDescriptorCount; nodes[node]['openFileDescriptorCount'] = s.system.openFileDescriptorCount; } } }); - MetricsAll.get(function (metricsResponse) { + Metrics.get({"nodes":"all", "prefix":"CONTAINER.fs,org.eclipse.jetty.server.handler.DefaultHandler.get-requests,INDEX.sizeInBytes,SEARCHER.searcher.numDocs,SEARCHER.searcher.deletedDocs,SEARCHER.searcher.warmupTime"}, + function (metricsResponse) { for (var node in metricsResponse) { if (node in nodes) { var m = metricsResponse[node]; @@ -199,6 +221,7 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met var diskFree = m.metrics['solr.node']['CONTAINER.fs.usableSpace']; var diskPercentage = Math.floor((diskTotal - diskFree) / diskTotal * 100); nodes[node]['diskUsedPct'] = diskPercentage + "%"; + nodes[node]['diskUsedPctStyle'] = styleForPct(diskPercentage); nodes[node]['diskTotal'] = bytesToSize(diskTotal); nodes[node]['diskFree'] = bytesToSize(diskFree); @@ -211,11 +234,6 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met nodes[node]['reqp95_ms'] = Math.floor(r['p95_ms']); nodes[node]['reqp99_ms'] = Math.floor(r['p99_ms']); - nodes[node]['gcMajorCount'] = m.metrics['solr.jvm']['gc.ConcurrentMarkSweep.count']; - nodes[node]['gcMajorTime'] = m.metrics['solr.jvm']['gc.ConcurrentMarkSweep.time']; - nodes[node]['gcMinorCount'] = m.metrics['solr.jvm']['gc.ParNew.count']; - nodes[node]['gcMinorTime'] = m.metrics['solr.jvm']['gc.ParNew.time']; - var cores = nodes[node]['cores']; var indexSizeTotal = 0; var docsTotal = 0; @@ -226,15 +244,22 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met var keyName = "solr.core." + core['core'].replace('_', '.').replace('_', '.'); var nodeMetric = m.metrics[keyName]; var size = nodeMetric['INDEX.sizeInBytes']; + size = (typeof size != 'undefined') ? size : 0; core['sizeInBytes'] = size; core['size'] = bytesToSize(size); core['label'] = core['core'].replace('_shard', '_s').replace(/_replica_./, 'r'); indexSizeTotal += size; - core['numDocs'] = nodeMetric['SEARCHER.searcher.numDocs']; - core['numDocsHuman'] = numDocsHuman(nodeMetric['SEARCHER.searcher.numDocs']); - core['deletedDocs'] = nodeMetric['SEARCHER.searcher.deletedDocs']; - core['deletedDocsHuman'] = numDocsHuman(nodeMetric['SEARCHER.searcher.deletedDocs']); - core['warmupTime'] = nodeMetric['SEARCHER.searcher.warmupTime']; + var numDocs = nodeMetric['SEARCHER.searcher.numDocs']; + numDocs = (typeof numDocs != 'undefined') ? numDocs : 0; + core['numDocs'] = numDocs; + core['numDocsHuman'] = numDocsHuman(numDocs); + var deletedDocs = nodeMetric['SEARCHER.searcher.deletedDocs']; + deletedDocs = (typeof deletedDocs != 'undefined') ? deletedDocs : 0; + core['deletedDocs'] = deletedDocs; + core['deletedDocsHuman'] = numDocsHuman(deletedDocs); + var warmupTime = nodeMetric['SEARCHER.searcher.warmupTime']; + warmupTime = (typeof warmupTime != 'undefined') ? warmupTime : 0; + core['warmupTime'] = warmupTime; docsTotal += core['numDocs']; } for (coreId in cores) { @@ -246,10 +271,12 @@ var nodesSubController = function($scope, Zookeeper, Collections, SystemAll, Met graphObj['pct'] = (core['sizeInBytes'] / indexSizeTotal) * 100; graphData.push(graphObj); } + cores.sort(function (a, b) { + return b.sizeInBytes - a.sizeInBytes + }); + } else { + cores = {}; } - cores.sort(function (a, b) { - return b.sizeInBytes - a.sizeInBytes - }); graphData.sort(function (a, b) { return b.size - a.size }); diff --git a/solr/webapp/web/js/angular/services.js b/solr/webapp/web/js/angular/services.js index 307dd9485047..66f2654d470d 100644 --- a/solr/webapp/web/js/angular/services.js +++ b/solr/webapp/web/js/angular/services.js @@ -19,15 +19,11 @@ var solrAdminServices = angular.module('solrAdminServices', ['ngResource']); solrAdminServices.factory('System', ['$resource', function($resource) { - return $resource('admin/info/system', {"wt":"json", "_":Date.now()}); + return $resource('admin/info/system', {"wt":"json", "nodes": "@nodes", "_":Date.now()}); }]) -.factory('SystemAll', +.factory('Metrics', ['$resource', function($resource) { - return $resource('admin/info/system', {"wt":"json", "nodes": "all", "_":Date.now()}); - }]) -.factory('MetricsAll', - ['$resource', function($resource) { - return $resource('admin/metrics', {"wt":"json", "nodes": "all", "_":Date.now()}); + return $resource('admin/metrics', {"wt":"json", "nodes": "@nodes", "prefix":"@prefix", "_":Date.now()}); }]) .factory('Collections', ['$resource', function($resource) { @@ -71,7 +67,6 @@ solrAdminServices.factory('System', ['$resource', function($resource) { return $resource('admin/zookeeper', {wt:'json', _:Date.now()}, { "simple": {}, - "dump": {params: {dump: "true"}}, "liveNodes": {params: {path: '/live_nodes'}}, "clusterState": {params: {detail: "true", path: "/clusterstate.json"}}, "detail": {params: {detail: "true", path: "@path"}}, diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index afa09baca43d..5083df039040 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -48,9 +48,9 @@ - +
    - reload + Refresh Show all details @@ -62,25 +62,24 @@ Node CPU Heap - Disk - GC + Disk usage Requests Collections Cores - + - +
    {{n.host}}
    - + {{n.system.system.name}} {{n.memTotal}} Java {{n.system.jvm.spec.version}}
    Load: {{n.loadAvg}}
    -
    +
    {{n.system.system.name}} {{n.system.system.version}}, {{n.system.system.availableProcessors}}cpu
    Uptime: {{n.uptime}}
    RAM: {{n.memTotal}}
    @@ -89,17 +88,20 @@ Load: {{n.loadAvg}}
    - + Uptime: {{n.jvmUptime}}
    Java {{n.system.jvm.jre.version}}
    Solr {{n.system.lucene['solr-impl-version'].split(" ")[0]}}
    -
    {{n.cpuPct}}
    - + +
    + {{n.cpuPct}} +
    +
    - {{n.heapUsedPct}} + {{n.heapUsedPct}}
    Used: {{n.heapUsed}} @@ -109,10 +111,11 @@ Free: {{n.heapFree}}
    - +
    - {{n.diskUsedPct}}
    + {{n.diskUsedPct}} +
    Total: {{n.size}}
    @@ -123,22 +126,16 @@
    - -
    - Major: {{Math.round(n.gcMajorCount / n.jvmUptimeSec * 60 * 5 * 100) / 100}}/5m
    - Minor: {{Math.round(n.gcMinorCount / n.jvmUptimeSec * 60 * 5 * 100) / 100}}/5m -
    - -
    - RPM: {{n.req1minRate}}
    p95: {{n.reqp95_ms}}ms
    +
    + RPM: {{n.req15minRate}}
    p95: {{n.reqp95_ms}}ms
    - +
    ({{n.collections.length - 2}} more...)
    - +
    {{ core.label }} ({{core.numDocsHuman}} docs) From 83a1014f16c16005e119e6082fb70203f6ea16af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Mon, 7 May 2018 13:43:31 +0200 Subject: [PATCH 18/47] Handle no-cores situation, display (empty) --- .../web/js/angular/controllers/cloud.js | 28 +++++++++++++------ solr/webapp/web/partials/cloud.html | 2 ++ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index dcc10832118a..e41a3304f486 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -71,10 +71,18 @@ function ensureInList(string, list) { } } +/* Puts a node name into the hosts structure */ +var ensureNodeInHosts = function (node_name, hosts) { + var hostName = node_name.split(":")[0]; + var host = getOrCreateObj(hostName, hosts); + var hostNodes = getOrCreateList("nodes", host); + ensureInList(node_name, hostNodes); +}; + // from http://scratch99.com/web-development/javascript/convert-bytes-to-mb-kb/ function bytesToSize(bytes) { var sizes = ['b', 'Kb', 'Mb', 'Gb', 'Tb']; - if (bytes === 0) return 'n/a'; + if (bytes === 0) return '0b'; var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); if (bytes === 0) return bytes + '' + sizes[i]; return (bytes / Math.pow(1024, i)).toFixed(1) + '' + sizes[i]; @@ -82,7 +90,7 @@ function bytesToSize(bytes) { function numDocsHuman(docs) { var sizes = ['', 'k', 'mn', 'bn', 'tn']; - if (docs === 0) return 'n/a'; + if (docs === 0) return '0'; var i = parseInt(Math.floor(Math.log(docs) / Math.log(1000))); if (i === 0) return docs + '' + sizes[i]; return (docs / Math.pow(1000, i)).toFixed(1) + '' + sizes[i]; @@ -156,22 +164,24 @@ var nodesSubController = function($scope, Collections, System, Metrics) { cores.push(core); node['base_url'] = core.base_url; node['id'] = core.base_url.replace(/[^\w\d]/g, ''); - var collections = getOrCreateList("collections", node); - ensureInList(core.collection, collections); var hostName = node_name.split(":")[0]; - var host = getOrCreateObj(hostName, hosts); - var hostNodes = getOrCreateList("nodes", host); node['host'] = hostName; - ensureInList(node_name, hostNodes); + var collections = getOrCreateList("collections", node); + ensureInList(core.collection, collections); + ensureNodeInHosts(node_name, hosts); } } } live_nodes = data.cluster.live_nodes; for (n in data.cluster.live_nodes) { - if (!(data.cluster.live_nodes[n] in nodes)) { - nodes[data.cluster.live_nodes[n]] = {}; + var node = data.cluster.live_nodes[n]; + if (!(node in nodes)) { + var hostName = node.split(":")[0]; + nodes[node] = {}; + nodes[node]['host'] = hostName; } + ensureNodeInHosts(node, hosts); } System.get({"nodes":"all"}, function (systemResponse) { diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index 5083df039040..ecdb77316412 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -130,6 +130,7 @@ RPM: {{n.req15minRate}}
    p95: {{n.reqp95_ms}}ms
    +
    (none)
    @@ -137,6 +138,7 @@
    +
    (none)
    {{ core.label }} ({{core.numDocsHuman}} docs)
      From fc873ebe25970867d22b457df38bbf62cd18f7e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Mon, 7 May 2018 13:47:22 +0200 Subject: [PATCH 19/47] Fix NAN for avg size/docs --- solr/webapp/web/js/angular/controllers/cloud.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index e41a3304f486..752e41a6fe04 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -294,7 +294,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { nodes[node]['numDocs'] = numDocsHuman(docsTotal); nodes[node]['sizeInBytes'] = indexSizeTotal; nodes[node]['size'] = bytesToSize(indexSizeTotal); - nodes[node]['sizePerDoc'] = bytesToSize(indexSizeTotal / docsTotal); + nodes[node]['sizePerDoc'] = docsTotal === 0 ? '0b' : bytesToSize(indexSizeTotal / docsTotal); // Add the div containing the whole chart $('#chart'+nodes[node]['id']).empty(); From b4aea86df81ca86f33cb806654bb51f8e398859d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Mon, 7 May 2018 21:14:34 +0200 Subject: [PATCH 20/47] First step for paging --- solr/webapp/web/css/angular/cloud.css | 6 + .../web/js/angular/controllers/cloud.js | 317 ++++++++++-------- solr/webapp/web/partials/cloud.html | 32 +- 3 files changed, 219 insertions(+), 136 deletions(-) diff --git a/solr/webapp/web/css/angular/cloud.css b/solr/webapp/web/css/angular/cloud.css index 90b8c5449b12..7fbd322a3d36 100644 --- a/solr/webapp/web/css/angular/cloud.css +++ b/solr/webapp/web/css/angular/cloud.css @@ -421,6 +421,12 @@ limitations under the License. padding-bottom: 15px; } +#nodesPaging +{ + padding-top: 5px; + padding-bottom: 5px; +} + #content #cloud #legend .shard-inactive, #content #cloud #legend .shard-inactive li, #content #cloud #legend .shard-inactive li text, diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index 752e41a6fe04..ef4b4d6a2caa 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -104,125 +104,177 @@ var styleForPct = function (pct) { }; var nodesSubController = function($scope, Collections, System, Metrics) { - $scope.showNodes = true; - $scope.showTree = false; - $scope.showGraph = false; - $scope.showData = false; - $scope.showAllDetails = false; - $scope.showDetails = {}; + $scope.pageSize = 10; + $scope.showNodes = true; + $scope.showTree = false; + $scope.showGraph = false; + $scope.showData = false; + $scope.showAllDetails = false; + $scope.showDetails = {}; + $scope.from = 0; + $scope.to = $scope.pageSize - 1; + + $scope.showPaging = function() { + return Object.keys($scope.hosts).length > $scope.pageSize; + }; + + $scope.toggleAllDetails = function() { + $scope.showAllDetails = !$scope.showAllDetails; + for (var node in $scope.nodes) { + $scope.showDetails[node] = $scope.showAllDetails; + } + for (var host in $scope.hosts) { + $scope.showDetails[host] = $scope.showAllDetails; + } + }; - $scope.toggleAllDetails = function() { - $scope.showAllDetails = !$scope.showAllDetails; - for (var node in $scope.nodes) { - $scope.showDetails[node] = $scope.showAllDetails; - } - for (var host in $scope.hosts) { - $scope.showDetails[host] = $scope.showAllDetails; - } - }; + $scope.toggleDetails = function(key) { + $scope.showDetails[key] = !$scope.showDetails[key] === true; + }; - $scope.toggleDetails = function(key) { - $scope.showDetails[key] = !$scope.showDetails[key] === true; - }; + $scope.toggleHostDetails = function(key) { + $scope.showDetails[key] = !$scope.showDetails[key] === true; + for (var nodeId in $scope.hosts[key].nodes) { + var node = $scope.hosts[key].nodes[nodeId]; + $scope.showDetails[node] = $scope.showDetails[key]; + } + }; - $scope.toggleHostDetails = function(key) { - $scope.showDetails[key] = !$scope.showDetails[key] === true; - for (var nodeId in $scope.hosts[key].nodes) { - var node = $scope.hosts[key].nodes[nodeId]; - $scope.showDetails[node] = $scope.showDetails[key]; - } - }; + // Initializes the cluster state, list of nodes, collections etc + $scope.initClusterState = function() { + var nodes = {}; + var hosts = {}; + var live_nodes = []; - $scope.reload = function() { - Collections.status(function (data) { - var nodes = {}; - var hosts = {}; - var live_nodes = []; - - // Fetch cluster state from collections API and invert to a nodes structure - for (var name in data.cluster.collections) { - var collection = data.cluster.collections[name]; - collection.name = name; - var shards = collection.shards; - collection.shards = []; - for (var shardName in shards) { - var shard = shards[shardName]; - shard.name = shardName; - shard.collection = collection.name; - var replicas = shard.replicas; - shard.replicas = []; - for (var replicaName in replicas) { - var core = replicas[replicaName]; - core.name = replicaName; - core.collection = collection.name; - core.shard = shard.name; - core.shard_state = shard.state; - - var node_name = core['node_name']; - var node = getOrCreateObj(node_name, nodes); - var cores = getOrCreateList("cores", node); - cores.push(core); - node['base_url'] = core.base_url; - node['id'] = core.base_url.replace(/[^\w\d]/g, ''); - var hostName = node_name.split(":")[0]; - node['host'] = hostName; - var collections = getOrCreateList("collections", node); - ensureInList(core.collection, collections); - ensureNodeInHosts(node_name, hosts); - } + Collections.status(function (data) { + // Fetch cluster state from collections API and invert to a nodes structure + for (var name in data.cluster.collections) { + var collection = data.cluster.collections[name]; + collection.name = name; + var shards = collection.shards; + collection.shards = []; + for (var shardName in shards) { + var shard = shards[shardName]; + shard.name = shardName; + shard.collection = collection.name; + var replicas = shard.replicas; + shard.replicas = []; + for (var replicaName in replicas) { + var core = replicas[replicaName]; + core.name = replicaName; + core.collection = collection.name; + core.shard = shard.name; + core.shard_state = shard.state; + + var node_name = core['node_name']; + var node = getOrCreateObj(node_name, nodes); + var cores = getOrCreateList("cores", node); + cores.push(core); + node['base_url'] = core.base_url; + node['id'] = core.base_url.replace(/[^\w\d]/g, ''); + var hostName = node_name.split(":")[0]; + node['host'] = hostName; + var collections = getOrCreateList("collections", node); + ensureInList(core.collection, collections); + ensureNodeInHosts(node_name, hosts); } } + } - live_nodes = data.cluster.live_nodes; - for (n in data.cluster.live_nodes) { - var node = data.cluster.live_nodes[n]; - if (!(node in nodes)) { - var hostName = node.split(":")[0]; - nodes[node] = {}; - nodes[node]['host'] = hostName; - } - ensureNodeInHosts(node, hosts); + live_nodes = data.cluster.live_nodes; + for (n in data.cluster.live_nodes) { + var node = data.cluster.live_nodes[n]; + if (!(node in nodes)) { + var hostName = node.split(":")[0]; + nodes[node] = {}; + nodes[node]['host'] = hostName; } + ensureNodeInHosts(node, hosts); + } - System.get({"nodes":"all"}, function (systemResponse) { - for (var node in systemResponse) { - if (node in nodes) { - var s = systemResponse[node]; - nodes[node]['system'] = s; - var memTotal = s.system.totalPhysicalMemorySize; - var memFree = s.system.freePhysicalMemorySize; - var memPercentage = Math.floor((memTotal - memFree) / memTotal * 100); - nodes[node]['memUsedPct'] = memPercentage + "%"; - nodes[node]['memUsedPctStyle'] = styleForPct(memPercentage); - nodes[node]['memTotal'] = bytesToSize(memTotal); - nodes[node]['memFree'] = bytesToSize(memFree); - nodes[node]['memUsed'] = bytesToSize(memTotal - memFree); - - var heapTotal = s.jvm.memory.raw.total; - var heapFree = s.jvm.memory.raw.free; - var heapPercentage = Math.floor((heapTotal - heapFree) / heapTotal * 100); - nodes[node]['heapUsed'] = bytesToSize(heapTotal - heapFree); - nodes[node]['heapUsedPct'] = heapPercentage + "%"; - nodes[node]['heapUsedPctStyle'] = styleForPct(heapPercentage); - nodes[node]['heapTotal'] = bytesToSize(heapTotal); - nodes[node]['heapFree'] = bytesToSize(heapFree); - - var jvmUptime = s.jvm.jmx.upTimeMS / 1000; // Seconds - nodes[node]['jvmUptime'] = secondsForHumans(jvmUptime); - nodes[node]['jvmUptimeSec'] = jvmUptime; - - nodes[node]['uptime'] = s.system.uptime.replace(/.*up (.*?,.*?),.*/, "$1"); - nodes[node]['loadAvg'] = Math.round(s.system.systemLoadAverage * 100) / 100; - nodes[node]['cpuPct'] = Math.ceil(s.system.processCpuLoad) + "%"; - nodes[node]['cpuPctStyle'] = styleForPct(Math.ceil(s.system.processCpuLoad)); - nodes[node]['maxFileDescriptorCount'] = s.system.maxFileDescriptorCount; - nodes[node]['openFileDescriptorCount'] = s.system.openFileDescriptorCount; - } - } - }); + // Make sure nodes are sorted alphabetically to align with rowspan in table + for (var host in hosts) { + hosts[host].nodes.sort(); + } + + $scope.nodes = nodes; + $scope.hosts = hosts; + $scope.live_nodes = live_nodes; + + $scope.Math = window.Math; + // console.log("***Initialized cluster state. nodes=" + JSON.stringify(nodes, undefined, 2) + ", hosts=" + JSON.stringify(hosts, undefined, 2)); + $scope.reload(); + }); + }; + + $scope.reload = function() { + var nodes = $scope.nodes; + var hosts = $scope.hosts; + var live_nodes = $scope.live_nodes; + var hostNames = Object.keys(hosts); + hostNames.sort(); + + // Calculate what nodes that will show on this page + var nodesToShow = []; + var nodesParam = ''; + var hostsToShow = []; + if ($scope.showPaging()) { + for (var id = $scope.from ; id < $scope.from + $scope.pageSize && hostNames[id] ; id++) { + var hostName = hostNames[id]; + hostsToShow.push(hostName); + nodesToShow = nodesToShow.concat(hosts[hostName]['nodes']); + nodesParam = nodesToShow.join(','); + } + } else { + nodesToShow = Object.keys(nodes); + hostsToShow = Object.keys(hosts); + nodesParam = 'all'; // Show all nodes + } + nodesToShow.sort(); + hostsToShow.sort(); + + System.get({"nodes": nodesParam}, function (systemResponse) { + for (var node in systemResponse) { + if (node in nodes) { + var s = systemResponse[node]; + nodes[node]['system'] = s; + var memTotal = s.system.totalPhysicalMemorySize; + var memFree = s.system.freePhysicalMemorySize; + var memPercentage = Math.floor((memTotal - memFree) / memTotal * 100); + nodes[node]['memUsedPct'] = memPercentage + "%"; + nodes[node]['memUsedPctStyle'] = styleForPct(memPercentage); + nodes[node]['memTotal'] = bytesToSize(memTotal); + nodes[node]['memFree'] = bytesToSize(memFree); + nodes[node]['memUsed'] = bytesToSize(memTotal - memFree); + + var heapTotal = s.jvm.memory.raw.total; + var heapFree = s.jvm.memory.raw.free; + var heapPercentage = Math.floor((heapTotal - heapFree) / heapTotal * 100); + nodes[node]['heapUsed'] = bytesToSize(heapTotal - heapFree); + nodes[node]['heapUsedPct'] = heapPercentage + "%"; + nodes[node]['heapUsedPctStyle'] = styleForPct(heapPercentage); + nodes[node]['heapTotal'] = bytesToSize(heapTotal); + nodes[node]['heapFree'] = bytesToSize(heapFree); + + var jvmUptime = s.jvm.jmx.upTimeMS / 1000; // Seconds + nodes[node]['jvmUptime'] = secondsForHumans(jvmUptime); + nodes[node]['jvmUptimeSec'] = jvmUptime; + + nodes[node]['uptime'] = s.system.uptime.replace(/.*up (.*?,.*?),.*/, "$1"); + nodes[node]['loadAvg'] = Math.round(s.system.systemLoadAverage * 100) / 100; + nodes[node]['cpuPct'] = Math.ceil(s.system.processCpuLoad) + "%"; + nodes[node]['cpuPctStyle'] = styleForPct(Math.ceil(s.system.processCpuLoad)); + nodes[node]['maxFileDescriptorCount'] = s.system.maxFileDescriptorCount; + nodes[node]['openFileDescriptorCount'] = s.system.openFileDescriptorCount; + } + } + }); - Metrics.get({"nodes":"all", "prefix":"CONTAINER.fs,org.eclipse.jetty.server.handler.DefaultHandler.get-requests,INDEX.sizeInBytes,SEARCHER.searcher.numDocs,SEARCHER.searcher.deletedDocs,SEARCHER.searcher.warmupTime"}, - function (metricsResponse) { + Metrics.get({ + "nodes": nodesParam, + "prefix": "CONTAINER.fs,org.eclipse.jetty.server.handler.DefaultHandler.get-requests,INDEX.sizeInBytes,SEARCHER.searcher.numDocs,SEARCHER.searcher.deletedDocs,SEARCHER.searcher.warmupTime" + }, + function (metricsResponse) { for (var node in metricsResponse) { if (node in nodes) { var m = metricsResponse[node]; @@ -269,7 +321,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { core['deletedDocsHuman'] = numDocsHuman(deletedDocs); var warmupTime = nodeMetric['SEARCHER.searcher.warmupTime']; warmupTime = (typeof warmupTime != 'undefined') ? warmupTime : 0; - core['warmupTime'] = warmupTime; + core['warmupTime'] = warmupTime; docsTotal += core['numDocs']; } for (coreId in cores) { @@ -295,43 +347,42 @@ var nodesSubController = function($scope, Collections, System, Metrics) { nodes[node]['sizeInBytes'] = indexSizeTotal; nodes[node]['size'] = bytesToSize(indexSizeTotal); nodes[node]['sizePerDoc'] = docsTotal === 0 ? '0b' : bytesToSize(indexSizeTotal / docsTotal); - + // Add the div containing the whole chart - $('#chart'+nodes[node]['id']).empty(); - var chart = d3.select('#chart'+nodes[node]['id']).append('div').attr('class', 'chart'); - + $('#chart' + nodes[node]['id']).empty(); + var chart = d3.select('#chart' + nodes[node]['id']).append('div').attr('class', 'chart'); + // Add one div per bar which will group together both labels and bars var g = chart.selectAll('div') .data(nodes[node]['graphData']).enter() .append('div'); - + // Add the bars var bars = g.append("div") .attr("class", "rect") - .text(function (d) { return d.label + ':\u00A0\u00A0' + d.sizeHuman; }); - + .text(function (d) { + return d.label + ':\u00A0\u00A0' + d.sizeHuman; + }); + // Execute the transition to show the bars bars.transition() .ease('elastic') - .style('width', function (d) { - return d.pct + '%'; + .style('width', function (d) { + return d.pct + '%'; }); } } - }); - // Make sure nodes are sorted alphabetically to align with rowspan in table - for (var host in hosts) { - hosts[host].nodes.sort(); - } - $scope.nodes = nodes; - $scope.hosts = hosts; - $scope.live_nodes = live_nodes; - - $scope.Math = window.Math; - }) - }; - $scope.reload(); -}; + }); + $scope.nodes = nodes; + $scope.hosts = hosts; + $scope.live_nodes = live_nodes; + $scope.nodesToShow = nodesToShow; + $scope.hostsToShow = hostsToShow; + $scope.hostNames = hostNames; + // console.log("***Reloaded data. nodes=" + JSON.stringify($scope.nodes, undefined, 2)); + }; + $scope.initClusterState(); +}; var treeSubController = function($scope, Zookeeper) { $scope.showTree = true; diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index ecdb77316412..b2084e20de11 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -50,11 +50,38 @@
      +
      +
      + + No hosts found. + Hosts {{from+1}} - {{from + hostsToShow.length + 1}} of {{hostNames.length}}.  + + Filter by:  :{{filterType}} + + + + + +   + + Show per page. + +
      +
      @@ -69,8 +96,7 @@ - - + - + @@ -108,14 +108,17 @@
      {{n.system.system.name}} {{n.system.system.version}}, {{n.system.system.availableProcessors}}cpu
      Uptime: {{n.uptime}}
      - RAM: {{n.memTotal}}
      - (used: {{n.memUsed}} free: {{n.memFree}})
      + Memory: {{n.memTotal}}
      File descriptors: {{n.openFileDescriptorCount}}/{{n.maxFileDescriptorCount}}
      + Disk: {{n.diskTotal}} used: {{n.diskUsedPct}}%
      Load: {{n.loadAvg}}
      - - From cc3f3a8095a73189d505c02f28d125be81eacbf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Mon, 4 Jun 2018 13:43:26 +0200 Subject: [PATCH 22/47] Restore functionality after merge --- .../org/apache/solr/core/CoreContainer.java | 2 +- .../solr/handler/admin/MetricsHandler.java | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java index e108ae19f892..55fa5f37857d 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -564,7 +564,7 @@ public void load() { configSetsHandler = createHandler(CONFIGSETS_HANDLER_PATH, cfg.getConfigSetsHandlerClass(), ConfigSetsHandler.class); // metricsHistoryHandler uses metricsHandler, so create it first - metricsHandler = new MetricsHandler(metricManager); + metricsHandler = new MetricsHandler(metricManager, this); containerHandlers.put(METRICS_PATH, metricsHandler); metricsHandler.initializeMetrics(metricManager, SolrInfoBean.Group.node.toString(), metricTag, METRICS_PATH); diff --git a/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java index db694b56b8c7..c76321282208 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java @@ -41,6 +41,8 @@ import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.common.util.StrUtils; +import org.apache.solr.core.CoreContainer; +import org.apache.solr.core.SolrCore; import org.apache.solr.handler.RequestHandlerBase; import org.apache.solr.metrics.SolrMetricManager; import org.apache.solr.request.SolrQueryRequest; @@ -67,13 +69,15 @@ public class MetricsHandler extends RequestHandlerBase implements PermissionName public static final String ALL = "all"; private static final Pattern KEY_REGEX = Pattern.compile("(? consumer) } } + private CoreContainer getCoreContainer(SolrQueryRequest req, SolrCore core) { + CoreContainer coreContainer; + if (core != null) { + coreContainer = req.getCore().getCoreContainer(); + } else { + coreContainer = cc; + } + return coreContainer; + } + private static String unescape(String s) { if (s.indexOf('\\') == -1) { return s; From 862060190e2a698f26733ea99046336b2f3f7dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Tue, 5 Jun 2018 15:31:00 +0200 Subject: [PATCH 23/47] Added distributed tests that verify the proxying Adding "node" param which is not a known cloud node throws exception, as does attempt to use in non-cloud mode. --- .../org/apache/solr/core/CoreContainer.java | 2 +- .../handler/admin/AdminHandlersProxy.java | 12 +- .../solr/handler/admin/MetricsHandler.java | 21 ++-- .../handler/admin/AdminHandlersProxyTest.java | 114 ++++++++++++++++++ .../handler/admin/MetricsHandlerTest.java | 8 +- .../solr/common/params/CommonParams.java | 2 + 6 files changed, 133 insertions(+), 26 deletions(-) create mode 100644 solr/core/src/test/org/apache/solr/handler/admin/AdminHandlersProxyTest.java diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java index 55fa5f37857d..8ab1a0556aa2 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -564,7 +564,7 @@ public void load() { configSetsHandler = createHandler(CONFIGSETS_HANDLER_PATH, cfg.getConfigSetsHandlerClass(), ConfigSetsHandler.class); // metricsHistoryHandler uses metricsHandler, so create it first - metricsHandler = new MetricsHandler(metricManager, this); + metricsHandler = new MetricsHandler(this); containerHandlers.put(METRICS_PATH, metricsHandler); metricsHandler.initializeMetrics(metricManager, SolrInfoBean.Group.node.toString(), metricTag, METRICS_PATH); diff --git a/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlersProxy.java b/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlersProxy.java index 421c4147d585..ae3e01f0e7d8 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlersProxy.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlersProxy.java @@ -58,11 +58,14 @@ public class AdminHandlersProxy { public static boolean maybeProxyToNodes(SolrQueryRequest req, SolrQueryResponse rsp, CoreContainer container) throws IOException, SolrServerException, InterruptedException { String nodeNames = req.getParams().get(PARAM_NODES); - if (nodeNames == null || nodeNames.isEmpty()) { return false; // local request } + if (!container.isZooKeeperAware()) { + throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Parameter " + PARAM_NODES + " only supported in Cloud mode"); + } + Set nodes; String pathStr = req.getPath(); @@ -87,13 +90,8 @@ public static boolean maybeProxyToNodes(SolrQueryRequest req, SolrQueryResponse } log.debug("Nodes requested: {}", nodes); } - - boolean solrCloudMode = container.isZooKeeperAware(); - log.debug(PARAM_NODES + " parameter {} specified on {} request", nodeNames, pathStr); - if (!solrCloudMode) { - throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Parameter " + PARAM_NODES + " only supported in Cloud mode"); - } + Map>, SolrClient>> responses = new HashMap<>(); for (String node : nodes) { responses.put(node, callRemoteNode(node, pathStr, params, container.getZkController())); diff --git a/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java index c76321282208..1f1a820b32d2 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java @@ -42,7 +42,6 @@ import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.common.util.StrUtils; import org.apache.solr.core.CoreContainer; -import org.apache.solr.core.SolrCore; import org.apache.solr.handler.RequestHandlerBase; import org.apache.solr.metrics.SolrMetricManager; import org.apache.solr.request.SolrQueryRequest; @@ -75,11 +74,15 @@ public MetricsHandler() { this.metricManager = null; } - public MetricsHandler(SolrMetricManager metricManager, CoreContainer coreContainer) { - this.metricManager = metricManager; + public MetricsHandler(CoreContainer coreContainer) { + this.metricManager = coreContainer.getMetricManager(); this.cc = coreContainer; } + public MetricsHandler(SolrMetricManager metricManager) { + this.metricManager = metricManager; + } + @Override public Name getPermissionName(AuthorizationContext request) { return Name.METRICS_READ_PERM; @@ -91,7 +94,7 @@ public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throw throw new SolrException(SolrException.ErrorCode.INVALID_STATE, "SolrMetricManager instance not initialized"); } - if (AdminHandlersProxy.maybeProxyToNodes(req, rsp, getCoreContainer(req, req.getCore()))) { + if (cc != null && AdminHandlersProxy.maybeProxyToNodes(req, rsp, cc)) { return; // Request was proxied to other node } @@ -169,16 +172,6 @@ public void handleKeyRequest(String[] keys, BiConsumer consumer) } } - private CoreContainer getCoreContainer(SolrQueryRequest req, SolrCore core) { - CoreContainer coreContainer; - if (core != null) { - coreContainer = req.getCore().getCoreContainer(); - } else { - coreContainer = cc; - } - return coreContainer; - } - private static String unescape(String s) { if (s.indexOf('\\') == -1) { return s; diff --git a/solr/core/src/test/org/apache/solr/handler/admin/AdminHandlersProxyTest.java b/solr/core/src/test/org/apache/solr/handler/admin/AdminHandlersProxyTest.java new file mode 100644 index 000000000000..78e9ba9be653 --- /dev/null +++ b/solr/core/src/test/org/apache/solr/handler/admin/AdminHandlersProxyTest.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.solr.handler.admin; + +import java.io.IOException; +import java.util.Collections; + +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.lucene.util.IOUtils; +import org.apache.solr.client.solrj.SolrRequest; +import org.apache.solr.client.solrj.SolrServerException; +import org.apache.solr.client.solrj.impl.CloudSolrClient; +import org.apache.solr.client.solrj.request.GenericSolrRequest; +import org.apache.solr.client.solrj.response.SimpleSolrResponse; +import org.apache.solr.cloud.SolrCloudTestCase; +import org.apache.solr.common.SolrException; +import org.apache.solr.common.params.MapSolrParams; +import org.apache.solr.common.util.NamedList; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class AdminHandlersProxyTest extends SolrCloudTestCase { + private CloseableHttpClient httpClient; + private CloudSolrClient solrClient; + + @BeforeClass + public static void setupCluster() throws Exception { + configureCluster(2) + .addConfig("conf", configset("cloud-minimal")) + .configure(); + } + + @Before + @Override + public void setUp() throws Exception { + super.setUp(); + solrClient = getCloudSolrClient(cluster); + httpClient = (CloseableHttpClient) solrClient.getHttpClient(); + } + + @After + @Override + public void tearDown() throws Exception { + super.tearDown(); + IOUtils.close(solrClient, httpClient); + } + + @Test + public void proxySystemInfoHandlerAllNodes() throws IOException, SolrServerException { + MapSolrParams params = new MapSolrParams(Collections.singletonMap("nodes", "all")); + GenericSolrRequest req = new GenericSolrRequest(SolrRequest.METHOD.GET, "/admin/info/system", params); + SimpleSolrResponse rsp = req.process(solrClient, null); + NamedList nl = rsp.getResponse(); + assertEquals(3, nl.size()); + assertTrue(nl.getName(1).endsWith("_solr")); + assertTrue(nl.getName(2).endsWith("_solr")); + assertEquals("solrcloud", ((NamedList)nl.get(nl.getName(1))).get("mode")); + assertEquals(nl.getName(2), ((NamedList)nl.get(nl.getName(2))).get("node")); + } + + @Test + public void proxyMetricsHandlerAllNodes() throws IOException, SolrServerException { + MapSolrParams params = new MapSolrParams(Collections.singletonMap("nodes", "all")); + GenericSolrRequest req = new GenericSolrRequest(SolrRequest.METHOD.GET, "/admin/metrics", params); + SimpleSolrResponse rsp = req.process(solrClient, null); + NamedList nl = rsp.getResponse(); + assertEquals(3, nl.size()); + assertTrue(nl.getName(1).endsWith("_solr")); + assertTrue(nl.getName(2).endsWith("_solr")); + assertNotNull(((NamedList)nl.get(nl.getName(1))).get("metrics")); + } + + @Test(expected = SolrException.class) + public void proxySystemInfoHandlerNonExistingNode() throws IOException, SolrServerException { + MapSolrParams params = new MapSolrParams(Collections.singletonMap("nodes", "example.com:1234_solr")); + GenericSolrRequest req = new GenericSolrRequest(SolrRequest.METHOD.GET, "/admin/info/system", params); + SimpleSolrResponse rsp = req.process(solrClient, null); + } + + @Test + public void proxySystemInfoHandlerOneNode() { + solrClient.getZkStateReader().getClusterState().getLiveNodes().forEach(node -> { + MapSolrParams params = new MapSolrParams(Collections.singletonMap("nodes", node)); + GenericSolrRequest req = new GenericSolrRequest(SolrRequest.METHOD.GET, "/admin/info/system", params); + SimpleSolrResponse rsp = null; + try { + rsp = req.process(solrClient, null); + } catch (Exception e) { + fail("Exception while proxying request to node " + node); + } + NamedList nl = rsp.getResponse(); + assertEquals(2, nl.size()); + assertEquals("solrcloud", ((NamedList)nl.get(nl.getName(1))).get("mode")); + assertEquals(nl.getName(1), ((NamedList)nl.get(nl.getName(1))).get("node")); + }); + } +} \ No newline at end of file diff --git a/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java b/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java index 392bdfc8f1d9..0fe5ad75fc6d 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java @@ -48,7 +48,7 @@ public static void beforeClass() throws Exception { @Test public void test() throws Exception { - MetricsHandler handler = new MetricsHandler(h.getCoreContainer().getMetricManager()); + MetricsHandler handler = new MetricsHandler(h.getCoreContainer()); SolrQueryResponse resp = new SolrQueryResponse(); handler.handleRequestBody(req(CommonParams.QT, "/admin/metrics", MetricsHandler.COMPACT_PARAM, "false", CommonParams.WT, "json"), resp); @@ -179,7 +179,7 @@ public void test() throws Exception { @Test public void testCompact() throws Exception { - MetricsHandler handler = new MetricsHandler(h.getCoreContainer().getMetricManager()); + MetricsHandler handler = new MetricsHandler(h.getCoreContainer()); SolrQueryResponse resp = new SolrQueryResponse(); handler.handleRequestBody(req(CommonParams.QT, "/admin/metrics", CommonParams.WT, "json", MetricsHandler.COMPACT_PARAM, "true"), resp); @@ -197,7 +197,7 @@ public void testCompact() throws Exception { public void testPropertyFilter() throws Exception { assertQ(req("*:*"), "//result[@numFound='0']"); - MetricsHandler handler = new MetricsHandler(h.getCoreContainer().getMetricManager()); + MetricsHandler handler = new MetricsHandler(h.getCoreContainer()); SolrQueryResponse resp = new SolrQueryResponse(); handler.handleRequestBody(req(CommonParams.QT, "/admin/metrics", CommonParams.WT, "json", @@ -234,7 +234,7 @@ public void testPropertyFilter() throws Exception { @Test public void testKeyMetrics() throws Exception { - MetricsHandler handler = new MetricsHandler(h.getCoreContainer().getMetricManager()); + MetricsHandler handler = new MetricsHandler(h.getCoreContainer()); String key1 = "solr.core.collection1:CACHE.core.fieldCache"; SolrQueryResponse resp = new SolrQueryResponse(); diff --git a/solr/solrj/src/java/org/apache/solr/common/params/CommonParams.java b/solr/solrj/src/java/org/apache/solr/common/params/CommonParams.java index 21879ba174c7..13c6d7aefb6f 100644 --- a/solr/solrj/src/java/org/apache/solr/common/params/CommonParams.java +++ b/solr/solrj/src/java/org/apache/solr/common/params/CommonParams.java @@ -182,6 +182,7 @@ public interface CommonParams { String AUTHZ_PATH = "/admin/authorization"; String AUTHC_PATH = "/admin/authentication"; String ZK_PATH = "/admin/zookeeper"; + String SYSTEM_INFO_PATH = "/admin/info/system"; String METRICS_PATH = "/admin/metrics"; String METRICS_HISTORY_PATH = "/admin/metrics/history"; String AUTOSCALING_PATH = "/admin/autoscaling"; @@ -199,6 +200,7 @@ public interface CommonParams { COLLECTIONS_HANDLER_PATH, HEALTH_CHECK_HANDLER_PATH, CONFIGSETS_HANDLER_PATH, + SYSTEM_INFO_PATH, AUTHC_PATH, AUTHZ_PATH, METRICS_PATH, From 181fcf9103ab40fd8185879be6584014f39e7976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Fri, 8 Jun 2018 14:18:57 +0200 Subject: [PATCH 24/47] Moved toggle details from table to links. Fixed offset bug in paging text --- solr/webapp/web/partials/cloud.html | 42 ++++++++++++++++++----------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index 84bc3dd295d0..b9a9bf37e428 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -59,7 +59,7 @@
      No hosts found. - Hosts {{from+1}} - {{from + hostsToShow.length + 1}} of {{hostNames.length}}.  + Hosts {{from+1}} - {{from + hostsToShow.length}} of {{hostNames.length}}.  Filter by: 
      - - - - + - - - - From 3a4b65fba9de691cffe090a7a16c9d750dad04ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 28 Jun 2018 10:48:38 +0200 Subject: [PATCH 25/47] WIP for next page --- solr/webapp/web/js/angular/controllers/cloud.js | 6 ++++++ solr/webapp/web/partials/cloud.html | 8 ++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index 2b1fe7ebda04..8a0219206111 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -140,6 +140,11 @@ var nodesSubController = function($scope, Collections, System, Metrics) { } }; + $scope.nextPage = function() { + $scope.pos += $scope.rows; + $scope.reload(); + } + // Initializes the cluster state, list of nodes, collections etc $scope.initClusterState = function() { var nodes = {}; @@ -225,6 +230,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { nodesToShow = nodesToShow.concat(hosts[hostName]['nodes']); nodesParam = nodesToShow.join(','); } + $scope.nextEnabled = $scope.from + $scope.pageSize < hostNames.length; } else { nodesToShow = Object.keys(nodes); hostsToShow = Object.keys(hosts); diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index db9f9cdb36e3..74de1574e82b 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -75,11 +75,11 @@ - -   + +   - Show per page. - + Show per page. +
      {{n.host}}
      From 871a9a9817ac713154a3c045223869753c0f958b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Fri, 11 May 2018 23:29:50 +0200 Subject: [PATCH 21/47] Rename cores->replicas, reword total/max heap New details button for node column show avg size in replica details --- solr/webapp/web/css/angular/cloud.css | 7 ++-- .../web/js/angular/controllers/cloud.js | 9 +++-- solr/webapp/web/partials/cloud.html | 38 +++++++++---------- 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/solr/webapp/web/css/angular/cloud.css b/solr/webapp/web/css/angular/cloud.css index 7fbd322a3d36..b3695ab46814 100644 --- a/solr/webapp/web/css/angular/cloud.css +++ b/solr/webapp/web/css/angular/cloud.css @@ -486,7 +486,8 @@ limitations under the License. } #content #cloud #nodes-content .host-spec, -#content #cloud #nodes-content .node-spec +#content #cloud #nodes-content .node-spec, +#content #cloud #nodes-content .node-spec a { font-style: italic; } @@ -501,7 +502,7 @@ limitations under the License. #content #cloud #nodes-content .node-disk { font-weight: bolder; - font-size: 25px; + font-size: 20px; } #content #cloud #nodes-content .pct-normal @@ -596,7 +597,7 @@ limitations under the License. max-height: 250px; overflow-scrolling: auto; overflow: auto; - overflow-y: scroll; + /*overflow-y: auto;*/ } #content #nodes-content .min-width-150 diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index ef4b4d6a2caa..925d7ff3645c 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -241,7 +241,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { var memTotal = s.system.totalPhysicalMemorySize; var memFree = s.system.freePhysicalMemorySize; var memPercentage = Math.floor((memTotal - memFree) / memTotal * 100); - nodes[node]['memUsedPct'] = memPercentage + "%"; + nodes[node]['memUsedPct'] = memPercentage; nodes[node]['memUsedPctStyle'] = styleForPct(memPercentage); nodes[node]['memTotal'] = bytesToSize(memTotal); nodes[node]['memFree'] = bytesToSize(memFree); @@ -251,7 +251,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { var heapFree = s.jvm.memory.raw.free; var heapPercentage = Math.floor((heapTotal - heapFree) / heapTotal * 100); nodes[node]['heapUsed'] = bytesToSize(heapTotal - heapFree); - nodes[node]['heapUsedPct'] = heapPercentage + "%"; + nodes[node]['heapUsedPct'] = heapPercentage; nodes[node]['heapUsedPctStyle'] = styleForPct(heapPercentage); nodes[node]['heapTotal'] = bytesToSize(heapTotal); nodes[node]['heapFree'] = bytesToSize(heapFree); @@ -262,7 +262,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { nodes[node]['uptime'] = s.system.uptime.replace(/.*up (.*?,.*?),.*/, "$1"); nodes[node]['loadAvg'] = Math.round(s.system.systemLoadAverage * 100) / 100; - nodes[node]['cpuPct'] = Math.ceil(s.system.processCpuLoad) + "%"; + nodes[node]['cpuPct'] = Math.ceil(s.system.processCpuLoad); nodes[node]['cpuPctStyle'] = styleForPct(Math.ceil(s.system.processCpuLoad)); nodes[node]['maxFileDescriptorCount'] = s.system.maxFileDescriptorCount; nodes[node]['openFileDescriptorCount'] = s.system.openFileDescriptorCount; @@ -282,7 +282,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { var diskTotal = m.metrics['solr.node']['CONTAINER.fs.totalSpace']; var diskFree = m.metrics['solr.node']['CONTAINER.fs.usableSpace']; var diskPercentage = Math.floor((diskTotal - diskFree) / diskTotal * 100); - nodes[node]['diskUsedPct'] = diskPercentage + "%"; + nodes[node]['diskUsedPct'] = diskPercentage; nodes[node]['diskUsedPctStyle'] = styleForPct(diskPercentage); nodes[node]['diskTotal'] = bytesToSize(diskTotal); nodes[node]['diskFree'] = bytesToSize(diskFree); @@ -315,6 +315,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { numDocs = (typeof numDocs != 'undefined') ? numDocs : 0; core['numDocs'] = numDocs; core['numDocsHuman'] = numDocsHuman(numDocs); + core['avgSizePerDoc'] = bytesToSize(numDocs == 0 ? 0 : size / numDocs); var deletedDocs = nodeMetric['SEARCHER.searcher.deletedDocs']; deletedDocs = (typeof deletedDocs != 'undefined') ? deletedDocs : 0; core['deletedDocs'] = deletedDocs; diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index b2084e20de11..84bc3dd295d0 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -92,7 +92,7 @@
      Disk usage Requests CollectionsCoresReplicas
      Uptime: {{n.jvmUptime}}
      +
      Java {{n.system.jvm.jre.version}}
      Solr {{n.system.lucene['solr-impl-version'].split(" ")[0]}}
      @@ -123,27 +126,21 @@
      - {{n.cpuPct}} + {{n.cpuPct}}%
      -
      - {{n.heapUsedPct}} -
      -
      - Used: {{n.heapUsed}} +
      + {{n.heapUsedPct}}%
      - Total: {{n.heapTotal}}
      - Free: {{n.heapFree}} + Max: {{n.heapTotal}}
      + Used: {{n.heapUsed}}
      -
      -
      - {{n.diskUsedPct}} -
      -
      - Total: {{n.size}} +
      +
      +
      + {{n.size}}
      Total #docs: {{n.numDocs}}
      @@ -162,18 +159,17 @@
      ({{n.collections.length - 2}} more...)
      -
      +
      (none)
      {{ core.label }} ({{core.numDocsHuman}} docs)
      • deleted: {{core.deletedDocsHuman}}
      • warmupTime: {{core.warmupTime}}
      • +
      • avg size/doc: {{core.avgSizePerDoc}}
      ({{n.cores.length - 2}} more...)
      -
      +
      {{n.host}}
      {{n.system.system.name}} @@ -113,22 +113,28 @@ Disk: {{n.diskTotal}} used: {{n.diskUsedPct}}%
      Load: {{n.loadAvg}} +
      + Uptime: {{n.jvmUptime}}
      -
      Java {{n.system.jvm.jre.version}}
      Solr {{n.system.lucene['solr-impl-version'].split(" ")[0]}}
      +
      +
      {{n.cpuPct}}% -
      + +
      {{n.heapUsedPct}}%
      @@ -137,7 +143,7 @@ Used: {{n.heapUsed}}
      +
      {{n.size}} @@ -149,27 +155,31 @@
      +
      RPM: {{n.req15minRate}}
      p95: {{n.reqp95_ms}}ms
      +
      (none)
      -
      ({{n.collections.length - 2}} more...)
      +
      +
      (none)
      - {{ core.label }} ({{core.numDocsHuman}} docs) + {{ core.label }} ({{core.numDocsHuman}} docs)
      • deleted: {{core.deletedDocsHuman}}
      • warmupTime: {{core.warmupTime}}
      • avg size/doc: {{core.avgSizePerDoc}}
      -
      ({{n.cores.length - 2}} more...)
      +
      From 982650d234ccf3fce8246ad1361df3781299810f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Wed, 1 Aug 2018 13:59:42 +0200 Subject: [PATCH 26/47] Make filtering on host/node and collection work. Still need to check paging --- .../web/js/angular/controllers/cloud.js | 91 ++++++++++++++++--- solr/webapp/web/partials/cloud.html | 28 +++--- 2 files changed, 91 insertions(+), 28 deletions(-) diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index 8a0219206111..31a95471fba6 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -103,6 +103,10 @@ var styleForPct = function (pct) { return "pct-critical" }; +function isNumeric(n) { + return !isNaN(parseFloat(n)) && isFinite(n); +} + var nodesSubController = function($scope, Collections, System, Metrics) { $scope.pageSize = 10; $scope.showNodes = true; @@ -113,8 +117,9 @@ var nodesSubController = function($scope, Collections, System, Metrics) { $scope.showDetails = {}; $scope.from = 0; $scope.to = $scope.pageSize - 1; + $scope.filterType = "node"; // Pre-initialize dropdown - $scope.showPaging = function() { + $scope.showNodesPaging = function() { return Object.keys($scope.hosts).length > $scope.pageSize; }; @@ -141,7 +146,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { }; $scope.nextPage = function() { - $scope.pos += $scope.rows; + $scope.pos += $scope.pageSize; $scope.reload(); } @@ -207,30 +212,90 @@ var nodesSubController = function($scope, Collections, System, Metrics) { $scope.live_nodes = live_nodes; $scope.Math = window.Math; - // console.log("***Initialized cluster state. nodes=" + JSON.stringify(nodes, undefined, 2) + ", hosts=" + JSON.stringify(hosts, undefined, 2)); $scope.reload(); }); }; + $scope.filterInput = function() { + $scope.from = 0; + $scope.pos = $scope.from; + $scope.to = $scope.pageSize - 1; + $scope.reload(); + } + $scope.reload = function() { var nodes = $scope.nodes; + var node_keys = Object.keys(nodes); var hosts = $scope.hosts; var live_nodes = $scope.live_nodes; var hostNames = Object.keys(hosts); + var filteredHosts; hostNames.sort(); + var pageSize = isNumeric($scope.pageSize) ? $scope.pageSize : 10; // Calculate what nodes that will show on this page var nodesToShow = []; var nodesParam = ''; var hostsToShow = []; - if ($scope.showPaging()) { - for (var id = $scope.from ; id < $scope.from + $scope.pageSize && hostNames[id] ; id++) { - var hostName = hostNames[id]; + var filteredNodes; + var filteredHosts; + var isFiltered = false; + if ($scope.showNodesPaging()) { + switch ($scope.filterType) { + case "node": + if ($scope.nodeFilter) { + filteredNodes = node_keys.filter(nod => nod.indexOf($scope.nodeFilter) !== -1); + } + break; + + case "collection": + if ($scope.collectionFilter) { + candidateNodes = {}; + nodesCollections = []; + for (var i = 0 ; i < node_keys.length ; i++) { + var node_name = node_keys[i]; + var node = nodes[node_name]; + nodeColl = {}; + nodeColl['node'] = node_name; + collections = {}; + node.cores.forEach(function(core) { + collections[core.collection] = true; + }); + nodeColl['collections'] = Object.keys(collections); + nodesCollections.push(nodeColl); + } + nodesCollections.forEach(function(nc) { + matchingColls = nc['collections'].filter(co => co.indexOf($scope.collectionFilter) != -1); + if (matchingColls.length > 0) { + candidateNodes[nc.node] = true; + } + }); + filteredNodes = Object.keys(candidateNodes); + } + break; + + case "health": + + } + if (filteredNodes) { + isFiltered = true; + filteredHosts = filteredNodes.map(nod => nod.split(":")[0]).filter((item,index,self) => self.indexOf(item)==index); + filteredHosts.sort(); + } else { + filteredNodes = node_keys; + filteredHosts = hostNames; + } + for (var id = $scope.from ; id < $scope.from + pageSize && filteredHosts[id] ; id++) { + var hostName = filteredHosts[id]; hostsToShow.push(hostName); - nodesToShow = nodesToShow.concat(hosts[hostName]['nodes']); - nodesParam = nodesToShow.join(','); + if (isFiltered) { // Only show the nodes per host matching active filter + nodesToShow = nodesToShow.concat(filteredNodes.filter(nod => nod.startsWith(hostName))); + } else { + nodesToShow = nodesToShow.concat(hosts[hostName]['nodes']); + } } - $scope.nextEnabled = $scope.from + $scope.pageSize < hostNames.length; + nodesParam = nodesToShow.join(','); + $scope.nextEnabled = $scope.from + pageSize < hostNames.length; } else { nodesToShow = Object.keys(nodes); hostsToShow = Object.keys(hosts); @@ -239,6 +304,11 @@ var nodesSubController = function($scope, Collections, System, Metrics) { nodesToShow.sort(); hostsToShow.sort(); +/* NOCOMMIT: Remove debug */ + console.log("***Initialized paging. filterType=" + $scope.filterType + ", statusFilter=" + JSON.stringify($scope.pagingStatusFilter, undefined, 2) + ", nodeFilter=" + JSON.stringify($scope.nodeFilter, undefined, 2) + + ", collectionFilter=" + JSON.stringify($scope.collectionFilter, undefined, 2) + ", pageSize=" + pageSize + ", from=" + $scope.from + ", nodesParam=" + nodesParam + + ", all nodes=" + node_keys); + System.get({"nodes": nodesParam}, function (systemResponse) { for (var node in systemResponse) { if (node in nodes) { @@ -385,8 +455,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { $scope.live_nodes = live_nodes; $scope.nodesToShow = nodesToShow; $scope.hostsToShow = hostsToShow; - $scope.hostNames = hostNames; - // console.log("***Reloaded data. nodes=" + JSON.stringify($scope.nodes, undefined, 2)); + $scope.filteredHosts = filteredHosts; }; $scope.initClusterState(); }; diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index 74de1574e82b..5bb452e59294 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -55,30 +55,24 @@ Show all details -
      +
      - No hosts found. - Hosts {{from+1}} - {{from + hostsToShow.length}} of {{hostNames.length}}.  + No hosts found. + Hosts {{from+1}} - {{from + hostsToShow.length}} of {{filteredHosts.length}}.  - Filter by:  + - -  :{{filterType}} +   - - - -   +   - Show per page. + +   + + Show hosts per page.
      From dd11c332602ea130a6021c2077d0073a072a60f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Wed, 1 Aug 2018 15:19:50 +0200 Subject: [PATCH 27/47] Always show filtering. Fix paging and next/prev buttons --- .../web/js/angular/controllers/cloud.js | 29 ++++++++++++------- solr/webapp/web/partials/cloud.html | 6 ++-- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index 31a95471fba6..9acfa1bbf37a 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -119,10 +119,6 @@ var nodesSubController = function($scope, Collections, System, Metrics) { $scope.to = $scope.pageSize - 1; $scope.filterType = "node"; // Pre-initialize dropdown - $scope.showNodesPaging = function() { - return Object.keys($scope.hosts).length > $scope.pageSize; - }; - $scope.toggleAllDetails = function() { $scope.showAllDetails = !$scope.showAllDetails; for (var node in $scope.nodes) { @@ -146,9 +142,20 @@ var nodesSubController = function($scope, Collections, System, Metrics) { }; $scope.nextPage = function() { - $scope.pos += $scope.pageSize; - $scope.reload(); - } + $scope.from += parseInt($scope.pageSize); + $scope.reload(); + }; + + $scope.previousPage = function() { + $scope.from = Math.max(0, $scope.from - parseInt($scope.pageSize)); + $scope.reload(); + }; + + $scope.isFirstNodeForHost = function(node) { + var hostName = node.split(":")[0]; + var nodesInHost = $scope.filteredNodes.filter(no => no.startsWith(hostName)); + return nodesInHost[0] === node; + }; // Initializes the cluster state, list of nodes, collections etc $scope.initClusterState = function() { @@ -218,7 +225,6 @@ var nodesSubController = function($scope, Collections, System, Metrics) { $scope.filterInput = function() { $scope.from = 0; - $scope.pos = $scope.from; $scope.to = $scope.pageSize - 1; $scope.reload(); } @@ -280,11 +286,12 @@ var nodesSubController = function($scope, Collections, System, Metrics) { if (filteredNodes) { isFiltered = true; filteredHosts = filteredNodes.map(nod => nod.split(":")[0]).filter((item,index,self) => self.indexOf(item)==index); - filteredHosts.sort(); } else { filteredNodes = node_keys; filteredHosts = hostNames; } + filteredNodes.sort(); + filteredHosts.sort(); for (var id = $scope.from ; id < $scope.from + pageSize && filteredHosts[id] ; id++) { var hostName = filteredHosts[id]; hostsToShow.push(hostName); @@ -295,7 +302,8 @@ var nodesSubController = function($scope, Collections, System, Metrics) { } } nodesParam = nodesToShow.join(','); - $scope.nextEnabled = $scope.from + pageSize < hostNames.length; + $scope.nextEnabled = $scope.from + pageSize < filteredHosts.length; + $scope.prevEnabled = $scope.from - pageSize >= 0; } else { nodesToShow = Object.keys(nodes); hostsToShow = Object.keys(hosts); @@ -455,6 +463,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { $scope.live_nodes = live_nodes; $scope.nodesToShow = nodesToShow; $scope.hostsToShow = hostsToShow; + $scope.filteredNodes = filteredNodes; $scope.filteredHosts = filteredHosts; }; $scope.initClusterState(); diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index 5bb452e59294..ec511b382022 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -55,9 +55,9 @@ Show all details
      -
      +
      - + No hosts found. Hosts {{from+1}} - {{from + hostsToShow.length}} of {{filteredHosts.length}}.  @@ -91,7 +91,7 @@
      -
      +
      {{n.host}}
      {{n.system.system.name}} From 8724f42b09c68a7f304dd29f6cf3d92c48a10070 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Wed, 1 Aug 2018 15:36:33 +0200 Subject: [PATCH 28/47] Add debuounce option to form inputs to allow 500ms for more input in text fields before calling reload() --- solr/webapp/web/partials/cloud.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index ec511b382022..078c9af40b7e 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -67,12 +67,12 @@   -   +   -   +   - Show hosts per page. + Show hosts per page. From 991b7819e93e2f3f2eaf88f0cd3ccbb0cec0d3a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 2 Aug 2018 12:27:10 +0200 Subject: [PATCH 29/47] Revert to "cloud" naming after spinning off tab renaming to separate issue --- solr/webapp/web/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solr/webapp/web/index.html b/solr/webapp/web/index.html index 935c7869ba45..fdd7a5f97f98 100644 --- a/solr/webapp/web/index.html +++ b/solr/webapp/web/index.html @@ -148,7 +148,7 @@

      Connection recovered...

      -
    • Cluster

      +
    • Cloud

      • Nodes
      • Tree
      • From ff3ec59bf99623af52523fed8a4fd39744836dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 2 Aug 2018 12:27:52 +0200 Subject: [PATCH 30/47] Always show paging, so remove defunct showNodesPaging() call --- .../web/js/angular/controllers/cloud.js | 110 +++++++++--------- 1 file changed, 52 insertions(+), 58 deletions(-) diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index 9acfa1bbf37a..c0458613fa6a 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -246,69 +246,63 @@ var nodesSubController = function($scope, Collections, System, Metrics) { var filteredNodes; var filteredHosts; var isFiltered = false; - if ($scope.showNodesPaging()) { - switch ($scope.filterType) { - case "node": - if ($scope.nodeFilter) { - filteredNodes = node_keys.filter(nod => nod.indexOf($scope.nodeFilter) !== -1); - } - break; - - case "collection": - if ($scope.collectionFilter) { - candidateNodes = {}; - nodesCollections = []; - for (var i = 0 ; i < node_keys.length ; i++) { - var node_name = node_keys[i]; - var node = nodes[node_name]; - nodeColl = {}; - nodeColl['node'] = node_name; - collections = {}; - node.cores.forEach(function(core) { - collections[core.collection] = true; - }); - nodeColl['collections'] = Object.keys(collections); - nodesCollections.push(nodeColl); - } - nodesCollections.forEach(function(nc) { - matchingColls = nc['collections'].filter(co => co.indexOf($scope.collectionFilter) != -1); - if (matchingColls.length > 0) { - candidateNodes[nc.node] = true; - } + switch ($scope.filterType) { + case "node": + if ($scope.nodeFilter) { + filteredNodes = node_keys.filter(nod => nod.indexOf($scope.nodeFilter) !== -1); + } + break; + + case "collection": + if ($scope.collectionFilter) { + candidateNodes = {}; + nodesCollections = []; + for (var i = 0 ; i < node_keys.length ; i++) { + var node_name = node_keys[i]; + var node = nodes[node_name]; + nodeColl = {}; + nodeColl['node'] = node_name; + collections = {}; + node.cores.forEach(function(core) { + collections[core.collection] = true; }); - filteredNodes = Object.keys(candidateNodes); + nodeColl['collections'] = Object.keys(collections); + nodesCollections.push(nodeColl); } - break; - - case "health": - - } - if (filteredNodes) { - isFiltered = true; - filteredHosts = filteredNodes.map(nod => nod.split(":")[0]).filter((item,index,self) => self.indexOf(item)==index); - } else { - filteredNodes = node_keys; - filteredHosts = hostNames; - } - filteredNodes.sort(); - filteredHosts.sort(); - for (var id = $scope.from ; id < $scope.from + pageSize && filteredHosts[id] ; id++) { - var hostName = filteredHosts[id]; - hostsToShow.push(hostName); - if (isFiltered) { // Only show the nodes per host matching active filter - nodesToShow = nodesToShow.concat(filteredNodes.filter(nod => nod.startsWith(hostName))); - } else { - nodesToShow = nodesToShow.concat(hosts[hostName]['nodes']); + nodesCollections.forEach(function(nc) { + matchingColls = nc['collections'].filter(co => co.indexOf($scope.collectionFilter) != -1); + if (matchingColls.length > 0) { + candidateNodes[nc.node] = true; + } + }); + filteredNodes = Object.keys(candidateNodes); } - } - nodesParam = nodesToShow.join(','); - $scope.nextEnabled = $scope.from + pageSize < filteredHosts.length; - $scope.prevEnabled = $scope.from - pageSize >= 0; + break; + + case "health": + + } + if (filteredNodes) { + isFiltered = true; + filteredHosts = filteredNodes.map(nod => nod.split(":")[0]).filter((item,index,self) => self.indexOf(item)==index); } else { - nodesToShow = Object.keys(nodes); - hostsToShow = Object.keys(hosts); - nodesParam = 'all'; // Show all nodes + filteredNodes = node_keys; + filteredHosts = hostNames; + } + filteredNodes.sort(); + filteredHosts.sort(); + for (var id = $scope.from ; id < $scope.from + pageSize && filteredHosts[id] ; id++) { + var hostName = filteredHosts[id]; + hostsToShow.push(hostName); + if (isFiltered) { // Only show the nodes per host matching active filter + nodesToShow = nodesToShow.concat(filteredNodes.filter(nod => nod.startsWith(hostName))); + } else { + nodesToShow = nodesToShow.concat(hosts[hostName]['nodes']); + } } + nodesParam = nodesToShow.join(','); + $scope.nextEnabled = $scope.from + pageSize < filteredHosts.length; + $scope.prevEnabled = $scope.from - pageSize >= 0; nodesToShow.sort(); hostsToShow.sort(); From 83cda01586fb76338ae87f7a8a7cbf462d2030c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 2 Aug 2018 12:28:19 +0200 Subject: [PATCH 31/47] Update refGuide --- solr/solr-ref-guide/src/cloud-screens.adoc | 12 +++++++----- .../src/images/cloud-screens/cloud-nodes.png | Bin 0 -> 185805 bytes .../src/images/cloud-screens/cloud-radial.png | Bin 102878 -> 0 bytes 3 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 solr/solr-ref-guide/src/images/cloud-screens/cloud-nodes.png delete mode 100644 solr/solr-ref-guide/src/images/cloud-screens/cloud-radial.png diff --git a/solr/solr-ref-guide/src/cloud-screens.adoc b/solr/solr-ref-guide/src/cloud-screens.adoc index 77cf9e540e3f..4fc92085edca 100644 --- a/solr/solr-ref-guide/src/cloud-screens.adoc +++ b/solr/solr-ref-guide/src/cloud-screens.adoc @@ -26,7 +26,13 @@ This screen provides status information about each collection & node in your clu The "Cloud" menu option is only available on Solr instances running in <>. Single node or master/slave replication instances of Solr will not display this option. ==== -Click on the Cloud option in the left-hand navigation, and a small sub-menu appears with options called "Tree", "Graph", and "Graph (Radial)". The default view ("Graph") shows a graph of each collection, the shards that make up those collections, and the addresses and type ("NRT", "TLOG" or "PULL") of each replica for each shard. +Click on the Cloud option in the left-hand navigation, and a small sub-menu appears with options called "Nodes", "Tree" and "Graph". The default view ("Nodes") shows a list of the hosts and nodes in the cluster along with key information for each: "CPU", "Heap", "Disk usage", "Requests", "Collections" and "Replicas". + +The example below shows the default "cloud" example with some documents added to the "gettingstarted" collection. Details are expanded for node on port 7574, showing more metadata and more metrics details. The screen provides links to navigate to nodes, collections and replicas. The table supports paging and filtering on host/node names and collection names. + +image::images/cloud-screens/cloud-nodes.png[image,width=512,height=236] + +The ("Graph") view shows a graph of each collection, the shards that make up those collections, and the addresses and type ("NRT", "TLOG" or "PULL") of each replica for each shard. This example shows a simple cluster. In addition to the 2 shard, 2 replica "gettingstarted" collection, there is an additional "tlog" collection consisting of mixed TLOG and PULL replica types. @@ -36,10 +42,6 @@ Tooltips appear when hovering over each replica giving additional information. image::images/cloud-screens/cloud-hover.png[image,width=512,height=250] -The "Graph (Radial)" option provides a different visual view of each node. Using the same example cluster, the radial graph view looks like: - -image::images/cloud-screens/cloud-radial.png[image,width=478,height=250] - The "Tree" option shows a directory structure of the data in ZooKeeper, including cluster wide information regarding the `live_nodes` and `overseer` status, as well as collection specific information such as the `state.json`, current shard leaders, and configuration files in use. In this example, we see part of the `state.json` definition for the "tlog" collection: image::images/cloud-screens/cloud-tree.png[image,width=487,height=250] diff --git a/solr/solr-ref-guide/src/images/cloud-screens/cloud-nodes.png b/solr/solr-ref-guide/src/images/cloud-screens/cloud-nodes.png new file mode 100644 index 0000000000000000000000000000000000000000..cecc758ea9a1b1fb56a2d06616d84368fdb2cda3 GIT binary patch literal 185805 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%0Al=_6bPTlg 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

        >_i2+WPDWKzllg0W1}!*rl{A+Hmhcdk&Z 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

        |$Oor_&27 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 literal 0 HcmV?d00001 diff --git a/solr/solr-ref-guide/src/images/cloud-screens/cloud-radial.png b/solr/solr-ref-guide/src/images/cloud-screens/cloud-radial.png deleted file mode 100644 index d3b245f8f171d47cca59d2a60c40a39c030144ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102878 zcmbTdWl)?=&^8JLcXwIbo#0MzcM0wU4~x6IySpX01PM-XcXxM}MGtvid%pV4IX~X5 z+NyhJrhB@3=AP-kx;I=&K@tfbA07-03`tt*iwYPRgfJKwxE3t*N6YUAF+DIa_&O^w zF(qj+F@Vx{dvhxrGcYiz@Z=O2HPt2TkcsxA=manb6;b;DAcRzPKJ2uJnkYIT2^T{Y z0}IU&vOgdKR!bO$7Cr_lPDGqx5xOtLI{*=4m|LqWVEA_z`FLB?y64HO_Vc>^*=hZR z;6YCPJhUH!5gcTB4I!A-3(zPmmQR3=HzdXr8L%4)qb6)pD-O}Lxe4ZHdH(7uzba{r zw#J%0es}Tyt~un?OvVYO#L{y`h{lJsl^CXHju3PNmiHa4Q^CB|Farfp0r&#{<#CsT zdi*-sDkgW2nw`~%lo&P^+>g3mtLF=tlmV)cKwx&*F6mEFoAHCoM_9$`f%NP@+W_5w z%YcT41D6;3;^K&d{YjCiEQ(ts zk@eXlZ&~dlW;36c?L3}+NAqn9Zs}73!2z3i$x%Wlt(>>%+VaRx``rEqV@dnc79nG` z4rXB-LYli+yaNnd4=sOax9q0fTjZ?9vx;g4dB!)z8FEaNWy;5P(g$Xdlh=c~)SWBDjZ39|5^`?;Vch z1Xpap*QQqkz`JhsvR-E|h(}jhrQqJzns9hr!7;$Ph&H@AGr_t2PFse@E(Ei2r0_Js zEz8X#gYoJGZ*M<+3KPbr0mI7k&!QAFglC9fCiJJjgzy2t2Kigo5Y~vGOMMcJgZtj? zp#&Sz%~^w>=J&b@DElPY?Kla~+vVhFR~3j)BxCTs^Z1oS%5c>nWWsbJ=|q$BzbVO=xu|g+Bg+Kfi+hWjOmT1!*+#g0c`oRkvbm+Z z)d9k_Lgsby9Y=nMMhGhciA_j+%&EkMu54FuvT>qz;BBg@MYRl!VGP zfh1u=nFiB4f}S!YL19U>yi_-jztAfwe<*E;#f+Qn#FWlV$JB15EroLMc&K%VDRnHK zF;RfjQ`JQ+22jd;Ksu1{m0pw9Ri{ePPB-T-Q;J+F1F{W(uewiKMB%Y&dl}(3@H@aA zgtK2r!O=pYjx{8OZjgE zmZ8=M)?C&?bEL;CKy;wXG4Lqr=-V;$@%}OAvEVfMA?t0zt;>n?iT5PeWbEul(Z&xU zn>?E?jzLyS4mV>dRv@dcnU;y$0<85P78%xMYv2ej=Pyf-34?&6IICBae{5KQ2A?E6=hI*A4~tO?K*+OJ{I)PA-10HN}>Xo3fvzoA|i+Sidkm zCBBNi(!b=w;KIOuTK=>p+}TCsuZVrZxX)~d1R*k-M=Ex%zBD<3Hz!|2@TYcFvqK}clpZ!%MIWAbBi!7m;XDH1XT*bsUif5Cj~OU9?K*SLq5gA9fkq6=03tq~3P8r(=G)gU*U zQsu`X!1X6&J9_&K@gQnADmEQ0ow{zf{!yE&F1nt}0%gzb;H3e-J)^yqUX$L{+wL8| z>GPa*e&dz(@A;z&dM&QBgG9}yoMu6@*J{u{s2Fs?^~KJTS&4a&9(VDuzP47WL`iG0 zX~=Qrjbu{j(&uo=rqO+3-(Ebcz`Ae0&#cctW|4Bir{S^oWuTl9?yJYIWxKT|q~Fn< zXKya4XU@gf#XQBI_#j*xPKz!WmO(xX5qg><6(jc-ROi?iDM>I%O=nYU^|lkK5k(Q6 z$>+&q>fh8ee+r)Nowm16I2+9P+`aZa3z2LRxhb8guBj9nsJftfvg~X|ilK$J`WnBe z8T{1ws{4G$@?KNKRCI3KuIKF?sM9+y(X716{hi`|u(B{mawS79^G9ZKMr5qN$+iiz zZ_G33&GCIlj~bUcL*Y2Pf>)eReHNn8v?;2Qs!?XSV8ui6Is5#ZtBufI__6UdbP)+viJDCO;Oe_rc9eh{5TfV#- z64HBbW5xc=`6%&der!9$m+Tt4@wM{;ABEVLGoF(blz&(_JkY8brMQ+$E`%a)?$hl} z`~K~=@ip_kiCWc4RTUy7?(+*4I+&X$E|?4lSi@H^)YS3&VfFy?=Vv^K_i&5n zBfKRDrBs+Mpsd*$yznPu4|n!TR9Fe_QLHWv4VCB8FK`+u^(|7BQr0S*pYM>5&>SVe zyv{N+GHkLlo^&EHpJDyR!O$(?cFUM(s&KxPR9I`A?xySlnExw13af45*}<>BFBW?^GyV`Kan!RX{}2Q+eHv~wc=4<`S` z=Zl$>$#*LUpq0HH;4fbzV|!>s`UV>LHd zt^c89W##<*Z_O9DY80qg&#JA2bF(GCqlx(hBl?o%bj{MvH*5|NNVNolFYvgcRZ zpRGTi*CR*EhKGk37Ut}zj7#Xr$o1PEwns+8QjJtKhD3OR{X~UH^H7ywX&^Bnn$RH1 zyXz#_0}F~_@G4aS2`^GsDn#`7c+}n{pF_;_>4h{}O%Fcb)X(%Xt!EkN56Cj#;CZv7 z+%(2>E^S38Q98$pmlVZ!j1r7B6*fi2_D?Vg;CD(L#ZRB^_F>o$Y%mEDue&rztoPRx zHAN&^)jkbv8d1~ZUsxWEa$)21fn2Umy4lh6Fy_crI;5;z+$aiuV^x1K`+8Lu!G6PK z@O5t~s@c**yI55>;uw56>UXgz-G|ul;Qwe*lMWl?;m4_pK>78*HTvl4f+ovD%tM0w z8m{t>lK+f0v<7@MRyvX-VgD!fUmMr}Acnz~g=>;&{$-Y5(0?28A4IJ3|I4;+E3k6-jVbZ zO&_lT3#X1poI^H5{H~--;<47$Aome_B`d>?4ybmzFU>WXf%z)d4*q$1sOC2M>N|?P ziH?KG1u8r4~$mP}ixxXKOX;8T<(@SWL)lZ?`6wu@lGwBr;8B0;jmDjFOH*Kxpp>!Fcx zlzrAA9DdPn@ND~z7$g`-7&7?3S#DA|%r}@~!?;!fCU`uIquPxNn5CSeNi4__#8p(L&I#69QKJy5`0Hl3oQ5@W9(xJiHDUuXm15Y z@P#&Of?F4xoYO0?sGFUYl{94a(cH03j{Rvg<%nk-H-&#u6ysHsKSla|6v&41+|S`o zv|Ct8V8$AKr4wRuElpn@o34LtCR9-o!sej=#_T-L)OaoJlYo-C!9bs8-X%Xc1GZy0 zDeZHbnVrOJW!hSVB-=Cesz4w(ud*P9K|P{7BZxgU&*vw;y`v%?`A}xylK}jT{|u7V=*XzSB_}@u zmjFAoF1HY0`T&jUVZlg3YvvJmwRT5(uCi~skW}Fb83=MG`ibBi>LiJbwZ5Eww3SWK zMdjDjft&P%kqg@z;XJy1ihU8+KH62tb@0k!- z0c#`V!@HpIku3*9BO`xlC4GJ3QF=16m(>*LxT(kVvlAn=DbUz^^t!>bEjKKK$31FZ zXPv7rY+@>N!A+?Uv?i3&BSL5JuxkelQERR4UON(UW9|ETEf4M z_bJrD;o+X$T?!4$pb#Xo!Y$KOu34ypuYN8;)1nRX1{Xn6PvSD{N0h=-o<1J$7f#Lh zbEUN`i=lf*(nc?C>(89=h1>PHq6&JSs3vkm>F&ykf1URZUicy(2zhZay`JH0=H{Ra zh=?{sf3`;_av9RF2XvXIn9tSeOAIWqjT5E-v-$)XlX8!G4;PV};&8SJrYRY6b0qi8 zto5%spUeeCJjBwYZq4x|I@qd-+LIa52L?4Kp|04rjC#njIMpQBg>IbFVtD&CTGRUA z1ksLqFG7`L5MlNpFT!cW7rhq}d(PWOOO-?4;oIdNbX5j9(hb(xO}} zBWq%!;|=2alc?Nqft(`={5?mawWFG?H8o6<{nDU>`NK@BsD+PZGb85H?{_mvQ$ria z9WZinaU`3Hvnxsk^;iN)C0Z|QTu7oH`+FpZS)LNANA25E9DBHqOyzc1_*UA2VjoMN z&2`49-$$+Xt;w@l#|Z8J_J|Z(6^yX|Avn*+CTQVL$c;|{MY^Trr%IPZx{0;&*o-lEen;v*=A(J_la^Z)=g)aF>On-mTQ7{$}0MN6KB=$hQ?_~ZCU0Zg0Gq( zm)fC?Js>;4zbIYtMJwRXRY^@!`Q8+8vt}vyG33@1-=vK-HojWV3pd(lB+Bux|Djxk zxU!d6C*G>>LSB7Y6B7GpFbz9A_Ty}1V;*o^bYt8JvY#GG>o;=w<(|&`KI6?^nM8jh zYryjPRZ0hs(Q53<9Pe6Z;md;Lj`1ixNZRA$4z!5kni)PZ)Q(2sGUF)81brtS;*%;p zIIsp$TiFfU$C-_iz!U5eJmQ0-@z`Qn$8b~j*!vx|xO<;T3vUacm?`xJ!Qd5J_o@Q= zQIc&o8&e(jFoc*wTCOuPthiaR-ohP=Od;M#a)d$lzQj2_WKnI`5D*Ji1!{f7HAcJ7 z-K?0t*P2r=^qrCUn(xe2UVB!MUXeh}p_1kEup^W)7v_G6V|%v^+dgP3%#L5Uw&jpJ z-fSUFNeMFP(Gp#Y0BZSP9vunL#aQGf%n9ne18ag#e$DiX_R&;K`hFMDRz(XCIR#|3 z$JXvPsPs<4Pb>EY$MFMOXXpL1LN8FduA0WlAwRsB^@Wd0g~CG~go3ALs99fr`!cXF zF8bnPNp6r;m=wmF!8Au`{>u}~Mhz?E+P*&o-_B>wc&M*ypa|)#vp)XgMIx!rIE@fl zyPMrFv*9>JuJ#(4`^7__7&`Zzv~LR6$cPc!*MSf#_Zd^i=h%YP@rbO-_t9dLe>p4( zI`1L36P^Sq7fO$C6XvGu-%c(;M3=1*m~^ITNmFJ@0}AQS66|u%@}|-&z$%B+s?bjG z1w`Cy4vez<##a{S%1^2r&#Fb|u00Q%bop6CQt!|G7-&sPIGxAk89h^$u8Q zl_O?P4omH>C8XDeR^M!2j=@^?=IN|O!~1<9A>kZ7$i6WX{NhR^vN!e2I=2))CG?yW zH+iXOAo9w$5#7xdQ~2tw*aH%#CtM2FdKpLP86R?cFQn;wAl;pvC)+d#AkTI|gCFbOoPoH2SGX#0}1P8JkJ!mke01PFbK{~a4N@j>(x=UGZ9 z^+2N{Y;{WYOHKj`_|VH!sp1K!qDl5o?#8>0fPSt49DMU4(< z>@w7{1Fn7{9KPLb6cw8WmwBA(nNJ<-{I^8#{_-M#C&5o}c)~VHHHrNbkBi*Up&@^^ za`f3~%m)F|h3j!WJrHVYNizn)d3#>dxZ3o@2@~7fWF7Z&zF)k(8FSng_@KU~o2Mw( zWSR@Yq@d-kXS@*cZHjA*3ZJ^MaD0mS-8WoQU;uJY zYCm(tJYNe{3&k+O8P7i;$>|>zdi#lcH1b|Nu&EVF%vAsOZ*jprAp^t=r_OR8L%X8- z`)+4B^xdw+y&hKHL#}G!FjFx}g@jOic%{7~rk^~m?1_%^K})&sv~4%xuG34JAW>^_ zlxO2F3RAW$brulZpnY0iReIBrbkK-CAao?UZJ$Vrl$@&aBOvY1QsCX>z);n!&U+m9 zRQi6<-qXeNzALi(@}iixUmjav`9NGWovvq+x;!a1vQGUzu+iggLCd!Oj{B181FNV` zlvRSULvCHIg7sg~Vjij#C&cPoy$SQO?n>MoY9O{mZ$VQNitqK3P#?nk8=cPuijaS= zE1{^J9r83#%rJbve^kkSvUZ31atr01PVnBTdM7dWMSgZ}!73rDKG7u3mMR{~WT&LL z85R!@PXzs^qmU66I$2d#8!FM>-ppEyZrhEMzG|cvE$8hEyXEU~B+c&|rpkfPkp9+= ztIttyQ@%Lv*_9kct{%8I_HRnJsAiwf{CW#VVxjKxpy~cANdE{ugzM1aI7KNs9PxyW zk1(9+uUK#hgfv(9u11|UMD_G4i=zq(L}$5XcLw7PS{Bzr$G-%h0M5YGoJn+1xDr{DWyK7B(&X`o zh)_R5Rjd6Ez5wr!Bnq&k|1&v+UJw2UIxy?T>3Wy;ToTxk68nctXc0*%M0Xb{}OzH3XT?YvJPRjyvGsza;WHwNBx}C+4#| zOtw+x5O8pDgyoQUp_okg;FR+~S-wo;Y|{Sp8%adQnPSOi=aa;hV`@TZnRTKdJhCs& zO)2yF*Ot&ygj|dz6R}2$lRLi24%?9wH5m3gU{Cmuxu)J z=d20AKIbh5R?ZnDLiZ*Y*vdqjd=BTU?peI<(2^H?0j~TC^vyJ#96fGkTF^*ij0!O( z#~#%CPpzzy1e8pOx4o`s5HA9@X+nZD8opgGn)elNrlzjE33-7^ zxcJL)xXk*cLiqUXyoLU^{o!0;itxnVw`hcXE{OKtCyC7_?}Df63v~Nr>CQX)fOGJS zvkMGQX!nWs@L&XHlcVAjEh*fgk6zW)1W2AI(~M~lashfFx#)Sq8HVX zo(@as+p)C6ratzSAPQ6hbX#qIi9UMh_zy^ozQ3#!OSu6!T+j5>2Uw6&X5+Zi?!&@9wWj~hZ zzH$4Un~?Moxe}Jh!)9+68!P~roZew{_K3obvvdO#MEVC zK5BW`k2LVY4@Ds%Bj4x#*c5j7$WxdXRW?{LnZP)!_Ce9BH;q(GDrMHSp!<72#tcBa)v8q z0e9X^YHgm34UgYu@9QC<1Oa1q*n)T`?rz8t-idgd*G}=mU09fO0Dt0ia(dY*LOdp2J2R?^uO=Ji?ZMpQ@73J-b{T)gOlpnj5`!{}P#RY# zOSb7L0P$9sipcKCv-2H+X3VCaD+k0z>?X{v8wC_K;9P%1NL+mpCZQV7?Y`cI;BPQc zl5nS-Mu<>q_RO7MDSEgM8|FpZ8KBV(=7RE95*z8Q&&Q#_?4}v+Kp$V1okIxtfE49+S%1Sm9?K29EYLU>7aB+8Y z)A`6cg>aMq;EhT0z87o!-qAi-gaqX-)}xl8+Pk%yMQ9qA8@~m2UsLnFE`Dnaz4LNG zaVPfu(CM)Y#z*(CFEKG1JMRsCW!r^T;CzStPp@%Lv&Of7(qdCYn2xb4xoY`HDPm zB}Qnuesm(nJc)URzgB%2FtaD8ZhJztu5|p4R$ad#gmSUX9nGa#P~--a@zZ7dw%B(7 zL{O^iwJFkk)G_2?iZQ2N@NxS4Ge-D1!j3BR1t9{e+#b^+4PF}!`n?~B`feuL{g_|J zHjG?Ckg@L=NfTSk>+9IWLuJ6H&Ne!6B+mr`_V-Kj(E8vT8ymOw4iq;rI`2-%at_e1 z95SY)$%B!y3E9d7pX!C8H(r^2!(7{TSWg#4MkZ`Md?;dhcu#NhoA_n=Ctk^hWkQOQ z1qt|rf8R$4ecVh#{cEQ*SItev-)=E@t}H==`wz6wi6Ve12a5v^OE!L5lDX7ZY6L3#jZoh zQ0;900Cesl9IFu(Lj*lG+M6RatmNh8BX*egt=L7@Hyv`Q&|{;b3aXn>HlEMfAKMjQ z;NGt7--4*fJN0%=#CBJgZrmndh{bGeE8|AnDhUUwCk2J`c%iJIpD*CF zz|{;@G?4`PaHwmju!^-0uC$NJ_epK10!$OlzE81FxCZrs|=t=c@_C$>I`7fY4qXpcEwtTBG|QfK)P z+z<(N(BZ>hm>t#%5cD{bu>YD|%~aOkP7n5@MNO z+6p;H{5tw&(J&)B8)LTsCd|`@jGJ>7-BHDy%w0XFG7Jo*rlvM4;xvoxw2D7qwcyo~ zX1uTGlqIG~PgFwz>yC|sEF01KhP@q27Wng!;{H=%YY!J!NY#|cs_Oyu6&Rji>Jw9; zbrA-LCwQ=kXc1%i`?dzSbh6lo7ZMiXXVX+nLMsMw($q*!S(My2x&*rwK5{xDM4J_j zQcJ)-CGfcU_41NDbkb+<$7J}yv)s)2a4k1&Y;?&|Iv(4P@8X>M_Rb|*+!KQuhTN5{ zt;uMc?WUG~k;Ka!r*>@!dpyLC`_vABIk#bD@VUsswm{B(-o-!71p8IlniP zMa`ybsxHF+x1OGpj`c@YoudLI)KRq>KnnJBw``v$+jTUGcY;{ZY!vA7md zof@8dR#6SI41CTLQZGhb_d+Q2q_A*sm_Zc$3?ipa^k=t9V~nybmWWzN1ON^ewl|3` zO-+*%`SV7sx;??$QF8U>?wu@b1+UektcymX_KyyW1ixnEeAMR8XmQ!h)3Iv9A9s0Q zfZ7k%yI>ox}?KnzRtw2CR-t=Cx$l=0rRG-&qY&^0-uiSW|QER?Bn!|LH~F*pVdVkVvS=T$c((t%QSYT zs|)aU>g4O6`*x`4$0cbxAd#LoXZAfUnr$3oZird>2q8q-$qKTcpVeF&hmB9*bo(qR z?Ekc0-$d9wKcA9jOQ;8qWtdraXs3|L2yk#jZGd(!3bRtWgs!Sw zp^+$Z-pM%?i-uK?2M-dZ2OQb-BkM&)Rp{ScMEr;mUd0yt+oEh3o=RDNZ}zd-HpLyo z=2e5^haq&dA6iJOh_=+ znd_5P4^Qz3!ahW-+{!0ydwX*9dfCbCH+b74*(om-q(CG*FE$b@Z7If^XuFPWepsjO z6BH!@4V5bCYamk(Z5_uvVDb8HLHNA83I+!Bc)c9?KAY68>LW+Gv#}{@Yx^%4@P$Yc zyA#ya*Rx8FSl-+qlpTaCxZ{Wc`_&C~mDYyXWOECnjifF124pOfQ~M}>DmVU3rAy?d zjo7Ba(gWn>cd=&(g^q z8?Z{Z>!v&8X~2NR`UQW)8c`Pgf47}J-bLG=r`p)ZT1WDZz$!y8#@hI!%}v1B#SP)x z-n&;QVz%<^XN^QOwE!Snz>BO;R7{kSr2{6P3+EKuLfkt|*2xT;`Mor}z z+1uMiN5oEb?w|bLXCuHEX_F+J=(&*ND#i8Je)!g~ zEi%M4=kWL5<|u3nmi9w^Wa_%3!iX_4XO`pY+69qt3@^*1F0oP>xUJ6w6Ra|o0wEkdvf zCR8*d0nDigkcZqH9AE_m1WX~3OcFG#9GMX(4z|_{dIJ7pG~xa0bj*szDb#%vlgjv- zOa|BzD9o`3Gs}??k&}~?fH#V4hP2ysdzdrCF#+)r*%4#Qv&pT%va+(SWcoAXFdLj~ z!wIo({roEL(bvT`_wK2utGZ@jwwU)C-*;a(71xJ`NCAu}AfVlve9SpcF4BNN!Z0O@ zKj4kyV1Q4t-7dYw0d)|8{nO(DS4a3$KedB}-lz8Z*+5ybHTd^kqiSwiNINV@Q-L}o zXw**wq9Epyp?=Ia~ZgXk`N~^_#7deb*g?-i=76aMV4>`Q<)lnuT@`<$- zEKS<6bT8Urn};@;7)$4*z<)&^#_s>(X*p^<7KfZS0#bzu z4_1z8|J3E2zQ%B-Q4qGBecXKU?Xu_5cZuu_Tq43u_mSZdf6|zAe@Xbawi)NTn?0ymPeC-+8 zbOtrb)f`iG1RQfesYjk2*b+K5JgM(WX^#hftJg2^OD%_onMl|ZBp&tjTEz13&x%$a&Jn6DDvoNh+(15H8EjZ!Uw1-TU0tv>1Cq_|6pK z4X$>ukYAAp_k8TyBOTqu7J%Lvi~f7g4+W>XGdyV&{*+d?Pl)Il(S`Hn-R(l}LX-+m zi2s3lQ8uZWJ6ZKFpf-lO$xEeSAyiAHfgGVg>VN>~Ds1w4)1*85661&SfvQM|FX=TG zeq*LXpsVF(59+v*R-RrosQwC;W{M*M!`v4iG77|b8mKn3@xekld-<%^@@iRXBDGj6 zjn5`4p7f8wFd?SUCh23eJOYxyF^Lq!9lrul*{rc~_AM`HU?S=eh73Ob6@ut`(Talg zO@A0a7ZP7^7Kgop0i>j|81c0Fo%eyB;J5VyU@SY_W;s&&KMJ|xSRg#qiDe~~EMcSA z#h-Q~QgUj3v6@Fw2&rV4+KZF#6iqbr*Nj^KbN_IqJN}0Q81ruzW}YGPpqK>%z}yKR zZ8p=q>Wkb5Vl1Pt@S6|{2?vSe!~YCm{~Tk)Ql5Hi!uXM-*Ym3I8Uz0I{i(Eo{&-a-WSX5P6xPrnwL`qyyq#Ovd{FF(1&)GLYYGcgICeEIX65_hJ*3~MATnV; z06jMXPUXVFtH=~$bw33_B}pq`&S^K&1>*O$dbj&+THdH%h>esmjzwmfIXuclB-&j(?q9e2A3@F4?07cUZ`0c}-T?pGhfJB(##lWUW+BwfL7NhFLMA zaZFP5*KZ)rBnf%r4lRM#eu-WPhcr2mAx{NC`sZ6X)&TXb@sS ztl;?1nLVc9)Yfo^A}-LevB@Ya{OpFm8E#|?KPM6U+2JkQDw2Vr;lZrrBEgExxf**6 z5;!ajRIHX)C@eoFZVsYCtoZ&^q0BE|>6LVUy(7K)4d0)kIQbP?hR zcencPU)C{xy04V4Qe8nIT?O85A8`f+C7#tk6>@czmZn*^>GQZL?v*cEM-|sp?Bfb3 zzuowjuBKP6mMR`8jwdjj)3Zmiqf>so0+F>?zduH?M5G?fS$zfd)hxBn%0AU@n@HN@ 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

        C$0(d+fE={jUa{eP{gU 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 M!qmou1oKSz19$wAF8}}l From 6d87a7347f658a4df08b9d8544a39e70b50440fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 2 Aug 2018 12:31:32 +0200 Subject: [PATCH 32/47] Remove a nocommit logging --- solr/webapp/web/js/angular/controllers/cloud.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index c0458613fa6a..eae2de83ebfb 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -306,11 +306,6 @@ var nodesSubController = function($scope, Collections, System, Metrics) { nodesToShow.sort(); hostsToShow.sort(); -/* NOCOMMIT: Remove debug */ - console.log("***Initialized paging. filterType=" + $scope.filterType + ", statusFilter=" + JSON.stringify($scope.pagingStatusFilter, undefined, 2) + ", nodeFilter=" + JSON.stringify($scope.nodeFilter, undefined, 2) + - ", collectionFilter=" + JSON.stringify($scope.collectionFilter, undefined, 2) + ", pageSize=" + pageSize + ", from=" + $scope.from + ", nodesParam=" + nodesParam + - ", all nodes=" + node_keys); - System.get({"nodes": nodesParam}, function (systemResponse) { for (var node in systemResponse) { if (node in nodes) { From a53df3d5fc71fb77fb4d763286b0d2292393ff70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 2 Aug 2018 14:15:20 +0200 Subject: [PATCH 33/47] Fix test proxySystemInfoHandlerOneNode to fetch live nodes from clusterStateProvider --- .../org/apache/solr/handler/admin/AdminHandlersProxyTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/solr/core/src/test/org/apache/solr/handler/admin/AdminHandlersProxyTest.java b/solr/core/src/test/org/apache/solr/handler/admin/AdminHandlersProxyTest.java index 78e9ba9be653..e68438b6ce22 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/AdminHandlersProxyTest.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/AdminHandlersProxyTest.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.util.Collections; +import java.util.concurrent.TimeUnit; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.lucene.util.IOUtils; @@ -52,6 +53,7 @@ public static void setupCluster() throws Exception { public void setUp() throws Exception { super.setUp(); solrClient = getCloudSolrClient(cluster); + solrClient.connect(1000, TimeUnit.MILLISECONDS); httpClient = (CloseableHttpClient) solrClient.getHttpClient(); } @@ -96,7 +98,7 @@ public void proxySystemInfoHandlerNonExistingNode() throws IOException, SolrServ @Test public void proxySystemInfoHandlerOneNode() { - solrClient.getZkStateReader().getClusterState().getLiveNodes().forEach(node -> { + solrClient.getClusterStateProvider().getLiveNodes().forEach(node -> { MapSolrParams params = new MapSolrParams(Collections.singletonMap("nodes", node)); GenericSolrRequest req = new GenericSolrRequest(SolrRequest.METHOD.GET, "/admin/info/system", params); SimpleSolrResponse rsp = null; From 04e3234c26f253ddf5971f77e713819c82e028d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 2 Aug 2018 14:30:05 +0200 Subject: [PATCH 34/47] Assert liveNodes --- .../apache/solr/handler/admin/AdminHandlersProxyTest.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/solr/core/src/test/org/apache/solr/handler/admin/AdminHandlersProxyTest.java b/solr/core/src/test/org/apache/solr/handler/admin/AdminHandlersProxyTest.java index e68438b6ce22..93cbe3e8df4f 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/AdminHandlersProxyTest.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/AdminHandlersProxyTest.java @@ -19,6 +19,7 @@ import java.io.IOException; import java.util.Collections; +import java.util.Set; import java.util.concurrent.TimeUnit; import org.apache.http.impl.client.CloseableHttpClient; @@ -98,7 +99,9 @@ public void proxySystemInfoHandlerNonExistingNode() throws IOException, SolrServ @Test public void proxySystemInfoHandlerOneNode() { - solrClient.getClusterStateProvider().getLiveNodes().forEach(node -> { + Set nodes = solrClient.getClusterStateProvider().getLiveNodes(); + assertEquals(2, nodes.size()); + nodes.forEach(node -> { MapSolrParams params = new MapSolrParams(Collections.singletonMap("nodes", node)); GenericSolrRequest req = new GenericSolrRequest(SolrRequest.METHOD.GET, "/admin/info/system", params); SimpleSolrResponse rsp = null; From 91a135e8a27b1b241b52dcaaff1b99337ebeef6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 2 Aug 2018 14:44:23 +0200 Subject: [PATCH 35/47] Add Changes entry --- solr/CHANGES.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 2d8db8c0f2c8..24fb5ec8720a 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -123,6 +123,8 @@ New Features * SOLR-12536: autoscaling policy support to equally distribute replicas on the basis of arbitrary properties (noble) +* SOLR-8207: Add "Nodes" tab to the Admin UI "Cloud" view, listing all nodes with info and metrics (janhoy) + * SOLR-11990: Make it possible to co-locate replicas of multiple collections together in a node. A collection may be co-located with another collection during collection creation time by specifying a 'withCollection' parameter. It can also be co-located afterwards by using the modify collection API. The co-location guarantee is enforced regardless of From 0c59e285074ef3be89fbb7b2ed715c1b1100b15c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 2 Aug 2018 14:49:06 +0200 Subject: [PATCH 36/47] Remove remnants of radial graph. Keep "graph" view as default for now --- solr/webapp/web/css/angular/menu.css | 1 - .../web/js/angular/controllers/cloud.js | 74 ++----------------- solr/webapp/web/partials/cloud.html | 2 +- 3 files changed, 6 insertions(+), 71 deletions(-) diff --git a/solr/webapp/web/css/angular/menu.css b/solr/webapp/web/css/angular/menu.css index ba5e0b6a42ab..8332a8023155 100644 --- a/solr/webapp/web/css/angular/menu.css +++ b/solr/webapp/web/css/angular/menu.css @@ -262,7 +262,6 @@ limitations under the License. #menu #cloud.global .tree a { background-image: url( ../../img/ico/folder-tree.png ); } #menu #cloud.global .nodes a { background-image: url( ../../img/solr-ico.png ); } #menu #cloud.global .graph a { background-image: url( ../../img/ico/molecule.png ); } -#menu #cloud.global .rgraph a { background-image: url( ../../img/ico/asterisk.png ); } .sub-menu .ping.error a { diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index eae2de83ebfb..a1cb711f349b 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -28,13 +28,10 @@ solrAdminApp.controller('CloudController', $scope.showDebug = false; }; - var view = $location.search().view ? $location.search().view : "nodes"; + var view = $location.search().view ? $location.search().view : "graph"; if (view == "tree") { $scope.resetMenu("cloud-tree", Constants.IS_ROOT_PAGE); treeSubController($scope, Zookeeper); - } else if (view == "rgraph") { - $scope.resetMenu("cloud-rgraph", Constants.IS_ROOT_PAGE); - graphSubController($scope, Zookeeper, true); } else if (view == "graph") { $scope.resetMenu("cloud-graph", Constants.IS_ROOT_PAGE); graphSubController($scope, Zookeeper, false); @@ -516,7 +513,7 @@ function secondsForHumans ( seconds ) { return returntext.trim() === '' ? '0m' : returntext.trim(); } -var graphSubController = function ($scope, Zookeeper, isRadial) { +var graphSubController = function ($scope, Zookeeper) { $scope.showTree = false; $scope.showGraph = true; @@ -671,7 +668,7 @@ var graphSubController = function ($scope, Zookeeper, isRadial) { $scope.helperData.state = $.unique($scope.helperData.state); $scope.helperData.core_node = $.unique($scope.helperData.core_node); - if (!isRadial && data.znode && data.znode.paging) { + if (data.znode && data.znode.paging) { $scope.showPaging = true; var parr = data.znode.paging.split('|'); @@ -705,7 +702,6 @@ var graphSubController = function ($scope, Zookeeper, isRadial) { } $scope.graphData = graph_data; $scope.leafCount = leaf_count; - $scope.isRadial = isRadial; }); }); }; @@ -721,7 +717,6 @@ solrAdminApp.directive('graph', function(Constants) { data: "=", leafCount: "=", helperData: "=", - isRadial: "=" }, link: function (scope, element, attrs) { var helper_path_class = function (p) { @@ -804,11 +799,7 @@ solrAdminApp.directive('graph', function(Constants) { scope.$watch("data", function(newValue, oldValue) { if (newValue) { - if (scope.isRadial) { - radialGraph(element, scope.data, scope.leafCount); - } else { - flatGraph(element, scope.data, scope.leafCount); - } + flatGraph(element, scope.data, scope.leafCount); } $('text').tooltip({ @@ -895,61 +886,6 @@ solrAdminApp.directive('graph', function(Constants) { setNodeNavigationBehavior(node); }; - - var radialGraph = function(element, graphData, leafCount) { - var max_val = Math.min(element.width(), $('body').height()) - var r = max_val / 2; - - var cluster = d3.layout.cluster() - .size([360, r - 160]); - - var diagonal = d3.svg.diagonal.radial() - .projection(function (d) { - return [d.y, d.x / 180 * Math.PI]; - }); - - d3.select('#canvas', element).html(''); - var vis = d3.select('#canvas').append('svg') - .attr('width', r * 2) - .attr('height', r * 2) - .append('g') - .attr('transform', 'translate(' + r + ',' + r + ')'); - - var nodes = cluster.nodes(graphData); - - var link = vis.selectAll('path.link') - .data(cluster.links(nodes)) - .enter().append('path') - .attr('class', helper_path_class) - .attr('d', diagonal); - - var node = vis.selectAll('g.node') - .data(nodes) - .enter().append('g') - .attr('class', helper_node_class) - .attr('transform', function (d) { - return 'rotate(' + (d.x - 90) + ')translate(' + d.y + ')'; - }) - - node.append('circle') - .attr('r', 4.5); - - node.append('text') - .attr('dx', function (d) { - return d.x < 180 ? 8 : -8; - }) - .attr('dy', '.31em') - .attr('text-anchor', function (d) { - return d.x < 180 ? 'start' : 'end'; - }) - .attr('transform', function (d) { - return d.x < 180 ? null : 'rotate(180)'; - }) - .attr("title", helper_tooltip_text) - .text(helper_node_text); - - setNodeNavigationBehavior(node, "rgraph"); - } } }; -}) +}); diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index 078c9af40b7e..bcda75b512a7 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -180,7 +180,7 @@

    • -
      +
      From 321a91a9d99e0b718fdf3d78cb32df4a2783f234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 2 Aug 2018 15:23:25 +0200 Subject: [PATCH 37/47] Make nodes screenshot larger in guide --- solr/solr-ref-guide/src/cloud-screens.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solr/solr-ref-guide/src/cloud-screens.adoc b/solr/solr-ref-guide/src/cloud-screens.adoc index 4fc92085edca..4d9af4fdf922 100644 --- a/solr/solr-ref-guide/src/cloud-screens.adoc +++ b/solr/solr-ref-guide/src/cloud-screens.adoc @@ -30,7 +30,7 @@ Click on the Cloud option in the left-hand navigation, and a small sub-menu appe The example below shows the default "cloud" example with some documents added to the "gettingstarted" collection. Details are expanded for node on port 7574, showing more metadata and more metrics details. The screen provides links to navigate to nodes, collections and replicas. The table supports paging and filtering on host/node names and collection names. -image::images/cloud-screens/cloud-nodes.png[image,width=512,height=236] +image::images/cloud-screens/cloud-nodes.png[image,width=900,height=415] The ("Graph") view shows a graph of each collection, the shards that make up those collections, and the addresses and type ("NRT", "TLOG" or "PULL") of each replica for each shard. From 739056961f16219d1556a4e66b2cae3690f0adc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 2 Aug 2018 15:42:41 +0200 Subject: [PATCH 38/47] Fix JS warning, use !== instead of != --- solr/webapp/web/js/angular/controllers/cloud.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index a1cb711f349b..f1565e0658aa 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -267,7 +267,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { nodesCollections.push(nodeColl); } nodesCollections.forEach(function(nc) { - matchingColls = nc['collections'].filter(co => co.indexOf($scope.collectionFilter) != -1); + matchingColls = nc['collections'].filter(co => co.indexOf($scope.collectionFilter) !== -1); if (matchingColls.length > 0) { candidateNodes[nc.node] = true; } From 653c7e50a1ec0c1d1c661edd9ed191ea42bd1786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 2 Aug 2018 16:49:04 +0200 Subject: [PATCH 39/47] Fix more JS warnings, change several var -> let/const etc. --- .../web/js/angular/controllers/cloud.js | 215 +++++++++--------- 1 file changed, 107 insertions(+), 108 deletions(-) diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index f1565e0658aa..d1d2745f4c39 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -28,14 +28,14 @@ solrAdminApp.controller('CloudController', $scope.showDebug = false; }; - var view = $location.search().view ? $location.search().view : "graph"; - if (view == "tree") { + let view = $location.search().view ? $location.search().view : "graph"; + if (view === "tree") { $scope.resetMenu("cloud-tree", Constants.IS_ROOT_PAGE); treeSubController($scope, Zookeeper); - } else if (view == "graph") { + } else if (view === "graph") { $scope.resetMenu("cloud-graph", Constants.IS_ROOT_PAGE); graphSubController($scope, Zookeeper, false); - } else if (view == "nodes") { + } else if (view === "nodes") { $scope.resetMenu("cloud-nodes", Constants.IS_ROOT_PAGE); nodesSubController($scope, Collections, System, Metrics); } @@ -69,28 +69,28 @@ function ensureInList(string, list) { } /* Puts a node name into the hosts structure */ -var ensureNodeInHosts = function (node_name, hosts) { - var hostName = node_name.split(":")[0]; - var host = getOrCreateObj(hostName, hosts); - var hostNodes = getOrCreateList("nodes", host); +function ensureNodeInHosts(node_name, hosts) { + let hostName = node_name.split(":")[0]; + let host = getOrCreateObj(hostName, hosts); + let hostNodes = getOrCreateList("nodes", host); ensureInList(node_name, hostNodes); -}; +} // from http://scratch99.com/web-development/javascript/convert-bytes-to-mb-kb/ function bytesToSize(bytes) { - var sizes = ['b', 'Kb', 'Mb', 'Gb', 'Tb']; - if (bytes === 0) return '0b'; - var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); - if (bytes === 0) return bytes + '' + sizes[i]; - return (bytes / Math.pow(1024, i)).toFixed(1) + '' + sizes[i]; + const sizes = ['b', 'Kb', 'Mb', 'Gb', 'Tb']; + if (bytes === 0) return '0b'; + let i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); + if (bytes === 0) return bytes + '' + sizes[i]; + return (bytes / Math.pow(1024, i)).toFixed(1) + '' + sizes[i]; } function numDocsHuman(docs) { - var sizes = ['', 'k', 'mn', 'bn', 'tn']; - if (docs === 0) return '0'; - var i = parseInt(Math.floor(Math.log(docs) / Math.log(1000))); - if (i === 0) return docs + '' + sizes[i]; - return (docs / Math.pow(1000, i)).toFixed(1) + '' + sizes[i]; + const sizes = ['', 'k', 'mn', 'bn', 'tn']; + if (docs === 0) return '0'; + let i = parseInt(Math.floor(Math.log(docs) / Math.log(1000))); + if (i === 0) return docs + '' + sizes[i]; + return (docs / Math.pow(1000, i)).toFixed(1) + '' + sizes[i]; } /* Returns a style class depending on percentage */ @@ -118,10 +118,10 @@ var nodesSubController = function($scope, Collections, System, Metrics) { $scope.toggleAllDetails = function() { $scope.showAllDetails = !$scope.showAllDetails; - for (var node in $scope.nodes) { + for (let node in $scope.nodes) { $scope.showDetails[node] = $scope.showAllDetails; } - for (var host in $scope.hosts) { + for (let host in $scope.hosts) { $scope.showDetails[host] = $scope.showAllDetails; } }; @@ -132,8 +132,8 @@ var nodesSubController = function($scope, Collections, System, Metrics) { $scope.toggleHostDetails = function(key) { $scope.showDetails[key] = !$scope.showDetails[key] === true; - for (var nodeId in $scope.hosts[key].nodes) { - var node = $scope.hosts[key].nodes[nodeId]; + for (let nodeId in $scope.hosts[key].nodes) { + let node = $scope.hosts[key].nodes[nodeId]; $scope.showDetails[node] = $scope.showDetails[key]; } }; @@ -149,46 +149,46 @@ var nodesSubController = function($scope, Collections, System, Metrics) { }; $scope.isFirstNodeForHost = function(node) { - var hostName = node.split(":")[0]; - var nodesInHost = $scope.filteredNodes.filter(no => no.startsWith(hostName)); + let hostName = node.split(":")[0]; + let nodesInHost = $scope.filteredNodes.filter(no => no.startsWith(hostName)); return nodesInHost[0] === node; }; // Initializes the cluster state, list of nodes, collections etc $scope.initClusterState = function() { - var nodes = {}; - var hosts = {}; - var live_nodes = []; + let nodes = {}; + let hosts = {}; + let live_nodes = []; Collections.status(function (data) { - // Fetch cluster state from collections API and invert to a nodes structure - for (var name in data.cluster.collections) { - var collection = data.cluster.collections[name]; + let node; +// Fetch cluster state from collections API and invert to a nodes structure + for (let name in data.cluster.collections) { + let collection = data.cluster.collections[name]; collection.name = name; - var shards = collection.shards; + let shards = collection.shards; collection.shards = []; - for (var shardName in shards) { - var shard = shards[shardName]; + for (let shardName in shards) { + let shard = shards[shardName]; shard.name = shardName; shard.collection = collection.name; - var replicas = shard.replicas; + let replicas = shard.replicas; shard.replicas = []; - for (var replicaName in replicas) { - var core = replicas[replicaName]; + for (let replicaName in replicas) { + let core = replicas[replicaName]; core.name = replicaName; core.collection = collection.name; core.shard = shard.name; core.shard_state = shard.state; - var node_name = core['node_name']; - var node = getOrCreateObj(node_name, nodes); - var cores = getOrCreateList("cores", node); + let node_name = core['node_name']; + node = getOrCreateObj(node_name, nodes); + let cores = getOrCreateList("cores", node); cores.push(core); node['base_url'] = core.base_url; node['id'] = core.base_url.replace(/[^\w\d]/g, ''); - var hostName = node_name.split(":")[0]; - node['host'] = hostName; - var collections = getOrCreateList("collections", node); + node['host'] = node_name.split(":")[0]; + let collections = getOrCreateList("collections", node); ensureInList(core.collection, collections); ensureNodeInHosts(node_name, hosts); } @@ -197,9 +197,9 @@ var nodesSubController = function($scope, Collections, System, Metrics) { live_nodes = data.cluster.live_nodes; for (n in data.cluster.live_nodes) { - var node = data.cluster.live_nodes[n]; + node = data.cluster.live_nodes[n]; if (!(node in nodes)) { - var hostName = node.split(":")[0]; + let hostName = node.split(":")[0]; nodes[node] = {}; nodes[node]['host'] = hostName; } @@ -207,7 +207,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { } // Make sure nodes are sorted alphabetically to align with rowspan in table - for (var host in hosts) { + for (let host in hosts) { hosts[host].nodes.sort(); } @@ -224,25 +224,24 @@ var nodesSubController = function($scope, Collections, System, Metrics) { $scope.from = 0; $scope.to = $scope.pageSize - 1; $scope.reload(); - } + }; $scope.reload = function() { - var nodes = $scope.nodes; - var node_keys = Object.keys(nodes); - var hosts = $scope.hosts; - var live_nodes = $scope.live_nodes; - var hostNames = Object.keys(hosts); - var filteredHosts; + let nodes = $scope.nodes; + let node_keys = Object.keys(nodes); + let hosts = $scope.hosts; + let live_nodes = $scope.live_nodes; + let hostNames = Object.keys(hosts); hostNames.sort(); - var pageSize = isNumeric($scope.pageSize) ? $scope.pageSize : 10; + let pageSize = isNumeric($scope.pageSize) ? $scope.pageSize : 10; // Calculate what nodes that will show on this page - var nodesToShow = []; - var nodesParam = ''; - var hostsToShow = []; - var filteredNodes; - var filteredHosts; - var isFiltered = false; + let nodesToShow = []; + let nodesParam = ''; + let hostsToShow = []; + let filteredNodes; + let filteredHosts; + let isFiltered = false; switch ($scope.filterType) { case "node": if ($scope.nodeFilter) { @@ -254,9 +253,9 @@ var nodesSubController = function($scope, Collections, System, Metrics) { if ($scope.collectionFilter) { candidateNodes = {}; nodesCollections = []; - for (var i = 0 ; i < node_keys.length ; i++) { - var node_name = node_keys[i]; - var node = nodes[node_name]; + for (let i = 0 ; i < node_keys.length ; i++) { + let node_name = node_keys[i]; + let node = nodes[node_name]; nodeColl = {}; nodeColl['node'] = node_name; collections = {}; @@ -281,15 +280,15 @@ var nodesSubController = function($scope, Collections, System, Metrics) { } if (filteredNodes) { isFiltered = true; - filteredHosts = filteredNodes.map(nod => nod.split(":")[0]).filter((item,index,self) => self.indexOf(item)==index); + filteredHosts = filteredNodes.map(nod => nod.split(":")[0]).filter((item,index,self) => self.indexOf(item)===index); } else { filteredNodes = node_keys; filteredHosts = hostNames; } filteredNodes.sort(); filteredHosts.sort(); - for (var id = $scope.from ; id < $scope.from + pageSize && filteredHosts[id] ; id++) { - var hostName = filteredHosts[id]; + for (let id = $scope.from ; id < $scope.from + pageSize && filteredHosts[id] ; id++) { + let hostName = filteredHosts[id]; hostsToShow.push(hostName); if (isFiltered) { // Only show the nodes per host matching active filter nodesToShow = nodesToShow.concat(filteredNodes.filter(nod => nod.startsWith(hostName))); @@ -304,29 +303,29 @@ var nodesSubController = function($scope, Collections, System, Metrics) { hostsToShow.sort(); System.get({"nodes": nodesParam}, function (systemResponse) { - for (var node in systemResponse) { + for (let node in systemResponse) { if (node in nodes) { - var s = systemResponse[node]; + const s = systemResponse[node]; nodes[node]['system'] = s; - var memTotal = s.system.totalPhysicalMemorySize; - var memFree = s.system.freePhysicalMemorySize; - var memPercentage = Math.floor((memTotal - memFree) / memTotal * 100); + const memTotal = s.system.totalPhysicalMemorySize; + const memFree = s.system.freePhysicalMemorySize; + const memPercentage = Math.floor((memTotal - memFree) / memTotal * 100); nodes[node]['memUsedPct'] = memPercentage; nodes[node]['memUsedPctStyle'] = styleForPct(memPercentage); nodes[node]['memTotal'] = bytesToSize(memTotal); nodes[node]['memFree'] = bytesToSize(memFree); nodes[node]['memUsed'] = bytesToSize(memTotal - memFree); - var heapTotal = s.jvm.memory.raw.total; - var heapFree = s.jvm.memory.raw.free; - var heapPercentage = Math.floor((heapTotal - heapFree) / heapTotal * 100); + const heapTotal = s.jvm.memory.raw.total; + const heapFree = s.jvm.memory.raw.free; + const heapPercentage = Math.floor((heapTotal - heapFree) / heapTotal * 100); nodes[node]['heapUsed'] = bytesToSize(heapTotal - heapFree); nodes[node]['heapUsedPct'] = heapPercentage; nodes[node]['heapUsedPctStyle'] = styleForPct(heapPercentage); nodes[node]['heapTotal'] = bytesToSize(heapTotal); nodes[node]['heapFree'] = bytesToSize(heapFree); - var jvmUptime = s.jvm.jmx.upTimeMS / 1000; // Seconds + const jvmUptime = s.jvm.jmx.upTimeMS / 1000; // Seconds nodes[node]['jvmUptime'] = secondsForHumans(jvmUptime); nodes[node]['jvmUptimeSec'] = jvmUptime; @@ -345,19 +344,19 @@ var nodesSubController = function($scope, Collections, System, Metrics) { "prefix": "CONTAINER.fs,org.eclipse.jetty.server.handler.DefaultHandler.get-requests,INDEX.sizeInBytes,SEARCHER.searcher.numDocs,SEARCHER.searcher.deletedDocs,SEARCHER.searcher.warmupTime" }, function (metricsResponse) { - for (var node in metricsResponse) { + for (let node in metricsResponse) { if (node in nodes) { - var m = metricsResponse[node]; + let m = metricsResponse[node]; nodes[node]['metrics'] = m; - var diskTotal = m.metrics['solr.node']['CONTAINER.fs.totalSpace']; - var diskFree = m.metrics['solr.node']['CONTAINER.fs.usableSpace']; - var diskPercentage = Math.floor((diskTotal - diskFree) / diskTotal * 100); + let diskTotal = m.metrics['solr.node']['CONTAINER.fs.totalSpace']; + let diskFree = m.metrics['solr.node']['CONTAINER.fs.usableSpace']; + let diskPercentage = Math.floor((diskTotal - diskFree) / diskTotal * 100); nodes[node]['diskUsedPct'] = diskPercentage; nodes[node]['diskUsedPctStyle'] = styleForPct(diskPercentage); nodes[node]['diskTotal'] = bytesToSize(diskTotal); nodes[node]['diskFree'] = bytesToSize(diskFree); - var r = m.metrics['solr.jetty']['org.eclipse.jetty.server.handler.DefaultHandler.get-requests']; + let r = m.metrics['solr.jetty']['org.eclipse.jetty.server.handler.DefaultHandler.get-requests']; nodes[node]['req'] = r.count; nodes[node]['req1minRate'] = Math.floor(r['1minRate'] * 100) / 100; nodes[node]['req5minRate'] = Math.floor(r['5minRate'] * 100) / 100; @@ -366,38 +365,38 @@ var nodesSubController = function($scope, Collections, System, Metrics) { nodes[node]['reqp95_ms'] = Math.floor(r['p95_ms']); nodes[node]['reqp99_ms'] = Math.floor(r['p99_ms']); - var cores = nodes[node]['cores']; - var indexSizeTotal = 0; - var docsTotal = 0; - var graphData = []; + let cores = nodes[node]['cores']; + let indexSizeTotal = 0; + let docsTotal = 0; + let graphData = []; if (cores) { for (coreId in cores) { - var core = cores[coreId]; - var keyName = "solr.core." + core['core'].replace('_', '.').replace('_', '.'); - var nodeMetric = m.metrics[keyName]; - var size = nodeMetric['INDEX.sizeInBytes']; - size = (typeof size != 'undefined') ? size : 0; + let core = cores[coreId]; + let keyName = "solr.core." + core['core'].replace('_', '.').replace('_', '.'); + let nodeMetric = m.metrics[keyName]; + let size = nodeMetric['INDEX.sizeInBytes']; + size = (typeof size !== 'undefined') ? size : 0; core['sizeInBytes'] = size; core['size'] = bytesToSize(size); core['label'] = core['core'].replace('_shard', '_s').replace(/_replica_./, 'r'); indexSizeTotal += size; - var numDocs = nodeMetric['SEARCHER.searcher.numDocs']; - numDocs = (typeof numDocs != 'undefined') ? numDocs : 0; + let numDocs = nodeMetric['SEARCHER.searcher.numDocs']; + numDocs = (typeof numDocs !== 'undefined') ? numDocs : 0; core['numDocs'] = numDocs; core['numDocsHuman'] = numDocsHuman(numDocs); - core['avgSizePerDoc'] = bytesToSize(numDocs == 0 ? 0 : size / numDocs); - var deletedDocs = nodeMetric['SEARCHER.searcher.deletedDocs']; - deletedDocs = (typeof deletedDocs != 'undefined') ? deletedDocs : 0; + core['avgSizePerDoc'] = bytesToSize(numDocs === 0 ? 0 : size / numDocs); + let deletedDocs = nodeMetric['SEARCHER.searcher.deletedDocs']; + deletedDocs = (typeof deletedDocs !== 'undefined') ? deletedDocs : 0; core['deletedDocs'] = deletedDocs; core['deletedDocsHuman'] = numDocsHuman(deletedDocs); - var warmupTime = nodeMetric['SEARCHER.searcher.warmupTime']; - warmupTime = (typeof warmupTime != 'undefined') ? warmupTime : 0; + let warmupTime = nodeMetric['SEARCHER.searcher.warmupTime']; + warmupTime = (typeof warmupTime !== 'undefined') ? warmupTime : 0; core['warmupTime'] = warmupTime; docsTotal += core['numDocs']; } for (coreId in cores) { - var core = cores[coreId]; - var graphObj = {}; + let core = cores[coreId]; + let graphObj = {}; graphObj['label'] = core['label']; graphObj['size'] = core['sizeInBytes']; graphObj['sizeHuman'] = core['size']; @@ -421,15 +420,15 @@ var nodesSubController = function($scope, Collections, System, Metrics) { // Add the div containing the whole chart $('#chart' + nodes[node]['id']).empty(); - var chart = d3.select('#chart' + nodes[node]['id']).append('div').attr('class', 'chart'); + let chart = d3.select('#chart' + nodes[node]['id']).append('div').attr('class', 'chart'); // Add one div per bar which will group together both labels and bars - var g = chart.selectAll('div') + let g = chart.selectAll('div') .data(nodes[node]['graphData']).enter() .append('div'); // Add the bars - var bars = g.append("div") + let bars = g.append("div") .attr("class", "rect") .text(function (d) { return d.label + ':\u00A0\u00A0' + d.sizeHuman; @@ -498,15 +497,15 @@ var treeSubController = function($scope, Zookeeper) { * @return {string} The phrase describing the the amount of time */ function secondsForHumans ( seconds ) { - var levels = [ + let levels = [ [Math.floor(seconds / 31536000), 'y'], [Math.floor((seconds % 31536000) / 86400), 'd'], [Math.floor(((seconds % 31536000) % 86400) / 3600), 'h'], [Math.floor((((seconds % 31536000) % 86400) % 3600) / 60), 'm'] ]; - var returntext = ''; + let returntext = ''; - for (var i = 0, max = levels.length; i < max; i++) { + for (let i = 0, max = levels.length; i < max; i++) { if ( levels[i][0] === 0 ) continue; returntext += ' ' + levels[i][0] + levels[i][1]; } @@ -536,17 +535,17 @@ var graphSubController = function ($scope, Zookeeper) { $scope.next = function() { $scope.pos += $scope.rows; $scope.initGraph(); - } + }; $scope.previous = function() { $scope.pos = Math.max(0, $scope.pos - $scope.rows); $scope.initGraph(); - } + }; $scope.resetGraph = function() { $scope.pos = 0; $scope.initGraph(); - } + }; $scope.initGraph = function() { Zookeeper.liveNodes(function (data) { From 63cc5d8b1ae2dcfe55207c159363048009b064f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Thu, 2 Aug 2018 16:50:33 +0200 Subject: [PATCH 40/47] Whitespace fixes --- .../web/js/angular/controllers/cloud.js | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index d1d2745f4c39..771e9c6a2d79 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -43,29 +43,29 @@ solrAdminApp.controller('CloudController', ); function getOrCreateObj(name, object) { - if (name in object) { - entry = object[name]; - } else { - entry = {}; - object[name] = entry; - } - return entry; + if (name in object) { + entry = object[name]; + } else { + entry = {}; + object[name] = entry; + } + return entry; } function getOrCreateList(name, object) { - if (name in object) { - entry = object[name]; - } else { - entry = []; - object[name] = entry; - } - return entry; + if (name in object) { + entry = object[name]; + } else { + entry = []; + object[name] = entry; + } + return entry; } function ensureInList(string, list) { - if (list.indexOf(string) === -1) { - list.push(string); - } + if (list.indexOf(string) === -1) { + list.push(string); + } } /* Puts a node name into the hosts structure */ @@ -442,7 +442,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { }); } } - }); + }); $scope.nodes = nodes; $scope.hosts = hosts; $scope.live_nodes = live_nodes; From 5844c802383f0f1a1b51c9591d0bb2bd50641f9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Fri, 3 Aug 2018 09:51:56 +0200 Subject: [PATCH 41/47] Revert some let/const changes --- solr/webapp/web/js/angular/controllers/cloud.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index 771e9c6a2d79..85d0b8bd9416 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -210,7 +210,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { for (let host in hosts) { hosts[host].nodes.sort(); } - + $scope.nodes = nodes; $scope.hosts = hosts; $scope.live_nodes = live_nodes; @@ -225,7 +225,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { $scope.to = $scope.pageSize - 1; $scope.reload(); }; - + $scope.reload = function() { let nodes = $scope.nodes; let node_keys = Object.keys(nodes); @@ -248,7 +248,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { filteredNodes = node_keys.filter(nod => nod.indexOf($scope.nodeFilter) !== -1); } break; - + case "collection": if ($scope.collectionFilter) { candidateNodes = {}; @@ -260,9 +260,9 @@ var nodesSubController = function($scope, Collections, System, Metrics) { nodeColl['node'] = node_name; collections = {}; node.cores.forEach(function(core) { - collections[core.collection] = true; + collections[core.collection] = true; }); - nodeColl['collections'] = Object.keys(collections); + nodeColl['collections'] = Object.keys(collections); nodesCollections.push(nodeColl); } nodesCollections.forEach(function(nc) { @@ -274,9 +274,9 @@ var nodesSubController = function($scope, Collections, System, Metrics) { filteredNodes = Object.keys(candidateNodes); } break; - + case "health": - + } if (filteredNodes) { isFiltered = true; From 4f622cc321a86915870f850f47fd57eea3b7eba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Fri, 3 Aug 2018 09:52:31 +0200 Subject: [PATCH 42/47] Revert let/const changes from 653c7e5 --- .../web/js/angular/controllers/cloud.js | 182 +++++++++--------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index 85d0b8bd9416..a21e4df13205 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -28,7 +28,7 @@ solrAdminApp.controller('CloudController', $scope.showDebug = false; }; - let view = $location.search().view ? $location.search().view : "graph"; + var view = $location.search().view ? $location.search().view : "graph"; if (view === "tree") { $scope.resetMenu("cloud-tree", Constants.IS_ROOT_PAGE); treeSubController($scope, Zookeeper); @@ -70,25 +70,25 @@ function ensureInList(string, list) { /* Puts a node name into the hosts structure */ function ensureNodeInHosts(node_name, hosts) { - let hostName = node_name.split(":")[0]; - let host = getOrCreateObj(hostName, hosts); - let hostNodes = getOrCreateList("nodes", host); + var hostName = node_name.split(":")[0]; + var host = getOrCreateObj(hostName, hosts); + var hostNodes = getOrCreateList("nodes", host); ensureInList(node_name, hostNodes); } // from http://scratch99.com/web-development/javascript/convert-bytes-to-mb-kb/ function bytesToSize(bytes) { - const sizes = ['b', 'Kb', 'Mb', 'Gb', 'Tb']; + var sizes = ['b', 'Kb', 'Mb', 'Gb', 'Tb']; if (bytes === 0) return '0b'; - let i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); + var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); if (bytes === 0) return bytes + '' + sizes[i]; return (bytes / Math.pow(1024, i)).toFixed(1) + '' + sizes[i]; } function numDocsHuman(docs) { - const sizes = ['', 'k', 'mn', 'bn', 'tn']; + var sizes = ['', 'k', 'mn', 'bn', 'tn']; if (docs === 0) return '0'; - let i = parseInt(Math.floor(Math.log(docs) / Math.log(1000))); + var i = parseInt(Math.floor(Math.log(docs) / Math.log(1000))); if (i === 0) return docs + '' + sizes[i]; return (docs / Math.pow(1000, i)).toFixed(1) + '' + sizes[i]; } @@ -118,10 +118,10 @@ var nodesSubController = function($scope, Collections, System, Metrics) { $scope.toggleAllDetails = function() { $scope.showAllDetails = !$scope.showAllDetails; - for (let node in $scope.nodes) { + for (var node in $scope.nodes) { $scope.showDetails[node] = $scope.showAllDetails; } - for (let host in $scope.hosts) { + for (var host in $scope.hosts) { $scope.showDetails[host] = $scope.showAllDetails; } }; @@ -132,8 +132,8 @@ var nodesSubController = function($scope, Collections, System, Metrics) { $scope.toggleHostDetails = function(key) { $scope.showDetails[key] = !$scope.showDetails[key] === true; - for (let nodeId in $scope.hosts[key].nodes) { - let node = $scope.hosts[key].nodes[nodeId]; + for (var nodeId in $scope.hosts[key].nodes) { + var node = $scope.hosts[key].nodes[nodeId]; $scope.showDetails[node] = $scope.showDetails[key]; } }; @@ -149,46 +149,46 @@ var nodesSubController = function($scope, Collections, System, Metrics) { }; $scope.isFirstNodeForHost = function(node) { - let hostName = node.split(":")[0]; - let nodesInHost = $scope.filteredNodes.filter(no => no.startsWith(hostName)); + var hostName = node.split(":")[0]; + var nodesInHost = $scope.filteredNodes.filter(no => no.startsWith(hostName)); return nodesInHost[0] === node; }; // Initializes the cluster state, list of nodes, collections etc $scope.initClusterState = function() { - let nodes = {}; - let hosts = {}; - let live_nodes = []; - + var nodes = {}; + var hosts = {}; + var live_nodes = []; + Collections.status(function (data) { - let node; -// Fetch cluster state from collections API and invert to a nodes structure - for (let name in data.cluster.collections) { - let collection = data.cluster.collections[name]; + var node; + // Fetch cluster state from collections API and invert to a nodes structure + for (var name in data.cluster.collections) { + var collection = data.cluster.collections[name]; collection.name = name; - let shards = collection.shards; + var shards = collection.shards; collection.shards = []; - for (let shardName in shards) { - let shard = shards[shardName]; + for (var shardName in shards) { + var shard = shards[shardName]; shard.name = shardName; shard.collection = collection.name; - let replicas = shard.replicas; + var replicas = shard.replicas; shard.replicas = []; - for (let replicaName in replicas) { - let core = replicas[replicaName]; + for (var replicaName in replicas) { + var core = replicas[replicaName]; core.name = replicaName; core.collection = collection.name; core.shard = shard.name; core.shard_state = shard.state; - let node_name = core['node_name']; - node = getOrCreateObj(node_name, nodes); - let cores = getOrCreateList("cores", node); + var node_name = core['node_name']; + var node = getOrCreateObj(node_name, nodes); + var cores = getOrCreateList("cores", node); cores.push(core); node['base_url'] = core.base_url; node['id'] = core.base_url.replace(/[^\w\d]/g, ''); node['host'] = node_name.split(":")[0]; - let collections = getOrCreateList("collections", node); + var collections = getOrCreateList("collections", node); ensureInList(core.collection, collections); ensureNodeInHosts(node_name, hosts); } @@ -197,9 +197,9 @@ var nodesSubController = function($scope, Collections, System, Metrics) { live_nodes = data.cluster.live_nodes; for (n in data.cluster.live_nodes) { - node = data.cluster.live_nodes[n]; + var node = data.cluster.live_nodes[n]; if (!(node in nodes)) { - let hostName = node.split(":")[0]; + var hostName = node.split(":")[0]; nodes[node] = {}; nodes[node]['host'] = hostName; } @@ -207,7 +207,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { } // Make sure nodes are sorted alphabetically to align with rowspan in table - for (let host in hosts) { + for (var host in hosts) { hosts[host].nodes.sort(); } @@ -227,21 +227,21 @@ var nodesSubController = function($scope, Collections, System, Metrics) { }; $scope.reload = function() { - let nodes = $scope.nodes; - let node_keys = Object.keys(nodes); - let hosts = $scope.hosts; - let live_nodes = $scope.live_nodes; - let hostNames = Object.keys(hosts); + var nodes = $scope.nodes; + var node_keys = Object.keys(nodes); + var hosts = $scope.hosts; + var live_nodes = $scope.live_nodes; + var hostNames = Object.keys(hosts); hostNames.sort(); - let pageSize = isNumeric($scope.pageSize) ? $scope.pageSize : 10; + var pageSize = isNumeric($scope.pageSize) ? $scope.pageSize : 10; // Calculate what nodes that will show on this page - let nodesToShow = []; - let nodesParam = ''; - let hostsToShow = []; - let filteredNodes; - let filteredHosts; - let isFiltered = false; + var nodesToShow = []; + var nodesParam = ''; + var hostsToShow = []; + var filteredNodes; + var filteredHosts; + var isFiltered = false; switch ($scope.filterType) { case "node": if ($scope.nodeFilter) { @@ -253,9 +253,9 @@ var nodesSubController = function($scope, Collections, System, Metrics) { if ($scope.collectionFilter) { candidateNodes = {}; nodesCollections = []; - for (let i = 0 ; i < node_keys.length ; i++) { - let node_name = node_keys[i]; - let node = nodes[node_name]; + for (var i = 0 ; i < node_keys.length ; i++) { + var node_name = node_keys[i]; + var node = nodes[node_name]; nodeColl = {}; nodeColl['node'] = node_name; collections = {}; @@ -287,8 +287,8 @@ var nodesSubController = function($scope, Collections, System, Metrics) { } filteredNodes.sort(); filteredHosts.sort(); - for (let id = $scope.from ; id < $scope.from + pageSize && filteredHosts[id] ; id++) { - let hostName = filteredHosts[id]; + for (var id = $scope.from ; id < $scope.from + pageSize && filteredHosts[id] ; id++) { + var hostName = filteredHosts[id]; hostsToShow.push(hostName); if (isFiltered) { // Only show the nodes per host matching active filter nodesToShow = nodesToShow.concat(filteredNodes.filter(nod => nod.startsWith(hostName))); @@ -303,29 +303,29 @@ var nodesSubController = function($scope, Collections, System, Metrics) { hostsToShow.sort(); System.get({"nodes": nodesParam}, function (systemResponse) { - for (let node in systemResponse) { + for (var node in systemResponse) { if (node in nodes) { - const s = systemResponse[node]; + var s = systemResponse[node]; nodes[node]['system'] = s; - const memTotal = s.system.totalPhysicalMemorySize; - const memFree = s.system.freePhysicalMemorySize; - const memPercentage = Math.floor((memTotal - memFree) / memTotal * 100); + var memTotal = s.system.totalPhysicalMemorySize; + var memFree = s.system.freePhysicalMemorySize; + var memPercentage = Math.floor((memTotal - memFree) / memTotal * 100); nodes[node]['memUsedPct'] = memPercentage; nodes[node]['memUsedPctStyle'] = styleForPct(memPercentage); nodes[node]['memTotal'] = bytesToSize(memTotal); nodes[node]['memFree'] = bytesToSize(memFree); nodes[node]['memUsed'] = bytesToSize(memTotal - memFree); - const heapTotal = s.jvm.memory.raw.total; - const heapFree = s.jvm.memory.raw.free; - const heapPercentage = Math.floor((heapTotal - heapFree) / heapTotal * 100); + var heapTotal = s.jvm.memory.raw.total; + var heapFree = s.jvm.memory.raw.free; + var heapPercentage = Math.floor((heapTotal - heapFree) / heapTotal * 100); nodes[node]['heapUsed'] = bytesToSize(heapTotal - heapFree); nodes[node]['heapUsedPct'] = heapPercentage; nodes[node]['heapUsedPctStyle'] = styleForPct(heapPercentage); nodes[node]['heapTotal'] = bytesToSize(heapTotal); nodes[node]['heapFree'] = bytesToSize(heapFree); - const jvmUptime = s.jvm.jmx.upTimeMS / 1000; // Seconds + var jvmUptime = s.jvm.jmx.upTimeMS / 1000; // Seconds nodes[node]['jvmUptime'] = secondsForHumans(jvmUptime); nodes[node]['jvmUptimeSec'] = jvmUptime; @@ -344,19 +344,19 @@ var nodesSubController = function($scope, Collections, System, Metrics) { "prefix": "CONTAINER.fs,org.eclipse.jetty.server.handler.DefaultHandler.get-requests,INDEX.sizeInBytes,SEARCHER.searcher.numDocs,SEARCHER.searcher.deletedDocs,SEARCHER.searcher.warmupTime" }, function (metricsResponse) { - for (let node in metricsResponse) { + for (var node in metricsResponse) { if (node in nodes) { - let m = metricsResponse[node]; + var m = metricsResponse[node]; nodes[node]['metrics'] = m; - let diskTotal = m.metrics['solr.node']['CONTAINER.fs.totalSpace']; - let diskFree = m.metrics['solr.node']['CONTAINER.fs.usableSpace']; - let diskPercentage = Math.floor((diskTotal - diskFree) / diskTotal * 100); + var diskTotal = m.metrics['solr.node']['CONTAINER.fs.totalSpace']; + var diskFree = m.metrics['solr.node']['CONTAINER.fs.usableSpace']; + var diskPercentage = Math.floor((diskTotal - diskFree) / diskTotal * 100); nodes[node]['diskUsedPct'] = diskPercentage; nodes[node]['diskUsedPctStyle'] = styleForPct(diskPercentage); nodes[node]['diskTotal'] = bytesToSize(diskTotal); nodes[node]['diskFree'] = bytesToSize(diskFree); - let r = m.metrics['solr.jetty']['org.eclipse.jetty.server.handler.DefaultHandler.get-requests']; + var r = m.metrics['solr.jetty']['org.eclipse.jetty.server.handler.DefaultHandler.get-requests']; nodes[node]['req'] = r.count; nodes[node]['req1minRate'] = Math.floor(r['1minRate'] * 100) / 100; nodes[node]['req5minRate'] = Math.floor(r['5minRate'] * 100) / 100; @@ -365,38 +365,38 @@ var nodesSubController = function($scope, Collections, System, Metrics) { nodes[node]['reqp95_ms'] = Math.floor(r['p95_ms']); nodes[node]['reqp99_ms'] = Math.floor(r['p99_ms']); - let cores = nodes[node]['cores']; - let indexSizeTotal = 0; - let docsTotal = 0; - let graphData = []; + var cores = nodes[node]['cores']; + var indexSizeTotal = 0; + var docsTotal = 0; + var graphData = []; if (cores) { for (coreId in cores) { - let core = cores[coreId]; - let keyName = "solr.core." + core['core'].replace('_', '.').replace('_', '.'); - let nodeMetric = m.metrics[keyName]; - let size = nodeMetric['INDEX.sizeInBytes']; - size = (typeof size !== 'undefined') ? size : 0; + var core = cores[coreId]; + var keyName = "solr.core." + core['core'].replace('_', '.').replace('_', '.'); + var nodeMetric = m.metrics[keyName]; + var size = nodeMetric['INDEX.sizeInBytes']; + size = (typeof size != 'undefined') ? size : 0; core['sizeInBytes'] = size; core['size'] = bytesToSize(size); core['label'] = core['core'].replace('_shard', '_s').replace(/_replica_./, 'r'); indexSizeTotal += size; - let numDocs = nodeMetric['SEARCHER.searcher.numDocs']; - numDocs = (typeof numDocs !== 'undefined') ? numDocs : 0; + var numDocs = nodeMetric['SEARCHER.searcher.numDocs']; + numDocs = (typeof numDocs != 'undefined') ? numDocs : 0; core['numDocs'] = numDocs; core['numDocsHuman'] = numDocsHuman(numDocs); - core['avgSizePerDoc'] = bytesToSize(numDocs === 0 ? 0 : size / numDocs); - let deletedDocs = nodeMetric['SEARCHER.searcher.deletedDocs']; - deletedDocs = (typeof deletedDocs !== 'undefined') ? deletedDocs : 0; + core['avgSizePerDoc'] = bytesToSize(numDocs == 0 ? 0 : size / numDocs); + var deletedDocs = nodeMetric['SEARCHER.searcher.deletedDocs']; + deletedDocs = (typeof deletedDocs != 'undefined') ? deletedDocs : 0; core['deletedDocs'] = deletedDocs; core['deletedDocsHuman'] = numDocsHuman(deletedDocs); - let warmupTime = nodeMetric['SEARCHER.searcher.warmupTime']; - warmupTime = (typeof warmupTime !== 'undefined') ? warmupTime : 0; + var warmupTime = nodeMetric['SEARCHER.searcher.warmupTime']; + warmupTime = (typeof warmupTime != 'undefined') ? warmupTime : 0; core['warmupTime'] = warmupTime; docsTotal += core['numDocs']; } for (coreId in cores) { - let core = cores[coreId]; - let graphObj = {}; + var core = cores[coreId]; + var graphObj = {}; graphObj['label'] = core['label']; graphObj['size'] = core['sizeInBytes']; graphObj['sizeHuman'] = core['size']; @@ -420,15 +420,15 @@ var nodesSubController = function($scope, Collections, System, Metrics) { // Add the div containing the whole chart $('#chart' + nodes[node]['id']).empty(); - let chart = d3.select('#chart' + nodes[node]['id']).append('div').attr('class', 'chart'); + var chart = d3.select('#chart' + nodes[node]['id']).append('div').attr('class', 'chart'); // Add one div per bar which will group together both labels and bars - let g = chart.selectAll('div') + var g = chart.selectAll('div') .data(nodes[node]['graphData']).enter() .append('div'); // Add the bars - let bars = g.append("div") + var bars = g.append("div") .attr("class", "rect") .text(function (d) { return d.label + ':\u00A0\u00A0' + d.sizeHuman; @@ -497,15 +497,15 @@ var treeSubController = function($scope, Zookeeper) { * @return {string} The phrase describing the the amount of time */ function secondsForHumans ( seconds ) { - let levels = [ + var levels = [ [Math.floor(seconds / 31536000), 'y'], [Math.floor((seconds % 31536000) / 86400), 'd'], [Math.floor(((seconds % 31536000) % 86400) / 3600), 'h'], [Math.floor((((seconds % 31536000) % 86400) % 3600) / 60), 'm'] ]; - let returntext = ''; + var returntext = ''; - for (let i = 0, max = levels.length; i < max; i++) { + for (var i = 0, max = levels.length; i < max; i++) { if ( levels[i][0] === 0 ) continue; returntext += ' ' + levels[i][0] + levels[i][1]; } From c7252ce3f12fc69b09c5664591fe31d23cd18b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Fri, 3 Aug 2018 10:00:58 +0200 Subject: [PATCH 43/47] Change arrow operators to anonymous function Fix some equality stuff --- .../web/js/angular/controllers/cloud.js | 39 ++++++++++++------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index a21e4df13205..c271354cb607 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -150,7 +150,9 @@ var nodesSubController = function($scope, Collections, System, Metrics) { $scope.isFirstNodeForHost = function(node) { var hostName = node.split(":")[0]; - var nodesInHost = $scope.filteredNodes.filter(no => no.startsWith(hostName)); + var nodesInHost = $scope.filteredNodes.filter(function (node) { + return node.startsWith(hostName); + }); return nodesInHost[0] === node; }; @@ -161,7 +163,6 @@ var nodesSubController = function($scope, Collections, System, Metrics) { var live_nodes = []; Collections.status(function (data) { - var node; // Fetch cluster state from collections API and invert to a nodes structure for (var name in data.cluster.collections) { var collection = data.cluster.collections[name]; @@ -197,7 +198,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { live_nodes = data.cluster.live_nodes; for (n in data.cluster.live_nodes) { - var node = data.cluster.live_nodes[n]; + node = data.cluster.live_nodes[n]; if (!(node in nodes)) { var hostName = node.split(":")[0]; nodes[node] = {}; @@ -237,7 +238,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { // Calculate what nodes that will show on this page var nodesToShow = []; - var nodesParam = ''; + var nodesParam; var hostsToShow = []; var filteredNodes; var filteredHosts; @@ -245,7 +246,9 @@ var nodesSubController = function($scope, Collections, System, Metrics) { switch ($scope.filterType) { case "node": if ($scope.nodeFilter) { - filteredNodes = node_keys.filter(nod => nod.indexOf($scope.nodeFilter) !== -1); + filteredNodes = node_keys.filter(function (node) { + return node.indexOf($scope.nodeFilter) !== -1; + }); } break; @@ -266,7 +269,9 @@ var nodesSubController = function($scope, Collections, System, Metrics) { nodesCollections.push(nodeColl); } nodesCollections.forEach(function(nc) { - matchingColls = nc['collections'].filter(co => co.indexOf($scope.collectionFilter) !== -1); + matchingColls = nc['collections'].filter(function (collection) { + return collection.indexOf($scope.collectionFilter) !== -1; + }); if (matchingColls.length > 0) { candidateNodes[nc.node] = true; } @@ -280,7 +285,11 @@ var nodesSubController = function($scope, Collections, System, Metrics) { } if (filteredNodes) { isFiltered = true; - filteredHosts = filteredNodes.map(nod => nod.split(":")[0]).filter((item,index,self) => self.indexOf(item)===index); + filteredHosts = filteredNodes.map(function (node) { + return node.split(":")[0]; + }).filter(function (item, index, self) { + return self.indexOf(item) === index; + }); } else { filteredNodes = node_keys; filteredHosts = hostNames; @@ -291,7 +300,9 @@ var nodesSubController = function($scope, Collections, System, Metrics) { var hostName = filteredHosts[id]; hostsToShow.push(hostName); if (isFiltered) { // Only show the nodes per host matching active filter - nodesToShow = nodesToShow.concat(filteredNodes.filter(nod => nod.startsWith(hostName))); + nodesToShow = nodesToShow.concat(filteredNodes.filter(function (node) { + return node.startsWith(hostName); + })); } else { nodesToShow = nodesToShow.concat(hosts[hostName]['nodes']); } @@ -375,27 +386,27 @@ var nodesSubController = function($scope, Collections, System, Metrics) { var keyName = "solr.core." + core['core'].replace('_', '.').replace('_', '.'); var nodeMetric = m.metrics[keyName]; var size = nodeMetric['INDEX.sizeInBytes']; - size = (typeof size != 'undefined') ? size : 0; + size = (typeof size !== 'undefined') ? size : 0; core['sizeInBytes'] = size; core['size'] = bytesToSize(size); core['label'] = core['core'].replace('_shard', '_s').replace(/_replica_./, 'r'); indexSizeTotal += size; var numDocs = nodeMetric['SEARCHER.searcher.numDocs']; - numDocs = (typeof numDocs != 'undefined') ? numDocs : 0; + numDocs = (typeof numDocs !== 'undefined') ? numDocs : 0; core['numDocs'] = numDocs; core['numDocsHuman'] = numDocsHuman(numDocs); - core['avgSizePerDoc'] = bytesToSize(numDocs == 0 ? 0 : size / numDocs); + core['avgSizePerDoc'] = bytesToSize(numDocs === 0 ? 0 : size / numDocs); var deletedDocs = nodeMetric['SEARCHER.searcher.deletedDocs']; - deletedDocs = (typeof deletedDocs != 'undefined') ? deletedDocs : 0; + deletedDocs = (typeof deletedDocs !== 'undefined') ? deletedDocs : 0; core['deletedDocs'] = deletedDocs; core['deletedDocsHuman'] = numDocsHuman(deletedDocs); var warmupTime = nodeMetric['SEARCHER.searcher.warmupTime']; - warmupTime = (typeof warmupTime != 'undefined') ? warmupTime : 0; + warmupTime = (typeof warmupTime !== 'undefined') ? warmupTime : 0; core['warmupTime'] = warmupTime; docsTotal += core['numDocs']; } for (coreId in cores) { - var core = cores[coreId]; + core = cores[coreId]; var graphObj = {}; graphObj['label'] = core['label']; graphObj['size'] = core['sizeInBytes']; From 0532e1736f721fc87dae951cd55493b6b6e3ea20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Fri, 3 Aug 2018 11:47:32 +0200 Subject: [PATCH 44/47] Mention removal of Radial view in the upgrade notes --- solr/CHANGES.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index c2332b1a48b6..09e67c5a4480 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -73,6 +73,8 @@ Upgrade Notes WINDOWS USERS: This JIRA corrects a bug in the start scripts that put example logs under ...\server, solr.log is now under ...\example. (Erick Erickson) +* The "Graph (radial)" view in the Admin UI "Cloud" menu is now removed, see SOLR-8207 + New Features ---------------------- @@ -123,7 +125,7 @@ New Features * SOLR-12536: autoscaling policy support to equally distribute replicas on the basis of arbitrary properties (noble) -* SOLR-8207: Add "Nodes" tab to the Admin UI "Cloud" view, listing all nodes with info and metrics (janhoy) +* SOLR-8207: Add "Nodes" view to the Admin UI "Cloud" view, listing nodes with key metrics. Remove "Radial" view. (janhoy) * SOLR-11990: Make it possible to co-locate replicas of multiple collections together in a node. A collection may be co-located with another collection during collection creation time by specifying a 'withCollection' parameter. It can From ea28947e9421a5c2e8beb98290179cfed382bd02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Fri, 3 Aug 2018 12:07:47 +0200 Subject: [PATCH 45/47] Add comments to JS --- .../web/js/angular/controllers/cloud.js | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index c271354cb607..dad6d169a6bc 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -148,6 +148,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { $scope.reload(); }; + // Checks if this node is the first (alphabetically) for a given host. Used to decide rowspan in table $scope.isFirstNodeForHost = function(node) { var hostName = node.split(":")[0]; var nodesInHost = $scope.filteredNodes.filter(function (node) { @@ -162,6 +163,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { var hosts = {}; var live_nodes = []; + // We build a node-centric view of the cluster state which we can easily consume to render the table Collections.status(function (data) { // Fetch cluster state from collections API and invert to a nodes structure for (var name in data.cluster.collections) { @@ -227,6 +229,10 @@ var nodesSubController = function($scope, Collections, System, Metrics) { $scope.reload(); }; + /* + Reload will fetch data for the current page of the table and thus refresh numbers. + It is also called whenever a filter or paging action is executed + */ $scope.reload = function() { var nodes = $scope.nodes; var node_keys = Object.keys(nodes); @@ -244,7 +250,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { var filteredHosts; var isFiltered = false; switch ($scope.filterType) { - case "node": + case "node": // Find what nodes match the node filter if ($scope.nodeFilter) { filteredNodes = node_keys.filter(function (node) { return node.indexOf($scope.nodeFilter) !== -1; @@ -252,7 +258,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { } break; - case "collection": + case "collection": // Find what collections match the collection filter and what nodes that have these collections if ($scope.collectionFilter) { candidateNodes = {}; nodesCollections = []; @@ -283,7 +289,9 @@ var nodesSubController = function($scope, Collections, System, Metrics) { case "health": } + if (filteredNodes) { + // If filtering is active, calculate what hosts contain the nodes that match the filters isFiltered = true; filteredHosts = filteredNodes.map(function (node) { return node.split(":")[0]; @@ -296,6 +304,8 @@ var nodesSubController = function($scope, Collections, System, Metrics) { } filteredNodes.sort(); filteredHosts.sort(); + + // Find what hosts & nodes (from the filtered set) that should be displayed on current page for (var id = $scope.from ; id < $scope.from + pageSize && filteredHosts[id] ; id++) { var hostName = filteredHosts[id]; hostsToShow.push(hostName); @@ -313,6 +323,10 @@ var nodesSubController = function($scope, Collections, System, Metrics) { nodesToShow.sort(); hostsToShow.sort(); + /* + Fetch system info for all selected nodes + Pick the data we want to display and add it to the node-centric data structure + */ System.get({"nodes": nodesParam}, function (systemResponse) { for (var node in systemResponse) { if (node in nodes) { @@ -350,6 +364,10 @@ var nodesSubController = function($scope, Collections, System, Metrics) { } }); + /* + Fetch metrics for all selected nodes. Only pull the metrics that we'll show to save bandwidth + Pick the data we want to display and add it to the node-centric data structure + */ Metrics.get({ "nodes": nodesParam, "prefix": "CONTAINER.fs,org.eclipse.jetty.server.handler.DefaultHandler.get-requests,INDEX.sizeInBytes,SEARCHER.searcher.numDocs,SEARCHER.searcher.deletedDocs,SEARCHER.searcher.warmupTime" @@ -429,7 +447,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { nodes[node]['size'] = bytesToSize(indexSizeTotal); nodes[node]['sizePerDoc'] = docsTotal === 0 ? '0b' : bytesToSize(indexSizeTotal / docsTotal); - // Add the div containing the whole chart + // Build the d3 powered bar chart $('#chart' + nodes[node]['id']).empty(); var chart = d3.select('#chart' + nodes[node]['id']).append('div').attr('class', 'chart'); From 7570692e02a469fdbf3badb82ed7a991abcac103 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Fri, 3 Aug 2018 12:44:21 +0200 Subject: [PATCH 46/47] Keep radial view. Will be removed in 8.0 --- solr/CHANGES.txt | 2 - solr/solr-ref-guide/src/cloud-screens.adoc | 21 ++++-- .../src/images/cloud-screens/cloud-radial.png | Bin 0 -> 62572 bytes solr/webapp/web/css/angular/menu.css | 1 + solr/webapp/web/index.html | 1 + .../web/js/angular/controllers/cloud.js | 70 +++++++++++++++++- solr/webapp/web/partials/cloud.html | 2 +- 7 files changed, 85 insertions(+), 12 deletions(-) create mode 100644 solr/solr-ref-guide/src/images/cloud-screens/cloud-radial.png diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 09e67c5a4480..2f1f5b6ebef0 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -73,8 +73,6 @@ Upgrade Notes WINDOWS USERS: This JIRA corrects a bug in the start scripts that put example logs under ...\server, solr.log is now under ...\example. (Erick Erickson) -* The "Graph (radial)" view in the Admin UI "Cloud" menu is now removed, see SOLR-8207 - New Features ---------------------- diff --git a/solr/solr-ref-guide/src/cloud-screens.adoc b/solr/solr-ref-guide/src/cloud-screens.adoc index 4d9af4fdf922..34982ee00f3a 100644 --- a/solr/solr-ref-guide/src/cloud-screens.adoc +++ b/solr/solr-ref-guide/src/cloud-screens.adoc @@ -26,13 +26,24 @@ This screen provides status information about each collection & node in your clu The "Cloud" menu option is only available on Solr instances running in <>. Single node or master/slave replication instances of Solr will not display this option. ==== -Click on the Cloud option in the left-hand navigation, and a small sub-menu appears with options called "Nodes", "Tree" and "Graph". The default view ("Nodes") shows a list of the hosts and nodes in the cluster along with key information for each: "CPU", "Heap", "Disk usage", "Requests", "Collections" and "Replicas". +Click on the "Cloud" option in the left-hand navigation, and a small sub-menu appears with options called "Nodes", "Tree", "Graph" and "Graph (Radial)". The sub-view selected by default is "Graph". + +== Nodes view +The "Nodes" view shows a list of the hosts and nodes in the cluster along with key information for each: "CPU", "Heap", "Disk usage", "Requests", "Collections" and "Replicas". The example below shows the default "cloud" example with some documents added to the "gettingstarted" collection. Details are expanded for node on port 7574, showing more metadata and more metrics details. The screen provides links to navigate to nodes, collections and replicas. The table supports paging and filtering on host/node names and collection names. image::images/cloud-screens/cloud-nodes.png[image,width=900,height=415] -The ("Graph") view shows a graph of each collection, the shards that make up those collections, and the addresses and type ("NRT", "TLOG" or "PULL") of each replica for each shard. +== Tree view +The "Tree" view shows a directory structure of the data in ZooKeeper, including cluster wide information regarding the `live_nodes` and `overseer` status, as well as collection specific information such as the `state.json`, current shard leaders, and configuration files in use. In this example, we see part of the `state.json` definition for the "tlog" collection: + +image::images/cloud-screens/cloud-tree.png[image,width=487,height=250] + +As an aid to debugging, the data shown in the "Tree" view can be exported locally using the following command `bin/solr zk ls -r /` + +== Graph views +The "Graph" view shows a graph of each collection, the shards that make up those collections, and the addresses and type ("NRT", "TLOG" or "PULL") of each replica for each shard. This example shows a simple cluster. In addition to the 2 shard, 2 replica "gettingstarted" collection, there is an additional "tlog" collection consisting of mixed TLOG and PULL replica types. @@ -42,8 +53,6 @@ Tooltips appear when hovering over each replica giving additional information. image::images/cloud-screens/cloud-hover.png[image,width=512,height=250] -The "Tree" option shows a directory structure of the data in ZooKeeper, including cluster wide information regarding the `live_nodes` and `overseer` status, as well as collection specific information such as the `state.json`, current shard leaders, and configuration files in use. In this example, we see part of the `state.json` definition for the "tlog" collection: - -image::images/cloud-screens/cloud-tree.png[image,width=487,height=250] +The "Graph (Radial)" option provides a different visual view of each node. Using the same example cluster, the radial graph view looks like: -As an aid to debugging, the data shown in the "Tree" view can be exported locally using the following command `bin/solr zk ls -r /` +image::images/cloud-screens/cloud-radial.png[image,width=478,height=250] diff --git a/solr/solr-ref-guide/src/images/cloud-screens/cloud-radial.png b/solr/solr-ref-guide/src/images/cloud-screens/cloud-radial.png new file mode 100644 index 0000000000000000000000000000000000000000..76f9e1e13c51ada7a4e34d8b8bc85f46e66f7744 GIT binary patch literal 62572 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 otsywK0+5$Z~Jb0EEF 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 Iq3N6d17o4#9{>OV literal 0 HcmV?d00001 diff --git a/solr/webapp/web/css/angular/menu.css b/solr/webapp/web/css/angular/menu.css index 8332a8023155..ba5e0b6a42ab 100644 --- a/solr/webapp/web/css/angular/menu.css +++ b/solr/webapp/web/css/angular/menu.css @@ -262,6 +262,7 @@ limitations under the License. #menu #cloud.global .tree a { background-image: url( ../../img/ico/folder-tree.png ); } #menu #cloud.global .nodes a { background-image: url( ../../img/solr-ico.png ); } #menu #cloud.global .graph a { background-image: url( ../../img/ico/molecule.png ); } +#menu #cloud.global .rgraph a { background-image: url( ../../img/ico/asterisk.png ); } .sub-menu .ping.error a { diff --git a/solr/webapp/web/index.html b/solr/webapp/web/index.html index fdd7a5f97f98..256af89ad0ae 100644 --- a/solr/webapp/web/index.html +++ b/solr/webapp/web/index.html @@ -153,6 +153,7 @@

      Connection recovered...

    • Nodes
    • Tree
    • Graph
    • +
    • Graph (Radial)
    diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index dad6d169a6bc..08eea38c7900 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -32,6 +32,9 @@ solrAdminApp.controller('CloudController', if (view === "tree") { $scope.resetMenu("cloud-tree", Constants.IS_ROOT_PAGE); treeSubController($scope, Zookeeper); + } else if (view === "rgraph") { + $scope.resetMenu("cloud-rgraph", Constants.IS_ROOT_PAGE); + graphSubController($scope, Zookeeper, true); } else if (view === "graph") { $scope.resetMenu("cloud-graph", Constants.IS_ROOT_PAGE); graphSubController($scope, Zookeeper, false); @@ -541,7 +544,7 @@ function secondsForHumans ( seconds ) { return returntext.trim() === '' ? '0m' : returntext.trim(); } -var graphSubController = function ($scope, Zookeeper) { +var graphSubController = function ($scope, Zookeeper, isRadial) { $scope.showTree = false; $scope.showGraph = true; @@ -696,7 +699,7 @@ var graphSubController = function ($scope, Zookeeper) { $scope.helperData.state = $.unique($scope.helperData.state); $scope.helperData.core_node = $.unique($scope.helperData.core_node); - if (data.znode && data.znode.paging) { + if (!isRadial && data.znode && data.znode.paging) { $scope.showPaging = true; var parr = data.znode.paging.split('|'); @@ -730,6 +733,7 @@ var graphSubController = function ($scope, Zookeeper) { } $scope.graphData = graph_data; $scope.leafCount = leaf_count; + $scope.isRadial = isRadial; }); }); }; @@ -745,6 +749,7 @@ solrAdminApp.directive('graph', function(Constants) { data: "=", leafCount: "=", helperData: "=", + isRadial: "=" }, link: function (scope, element, attrs) { var helper_path_class = function (p) { @@ -827,7 +832,11 @@ solrAdminApp.directive('graph', function(Constants) { scope.$watch("data", function(newValue, oldValue) { if (newValue) { - flatGraph(element, scope.data, scope.leafCount); + if (scope.isRadial) { + radialGraph(element, scope.data, scope.leafCount); + } else { + flatGraph(element, scope.data, scope.leafCount); + } } $('text').tooltip({ @@ -914,6 +923,61 @@ solrAdminApp.directive('graph', function(Constants) { setNodeNavigationBehavior(node); }; + + var radialGraph = function(element, graphData, leafCount) { + var max_val = Math.min(element.width(), $('body').height()) + var r = max_val / 2; + + var cluster = d3.layout.cluster() + .size([360, r - 160]); + + var diagonal = d3.svg.diagonal.radial() + .projection(function (d) { + return [d.y, d.x / 180 * Math.PI]; + }); + + d3.select('#canvas', element).html(''); + var vis = d3.select('#canvas').append('svg') + .attr('width', r * 2) + .attr('height', r * 2) + .append('g') + .attr('transform', 'translate(' + r + ',' + r + ')'); + + var nodes = cluster.nodes(graphData); + + var link = vis.selectAll('path.link') + .data(cluster.links(nodes)) + .enter().append('path') + .attr('class', helper_path_class) + .attr('d', diagonal); + + var node = vis.selectAll('g.node') + .data(nodes) + .enter().append('g') + .attr('class', helper_node_class) + .attr('transform', function (d) { + return 'rotate(' + (d.x - 90) + ')translate(' + d.y + ')'; + }) + + node.append('circle') + .attr('r', 4.5); + + node.append('text') + .attr('dx', function (d) { + return d.x < 180 ? 8 : -8; + }) + .attr('dy', '.31em') + .attr('text-anchor', function (d) { + return d.x < 180 ? 'start' : 'end'; + }) + .attr('transform', function (d) { + return d.x < 180 ? null : 'rotate(180)'; + }) + .attr("title", helper_tooltip_text) + .text(helper_node_text); + + setNodeNavigationBehavior(node, "rgraph"); + } } }; }); diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index bcda75b512a7..078c9af40b7e 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -180,7 +180,7 @@
    -
    +
    From cb8379b9070242a75f0439d80153a4f1eb3e143b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Fri, 3 Aug 2018 12:52:18 +0200 Subject: [PATCH 47/47] Changes should not say radial is removed --- solr/CHANGES.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 2f1f5b6ebef0..ac57667a7d94 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -123,7 +123,7 @@ New Features * SOLR-12536: autoscaling policy support to equally distribute replicas on the basis of arbitrary properties (noble) -* SOLR-8207: Add "Nodes" view to the Admin UI "Cloud" view, listing nodes with key metrics. Remove "Radial" view. (janhoy) +* SOLR-8207: Add "Nodes" view to the Admin UI "Cloud" view, listing nodes with key metrics (janhoy) * SOLR-11990: Make it possible to co-locate replicas of multiple collections together in a node. A collection may be co-located with another collection during collection creation time by specifying a 'withCollection' parameter. It can