This is an automated email from the ASF dual-hosted git repository.

dsmiley pushed a commit to branch branch_10x
in repository https://gitbox.apache.org/repos/asf/solr.git

commit 06eddf725910e0e6b005c0a7a950d588bbb4df0e
Author: Jan Høydahl <[email protected]>
AuthorDate: Thu Oct 8 08:33:22 2026 +0200

    SOLR-18400: Plugins screen 500s when metrics are disabled (#4803)
    
    (cherry picked from commit e34067ae6471af9b37f3da07409b0ab62c44f7bf)
---
 .../SOLR-18400-plugins-metrics-disabled.yml        | 11 ++++
 .../apache/solr/handler/admin/MetricsHandler.java  |  4 +-
 .../solr/handler/admin/MetricsDisabledTest.java    | 65 +++++++++++++++++++
 .../deployment-guide/pages/metrics-reporting.adoc  |  3 +
 .../AdminUiMetricsDisabledStandaloneTest.java      | 74 ++++++++++++++++++++++
 solr/webapp/web/js/angular/app.js                  |  5 +-
 solr/webapp/web/js/angular/controllers/plugins.js  |  7 ++
 solr/webapp/web/partials/plugins.html              |  3 +
 8 files changed, 169 insertions(+), 3 deletions(-)

diff --git a/changelog/unreleased/SOLR-18400-plugins-metrics-disabled.yml 
b/changelog/unreleased/SOLR-18400-plugins-metrics-disabled.yml
new file mode 100644
index 00000000000..812f62b29f8
--- /dev/null
+++ b/changelog/unreleased/SOLR-18400-plugins-metrics-disabled.yml
@@ -0,0 +1,11 @@
+title: >
+  The metrics endpoints now answer HTTP 510 when metrics collection is 
disabled in solr.xml,
+  on both the v1 and v2 API. The v1 API used to return HTTP 500, which made 
the Admin UI
+  Plugins / Stats screen render blank. It now explains that metrics are 
disabled.
+type: fixed
+authors:
+  - name: Jan Høydahl
+  - name: Eric Pugh
+links:
+  - name: SOLR-18400
+    url: https://issues.apache.org/jira/browse/SOLR-18400
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 784676656ae..d8063bfe988 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
@@ -124,8 +124,8 @@ public class MetricsHandler extends RequestHandlerBase 
implements PermissionName
 
   public void handleRequest(SolrParams params, BiConsumer<String, Object> 
consumer) {
     if (!enabled) {
-      consumer.accept("error", "metrics collection is disabled");
-      return;
+      throw new SolrException(
+          SolrException.ErrorCode.INVALID_STATE, "Metrics collection is 
disabled");
     }
 
     Set<String> metricNames = MetricUtils.readParamsAsSet(params, 
MetricUtils.METRIC_NAME_PARAM);
diff --git 
a/solr/core/src/test/org/apache/solr/handler/admin/MetricsDisabledTest.java 
b/solr/core/src/test/org/apache/solr/handler/admin/MetricsDisabledTest.java
new file mode 100644
index 00000000000..5f70377c444
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/handler/admin/MetricsDisabledTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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 org.apache.solr.client.solrj.request.MetricsRequest;
+import org.apache.solr.client.solrj.response.InputStreamResponseParser;
+import org.apache.solr.cloud.SolrCloudTestCase;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.NamedList;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * Both the v1 {@code /admin/metrics} and the v2 {@code /api/metrics} endpoint 
answer HTTP 510 when
+ * metrics collection is switched off in solr.xml.
+ */
+public class MetricsDisabledTest extends SolrCloudTestCase {
+
+  private static final String METRICS_V2_PATH = "/metrics";
+
+  @BeforeClass
+  public static void setupCluster() throws Exception {
+    // MiniSolrCloudCluster's default solr.xml has <metrics enabled="false">
+    configureCluster(1).configure();
+  }
+
+  @Test
+  public void testV1MetricsDisabled() throws Exception {
+    assertMetricsDisabled(CommonParams.METRICS_PATH);
+  }
+
+  @Test
+  public void testV2MetricsDisabled() throws Exception {
+    assertMetricsDisabled(METRICS_V2_PATH);
+  }
+
+  private static void assertMetricsDisabled(String path) throws Exception {
+    var req = new MetricsRequest(path, SolrParams.of(CommonParams.WT, 
"prometheus"));
+
+    NamedList<Object> resp = cluster.getSolrClient().request(req);
+    String body = InputStreamResponseParser.consumeResponseToString(resp);
+
+    assertEquals(
+        "Expected HTTP 510 from " + path,
+        SolrException.ErrorCode.INVALID_STATE.code,
+        (int) (Integer) resp.get(InputStreamResponseParser.HTTP_STATUS_KEY));
+    assertTrue(body, body.contains("Metrics collection is disabled"));
+  }
+}
diff --git 
a/solr/solr-ref-guide/modules/deployment-guide/pages/metrics-reporting.adoc 
b/solr/solr-ref-guide/modules/deployment-guide/pages/metrics-reporting.adoc
index 1be5df0b61b..880359491fd 100644
--- a/solr/solr-ref-guide/modules/deployment-guide/pages/metrics-reporting.adoc
+++ b/solr/solr-ref-guide/modules/deployment-guide/pages/metrics-reporting.adoc
@@ -171,6 +171,9 @@ The V2 `/metrics` endpoint is equivalent to the V1 
`/admin/metrics` endpoint.
 Examples on this page show only the V2 endpoint.
 ====
 
+Metrics collection can be switched off for a node with `<metrics 
enabled="false"/>` in `solr.xml`.
+Both endpoints then respond with `HTTP 510` and the message `Metrics 
collection is disabled`, which a Prometheus scraper reports as a target that is 
down.
+
 === Prometheus
 
 See https://prometheus.io/docs/concepts/data_model/[Prometheus Data Model] 
documentation for more information on its data model.
diff --git 
a/solr/webapp/src/test/org/apache/solr/webapp/AdminUiMetricsDisabledStandaloneTest.java
 
b/solr/webapp/src/test/org/apache/solr/webapp/AdminUiMetricsDisabledStandaloneTest.java
new file mode 100644
index 00000000000..7a97de4c6be
--- /dev/null
+++ 
b/solr/webapp/src/test/org/apache/solr/webapp/AdminUiMetricsDisabledStandaloneTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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.webapp;
+
+import java.nio.file.Path;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.openqa.selenium.By;
+
+/**
+ * SOLR-18400: the Plugins screen on a node with metrics collection switched 
off in solr.xml. The
+ * metrics endpoint answers HTTP 510 there, which the screen must turn into an 
explanation rather
+ * than a blank page or the global error banner.
+ */
+public class AdminUiMetricsDisabledStandaloneTest extends 
AdminUiStandaloneTestBase {
+
+  private static final String CORE = "collection1";
+
+  @BeforeClass
+  public static void startStandaloneNode() throws Exception {
+    // the base class turned metrics on for the UI screens; this suite is 
about them being off.
+    // Must come before the node starts, and is restored after the class with 
the other properties
+    System.setProperty("metricsEnabled", "false");
+    Path home = buildStandaloneHome(CORE);
+    standaloneJetty = startStandaloneJetty(home);
+    baseUrl = standaloneJetty.getBaseUrl().toString();
+    assertFalse(
+        "fixture node should have metrics disabled",
+        
standaloneJetty.getCoreContainer().getConfig().getMetricsConfig().isEnabled());
+  }
+
+  @AfterClass
+  public static void stopStandaloneNode() throws Exception {
+    if (standaloneJetty != null) {
+      standaloneJetty.stop();
+      standaloneJetty = null;
+    }
+  }
+
+  @Test
+  public void testPluginsScreenExplainsDisabledMetrics() {
+    openPage(CORE + "/plugins", By.id("plugins"));
+
+    String message = waitForText(By.cssSelector("#plugins .message-container 
.message"));
+    assertTrue(message, message.contains("Metrics collection is disabled"));
+
+    // no plugin categories or entries, as there is no metrics data to build 
them from
+    assertTrue(driver.findElements(By.cssSelector("#plugins #navigation 
a[rel]")).isEmpty());
+    assertTrue(driver.findElements(By.cssSelector("#plugins #frame 
li.entry")).isEmpty());
+
+    // the 510 is handled by the screen itself; the global error banner must 
stay away
+    assertTrue(
+        "global error banner should not show for a disabled feature",
+        driver.findElements(By.id("http-exception")).isEmpty());
+
+    // Chrome reports the failed XHR itself at SEVERE level; everything else 
must be clean
+    assertNoSevereConsoleErrors("510");
+  }
+}
diff --git a/solr/webapp/web/js/angular/app.js 
b/solr/webapp/web/js/angular/app.js
index 1558918d09e..aba91049975 100644
--- a/solr/webapp/web/js/angular/app.js
+++ b/solr/webapp/web/js/angular/app.js
@@ -429,6 +429,9 @@ solrAdminApp.config([
     // Schema Designer and Security panels handle errors internally to provide 
a better user experience than the global error handler
     var isHandledBySchemaDesigner = rejection.config.url && 
rejection.config.url.startsWith("/api/schema-designer/");
     var isHandledBySecurity = rejection.config.url && 
rejection.config.url.startsWith("/api/cluster/security/");
+    // HTTP 510 means a feature is switched off in solr.xml, e.g. metrics 
collection. The screen
+    // asking for that data explains it in place, so skip the global error 
banner.
+    var isDisabledFeature = rejection.status === 510 && rejection.config.url 
&& rejection.config.url.endsWith("admin/metrics");
     if (rejection.status === 0) {
       $rootScope.$broadcast('connectionStatusActive');
       if (!$rootScope.retryCount) $rootScope.retryCount=0;
@@ -463,7 +466,7 @@ solrAdminApp.config([
     } else if (isHandledBySecurity) {
       // Let the security panel surface the detailed error in its own dialog
       $rootScope.$broadcast('securityApiError', rejection);
-    } else {
+    } else if (!isDisabledFeature) {
       // schema designer prefers to handle errors itself
       if (!isHandledBySchemaDesigner) {
         $rootScope.exceptions[rejection.config.url] = rejection.data.error;
diff --git a/solr/webapp/web/js/angular/controllers/plugins.js 
b/solr/webapp/web/js/angular/controllers/plugins.js
index bf0dd9bcac7..157639980f0 100644
--- a/solr/webapp/web/js/angular/controllers/plugins.js
+++ b/solr/webapp/web/js/angular/controllers/plugins.js
@@ -35,6 +35,7 @@ solrAdminApp.controller('PluginsController',
             var type = $location.search().type;
 
             Metrics.raw(params, function (response) {
+                $scope.metricsDisabled = false;
                 $scope.types = getPluginTypesFromMetrics(response.data, type);
                 $scope.type = getSelectedType($scope.types, type);
 
@@ -44,6 +45,12 @@ solrAdminApp.controller('PluginsController',
                 } else {
                     $scope.plugins = [];
                 }
+            }, function (response) {
+                // Solr answers HTTP 510 when metrics collection is turned off 
in solr.xml
+                $scope.metricsDisabled = response.status === 510;
+                $scope.types = [];
+                $scope.type = null;
+                $scope.plugins = [];
             });
         };
 
diff --git a/solr/webapp/web/partials/plugins.html 
b/solr/webapp/web/partials/plugins.html
index 1e80b6f9b6e..f858f4ce6dd 100644
--- a/solr/webapp/web/partials/plugins.html
+++ b/solr/webapp/web/partials/plugins.html
@@ -17,6 +17,9 @@ limitations under the License.
 <div id="plugins" class="clearfix">
 
   <div id="frame">
+      <div class="message-container" ng-show="metricsDisabled">
+        <div class="message">Metrics collection is disabled in this node's 
solr.xml (&lt;metrics enabled="false"&gt;), so no plugin information is 
available.</div>
+      </div>
       <ul>
       <li class="entry" ng-class="{changed: plugin.changed}" ng-repeat="plugin 
in type.plugins">
         <a ng-click="selectPlugin(plugin)">

Reply via email to