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 923e2ac79e Consolidate monitor status fetching into a new shared 
endpoint (#6333)
923e2ac79e is described below

commit 923e2ac79e63d3edbed1e46e3d0654b706d258c3
Author: Dom G. <[email protected]>
AuthorDate: Tue Apr 28 10:04:32 2026 -0400

    Consolidate monitor status fetching into a new shared endpoint (#6333)
    
    * Consolidate monitor status fetching into a new shared endpoint
    
    * Move status calculation into SystemInformation build step
    
    * IDE automated cleanup reccomendations
---
 .../apache/accumulo/monitor/next/Endpoints.java    |  15 ++
 .../accumulo/monitor/next/SystemInformation.java   | 100 +++++++++++--
 .../accumulo/monitor/next/views/ServersView.java   |  26 ++--
 .../monitor/rest/status/StatusInformation.java     |  52 -------
 .../monitor/rest/status/StatusResource.java        | 101 -------------
 .../accumulo/monitor/resources/js/compactors.js    |   3 +-
 .../org/apache/accumulo/monitor/resources/js/ec.js |   2 +-
 .../accumulo/monitor/resources/js/functions.js     |  83 ++++++-----
 .../org/apache/accumulo/monitor/resources/js/gc.js |   9 +-
 .../accumulo/monitor/resources/js/manager.js       |  17 +--
 .../apache/accumulo/monitor/resources/js/navbar.js | 159 +++++----------------
 .../monitor/resources/js/server_process_common.js  |  44 ++++--
 .../accumulo/monitor/resources/js/sservers.js      |   3 +-
 .../accumulo/monitor/resources/js/tservers.js      |  39 ++---
 14 files changed, 262 insertions(+), 391 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 6346f22d10..a900e1c39e 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
@@ -58,6 +58,7 @@ import 
org.apache.accumulo.monitor.next.SystemInformation.TimeOrderedRunningComp
 import org.apache.accumulo.monitor.next.deployment.DeploymentOverview;
 import org.apache.accumulo.monitor.next.ec.CompactorsSummary;
 import org.apache.accumulo.monitor.next.views.ServersView;
+import org.apache.accumulo.monitor.next.views.ServersView.Status;
 
 import io.micrometer.core.instrument.Meter.Id;
 import io.micrometer.core.instrument.cumulative.CumulativeDistributionSummary;
@@ -83,6 +84,10 @@ public class Endpoints {
   @Inject
   private Monitor monitor;
 
+  public record MonitorStatus(String managerGoalState, 
Map<ServerId.Type,Status> componentStatuses,
+      long timestamp) {
+  }
+
   private void validateResourceGroup(String resourceGroup) {
     if 
(monitor.getInformationFetcher().getSummaryForEndpoint().getResourceGroups()
         .contains(resourceGroup)) {
@@ -160,6 +165,16 @@ public class Endpoints {
     return monitor.getInformationFetcher().getAllMetrics().asMap().get(s);
   }
 
+  @GET
+  @Path("status")
+  @Produces(MediaType.APPLICATION_JSON)
+  @Description("Returns status of server components")
+  public MonitorStatus getStatus() {
+    SystemInformation summary = 
monitor.getInformationFetcher().getSummaryForEndpoint();
+    return new MonitorStatus(summary.getManagerGoalState(), 
summary.getComponentStatuses(),
+        summary.getTimestamp());
+  }
+
   @GET
   @Path("instance")
   @Produces(MediaType.APPLICATION_JSON)
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 33493e3265..2009068829 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
@@ -33,6 +33,7 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -69,6 +70,7 @@ import 
org.apache.accumulo.monitor.next.deployment.DeploymentOverview;
 import org.apache.accumulo.monitor.next.views.ServersView;
 import org.apache.accumulo.monitor.next.views.ServersView.Column;
 import org.apache.accumulo.monitor.next.views.ServersView.ColumnFactory;
+import org.apache.accumulo.monitor.next.views.ServersView.Status;
 import org.apache.accumulo.server.ServerContext;
 import org.apache.accumulo.server.conf.TableConfiguration;
 import org.apache.accumulo.server.metrics.MetricResponseWrapper;
@@ -427,9 +429,12 @@ public class SystemInformation {
   private final Set<String> configuredCompactionResourceGroups = 
ConcurrentHashMap.newKeySet();
 
   private final AtomicLong timestamp = new AtomicLong(0);
+  private final EnumMap<ServerId.Type,Status> componentStatuses =
+      new EnumMap<>(ServerId.Type.class);
   private final EnumMap<ServersView.ServerTable,Supplier<ServersView>> 
serverMetricsView =
       new EnumMap<>(ServersView.ServerTable.class);
   private DeploymentOverview deploymentOverview = new DeploymentOverview(0L, 
List.of());
+  private String managerGoalState;
   private final int rgLongRunningCompactionSize;
 
   public SystemInformation(Cache<ServerId,MetricResponse> allMetrics, 
ServerContext ctx) {
@@ -465,6 +470,8 @@ public class SystemInformation {
     tableCompactions.clear();
     groupCompactions.clear();
     configuredCompactionResourceGroups.clear();
+    componentStatuses.clear();
+    managerGoalState = null;
     serverMetricsView.clear();
   }
 
@@ -726,6 +733,14 @@ public class SystemInformation {
     }
 
     timestamp.set(System.currentTimeMillis());
+    componentStatuses.clear();
+    for (final ServerId.Type type : ServerId.Type.values()) {
+      if (type == ServerId.Type.MONITOR) {
+        continue;
+      }
+      componentStatuses.put(type, computeServerStatus(type));
+    }
+    managerGoalState = computeManagerGoalState();
 
     for (Entry<TableId,LongAdder> e : runningCompactionsPerTable.entrySet()) {
       TableId tid = e.getKey();
@@ -741,38 +756,34 @@ public class SystemInformation {
         .forEach((k, v) -> groupCompactions.add(new CompactionGroupSummary(k, 
v.sum())));
 
     for (final ServerId.Type type : ServerId.Type.values()) {
-      long problemHostCount =
-          problemHosts.stream().filter(serverId -> serverId.getType() == 
type).count();
       Set<ServerId> servers = new HashSet<>();
       switch (type) {
         case COMPACTOR:
           compactors.values().forEach(servers::addAll);
-          cacheServerProcessView(ServersView.ServerTable.COMPACTORS, servers, 
problemHostCount);
+          cacheServerProcessView(ServersView.ServerTable.COMPACTORS, servers);
           break;
         case GARBAGE_COLLECTOR:
           servers.add(gc.get());
-          cacheServerProcessView(ServersView.ServerTable.GC_SUMMARY, servers, 
problemHostCount);
-          cacheServerProcessView(ServersView.ServerTable.GC_FILES, servers, 
problemHostCount);
-          cacheServerProcessView(ServersView.ServerTable.GC_WALS, servers, 
problemHostCount);
+          cacheServerProcessView(ServersView.ServerTable.GC_SUMMARY, servers);
+          cacheServerProcessView(ServersView.ServerTable.GC_FILES, servers);
+          cacheServerProcessView(ServersView.ServerTable.GC_WALS, servers);
           break;
         case MANAGER:
           servers.addAll(managers);
-          cacheServerProcessView(ServersView.ServerTable.MANAGERS, servers, 
problemHostCount);
-          cacheServerProcessView(ServersView.ServerTable.MANAGER_FATE, 
servers, problemHostCount);
-          cacheServerProcessView(ServersView.ServerTable.MANAGER_COMPACTIONS, 
servers,
-              problemHostCount);
+          cacheServerProcessView(ServersView.ServerTable.MANAGERS, servers);
+          cacheServerProcessView(ServersView.ServerTable.MANAGER_FATE, 
servers);
+          cacheServerProcessView(ServersView.ServerTable.MANAGER_COMPACTIONS, 
servers);
           ServersView coordinatorQueues = 
createCompactionQueueSummary(servers);
           serverMetricsView.put(ServersView.ServerTable.COORDINATOR_QUEUES,
               memoize(() -> coordinatorQueues));
-
           break;
         case SCAN_SERVER:
           sservers.values().forEach(servers::addAll);
-          cacheServerProcessView(ServersView.ServerTable.SCAN_SERVERS, 
servers, problemHostCount);
+          cacheServerProcessView(ServersView.ServerTable.SCAN_SERVERS, 
servers);
           break;
         case TABLET_SERVER:
           tservers.values().forEach(servers::addAll);
-          cacheServerProcessView(ServersView.ServerTable.TABLET_SERVERS, 
servers, problemHostCount);
+          cacheServerProcessView(ServersView.ServerTable.TABLET_SERVERS, 
servers);
           break;
         case MONITOR:
         default:
@@ -794,6 +805,64 @@ public class SystemInformation {
     return this.managers;
   }
 
+  public Status getServerStatus(ServerId.Type type) {
+    return componentStatuses.get(type);
+  }
+
+  public Map<ServerId.Type,Status> getComponentStatuses() {
+    return new EnumMap<>(componentStatuses);
+  }
+
+  public String getManagerGoalState() {
+    return managerGoalState;
+  }
+
+  private Status computeServerStatus(ServerId.Type type) {
+    Set<ServerId> servers = getServers(type);
+    long problemHostCount =
+        problemHosts.stream().filter(serverId -> serverId.getType() == 
type).count();
+    int missingMetricCount = (int) servers.stream()
+        .filter(serverId -> 
!ServersView.hasMetricData(allMetrics.getIfPresent(serverId))).count();
+    return ServersView.buildStatus(servers.size(), problemHostCount, 
missingMetricCount,
+        type == ServerId.Type.TABLET_SERVER);
+  }
+
+  private String computeManagerGoalState() {
+    Integer goalState = managers.stream().map(allMetrics::getIfPresent)
+        .map(response -> ServersView.metricValuesByName(response)
+            .get(Metric.MANAGER_GOAL_STATE.getName()))
+        .filter(value -> value != null && !value.isEmpty())
+        .map(value -> 
value.stream().map(SystemInformation::getMetricValue).filter(Objects::nonNull)
+            .map(Number::intValue).min(Comparator.naturalOrder()).orElse(null))
+        .filter(Objects::nonNull).min(Comparator.naturalOrder()).orElse(null);
+
+    return switch (goalState == null ? -1 : goalState) {
+      case 0 -> "CLEAN_STOP";
+      case 1 -> "SAFE_MODE";
+      case 2 -> "NORMAL";
+      default -> null;
+    };
+  }
+
+  private Set<ServerId> getServers(ServerId.Type type) {
+    return switch (type) {
+      case COMPACTOR -> getAll(compactors);
+      case GARBAGE_COLLECTOR -> {
+        final var gcServer = gc.get();
+        yield gcServer == null ? Set.of() : Set.of(gcServer);
+      }
+      case MANAGER -> Set.copyOf(managers);
+      case SCAN_SERVER -> getAll(sservers);
+      case TABLET_SERVER -> getAll(tservers);
+      case MONITOR -> Set.of();
+    };
+  }
+
+  private static Set<ServerId> getAll(Map<String,Set<ServerId>> 
groupedServers) {
+    return 
groupedServers.values().stream().flatMap(Set::stream).collect(HashSet::new, 
Set::add,
+        Set::addAll);
+  }
+
   public ServerId getGarbageCollector() {
     return this.gc.get();
   }
@@ -880,8 +949,9 @@ public class SystemInformation {
   /**
    * Cache a ServersView for the given table and set of servers.
    */
-  private void cacheServerProcessView(ServersView.ServerTable table, 
Set<ServerId> servers,
-      long problemHostCount) {
+  private void cacheServerProcessView(ServersView.ServerTable table, 
Set<ServerId> servers) {
+    long problemHostCount =
+        problemHosts.stream().filter(serverId -> 
servers.contains(serverId)).count();
     serverMetricsView.put(table, memoize(() -> new ServersView(servers, 
problemHostCount,
         allMetrics.asMap(), timestamp.get(), ServersView.columnsFor(table))));
   }
diff --git 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/views/ServersView.java
 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/views/ServersView.java
index 4807155ff5..cb75043752 100644
--- 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/next/views/ServersView.java
+++ 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/next/views/ServersView.java
@@ -29,7 +29,6 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
@@ -55,7 +54,6 @@ import org.slf4j.LoggerFactory;
  * columns - contains an array of column definitions that can be used to 
create the table headers
  *           and Data Table columns
  * data    - an array of objects that can be used for the Data Table data 
definition
- * status  - overall status information, counts, warnings, etc.
  * </pre>
  *
  * Each server-process table is identified by {@link ServerTable}. The 
table-specific metric methods
@@ -101,6 +99,7 @@ public class ServersView {
   }
 
   private static final String LEVEL_OK = "OK";
+  private static final String LEVEL_ERROR = "ERROR";
   private static final String LEVEL_WARN = "WARN";
 
   public static final String RG_COL_KEY = "resourceGroup";
@@ -157,14 +156,12 @@ public class ServersView {
 
   public final List<Map<String,Object>> data = new ArrayList<>();
   public final List<Column> columns;
-  public final Status status;
   public final long timestamp;
 
   public ServersView(final Set<ServerId> servers, final long 
problemServerCount,
       final Map<ServerId,MetricResponse> allMetrics, final long timestamp,
       final List<ColumnFactory> requestedColumns) {
 
-    AtomicInteger serversMissingMetrics = new AtomicInteger(0);
     // Grab the current metrics for each server
     List<ServerMetricRow> serverMetricRows = 
servers.stream().sorted().map(serverId -> {
       MetricResponse metricResponse = allMetrics.get(serverId);
@@ -172,10 +169,6 @@ public class ServersView {
       Map<String,List<FMetric>> serverMetrics =
           hasMetricData ? metricValuesByName(metricResponse) : Map.of();
 
-      if (!hasMetricData) {
-        serversMissingMetrics.incrementAndGet();
-      }
-
       return new ServerMetricRow(serverId, metricResponse, serverMetrics);
     }).toList();
 
@@ -189,15 +182,26 @@ public class ServersView {
       }
       data.add(row);
     });
-    status = buildStatus(servers.size(), problemServerCount, 
serversMissingMetrics.get());
     this.timestamp = timestamp;
   }
 
-  private static Status buildStatus(int serverCount, long problemServerCount,
+  public static Status buildStatus(int serverCount, long problemServerCount,
       int serversMissingMetrics) {
+    return buildStatus(serverCount, problemServerCount, serversMissingMetrics, 
false);
+  }
+
+  public static Status buildStatus(int serverCount, long problemServerCount,
+      int serversMissingMetrics, boolean errorWhenAllServersUnavailable) {
     final boolean hasServers = serverCount > 0;
     final boolean hasProblemServers = problemServerCount > 0;
     final boolean hasMissingMetrics = serversMissingMetrics > 0;
+    final boolean allServersUnavailable =
+        errorWhenAllServersUnavailable && hasServers && problemServerCount >= 
serverCount;
+
+    if (allServersUnavailable) {
+      return new Status(true, true, hasMissingMetrics, serverCount, 
problemServerCount,
+          serversMissingMetrics, LEVEL_ERROR, "ERROR: All servers are 
unavailable.");
+    }
 
     List<String> warnings = new ArrayList<>(2);
     if (hasProblemServers) {
@@ -217,7 +221,7 @@ public class ServersView {
         problemServerCount, serversMissingMetrics, LEVEL_WARN, message);
   }
 
-  private static boolean hasMetricData(MetricResponse mr) {
+  public static boolean hasMetricData(MetricResponse mr) {
     return mr != null && mr.getMetrics() != null && !mr.getMetrics().isEmpty();
   }
 
diff --git 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/status/StatusInformation.java
 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/status/StatusInformation.java
deleted file mode 100644
index d35b3214bd..0000000000
--- 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/status/StatusInformation.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.rest.status;
-
-/**
- * Generates status of manager, gc, and tservers, as well as log and problem 
report
- *
- * @since 2.0.0
- */
-public class StatusInformation {
-
-  // Variable names become JSON keys
-  public String managerStatus = null;
-  public String gcStatus = null;
-  public String tServerStatus = null;
-  public String coordinatorStatus = null;
-
-  public StatusInformation() {}
-
-  /**
-   * Generate the status report for the services
-   *
-   * @param managerStatus Status for the manager
-   * @param gcStatus Status for the GC
-   * @param tServerStatus Status for the tserver
-   * @param coordinatorStatus Status for the Compaction Coordinator
-   */
-  public StatusInformation(String managerStatus, String gcStatus, String 
tServerStatus,
-      String coordinatorStatus) {
-    this.managerStatus = managerStatus;
-    this.gcStatus = gcStatus;
-    this.tServerStatus = tServerStatus;
-    this.coordinatorStatus = coordinatorStatus;
-
-  }
-}
diff --git 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/status/StatusResource.java
 
b/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/status/StatusResource.java
deleted file mode 100644
index 9ca3042bb5..0000000000
--- 
a/server/monitor/src/main/java/org/apache/accumulo/monitor/rest/status/StatusResource.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 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.rest.status;
-
-import jakarta.inject.Inject;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.core.MediaType;
-
-import org.apache.accumulo.core.lock.ServiceLockPaths.ServiceLockPath;
-import org.apache.accumulo.core.manager.thrift.ManagerMonitorInfo;
-import org.apache.accumulo.monitor.Monitor;
-
-/**
- * Generates the status for manager, gc, and tservers as well as log and 
problem reports
- *
- * @since 2.0.0
- */
-@Path("/status")
-@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
-public class StatusResource {
-
-  @Inject
-  private Monitor monitor;
-
-  public enum Status {
-    OK, ERROR, WARN
-  }
-
-  /**
-   * Generates the JSON object with the status
-   *
-   * @return Status report
-   */
-  @GET
-  public StatusInformation getTables() {
-
-    Status managerStatus;
-    Status gcStatus;
-    Status tServerStatus = Status.ERROR;
-    Status coordinatorStatus = monitor.getCoordinatorHost().isPresent() ? 
Status.OK : Status.ERROR;
-
-    ManagerMonitorInfo mmi = monitor.getMmi();
-
-    if (mmi != null) {
-      if (monitor.getGcStatus() != null) {
-        gcStatus = Status.OK;
-      } else {
-        gcStatus = Status.ERROR;
-      }
-
-      ServiceLockPath slp = 
monitor.getContext().getServerPaths().getManager(true);
-      managerStatus = slp == null ? Status.ERROR : Status.OK;
-
-      int tServerUp = mmi.getTServerInfoSize();
-      int tServerDown = mmi.getDeadTabletServersSize();
-      int tServerBad = mmi.getBadTServersSize();
-
-      /*
-       * If there are no dead or bad servers and there are tservers up, status 
is OK, if there are
-       * dead or bad servers and there is at least a tserver up, status is 
WARN, otherwise, the
-       * status is an error.
-       */
-      if ((tServerDown > 0 || tServerBad > 0) && tServerUp > 0) {
-        tServerStatus = Status.WARN;
-      } else if ((tServerDown == 0 || tServerBad == 0) && tServerUp > 0) {
-        tServerStatus = Status.OK;
-      } else if (tServerUp == 0) {
-        tServerStatus = Status.ERROR;
-      }
-    } else {
-      managerStatus = Status.ERROR;
-      if (monitor.getGcStatus() == null) {
-        gcStatus = Status.ERROR;
-      } else {
-        gcStatus = Status.OK;
-      }
-      tServerStatus = Status.ERROR;
-    }
-
-    return new StatusInformation(managerStatus.toString(), gcStatus.toString(),
-        tServerStatus.toString(), coordinatorStatus.toString());
-  }
-}
diff --git 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/compactors.js
 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/compactors.js
index 8ce45315b4..51be0aa1d6 100644
--- 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/compactors.js
+++ 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/compactors.js
@@ -30,8 +30,7 @@ function refresh() {
 $(function () {
   sessionStorage[COMPACTOR_SERVER_PROCESS_VIEW] = JSON.stringify({
     data: [],
-    columns: [],
-    status: null
+    columns: []
   });
 
   refreshServerInformation(getCompactorsView, htmlTable, 
COMPACTOR_SERVER_PROCESS_VIEW,
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 9fcda2ec5b..41bcfd4c0f 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
@@ -321,7 +321,7 @@ function refreshRunningCompactions() {
  */
 async function refreshManagerStatus() {
   return getStatus().then(function () {
-    var managerStatus = JSON.parse(sessionStorage.status).managerStatus;
+    var managerStatus = getComponentStatus(getStoredStatusData(), 'MANAGER');
     if (managerStatus === 'ERROR') {
       // show banner and hide tables
       $('#managerBanner').show();
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 2d4a2c3260..a449eb78d5 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
@@ -23,7 +23,6 @@ var QUANTITY_SUFFIX = ['', 'K', 'M', 'B', 'T', 'e15', 'e18', 
'e21'];
 // Suffixes for size
 var SIZE_SUFFIX = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB'];
 const REST_V2_PREFIX = contextPath + 'rest-v2';
-const MANAGER_GOAL_STATE_METRIC = 'accumulo.manager.goal.state';
 
 const COMPACTOR_SERVER_PROCESS_VIEW = 'compactorsView';
 const COORDINATOR_QUEUE_PROCESS_VIEW = 'coordinatorQueueView';
@@ -35,6 +34,7 @@ const MANAGER_FATE_SERVER_PROCESS_VIEW = 'managersFateView';
 const MANAGER_COMPACTION_SERVER_PROCESS_VIEW = 'managersCompactionView';
 const SCAN_SERVER_PROCESS_VIEW = 'sserversView';
 const TABLET_SERVER_PROCESS_VIEW = 'tserversView';
+var STATUS_REQUEST = null;
 const RUNNING_COMPACTIONS_BY_TABLE = 'runningCompactionsByTable';
 const RUNNING_COMPACTIONS_BY_GROUP = 'runningCompactionsByGroup';
 
@@ -399,40 +399,6 @@ function doLoggedPostCall(call, callback, shouldSanitize) {
 
 ///// REST Calls /////////////
 
-/**
- * Gets the manager goal state from the cached manager response, if available.
- *
- * @return {string|null} Manager goal state (CLEAN_STOP, SAFE_MODE, NORMAL) or 
null
- */
-function getManagerGoalStateFromSession() {
-  var mgrs = getStoredRows(MANAGER_SERVER_PROCESS_VIEW);
-  if (!Array.isArray(mgrs) || mgrs.length === 0) {
-    console.debug('No manager data in session storage. Returning null.');
-    return null;
-  }
-  // There could be multiple managers that report different goal states.
-  // The goal state is stored in ZK, but it's eventually consistent.
-  // Use the lowest value seen as the current state for the Monitor
-  var goalState = 10;
-  $.each(mgrs, function (index, mgr) {
-    var stateVal = mgr[MANAGER_GOAL_STATE_METRIC];
-    if (stateVal < goalState) {
-      goalState = stateVal;
-    }
-  });
-  switch (goalState) {
-  case 0:
-    return 'CLEAN_STOP';
-  case 1:
-    return 'SAFE_MODE';
-  case 2:
-    return 'NORMAL';
-  default:
-    console.debug('Manager goal state metric not found');
-    return null;
-  }
-}
-
 /**
  * REST GET call for the namespaces, stores it on a global variable
  */
@@ -534,13 +500,6 @@ function getTableServers(tableID) {
   return getJSONForTable(contextPath + 'rest/tables/' + tableID, 
'tableServers');
 }
 
-/**
- * REST GET call for the server status, stores it on a sessionStorage variable
- */
-function getStatus() {
-  return getJSONForTable(contextPath + 'rest/status', 'status');
-}
-
 /*
  * Jquery call to clear all data from cells of a table
  */
@@ -637,6 +596,46 @@ function getMetrics() {
   return getJSONForTable(REST_V2_PREFIX + '/metrics', 'metrics');
 }
 
+/**
+ * REST GET call for /status,
+ * stores it on a sessionStorage variable
+ */
+function getStatus() {
+  if (STATUS_REQUEST) {
+    return STATUS_REQUEST;
+  }
+  STATUS_REQUEST = getJSONForTable(REST_V2_PREFIX + '/status', 'status');
+  STATUS_REQUEST.always(function () {
+    STATUS_REQUEST = null;
+  });
+  return STATUS_REQUEST;
+}
+
+function getStoredStatusData() {
+  return sessionStorage.status ? JSON.parse(sessionStorage.status) : null;
+}
+
+function getComponentStatus(statusData, componentType) {
+  if (!statusData || !statusData.componentStatuses) {
+    return 'ERROR';
+  }
+
+  var status = statusData.componentStatuses[componentType];
+  if (!status || !status.hasServers) {
+    return 'ERROR';
+  }
+
+  if (status.level === 'ERROR') {
+    return 'ERROR';
+  }
+
+  if (status.level === 'WARN') {
+    return 'WARN';
+  }
+
+  return 'OK';
+}
+
 /**
  * REST GET call for /gc,
  * stores it on a sessionStorage variable
diff --git 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/gc.js
 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/gc.js
index 95c515bdac..9e45a435c5 100644
--- 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/gc.js
+++ 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/gc.js
@@ -36,19 +36,16 @@ function refresh() {
 $(function () {
   sessionStorage[GC_SERVER_PROCESS_VIEW] = JSON.stringify({
     data: [],
-    columns: [],
-    status: null
+    columns: []
   });
 
   sessionStorage[GC_FILE_SERVER_PROCESS_VIEW] = JSON.stringify({
     data: [],
-    columns: [],
-    status: null
+    columns: []
   });
   sessionStorage[GC_WAL_SERVER_PROCESS_VIEW] = JSON.stringify({
     data: [],
-    columns: [],
-    status: null
+    columns: []
   });
 
   refreshServerInformation(getGcView, htmlTable, GC_SERVER_PROCESS_VIEW, 
htmlBanner,
diff --git 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/manager.js
 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/manager.js
index 0e20a8716d..569cc3c59e 100644
--- 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/manager.js
+++ 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/manager.js
@@ -27,7 +27,8 @@ const htmlTable = '#managers'
 const fateHtmlTable = '#managers_fate'
 
 function updateManagerGoalStateBanner() {
-  const goalState = getManagerGoalStateFromSession();
+  const status = sessionStorage.status ? JSON.parse(sessionStorage.status) : 
null;
+  const goalState = status ? status.managerGoalState : null;
   if (goalState === 'SAFE_MODE' || goalState === 'CLEAN_STOP') {
     $(managerStateBannerMessage)
       .removeClass('alert-danger alert-warning')
@@ -56,7 +57,7 @@ function refreshManagerBanners() {
 }
 
 function refresh() {
-  $.when(getManagersView(), getManagersFateView()).then(function () {
+  $.when(getManagersView(), getManagersFateView(), getStatus()).then(function 
() {
     refreshTable(htmlTable, MANAGER_SERVER_PROCESS_VIEW);
     refreshTable(fateHtmlTable, MANAGER_FATE_SERVER_PROCESS_VIEW);
     refreshManagerBanners();
@@ -64,13 +65,11 @@ function refresh() {
   }).fail(function () {
     sessionStorage[MANAGER_SERVER_PROCESS_VIEW] = JSON.stringify({
       data: [],
-      columns: [],
-      status: null
+      columns: []
     });
     sessionStorage[MANAGER_FATE_SERVER_PROCESS_VIEW] = JSON.stringify({
       data: [],
-      columns: [],
-      status: null
+      columns: []
     });
     refreshTable(htmlTable, MANAGER_SERVER_PROCESS_VIEW);
     refreshTable(fateHtmlTable, MANAGER_FATE_SERVER_PROCESS_VIEW);
@@ -85,13 +84,11 @@ function refresh() {
 $(function () {
   sessionStorage[MANAGER_SERVER_PROCESS_VIEW] = JSON.stringify({
     data: [],
-    columns: [],
-    status: null
+    columns: []
   });
   sessionStorage[MANAGER_FATE_SERVER_PROCESS_VIEW] = JSON.stringify({
     data: [],
-    columns: [],
-    status: null
+    columns: []
   });
 
   refresh();
diff --git 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/navbar.js
 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/navbar.js
index aa4a0d8a5b..ae78c821db 100644
--- 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/navbar.js
+++ 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/navbar.js
@@ -64,126 +64,43 @@ function updateElementStatus(elementId, status) {
  * @param {JSON} statusData object containing the status info for the servers
  */
 function updateServerNotifications(statusData) {
-  const applyStatuses = function (managerGoalState) {
-    const isSafeMode = managerGoalState === 'SAFE_MODE';
-    const isCleanStop = managerGoalState === 'CLEAN_STOP';
-
-    // setting manager status notification
-    if (statusData.managerStatus === STATUS.ERROR || isCleanStop) {
-      updateElementStatus('managerStatusNotification', STATUS.ERROR);
-    } else if (statusData.managerStatus === STATUS.WARN || isSafeMode) {
-      updateElementStatus('managerStatusNotification', STATUS.WARN);
-    } else if (statusData.managerStatus === STATUS.OK) {
-      updateElementStatus('managerStatusNotification', STATUS.OK);
-    } else {
-      console.error('Unrecognized manager state: ' + statusData.managerStatus 
+ '. Could not properly set manager status notification.');
-    }
-
-    // setting tserver status notification
-    if (statusData.tServerStatus === STATUS.OK) {
-      updateElementStatus('serverStatusNotification', STATUS.OK);
-    } else if (statusData.tServerStatus === STATUS.WARN) {
-      updateElementStatus('serverStatusNotification', STATUS.WARN);
-    } else {
-      updateElementStatus('serverStatusNotification', STATUS.ERROR);
-    }
-
-    // setting gc status notification
-    if (statusData.gcStatus === STATUS.OK) {
-      updateElementStatus('gcStatusNotification', STATUS.OK);
-    } else {
-      updateElementStatus('gcStatusNotification', STATUS.ERROR);
-    }
-
-    // setting scan server status notification
-    if (statusData.sServerStatus === STATUS.ERROR) {
-      updateElementStatus('sserverStatusNotification', STATUS.ERROR);
-    } else if (statusData.sServerStatus === STATUS.WARN) {
-      updateElementStatus('sserverStatusNotification', STATUS.WARN);
-    } else if (statusData.sServerStatus === STATUS.OK) {
-      updateElementStatus('sserverStatusNotification', STATUS.OK);
-    } else {
-      console.error('Unrecognized scan server state: ' + 
statusData.sServerStatus +
-        '. Could not properly set scan server status notification.');
-    }
-
-    // setting compactor status notification
-    if (statusData.compactorStatus === STATUS.OK) {
-      updateElementStatus('compactorStatusNotification', STATUS.OK);
-    } else {
-      updateElementStatus('compactorStatusNotification', STATUS.ERROR);
-    }
-
-    // Setting overall servers status notification
-    if ((statusData.managerStatus === STATUS.OK && !isSafeMode && 
!isCleanStop) &&
-      statusData.tServerStatus === STATUS.OK &&
-      statusData.gcStatus === STATUS.OK &&
-      statusData.sServerStatus === STATUS.OK &&
-      statusData.compactorStatus === STATUS.OK) {
-      updateElementStatus('statusNotification', STATUS.OK);
-    } else if (statusData.managerStatus === STATUS.ERROR || isCleanStop ||
-      statusData.tServerStatus === STATUS.ERROR ||
-      statusData.gcStatus === STATUS.ERROR ||
-      statusData.sServerStatus === STATUS.ERROR ||
-      statusData.compactorStatus === STATUS.ERROR) {
-      updateElementStatus('statusNotification', STATUS.ERROR);
-    } else if (statusData.managerStatus === STATUS.WARN || isSafeMode ||
-      statusData.tServerStatus === STATUS.WARN ||
-      statusData.gcStatus === STATUS.WARN ||
-      statusData.sServerStatus === STATUS.WARN) {
-      updateElementStatus('statusNotification', STATUS.WARN);
-    }
-  };
-
-
-  getManagersView().always(function () {
-    applyStatuses(getManagerGoalStateFromSession());
-  });
-}
-
-/**
- * Updates the scan server notification based on REST v2 status.
- */
-function refreshSserverStatus() {
-  return getSserversView().done(function () {
-    var view = sessionStorage.sserversView ? 
JSON.parse(sessionStorage.sserversView) : null;
-    var status = view && view.status ? view.status : null;
-    if (!status) {
-      sessionStorage.sServerStatus = STATUS.ERROR;
-      updateElementStatus('sserverStatusNotification', STATUS.ERROR);
-      return;
-    }
-
-    if (status.hasProblemScanServers === true) {
-      sessionStorage.sServerStatus = STATUS.WARN;
-      updateElementStatus('sserverStatusNotification', STATUS.WARN);
-    } else {
-      sessionStorage.sServerStatus = STATUS.OK;
-      updateElementStatus('sserverStatusNotification', STATUS.OK);
-    }
-  }).fail(function () {
-    // else, display ERROR when call fails
-    sessionStorage.sServerStatus = STATUS.ERROR;
-    updateElementStatus('sserverStatusNotification', STATUS.ERROR);
-  });
-}
+  const managerGoalState = statusData.managerGoalState;
+  const isSafeMode = managerGoalState === 'SAFE_MODE';
+  const isCleanStop = managerGoalState === 'CLEAN_STOP';
+  const componentStatuses = [
+    getComponentStatus(statusData, 'MANAGER'),
+    getComponentStatus(statusData, 'TABLET_SERVER'),
+    getComponentStatus(statusData, 'GARBAGE_COLLECTOR'),
+    getComponentStatus(statusData, 'SCAN_SERVER'),
+    getComponentStatus(statusData, 'COMPACTOR')
+  ];
+  const managerStatus = componentStatuses[0];
+
+  // setting manager status notification
+  if (managerStatus === STATUS.ERROR || isCleanStop) {
+    updateElementStatus('managerStatusNotification', STATUS.ERROR);
+  } else if (managerStatus === STATUS.WARN || isSafeMode) {
+    updateElementStatus('managerStatusNotification', STATUS.WARN);
+  } else if (managerStatus === STATUS.OK) {
+    updateElementStatus('managerStatusNotification', STATUS.OK);
+  } else {
+    console.error('Unrecognized manager state: ' + managerStatus +
+      '. Could not properly set manager status notification.');
+  }
 
-/**
- * Sets compactor menu status LED notification to OK if any compactors exist, 
else ERROR
- */
-function refreshCompactorStatus() {
-  return $.getJSON(REST_V2_PREFIX + '/ec/compactors').done(function (data) {
-    if (Number(data?.numCompactors) > 0) {
-      sessionStorage.compactorStatus = STATUS.OK;
-      updateElementStatus('compactorStatusNotification', STATUS.OK);
-    } else {
-      sessionStorage.compactorStatus = STATUS.ERROR;
-      updateElementStatus('compactorStatusNotification', STATUS.ERROR);
-    }
-  }).fail(function () {
-    sessionStorage.compactorStatus = STATUS.ERROR;
-    updateElementStatus('compactorStatusNotification', STATUS.ERROR);
-  });
+  updateElementStatus('serverStatusNotification', componentStatuses[1]);
+  updateElementStatus('gcStatusNotification', componentStatuses[2]);
+  updateElementStatus('sserverStatusNotification', componentStatuses[3]);
+  updateElementStatus('compactorStatusNotification', componentStatuses[4]);
+
+  // Setting overall servers status notification
+  if (!isSafeMode && !isCleanStop && componentStatuses.every(status => status 
=== STATUS.OK)) {
+    updateElementStatus('statusNotification', STATUS.OK);
+  } else if (isCleanStop || componentStatuses.some(status => status === 
STATUS.ERROR)) {
+    updateElementStatus('statusNotification', STATUS.ERROR);
+  } else if (isSafeMode || componentStatuses.some(status => status === 
STATUS.WARN)) {
+    updateElementStatus('statusNotification', STATUS.WARN);
+  }
 }
 
 /**
@@ -197,7 +114,7 @@ $(function () {
  * Makes the REST call for the server status, generates the sidebar with the 
new information
  */
 function refreshSidebar() {
-  $.when(getStatus(), refreshSserverStatus(), 
refreshCompactorStatus()).always(function () {
+  getStatus().always(function () {
     refreshSideBarNotifications();
   });
 }
@@ -218,8 +135,6 @@ function refreshSideBarNotifications() {
   if (!statusData) {
     return;
   }
-  statusData.sServerStatus = sessionStorage.sServerStatus || STATUS.OK;
-  statusData.compactorStatus = sessionStorage.compactorStatus || STATUS.OK;
 
   updateServerNotifications(statusData);
 }
diff --git 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/server_process_common.js
 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/server_process_common.js
index fd53c76b6c..b35c694951 100644
--- 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/server_process_common.js
+++ 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/server_process_common.js
@@ -48,8 +48,6 @@
  *       "uiClass": ""
  *     }
  *   ],
- *   "status": {
- *   },
  *   timestamp: long
  * }
  *
@@ -98,11 +96,36 @@ function getStoredRows(storageKey) {
 }
 
 /**
- * This function returns the stats object from the entire response
+ * This function returns the status object for a server process table.
  */
 function getStoredStatus(storageKey) {
-  var view = getStoredView(storageKey);
-  return view.status || null;
+  var status = sessionStorage.status ? JSON.parse(sessionStorage.status) : 
null;
+  var statusKey = getComponentStatusKey(storageKey);
+  if (!status || !status.componentStatuses || !statusKey) {
+    return null;
+  }
+  return status.componentStatuses[statusKey] || null;
+}
+
+function getComponentStatusKey(storageKey) {
+  switch (storageKey) {
+  case COMPACTOR_SERVER_PROCESS_VIEW:
+    return 'COMPACTOR';
+  case GC_SERVER_PROCESS_VIEW:
+  case GC_FILE_SERVER_PROCESS_VIEW:
+  case GC_WAL_SERVER_PROCESS_VIEW:
+    return 'GARBAGE_COLLECTOR';
+  case MANAGER_SERVER_PROCESS_VIEW:
+  case MANAGER_FATE_SERVER_PROCESS_VIEW:
+  case MANAGER_COMPACTION_SERVER_PROCESS_VIEW:
+    return 'MANAGER';
+  case SCAN_SERVER_PROCESS_VIEW:
+    return 'SCAN_SERVER';
+  case TABLET_SERVER_PROCESS_VIEW:
+    return 'TABLET_SERVER';
+  default:
+    return null;
+  }
 }
 
 /**
@@ -176,6 +199,12 @@ function refreshBanner(banner, bannerMsg, status) {
       .addClass('alert-warning')
       .text(status.message || 'WARN: server status warning.');
     $(banner).show();
+  } else if (status && status.level === 'ERROR') {
+    $(bannerMsg)
+      .removeClass('alert-warning')
+      .addClass('alert-danger')
+      .text(status.message || 'ERROR: server status error.');
+    $(banner).show();
   } else {
     $(banner).hide();
   }
@@ -200,14 +229,13 @@ function showBannerError(banner, bannerMsg) {
  * bannerMsg - reference to the HTML object that is the banner
  */
 function refreshServerInformation(callback, table, storageKey, banner, 
bannerMsg) {
-  callback().then(function () {
+  $.when(callback(), getStatus()).then(function () {
     refreshTable(table, storageKey);
     refreshBanner(banner, bannerMsg, getStoredStatus(storageKey));
   }).fail(function () {
     sessionStorage[storageKey] = JSON.stringify({
       data: [],
-      columns: [],
-      status: null
+      columns: []
     });
     refreshTable(table, storageKey);
     showBannerError(banner, bannerMsg);
diff --git 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/sservers.js
 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/sservers.js
index 5107b01e97..cf2a118111 100644
--- 
a/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/sservers.js
+++ 
b/server/monitor/src/main/resources/org/apache/accumulo/monitor/resources/js/sservers.js
@@ -30,8 +30,7 @@ function refresh() {
 $(function () {
   sessionStorage[SCAN_SERVER_PROCESS_VIEW] = JSON.stringify({
     data: [],
-    columns: [],
-    status: null
+    columns: []
   });
 
   refreshServerInformation(getSserversView, htmlTable, 
SCAN_SERVER_PROCESS_VIEW, htmlBanner,
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 b222870c1b..80259f8f87 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
@@ -63,27 +63,29 @@ function refreshRecoveryList() {
  * Show a page banner that matches the tablet server status shown in the 
navbar.
  */
 function refreshTServersBanner() {
-  var statusData = JSON.parse(sessionStorage.status);
-  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') {
+  getStatus().then(function () {
+    var statusData = getStoredStatusData();
+    if (getComponentStatus(statusData, 'MANAGER') === 'ERROR') {
+      $('#tserversManagerBanner').show();
       $('#tserversWarnBanner').hide();
-      $('#tserversErrorBanner').show();
-    } else if (statusData.tServerStatus === 'WARN') {
-      $('#tserversWarnBanner').show();
       $('#tserversErrorBanner').hide();
+      $('#tservers_wrapper').hide();
+      $('#recovery-caption').hide();
     } else {
-      $('#tserversWarnBanner').hide();
-      $('#tserversErrorBanner').hide();
+      $('#tserversManagerBanner').hide();
+      $('#tservers_wrapper').show();
+      if (getComponentStatus(statusData, 'TABLET_SERVER') === 'ERROR') {
+        $('#tserversWarnBanner').hide();
+        $('#tserversErrorBanner').show();
+      } else if (getComponentStatus(statusData, 'TABLET_SERVER') === 'WARN') {
+        $('#tserversWarnBanner').show();
+        $('#tserversErrorBanner').hide();
+      } else {
+        $('#tserversWarnBanner').hide();
+        $('#tserversErrorBanner').hide();
+      }
     }
-  }
+  });
 }
 
 
@@ -100,8 +102,7 @@ $(function () {
 
   sessionStorage[TABLET_SERVER_PROCESS_VIEW] = JSON.stringify({
     data: [],
-    columns: [],
-    status: null
+    columns: []
   });
 
   refreshServerInformation(getTserversView, htmlTable, 
TABLET_SERVER_PROCESS_VIEW, htmlBanner,


Reply via email to