From 8f29d1eaadce5ca2c79b1f48161a8dda696d9952 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=C3=B8ydahl?= Date: Fri, 15 Mar 2019 13:30:02 +0100 Subject: [PATCH] SOLR-13244: Nodes view fails when a node is temporarily down --- solr/CHANGES.txt | 2 + solr/webapp/web/css/angular/cloud.css | 11 +++ .../web/js/angular/controllers/cloud.js | 27 +++++- solr/webapp/web/partials/cloud.html | 90 ++++++++++--------- 4 files changed, 85 insertions(+), 45 deletions(-) diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 72a26bb9699..1c6ee04b8ea 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -120,6 +120,8 @@ Bug Fixes * SOLR-13284: NullPointerException with 500 http status on omitted or wrong wt param. It's fixed by fallback to json (Munendra S N via Mikhail Khludnev) +* SOLR-13244: Admin UI Nodes view fails and is empty when a node is temporarily down (janhoy) + Improvements ---------------------- * SOLR-12999: Index replication could delete segments before downloading segments from master if there is not enough diff --git a/solr/webapp/web/css/angular/cloud.css b/solr/webapp/web/css/angular/cloud.css index 5c8ce453bc0..c702c7a1db6 100644 --- a/solr/webapp/web/css/angular/cloud.css +++ b/solr/webapp/web/css/angular/cloud.css @@ -535,6 +535,17 @@ limitations under the License. color: red; } +#content #cloud #nodes-content .node-down +{ + font-weight: bold; + font-size: 12px; +} + +#content #cloud #nodes-content .dead-node +{ + background-color: salmon; +} + /* Styling of reload and details buttons */ #content #cloud #controls, #content #cloud #frame #zk-status-content #zk-controls diff --git a/solr/webapp/web/js/angular/controllers/cloud.js b/solr/webapp/web/js/angular/controllers/cloud.js index d6730d518ec..0d49df2db93 100644 --- a/solr/webapp/web/js/angular/controllers/cloud.js +++ b/solr/webapp/web/js/angular/controllers/cloud.js @@ -107,6 +107,10 @@ function isNumeric(n) { return !isNaN(parseFloat(n)) && isFinite(n); } +function coreNameToLabel(name) { + return name.replace(/(.*?)_shard((\d+_?)+)_replica_?[ntp]?(\d+)/, '\$1_s\$2r\$4'); +} + var nodesSubController = function($scope, Collections, System, Metrics) { $scope.pageSize = 10; $scope.showNodes = true; @@ -160,6 +164,17 @@ var nodesSubController = function($scope, Collections, System, Metrics) { return nodesInHost[0] === node; }; + // Returns the first live node for this host, to make sure we pick host-level metrics from a live node + $scope.firstLiveNodeForHost = function(key) { + var hostName = key.split(":")[0]; + var liveNodesInHost = $scope.filteredNodes.filter(function (key) { + return key.startsWith(hostName); + }).filter(function (key) { + return $scope.live_nodes.includes(key); + }); + return liveNodesInHost.length > 0 ? liveNodesInHost[0] : key; + }; + // Initializes the cluster state, list of nodes, collections etc $scope.initClusterState = function() { var nodes = {}; @@ -183,6 +198,7 @@ var nodesSubController = function($scope, Collections, System, Metrics) { for (var replicaName in replicas) { var core = replicas[replicaName]; core.name = replicaName; + core.label = coreNameToLabel(core['core']); core.collection = collection.name; core.shard = shard.name; core.shard_state = shard.state; @@ -320,7 +336,15 @@ var nodesSubController = function($scope, Collections, System, Metrics) { nodesToShow = nodesToShow.concat(hosts[hostName]['nodes']); } } - nodesParam = nodesToShow.join(','); + nodesParam = nodesToShow.filter(function (node) { + return live_nodes.includes(node); + }).join(','); + var deadNodes = nodesToShow.filter(function (node) { + return !live_nodes.includes(node); + }); + deadNodes.forEach(function (node) { + nodes[node]['dead'] = true; + }); $scope.nextEnabled = $scope.from + pageSize < filteredHosts.length; $scope.prevEnabled = $scope.from - pageSize >= 0; nodesToShow.sort(); @@ -410,7 +434,6 @@ var nodesSubController = function($scope, Collections, System, Metrics) { size = (typeof size !== 'undefined') ? size : 0; core['sizeInBytes'] = size; core['size'] = bytesToSize(size); - core['label'] = core['core'].replace(/(.*?)_shard((\d+_?)+)_replica_?[ntp]?(\d+)/, '\$1_s\$2r\$4'); if (core['shard_state'] !== 'active' || core['state'] !== 'active') { // If core state is not active, display the real state, or if shard is inactive, display that var labelState = (core['state'] !== 'active') ? core['state'] : core['shard_state']; diff --git a/solr/webapp/web/partials/cloud.html b/solr/webapp/web/partials/cloud.html index 59e9a40eaa2..1e64d2976f0 100644 --- a/solr/webapp/web/partials/cloud.html +++ b/solr/webapp/web/partials/cloud.html @@ -149,88 +149,92 @@ limitations under the License. - - -
{{n.host}}
- - {{n.system.system.name}} - {{n.memTotal}} - Java {{n.system.jvm.spec.version}} -
Load: {{n.loadAvg}} + + +
{{h.host}}
+ + {{h.system.system.name}} + {{h.memTotal}} + Java {{h.system.jvm.spec.version}} +
Load: {{h.loadAvg}}
-
- {{n.system.system.name}} {{n.system.system.version}}, {{n.system.system.availableProcessors}}cpu
- Uptime: {{n.uptime}}
- Memory: {{n.memTotal}}
- File descriptors: {{n.openFileDescriptorCount}}/{{n.maxFileDescriptorCount}}
- Disk: {{n.diskTotal}} used: {{n.diskUsedPct}}%
- Load: {{n.loadAvg}} +
+ {{h.system.system.name}} {{h.system.system.version}}, {{h.system.system.availableProcessors}}cpu
+ Uptime: {{h.uptime}}
+ Memory: {{h.memTotal}}
+ File descriptors: {{h.openFileDescriptorCount}}/{{h.maxFileDescriptorCount}}
+ Disk: {{h.diskTotal}} used: {{h.diskUsedPct}}%
+ Load: {{h.loadAvg}}
-
- hide details... - show details... + - - Uptime: {{n.jvmUptime}}
-
- Java {{n.system.jvm.jre.version}}
- Solr {{n.system.lucene['solr-impl-version'].split(" ")[0]}}
-
-
- hide details... - show details... + +
(DEAD)
+
+ Uptime: {{n.jvmUptime}}
+
+ Java {{n.system.jvm.jre.version}}
+ Solr {{n.system.lucene['solr-impl-version'].split(" ")[0]}}
+
+
- -
+ +
{{n.cpuPct}}%
- -
+ +
{{n.heapUsedPct}}%
-
+
Max: {{n.heapTotal}}
Used: {{n.heapUsed}}
- +
-
+
{{n.size}}
-
+
Total #docs: {{n.numDocs}}
Avg size/doc: {{n.sizePerDoc}}
-
+
-
+
RPM: {{n.req15minRate}}
p95: {{n.reqp95_ms}}ms
- +
(none)
- +
(none)
- {{ core.label }} ({{core.numDocsHuman}} docs) -
    +
    {{ core.label }} ({{core.numDocsHuman}} docs)
    +
    {{ core.label }}
    +
    • deleted: {{core.deletedDocsHuman}}
    • warmupTime: {{core.warmupTime}}
    • avg size/doc: {{core.avgSizePerDoc}}
-