This is an automated email from the ASF dual-hosted git repository.
gerlowskija pushed a commit to branch branch_10x
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/branch_10x by this push:
new a9b87593fae SOLR-17136: Add request classes for metrics and sys-info
(#3955)
a9b87593fae is described below
commit a9b87593fae28ef7720e82864f1896798f330906
Author: igiguere <[email protected]>
AuthorDate: Sun Dec 28 12:54:49 2025 -0500
SOLR-17136: Add request classes for metrics and sys-info (#3955)
Having dedicated SolrRequest implementations for these APIs gives users
a much better experience, and allows the server-side code to replace a
number of GenericSolrRequest usages that were pretty ugly in the
server's "core" module.
Co-authored-by: Isabelle Giguere <[email protected]>
Co-authored-by: Eric Pugh <[email protected]>
Co-authored-by: Jason Gerlowski <[email protected]>
---
.../SOLR-17136-replace-GenericSolrRequest.yml | 7 +
.../solr/client/api/model/NodeSystemResponse.java | 126 +++++++++++
.../src/java/org/apache/solr/cli/CLIUtils.java | 18 +-
.../src/java/org/apache/solr/cli/CreateTool.java | 16 +-
.../java/org/apache/solr/cli/HealthcheckTool.java | 21 +-
.../src/java/org/apache/solr/cli/StatusTool.java | 47 ++--
.../solr/cloud/api/collections/SplitShardCmd.java | 8 +-
.../solr/packagemanager/RepositoryManager.java | 17 +-
.../TestEmbeddedSolrServerAdminHandler.java | 28 +--
.../apache/solr/cloud/BasicDistributedZkTest.java | 10 +-
.../apache/solr/cloud/TestBaseStatsCacheCloud.java | 11 +-
.../solr/handler/admin/AdminHandlersProxyTest.java | 46 ++--
.../solr/handler/admin/MetricsHandlerTest.java | 16 +-
.../response/TestPrometheusResponseWriter.java | 21 +-
.../TestPrometheusResponseWriterCloud.java | 12 +-
.../apache/solr/security/MultiAuthPluginTest.java | 9 +-
.../security/jwt/JWTAuthPluginIntegrationTest.java | 11 +-
.../solr/opentelemetry/TestDistributedTracing.java | 6 +-
.../solr/opentelemetry/TestMetricExemplars.java | 10 +-
.../client/solrj/io/sql/DatabaseMetaDataImpl.java | 14 +-
.../solr/client/solrj/impl/NodeValueFetcher.java | 6 +-
.../solrj/impl/SolrClientNodeStateProvider.java | 5 +-
.../solr/client/solrj/request/MetricsRequest.java | 57 +++++
.../client/solrj/request/SystemInfoRequest.java | 83 +++++++
.../client/solrj/response/SystemInfoResponse.java | 251 +++++++++++++++++++++
.../apache/solr/common/params/CommonParams.java | 1 +
.../apache/solr/client/solrj/SolrExampleTests.java | 2 +-
.../solrj/response/SystemInfoResponseTest.java | 80 +++++++
.../org/apache/solr/util/SolrJMetricTestUtils.java | 24 +-
29 files changed, 722 insertions(+), 241 deletions(-)
diff --git a/changelog/unreleased/SOLR-17136-replace-GenericSolrRequest.yml
b/changelog/unreleased/SOLR-17136-replace-GenericSolrRequest.yml
new file mode 100644
index 00000000000..4d20d1a613f
--- /dev/null
+++ b/changelog/unreleased/SOLR-17136-replace-GenericSolrRequest.yml
@@ -0,0 +1,7 @@
+title: Introduce new SolrJ SolrRequest classes for metrics and "system info"
requests.
+type: added
+authors:
+- name: Isabelle Giguère
+links:
+- name: SOLR-17136
+ url: https://issues.apache.org/jira/browse/SOLR-17136
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
new file mode 100644
index 00000000000..09bc35f0867
--- /dev/null
+++ b/solr/api/src/java/org/apache/solr/client/api/model/NodeSystemResponse.java
@@ -0,0 +1,126 @@
+/*
+ * 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.client.api.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/** Response from /node/system */
+public class NodeSystemResponse extends SolrJerseyResponse {
+
+ @JsonProperty public String mode;
+ @JsonProperty public String zkHost;
+
+ @JsonProperty("solr_home")
+ public String solrHome;
+
+ @JsonProperty("core_root")
+ public String coreRoot;
+
+ @JsonProperty public String environment;
+
+ @JsonProperty(value = "environment_label")
+ public String environmentLabel;
+
+ @JsonProperty(value = "environment_color")
+ public String environmentColor;
+
+ @JsonProperty public String node;
+ @JsonProperty public Lucene lucene;
+ @JsonProperty public JVM jvm;
+ @JsonProperty public Security security;
+ @JsonProperty public GPU gpu;
+ @JsonProperty public Map<String, String> system;
+
+ /** /node/system/security */
+ public static class Security {
+ @JsonProperty public boolean tls;
+ @JsonProperty public String authenticationPlugin;
+ @JsonProperty public String authorizationPlugin;
+ @JsonProperty public String username;
+ @JsonProperty public List<String> roles;
+ @JsonProperty public List<String> permissions;
+ }
+
+ /** /node/system/lucene */
+ public static class Lucene {
+ @JsonProperty("solr-spec-version")
+ public String solrSpecVersion;
+
+ @JsonProperty("solr-impl-version")
+ public String solrImplVersion;
+
+ @JsonProperty("lucene-spec-version")
+ public String luceneSpecVersion;
+
+ @JsonProperty("lucene-impl-version")
+ public String luceneImplVersion;
+ }
+
+ /** /node/system/jvm */
+ public static class JVM extends Vendor {
+ @JsonProperty public int processors;
+ @JsonProperty public Vendor jre;
+ @JsonProperty public Vendor spec;
+ @JsonProperty public Vendor vm;
+ @JsonProperty public JvmJmx jmx;
+ @JsonProperty public JvmMemory memory;
+ }
+
+ public static class JvmMemory {
+ @JsonProperty public String free;
+ @JsonProperty public String total;
+ @JsonProperty public String max;
+ @JsonProperty public String used;
+ @JsonProperty public JvmMemoryRaw raw;
+ }
+
+ public static class JvmMemoryRaw extends MemoryRaw {
+ @JsonProperty public long max;
+
+ @JsonProperty("used%")
+ public double usedPercent;
+ }
+
+ public static class MemoryRaw {
+ @JsonProperty public long free;
+ @JsonProperty public long total;
+ @JsonProperty public long used;
+ }
+
+ public static class Vendor {
+ @JsonProperty public String name;
+ @JsonProperty public String vendor;
+ @JsonProperty public String version;
+ }
+
+ public static class JvmJmx {
+ @JsonProperty public String classpath;
+ @JsonProperty public Date startTime;
+ @JsonProperty public long upTimeMS;
+ @JsonProperty public List<String> commandLineArgs;
+ }
+
+ public static class GPU {
+ @JsonProperty public boolean available;
+ @JsonProperty public long count;
+ @JsonProperty public MemoryRaw memory;
+ @JsonProperty Map<String, Object> devices;
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/cli/CLIUtils.java
b/solr/core/src/java/org/apache/solr/cli/CLIUtils.java
index 0520fab4e51..36baeb8357f 100644
--- a/solr/core/src/java/org/apache/solr/cli/CLIUtils.java
+++ b/solr/core/src/java/org/apache/solr/cli/CLIUtils.java
@@ -19,7 +19,6 @@ package org.apache.solr.cli;
import static org.apache.solr.common.SolrException.ErrorCode.FORBIDDEN;
import static org.apache.solr.common.SolrException.ErrorCode.UNAUTHORIZED;
-import static org.apache.solr.common.params.CommonParams.SYSTEM_INFO_PATH;
import java.io.IOException;
import java.net.SocketException;
@@ -38,18 +37,17 @@ import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.exec.OS;
import org.apache.solr.client.solrj.SolrClient;
-import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.impl.SolrZkClientTimeout;
import org.apache.solr.client.solrj.jetty.HttpJettySolrClient;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.client.solrj.request.CoresApi;
-import org.apache.solr.client.solrj.request.GenericSolrRequest;
+import org.apache.solr.client.solrj.request.SystemInfoRequest;
+import org.apache.solr.client.solrj.response.SystemInfoResponse;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.cloud.SolrZkClient;
import org.apache.solr.common.cloud.ZkStateReader;
-import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.EnvUtils;
import org.apache.solr.common.util.NamedList;
@@ -249,12 +247,7 @@ public final class CLIUtils {
try (SolrClient solrClient = getSolrClient(cli)) {
// hit Solr to get system info
- NamedList<Object> systemInfo =
- solrClient.request(
- new GenericSolrRequest(SolrRequest.METHOD.GET,
CommonParams.SYSTEM_INFO_PATH));
-
- // convert raw JSON into user-friendly output
- Map<String, Object> status = StatusTool.reportStatus(systemInfo,
solrClient);
+ Map<String, Object> status = StatusTool.reportStatus(solrClient);
@SuppressWarnings("unchecked")
Map<String, Object> cloud = (Map<String, Object>) status.get("cloud");
if (cloud != null) {
@@ -357,9 +350,8 @@ public final class CLIUtils {
}
public static boolean isCloudMode(SolrClient solrClient) throws
SolrServerException, IOException {
- NamedList<Object> systemInfo =
- solrClient.request(new GenericSolrRequest(SolrRequest.METHOD.GET,
SYSTEM_INFO_PATH));
- return "solrcloud".equals(systemInfo.get("mode"));
+ SystemInfoResponse sysResponse = new
SystemInfoRequest().process(solrClient);
+ return "solrcloud".equals(sysResponse.getMode());
}
public static Path getConfigSetsDir(Path solrInstallDir) {
diff --git a/solr/core/src/java/org/apache/solr/cli/CreateTool.java
b/solr/core/src/java/org/apache/solr/cli/CreateTool.java
index b6790b4a4fa..d18d2e0c40e 100644
--- a/solr/core/src/java/org/apache/solr/cli/CreateTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/CreateTool.java
@@ -29,18 +29,17 @@ import org.apache.commons.cli.Options;
import org.apache.commons.io.file.PathUtils;
import org.apache.solr.cli.CommonCLIOptions.DefaultValues;
import org.apache.solr.client.solrj.SolrClient;
-import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.jetty.HttpJettySolrClient;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.client.solrj.request.CoreAdminRequest;
-import org.apache.solr.client.solrj.request.GenericSolrRequest;
+import org.apache.solr.client.solrj.request.SystemInfoRequest;
import org.apache.solr.client.solrj.response.CoreAdminResponse;
+import org.apache.solr.client.solrj.response.SystemInfoResponse;
import org.apache.solr.client.solrj.response.json.JsonMapResponseParser;
import org.apache.solr.cloud.ZkConfigSetService;
import org.apache.solr.common.cloud.ZkStateReader;
-import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.ConfigSetService;
import org.noggit.CharArr;
@@ -157,14 +156,9 @@ public class CreateTool extends ToolBase {
}
printDefaultConfigsetWarningIfNecessary(cli);
- String coreRootDirectory; // usually same as solr home, but not always
-
- NamedList<?> systemInfo =
- solrClient.request(
- new GenericSolrRequest(SolrRequest.METHOD.GET,
CommonParams.SYSTEM_INFO_PATH));
-
- // convert raw JSON into user-friendly output
- coreRootDirectory = (String) systemInfo.get("core_root");
+ SystemInfoResponse sysResponse = (new
SystemInfoRequest()).process(solrClient);
+ // usually same as solr home, but not always
+ String coreRootDirectory = sysResponse.getCoreRoot();
if (CLIUtils.safeCheckCoreExists(
solrUrl, coreName,
cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION))) {
diff --git a/solr/core/src/java/org/apache/solr/cli/HealthcheckTool.java
b/solr/core/src/java/org/apache/solr/cli/HealthcheckTool.java
index ef0f61bebda..8745941cff3 100644
--- a/solr/core/src/java/org/apache/solr/cli/HealthcheckTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/HealthcheckTool.java
@@ -30,18 +30,16 @@ import java.util.Set;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
-import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
-import org.apache.solr.client.solrj.request.GenericSolrRequest;
import org.apache.solr.client.solrj.request.SolrQuery;
+import org.apache.solr.client.solrj.request.SystemInfoRequest;
import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.client.solrj.response.SystemInfoResponse;
import org.apache.solr.common.cloud.ClusterState;
import org.apache.solr.common.cloud.DocCollection;
import org.apache.solr.common.cloud.Replica;
import org.apache.solr.common.cloud.Slice;
import org.apache.solr.common.cloud.ZkStateReader;
-import org.apache.solr.common.params.CommonParams;
-import org.apache.solr.common.util.NamedList;
import org.noggit.CharArr;
import org.noggit.JSONWriter;
import org.slf4j.Logger;
@@ -168,15 +166,12 @@ public class HealthcheckTool extends ToolBase {
try (var solrClient =
CLIUtils.getSolrClient(
r.getBaseUrl(),
cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION))) {
- NamedList<Object> systemInfo =
- solrClient.request(
- new GenericSolrRequest(
- SolrRequest.METHOD.GET,
CommonParams.SYSTEM_INFO_PATH));
- uptime =
- SolrCLI.uptime((Long) systemInfo._get(List.of("jvm", "jmx",
"upTimeMS"), null));
- String usedMemory = systemInfo._getStr(List.of("jvm", "memory",
"used"), null);
- String totalMemory = systemInfo._getStr(List.of("jvm", "memory",
"total"), null);
- memory = usedMemory + " of " + totalMemory;
+ SystemInfoResponse sysResponse = (new
SystemInfoRequest()).process(solrClient);
+ uptime = SolrCLI.uptime(sysResponse.getJVMUpTimeMillis());
+ memory =
+ sysResponse.getHumanReadableJVMMemoryUsed()
+ + " of "
+ + sysResponse.getHumanReadableJVMMemoryTotal();
}
// if we get here, we can trust the state
diff --git a/solr/core/src/java/org/apache/solr/cli/StatusTool.java
b/solr/core/src/java/org/apache/solr/cli/StatusTool.java
index 2f7422c054f..9fee5940a17 100644
--- a/solr/core/src/java/org/apache/solr/cli/StatusTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/StatusTool.java
@@ -31,10 +31,9 @@ import org.apache.commons.cli.OptionGroup;
import org.apache.commons.cli.Options;
import org.apache.solr.cli.SolrProcessManager.SolrProcess;
import org.apache.solr.client.solrj.SolrClient;
-import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
-import org.apache.solr.client.solrj.request.GenericSolrRequest;
-import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.client.solrj.request.SystemInfoRequest;
+import org.apache.solr.client.solrj.response.SystemInfoResponse;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.URLUtil;
import org.noggit.CharArr;
@@ -292,42 +291,30 @@ public class StatusTool extends ToolBase {
public Map<String, Object> getStatus(String solrUrl, String credentials)
throws Exception {
try (var solrClient = CLIUtils.getSolrClient(solrUrl, credentials)) {
- return getStatus(solrClient);
+ Map<String, Object> status = reportStatus(solrClient);
+ return status;
}
}
- public Map<String, Object> getStatus(SolrClient solrClient) throws Exception
{
- Map<String, Object> status;
-
- NamedList<Object> systemInfo =
- solrClient.request(
- new GenericSolrRequest(SolrRequest.METHOD.GET,
CommonParams.SYSTEM_INFO_PATH));
- // convert raw JSON into user-friendly output
- status = reportStatus(systemInfo, solrClient);
-
- return status;
- }
-
- public static Map<String, Object> reportStatus(NamedList<Object> info,
SolrClient solrClient)
- throws Exception {
+ public static Map<String, Object> reportStatus(SolrClient solrClient) throws
Exception {
Map<String, Object> status = new LinkedHashMap<>();
+ SystemInfoResponse sysResponse = (new
SystemInfoRequest()).process(solrClient);
+ status.put("solr_home", sysResponse.getSolrHome() != null ?
sysResponse.getSolrHome() : "?");
+ status.put("version", sysResponse.getSolrImplVersion());
- String solrHome = (String) info.get("solr_home");
- status.put("solr_home", solrHome != null ? solrHome : "?");
- status.put("version", info._getStr(List.of("lucene", "solr-impl-version"),
null));
- status.put("startTime", info._getStr(List.of("jvm", "jmx", "startTime"),
null));
- status.put("uptime", SolrCLI.uptime((Long) info._get(List.of("jvm", "jmx",
"upTimeMS"), null)));
+ status.put("startTime", sysResponse.getJVMStartTime());
+ status.put("uptime", sysResponse.getJVMUpTimeMillis());
- String usedMemory = info._getStr(List.of("jvm", "memory", "used"), null);
- String totalMemory = info._getStr(List.of("jvm", "memory", "total"), null);
- status.put("memory", usedMemory + " of " + totalMemory);
+ status.put(
+ "memory",
+ sysResponse.getHumanReadableJVMMemoryUsed()
+ + " of "
+ + sysResponse.getHumanReadableJVMMemoryTotal());
// if this is a Solr in solrcloud mode, gather some basic cluster info
- if ("solrcloud".equals(info.get("mode"))) {
- String zkHost = (String) info.get("zkHost");
- status.put("cloud", getCloudStatus(solrClient, zkHost));
+ if ("solrcloud".equals(sysResponse.getMode())) {
+ status.put("cloud", getCloudStatus(solrClient, sysResponse.getZkHost()));
}
-
return status;
}
diff --git
a/solr/core/src/java/org/apache/solr/cloud/api/collections/SplitShardCmd.java
b/solr/core/src/java/org/apache/solr/cloud/api/collections/SplitShardCmd.java
index 8548a0bc17a..c799ec98969 100644
---
a/solr/core/src/java/org/apache/solr/cloud/api/collections/SplitShardCmd.java
+++
b/solr/core/src/java/org/apache/solr/cloud/api/collections/SplitShardCmd.java
@@ -39,13 +39,12 @@ import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
-import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrResponse;
import org.apache.solr.client.solrj.cloud.DistribStateManager;
import org.apache.solr.client.solrj.cloud.SolrCloudManager;
import org.apache.solr.client.solrj.cloud.VersionedData;
import org.apache.solr.client.solrj.request.CoreAdminRequest;
-import org.apache.solr.client.solrj.request.GenericSolrRequest;
+import org.apache.solr.client.solrj.request.MetricsRequest;
import org.apache.solr.cloud.DistributedClusterStateUpdater;
import org.apache.solr.cloud.Overseer;
import
org.apache.solr.cloud.api.collections.CollectionHandlingUtils.ShardRequestTracker;
@@ -869,10 +868,7 @@ public class SplitShardCmd implements
CollApiCmds.CollectionApiCommand {
new ModifiableSolrParams()
.add("key", indexSizeMetricName)
.add("key", freeDiskSpaceMetricName);
- SolrResponse rsp =
- new GenericSolrRequest(
- SolrRequest.METHOD.GET, "/admin/metrics",
SolrRequest.SolrRequestType.ADMIN, params)
- .process(cloudManager.getSolrClient());
+ SolrResponse rsp = new
MetricsRequest(params).process(cloudManager.getSolrClient());
Number size = (Number) rsp.getResponse()._get(List.of("metrics",
indexSizeMetricName), null);
if (size == null) {
diff --git
a/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java
b/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java
index b56d6441709..7e5c0e16b29 100644
--- a/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java
+++ b/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java
@@ -18,7 +18,6 @@
package org.apache.solr.packagemanager;
import static org.apache.solr.cli.SolrCLI.printGreen;
-import static org.apache.solr.common.params.CommonParams.SYSTEM_INFO_PATH;
import static org.apache.solr.packagemanager.PackageUtils.getMapper;
import java.io.IOException;
@@ -47,10 +46,13 @@ import org.apache.solr.client.solrj.request.FileStoreApi;
import org.apache.solr.client.solrj.request.GenericSolrRequest;
import org.apache.solr.client.solrj.request.GenericV2SolrRequest;
import org.apache.solr.client.solrj.request.RequestWriter;
+import org.apache.solr.client.solrj.request.SystemInfoRequest;
import org.apache.solr.client.solrj.request.beans.PackagePayload;
+import org.apache.solr.client.solrj.response.SystemInfoResponse;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.cloud.SolrZkClient;
+import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.Utils;
import org.apache.solr.filestore.ClusterFileStore;
@@ -142,14 +144,17 @@ public class RepositoryManager {
public void addKey(byte[] key, String destinationKeyFilename) throws
Exception {
// get solr_home directory from info servlet
- NamedList<Object> systemInfo =
- solrClient.request(
- new GenericSolrRequest(SolrRequest.METHOD.GET, "/solr" +
SYSTEM_INFO_PATH));
- String solrHome = (String) systemInfo.get("solr_home");
+ // This method is only called from PackageTool ("add-repo", or "add-key"),
where the Solr URL is
+ // normalized to remove the /solr path part
+ // So might as well ping the V2 API "/node/system" instead.
+ // Otherwise, this SystemInfoRequest constructor would need to set the full
+ // /solr/admin/info/system path
+ SystemInfoResponse sysResponse =
+ new
SystemInfoRequest(CommonParams.V2_SYSTEM_INFO_PATH).process(solrClient);
// put the public key into package store's trusted key store and request a
sync.
String path = ClusterFileStore.KEYS_DIR + "/" + destinationKeyFilename;
- PackageUtils.uploadKey(key, path, Path.of(solrHome));
+ PackageUtils.uploadKey(key, path, Path.of(sysResponse.getSolrHome()));
final var syncRequest = new FileStoreApi.SyncFile(path);
final var syncResponse = syncRequest.process(solrClient);
final var status = syncResponse.responseHeader.status;
diff --git
a/solr/core/src/test/org/apache/solr/client/solrj/embedded/TestEmbeddedSolrServerAdminHandler.java
b/solr/core/src/test/org/apache/solr/client/solrj/embedded/TestEmbeddedSolrServerAdminHandler.java
index 7118520fa12..33be625e1ad 100644
---
a/solr/core/src/test/org/apache/solr/client/solrj/embedded/TestEmbeddedSolrServerAdminHandler.java
+++
b/solr/core/src/test/org/apache/solr/client/solrj/embedded/TestEmbeddedSolrServerAdminHandler.java
@@ -18,12 +18,9 @@ package org.apache.solr.client.solrj.embedded;
import java.io.IOException;
import org.apache.solr.SolrTestCaseJ4;
-import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
-import org.apache.solr.client.solrj.response.QueryResponse;
-import org.apache.solr.common.params.ModifiableSolrParams;
-import org.apache.solr.common.params.SolrParams;
-import org.apache.solr.common.util.NamedList;
+import org.apache.solr.client.solrj.request.SystemInfoRequest;
+import org.apache.solr.client.solrj.response.SystemInfoResponse;
import org.apache.solr.core.NodeConfig;
import org.junit.Test;
@@ -39,25 +36,8 @@ public class TestEmbeddedSolrServerAdminHandler extends
SolrTestCaseJ4 {
try (final EmbeddedSolrServer server = new EmbeddedSolrServer(config,
"collection1")) {
final SystemInfoRequest info = new SystemInfoRequest();
- final NamedList<?> response = server.request(info);
- assertTrue(response.size() > 0);
- }
- }
-
- private static class SystemInfoRequest extends SolrRequest<QueryResponse> {
-
- public SystemInfoRequest() {
- super(METHOD.GET, "/admin/info/system",
SolrRequest.SolrRequestType.ADMIN);
- }
-
- @Override
- public SolrParams getParams() {
- return new ModifiableSolrParams();
- }
-
- @Override
- protected QueryResponse createResponse(final NamedList<Object> namedList) {
- return new QueryResponse();
+ final SystemInfoResponse response = info.process(server);
+ assertTrue(response.getResponse().size() > 0);
}
}
}
diff --git
a/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java
b/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java
index 1732cd487d0..920b1aa2f3b 100644
--- a/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java
@@ -43,14 +43,13 @@ import org.apache.lucene.util.IOUtils;
import org.apache.solr.JSONTestUtil;
import org.apache.solr.SolrTestCaseJ4.SuppressSSL;
import org.apache.solr.client.solrj.SolrClient;
-import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.apache.HttpSolrClient;
import org.apache.solr.client.solrj.request.AbstractUpdateRequest;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.client.solrj.request.CoreAdminRequest.Create;
import org.apache.solr.client.solrj.request.CoreAdminRequest.Unload;
-import org.apache.solr.client.solrj.request.GenericSolrRequest;
+import org.apache.solr.client.solrj.request.MetricsRequest;
import org.apache.solr.client.solrj.request.QueryRequest;
import org.apache.solr.client.solrj.request.SolrQuery;
import org.apache.solr.client.solrj.request.StreamingUpdateRequest;
@@ -1283,12 +1282,7 @@ public class BasicDistributedZkTest extends
AbstractFullDistribZkTestBase {
.withConnectionTimeout(15000, TimeUnit.MILLISECONDS)
.withSocketTimeout(60000, TimeUnit.MILLISECONDS)
.build()) {
- var req =
- new GenericSolrRequest(
- SolrRequest.METHOD.GET,
- "/admin/metrics",
- SolrRequest.SolrRequestType.ADMIN,
- SolrParams.of("wt", "prometheus"));
+ var req = new MetricsRequest(SolrParams.of("wt", "prometheus"));
req.setResponseParser(new InputStreamResponseParser("prometheus"));
NamedList<Object> resp = client.request(req);
diff --git
a/solr/core/src/test/org/apache/solr/cloud/TestBaseStatsCacheCloud.java
b/solr/core/src/test/org/apache/solr/cloud/TestBaseStatsCacheCloud.java
index 11cff8c431c..5fc8bf904a8 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestBaseStatsCacheCloud.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestBaseStatsCacheCloud.java
@@ -22,12 +22,10 @@ import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import org.apache.solr.client.solrj.SolrClient;
-import org.apache.solr.client.solrj.SolrRequest.METHOD;
-import org.apache.solr.client.solrj.SolrRequest.SolrRequestType;
import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
-import org.apache.solr.client.solrj.request.GenericSolrRequest;
+import org.apache.solr.client.solrj.request.MetricsRequest;
import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.client.solrj.response.InputStreamResponseParser;
import org.apache.solr.client.solrj.response.QueryResponse;
@@ -140,12 +138,7 @@ public abstract class TestBaseStatsCacheCloud extends
SolrCloudTestCase {
StatsCache.StatsCacheMetrics statsCacheMetrics = new
StatsCache.StatsCacheMetrics();
for (JettySolrRunner jettySolrRunner : cluster.getJettySolrRunners()) {
try (SolrClient client =
getHttpSolrClient(jettySolrRunner.getBaseUrl().toString())) {
- var req =
- new GenericSolrRequest(
- METHOD.GET,
- "/admin/metrics",
- SolrRequestType.ADMIN,
- SolrParams.of("wt", "prometheus"));
+ var req = new MetricsRequest(SolrParams.of("wt", "prometheus"));
req.setResponseParser(new InputStreamResponseParser("prometheus"));
NamedList<Object> resp = client.request(req);
diff --git
a/solr/core/src/test/org/apache/solr/handler/admin/AdminHandlersProxyTest.java
b/solr/core/src/test/org/apache/solr/handler/admin/AdminHandlersProxyTest.java
index ef39b046a6f..14411a38876 100644
---
a/solr/core/src/test/org/apache/solr/handler/admin/AdminHandlersProxyTest.java
+++
b/solr/core/src/test/org/apache/solr/handler/admin/AdminHandlersProxyTest.java
@@ -20,13 +20,10 @@ package org.apache.solr.handler.admin;
import java.io.IOException;
import java.util.Collections;
import java.util.Set;
-import org.apache.http.client.HttpClient;
-import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
-import org.apache.solr.client.solrj.apache.CloudLegacySolrClient;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
-import org.apache.solr.client.solrj.request.GenericSolrRequest;
-import org.apache.solr.client.solrj.response.SimpleSolrResponse;
+import org.apache.solr.client.solrj.request.SystemInfoRequest;
+import org.apache.solr.client.solrj.response.SystemInfoResponse;
import org.apache.solr.cloud.SolrCloudTestCase;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.MapSolrParams;
@@ -36,7 +33,6 @@ import org.junit.BeforeClass;
import org.junit.Test;
public class AdminHandlersProxyTest extends SolrCloudTestCase {
- private HttpClient httpClient;
private CloudSolrClient solrClient;
@BeforeClass
@@ -50,19 +46,14 @@ public class AdminHandlersProxyTest extends
SolrCloudTestCase {
public void setUp() throws Exception {
super.setUp();
solrClient = cluster.getSolrClient();
- httpClient = ((CloudLegacySolrClient) solrClient).getHttpClient();
}
@Test
public void proxySystemInfoHandlerAllNodes() throws IOException,
SolrServerException {
MapSolrParams params = new MapSolrParams(Collections.singletonMap("nodes",
"all"));
- GenericSolrRequest req =
- new GenericSolrRequest(
- SolrRequest.METHOD.GET,
- "/admin/info/system",
- SolrRequest.SolrRequestType.ADMIN,
- params);
- SimpleSolrResponse rsp = req.process(solrClient, null);
+
+ SystemInfoRequest req = new SystemInfoRequest(params);
+ SystemInfoResponse rsp = req.process(solrClient, null);
NamedList<Object> nl = rsp.getResponse();
assertEquals(3, nl.size());
assertTrue(nl.getName(1).endsWith("_solr"));
@@ -75,13 +66,8 @@ public class AdminHandlersProxyTest extends
SolrCloudTestCase {
public void proxySystemInfoHandlerNonExistingNode() throws IOException,
SolrServerException {
MapSolrParams params =
new MapSolrParams(Collections.singletonMap("nodes",
"example.com:1234_solr"));
- GenericSolrRequest req =
- new GenericSolrRequest(
- SolrRequest.METHOD.GET,
- "/admin/info/system",
- SolrRequest.SolrRequestType.ADMIN,
- params);
- SimpleSolrResponse rsp = req.process(solrClient, null);
+ SystemInfoRequest req = new SystemInfoRequest(params);
+ SystemInfoResponse rsp = req.process(solrClient, null);
}
@Test
@@ -91,22 +77,16 @@ public class AdminHandlersProxyTest extends
SolrCloudTestCase {
nodes.forEach(
node -> {
MapSolrParams params = new
MapSolrParams(Collections.singletonMap("nodes", node));
- GenericSolrRequest req =
- new GenericSolrRequest(
- SolrRequest.METHOD.GET,
- "/admin/info/system",
- SolrRequest.SolrRequestType.ADMIN,
- params);
- SimpleSolrResponse rsp = null;
+ SystemInfoRequest req = new SystemInfoRequest(params);
try {
- rsp = req.process(solrClient, null);
+ SystemInfoResponse rsp = req.process(solrClient, null);
+ NamedList<Object> nl = rsp.getResponse();
+ assertEquals(2, nl.size());
+ assertEquals("solrcloud", rsp.getMode());
+ assertEquals(nl.getName(1), rsp.getNode());
} catch (Exception e) {
fail("Exception while proxying request to node " + node);
}
- NamedList<Object> nl = rsp.getResponse();
- assertEquals(2, nl.size());
- assertEquals("solrcloud", ((NamedList)
nl.get(nl.getName(1))).get("mode"));
- assertEquals(nl.getName(1), ((NamedList)
nl.get(nl.getName(1))).get("node"));
});
}
}
diff --git
a/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java
b/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java
index f2ea61a9fb5..7cf04d54375 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/MetricsHandlerTest.java
@@ -51,7 +51,7 @@ public class MetricsHandlerTest extends SolrTestCaseJ4 {
handler.handleRequestBody(
req(
CommonParams.QT,
- "/admin/metrics",
+ CommonParams.METRICS_PATH,
CommonParams.WT,
MetricsHandler.PROMETHEUS_METRICS_WT,
MetricsHandler.METRIC_NAME_PARAM,
@@ -78,7 +78,7 @@ public class MetricsHandlerTest extends SolrTestCaseJ4 {
handler.handleRequestBody(
req(
CommonParams.QT,
- "/admin/metrics",
+ CommonParams.METRICS_PATH,
CommonParams.WT,
MetricsHandler.PROMETHEUS_METRICS_WT,
MetricsHandler.METRIC_NAME_PARAM,
@@ -103,7 +103,7 @@ public class MetricsHandlerTest extends SolrTestCaseJ4 {
handler.handleRequestBody(
req(
CommonParams.QT,
- "/admin/metrics",
+ CommonParams.METRICS_PATH,
CommonParams.WT,
MetricsHandler.PROMETHEUS_METRICS_WT,
MetricsHandler.METRIC_NAME_PARAM,
@@ -124,7 +124,7 @@ public class MetricsHandlerTest extends SolrTestCaseJ4 {
handler.handleRequestBody(
req(
CommonParams.QT,
- "/admin/metrics",
+ CommonParams.METRICS_PATH,
CommonParams.WT,
MetricsHandler.PROMETHEUS_METRICS_WT,
MetricsHandler.CATEGORY_PARAM,
@@ -154,7 +154,7 @@ public class MetricsHandlerTest extends SolrTestCaseJ4 {
handler.handleRequestBody(
req(
CommonParams.QT,
- "/admin/metrics",
+ CommonParams.METRICS_PATH,
CommonParams.WT,
MetricsHandler.PROMETHEUS_METRICS_WT,
MetricsHandler.CATEGORY_PARAM,
@@ -186,7 +186,7 @@ public class MetricsHandlerTest extends SolrTestCaseJ4 {
handler.handleRequestBody(
req(
CommonParams.QT,
- "/admin/metrics",
+ CommonParams.METRICS_PATH,
CommonParams.WT,
MetricsHandler.PROMETHEUS_METRICS_WT,
MetricsHandler.CORE_PARAM,
@@ -208,7 +208,7 @@ public class MetricsHandlerTest extends SolrTestCaseJ4 {
handler.handleRequestBody(
req(
CommonParams.QT,
- "/admin/metrics",
+ CommonParams.METRICS_PATH,
CommonParams.WT,
MetricsHandler.PROMETHEUS_METRICS_WT,
MetricsHandler.CORE_PARAM,
@@ -243,7 +243,7 @@ public class MetricsHandlerTest extends SolrTestCaseJ4 {
handler.handleRequestBody(
req(
CommonParams.QT,
- "/admin/metrics",
+ CommonParams.METRICS_PATH,
CommonParams.WT,
MetricsHandler.PROMETHEUS_METRICS_WT,
MetricsHandler.CATEGORY_PARAM,
diff --git
a/solr/core/src/test/org/apache/solr/response/TestPrometheusResponseWriter.java
b/solr/core/src/test/org/apache/solr/response/TestPrometheusResponseWriter.java
index 2c86fc41bfb..fc2754da254 100644
---
a/solr/core/src/test/org/apache/solr/response/TestPrometheusResponseWriter.java
+++
b/solr/core/src/test/org/apache/solr/response/TestPrometheusResponseWriter.java
@@ -29,9 +29,7 @@ import java.util.stream.Collectors;
import org.apache.lucene.tests.util.LuceneTestCase;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.client.solrj.SolrClient;
-import org.apache.solr.client.solrj.SolrRequest.METHOD;
-import org.apache.solr.client.solrj.SolrRequest.SolrRequestType;
-import org.apache.solr.client.solrj.request.GenericSolrRequest;
+import org.apache.solr.client.solrj.request.MetricsRequest;
import org.apache.solr.client.solrj.response.InputStreamResponseParser;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.util.NamedList;
@@ -74,7 +72,7 @@ public class TestPrometheusResponseWriter extends
SolrTestCaseJ4 {
public void testPrometheusStructureOutput() throws Exception {
ModifiableSolrParams params = new ModifiableSolrParams();
params.set("wt", "prometheus");
- var req = new GenericSolrRequest(METHOD.GET, "/admin/metrics",
SolrRequestType.ADMIN, params);
+ var req = new MetricsRequest(params);
req.setResponseParser(new InputStreamResponseParser("prometheus"));
try (SolrClient adminClient =
getHttpSolrClient(solrClientTestRule.getBaseUrl())) {
@@ -122,8 +120,7 @@ public class TestPrometheusResponseWriter extends
SolrTestCaseJ4 {
@Test
public void testAcceptHeaderOpenMetricsFormat() throws Exception {
- ModifiableSolrParams params = new ModifiableSolrParams();
- var req = new GenericSolrRequest(METHOD.GET, "/admin/metrics",
SolrRequestType.ADMIN, params);
+ var req = new MetricsRequest();
req.setResponseParser(new InputStreamResponseParser(null));
@@ -143,8 +140,7 @@ public class TestPrometheusResponseWriter extends
SolrTestCaseJ4 {
@Test
public void testWtParameterOpenMetricsFormat() throws Exception {
- ModifiableSolrParams params = new ModifiableSolrParams();
- var req = new GenericSolrRequest(METHOD.GET, "/admin/metrics",
SolrRequestType.ADMIN, params);
+ var req = new MetricsRequest();
req.setResponseParser(new InputStreamResponseParser("openmetrics"));
@@ -162,8 +158,7 @@ public class TestPrometheusResponseWriter extends
SolrTestCaseJ4 {
@Test
public void testDefaultPrometheusFormat() throws Exception {
- ModifiableSolrParams params = new ModifiableSolrParams();
- var req = new GenericSolrRequest(METHOD.GET, "/admin/metrics",
SolrRequestType.ADMIN, params);
+ var req = new MetricsRequest();
req.setResponseParser(new InputStreamResponseParser("prometheus"));
@@ -181,8 +176,7 @@ public class TestPrometheusResponseWriter extends
SolrTestCaseJ4 {
@Test
public void testDefaultPrometheusFormatNoWtParam() throws Exception {
- ModifiableSolrParams params = new ModifiableSolrParams();
- var req = new GenericSolrRequest(METHOD.GET, "/admin/metrics",
SolrRequestType.ADMIN, params);
+ var req = new MetricsRequest();
req.setResponseParser(new InputStreamResponseParser(null));
@@ -200,8 +194,7 @@ public class TestPrometheusResponseWriter extends
SolrTestCaseJ4 {
@Test
public void testUnsupportedMetricsFormat() throws Exception {
- ModifiableSolrParams params = new ModifiableSolrParams();
- var req = new GenericSolrRequest(METHOD.GET, "/admin/metrics",
SolrRequestType.ADMIN, params);
+ var req = new MetricsRequest();
req.setResponseParser(new InputStreamResponseParser("unknownFormat"));
diff --git
a/solr/core/src/test/org/apache/solr/response/TestPrometheusResponseWriterCloud.java
b/solr/core/src/test/org/apache/solr/response/TestPrometheusResponseWriterCloud.java
index cd5149ca37f..ffc254723e1 100644
---
a/solr/core/src/test/org/apache/solr/response/TestPrometheusResponseWriterCloud.java
+++
b/solr/core/src/test/org/apache/solr/response/TestPrometheusResponseWriterCloud.java
@@ -19,10 +19,8 @@ package org.apache.solr.response;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import org.apache.solr.client.solrj.SolrClient;
-import org.apache.solr.client.solrj.SolrRequest.METHOD;
-import org.apache.solr.client.solrj.SolrRequest.SolrRequestType;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
-import org.apache.solr.client.solrj.request.GenericSolrRequest;
+import org.apache.solr.client.solrj.request.MetricsRequest;
import org.apache.solr.client.solrj.request.SolrQuery;
import org.apache.solr.client.solrj.response.InputStreamResponseParser;
import org.apache.solr.cloud.SolrCloudTestCase;
@@ -69,9 +67,7 @@ public class TestPrometheusResponseWriterCloud extends
SolrCloudTestCase {
SolrQuery query = new SolrQuery("*:*");
solrClient.query("collection1", query);
- var req =
- new GenericSolrRequest(
- METHOD.GET, "/admin/metrics", SolrRequestType.ADMIN,
SolrParams.of("wt", "prometheus"));
+ var req = new MetricsRequest(SolrParams.of("wt", "prometheus"));
req.setResponseParser(new InputStreamResponseParser("prometheus"));
NamedList<Object> resp = solrClient.request(req);
@@ -101,9 +97,7 @@ public class TestPrometheusResponseWriterCloud extends
SolrCloudTestCase {
solrClient.query("collection1", query);
solrClient.query("collection2", query);
- var req =
- new GenericSolrRequest(
- METHOD.GET, "/admin/metrics", SolrRequestType.ADMIN,
SolrParams.of("wt", "prometheus"));
+ var req = new MetricsRequest(SolrParams.of("wt", "prometheus"));
req.setResponseParser(new InputStreamResponseParser("prometheus"));
NamedList<Object> resp = solrClient.request(req);
diff --git
a/solr/core/src/test/org/apache/solr/security/MultiAuthPluginTest.java
b/solr/core/src/test/org/apache/solr/security/MultiAuthPluginTest.java
index f04bd268cda..8a9c2ca9205 100644
--- a/solr/core/src/test/org/apache/solr/security/MultiAuthPluginTest.java
+++ b/solr/core/src/test/org/apache/solr/security/MultiAuthPluginTest.java
@@ -48,6 +48,7 @@ import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.apache.HttpClientUtil;
import org.apache.solr.common.SolrException;
+import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.CommandOperation;
import org.apache.solr.common.util.Utils;
import org.apache.solr.embedded.JettySolrRunner;
@@ -132,12 +133,12 @@ public class MultiAuthPluginTest extends SolrTestCaseJ4 {
pass);
// anonymous requests are blocked by all plugins
- int statusCode = doHttpGetAnonymous(httpClient, baseUrl +
"/admin/info/system");
+ int statusCode = doHttpGetAnonymous(httpClient, baseUrl +
CommonParams.SYSTEM_INFO_PATH);
assertEquals("anonymous get succeeded but should not have", 401,
statusCode);
// update blockUnknown to allow anonymous for the basic plugin
String command = "{\n" + "'set-property': { 'basic':
{'blockUnknown':false} }\n" + "}";
doHttpPost(httpClient, baseUrl + authcPrefix, command, user, pass, 200);
- statusCode = doHttpGetAnonymous(httpClient, baseUrl +
"/admin/info/system");
+ statusCode = doHttpGetAnonymous(httpClient, baseUrl +
CommonParams.SYSTEM_INFO_PATH);
assertEquals("anonymous get failed but should have succeeded", 200,
statusCode);
// For the multi-auth plugin, every command is wrapped with an object
that identifies the
@@ -474,7 +475,7 @@ public class MultiAuthPluginTest extends SolrTestCaseJ4 {
securityConfHandler.securityConfEdited();
// Pretend to send unauthorized AJAX request
- HttpGet httpGet = new HttpGet(baseUrl + "/admin/info/system");
+ HttpGet httpGet = new HttpGet(baseUrl + CommonParams.SYSTEM_INFO_PATH);
httpGet.addHeader(new BasicHeader("X-Requested-With", "XMLHttpRequest"));
HttpResponse response = httpClient.execute(httpGet);
@@ -515,7 +516,7 @@ public class MultiAuthPluginTest extends SolrTestCaseJ4 {
private void verifyWWWAuthenticateHeaders(HttpClient httpClient, String
baseUrl)
throws Exception {
- HttpGet httpGet = new HttpGet(baseUrl + "/admin/info/system");
+ HttpGet httpGet = new HttpGet(baseUrl + CommonParams.SYSTEM_INFO_PATH);
HttpResponse response = httpClient.execute(httpGet);
Header[] headers = response.getHeaders(HttpHeaders.WWW_AUTHENTICATE);
List<String> actualSchemes =
diff --git
a/solr/modules/jwt-auth/src/test/org/apache/solr/security/jwt/JWTAuthPluginIntegrationTest.java
b/solr/modules/jwt-auth/src/test/org/apache/solr/security/jwt/JWTAuthPluginIntegrationTest.java
index 1650fbb4788..dc281359b8c 100644
---
a/solr/modules/jwt-auth/src/test/org/apache/solr/security/jwt/JWTAuthPluginIntegrationTest.java
+++
b/solr/modules/jwt-auth/src/test/org/apache/solr/security/jwt/JWTAuthPluginIntegrationTest.java
@@ -61,6 +61,7 @@ import org.apache.solr.client.solrj.apache.HttpClientUtil;
import org.apache.solr.cloud.MiniSolrCloudCluster;
import org.apache.solr.cloud.SolrCloudAuthTestCase;
import org.apache.solr.common.SolrException;
+import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.Pair;
import org.apache.solr.common.util.TimeSource;
import org.apache.solr.embedded.JettySolrRunner;
@@ -142,11 +143,11 @@ public class JWTAuthPluginIntegrationTest extends
SolrCloudAuthTestCase {
String baseUrl =
myCluster.getRandomJetty(random()).getBaseUrl().toString();
// First attempt without token fails
- Map<String, String> headers = getHeaders(baseUrl + "/admin/info/system",
null);
+ Map<String, String> headers = getHeaders(baseUrl +
CommonParams.SYSTEM_INFO_PATH, null);
assertEquals("Should have received 401 code", "401", headers.get("code"));
// Second attempt with token from Oauth mock server succeeds
- headers = getHeaders(baseUrl + "/admin/info/system", mockOAuthToken);
+ headers = getHeaders(baseUrl + CommonParams.SYSTEM_INFO_PATH,
mockOAuthToken);
assertEquals("200", headers.get("code"));
myCluster.shutdown();
}
@@ -162,10 +163,10 @@ public class JWTAuthPluginIntegrationTest extends
SolrCloudAuthTestCase {
String baseUrl =
myCluster.getRandomJetty(random()).getBaseUrl().toString();
// No token fails
- assertThrows(IOException.class, () -> get(baseUrl + "/admin/info/system",
null));
+ assertThrows(IOException.class, () -> get(baseUrl +
CommonParams.SYSTEM_INFO_PATH, null));
// Validate X-Solr-AuthData headers
- Map<String, String> headers = getHeaders(baseUrl + "/admin/info/system",
null);
+ Map<String, String> headers = getHeaders(baseUrl +
CommonParams.SYSTEM_INFO_PATH, null);
assertEquals("Should have received 401 code", "401", headers.get("code"));
assertEquals("Bearer realm=\"my-solr-jwt\"",
headers.get("WWW-Authenticate"));
String authData = new
String(Base64.getDecoder().decode(headers.get("X-Solr-AuthData")), UTF_8);
@@ -188,7 +189,7 @@ public class JWTAuthPluginIntegrationTest extends
SolrCloudAuthTestCase {
configureClusterStaticKeys("jwt_plugin_jwk_security_blockUnknownFalse.json");
String baseUrl =
myCluster.getRandomJetty(random()).getBaseUrl().toString();
- Map<String, String> headers = getHeaders(baseUrl + "/admin/info/system",
null);
+ Map<String, String> headers = getHeaders(baseUrl +
CommonParams.SYSTEM_INFO_PATH, null);
assertEquals("Should have received 401 code", "401", headers.get("code"));
assertEquals(
"Bearer realm=\"my-solr-jwt-blockunknown-false\"",
headers.get("WWW-Authenticate"));
diff --git
a/solr/modules/opentelemetry/src/test/org/apache/solr/opentelemetry/TestDistributedTracing.java
b/solr/modules/opentelemetry/src/test/org/apache/solr/opentelemetry/TestDistributedTracing.java
index bc90908bc6d..97916c007ca 100644
---
a/solr/modules/opentelemetry/src/test/org/apache/solr/opentelemetry/TestDistributedTracing.java
+++
b/solr/modules/opentelemetry/src/test/org/apache/solr/opentelemetry/TestDistributedTracing.java
@@ -31,11 +31,10 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.solr.client.solrj.SolrRequest;
-import org.apache.solr.client.solrj.SolrRequest.SolrRequestType;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
-import org.apache.solr.client.solrj.request.GenericSolrRequest;
+import org.apache.solr.client.solrj.request.MetricsRequest;
import org.apache.solr.client.solrj.request.SolrQuery;
import org.apache.solr.client.solrj.request.V2Request;
import org.apache.solr.client.solrj.response.CollectionAdminResponse;
@@ -136,8 +135,7 @@ public class TestDistributedTracing extends
SolrCloudTestCase {
public void testAdminApi() throws Exception {
CloudSolrClient cloudClient = cluster.getSolrClient();
- GenericSolrRequest request =
- new GenericSolrRequest(SolrRequest.METHOD.GET, "/admin/metrics",
SolrRequestType.ADMIN);
+ MetricsRequest request = new MetricsRequest();
request.setResponseParser(new
InputStreamResponseParser(PROMETHEUS_METRICS_WT));
NamedList<Object> rsp = cloudClient.request(request);
((InputStream) rsp.get("stream")).close();
diff --git
a/solr/modules/opentelemetry/src/test/org/apache/solr/opentelemetry/TestMetricExemplars.java
b/solr/modules/opentelemetry/src/test/org/apache/solr/opentelemetry/TestMetricExemplars.java
index 0a842d57915..6eaf0c07e17 100644
---
a/solr/modules/opentelemetry/src/test/org/apache/solr/opentelemetry/TestMetricExemplars.java
+++
b/solr/modules/opentelemetry/src/test/org/apache/solr/opentelemetry/TestMetricExemplars.java
@@ -23,10 +23,9 @@ import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.api.trace.TracerProvider;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
-import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
-import org.apache.solr.client.solrj.request.GenericSolrRequest;
+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.params.ModifiableSolrParams;
@@ -79,12 +78,7 @@ public class TestMetricExemplars extends SolrCloudTestCase {
var spans = getAndClearSpans();
var expectedTrace = getRootTraceId(spans);
- var req =
- new GenericSolrRequest(
- SolrRequest.METHOD.GET,
- "/admin/metrics",
- SolrRequest.SolrRequestType.ADMIN,
- new ModifiableSolrParams().set("wt", "openmetrics"));
+ var req = new MetricsRequest(new ModifiableSolrParams().set("wt",
"openmetrics"));
req.setResponseParser(new InputStreamResponseParser("openmetrics"));
NamedList<Object> resp = cloudClient.request(req);
diff --git
a/solr/solrj-streaming/src/java/org/apache/solr/client/solrj/io/sql/DatabaseMetaDataImpl.java
b/solr/solrj-streaming/src/java/org/apache/solr/client/solrj/io/sql/DatabaseMetaDataImpl.java
index 643b51b57b1..cde6a04b068 100644
---
a/solr/solrj-streaming/src/java/org/apache/solr/client/solrj/io/sql/DatabaseMetaDataImpl.java
+++
b/solr/solrj-streaming/src/java/org/apache/solr/client/solrj/io/sql/DatabaseMetaDataImpl.java
@@ -28,10 +28,9 @@ import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.jetty.HttpJettySolrClient;
-import org.apache.solr.client.solrj.request.SolrQuery;
-import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.client.solrj.request.SystemInfoRequest;
+import org.apache.solr.client.solrj.response.SystemInfoResponse;
import org.apache.solr.common.cloud.ClusterState;
-import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.common.util.Utils;
class DatabaseMetaDataImpl implements DatabaseMetaData {
@@ -111,8 +110,6 @@ class DatabaseMetaDataImpl implements DatabaseMetaData {
@Override
public String getDatabaseProductVersion() throws SQLException {
// Returns the version for the first live node in the Solr cluster.
- SolrQuery sysQuery = new SolrQuery();
- sysQuery.setRequestHandler("/admin/info/system");
CloudSolrClient cloudSolrClient = this.connection.getClient();
Set<String> liveNodes = cloudSolrClient.getClusterState().getLiveNodes();
@@ -126,9 +123,10 @@ class DatabaseMetaDataImpl implements DatabaseMetaData {
String nodeURL = Utils.getBaseUrlForNodeName(node, urlScheme);
solrClient = new HttpJettySolrClient.Builder(nodeURL).build();
- QueryResponse rsp = solrClient.query(sysQuery);
- return String.valueOf(
- ((SimpleOrderedMap)
rsp.getResponse().get("lucene")).get("solr-spec-version"));
+ SystemInfoRequest req = new SystemInfoRequest();
+ SystemInfoResponse resp = req.process(solrClient);
+
+ return resp.getSolrSpecVersion();
} catch (SolrServerException | IOException ignore) {
return "";
} finally {
diff --git
a/solr/solrj-zookeeper/src/java/org/apache/solr/client/solrj/impl/NodeValueFetcher.java
b/solr/solrj-zookeeper/src/java/org/apache/solr/client/solrj/impl/NodeValueFetcher.java
index 868cbfd2926..3dd91fca5d3 100644
---
a/solr/solrj-zookeeper/src/java/org/apache/solr/client/solrj/impl/NodeValueFetcher.java
+++
b/solr/solrj-zookeeper/src/java/org/apache/solr/client/solrj/impl/NodeValueFetcher.java
@@ -30,9 +30,7 @@ import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
-import org.apache.solr.client.solrj.SolrRequest.METHOD;
-import org.apache.solr.client.solrj.SolrRequest.SolrRequestType;
-import org.apache.solr.client.solrj.request.GenericSolrRequest;
+import org.apache.solr.client.solrj.request.MetricsRequest;
import org.apache.solr.client.solrj.response.InputStreamResponseParser;
import org.apache.solr.client.solrj.response.SimpleSolrResponse;
import org.apache.solr.common.SolrException;
@@ -176,7 +174,7 @@ public class NodeValueFetcher {
params.add("name", StrUtils.join(uniqueMetricNames, ','));
try {
- var req = new GenericSolrRequest(METHOD.GET, "/admin/metrics",
SolrRequestType.ADMIN, params);
+ var req = new MetricsRequest(params);
req.setResponseParser(new InputStreamResponseParser("prometheus"));
String baseUrl =
diff --git
a/solr/solrj-zookeeper/src/java/org/apache/solr/client/solrj/impl/SolrClientNodeStateProvider.java
b/solr/solrj-zookeeper/src/java/org/apache/solr/client/solrj/impl/SolrClientNodeStateProvider.java
index cc8365067ae..ef6bb5dbd21 100644
---
a/solr/solrj-zookeeper/src/java/org/apache/solr/client/solrj/impl/SolrClientNodeStateProvider.java
+++
b/solr/solrj-zookeeper/src/java/org/apache/solr/client/solrj/impl/SolrClientNodeStateProvider.java
@@ -34,6 +34,7 @@ import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.cloud.NodeStateProvider;
import org.apache.solr.client.solrj.request.GenericSolrRequest;
+import org.apache.solr.client.solrj.request.MetricsRequest;
import org.apache.solr.client.solrj.response.InputStreamResponseParser;
import org.apache.solr.client.solrj.response.JavaBinResponseParser;
import org.apache.solr.client.solrj.response.SimpleSolrResponse;
@@ -212,9 +213,7 @@ public class SolrClientNodeStateProvider implements
NodeStateProvider, MapWriter
params.add("wt", "prometheus");
params.add("name", String.join(",", metricNames));
- var req =
- new GenericSolrRequest(
- SolrRequest.METHOD.GET, "/admin/metrics",
SolrRequest.SolrRequestType.ADMIN, params);
+ var req = new MetricsRequest(params);
req.setResponseParser(new InputStreamResponseParser("prometheus"));
String baseUrl =
diff --git
a/solr/solrj/src/java/org/apache/solr/client/solrj/request/MetricsRequest.java
b/solr/solrj/src/java/org/apache/solr/client/solrj/request/MetricsRequest.java
new file mode 100644
index 00000000000..82c10659586
--- /dev/null
+++
b/solr/solrj/src/java/org/apache/solr/client/solrj/request/MetricsRequest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.client.solrj.request;
+
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.SolrResponse;
+import org.apache.solr.client.solrj.response.SolrResponseBase;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.NamedList;
+
+/** Request to "/admin/metrics" */
+public class MetricsRequest extends SolrRequest<SolrResponse> {
+
+ private static final long serialVersionUID = 1L;
+
+ private final SolrParams params;
+
+ /** Request to "/admin/metrics" by default, without params */
+ public MetricsRequest() {
+ this(new ModifiableSolrParams());
+ }
+
+ /**
+ * @param params the Solr parameters to use for this request.
+ */
+ public MetricsRequest(SolrParams params) {
+ super(METHOD.GET, CommonParams.METRICS_PATH, SolrRequestType.ADMIN);
+ this.params = params;
+ }
+
+ @Override
+ public SolrParams getParams() {
+ return params;
+ }
+
+ @Override
+ protected SolrResponse createResponse(NamedList<Object> namedList) {
+ SolrResponseBase resp = new SolrResponseBase();
+ return (SolrResponse) resp;
+ }
+}
diff --git
a/solr/solrj/src/java/org/apache/solr/client/solrj/request/SystemInfoRequest.java
b/solr/solrj/src/java/org/apache/solr/client/solrj/request/SystemInfoRequest.java
new file mode 100644
index 00000000000..345c0650256
--- /dev/null
+++
b/solr/solrj/src/java/org/apache/solr/client/solrj/request/SystemInfoRequest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.client.solrj.request;
+
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.response.SystemInfoResponse;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.NamedList;
+
+/** Class to get a system info response. */
+public class SystemInfoRequest extends SolrRequest<SystemInfoResponse> {
+
+ private static final long serialVersionUID = 1L;
+
+ private final SolrParams params;
+
+ /** Request to "/admin/info/system" by default, without params. */
+ public SystemInfoRequest() {
+ // TODO: support V2 by default. Requires refactoring throughout the CLI
tools, at least
+ this(CommonParams.SYSTEM_INFO_PATH);
+ }
+
+ /**
+ * @param path the HTTP path to use for this request. Supports V1
"/admin/info/system" (default)
+ * or V2 "/node/system"
+ */
+ public SystemInfoRequest(String path) {
+ this(path, new ModifiableSolrParams());
+ }
+
+ /**
+ * @param params the Solr parameters to use for this request.
+ */
+ public SystemInfoRequest(SolrParams params) {
+ this(CommonParams.SYSTEM_INFO_PATH, params);
+ }
+
+ /**
+ * @param path the HTTP path to use for this request. Supports V1
"/admin/info/system" (default)
+ * or V2 "/node/system"
+ * @param params query parameter names and values for making this request.
+ */
+ public SystemInfoRequest(String path, SolrParams params) {
+ super(METHOD.GET, path, SolrRequestType.ADMIN);
+ this.params = params;
+ }
+
+ @Override
+ public SolrParams getParams() {
+ return params;
+ }
+
+ @Override
+ protected SystemInfoResponse createResponse(NamedList<Object> namedList) {
+ return new SystemInfoResponse(namedList);
+ }
+
+ @Override
+ public ApiVersion getApiVersion() {
+ if (CommonParams.SYSTEM_INFO_PATH.equals(getPath())) {
+ // (/solr) /admin/info/system
+ return ApiVersion.V1;
+ }
+ // Ref. org.apache.solr.handler.admin.api.NodeSystemInfoAPI : /node/system
+ return ApiVersion.V2;
+ }
+}
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
new file mode 100644
index 00000000000..8dbea63118b
--- /dev/null
+++
b/solr/solrj/src/java/org/apache/solr/client/solrj/response/SystemInfoResponse.java
@@ -0,0 +1,251 @@
+/*
+ * 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.client.solrj.response;
+
+import java.lang.invoke.MethodHandles;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.apache.solr.client.api.model.NodeSystemResponse;
+import org.apache.solr.client.solrj.request.json.JacksonContentWriter;
+import org.apache.solr.common.util.NamedList;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** This class holds the response from V1 "/admin/info/system" or V2
"/node/system" */
+public class SystemInfoResponse extends SolrResponseBase {
+
+ private static final Logger log =
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ private static final long serialVersionUID = 1L;
+
+ private final Map<String, NodeSystemResponse> nodesInfo = new HashMap<>();
+
+ public SystemInfoResponse(NamedList<Object> namedList) {
+ if (namedList == null) throw new IllegalArgumentException("Null NamedList
is not allowed.");
+ setResponse(namedList);
+ }
+
+ @Override
+ public void setResponse(NamedList<Object> response) {
+ if (getResponse() == null) super.setResponse(response);
+ if (getResponse().get("node") == null) {
+ // multi-nodes response, NamedList of
"host:port_solr"->NodeSystemResponse
+ for (Entry<String, Object> node : getResponse()) {
+ if (node.getKey().endsWith("_solr")) {
+ nodesInfo.put(
+ node.getKey(),
+ JacksonContentWriter.DEFAULT_MAPPER.convertValue(
+ node.getValue(), NodeSystemResponse.class));
+ }
+ }
+ } else {
+ // single-node response
+ nodesInfo.put(
+ getResponse().get("node").toString(),
+ JacksonContentWriter.DEFAULT_MAPPER.convertValue(
+ getResponse(), NodeSystemResponse.class));
+ }
+ }
+
+ /** Get the mode from a single node system info */
+ public String getMode() {
+ if (nodesInfo.size() == 1) {
+ return nodesInfo.values().stream().findFirst().orElseThrow().mode;
+ } else {
+ throw new UnsupportedOperationException(
+ "Multiple nodes system info available, use method 'getAllModes', or
'getModeForNode(String)'.");
+ }
+ }
+
+ /** Get all modes, per node */
+ public Map<String, String> getAllModes() {
+ Map<String, String> allModes = new HashMap<>();
+ nodesInfo.entrySet().stream().forEach(e -> allModes.put(e.getKey(),
e.getValue().mode));
+ return allModes;
+ }
+
+ /** Get the mode for the given node name */
+ public String getModeForNode(String node) {
+ return nodesInfo.get(node).mode;
+ }
+
+ /** Get the ZK host from a single node system info */
+ public String getZkHost() {
+ if (nodesInfo.size() == 1) {
+ return nodesInfo.values().stream().findFirst().orElseThrow().zkHost;
+ } else {
+ throw new UnsupportedOperationException(
+ "Multiple nodes system info available, use method 'getAllZkHosts',
or 'getZkHostForNode(String)'.");
+ }
+ }
+
+ /** Get all ZK hosts, per node */
+ public Map<String, String> getAllZkHosts() {
+ Map<String, String> allModes = new HashMap<>();
+ nodesInfo.entrySet().stream().forEach(e -> allModes.put(e.getKey(),
e.getValue().zkHost));
+ return allModes;
+ }
+
+ /** Get the ZK host for the given node name */
+ public String getZkHostForNode(String node) {
+ return nodesInfo.get(node).zkHost;
+ }
+
+ /** Get the Solr home from a single node system info */
+ public String getSolrHome() {
+ if (nodesInfo.size() == 1) {
+ return nodesInfo.values().stream().findFirst().orElseThrow().solrHome;
+ } else {
+ throw new UnsupportedOperationException(
+ "Multiple nodes system info available, use method 'getAllSolrHomes',
or 'getSolrHomeForNode(String)'.");
+ }
+ }
+
+ /** Get all Solr homes, per node */
+ public Map<String, String> getAllSolrHomes() {
+ Map<String, String> allModes = new HashMap<>();
+ nodesInfo.entrySet().stream().forEach(e -> allModes.put(e.getKey(),
e.getValue().solrHome));
+ return allModes;
+ }
+
+ /** Get the Solr home for the given node name */
+ public String getSolrHomeForNode(String node) {
+ return nodesInfo.get(node).solrHome;
+ }
+
+ /** Get the core root from a single node system info */
+ public String getCoreRoot() {
+ if (nodesInfo.size() == 1) {
+ return nodesInfo.values().stream().findFirst().orElseThrow().coreRoot;
+ } else {
+ throw new UnsupportedOperationException(
+ "Multiple nodes system info available, use method 'getAllCoreRoots',
or 'getCoreRootForNode(String)'.");
+ }
+ }
+
+ /** Get all core roots, per node */
+ public Map<String, String> getAllCoreRoots() {
+ Map<String, String> allModes = new HashMap<>();
+ nodesInfo.entrySet().stream().forEach(e -> allModes.put(e.getKey(),
e.getValue().coreRoot));
+ return allModes;
+ }
+
+ /** Get the core root for the given node name */
+ public String getCoreRootForNode(String node) {
+ return nodesInfo.get(node).coreRoot;
+ }
+
+ /** Get the node name from a single node system info */
+ public String getNode() {
+ if (nodesInfo.size() == 1) {
+ return nodesInfo.values().stream().findFirst().orElseThrow().node;
+ } else {
+ throw new UnsupportedOperationException(
+ "Multiple nodes system info available, use method 'getAllNodes', or
'getNodeForSolrHome(String)', or 'getNodeForCoreRoot(String)'.");
+ }
+ }
+
+ /** Get all nodes names */
+ public Set<String> getAllNodes() {
+ return nodesInfo.keySet();
+ }
+
+ /** Get the node name for the given Solr home */
+ public String getNodeForSolrHome(String solrHome) {
+ return nodesInfo.values().stream()
+ .filter(v -> solrHome.equals(v.solrHome))
+ .map(v -> v.node)
+ .findFirst()
+ .get();
+ }
+
+ /** Get the node name for the given core root */
+ public String getNodeForCoreRoot(String coreRoot) {
+ return nodesInfo.values().stream()
+ .filter(v -> coreRoot.equals(v.coreRoot))
+ .map(v -> v.node)
+ .findFirst()
+ .get();
+ }
+
+ /** Get the {@code NodeSystemResponse} for a single node */
+ public NodeSystemResponse getNodeResponse() {
+ if (nodesInfo.size() == 1) {
+ return nodesInfo.values().stream().findFirst().get();
+ } else {
+ throw new UnsupportedOperationException(
+ "Multiple nodes system info available, use method
'getAllNodeResponses', or 'getNodeResponseForNode(String)'.");
+ }
+ }
+
+ /** Get all {@code NodeSystemResponse}s */
+ public Map<String, NodeSystemResponse> getAllNodeResponses() {
+ return nodesInfo;
+ }
+
+ /** Get the {@code NodeSystemResponse} for the given node name */
+ public NodeSystemResponse getNodeResponseForNode(String node) {
+ return nodesInfo.get(node);
+ }
+
+ public String getSolrImplVersion() {
+ return getNodeResponse() != null && getNodeResponse().lucene != null
+ ? getNodeResponse().lucene.solrImplVersion
+ : null;
+ }
+
+ public String getSolrSpecVersion() {
+ return getNodeResponse() != null && getNodeResponse().lucene != null
+ ? getNodeResponse().lucene.solrSpecVersion
+ : null;
+ }
+
+ public Date getJVMStartTime() {
+ return getNodeResponse() != null
+ && getNodeResponse().jvm != null
+ && getNodeResponse().jvm.jmx != null
+ ? getNodeResponse().jvm.jmx.startTime
+ : null;
+ }
+
+ public Long getJVMUpTimeMillis() {
+ return getNodeResponse() != null
+ && getNodeResponse().jvm != null
+ && getNodeResponse().jvm.jmx != null
+ ? getNodeResponse().jvm.jmx.upTimeMS
+ : null;
+ }
+
+ public String getHumanReadableJVMMemoryUsed() {
+ return getNodeResponse() != null
+ && getNodeResponse().jvm != null
+ && getNodeResponse().jvm.memory != null
+ ? getNodeResponse().jvm.memory.used
+ : null;
+ }
+
+ public String getHumanReadableJVMMemoryTotal() {
+ return getNodeResponse() != null
+ && getNodeResponse().jvm != null
+ && getNodeResponse().jvm.memory != null
+ ? getNodeResponse().jvm.memory.total
+ : null;
+ }
+}
diff --git
a/solr/solrj/src/java/org/apache/solr/common/params/CommonParams.java
b/solr/solrj/src/java/org/apache/solr/common/params/CommonParams.java
index 052d0104bff..b26360864c5 100644
--- a/solr/solrj/src/java/org/apache/solr/common/params/CommonParams.java
+++ b/solr/solrj/src/java/org/apache/solr/common/params/CommonParams.java
@@ -205,6 +205,7 @@ public interface CommonParams {
String ZK_STATUS_PATH = "/admin/zookeeper/status";
String SYSTEM_INFO_PATH = "/admin/info/system";
String METRICS_PATH = "/admin/metrics";
+ String V2_SYSTEM_INFO_PATH = "/node/system";
String STATUS = "status";
diff --git
a/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleTests.java
b/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleTests.java
index 8935d0301a5..759dd72a153 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleTests.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/SolrExampleTests.java
@@ -441,7 +441,7 @@ public abstract class SolrExampleTests extends
SolrExampleTestsBase {
String url = getBaseUrl();
try (SolrClient adminClient = getHttpSolrClient(url)) {
SolrQuery q = new SolrQuery();
- q.set("qt", "/admin/info/system");
+ q.set("qt", CommonParams.SYSTEM_INFO_PATH);
QueryResponse rsp = adminClient.query(q);
assertNotNull(rsp.getResponse().get("mode"));
diff --git
a/solr/solrj/src/test/org/apache/solr/client/solrj/response/SystemInfoResponseTest.java
b/solr/solrj/src/test/org/apache/solr/client/solrj/response/SystemInfoResponseTest.java
new file mode 100644
index 00000000000..f129d63f10e
--- /dev/null
+++
b/solr/solrj/src/test/org/apache/solr/client/solrj/response/SystemInfoResponseTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.client.solrj.response;
+
+import java.io.IOException;
+import java.util.Map;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.impl.CloudSolrClient;
+import org.apache.solr.client.solrj.request.SystemInfoRequest;
+import org.apache.solr.cloud.SolrCloudTestCase;
+import org.apache.solr.common.params.MapSolrParams;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class SystemInfoResponseTest extends SolrCloudTestCase {
+
+ private CloudSolrClient solrClient;
+
+ @BeforeClass
+ public static void setupCluster() throws Exception {
+ configureCluster(2).addConfig("config",
getFile("solrj/solr/collection1/conf")).configure();
+ }
+
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ solrClient = cluster.getSolrClient();
+ }
+
+ @Test
+ public void testAllNodesResponse() throws SolrServerException, IOException {
+ MapSolrParams params = new MapSolrParams(Map.of("nodes", "all"));
+
+ SystemInfoRequest req = new SystemInfoRequest(params);
+ SystemInfoResponse rsp = req.process(solrClient);
+
+ try {
+ rsp.getNodeResponse();
+ Assert.fail("Should throw UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ Assert.assertTrue(e.getMessage().startsWith("Multiple nodes system info
available"));
+ }
+
+ Assert.assertEquals(2, rsp.getAllNodeResponses().size());
+ Assert.assertEquals(2, rsp.getAllCoreRoots().size());
+ Assert.assertEquals(2, rsp.getAllModes().size());
+ }
+
+ @Test
+ public void testResponseForGivenNode() throws SolrServerException,
IOException {
+ MapSolrParams params = new MapSolrParams(Map.of("nodes", "all"));
+
+ SystemInfoRequest req = new SystemInfoRequest(params);
+ SystemInfoResponse rsp = req.process(solrClient);
+
+ for (String node : rsp.getAllNodes()) {
+ String coreRoot = rsp.getCoreRootForNode(node);
+ Assert.assertEquals(node, rsp.getNodeForCoreRoot(coreRoot));
+ String solrHome = rsp.getCoreRootForNode(node);
+ Assert.assertEquals(node, rsp.getNodeForSolrHome(solrHome));
+ }
+ }
+}
diff --git
a/solr/test-framework/src/java/org/apache/solr/util/SolrJMetricTestUtils.java
b/solr/test-framework/src/java/org/apache/solr/util/SolrJMetricTestUtils.java
index 556aee93650..1ec456202c6 100644
---
a/solr/test-framework/src/java/org/apache/solr/util/SolrJMetricTestUtils.java
+++
b/solr/test-framework/src/java/org/apache/solr/util/SolrJMetricTestUtils.java
@@ -21,10 +21,9 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import org.apache.solr.client.solrj.SolrClient;
-import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.jetty.HttpJettySolrClient;
-import org.apache.solr.client.solrj.request.GenericSolrRequest;
+import org.apache.solr.client.solrj.request.MetricsRequest;
import org.apache.solr.client.solrj.response.InputStreamResponseParser;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
@@ -33,12 +32,7 @@ public final class SolrJMetricTestUtils {
public static double getPrometheusMetricValue(SolrClient solrClient, String
metricName)
throws SolrServerException, IOException {
- var req =
- new GenericSolrRequest(
- SolrRequest.METHOD.GET,
- "/admin/metrics",
- SolrRequest.SolrRequestType.ADMIN,
- SolrParams.of("wt", "prometheus"));
+ var req = new MetricsRequest(SolrParams.of("wt", "prometheus"));
req.setResponseParser(new InputStreamResponseParser("prometheus"));
NamedList<Object> resp = solrClient.request(req);
@@ -57,12 +51,7 @@ public final class SolrJMetricTestUtils {
throws SolrServerException, IOException {
try (var client = new HttpJettySolrClient.Builder(baseUrl).build()) {
- var req =
- new GenericSolrRequest(
- SolrRequest.METHOD.GET,
- "/admin/metrics",
- SolrRequest.SolrRequestType.ADMIN,
- SolrParams.of("wt", "prometheus"));
+ var req = new MetricsRequest(SolrParams.of("wt", "prometheus"));
req.setResponseParser(new InputStreamResponseParser("prometheus"));
NamedList<Object> resp = client.request(req);
@@ -90,12 +79,7 @@ public final class SolrJMetricTestUtils {
throws SolrServerException, IOException {
try (var client = new HttpJettySolrClient.Builder(baseUrl).build()) {
- var req =
- new GenericSolrRequest(
- SolrRequest.METHOD.GET,
- "/admin/metrics",
- SolrRequest.SolrRequestType.ADMIN,
- SolrParams.of("wt", "prometheus"));
+ var req = new MetricsRequest(SolrParams.of("wt", "prometheus"));
req.setResponseParser(new InputStreamResponseParser("prometheus"));
NamedList<Object> resp = client.request(req);