From 926bdb176af7fa59383add97f709a3d180336edd Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Tue, 27 Jan 2026 23:02:03 -0500 Subject: [PATCH 01/13] Seperate out into two end points --- .../solr/handler/admin/CoreInfoHandler.java | 77 +++++++++++++++++++ .../solr/handler/admin/SystemInfoHandler.java | 41 +--------- solr/core/src/resources/ImplicitPlugins.json | 6 +- 3 files changed, 84 insertions(+), 40 deletions(-) create mode 100644 solr/core/src/java/org/apache/solr/handler/admin/CoreInfoHandler.java diff --git a/solr/core/src/java/org/apache/solr/handler/admin/CoreInfoHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/CoreInfoHandler.java new file mode 100644 index 000000000000..d104888be37a --- /dev/null +++ b/solr/core/src/java/org/apache/solr/handler/admin/CoreInfoHandler.java @@ -0,0 +1,77 @@ +package org.apache.solr.handler.admin; + +import org.apache.solr.common.util.SimpleOrderedMap; +import org.apache.solr.core.SolrCore; +import org.apache.solr.handler.RequestHandlerBase; +import org.apache.solr.request.SolrQueryRequest; +import org.apache.solr.response.SolrQueryResponse; +import org.apache.solr.schema.IndexSchema; +import org.apache.solr.security.AuthorizationContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.lang.invoke.MethodHandles; +import java.nio.file.Path; +import java.util.Date; + +public class CoreInfoHandler extends RequestHandlerBase { + private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + + @Override + public String getDescription() { + return "Get Core Info"; + } + + @Override + public Category getCategory() { + return Category.ADMIN; + } + + @Override + public Name getPermissionName(AuthorizationContext request) { + return Name.CONFIG_READ_PERM; + } + + @Override + public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { + rsp.setHttpCaching(false); + SolrCore core = req.getCore(); + + rsp.add("core", getCoreInfo(core, req.getSchema())); + } + + + private SimpleOrderedMap getCoreInfo(SolrCore core, IndexSchema schema) { + SimpleOrderedMap info = new SimpleOrderedMap<>(); + + info.add("schema", schema != null ? schema.getSchemaName() : "no schema!"); + + + + // Now + info.add("now", new Date()); + + // Start Time + info.add("start", core.getStartTimeStamp()); + + // Solr Home + SimpleOrderedMap dirs = new SimpleOrderedMap<>(); + dirs.add("cwd", Path.of(System.getProperty("user.dir")).toAbsolutePath().toString()); + dirs.add("instance", core.getInstancePath().toString()); + try { + dirs.add("data", core.getDirectoryFactory().normalize(core.getDataDir())); + } catch (IOException e) { + log.warn("Problem getting the normalized data directory path", e); + dirs.add("data", "N/A"); + } + dirs.add("dirimpl", core.getDirectoryFactory().getClass().getName()); + try { + dirs.add("index", core.getDirectoryFactory().normalize(core.getIndexDir())); + } catch (IOException e) { + log.warn("Problem getting the normalized index directory path", e); + dirs.add("index", "N/A"); + } + info.add("directory", dirs); + return info; + } +} 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 16e78ab4268b..2ae5556f3cdb 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 @@ -219,13 +219,15 @@ private void initHostname() { @Override public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { rsp.setHttpCaching(false); - SolrCore core = req.getCore(); + //SolrCore core = req.getCore(); if (AdminHandlersProxy.maybeProxyToNodes(req, rsp, getCoreContainer(req))) { return; // Request was proxied to other node } - if (core != null) rsp.add("core", getCoreInfo(core, req.getSchema())); + //if (core != null) rsp.add("core", getCoreInfo(core, req.getSchema())); boolean solrCloudMode = getCoreContainer(req).isZooKeeperAware(); rsp.add("mode", solrCloudMode ? "solrcloud" : "std"); + + rsp.add("host", hostname); // moved from core. tree. if (solrCloudMode) { rsp.add("zkHost", getCoreContainer(req).getZkController().getZkServerAddress()); } @@ -263,41 +265,6 @@ private CoreContainer getCoreContainer(SolrQueryRequest req) { return coreContainer == null ? cc : coreContainer; } - /** Get system info */ - private SimpleOrderedMap getCoreInfo(SolrCore core, IndexSchema schema) { - SimpleOrderedMap info = new SimpleOrderedMap<>(); - - info.add("schema", schema != null ? schema.getSchemaName() : "no schema!"); - - // Host - info.add("host", hostname); - - // Now - info.add("now", new Date()); - - // Start Time - info.add("start", core.getStartTimeStamp()); - - // Solr Home - SimpleOrderedMap dirs = new SimpleOrderedMap<>(); - dirs.add("cwd", Path.of(System.getProperty("user.dir")).toAbsolutePath().toString()); - dirs.add("instance", core.getInstancePath().toString()); - try { - dirs.add("data", core.getDirectoryFactory().normalize(core.getDataDir())); - } catch (IOException e) { - log.warn("Problem getting the normalized data directory path", e); - dirs.add("data", "N/A"); - } - dirs.add("dirimpl", core.getDirectoryFactory().getClass().getName()); - try { - dirs.add("index", core.getDirectoryFactory().normalize(core.getIndexDir())); - } catch (IOException e) { - log.warn("Problem getting the normalized index directory path", e); - dirs.add("index", "N/A"); - } - info.add("directory", dirs); - return info; - } /** Get system info */ public static SimpleOrderedMap getSystemInfo() { diff --git a/solr/core/src/resources/ImplicitPlugins.json b/solr/core/src/resources/ImplicitPlugins.json index 4154e70ded9e..79305aba1b67 100644 --- a/solr/core/src/resources/ImplicitPlugins.json +++ b/solr/core/src/resources/ImplicitPlugins.json @@ -73,9 +73,9 @@ "class": "solr.LukeRequestHandler", "useParams":"_ADMIN_LUKE" }, - "/admin/system": { - "class": "solr.SystemInfoHandler", - "useParams":"_ADMIN_SYSTEM" + "/admin/core": { + "class": "solr.CoreInfoHandler", + "useParams":"_ADMIN_CORE" }, "/admin/file": { "class": "solr.ShowFileRequestHandler", From e662b0d11788fa474a13df166ca0d8db9ab4b857 Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Tue, 27 Jan 2026 23:29:22 -0500 Subject: [PATCH 02/13] use better path name --- solr/core/src/resources/ImplicitPlugins.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solr/core/src/resources/ImplicitPlugins.json b/solr/core/src/resources/ImplicitPlugins.json index 79305aba1b67..ec8072302fca 100644 --- a/solr/core/src/resources/ImplicitPlugins.json +++ b/solr/core/src/resources/ImplicitPlugins.json @@ -73,7 +73,7 @@ "class": "solr.LukeRequestHandler", "useParams":"_ADMIN_LUKE" }, - "/admin/core": { + "/admin/info": { "class": "solr.CoreInfoHandler", "useParams":"_ADMIN_CORE" }, From a0345d73b2fcd7dcd962ebe55d05e80429a88239 Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Wed, 28 Jan 2026 07:26:52 -0500 Subject: [PATCH 03/13] remove commented code --- .../solr/handler/admin/CoreInfoHandler.java | 11 ++++------- .../solr/handler/admin/SystemInfoHandler.java | 18 +++++++----------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/handler/admin/CoreInfoHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/CoreInfoHandler.java index d104888be37a..6bc91229a9fc 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/CoreInfoHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/CoreInfoHandler.java @@ -1,5 +1,9 @@ package org.apache.solr.handler.admin; +import java.io.IOException; +import java.lang.invoke.MethodHandles; +import java.nio.file.Path; +import java.util.Date; import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.core.SolrCore; import org.apache.solr.handler.RequestHandlerBase; @@ -9,10 +13,6 @@ import org.apache.solr.security.AuthorizationContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.lang.invoke.MethodHandles; -import java.nio.file.Path; -import java.util.Date; public class CoreInfoHandler extends RequestHandlerBase { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); @@ -40,14 +40,11 @@ public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throw rsp.add("core", getCoreInfo(core, req.getSchema())); } - private SimpleOrderedMap getCoreInfo(SolrCore core, IndexSchema schema) { SimpleOrderedMap info = new SimpleOrderedMap<>(); info.add("schema", schema != null ? schema.getSchemaName() : "no schema!"); - - // Now info.add("now", new Date()); 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 2ae5556f3cdb..2ae915bbc9d6 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 @@ -22,7 +22,6 @@ import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; -import java.io.IOException; import java.lang.invoke.MethodHandles; import java.lang.management.ManagementFactory; import java.lang.management.OperatingSystemMXBean; @@ -30,7 +29,6 @@ import java.lang.management.RuntimeMXBean; import java.lang.reflect.Method; import java.net.InetAddress; -import java.nio.file.Path; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.ArrayList; @@ -58,7 +56,6 @@ import org.apache.solr.metrics.GpuMetricsProvider; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.SolrQueryResponse; -import org.apache.solr.schema.IndexSchema; import org.apache.solr.security.AuthorizationContext; import org.apache.solr.security.AuthorizationPlugin; import org.apache.solr.security.PKIAuthenticationPlugin; @@ -97,7 +94,7 @@ public class SystemInfoHandler extends RequestHandlerBase { private static final ConcurrentMap, BeanInfo> beanInfos = new ConcurrentHashMap<>(); // on some platforms, resolving canonical hostname can cause the thread - // to block for several seconds if nameservices aren't available + // to block for several seconds if name services aren't available // so resolve this once per handler instance // (ie: not static, so core reload will refresh) private String hostname = null; @@ -219,11 +216,11 @@ private void initHostname() { @Override public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { rsp.setHttpCaching(false); - //SolrCore core = req.getCore(); + // SolrCore core = req.getCore(); if (AdminHandlersProxy.maybeProxyToNodes(req, rsp, getCoreContainer(req))) { return; // Request was proxied to other node } - //if (core != null) rsp.add("core", getCoreInfo(core, req.getSchema())); + // if (core != null) rsp.add("core", getCoreInfo(core, req.getSchema())); boolean solrCloudMode = getCoreContainer(req).isZooKeeperAware(); rsp.add("mode", solrCloudMode ? "solrcloud" : "std"); @@ -265,7 +262,6 @@ private CoreContainer getCoreContainer(SolrQueryRequest req) { return coreContainer == null ? cc : coreContainer; } - /** Get system info */ public static SimpleOrderedMap getSystemInfo() { SimpleOrderedMap info = new SimpleOrderedMap<>(); @@ -448,13 +444,13 @@ private static String humanReadableUnits(long bytes, DecimalFormat df) { String newSizeAndUnits; if (bytes / ONE_GB > 0) { - newSizeAndUnits = String.valueOf(df.format((float) bytes / ONE_GB)) + " GB"; + newSizeAndUnits = df.format((float) bytes / ONE_GB) + " GB"; } else if (bytes / ONE_MB > 0) { - newSizeAndUnits = String.valueOf(df.format((float) bytes / ONE_MB)) + " MB"; + newSizeAndUnits = df.format((float) bytes / ONE_MB) + " MB"; } else if (bytes / ONE_KB > 0) { - newSizeAndUnits = String.valueOf(df.format((float) bytes / ONE_KB)) + " KB"; + newSizeAndUnits = df.format((float) bytes / ONE_KB) + " KB"; } else { - newSizeAndUnits = String.valueOf(bytes) + " bytes"; + newSizeAndUnits = bytes + " bytes"; } return newSizeAndUnits; From 25419e409cc01b3d10dc57ff00e4fd9a35143485 Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Wed, 28 Jan 2026 07:30:41 -0500 Subject: [PATCH 04/13] add some docs --- .../java/org/apache/solr/handler/admin/CoreInfoHandler.java | 3 +++ .../org/apache/solr/handler/admin/SystemInfoHandler.java | 5 ++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/handler/admin/CoreInfoHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/CoreInfoHandler.java index 6bc91229a9fc..e798c7111546 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/CoreInfoHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/CoreInfoHandler.java @@ -14,6 +14,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * This handler returns core level info. See {@link org.apache.solr.handler.admin.SystemInfoHandler} + */ public class CoreInfoHandler extends RequestHandlerBase { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); 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 2ae915bbc9d6..992745122e0f 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 @@ -66,9 +66,8 @@ import org.slf4j.LoggerFactory; /** - * This handler returns system info - * - * @since solr 1.2 + * This handler returns node/container level info. See {@link + * org.apache.solr.handler.admin.CoreInfoHandler} */ public class SystemInfoHandler extends RequestHandlerBase { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); From 7d820150ca8ab0af23fbf2686f4203337c4a239a Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Wed, 28 Jan 2026 07:38:52 -0500 Subject: [PATCH 05/13] finally chase out remnants --- .../java/org/apache/solr/handler/admin/SystemInfoHandler.java | 3 +-- 1 file changed, 1 insertion(+), 2 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 992745122e0f..265c64f99e91 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 @@ -215,11 +215,10 @@ private void initHostname() { @Override public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { rsp.setHttpCaching(false); - // SolrCore core = req.getCore(); if (AdminHandlersProxy.maybeProxyToNodes(req, rsp, getCoreContainer(req))) { return; // Request was proxied to other node } - // if (core != null) rsp.add("core", getCoreInfo(core, req.getSchema())); + boolean solrCloudMode = getCoreContainer(req).isZooKeeperAware(); rsp.add("mode", solrCloudMode ? "solrcloud" : "std"); From 587f9800b4a5b842bade1bec6140e476a301f84b Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Sat, 31 Jan 2026 10:54:44 -0500 Subject: [PATCH 06/13] Introduce a test to support new handler --- .../handler/admin/CoreInfoHandlerTest.java | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 solr/core/src/test/org/apache/solr/handler/admin/CoreInfoHandlerTest.java diff --git a/solr/core/src/test/org/apache/solr/handler/admin/CoreInfoHandlerTest.java b/solr/core/src/test/org/apache/solr/handler/admin/CoreInfoHandlerTest.java new file mode 100644 index 000000000000..c7274605a715 --- /dev/null +++ b/solr/core/src/test/org/apache/solr/handler/admin/CoreInfoHandlerTest.java @@ -0,0 +1,117 @@ +/* + * 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.util.Date; +import org.apache.solr.SolrTestCaseJ4; +import org.apache.solr.common.util.NamedList; +import org.apache.solr.common.util.SimpleOrderedMap; +import org.apache.solr.core.SolrCore; +import org.apache.solr.request.SolrQueryRequest; +import org.apache.solr.response.SolrQueryResponse; +import org.junit.BeforeClass; +import org.junit.Test; + +/** Test for {@link CoreInfoHandler} */ +public class CoreInfoHandlerTest extends SolrTestCaseJ4 { + + @BeforeClass + public static void beforeClass() throws Exception { + initCore("solrconfig.xml", "schema.xml"); + } + + @Test + public void testCoreInfoHandlerResponse() throws Exception { + CoreInfoHandler handler = new CoreInfoHandler(); + SolrQueryRequest req = req(); + SolrQueryResponse rsp = new SolrQueryResponse(); + + handler.handleRequestBody(req, rsp); + + NamedList values = rsp.getValues(); + assertNotNull("Response should not be null", values); + + @SuppressWarnings("unchecked") + SimpleOrderedMap core = (SimpleOrderedMap) values.get("core"); + assertNotNull("Core info should not be null", core); + + // Verify schema name is present + String schema = (String) core.get("schema"); + assertNotNull("Schema should not be null", schema); + assertEquals("test", schema); + + // Verify 'now' date is present and reasonable + Date now = (Date) core.get("now"); + assertNotNull("Now date should not be null", now); + long currentTime = System.currentTimeMillis(); + long responseTime = now.getTime(); + assertTrue( + "Response time should be close to current time", + Math.abs(currentTime - responseTime) < 5000); // within 5 seconds + + // Verify start time is present + Date start = (Date) core.get("start"); + assertNotNull("Start time should not be null", start); + assertTrue("Start time should be before now", start.before(now) || start.equals(now)); + + // Verify directory info + @SuppressWarnings("unchecked") + SimpleOrderedMap directory = (SimpleOrderedMap) core.get("directory"); + assertNotNull("Directory info should not be null", directory); + + // Check all expected directory fields are present + assertNotNull("cwd should not be null", directory.get("cwd")); + assertNotNull("instance should not be null", directory.get("instance")); + assertNotNull("data should not be null", directory.get("data")); + assertNotNull("dirimpl should not be null", directory.get("dirimpl")); + assertNotNull("index should not be null", directory.get("index")); + + assertFalse("HTTP caching should be disabled", rsp.isHttpCaching()); + + req.close(); + } + + @Test + public void testCoreInfoMatchesActualCore() throws Exception { + CoreInfoHandler handler = new CoreInfoHandler(); + + try (SolrQueryRequest req = req()) { + SolrCore core = req.getCore(); + assertNotNull("Core should not be null", core); + + SolrQueryResponse rsp = new SolrQueryResponse(); + handler.handleRequestBody(req, rsp); + + @SuppressWarnings("unchecked") + SimpleOrderedMap coreInfo = (SimpleOrderedMap) rsp.getValues().get("core"); + + // Verify the schema name matches what we expect + String schemaName = (String) coreInfo.get("schema"); + assertEquals("Schema name should match", core.getLatestSchema().getSchemaName(), schemaName); + + // Verify start time matches core's start time + Date startTime = (Date) coreInfo.get("start"); + assertEquals("Start time should match core start time", core.getStartTimeStamp(), startTime); + + // Verify instance path is correctly reported + @SuppressWarnings("unchecked") + SimpleOrderedMap directory = (SimpleOrderedMap) coreInfo.get("directory"); + String instancePath = (String) directory.get("instance"); + assertEquals("Instance path should match", core.getInstancePath().toString(), instancePath); + } + } +} From 96b553b4de69a697eeb657e874921441f5251fdf Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Sat, 31 Jan 2026 10:59:51 -0500 Subject: [PATCH 07/13] lint --- changelog/unreleased/SOLR-18091.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 changelog/unreleased/SOLR-18091.yml diff --git a/changelog/unreleased/SOLR-18091.yml b/changelog/unreleased/SOLR-18091.yml new file mode 100644 index 000000000000..325a6d577364 --- /dev/null +++ b/changelog/unreleased/SOLR-18091.yml @@ -0,0 +1,8 @@ +# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc +title: Seperate the node/container level info from the core level info for the admin end points. +type: other # added, changed, fixed, deprecated, removed, dependency_update, security, other +authors: + - name: Eric Pugh +links: + - name: SOLR-18091 + url: https://issues.apache.org/jira/browse/SOLR-18091 From 0d4064fb5adc9f8473d66617f7c35abb95258e8b Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Sat, 31 Jan 2026 11:00:01 -0500 Subject: [PATCH 08/13] lint --- .../solr/handler/admin/CoreInfoHandler.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/solr/core/src/java/org/apache/solr/handler/admin/CoreInfoHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/CoreInfoHandler.java index e798c7111546..e03ef6253a29 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/CoreInfoHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/CoreInfoHandler.java @@ -1,3 +1,19 @@ +/* + * 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; From a02dcdf6593cf0d6c20fcb8ecda5fbc78d09999a Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Sat, 31 Jan 2026 11:58:58 -0500 Subject: [PATCH 09/13] More robust test to pass precheck --- .../org/apache/solr/handler/admin/CoreInfoHandlerTest.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/solr/core/src/test/org/apache/solr/handler/admin/CoreInfoHandlerTest.java b/solr/core/src/test/org/apache/solr/handler/admin/CoreInfoHandlerTest.java index c7274605a715..2b94d3233cfe 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/CoreInfoHandlerTest.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/CoreInfoHandlerTest.java @@ -66,7 +66,7 @@ public void testCoreInfoHandlerResponse() throws Exception { // Verify start time is present Date start = (Date) core.get("start"); assertNotNull("Start time should not be null", start); - assertTrue("Start time should be before now", start.before(now) || start.equals(now)); + assertTrue("Start time should be before or equal to now", start.getTime() <= now.getTime()); // Verify directory info @SuppressWarnings("unchecked") @@ -105,7 +105,10 @@ public void testCoreInfoMatchesActualCore() throws Exception { // Verify start time matches core's start time Date startTime = (Date) coreInfo.get("start"); - assertEquals("Start time should match core start time", core.getStartTimeStamp(), startTime); + assertEquals( + "Start time should match core start time", + core.getStartTimeStamp().getTime(), + startTime.getTime()); // Verify instance path is correctly reported @SuppressWarnings("unchecked") From 01ce123eab1e9becb23c3acc08da2590e28d7ecb Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Sat, 31 Jan 2026 13:03:37 -0500 Subject: [PATCH 10/13] Use the new endpoints for a core. --- solr/webapp/web/js/angular/controllers/core-overview.js | 9 ++++----- solr/webapp/web/js/angular/services.js | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/solr/webapp/web/js/angular/controllers/core-overview.js b/solr/webapp/web/js/angular/controllers/core-overview.js index 8605411c3715..4c97e6d12b07 100644 --- a/solr/webapp/web/js/angular/controllers/core-overview.js +++ b/solr/webapp/web/js/angular/controllers/core-overview.js @@ -16,7 +16,7 @@ */ solrAdminApp.controller('CoreOverviewController', -function($scope, $rootScope, $routeParams, Luke, CoreSystem, Update, Replication, Ping, Constants) { +function($scope, $rootScope, $routeParams, Luke, CoreInfo, Update, Replication, Ping, Constants) { $scope.resetMenu("overview", Constants.IS_CORE_PAGE); $scope.refreshIndex = function() { Luke.index({core: $routeParams.core}, @@ -42,8 +42,8 @@ function($scope, $rootScope, $routeParams, Luke, CoreSystem, Update, Replication }); }; - $scope.refreshSystem = function() { - CoreSystem.get({core: $routeParams.core}, + $scope.refreshInfo = function() { + CoreInfo.get({core: $routeParams.core}, function(data) { $scope.core = data.core; delete $scope.systemMessage; @@ -86,10 +86,9 @@ function($scope, $rootScope, $routeParams, Luke, CoreSystem, Update, Replication $scope.refresh = function() { $scope.refreshIndex(); $scope.refreshReplication(); - $scope.refreshSystem(); + $scope.refreshInfo(); $scope.refreshPing(); }; $scope.refresh(); }); - diff --git a/solr/webapp/web/js/angular/services.js b/solr/webapp/web/js/angular/services.js index 67eaa42e21fe..6af7cc8e3096 100644 --- a/solr/webapp/web/js/angular/services.js +++ b/solr/webapp/web/js/angular/services.js @@ -137,9 +137,9 @@ solrAdminServices.factory('System', "command": {params: {}} }); }]) -.factory('CoreSystem', +.factory('CoreInfo', ['$resource', function($resource) { - return $resource(':core/admin/system', {wt:'json', core: "@core", _:Date.now()}); + return $resource(':core/admin/info', {wt:'json', core: "@core", _:Date.now()}); }]) .factory('Update', ['$resource', function($resource) { From ea51ef6abd8a9c506943e9d47cda48d8881f0eec Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Sat, 31 Jan 2026 13:10:55 -0500 Subject: [PATCH 11/13] Now supporting the host name --- .../client/api/model/NodeSystemResponse.java | 1 + .../solr/handler/admin/SystemInfoHandler.java | 4 ++-- .../solrj/response/SystemInfoResponse.java | 22 +++++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/solr/api/src/java/org/apache/solr/client/api/model/NodeSystemResponse.java b/solr/api/src/java/org/apache/solr/client/api/model/NodeSystemResponse.java index 09bc35f08677..efd73c269dcd 100644 --- a/solr/api/src/java/org/apache/solr/client/api/model/NodeSystemResponse.java +++ b/solr/api/src/java/org/apache/solr/client/api/model/NodeSystemResponse.java @@ -25,6 +25,7 @@ public class NodeSystemResponse extends SolrJerseyResponse { @JsonProperty public String mode; + @JsonProperty public String host; @JsonProperty public String zkHost; @JsonProperty("solr_home") 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 bae293e5586f..33abf67e4e50 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 @@ -217,11 +217,11 @@ public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throw if (AdminHandlersProxy.maybeProxyToNodes(req, rsp, getCoreContainer(req))) { return; // Request was proxied to other node } - boolean solrCloudMode = getCoreContainer(req).isZooKeeperAware(); rsp.add("mode", solrCloudMode ? "solrcloud" : "std"); - rsp.add("host", hostname); // moved from core. tree. + rsp.add("host", hostname); + if (solrCloudMode) { rsp.add("zkHost", getCoreContainer(req).getZkController().getZkServerAddress()); } diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/response/SystemInfoResponse.java b/solr/solrj/src/java/org/apache/solr/client/solrj/response/SystemInfoResponse.java index a34981dc16b7..71274bfbf90f 100644 --- a/solr/solrj/src/java/org/apache/solr/client/solrj/response/SystemInfoResponse.java +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/response/SystemInfoResponse.java @@ -96,6 +96,28 @@ public String getModeForNode(String node) { return nodesInfo.get(node).mode; } + /** Get the hostname from a single node system info */ + public String getHost() { + if (nodesInfo.size() == 1) { + return nodesInfo.values().stream().findFirst().orElseThrow().host; + } else { + throw new UnsupportedOperationException( + "Multiple nodes system info available, use method 'getAllHosts', or 'getHostForNode(String)'."); + } + } + + /** Get all hostnames, per node */ + public Map getAllHosts() { + Map allHosts = new HashMap<>(); + nodesInfo.forEach((key, value) -> allHosts.put(key, value.host)); + return allHosts; + } + + /** Get the hostname for the given node name */ + public String getHostForNode(String node) { + return nodesInfo.get(node).host; + } + /** Get the ZK host from a single node system info */ public String getZkHost() { if (nodesInfo.size() == 1) { From c96a8e3e548c454507b5f12c9573b89a814acc3c Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Sat, 31 Jan 2026 13:32:24 -0500 Subject: [PATCH 12/13] rework the docs to reflect the new handler. --- .../configuration-guide/config-nav.adoc | 2 + .../pages/core-info-handler.adoc | 182 ++++++++++++++++++ .../pages/implicit-requesthandlers.adoc | 10 +- .../pages/system-info-handler.adoc | 37 +--- 4 files changed, 191 insertions(+), 40 deletions(-) create mode 100644 solr/solr-ref-guide/modules/configuration-guide/pages/core-info-handler.adoc diff --git a/solr/solr-ref-guide/modules/configuration-guide/config-nav.adoc b/solr/solr-ref-guide/modules/configuration-guide/config-nav.adoc index 3c939435b6a4..efafa996ad25 100644 --- a/solr/solr-ref-guide/modules/configuration-guide/config-nav.adoc +++ b/solr/solr-ref-guide/modules/configuration-guide/config-nav.adoc @@ -21,6 +21,7 @@ * xref:property-substitution.adoc[] * xref:core-discovery.adoc[] * xref:configuring-solr-xml.adoc[] +* xref:system-info-handler.adoc[] * xref:solr-properties.adoc[] * xref:configuring-solrconfig-xml.adoc[] @@ -31,6 +32,7 @@ ** xref:caches-warming.adoc[] ** xref:requesthandlers-searchcomponents.adoc[] ** xref:implicit-requesthandlers.adoc[] +** xref:core-info-handler.adoc[] ** xref:realtime-get.adoc[] ** xref:initparams.adoc[] ** xref:requestdispatcher.adoc[] diff --git a/solr/solr-ref-guide/modules/configuration-guide/pages/core-info-handler.adoc b/solr/solr-ref-guide/modules/configuration-guide/pages/core-info-handler.adoc new file mode 100644 index 000000000000..a2bef630212b --- /dev/null +++ b/solr/solr-ref-guide/modules/configuration-guide/pages/core-info-handler.adoc @@ -0,0 +1,182 @@ += Core Info Handler +// 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. + +This API provides the same information displayed on the Dashboard. + +Core information is available via: + +[source,bash] +---- +http://localhost:8983/solr//admin/info +---- + +The `core` key in the response is an object with these keys: + +`schema`:: +Schema name. + +`host`:: +Hostname. `null` if not available. + +`start`:: +Core start time. + +`now`:: +Current time on the core's host. + +`directory`:: +Object with directories relevant to the core. + +== Core Information API Examples + +Retrieve core information from a node in cloud mode. + +[source.bash] +---- +curl http://localhost:8983/solr/techproducts/admin/info +---- + +[source.json] +---- +{ + "responseHeader":{ + "status":0, + "QTime":9 + }, + "core":{ + "schema":"techprodducts", + "now":"2026-01-31T17:47:54.199Z", + "start":"2026-01-31T17:41:52.034Z", + "directory":{ + "cwd":"/var/solr/server", + "instance":"/var/solr/server/solr/techproducts_shard1_replica_n1", + "data":"/var/solr/server/solr/techproducts_shard1_replica_n1/data", + "dirimpl":"org.apache.solr.core.NRTCachingDirectoryFactory", + "index":"/var/solr/server/solr/techproducts_shard1_replica_n1/data/index" + } + } +} +---- + +Retrieve system information from a core, without cloud mode. + +[source.bash] +---- +curl http://localhost:8983/solr/gettingstarted/admin/system +---- + +[source.json] +---- +{ + "responseHeader":{ + "status":0, + "QTime":23}, + "core":{ + "schema":"default-config", + "host":"fd7fbdff8b3e", + "now":"2019-07-18T11:56:51.472Z", + "start":"2019-07-18T11:54:52.509Z", + "directory":{ + "cwd":"/opt/solr-8.1.1/server", + "instance":"/var/solr/data/gettingstarted", + "data":"/var/solr/data/gettingstarted/data", + "dirimpl":"org.apache.solr.core.NRTCachingDirectoryFactory", + "index":"/var/solr/data/gettingstarted/data/index"}}, + "mode":"std", + "lucene":{ + "solr-spec-version":"8.1.1", + "solr-impl-version":"8.1.1 fcbe46c28cef11bc058779afba09521de1b19bef - ab - 2019-05-22 15:20:01", + "lucene-spec-version":"8.1.1", + "lucene-impl-version":"8.1.1 fcbe46c28cef11bc058779afba09521de1b19bef - ab - 2019-05-22 15:15:24"}, + "jvm":{ + "version":"11.0.3 11.0.3+7", + "name":"Oracle Corporation OpenJDK 64-Bit Server VM", + "spec":{ + "vendor":"Oracle Corporation", + "name":"Java Platform API Specification", + "version":"11"}, + "jre":{ + "vendor":"Oracle Corporation", + "version":"11.0.3"}, + "vm":{ + "vendor":"Oracle Corporation", + "name":"OpenJDK 64-Bit Server VM", + "version":"11.0.3+7"}, + "processors":4, + "memory":{ + "free":"394.9 MB", + "total":"512 MB", + "max":"512 MB", + "used":"117.1 MB (%22.9)", + "raw":{ + "free":414074904, + "total":536870912, + "max":536870912, + "used":122796008, + "used%":22.87253886461258}}, + "jmx":{ + "classpath":"start.jar", + "commandLineArgs":["-Xms512m", + "-Xmx512m", + "-XX:+UseG1GC", + "-XX:+PerfDisableSharedMem", + "-XX:+ParallelRefProcEnabled", + "-XX:MaxGCPauseMillis=250", + "-XX:+UseLargePages", + "-XX:+AlwaysPreTouch", + "-Xlog:gc*:file=/var/solr/logs/solr_gc.log:time,uptime:filecount=9,filesize=20M", + "-Dcom.sun.management.jmxremote", + "-Dcom.sun.management.jmxremote.local.only=false", + "-Dcom.sun.management.jmxremote.ssl=false", + "-Dcom.sun.management.jmxremote.authenticate=false", + "-Dcom.sun.management.jmxremote.port=18983", + "-Dcom.sun.management.jmxremote.rmi.port=18983", + "-Dsolr.logs.dir=/var/solr/logs", + "-Dsolr.port.listen=8983", + "-DSTOP.PORT=7983", + "-DSTOP.KEY=solrrocks", + "-Duser.timezone=UTC", + "-Djetty.home=/opt/solr/server", + "-Dsolr.solr.home=/var/solr/data", + "-Dsolr.data.home=", + "-Dsolr.install.dir=/opt/solr", + "-Dsolr.configset.default.confdir=/opt/solr/server/solr/configsets/_default/conf", + "-Dlog4j.configurationFile=file:/var/solr/log4j2.xml", + "-Xss256k", + "-Dsolr.jetty.https.port=8983"], + "startTime":"2019-07-16T05:52:16.213Z", + "upTimeMS":194675370}}, + "system":{ + "name":"Linux", + "arch":"amd64", + "availableProcessors":4, + "systemLoadAverage":0.88, + "version":"4.9.0-9-amd64", + "committedVirtualMemorySize":4306059264, + "freePhysicalMemorySize":144179200, + "freeSwapSpaceSize":11626409984, + "processCpuLoad":0.0, + "processCpuTime":557920000000, + "systemCpuLoad":0.0, + "totalPhysicalMemorySize":4005376000, + "totalSwapSpaceSize":12884897792, + "maxFileDescriptorCount":1048576, + "openFileDescriptorCount":223, + "uname":"Linux fd7fbdff8b3e 4.9.0-9-amd64 #1 SMP Debian 4.9.168-1+deb9u3 (2019-06-16) x86_64 GNU/Linux\n", + "uptime":" 11:56:51 up 28 days, 23:00, 0 users, load average: 0.88, 0.65, 0.62\n"}} +---- diff --git a/solr/solr-ref-guide/modules/configuration-guide/pages/implicit-requesthandlers.adoc b/solr/solr-ref-guide/modules/configuration-guide/pages/implicit-requesthandlers.adoc index 85f25610a0ac..05784283e4de 100644 --- a/solr/solr-ref-guide/modules/configuration-guide/pages/implicit-requesthandlers.adoc +++ b/solr/solr-ref-guide/modules/configuration-guide/pages/implicit-requesthandlers.adoc @@ -103,19 +103,15 @@ Segments:: Return info on last commit generation Lucene index segments. |`solr//admin/segments` |{solr-javadocs}/core/org/apache/solr/handler/admin/SegmentsInfoRequestHandler.html[SegmentsInfoRequestHandler] |`_ADMIN_SEGMENTS` |=== -System Info:: Return server statistics and settings. +Core Info:: Return core information. + -*Documentation*: xref:system-info-handler.adoc[] +*Documentation*: xref:core-info-handler.adoc[] + [cols="3*.",frame=none,grid=cols,options="header"] |=== |API Endpoints |Class & Javadocs |Paramset -|v1: `solr/admin/info/system` - -v2: `api/node/system` |{solr-javadocs}/core/org/apache/solr/handler/admin/SystemInfoHandler.html[SystemInfoHandler] |`_ADMIN_SYSTEM` +|v1: `solr//admin/info`|{solr-javadocs}/core/org/apache/solr/handler/admin/CoreInfoHandler.html[CoreInfoHandler] | |=== -+ -This endpoint can also take the collection or core name in the path (`solr//admin/system` or `solr//admin/system`) which will include all of the system-level information and additional information about the specific core that served the request. Threads:: Return info on all JVM threads. + diff --git a/solr/solr-ref-guide/modules/configuration-guide/pages/system-info-handler.adoc b/solr/solr-ref-guide/modules/configuration-guide/pages/system-info-handler.adoc index f49175738162..6d55650a9488 100644 --- a/solr/solr-ref-guide/modules/configuration-guide/pages/system-info-handler.adoc +++ b/solr/solr-ref-guide/modules/configuration-guide/pages/system-info-handler.adoc @@ -18,22 +18,13 @@ This API provides the same information displayed on the Dashboard. -System information is available via two different URLs: +System information is available via: [source,bash] ---- -http://localhost:8983/solr/admin/system +http://localhost:8983/solr/admin/info/system ---- -and - -[source,bash] ----- -http://localhost:8983/solr//admin/system ----- - -the only difference being populating the `core` key in the result. - The keys in the result are: `mode`:: @@ -49,7 +40,7 @@ An object containing information on the JVM Information on the system. `solr_home`:: -Solr base directory. Only available under `/solr/admin/system`. +Solr base directory. Only available under `/solr/admin/info/system`. `zkHost`:: Zookeeper host, when running in cloud mode. @@ -57,10 +48,6 @@ Zookeeper host, when running in cloud mode. `node`:: Node name, when running cloud mode. -`core`:: -An object containing basic information on the core, only present if -the core/collection name is provided - == Lucene and Solr Information Object The `solr` key in the response is an object with these keys: @@ -103,23 +90,6 @@ The result of running `uname -a`. Not available on Windows. `uptime`:: The result of running `uptime`. Not available on Windows. -== Core Information Object - -`schema`:: -Schema name. - -`host`:: -Hostname. `null` if not available. - -`start`:: -Core start time. - -`now`:: -Current time on the core's host. - -`directory`:: -Object with directories relevant to the core. - == System Information API Examples Retrieve system information from a node in cloud mode. @@ -136,6 +106,7 @@ curl http://localhost:8983/solr/admin/info/system "status":0, "QTime":13}, "mode":"solrcloud", + "host":"localhost", "zkHost":"192.168.32.3:2181", "solr_home":"/var/solr/data", "lucene":{ From 84c94b03fee28bbac578252b11280abf8e723a6f Mon Sep 17 00:00:00 2001 From: Eric Pugh Date: Sat, 31 Jan 2026 14:55:40 -0500 Subject: [PATCH 13/13] pass forbiddenapi check --- .../org/apache/solr/handler/admin/CoreInfoHandlerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/solr/core/src/test/org/apache/solr/handler/admin/CoreInfoHandlerTest.java b/solr/core/src/test/org/apache/solr/handler/admin/CoreInfoHandlerTest.java index 2b94d3233cfe..39c8e964224a 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/CoreInfoHandlerTest.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/CoreInfoHandlerTest.java @@ -57,11 +57,11 @@ public void testCoreInfoHandlerResponse() throws Exception { // Verify 'now' date is present and reasonable Date now = (Date) core.get("now"); assertNotNull("Now date should not be null", now); - long currentTime = System.currentTimeMillis(); + Date currentTime = new Date(); long responseTime = now.getTime(); assertTrue( "Response time should be close to current time", - Math.abs(currentTime - responseTime) < 5000); // within 5 seconds + Math.abs(currentTime.getTime() - responseTime) < 5000); // within 5 seconds // Verify start time is present Date start = (Date) core.get("start");