This is an automated email from the ASF dual-hosted git repository.
domgarguilo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/accumulo.git
The following commit(s) were added to refs/heads/main by this push:
new 09894478d1 Add Resource Group Overview tables to the Monitor Home page
(#6240)
09894478d1 is described below
commit 09894478d17e38f2810d0de0cd40a11d7f5943c5
Author: Dom G. <[email protected]>
AuthorDate: Tue Mar 31 13:01:24 2026 -0400
Add Resource Group Overview tables to the Monitor Home page (#6240)
* Add Resource Group Overview tables to the Monitor Home page
* build deployment view on finalize
* Add two tables to overview page
* Add pagination and info back to breakdown table
* Update
server/monitor/src/main/java/org/apache/accumulo/monitor/next/Endpoints.java
Co-authored-by: Dave Marion <[email protected]>
* properly update notResponded set
* center entry count on table
---------
Co-authored-by: Dave Marion <[email protected]>
---
.../apache/accumulo/monitor/next/Endpoints.java | 11 +-
.../accumulo/monitor/next/InformationFetcher.java | 2 +-
.../accumulo/monitor/next/SystemInformation.java | 65 +++++----
.../next/deployment/DeploymentOverview.java | 82 ++++++++++++
.../org/apache/accumulo/monitor/resources/js/ec.js | 10 --
.../accumulo/monitor/resources/js/functions.js | 15 +++
.../accumulo/monitor/resources/js/overview.js | 147 ++++++++++++++++++---
.../accumulo/monitor/resources/js/tservers.js | 23 +++-
.../apache/accumulo/monitor/templates/overview.ftl | 71 ++++++----
.../apache/accumulo/monitor/templates/tservers.ftl | 10 ++
10 files changed, 336 insertions(+), 100 deletions(-)
diff --git
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/Endpoints.java
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/Endpoints.java
index d2fdaa26ef..9a809e9d3c 100644
---
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/Endpoints.java
+++
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/Endpoints.java
@@ -43,16 +43,15 @@ import jakarta.ws.rs.core.MediaType;
import org.apache.accumulo.core.Constants;
import org.apache.accumulo.core.client.admin.TabletInformation;
import org.apache.accumulo.core.client.admin.servers.ServerId;
-import org.apache.accumulo.core.data.ResourceGroupId;
import org.apache.accumulo.core.data.TableId;
import org.apache.accumulo.core.metrics.flatbuffers.FMetric;
import org.apache.accumulo.core.process.thrift.MetricResponse;
import org.apache.accumulo.core.util.compaction.RunningCompactionInfo;
import org.apache.accumulo.monitor.Monitor;
import org.apache.accumulo.monitor.next.InformationFetcher.InstanceSummary;
-import org.apache.accumulo.monitor.next.SystemInformation.ProcessSummary;
import org.apache.accumulo.monitor.next.SystemInformation.TableSummary;
import
org.apache.accumulo.monitor.next.SystemInformation.TimeOrderedRunningCompactionSet;
+import org.apache.accumulo.monitor.next.deployment.DeploymentOverview;
import org.apache.accumulo.monitor.next.ec.CompactorsSummary;
import org.apache.accumulo.monitor.next.ec.CoordinatorSummary;
import org.apache.accumulo.monitor.next.sservers.ScanServerView;
@@ -408,10 +407,10 @@ public class Endpoints {
@GET
@Path("deployment")
@Produces(MediaType.APPLICATION_JSON)
- @Description("Returns a map of resource group to server type to process
summary."
- + " The process summary contains the number of configured, responding,
and not responding servers")
- public Map<ResourceGroupId,Map<String,ProcessSummary>>
getDeploymentOverview() {
- return
monitor.getInformationFetcher().getSummaryForEndpoint().getDeploymentOverview();
+ @Description("Returns a UI-ready deployment overview grouped by resource
group. Each process row"
+ + " contains the total and responding server counts.")
+ public DeploymentOverview getDeploymentOverview() {
+ return
monitor.getInformationFetcher().getSummaryForEndpoint().getDeploymentView();
}
@GET
diff --git
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/InformationFetcher.java
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/InformationFetcher.java
index 9b27141f0d..1f5f915114 100644
---
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/InformationFetcher.java
+++
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/InformationFetcher.java
@@ -133,7 +133,7 @@ public class InformationFetcher implements
RemovalListener<ServerId,MetricRespon
}
} catch (Exception e) {
LOG.warn("Error trying to get metrics from server: {}", server, e);
- summary.processError(server);
+ summary.processMetricsError(server);
}
}
diff --git
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/SystemInformation.java
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/SystemInformation.java
index 3de740a1b8..3949e5766b 100644
---
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/SystemInformation.java
+++
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/SystemInformation.java
@@ -58,6 +58,7 @@ import org.apache.accumulo.core.metrics.flatbuffers.FTag;
import org.apache.accumulo.core.process.thrift.MetricResponse;
import org.apache.accumulo.core.spi.balancer.TableLoadBalancer;
import org.apache.accumulo.core.util.compaction.RunningCompactionInfo;
+import org.apache.accumulo.monitor.next.deployment.DeploymentOverview;
import org.apache.accumulo.monitor.next.sservers.ScanServerView;
import org.apache.accumulo.server.ServerContext;
import org.apache.accumulo.server.conf.TableConfiguration;
@@ -272,34 +273,25 @@ public class SystemInformation {
}
public static class ProcessSummary {
- private final AtomicLong configured = new AtomicLong(0);
- private final AtomicLong responded = new AtomicLong();
- private final Set<String> notResponded = ConcurrentHashMap.newKeySet();
+ private final Set<ServerId> responded = ConcurrentHashMap.newKeySet();
+ private final Set<ServerId> notResponded = ConcurrentHashMap.newKeySet();
- public void addResponded() {
- configured.incrementAndGet();
- responded.incrementAndGet();
+ public void addResponded(ServerId server) {
+ notResponded.remove(server);
+ responded.add(server);
}
public void addNotResponded(ServerId server) {
- configured.incrementAndGet();
- notResponded.add(server.getHost() + ":" + server.getPort());
+ responded.remove(server);
+ notResponded.add(server);
}
- public long getConfigured() {
- return this.configured.get();
+ public long getTotal() {
+ return this.responded.size() + this.notResponded.size();
}
public long getResponded() {
- return this.responded.get();
- }
-
- public long getNotResponded() {
- return this.notResponded.size();
- }
-
- public Set<String> getNotRespondedHosts() {
- return this.notResponded;
+ return this.responded.size();
}
}
@@ -368,6 +360,7 @@ public class SystemInformation {
private final Set<String> resourceGroups = ConcurrentHashMap.newKeySet();
private final Set<ServerId> problemHosts = ConcurrentHashMap.newKeySet();
+ private final Set<ServerId> metricProblemHosts =
ConcurrentHashMap.newKeySet();
private final AtomicReference<ServerId> manager = new AtomicReference<>();
private final AtomicReference<ServerId> gc = new AtomicReference<>();
@@ -410,7 +403,7 @@ public class SystemInformation {
private final Map<TableId,List<TabletInformation>> tablets = new
ConcurrentHashMap<>();
// Deployment Overview
- private final Map<ResourceGroupId,Map<String,ProcessSummary>> deployment =
+ private final Map<ResourceGroupId,Map<ServerId.Type,ProcessSummary>>
deployment =
new ConcurrentHashMap<>();
private final Set<String> suggestions = new ConcurrentSkipListSet<>();
@@ -418,7 +411,9 @@ public class SystemInformation {
private final Set<String> configuredCompactionResourceGroups =
ConcurrentHashMap.newKeySet();
private long timestamp = 0;
- private ScanServerView scanServerView;
+ private ScanServerView scanServerView = new ScanServerView(0L, List.of(),
+ new ScanServerView.Status(false, false, false, 0, 0, 0L, "OK", null));
+ private DeploymentOverview deploymentOverview = new DeploymentOverview(0L,
List.of());
private final int rgLongRunningCompactionSize;
public SystemInformation(Cache<ServerId,MetricResponse> allMetrics,
ServerContext ctx) {
@@ -431,6 +426,7 @@ public class SystemInformation {
public void clear() {
resourceGroups.clear();
problemHosts.clear();
+ metricProblemHosts.clear();
compactors.clear();
sservers.clear();
tservers.clear();
@@ -451,7 +447,6 @@ public class SystemInformation {
runningCompactionsPerGroup.clear();
runningCompactionsPerTable.clear();
configuredCompactionResourceGroups.clear();
- scanServerView = null;
}
private void updateAggregates(final MetricResponse response,
@@ -509,10 +504,11 @@ public class SystemInformation {
public void processResponse(final ServerId server, final MetricResponse
response) {
problemHosts.remove(server);
+ metricProblemHosts.remove(server);
allMetrics.put(server, response);
resourceGroups.add(response.getResourceGroup());
deployment.computeIfAbsent(server.getResourceGroup(), g -> new
ConcurrentHashMap<>())
- .computeIfAbsent(server.getType().name(), t -> new
ProcessSummary()).addResponded();
+ .computeIfAbsent(server.getType(), t -> new
ProcessSummary()).addResponded(server);
switch (response.serverType) {
case COMPACTOR:
compactors
@@ -583,17 +579,21 @@ public class SystemInformation {
problemHosts.add(server);
}
+ public void processMetricsError(ServerId server) {
+ problemHosts.add(server);
+ metricProblemHosts.add(server);
+ }
+
public void addConfiguredCompactionGroups(Set<String> groups) {
configuredCompactionResourceGroups.addAll(groups);
}
public void finish() {
// Update the deployment not-responded numbers based
- // on the problem hosts.
- problemHosts.forEach(serverId -> {
+ // on metric fetch failures for this refresh.
+ metricProblemHosts.forEach(serverId -> {
deployment.computeIfAbsent(serverId.getResourceGroup(), g -> new
ConcurrentHashMap<>())
- .computeIfAbsent(serverId.getType().name(), t -> new
ProcessSummary())
- .addNotResponded(serverId);
+ .computeIfAbsent(serverId.getType(), t -> new
ProcessSummary()).addNotResponded(serverId);
});
for (SystemTables table : SystemTables.values()) {
TableConfiguration tconf =
this.ctx.getTableConfiguration(table.tableId());
@@ -607,6 +607,9 @@ public class SystemInformation {
for (String rg : getResourceGroups()) {
Set<ServerId> rgCompactors = getCompactorResourceGroupServers(rg);
List<FMetric> metrics = queueMetrics.get(rg);
+ if (metrics == null || metrics.isEmpty()) {
+ continue;
+ }
Optional<FMetric> queued = metrics.stream()
.filter(fm ->
fm.name().equals(Metric.COMPACTOR_JOB_PRIORITY_QUEUE_JOBS_QUEUED.getName()))
.findFirst();
@@ -620,6 +623,9 @@ public class SystemInformation {
// Check for idle compactors.
Map<Id,CumulativeDistributionSummary> rgMetrics =
getCompactorResourceGroupMetricSummary(rg);
+ if (rgMetrics == null || rgMetrics.isEmpty()) {
+ continue;
+ }
Optional<Entry<Id,CumulativeDistributionSummary>> idleMetric =
rgMetrics.entrySet()
.stream().filter(e ->
e.getKey().getName().equals(Metric.SERVER_IDLE.getName()))
.findFirst();
@@ -648,6 +654,7 @@ public class SystemInformation {
.filter(serverId -> serverId.getType() ==
ServerId.Type.SCAN_SERVER).count();
var responses = allMetrics.getAllPresent(scanServers).values();
timestamp = System.currentTimeMillis();
+ deploymentOverview = DeploymentOverview.fromSummary(deployment, timestamp);
scanServerView = ScanServerView.fromMetrics(responses, scanServers.size(),
problemScanServerCount, timestamp);
}
@@ -731,8 +738,8 @@ public class SystemInformation {
return this.tablets.get(tableId);
}
- public Map<ResourceGroupId,Map<String,ProcessSummary>>
getDeploymentOverview() {
- return this.deployment;
+ public DeploymentOverview getDeploymentView() {
+ return this.deploymentOverview;
}
public Set<String> getSuggestions() {
diff --git
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/deployment/DeploymentOverview.java
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/deployment/DeploymentOverview.java
new file mode 100644
index 0000000000..536399fda1
--- /dev/null
+++
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/deployment/DeploymentOverview.java
@@ -0,0 +1,82 @@
+/*
+ * 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
+ *
+ * https://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.accumulo.monitor.next.deployment;
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.accumulo.core.client.admin.servers.ServerId;
+import org.apache.accumulo.core.data.ResourceGroupId;
+import org.apache.accumulo.monitor.next.SystemInformation.ProcessSummary;
+
+/**
+ * Data Transfer Object for the Monitor Deployment page.
+ */
+public record DeploymentOverview(long lastUpdate, List<DeploymentRow>
breakdown) {
+
+ /**
+ * Data Transfer Object containing counts of total and responding servers
for a given resource
+ * group and server type.
+ */
+ public record DeploymentRow(String resourceGroup, String serverType, long
total,
+ long responding) {
+ }
+
+ public static DeploymentOverview fromSummary(
+ Map<ResourceGroupId,Map<ServerId.Type,ProcessSummary>> deployment, long
lastUpdate) {
+ if (deployment == null || deployment.isEmpty()) {
+ return new DeploymentOverview(lastUpdate, List.of());
+ }
+
+ var breakdown =
+
deployment.entrySet().stream().sorted(Map.Entry.comparingByKey()).flatMap(entry
-> {
+ var resourceGroup = entry.getKey().canonical();
+ var processes = entry.getValue();
+ if (processes == null || processes.isEmpty()) {
+ return java.util.stream.Stream.empty();
+ }
+
+ return processes.entrySet().stream()
+
.sorted(Map.Entry.comparingByKey(Comparator.comparingInt(Enum::ordinal)))
+ .map(processEntry -> {
+ ServerId.Type type = processEntry.getKey();
+ ProcessSummary processSummary = processEntry.getValue();
+ return new DeploymentRow(resourceGroup, processLabel(type),
+ processSummary.getTotal(), processSummary.getResponded());
+ });
+ }).toList();
+
+ return new DeploymentOverview(lastUpdate, breakdown);
+ }
+
+ /**
+ * @return String representation of the server type
+ */
+ private static String processLabel(ServerId.Type process) {
+ return switch (process) {
+ case COMPACTOR -> "Compactor";
+ case GARBAGE_COLLECTOR -> "Garbage Collector";
+ case MANAGER -> "Manager";
+ case MONITOR -> "Monitor";
+ case SCAN_SERVER -> "Scan Server";
+ case TABLET_SERVER -> "Tablet Server";
+ };
+ }
+}
diff --git
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/ec.js
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/ec.js
index 9541cbc30e..9fcda2ec5b 100644
---
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/ec.js
+++
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/ec.js
@@ -334,13 +334,3 @@ async function refreshManagerStatus() {
return managerStatus;
});
}
-
-// Helper function to validate regex
-function isValidRegex(input) {
- try {
- new RegExp(input);
- return true;
- } catch (e) {
- return false;
- }
-}
diff --git
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/functions.js
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/functions.js
index 331f0844db..947b8b943d 100644
---
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/functions.js
+++
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/functions.js
@@ -753,3 +753,18 @@ function getTable(name) {
function getCompactionsSummary() {
return getJSONForTable(REST_V2_PREFIX + '/compactions/summary',
'compactionsSummary');
}
+
+/**
+ * Returns true if the input is a valid regular expression, false otherwise.
+ *
+ * @param {string} input Potential regex string
+ * @returns {boolean} Whether the input is a valid regex
+ */
+function isValidRegex(input) {
+ try {
+ new RegExp(input);
+ return true;
+ } catch (e) {
+ return false;
+ }
+}
diff --git
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/overview.js
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/overview.js
index a0255e32c9..fe5e691406 100644
---
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/overview.js
+++
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/overview.js
@@ -18,10 +18,101 @@
*/
"use strict";
+var deploymentSummaryTable;
+var deploymentBreakdownTable;
+
/**
* Creates overview initial table
*/
$(function () {
+ // display datatables errors in the console instead of in alerts
+ $.fn.dataTable.ext.errMode = 'throw';
+
+ deploymentSummaryTable = $('#deploymentSummaryTable').DataTable({
+ "autoWidth": false,
+ "paging": false,
+ "searching": false,
+ "info": false,
+ "ordering": false,
+ "dom": 't',
+ "data": [],
+ "columnDefs": [{
+ "targets": 0,
+ "width": "60%"
+ },
+ {
+ "targets": 1,
+ "width": "40%"
+ }
+ ],
+ "columns": [{
+ "data": "serverType"
+ },
+ {
+ "data": null,
+ "render": function (data, type, row) {
+ return row.responding + ' / ' + row.total;
+ }
+ }
+ ]
+ });
+
+ deploymentBreakdownTable = $('#deploymentBreakdownTable').DataTable({
+ "autoWidth": false,
+ "paging": true,
+ "pageLength": 10,
+ "searching": true,
+ "info": true,
+ "order": [
+ [0, 'asc'],
+ [1, 'asc']
+ ],
+ "dom": 't<"row"<"col-sm-3"l><"col-sm-5 text-center"i><"col-sm-4
text-right"p>>',
+ "data": [],
+ "columnDefs": [{
+ "targets": 0,
+ "width": "30%"
+ },
+ {
+ "targets": 1,
+ "width": "40%"
+ },
+ {
+ "targets": 2,
+ "width": "30%"
+ }
+ ],
+ "columns": [{
+ "data": "resourceGroup",
+ "name": "resourceGroup"
+ },
+ {
+ "data": "serverType"
+ },
+ {
+ "data": null,
+ "render": function (data, type, row) {
+ return row.responding + ' / ' + row.total;
+ }
+ }
+ ]
+ });
+
+ $('#deployment-rg-filter').on('keyup', function () {
+ var input = this.value;
+ if (isValidRegex(input) || input === '') {
+ $('#deployment-rg-feedback').hide();
+ $(this).removeClass('is-invalid');
+ deploymentBreakdownTable
+ .column('resourceGroup:name')
+ .search(input, true, false)
+ .draw();
+ } else {
+ $('#deployment-rg-feedback').show();
+ $(this).addClass('is-invalid');
+ }
+ });
+
refreshOverview();
});
@@ -29,17 +120,7 @@ $(function () {
* Makes the REST calls, generates the table with the new information
*/
function refreshOverview() {
- getStatus().then(function () {
- var managerStatus = JSON.parse(sessionStorage.status).managerStatus;
- // If the manager is down, show only the first row, otherwise refresh old
values
- $('#manager tr td').hide();
- if (managerStatus === 'ERROR') {
- $('#manager tr td:first').show();
- } else {
- $('#manager tr td:not(:first)').show();
- refreshManagerTable();
- }
- });
+ refreshDeploymentTables();
}
/**
@@ -50,16 +131,42 @@ function refresh() {
}
/**
- * Refreshes the manager table
+ * Refreshes the deployment overview tables
*/
-function refreshManagerTable() {
- getManager().then(function () {
- var data = JSON.parse(sessionStorage.manager);
- var table = $('#manager td.right');
+function refreshDeploymentTables() {
+ getDeployment().then(function () {
+ var data = JSON.parse(sessionStorage.deployment);
+ var breakdown = Array.isArray(data.breakdown) ? data.breakdown : [];
+ var summary = buildDeploymentSummary(breakdown);
+
+ if (breakdown.length === 0) {
+ $('#deploymentWarning').html('<div class="alert alert-warning"
role="alert">' +
+ 'No deployment data is currently available.</div>');
+ } else {
+ $('#deploymentWarning').empty();
+ }
- table.eq(0).html(data.host);
- table.eq(1).html(data.resourceGroup);
- table.eq(2).html(dateFormat(data.timestamp));
- table.eq(3).html('<a href="' + contextPath +
'rest-v2/manager/metrics">Metrics</a>');
+ deploymentSummaryTable.clear().rows.add(summary).draw();
+ deploymentBreakdownTable.clear().rows.add(breakdown).draw();
});
}
+
+function buildDeploymentSummary(breakdown) {
+ var totalsByType = new Map();
+
+ breakdown.forEach(function (row) {
+ var existing = totalsByType.get(row.serverType);
+ if (existing === undefined) {
+ totalsByType.set(row.serverType, {
+ serverType: row.serverType,
+ total: row.total,
+ responding: row.responding
+ });
+ } else {
+ existing.total += row.total;
+ existing.responding += row.responding;
+ }
+ });
+
+ return Array.from(totalsByType.values());
+}
diff --git
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/tservers.js
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/tservers.js
index 981ec85762..e03cff19b4 100644
---
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/tservers.js
+++
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/tservers.js
@@ -70,16 +70,28 @@ function refreshTServersTable() {
}
/**
- * If manager is down, tserver status will be ERROR. Add a banner to indicate
+ * Show a page banner that matches the tablet server status shown in the
navbar.
*/
-function refreshTServersBanner(managerStatus) {
- if (managerStatus === 'ERROR') {
+function refreshTServersBanner(statusData) {
+ if (statusData.managerStatus === 'ERROR') {
$('#tserversManagerBanner').show();
+ $('#tserversWarnBanner').hide();
+ $('#tserversErrorBanner').hide();
$('#tservers_wrapper').hide();
$('#recovery-caption').hide();
} else {
$('#tserversManagerBanner').hide();
$('#tservers_wrapper').show();
+ if (statusData.tServerStatus === 'ERROR') {
+ $('#tserversWarnBanner').hide();
+ $('#tserversErrorBanner').show();
+ } else if (statusData.tServerStatus === 'WARN') {
+ $('#tserversWarnBanner').show();
+ $('#tserversErrorBanner').hide();
+ } else {
+ $('#tserversWarnBanner').hide();
+ $('#tserversErrorBanner').hide();
+ }
}
}
@@ -88,8 +100,9 @@ function refreshTServersBanner(managerStatus) {
*/
function refreshTServers() {
getStatus().then(function () {
- var managerStatus = JSON.parse(sessionStorage.status).managerStatus;
- refreshTServersBanner(managerStatus);
+ var statusData = JSON.parse(sessionStorage.status);
+ var managerStatus = statusData.managerStatus;
+ refreshTServersBanner(statusData);
if (managerStatus === 'ERROR') {
return;
diff --git
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/overview.ftl
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/overview.ftl
index 55a6f2cad5..72875d4952 100644
---
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/overview.ftl
+++
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/overview.ftl
@@ -24,33 +24,46 @@
</div>
</div>
<div class="row d-flex justify-content-center">
- <div class="col-sm-6 col-sm-offset-3" id="manager">
- <table class="table table-bordered table-striped table-condensed">
- <thead>
- <tr>
- <th colspan="2"><a href="manager">Accumulo Manager</a></th>
- </tr>
- <tr>
- <td colspan="2" class="center" style="display:none;"><span
class="label label-danger nowrap">Manager is Down</span></td>
- </tr>
- <tr>
- <td class="left">Server</td>
- <td class="right"></td>
- </tr>
- <tr>
- <td class="left">Resource Group</td>
- <td class="right"></td>
- </tr>
- <tr>
- <td class="left">Last Contact</td>
- <td class="right"></td>
- </tr>
- <tr>
- <td class="left">Metrics</td>
- <td class="right"></td>
- </tr>
- </thead>
- <tbody></tbody>
- </table>
+ <div class="col-xs-12" id="deploymentOverview">
+ <div id="deploymentWarning"></div>
+ <div class="mb-4" style="max-width: 560px; margin: 0 auto;">
+ <table id="deploymentSummaryTable"
+ class="table table-bordered table-striped table-condensed"
style="width: 100%;">
+ <thead>
+ <tr>
+ <th colspan="2" class="center">Server Type Summary</th>
+ </tr>
+ <tr>
+ <th>Server Type</th>
+ <th>Responding / Total</th>
+ </tr>
+ </thead>
+ <tbody></tbody>
+ </table>
+ </div>
+
+ <div style="max-width: 760px; margin: 0 auto;">
+ <div class="mb-3">
+ <label for="deployment-rg-filter" class="form-label">Resource
Group Filter</label>
+ <input type="text" id="deployment-rg-filter" class="form-control"
+ placeholder="Enter resource group regex">
+ <small id="deployment-rg-feedback" class="form-text text-danger"
+ style="display:none;">Invalid regex pattern</small>
+ </div>
+ <table id="deploymentBreakdownTable"
+ class="table table-bordered table-striped table-condensed"
style="width: 100%;">
+ <thead>
+ <tr>
+ <th colspan="3" class="center">Deployment Breakdown</th>
+ </tr>
+ <tr>
+ <th>Resource Group</th>
+ <th>Server Type</th>
+ <th>Responding / Total</th>
+ </tr>
+ </thead>
+ <tbody></tbody>
+ </table>
+ </div>
</div>
- </div>
\ No newline at end of file
+ </div>
diff --git
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/tservers.ftl
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/tservers.ftl
index ac3368e946..311938b32d 100644
---
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/tservers.ftl
+++
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/templates/tservers.ftl
@@ -26,6 +26,16 @@
<div id="tserversManagerBanner" style="display: none;">
<div class="alert alert-danger" role="alert">Manager Not Running</div>
</div>
+ <div id="tserversWarnBanner" style="display: none;">
+ <div class="alert alert-warning" role="alert">
+ One or more Tablet Servers are unavailable or reported as bad.
+ </div>
+ </div>
+ <div id="tserversErrorBanner" style="display: none;">
+ <div class="alert alert-danger" role="alert">
+ No Tablet Servers are currently responding.
+ </div>
+ </div>
<div class="row">
<div class="col-xs-12">
<span id="recovery-caption" style="background-color: gold; display:
none;">Highlighted rows correspond to tservers in recovery mode.</span>