This is an automated email from the ASF dual-hosted git repository.
gerlowskija pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/main by this push:
new c74142675eb SOLR-16458: Convert /api/node/system to JAX-RS (#4078)
c74142675eb is described below
commit c74142675ebdabf0ebab8bf8b162223f63262af3
Author: igiguere <[email protected]>
AuthorDate: Mon Mar 16 13:51:28 2026 -0400
SOLR-16458: Convert /api/node/system to JAX-RS (#4078)
This migration to JAX-RS implicitly adds these APIs to the OAS, and ensures
autogeneration of SolrRequest/SolrResponse types.
Co-authored-by: Isabelle Giguere <[email protected]>
Co-authored-by: Jason Gerlowski <[email protected]>
---
...078-node-system-response-v2-jersey-resource.yml | 8 +
.../client/api/endpoint/NodeSystemInfoApi.java | 34 ++
.../solr/client/api/model/NodeSystemResponse.java | 11 +-
.../apache/solr/handler/admin/CoreInfoHandler.java | 39 +-
.../solr/handler/admin/SystemInfoHandler.java | 457 +---------------
...temInfoHandler.java => SystemInfoProvider.java} | 574 +++++++++++----------
.../solr/handler/admin/api/GetNodeSystemInfo.java | 81 +++
.../solr/handler/admin/api/NodeSystemInfoAPI.java | 50 --
.../solr/packagemanager/RepositoryManager.java | 15 +-
.../handler/admin/NodeSystemInfoProviderTest.java | 83 +++
.../solr/handler/admin/SystemInfoHandlerTest.java | 46 --
.../handler/admin/api/GetNodeSystemInfoTest.java | 58 +++
.../handler/admin/api/V2NodeAPIMappingTest.java | 20 -
.../pages/system-info-handler.adoc | 391 +++++++-------
.../client/solrj/request/SystemInfoRequest.java | 19 +-
.../client/solrj/response/SystemInfoResponse.java | 33 +-
.../json/JacksonDataBindResponseParser.java | 3 +
.../apache/solr/common/params/CommonParams.java | 1 -
.../solrj/response/SystemInfoResponseTest.java | 34 +-
19 files changed, 822 insertions(+), 1135 deletions(-)
diff --git
a/changelog/unreleased/PR#4078-node-system-response-v2-jersey-resource.yml
b/changelog/unreleased/PR#4078-node-system-response-v2-jersey-resource.yml
new file mode 100644
index 00000000000..6cbea3de784
--- /dev/null
+++ b/changelog/unreleased/PR#4078-node-system-response-v2-jersey-resource.yml
@@ -0,0 +1,8 @@
+# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc
+title: Add V2 "System Info" API and SolrJ request 'SystemApi.GetNodeSystemInfo'
+type: added # added, changed, fixed, deprecated, removed, dependency_update,
security, other
+authors:
+ - name: Isabelle Giguère
+links:
+ - name: PR#4078
+ url: https://github.com/apache/solr/pull/4078
diff --git
a/solr/api/src/java/org/apache/solr/client/api/endpoint/NodeSystemInfoApi.java
b/solr/api/src/java/org/apache/solr/client/api/endpoint/NodeSystemInfoApi.java
new file mode 100644
index 00000000000..07342668102
--- /dev/null
+++
b/solr/api/src/java/org/apache/solr/client/api/endpoint/NodeSystemInfoApi.java
@@ -0,0 +1,34 @@
+/*
+ * 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.endpoint;
+
+import io.swagger.v3.oas.annotations.Operation;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.QueryParam;
+import org.apache.solr.client.api.model.NodeSystemResponse;
+
+/** V2 API definitions to fetch node system info, analogous to the v1
/admin/info/system. */
+@Path("/node/system")
+public interface NodeSystemInfoApi {
+
+ @GET
+ @Operation(
+ summary = "Retrieve all node system info.",
+ tags = {"system"})
+ NodeSystemResponse getNodeSystemInfo(@QueryParam(value = "nodes") String
nodes);
+}
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 efd73c269dc..024f53cdffc 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
@@ -20,12 +20,14 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Date;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/** Response from /node/system */
public class NodeSystemResponse extends SolrJerseyResponse {
- @JsonProperty public String mode;
@JsonProperty public String host;
+ @JsonProperty public String node;
+ @JsonProperty public String mode;
@JsonProperty public String zkHost;
@JsonProperty("solr_home")
@@ -42,7 +44,6 @@ public class NodeSystemResponse extends SolrJerseyResponse {
@JsonProperty(value = "environment_color")
public String environmentColor;
- @JsonProperty public String node;
@JsonProperty public Lucene lucene;
@JsonProperty public JVM jvm;
@JsonProperty public Security security;
@@ -55,8 +56,8 @@ public class NodeSystemResponse extends SolrJerseyResponse {
@JsonProperty public String authenticationPlugin;
@JsonProperty public String authorizationPlugin;
@JsonProperty public String username;
- @JsonProperty public List<String> roles;
- @JsonProperty public List<String> permissions;
+ @JsonProperty public Set<String> roles;
+ @JsonProperty public Set<String> permissions;
}
/** /node/system/lucene */
@@ -122,6 +123,6 @@ public class NodeSystemResponse extends SolrJerseyResponse {
@JsonProperty public boolean available;
@JsonProperty public long count;
@JsonProperty public MemoryRaw memory;
- @JsonProperty Map<String, Object> devices;
+ @JsonProperty public Map<String, Object> devices;
}
}
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 4433713209d..2279fb03b17 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
@@ -16,16 +16,10 @@
*/
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;
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;
@@ -54,38 +48,7 @@ public class CoreInfoHandler extends RequestHandlerBase {
@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<Object> getCoreInfo(SolrCore core, IndexSchema
schema) {
- SimpleOrderedMap<Object> 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<Object> 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("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);
- }
- info.add("directory", dirs);
- return info;
+ rsp.add("core", SystemInfoProvider.getCoreInfo(req.getCore(),
req.getSchema()));
}
}
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 eb0079b5080..20fe09098d2 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
@@ -16,52 +16,18 @@
*/
package org.apache.solr.handler.admin;
-import static org.apache.solr.common.params.CommonParams.NAME;
-
-import java.beans.BeanInfo;
-import java.beans.IntrospectionException;
-import java.beans.Introspector;
-import java.beans.PropertyDescriptor;
import java.lang.invoke.MethodHandles;
-import java.lang.management.ManagementFactory;
-import java.lang.management.OperatingSystemMXBean;
-import java.lang.management.PlatformManagedObject;
-import java.lang.management.RuntimeMXBean;
-import java.lang.reflect.Method;
-import java.net.InetAddress;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.function.BiConsumer;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import org.apache.lucene.util.Version;
-import org.apache.solr.api.AnnotatedApi;
-import org.apache.solr.api.Api;
-import org.apache.solr.common.cloud.ZkStateReader;
-import org.apache.solr.common.util.EnvUtils;
-import org.apache.solr.common.util.SimpleOrderedMap;
+import org.apache.solr.api.JerseyResource;
+import org.apache.solr.client.api.model.NodeSystemResponse;
import org.apache.solr.core.CoreContainer;
-import org.apache.solr.core.NodeConfig;
-import org.apache.solr.core.SolrCore;
import org.apache.solr.handler.RequestHandlerBase;
-import org.apache.solr.handler.admin.api.NodeSystemInfoAPI;
-import org.apache.solr.metrics.GpuMetricsProvider;
+import org.apache.solr.handler.admin.api.GetNodeSystemInfo;
+import org.apache.solr.handler.api.V2ApiUtils;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.security.AuthorizationContext;
-import org.apache.solr.security.AuthorizationPlugin;
-import org.apache.solr.security.PKIAuthenticationPlugin;
-import org.apache.solr.security.RuleBasedAuthorizationPluginBase;
-import org.apache.solr.util.RTimer;
-import org.apache.solr.util.stats.MetricUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -72,182 +38,24 @@ import org.slf4j.LoggerFactory;
public class SystemInfoHandler extends RequestHandlerBase {
private static final Logger log =
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
- /**
- * Expert level system property to prevent doing a reverse lookup of our
hostname. This property
- * will be logged as a suggested workaround if any problems are noticed when
doing reverse lookup.
- *
- * <p>TODO: should we refactor this (and the associated logic) into a helper
method for any other
- * places where DNS is used?
- *
- * @see #initHostname
- */
- private static final String REVERSE_DNS_OF_LOCALHOST_SYSPROP =
- "solr.admin.handler.systeminfo.dns.reverse.lookup.enabled";
-
- /**
- * Local cache for BeanInfo instances that are created to scan for system
metrics. List of
- * properties is not supposed to change for the JVM lifespan, so we can keep
already create
- * BeanInfo instance for future calls.
- */
- private static final ConcurrentMap<Class<?>, BeanInfo> beanInfos = new
ConcurrentHashMap<>();
-
- // on some platforms, resolving canonical hostname can cause the thread
- // 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;
-
private CoreContainer cc;
public SystemInfoHandler(CoreContainer cc) {
super();
this.cc = cc;
- initHostname();
- }
-
- /**
- * Iterates over properties of the given MXBean and invokes the provided
consumer with each
- * property name and its current value.
- *
- * @param obj an instance of MXBean
- * @param interfaces interfaces that it may implement. Each interface will
be tried in turn, and
- * only if it exists and if it contains unique properties then they will
be added as metrics.
- * @param consumer consumer for each property name and value
- * @param <T> formal type
- */
- public static <T extends PlatformManagedObject> void forEachGetterValue(
- T obj, String[] interfaces, BiConsumer<String, Object> consumer) {
- for (String clazz : interfaces) {
- try {
- final Class<? extends PlatformManagedObject> intf =
- Class.forName(clazz).asSubclass(PlatformManagedObject.class);
- forEachGetterValue(obj, intf, consumer);
- } catch (ClassNotFoundException e) {
- // ignore
- }
- }
- }
-
- /**
- * Iterates over properties of the given MXBean and invokes the provided
consumer with each
- * property name and its current value.
- *
- * @param obj an instance of MXBean
- * @param intf MXBean interface, one of {@link PlatformManagedObject}-s
- * @param consumer consumer for each property name and value
- * @param <T> formal type
- */
- public static <T extends PlatformManagedObject> void forEachGetterValue(
- T obj, Class<? extends T> intf, BiConsumer<String, Object> consumer) {
- if (intf.isInstance(obj)) {
- BeanInfo beanInfo =
- beanInfos.computeIfAbsent(
- intf,
- clazz -> {
- try {
- return Introspector.getBeanInfo(
- clazz, clazz.getSuperclass(),
Introspector.IGNORE_ALL_BEANINFO);
-
- } catch (IntrospectionException e) {
- log.warn("Unable to fetch properties of MXBean {}",
obj.getClass().getName());
- return null;
- }
- });
-
- // if BeanInfo retrieval failed, return early
- if (beanInfo == null) {
- return;
- }
- for (final PropertyDescriptor desc : beanInfo.getPropertyDescriptors()) {
- try {
- Method readMethod = desc.getReadMethod();
- if (readMethod == null) {
- continue; // skip properties without a read method
- }
-
- final String name = desc.getName();
- Object value = readMethod.invoke(obj);
- consumer.accept(name, value);
- } catch (Exception e) {
- // didn't work, skip it...
- }
- }
- }
- }
-
- private void initHostname() {
- if (!EnvUtils.getPropertyAsBool(REVERSE_DNS_OF_LOCALHOST_SYSPROP, true)) {
- log.info(
- "Resolving canonical hostname for local host prevented due to '{}'
sysprop",
- REVERSE_DNS_OF_LOCALHOST_SYSPROP);
- hostname = null;
- return;
- }
-
- RTimer timer = new RTimer();
- try {
- InetAddress addr = InetAddress.getLocalHost();
- hostname = addr.getCanonicalHostName();
- } catch (Exception e) {
- log.warn(
- "Unable to resolve canonical hostname for local host, possible DNS
misconfiguration. Set the '{}' sysprop to false on startup to prevent future
lookups if DNS can not be fixed.",
- REVERSE_DNS_OF_LOCALHOST_SYSPROP,
- e);
- hostname = null;
- return;
- }
- timer.stop();
-
- if (15000D < timer.getTime()) {
- String readableTime = String.format(Locale.ROOT, "%.3f",
(timer.getTime() / 1000));
- log.warn(
- "Resolving canonical hostname for local host took {} seconds,
possible DNS misconfiguration. Set the '{}' sysprop to false on startup to
prevent future lookups if DNS can not be fixed.",
- readableTime,
- REVERSE_DNS_OF_LOCALHOST_SYSPROP);
- }
}
@Override
public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp)
throws Exception {
rsp.setHttpCaching(false);
+
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);
-
- if (solrCloudMode) {
- rsp.add("zkHost",
getCoreContainer(req).getZkController().getZkServerAddress());
- }
- if (cc != null) {
- rsp.add("solr_home", cc.getSolrHome());
- rsp.add("core_root", cc.getCoreRootDirectory());
- }
-
- rsp.add("lucene", getLuceneInfo());
- NodeConfig nodeConfig = getCoreContainer(req).getNodeConfig();
- rsp.add("jvm", getJvmInfo(nodeConfig));
- rsp.add("security", getSecurityInfo(req));
- rsp.add("system", getSystemInfo());
-
- rsp.add("gpu", getGpuInfo(req));
- if (solrCloudMode) {
- rsp.add("node", getCoreContainer(req).getZkController().getNodeName());
- }
- SolrEnvironment env =
- SolrEnvironment.getFromSyspropOrClusterprop(
- solrCloudMode ?
getCoreContainer(req).getZkController().zkStateReader : null);
- if (env.isDefined()) {
- rsp.add("environment", env.getCode());
- if (env.getLabel() != null) {
- rsp.add("environment_label", env.getLabel());
- }
- if (env.getColor() != null) {
- rsp.add("environment_color", env.getColor());
- }
- }
+ SystemInfoProvider provider = new SystemInfoProvider(req);
+ NodeSystemResponse response = provider.getNodeSystemInfo(new
NodeSystemResponse());
+ V2ApiUtils.squashIntoSolrResponseWithoutHeader(rsp, response);
}
private CoreContainer getCoreContainer(SolrQueryRequest req) {
@@ -255,167 +63,6 @@ public class SystemInfoHandler extends RequestHandlerBase {
return coreContainer == null ? cc : coreContainer;
}
- /** Get system info */
- public static SimpleOrderedMap<Object> getSystemInfo() {
- SimpleOrderedMap<Object> info = new SimpleOrderedMap<>();
-
- OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
- info.add(NAME, os.getName()); // add at least this one
-
- // add remaining ones dynamically using Java Beans API
- // also those from JVM implementation-specific classes
- forEachGetterValue(
- os,
- MetricUtils.OS_MXBEAN_CLASSES,
- (name, value) -> {
- if (info.get(name) == null) {
- info.add(name, value);
- }
- });
-
- return info;
- }
-
- /** Get JVM Info - including memory info */
- public static SimpleOrderedMap<Object> getJvmInfo(NodeConfig nodeConfig) {
- SimpleOrderedMap<Object> jvm = new SimpleOrderedMap<>();
-
- final String javaVersion =
System.getProperty("java.specification.version", "unknown");
- final String javaVendor = System.getProperty("java.specification.vendor",
"unknown");
- final String javaName = System.getProperty("java.specification.name",
"unknown");
- final String jreVersion = System.getProperty("java.version", "unknown");
- final String jreVendor = System.getProperty("java.vendor", "unknown");
- final String vmVersion = System.getProperty("java.vm.version", "unknown");
- final String vmVendor = System.getProperty("java.vm.vendor", "unknown");
- final String vmName = System.getProperty("java.vm.name", "unknown");
-
- // Summary Info
- jvm.add("version", jreVersion + " " + vmVersion);
- jvm.add(NAME, jreVendor + " " + vmName);
-
- // details
- SimpleOrderedMap<Object> java = new SimpleOrderedMap<>();
- java.add("vendor", javaVendor);
- java.add(NAME, javaName);
- java.add("version", javaVersion);
- jvm.add("spec", java);
- SimpleOrderedMap<Object> jre = new SimpleOrderedMap<>();
- jre.add("vendor", jreVendor);
- jre.add("version", jreVersion);
- jvm.add("jre", jre);
- SimpleOrderedMap<Object> vm = new SimpleOrderedMap<>();
- vm.add("vendor", vmVendor);
- vm.add(NAME, vmName);
- vm.add("version", vmVersion);
- jvm.add("vm", vm);
-
- Runtime runtime = Runtime.getRuntime();
- jvm.add("processors", runtime.availableProcessors());
-
- // not thread safe, but could be thread local
- DecimalFormat df = new DecimalFormat("#.#",
DecimalFormatSymbols.getInstance(Locale.ROOT));
-
- SimpleOrderedMap<Object> mem = new SimpleOrderedMap<>();
- SimpleOrderedMap<Object> raw = new SimpleOrderedMap<>();
- long free = runtime.freeMemory();
- long max = runtime.maxMemory();
- long total = runtime.totalMemory();
- long used = total - free;
- double percentUsed = ((double) (used) / (double) max) * 100;
- raw.add("free", free);
- mem.add("free", humanReadableUnits(free, df));
- raw.add("total", total);
- mem.add("total", humanReadableUnits(total, df));
- raw.add("max", max);
- mem.add("max", humanReadableUnits(max, df));
- raw.add("used", used);
- mem.add("used", humanReadableUnits(used, df) + " (%" +
df.format(percentUsed) + ")");
- raw.add("used%", percentUsed);
-
- mem.add("raw", raw);
- jvm.add("memory", mem);
-
- // JMX properties -- probably should be moved to a different handler
- SimpleOrderedMap<Object> jmx = new SimpleOrderedMap<>();
- try {
- RuntimeMXBean mx = ManagementFactory.getRuntimeMXBean();
- if (mx.isBootClassPathSupported()) {
- jmx.add("bootclasspath", mx.getBootClassPath());
- }
- jmx.add("classpath", mx.getClassPath());
-
- // the input arguments passed to the Java virtual machine
- // which does not include the arguments to the main method.
- jmx.add("commandLineArgs", getInputArgumentsRedacted(nodeConfig, mx));
-
- jmx.add("startTime", new Date(mx.getStartTime()));
- jmx.add("upTimeMS", mx.getUptime());
-
- } catch (Exception e) {
- log.warn("Error getting JMX properties", e);
- }
- jvm.add("jmx", jmx);
- return jvm;
- }
-
- /** Get Security Info */
- public SimpleOrderedMap<Object> getSecurityInfo(SolrQueryRequest req) {
- SimpleOrderedMap<Object> info = new SimpleOrderedMap<>();
-
- if (cc != null) {
- if (cc.getAuthenticationPlugin() != null) {
- info.add("authenticationPlugin",
cc.getAuthenticationPlugin().getName());
- }
- if (cc.getAuthorizationPlugin() != null) {
- info.add("authorizationPlugin",
cc.getAuthorizationPlugin().getClass().getName());
- }
- }
-
- if (req.getUserPrincipal() != null
- && req.getUserPrincipal() !=
PKIAuthenticationPlugin.CLUSTER_MEMBER_NODE) {
- // User principal
- info.add("username", req.getUserPrincipal().getName());
-
- // Mapped roles for this principal
- @SuppressWarnings("resource")
- AuthorizationPlugin auth = cc == null ? null :
cc.getAuthorizationPlugin();
- if (auth instanceof RuleBasedAuthorizationPluginBase rbap) {
- Set<String> roles = rbap.getUserRoles(req.getUserPrincipal());
- info.add("roles", roles);
- if (roles == null) {
- info.add("permissions", Set.of());
- } else {
- info.add(
- "permissions",
- rbap.getPermissionNamesForRoles(
- Stream.concat(roles.stream(), Stream.of("*",
null)).collect(Collectors.toSet())));
- }
- }
- }
-
- if (cc != null && cc.getZkController() != null) {
- String urlScheme =
-
cc.getZkController().zkStateReader.getClusterProperty(ZkStateReader.URL_SCHEME,
"http");
- info.add("tls", ZkStateReader.HTTPS.equals(urlScheme));
- }
-
- return info;
- }
-
- private static SimpleOrderedMap<Object> getLuceneInfo() {
- SimpleOrderedMap<Object> info = new SimpleOrderedMap<>();
-
- Package p = SolrCore.class.getPackage();
-
- info.add("solr-spec-version", p.getSpecificationVersion());
- info.add("solr-impl-version", p.getImplementationVersion());
-
- info.add("lucene-spec-version", Version.LATEST.toString());
- info.add("lucene-impl-version", Version.getPackageImplementationVersion());
-
- return info;
- }
-
//////////////////////// SolrInfoMBeans methods //////////////////////
@Override
@@ -428,49 +75,9 @@ public class SystemInfoHandler extends RequestHandlerBase {
return Category.ADMIN;
}
- private static final long ONE_KB = 1024;
- private static final long ONE_MB = ONE_KB * ONE_KB;
- private static final long ONE_GB = ONE_KB * ONE_MB;
-
- /** Return good default units based on byte size. */
- private static String humanReadableUnits(long bytes, DecimalFormat df) {
- String newSizeAndUnits;
-
- if (bytes / ONE_GB > 0) {
- newSizeAndUnits = df.format((float) bytes / ONE_GB) + " GB";
- } else if (bytes / ONE_MB > 0) {
- newSizeAndUnits = df.format((float) bytes / ONE_MB) + " MB";
- } else if (bytes / ONE_KB > 0) {
- newSizeAndUnits = df.format((float) bytes / ONE_KB) + " KB";
- } else {
- newSizeAndUnits = bytes + " bytes";
- }
-
- return newSizeAndUnits;
- }
-
- private static List<String> getInputArgumentsRedacted(NodeConfig nodeConfig,
RuntimeMXBean mx) {
- List<String> list = new ArrayList<>();
- for (String arg : mx.getInputArguments()) {
- if (arg.startsWith("-D")
- && arg.contains("=")
- && nodeConfig.isSysPropHidden(arg.substring(2, arg.indexOf('=')))) {
- list.add(
- String.format(
- Locale.ROOT,
- "%s=%s",
- arg.substring(0, arg.indexOf('=')),
- NodeConfig.REDACTED_SYS_PROP_VALUE));
- } else {
- list.add(arg);
- }
- }
- return list;
- }
-
@Override
- public Collection<Api> getApis() {
- return AnnotatedApi.getApis(new NodeSystemInfoAPI(this));
+ public Collection<Class<? extends JerseyResource>> getJerseyResources() {
+ return Set.of(GetNodeSystemInfo.class);
}
@Override
@@ -478,50 +85,6 @@ public class SystemInfoHandler extends RequestHandlerBase {
return Boolean.TRUE;
}
- private SimpleOrderedMap<Object> getGpuInfo(SolrQueryRequest req) {
- SimpleOrderedMap<Object> gpuInfo = new SimpleOrderedMap<>();
-
- try {
- GpuMetricsProvider provider =
getCoreContainer(req).getGpuMetricsProvider();
-
- if (provider == null) {
- gpuInfo.add("available", false);
- return gpuInfo;
- }
-
- long gpuCount = provider.getGpuCount();
- if (gpuCount > 0) {
- gpuInfo.add("available", true);
- gpuInfo.add("count", gpuCount);
-
- long gpuMemoryTotal = provider.getGpuMemoryTotal();
- long gpuMemoryUsed = provider.getGpuMemoryUsed();
- long gpuMemoryFree = provider.getGpuMemoryFree();
-
- if (gpuMemoryTotal > 0) {
- SimpleOrderedMap<Object> memory = new SimpleOrderedMap<>();
- memory.add("total", gpuMemoryTotal);
- memory.add("used", gpuMemoryUsed);
- memory.add("free", gpuMemoryFree);
- gpuInfo.add("memory", memory);
- }
-
- var devices = provider.getGpuDevices();
- if (devices != null && devices.size() > 0) {
- gpuInfo.add("devices", devices);
- }
- } else {
- gpuInfo.add("available", false);
- }
-
- } catch (Exception e) {
- log.warn("Failed to get GPU information", e);
- gpuInfo.add("available", false);
- }
-
- return gpuInfo;
- }
-
@Override
public Name getPermissionName(AuthorizationContext request) {
return Name.CONFIG_READ_PERM;
diff --git
a/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java
b/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoProvider.java
similarity index 58%
copy from
solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java
copy to solr/core/src/java/org/apache/solr/handler/admin/SystemInfoProvider.java
index eb0079b5080..03e7df5c4b0 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/SystemInfoProvider.java
@@ -22,6 +22,7 @@ import java.beans.BeanInfo;
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;
@@ -29,13 +30,15 @@ import java.lang.management.PlatformManagedObject;
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;
-import java.util.Collection;
import java.util.Date;
+import java.util.HashMap;
import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@@ -43,20 +46,18 @@ import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.lucene.util.Version;
-import org.apache.solr.api.AnnotatedApi;
-import org.apache.solr.api.Api;
+import org.apache.solr.client.api.model.NodeSystemResponse;
+import org.apache.solr.client.api.util.SolrVersion;
import org.apache.solr.common.cloud.ZkStateReader;
+import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.EnvUtils;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.NodeConfig;
import org.apache.solr.core.SolrCore;
-import org.apache.solr.handler.RequestHandlerBase;
-import org.apache.solr.handler.admin.api.NodeSystemInfoAPI;
import org.apache.solr.metrics.GpuMetricsProvider;
import org.apache.solr.request.SolrQueryRequest;
-import org.apache.solr.response.SolrQueryResponse;
-import org.apache.solr.security.AuthorizationContext;
+import org.apache.solr.schema.IndexSchema;
import org.apache.solr.security.AuthorizationPlugin;
import org.apache.solr.security.PKIAuthenticationPlugin;
import org.apache.solr.security.RuleBasedAuthorizationPluginBase;
@@ -65,16 +66,28 @@ import org.apache.solr.util.stats.MetricUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-/**
- * This handler returns node/container level info. See {@link
- * org.apache.solr.handler.admin.CoreInfoHandler}
- */
-public class SystemInfoHandler extends RequestHandlerBase {
+/** Used by GetNodeSystemInfo, and indirectly by SystemInfoHandler */
+public class SystemInfoProvider {
private static final Logger log =
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+ private SolrQueryRequest req;
+ private SolrParams params;
+ private CoreContainer cc;
+
+ // on some platforms, resolving canonical hostname can cause the thread
+ // to block for several seconds if nameservices aren't available
+ // so resolve this once per provider instance
+ // (ie: not static, so core reload will refresh)
+ private String hostname;
+
+ private static final long ONE_KB = 1024;
+ private static final long ONE_MB = ONE_KB * ONE_KB;
+ private static final long ONE_GB = ONE_KB * ONE_MB;
+
/**
- * Expert level system property to prevent doing a reverse lookup of our
hostname. This property
- * will be logged as a suggested workaround if any problems are noticed when
doing reverse lookup.
+ * Undocumented expert level system property to prevent doing a reverse
lookup of our hostname.
+ * This property will be logged as a suggested workaround if any problems
are noticed when doing
+ * reverse lookup.
*
* <p>TODO: should we refactor this (and the associated logic) into a helper
method for any other
* places where DNS is used?
@@ -91,176 +104,87 @@ public class SystemInfoHandler extends RequestHandlerBase
{
*/
private static final ConcurrentMap<Class<?>, BeanInfo> beanInfos = new
ConcurrentHashMap<>();
- // on some platforms, resolving canonical hostname can cause the thread
- // 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;
-
- private CoreContainer cc;
-
- public SystemInfoHandler(CoreContainer cc) {
- super();
- this.cc = cc;
+ public SystemInfoProvider(SolrQueryRequest request) {
+ req = request;
+ params = request.getParams();
+ cc = request.getCoreContainer();
initHostname();
}
- /**
- * Iterates over properties of the given MXBean and invokes the provided
consumer with each
- * property name and its current value.
- *
- * @param obj an instance of MXBean
- * @param interfaces interfaces that it may implement. Each interface will
be tried in turn, and
- * only if it exists and if it contains unique properties then they will
be added as metrics.
- * @param consumer consumer for each property name and value
- * @param <T> formal type
- */
- public static <T extends PlatformManagedObject> void forEachGetterValue(
- T obj, String[] interfaces, BiConsumer<String, Object> consumer) {
- for (String clazz : interfaces) {
- try {
- final Class<? extends PlatformManagedObject> intf =
- Class.forName(clazz).asSubclass(PlatformManagedObject.class);
- forEachGetterValue(obj, intf, consumer);
- } catch (ClassNotFoundException e) {
- // ignore
- }
- }
- }
-
- /**
- * Iterates over properties of the given MXBean and invokes the provided
consumer with each
- * property name and its current value.
- *
- * @param obj an instance of MXBean
- * @param intf MXBean interface, one of {@link PlatformManagedObject}-s
- * @param consumer consumer for each property name and value
- * @param <T> formal type
- */
- public static <T extends PlatformManagedObject> void forEachGetterValue(
- T obj, Class<? extends T> intf, BiConsumer<String, Object> consumer) {
- if (intf.isInstance(obj)) {
- BeanInfo beanInfo =
- beanInfos.computeIfAbsent(
- intf,
- clazz -> {
- try {
- return Introspector.getBeanInfo(
- clazz, clazz.getSuperclass(),
Introspector.IGNORE_ALL_BEANINFO);
-
- } catch (IntrospectionException e) {
- log.warn("Unable to fetch properties of MXBean {}",
obj.getClass().getName());
- return null;
- }
- });
-
- // if BeanInfo retrieval failed, return early
- if (beanInfo == null) {
- return;
- }
- for (final PropertyDescriptor desc : beanInfo.getPropertyDescriptors()) {
- try {
- Method readMethod = desc.getReadMethod();
- if (readMethod == null) {
- continue; // skip properties without a read method
- }
-
- final String name = desc.getName();
- Object value = readMethod.invoke(obj);
- consumer.accept(name, value);
- } catch (Exception e) {
- // didn't work, skip it...
- }
- }
- }
- }
-
- private void initHostname() {
- if (!EnvUtils.getPropertyAsBool(REVERSE_DNS_OF_LOCALHOST_SYSPROP, true)) {
- log.info(
- "Resolving canonical hostname for local host prevented due to '{}'
sysprop",
- REVERSE_DNS_OF_LOCALHOST_SYSPROP);
- hostname = null;
- return;
- }
-
- RTimer timer = new RTimer();
- try {
- InetAddress addr = InetAddress.getLocalHost();
- hostname = addr.getCanonicalHostName();
- } catch (Exception e) {
- log.warn(
- "Unable to resolve canonical hostname for local host, possible DNS
misconfiguration. Set the '{}' sysprop to false on startup to prevent future
lookups if DNS can not be fixed.",
- REVERSE_DNS_OF_LOCALHOST_SYSPROP,
- e);
- hostname = null;
- return;
- }
- timer.stop();
-
- if (15000D < timer.getTime()) {
- String readableTime = String.format(Locale.ROOT, "%.3f",
(timer.getTime() / 1000));
- log.warn(
- "Resolving canonical hostname for local host took {} seconds,
possible DNS misconfiguration. Set the '{}' sysprop to false on startup to
prevent future lookups if DNS can not be fixed.",
- readableTime,
- REVERSE_DNS_OF_LOCALHOST_SYSPROP);
+ /** Fill-out the provided response with all system info. */
+ public NodeSystemResponse getNodeSystemInfo(NodeSystemResponse response) {
+ if (cc != null) {
+ response.solrHome = cc.getSolrHome().toString();
+ response.coreRoot = cc.getCoreRootDirectory().toString();
}
- }
- @Override
- public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp)
throws Exception {
- rsp.setHttpCaching(false);
- if (AdminHandlersProxy.maybeProxyToNodes(req, rsp, getCoreContainer(req)))
{
- return; // Request was proxied to other node
+ boolean solrCloudMode = cc != null && cc.isZooKeeperAware();
+ response.mode = solrCloudMode ? "solrcloud" : "std";
+ if (solrCloudMode) {
+ response.zkHost = cc.getZkController().getZkServerAddress();
+ response.node = cc.getZkController().getNodeName();
}
- boolean solrCloudMode = getCoreContainer(req).isZooKeeperAware();
- rsp.add("mode", solrCloudMode ? "solrcloud" : "std");
- rsp.add("host", hostname);
+ response.lucene = getLuceneInfo();
- if (solrCloudMode) {
- rsp.add("zkHost",
getCoreContainer(req).getZkController().getZkServerAddress());
- }
- if (cc != null) {
- rsp.add("solr_home", cc.getSolrHome());
- rsp.add("core_root", cc.getCoreRootDirectory());
- }
+ response.jvm = getJvmInfo();
- rsp.add("lucene", getLuceneInfo());
- NodeConfig nodeConfig = getCoreContainer(req).getNodeConfig();
- rsp.add("jvm", getJvmInfo(nodeConfig));
- rsp.add("security", getSecurityInfo(req));
- rsp.add("system", getSystemInfo());
+ response.security = getSecurityInfo();
+ response.system = getSystemInfo();
+ response.gpu = getGpuInfo();
- rsp.add("gpu", getGpuInfo(req));
- if (solrCloudMode) {
- rsp.add("node", getCoreContainer(req).getZkController().getNodeName());
- }
SolrEnvironment env =
SolrEnvironment.getFromSyspropOrClusterprop(
- solrCloudMode ?
getCoreContainer(req).getZkController().zkStateReader : null);
+ solrCloudMode ? cc.getZkController().zkStateReader : null);
if (env.isDefined()) {
- rsp.add("environment", env.getCode());
+ response.environment = env.getCode();
if (env.getLabel() != null) {
- rsp.add("environment_label", env.getLabel());
+ response.environmentLabel = env.getLabel();
}
if (env.getColor() != null) {
- rsp.add("environment_color", env.getColor());
+ response.environmentColor = env.getColor();
}
}
+ return response;
}
- private CoreContainer getCoreContainer(SolrQueryRequest req) {
- CoreContainer coreContainer = req.getCoreContainer();
- return coreContainer == null ? cc : coreContainer;
+ /** Get core Info for V1 */
+ public static SimpleOrderedMap<Object> getCoreInfo(SolrCore core,
IndexSchema schema) {
+ SimpleOrderedMap<Object> 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<Object> 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("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);
+ }
+ info.add("directory", dirs);
+ return info;
}
/** Get system info */
- public static SimpleOrderedMap<Object> getSystemInfo() {
- SimpleOrderedMap<Object> info = new SimpleOrderedMap<>();
+ public Map<String, String> getSystemInfo() {
+ Map<String, String> info = new HashMap<>();
OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
- info.add(NAME, os.getName()); // add at least this one
+ info.put(NAME, os.getName()); // add at least this one
// add remaining ones dynamically using Java Beans API
// also those from JVM implementation-specific classes
@@ -269,7 +193,7 @@ public class SystemInfoHandler extends RequestHandlerBase {
MetricUtils.OS_MXBEAN_CLASSES,
(name, value) -> {
if (info.get(name) == null) {
- info.add(name, value);
+ info.put(name, String.valueOf(value));
}
});
@@ -277,8 +201,8 @@ public class SystemInfoHandler extends RequestHandlerBase {
}
/** Get JVM Info - including memory info */
- public static SimpleOrderedMap<Object> getJvmInfo(NodeConfig nodeConfig) {
- SimpleOrderedMap<Object> jvm = new SimpleOrderedMap<>();
+ public NodeSystemResponse.JVM getJvmInfo() {
+ NodeSystemResponse.JVM jvm = new NodeSystemResponse.JVM();
final String javaVersion =
System.getProperty("java.specification.version", "unknown");
final String javaVendor = System.getProperty("java.specification.vendor",
"unknown");
@@ -290,105 +214,107 @@ public class SystemInfoHandler extends
RequestHandlerBase {
final String vmName = System.getProperty("java.vm.name", "unknown");
// Summary Info
- jvm.add("version", jreVersion + " " + vmVersion);
- jvm.add(NAME, jreVendor + " " + vmName);
+ jvm.version = jreVersion + " " + vmVersion;
+ jvm.name = jreVendor + " " + vmName;
// details
- SimpleOrderedMap<Object> java = new SimpleOrderedMap<>();
- java.add("vendor", javaVendor);
- java.add(NAME, javaName);
- java.add("version", javaVersion);
- jvm.add("spec", java);
- SimpleOrderedMap<Object> jre = new SimpleOrderedMap<>();
- jre.add("vendor", jreVendor);
- jre.add("version", jreVersion);
- jvm.add("jre", jre);
- SimpleOrderedMap<Object> vm = new SimpleOrderedMap<>();
- vm.add("vendor", vmVendor);
- vm.add(NAME, vmName);
- vm.add("version", vmVersion);
- jvm.add("vm", vm);
+ NodeSystemResponse.Vendor spec = new NodeSystemResponse.Vendor();
+ spec.vendor = javaVendor;
+ spec.name = javaName;
+ spec.version = javaVersion;
+ jvm.spec = spec;
+
+ NodeSystemResponse.Vendor jre = new NodeSystemResponse.Vendor();
+ jre.vendor = jreVendor;
+ jre.version = jreVersion;
+ jvm.jre = jre;
+
+ NodeSystemResponse.Vendor vm = new NodeSystemResponse.Vendor();
+ vm.vendor = vmVendor;
+ vm.name = vmName;
+ vm.version = vmVersion;
+ jvm.vm = vm;
Runtime runtime = Runtime.getRuntime();
- jvm.add("processors", runtime.availableProcessors());
+ jvm.processors = runtime.availableProcessors();
// not thread safe, but could be thread local
DecimalFormat df = new DecimalFormat("#.#",
DecimalFormatSymbols.getInstance(Locale.ROOT));
- SimpleOrderedMap<Object> mem = new SimpleOrderedMap<>();
- SimpleOrderedMap<Object> raw = new SimpleOrderedMap<>();
+ NodeSystemResponse.JvmMemory mem = new NodeSystemResponse.JvmMemory();
+ NodeSystemResponse.JvmMemoryRaw raw = new
NodeSystemResponse.JvmMemoryRaw();
long free = runtime.freeMemory();
long max = runtime.maxMemory();
long total = runtime.totalMemory();
long used = total - free;
double percentUsed = ((double) (used) / (double) max) * 100;
- raw.add("free", free);
- mem.add("free", humanReadableUnits(free, df));
- raw.add("total", total);
- mem.add("total", humanReadableUnits(total, df));
- raw.add("max", max);
- mem.add("max", humanReadableUnits(max, df));
- raw.add("used", used);
- mem.add("used", humanReadableUnits(used, df) + " (%" +
df.format(percentUsed) + ")");
- raw.add("used%", percentUsed);
-
- mem.add("raw", raw);
- jvm.add("memory", mem);
-
- // JMX properties -- probably should be moved to a different handler
- SimpleOrderedMap<Object> jmx = new SimpleOrderedMap<>();
+ raw.free = free;
+ mem.free = humanReadableUnits(free, df);
+ raw.total = total;
+ mem.total = humanReadableUnits(total, df);
+ raw.max = max;
+ mem.max = humanReadableUnits(max, df);
+ raw.used = used;
+ mem.used = humanReadableUnits(used, df) + " (%" + df.format(percentUsed) +
")";
+ raw.usedPercent = percentUsed;
+
+ mem.raw = raw;
+ jvm.memory = mem;
+
+ // JMX properties
+ NodeSystemResponse.JvmJmx jmx = new NodeSystemResponse.JvmJmx();
try {
RuntimeMXBean mx = ManagementFactory.getRuntimeMXBean();
if (mx.isBootClassPathSupported()) {
- jmx.add("bootclasspath", mx.getBootClassPath());
+ jmx.classpath = mx.getBootClassPath();
}
- jmx.add("classpath", mx.getClassPath());
+ jmx.classpath = mx.getClassPath();
// the input arguments passed to the Java virtual machine
// which does not include the arguments to the main method.
- jmx.add("commandLineArgs", getInputArgumentsRedacted(nodeConfig, mx));
+ NodeConfig nodeConfig = cc != null ? cc.getNodeConfig() : null;
+ jmx.commandLineArgs = getInputArgumentsRedacted(nodeConfig, mx);
- jmx.add("startTime", new Date(mx.getStartTime()));
- jmx.add("upTimeMS", mx.getUptime());
+ jmx.startTime = new Date(mx.getStartTime());
+ jmx.upTimeMS = mx.getUptime();
} catch (Exception e) {
log.warn("Error getting JMX properties", e);
}
- jvm.add("jmx", jmx);
+ jvm.jmx = jmx;
return jvm;
}
/** Get Security Info */
- public SimpleOrderedMap<Object> getSecurityInfo(SolrQueryRequest req) {
- SimpleOrderedMap<Object> info = new SimpleOrderedMap<>();
+ public NodeSystemResponse.Security getSecurityInfo() {
+ NodeSystemResponse.Security info = new NodeSystemResponse.Security();
if (cc != null) {
if (cc.getAuthenticationPlugin() != null) {
- info.add("authenticationPlugin",
cc.getAuthenticationPlugin().getName());
+ info.authenticationPlugin = cc.getAuthenticationPlugin().getName();
}
if (cc.getAuthorizationPlugin() != null) {
- info.add("authorizationPlugin",
cc.getAuthorizationPlugin().getClass().getName());
+ info.authorizationPlugin =
cc.getAuthorizationPlugin().getClass().getName();
}
}
if (req.getUserPrincipal() != null
&& req.getUserPrincipal() !=
PKIAuthenticationPlugin.CLUSTER_MEMBER_NODE) {
// User principal
- info.add("username", req.getUserPrincipal().getName());
+ info.username = req.getUserPrincipal().getName();
// Mapped roles for this principal
- @SuppressWarnings("resource")
+ // @SuppressWarnings("resource")
AuthorizationPlugin auth = cc == null ? null :
cc.getAuthorizationPlugin();
if (auth instanceof RuleBasedAuthorizationPluginBase rbap) {
Set<String> roles = rbap.getUserRoles(req.getUserPrincipal());
- info.add("roles", roles);
+ info.roles = roles;
if (roles == null) {
- info.add("permissions", Set.of());
+ info.permissions = Set.of();
} else {
- info.add(
- "permissions",
+ info.permissions =
rbap.getPermissionNamesForRoles(
- Stream.concat(roles.stream(), Stream.of("*",
null)).collect(Collectors.toSet())));
+ Stream.concat(roles.stream(), Stream.of("*",
null)).collect(Collectors.toSet()));
}
}
}
@@ -396,65 +322,96 @@ public class SystemInfoHandler extends RequestHandlerBase
{
if (cc != null && cc.getZkController() != null) {
String urlScheme =
cc.getZkController().zkStateReader.getClusterProperty(ZkStateReader.URL_SCHEME,
"http");
- info.add("tls", ZkStateReader.HTTPS.equals(urlScheme));
+ info.tls = ZkStateReader.HTTPS.equals(urlScheme);
}
return info;
}
- private static SimpleOrderedMap<Object> getLuceneInfo() {
- SimpleOrderedMap<Object> info = new SimpleOrderedMap<>();
+ /** Get Lucene and Solr versions */
+ public NodeSystemResponse.Lucene getLuceneInfo() {
+ NodeSystemResponse.Lucene info = new NodeSystemResponse.Lucene();
Package p = SolrCore.class.getPackage();
+ String specVersion = p.getSpecificationVersion();
+ String implVersion = p.getImplementationVersion();
+ // non-null mostly for testing
+ info.solrSpecVersion = specVersion == null ? SolrVersion.LATEST_STRING :
specVersion;
+ info.solrImplVersion =
+ implVersion == null ? SolrVersion.LATEST.getPrereleaseVersion() :
implVersion;
- info.add("solr-spec-version", p.getSpecificationVersion());
- info.add("solr-impl-version", p.getImplementationVersion());
-
- info.add("lucene-spec-version", Version.LATEST.toString());
- info.add("lucene-impl-version", Version.getPackageImplementationVersion());
+ info.luceneSpecVersion = Version.LATEST.toString();
+ info.luceneImplVersion = Version.getPackageImplementationVersion();
return info;
}
- //////////////////////// SolrInfoMBeans methods //////////////////////
+ /** Get GPU info */
+ public NodeSystemResponse.GPU getGpuInfo() {
+ NodeSystemResponse.GPU gpuInfo = new NodeSystemResponse.GPU();
+ gpuInfo.available = false; // set below if available
- @Override
- public String getDescription() {
- return "Get System Info";
- }
+ try {
+ GpuMetricsProvider provider = cc.getGpuMetricsProvider();
- @Override
- public Category getCategory() {
- return Category.ADMIN;
- }
+ if (provider == null) {
+ return gpuInfo;
+ }
- private static final long ONE_KB = 1024;
- private static final long ONE_MB = ONE_KB * ONE_KB;
- private static final long ONE_GB = ONE_KB * ONE_MB;
+ long gpuCount = provider.getGpuCount();
+ if (gpuCount > 0) {
+ gpuInfo.available = true;
+ gpuInfo.count = gpuCount;
+
+ long gpuMemoryTotal = provider.getGpuMemoryTotal();
+ long gpuMemoryUsed = provider.getGpuMemoryUsed();
+ long gpuMemoryFree = provider.getGpuMemoryFree();
+
+ if (gpuMemoryTotal > 0) {
+ NodeSystemResponse.MemoryRaw memory = new
NodeSystemResponse.MemoryRaw();
+ memory.total = gpuMemoryTotal;
+ memory.used = gpuMemoryUsed;
+ memory.free = gpuMemoryFree;
+ gpuInfo.memory = memory;
+ }
+
+ var devices = provider.getGpuDevices();
+ if (devices != null && devices.size() > 0) {
+ gpuInfo.devices = devices;
+ }
+ }
+
+ } catch (Exception e) {
+ log.warn("Failed to get GPU information", e);
+ }
+
+ return gpuInfo;
+ }
/** Return good default units based on byte size. */
- private static String humanReadableUnits(long bytes, DecimalFormat df) {
+ private String humanReadableUnits(long bytes, DecimalFormat df) {
String newSizeAndUnits;
if (bytes / ONE_GB > 0) {
- newSizeAndUnits = df.format((float) bytes / ONE_GB) + " GB";
+ newSizeAndUnits = String.valueOf(df.format((float) bytes / ONE_GB)) + "
GB";
} else if (bytes / ONE_MB > 0) {
- newSizeAndUnits = df.format((float) bytes / ONE_MB) + " MB";
+ newSizeAndUnits = String.valueOf(df.format((float) bytes / ONE_MB)) + "
MB";
} else if (bytes / ONE_KB > 0) {
- newSizeAndUnits = df.format((float) bytes / ONE_KB) + " KB";
+ newSizeAndUnits = String.valueOf(df.format((float) bytes / ONE_KB)) + "
KB";
} else {
- newSizeAndUnits = bytes + " bytes";
+ newSizeAndUnits = String.valueOf(bytes) + " bytes";
}
return newSizeAndUnits;
}
- private static List<String> getInputArgumentsRedacted(NodeConfig nodeConfig,
RuntimeMXBean mx) {
+ private List<String> getInputArgumentsRedacted(NodeConfig nodeConfig,
RuntimeMXBean mx) {
List<String> list = new ArrayList<>();
for (String arg : mx.getInputArguments()) {
if (arg.startsWith("-D")
&& arg.contains("=")
- && nodeConfig.isSysPropHidden(arg.substring(2, arg.indexOf('=')))) {
+ && (nodeConfig != null
+ && nodeConfig.isSysPropHidden(arg.substring(2,
arg.indexOf('='))))) {
list.add(
String.format(
Locale.ROOT,
@@ -468,62 +425,107 @@ public class SystemInfoHandler extends
RequestHandlerBase {
return list;
}
- @Override
- public Collection<Api> getApis() {
- return AnnotatedApi.getApis(new NodeSystemInfoAPI(this));
- }
-
- @Override
- public Boolean registerV2() {
- return Boolean.TRUE;
+ /**
+ * Iterates over properties of the given MXBean and invokes the provided
consumer with each
+ * property name and its current value.
+ *
+ * @param obj an instance of MXBean
+ * @param interfaces interfaces that it may implement. Each interface will
be tried in turn, and
+ * only if it exists and if it contains unique properties then they will
be added as metrics.
+ * @param consumer consumer for each property name and value
+ * @param <T> formal type
+ */
+ private <T extends PlatformManagedObject> void forEachGetterValue(
+ T obj, String[] interfaces, BiConsumer<String, Object> consumer) {
+ for (String clazz : interfaces) {
+ try {
+ final Class<? extends PlatformManagedObject> intf =
+ Class.forName(clazz).asSubclass(PlatformManagedObject.class);
+ forEachGetterValue(obj, intf, consumer);
+ } catch (ClassNotFoundException e) {
+ // ignore
+ }
+ }
}
- private SimpleOrderedMap<Object> getGpuInfo(SolrQueryRequest req) {
- SimpleOrderedMap<Object> gpuInfo = new SimpleOrderedMap<>();
+ /**
+ * Iterates over properties of the given MXBean and invokes the provided
consumer with each
+ * property name and its current value.
+ *
+ * @param obj an instance of MXBean
+ * @param intf MXBean interface, one of {@link PlatformManagedObject}-s
+ * @param consumer consumer for each property name and value
+ * @param <T> formal type
+ */
+ // protected & static : ref. test in NodeSystemInfoProviderTest
+ protected static <T extends PlatformManagedObject> void forEachGetterValue(
+ T obj, Class<? extends T> intf, BiConsumer<String, Object> consumer) {
+ if (intf.isInstance(obj)) {
+ BeanInfo beanInfo =
+ beanInfos.computeIfAbsent(
+ intf,
+ clazz -> {
+ try {
+ return Introspector.getBeanInfo(
+ clazz, clazz.getSuperclass(),
Introspector.IGNORE_ALL_BEANINFO);
- try {
- GpuMetricsProvider provider =
getCoreContainer(req).getGpuMetricsProvider();
+ } catch (IntrospectionException e) {
+ log.warn("Unable to fetch properties of MXBean {}",
obj.getClass().getName());
+ return null;
+ }
+ });
- if (provider == null) {
- gpuInfo.add("available", false);
- return gpuInfo;
+ // if BeanInfo retrieval failed, return early
+ if (beanInfo == null) {
+ return;
}
+ for (final PropertyDescriptor desc : beanInfo.getPropertyDescriptors()) {
+ try {
+ Method readMethod = desc.getReadMethod();
+ if (readMethod == null) {
+ continue; // skip properties without a read method
+ }
- long gpuCount = provider.getGpuCount();
- if (gpuCount > 0) {
- gpuInfo.add("available", true);
- gpuInfo.add("count", gpuCount);
-
- long gpuMemoryTotal = provider.getGpuMemoryTotal();
- long gpuMemoryUsed = provider.getGpuMemoryUsed();
- long gpuMemoryFree = provider.getGpuMemoryFree();
-
- if (gpuMemoryTotal > 0) {
- SimpleOrderedMap<Object> memory = new SimpleOrderedMap<>();
- memory.add("total", gpuMemoryTotal);
- memory.add("used", gpuMemoryUsed);
- memory.add("free", gpuMemoryFree);
- gpuInfo.add("memory", memory);
- }
-
- var devices = provider.getGpuDevices();
- if (devices != null && devices.size() > 0) {
- gpuInfo.add("devices", devices);
+ final String name = desc.getName();
+ Object value = readMethod.invoke(obj);
+ consumer.accept(name, value);
+ } catch (Exception e) {
+ // didn't work, skip it...
}
- } else {
- gpuInfo.add("available", false);
}
-
- } catch (Exception e) {
- log.warn("Failed to get GPU information", e);
- gpuInfo.add("available", false);
}
-
- return gpuInfo;
}
- @Override
- public Name getPermissionName(AuthorizationContext request) {
- return Name.CONFIG_READ_PERM;
+ private void initHostname() {
+ if (!EnvUtils.getPropertyAsBool(REVERSE_DNS_OF_LOCALHOST_SYSPROP, true)) {
+ log.info(
+ "Resolving canonical hostname for local host prevented due to '{}'
sysprop",
+ REVERSE_DNS_OF_LOCALHOST_SYSPROP);
+ hostname = null;
+ return;
+ }
+
+ RTimer timer = new RTimer();
+ try {
+ InetAddress addr = InetAddress.getLocalHost();
+ hostname = addr.getCanonicalHostName();
+ } catch (Exception e) {
+ log.warn(
+ "Unable to resolve canonical hostname for local host, possible DNS
misconfiguration. Set the '{}' sysprop to false on startup to prevent future
lookups if DNS can not be fixed.",
+ REVERSE_DNS_OF_LOCALHOST_SYSPROP,
+ e);
+ hostname = null;
+ return;
+ } finally {
+ timer.stop();
+
+ if (15000D < timer.getTime()) {
+ String readableTime = String.format(Locale.ROOT, "%.3f",
(timer.getTime() / 1000));
+ log.warn(
+ "Resolving canonical hostname for local host took {} seconds,
possible DNS misconfiguration. Set the '{}' sysprop to false on startup to
prevent future lookups if DNS can not be fixed.",
+ readableTime,
+ REVERSE_DNS_OF_LOCALHOST_SYSPROP);
+ }
+ }
}
}
diff --git
a/solr/core/src/java/org/apache/solr/handler/admin/api/GetNodeSystemInfo.java
b/solr/core/src/java/org/apache/solr/handler/admin/api/GetNodeSystemInfo.java
new file mode 100644
index 00000000000..5885489f78e
--- /dev/null
+++
b/solr/core/src/java/org/apache/solr/handler/admin/api/GetNodeSystemInfo.java
@@ -0,0 +1,81 @@
+/*
+ * 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.api;
+
+import jakarta.inject.Inject;
+import java.lang.invoke.MethodHandles;
+import org.apache.solr.api.JerseyResource;
+import org.apache.solr.client.api.endpoint.NodeSystemInfoApi;
+import org.apache.solr.client.api.model.NodeSystemResponse;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.core.CoreContainer;
+import org.apache.solr.handler.admin.AdminHandlersProxy;
+import org.apache.solr.handler.admin.SystemInfoProvider;
+import org.apache.solr.jersey.PermissionName;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
+import org.apache.solr.security.PermissionNameProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/** Implementation for {@link NodeSystemInfoApi} */
+public class GetNodeSystemInfo extends JerseyResource implements
NodeSystemInfoApi {
+ private static final Logger log =
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ private final CoreContainer coreContainer;
+ private final SolrQueryRequest solrQueryRequest;
+ private final SolrQueryResponse solrQueryResponse;
+
+ @Inject
+ public GetNodeSystemInfo(SolrQueryRequest solrQueryRequest,
SolrQueryResponse solrQueryResponse) {
+ this.coreContainer = solrQueryRequest.getCoreContainer();
+ this.solrQueryRequest = solrQueryRequest;
+ this.solrQueryResponse = solrQueryResponse;
+ }
+
+ @Override
+ @PermissionName(PermissionNameProvider.Name.CONFIG_READ_PERM)
+ public NodeSystemResponse getNodeSystemInfo(String nodes) {
+ solrQueryResponse.setHttpCaching(false);
+
+ if (proxyToNodes()) {
+ return null; // Request handled via proxying
+ }
+
+ SystemInfoProvider provider = new SystemInfoProvider(solrQueryRequest);
+ NodeSystemResponse response =
instantiateJerseyResponse(NodeSystemResponse.class);
+ provider.getNodeSystemInfo(response);
+ if (log.isTraceEnabled()) {
+ log.trace("Node {}, core root: {}", response.node, response.coreRoot);
+ }
+ return response;
+ }
+
+ private boolean proxyToNodes() {
+ try {
+ if (coreContainer != null
+ && AdminHandlersProxy.maybeProxyToNodes(
+ "V2", solrQueryRequest, solrQueryResponse, coreContainer)) {
+ return true; // Request was proxied to other node
+ }
+ } catch (Exception e) {
+ throw new SolrException(
+ SolrException.ErrorCode.SERVER_ERROR, "Error occurred while proxying
to other node", e);
+ }
+ return false;
+ }
+}
diff --git
a/solr/core/src/java/org/apache/solr/handler/admin/api/NodeSystemInfoAPI.java
b/solr/core/src/java/org/apache/solr/handler/admin/api/NodeSystemInfoAPI.java
deleted file mode 100644
index d7df2cfa0cd..00000000000
---
a/solr/core/src/java/org/apache/solr/handler/admin/api/NodeSystemInfoAPI.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * 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.api;
-
-import static org.apache.solr.client.solrj.SolrRequest.METHOD.GET;
-import static
org.apache.solr.security.PermissionNameProvider.Name.CONFIG_READ_PERM;
-
-import org.apache.solr.api.EndPoint;
-import org.apache.solr.handler.admin.SystemInfoHandler;
-import org.apache.solr.request.SolrQueryRequest;
-import org.apache.solr.response.SolrQueryResponse;
-
-/**
- * V2 API for getting "system" information from the receiving node.
- *
- * <p>This includes current resource utilization, information about the
installation (location,
- * version, etc.), and JVM settings.
- *
- * <p>This API (GET /v2/node/system) is analogous to the v1 /admin/info/system.
- */
-public class NodeSystemInfoAPI {
- private final SystemInfoHandler handler;
-
- public NodeSystemInfoAPI(SystemInfoHandler handler) {
- this.handler = handler;
- }
-
- @EndPoint(
- path = {"/node/system"},
- method = GET,
- permission = CONFIG_READ_PERM)
- public void getSystemInformation(SolrQueryRequest req, SolrQueryResponse
rsp) throws Exception {
- handler.handleRequestBody(req, rsp);
- }
-}
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 013d3639e55..1076f7a3bd3 100644
--- a/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java
+++ b/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java
@@ -46,13 +46,11 @@ 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.SystemApi;
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;
@@ -141,18 +139,11 @@ public class RepositoryManager {
}
public void addKey(byte[] key, String destinationKeyFilename) throws
Exception {
- // get solr_home directory from info servlet
- // 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);
+ final var sysResponse = new
SystemApi.GetNodeSystemInfo().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(sysResponse.getSolrHome()));
+ PackageUtils.uploadKey(key, path, Path.of(sysResponse.solrHome));
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/handler/admin/NodeSystemInfoProviderTest.java
b/solr/core/src/test/org/apache/solr/handler/admin/NodeSystemInfoProviderTest.java
new file mode 100644
index 00000000000..13b3ee4ce3e
--- /dev/null
+++
b/solr/core/src/test/org/apache/solr/handler/admin/NodeSystemInfoProviderTest.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.handler.admin;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.OperatingSystemMXBean;
+import java.util.Arrays;
+import org.apache.lucene.util.Version;
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.api.model.NodeSystemResponse;
+import org.apache.solr.client.api.util.SolrVersion;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.util.SimpleOrderedMap;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.request.SolrQueryRequestBase;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+
+public class NodeSystemInfoProviderTest extends SolrTestCaseJ4 {
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ initCore("solrconfig-minimal.xml", "schema.xml");
+ }
+
+ public void testMagickGetter() {
+ OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
+
+ // make one directly
+ SimpleOrderedMap<Object> info = new SimpleOrderedMap<>();
+ info.add("name", os.getName());
+ info.add("version", os.getVersion());
+ info.add("arch", os.getArch());
+
+ // make another using MetricUtils.addMXBeanMetrics()
+ SimpleOrderedMap<Object> info2 = new SimpleOrderedMap<>();
+ SystemInfoProvider.forEachGetterValue(os, OperatingSystemMXBean.class,
info2::add);
+
+ // make sure they got the same thing
+ for (String p : Arrays.asList("name", "version", "arch")) {
+ assertEquals(info.get(p), info2.get(p));
+ }
+ }
+
+ public void testGetNodeSystemInfo() {
+ SolrQueryRequest req = new SolrQueryRequestBase(h.getCore(), new
ModifiableSolrParams()) {};
+ SystemInfoProvider provider = new SystemInfoProvider(req);
+ NodeSystemResponse info = provider.getNodeSystemInfo(new
NodeSystemResponse());
+
+ Assert.assertNotNull(info);
+ // these can be validated
+ Assert.assertEquals(h.getCoreContainer().getSolrHome().toString(),
info.solrHome);
+
Assert.assertEquals(h.getCoreContainer().getCoreRootDirectory().toString(),
info.coreRoot);
+ Assert.assertNotNull(info.lucene);
+ Assert.assertNotNull(info.lucene.solrImplVersion);
+ Assert.assertEquals(info.lucene.solrImplVersion,
SolrVersion.LATEST.getPrereleaseVersion());
+ Assert.assertNotNull(info.lucene.solrSpecVersion);
+ Assert.assertEquals(info.lucene.solrSpecVersion,
SolrVersion.LATEST_STRING);
+ Assert.assertNotNull(info.lucene.luceneImplVersion);
+ Assert.assertEquals(info.lucene.luceneImplVersion,
Version.getPackageImplementationVersion());
+ Assert.assertNotNull(info.lucene.luceneSpecVersion);
+ Assert.assertEquals(info.lucene.luceneSpecVersion,
Version.LATEST.toString());
+ // these should be set
+ Assert.assertNotNull(info.mode);
+ Assert.assertNotNull(info.jvm);
+ Assert.assertNotNull(info.security);
+ Assert.assertNotNull(info.system);
+ }
+}
diff --git
a/solr/core/src/test/org/apache/solr/handler/admin/SystemInfoHandlerTest.java
b/solr/core/src/test/org/apache/solr/handler/admin/SystemInfoHandlerTest.java
deleted file mode 100644
index 363de728439..00000000000
---
a/solr/core/src/test/org/apache/solr/handler/admin/SystemInfoHandlerTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * 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.lang.management.ManagementFactory;
-import java.lang.management.OperatingSystemMXBean;
-import java.util.Arrays;
-import org.apache.solr.SolrTestCase;
-import org.apache.solr.common.util.SimpleOrderedMap;
-
-public class SystemInfoHandlerTest extends SolrTestCase {
-
- public void testMagickGetter() {
-
- OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
-
- // make one directly
- SimpleOrderedMap<Object> info = new SimpleOrderedMap<>();
- info.add("name", os.getName());
- info.add("version", os.getVersion());
- info.add("arch", os.getArch());
-
- // make another using MetricUtils.addMXBeanMetrics()
- SimpleOrderedMap<Object> info2 = new SimpleOrderedMap<>();
- SystemInfoHandler.forEachGetterValue(os, OperatingSystemMXBean.class,
info2::add);
-
- // make sure they got the same thing
- for (String p : Arrays.asList("name", "version", "arch")) {
- assertEquals(info.get(p), info2.get(p));
- }
- }
-}
diff --git
a/solr/core/src/test/org/apache/solr/handler/admin/api/GetNodeSystemInfoTest.java
b/solr/core/src/test/org/apache/solr/handler/admin/api/GetNodeSystemInfoTest.java
new file mode 100644
index 00000000000..e6cf199b543
--- /dev/null
+++
b/solr/core/src/test/org/apache/solr/handler/admin/api/GetNodeSystemInfoTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.api;
+
+import static org.apache.solr.core.CoreContainer.ALLOW_PATHS_SYSPROP;
+
+import org.apache.lucene.util.Version;
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.client.solrj.request.SystemApi;
+import org.apache.solr.common.util.EnvUtils;
+import org.apache.solr.util.ExternalPaths;
+import org.apache.solr.util.SolrJettyTestRule;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+/** Test {@link GetNodeSystemInfo}. */
+public class GetNodeSystemInfoTest extends SolrTestCaseJ4 {
+
+ @ClassRule public static SolrJettyTestRule solrTestRule = new
SolrJettyTestRule();
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ EnvUtils.setProperty(
+ ALLOW_PATHS_SYSPROP,
ExternalPaths.SERVER_HOME.toAbsolutePath().toString());
+ solrTestRule.startSolr(createTempDir());
+ solrTestRule
+ .newCollection(DEFAULT_TEST_CORENAME)
+ .withConfigSet(ExternalPaths.DEFAULT_CONFIGSET)
+ .create();
+ }
+
+ @Test
+ public void testGetNodeInfoHttp() throws Exception {
+ final var req = new SystemApi.GetNodeSystemInfo();
+
+ final var infoRsp = req.process(solrTestRule.getSolrClient(null));
+
+ // Test a few values, majority of field-level validation occurs in
NodeSystemInfoProviderTest
+ assertEquals(0, infoRsp.responseHeader.status);
+ assertEquals("std", infoRsp.mode);
+ assertEquals(Version.LATEST.toString(), infoRsp.lucene.luceneSpecVersion);
+ }
+}
diff --git
a/solr/core/src/test/org/apache/solr/handler/admin/api/V2NodeAPIMappingTest.java
b/solr/core/src/test/org/apache/solr/handler/admin/api/V2NodeAPIMappingTest.java
index c0ca1bff0c0..1e7dc2c43e7 100644
---
a/solr/core/src/test/org/apache/solr/handler/admin/api/V2NodeAPIMappingTest.java
+++
b/solr/core/src/test/org/apache/solr/handler/admin/api/V2NodeAPIMappingTest.java
@@ -39,7 +39,6 @@ import org.apache.solr.handler.admin.HealthCheckHandler;
import org.apache.solr.handler.admin.InfoHandler;
import org.apache.solr.handler.admin.LoggingHandler;
import org.apache.solr.handler.admin.PropertiesRequestHandler;
-import org.apache.solr.handler.admin.SystemInfoHandler;
import org.apache.solr.handler.admin.ThreadDumpHandler;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrQueryRequestBase;
@@ -55,7 +54,6 @@ public class V2NodeAPIMappingTest extends SolrTestCaseJ4 {
private ArgumentCaptor<SolrQueryRequest> queryRequestCaptor;
private CoreAdminHandler mockCoresHandler;
private InfoHandler infoHandler;
- private SystemInfoHandler mockSystemInfoHandler;
private LoggingHandler mockLoggingHandler;
private PropertiesRequestHandler mockPropertiesHandler;
private HealthCheckHandler mockHealthCheckHandler;
@@ -70,14 +68,12 @@ public class V2NodeAPIMappingTest extends SolrTestCaseJ4 {
public void setupApiBag() {
mockCoresHandler = mock(CoreAdminHandler.class);
infoHandler = mock(InfoHandler.class);
- mockSystemInfoHandler = mock(SystemInfoHandler.class);
mockLoggingHandler = mock(LoggingHandler.class);
mockPropertiesHandler = mock(PropertiesRequestHandler.class);
mockHealthCheckHandler = mock(HealthCheckHandler.class);
mockThreadDumpHandler = mock(ThreadDumpHandler.class);
queryRequestCaptor = ArgumentCaptor.forClass(SolrQueryRequest.class);
- when(infoHandler.getSystemInfoHandler()).thenReturn(mockSystemInfoHandler);
when(infoHandler.getLoggingHandler()).thenReturn(mockLoggingHandler);
when(infoHandler.getPropertiesHandler()).thenReturn(mockPropertiesHandler);
when(infoHandler.getHealthCheckHandler()).thenReturn(mockHealthCheckHandler);
@@ -146,16 +142,6 @@ public class V2NodeAPIMappingTest extends SolrTestCaseJ4 {
assertEquals("anyParamValue", v1Params.get("anyParamName"));
}
- @Test
- public void testSystemInfoApiAllProperties() throws Exception {
- final ModifiableSolrParams solrParams = new ModifiableSolrParams();
- solrParams.add("anyParamName", "anyParamValue");
- final SolrParams v1Params = captureConvertedSystemV1Params("/node/system",
"GET", solrParams);
-
- // All parameters are passed through to v1 API as-is.
- assertEquals("anyParamValue", v1Params.get("anyParamName"));
- }
-
@Test
public void testHealthCheckApiAllProperties() throws Exception {
final ModifiableSolrParams solrParams = new ModifiableSolrParams();
@@ -175,11 +161,6 @@ public class V2NodeAPIMappingTest extends SolrTestCaseJ4 {
path, method, new ModifiableSolrParams(), v2RequestBody,
mockCoresHandler);
}
- private SolrParams captureConvertedSystemV1Params(
- String path, String method, SolrParams inputParams) throws Exception {
- return doCaptureParams(path, method, inputParams, null,
mockSystemInfoHandler);
- }
-
private SolrParams captureConvertedPropertiesV1Params(
String path, String method, SolrParams inputParams) throws Exception {
return doCaptureParams(path, method, inputParams, null,
mockPropertiesHandler);
@@ -232,7 +213,6 @@ public class V2NodeAPIMappingTest extends SolrTestCaseJ4 {
apiBag.registerObject(new RejoinLeaderElectionAPI(coreHandler));
apiBag.registerObject(new
NodePropertiesAPI(infoHandler.getPropertiesHandler()));
apiBag.registerObject(new
NodeThreadsAPI(infoHandler.getThreadDumpHandler()));
- apiBag.registerObject(new
NodeSystemInfoAPI(infoHandler.getSystemInfoHandler()));
apiBag.registerObject(new
NodeHealthAPI(infoHandler.getHealthCheckHandler()));
}
}
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 6d55650a948..5fe1359e2e7 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,17 +18,50 @@
This API provides the same information displayed on the Dashboard.
-System information is available via:
+== Request
+"System"-level information for individual nodes can be fetched with the API
below:
+
+[tabs#systeminformation]
+======
+V1 API::
++
+====
[source,bash]
----
http://localhost:8983/solr/admin/info/system
----
+====
+
+V2 API::
++
+====
+[source,bash]
+----
+http://localhost:8983/api/node/system
+----
+====
+======
+
+
+== Response
The keys in the result are:
`mode`::
-Either `solrcloud` or `std`, indicating the mode Solr is running in
+Either `solrcloud` or `std`, indicating the mode Solr is running in standalone
mode.
+
+`solr_home`::
+Solr base directory.
+
+`core_root`::
+Solr core base directory.
+
+`zkHost`::
+Zookeeper host, when running in cloud mode.
+
+`node`::
+Node name, when running cloud mode.
`lucene`::
An object containing Solr and Lucene version information
@@ -39,18 +72,15 @@ An object containing information on the JVM
`system`::
Information on the system.
-`solr_home`::
-Solr base directory. Only available under `/solr/admin/info/system`.
+`security`::
+Information on security.
-`zkHost`::
-Zookeeper host, when running in cloud mode.
-
-`node`::
-Node name, when running cloud mode.
+`gpu`::
+Information on GPUs.
-== Lucene and Solr Information Object
+=== Lucene and Solr Versions Information Object
-The `solr` key in the response is an object with these keys:
+The `lucene` key in the response is an object with these keys:
`lucene-spec-version`::
The specification version of the Lucene package.
@@ -64,7 +94,7 @@ The specification version of the Solr package.
`solr-impl-version`::
The implementation version of the Solr package.
-== JVM Information Object
+=== JVM Information Object
The `jvm` key in the response is an object with these keys and more:
@@ -77,9 +107,9 @@ Name of the JVM.
`memory`::
An object containing memory usage information.
-== System Information Object
+=== System Information Object
-The `system` key in the response is an object with these keys and more:
+The `system` key in the response is a map of the underlying system
information, containing these keys, and more:
`name`::
Operating system name.
@@ -90,170 +120,98 @@ The result of running `uname -a`. Not available on
Windows.
`uptime`::
The result of running `uptime`. Not available on Windows.
-== System Information API Examples
+=== Security Information Object
-Retrieve system information from a node in cloud mode.
+The `security` key in the response is an object with these keys:
-[source.bash]
-----
-curl http://localhost:8983/solr/admin/info/system
-----
+`tls`::
+Flag to indicate if TLS is enabled or not. If disabled, this is the only key
in the response.
-[source.json]
-----
-{
- "responseHeader":{
- "status":0,
- "QTime":13},
- "mode":"solrcloud",
- "host":"localhost",
- "zkHost":"192.168.32.3:2181",
- "solr_home":"/var/solr/data",
- "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":"396 MB",
- "total":"512 MB",
- "max":"512 MB",
- "used":"116 MB (%22.7)",
- "raw":{
- "free":415213560,
- "total":536870912,
- "max":536870912,
- "used":121657352,
- "used%":22.660447657108307}},
- "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",
- "-DzkClientTimeout=15000",
- "-DzkHost=192.168.32.3:2181",
- "-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-18T11:16:00.769Z",
- "upTimeMS":1339007}},
- "system":{
- "name":"Linux",
- "arch":"amd64",
- "availableProcessors":4,
- "systemLoadAverage":0.92,
- "version":"4.9.0-9-amd64",
- "committedVirtualMemorySize":4317540352,
- "freePhysicalMemorySize":117563392,
- "freeSwapSpaceSize":11583721472,
- "processCpuLoad":0.0,
- "processCpuTime":42690000000,
- "systemCpuLoad":0.0,
- "totalPhysicalMemorySize":4005376000,
- "totalSwapSpaceSize":12884897792,
- "maxFileDescriptorCount":1048576,
- "openFileDescriptorCount":225,
- "uname":"Linux f0281c6ee880 4.9.0-9-amd64 #1 SMP Debian 4.9.168-1+deb9u3
(2019-06-16) x86_64 GNU/Linux\n",
- "uptime":" 11:38:19 up 28 days, 22:41, 0 users, load average: 0.92,
0.57, 0.51\n"},
- "node":"172.17.0.4:8983_solr"}
-----
+`authenticationPlugin`::
+The name of the configured authentication plugin.
+
+`authorizationPlugin`::
+The name of the configured authorization plugin.
+
+`username`::
+The name of the current user.
+
+`roles`::
+The roles of the current user.
+
+`permissions`::
+The permissions of the current user.
+
+=== GPU Information Object
+
+The `gpu` key in the response is an object with these keys:
+
+`available`::
+Flag to indicate if GPU is available or not. If unavailable, this is the only
key in the response.
+
+`count`::
+Count of available GPUs.
+
+`memory`::
+An object listing the 'free', 'total', and 'used' memory.
+
+`devices`::
+A listing of the GPU devices.
+
+== Examples
+
+Examples on this page refer to the V2 API.
+
+=== Retrieve system information from a node in cloud mode.
-Retrieve system information from a core, without cloud mode.
[source.bash]
----
-curl http://localhost:8983/solr/gettingstarted/admin/system
+curl http://localhost:8983/api/node/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",
+ "responseHeader": {
+ "status": 0,
+ "QTime": 4
+ },
+ "node": "localhost:8983_solr",
+ "mode": "solrcloud",
+ "zkHost": "127.0.0.1:9983",
+ "solr_home": "/opt/solr/example/cloud/node1/solr",
+ "core_root": "/opt/solr/example/cloud/node1/solr",
+ "lucene": {
+ "solr-spec-version": "11.0.0",
+ "solr-impl-version": "11.0.0-SNAPSHOT
f096b9a8aa2e10b8d2e87d7b8699953544d0f4f6 [snapshot build, details omitted]",
+ "lucene-spec-version": "10.3.2",
+ "lucene-impl-version": "10.3.2 dadfd90b4401947f4d0387669dc94999fbb2c830 -
2025-11-13 10:41:29"
+ },
+ "jvm": {
+ "name": "Ubuntu OpenJDK 64-Bit Server VM",
+ "version": "21.0.9 21.0.9+10-Ubuntu-124.04",
+ "processors": 4,
+ "jre": {
+ "vendor": "Ubuntu",
+ "version": "21.0.9"
+ },
+ "spec": {
+ "name": "Java Platform API Specification",
+ "vendor": "Oracle Corporation",
+ "version": "21"
+ },
+ "vm": {
+ "name": "OpenJDK 64-Bit Server VM",
+ "vendor": "Ubuntu",
+ "version": "21.0.9+10-Ubuntu-124.04"
+ },
+ "jmx": {
+ "classpath": "start.jar",
+ "startTime": 1771355675708,
+ "upTimeMS": 1695023,
+ "commandLineArgs": [
+ "-Xms512m",
"-Xmx512m",
"-XX:+UseG1GC",
"-XX:+PerfDisableSharedMem",
@@ -261,44 +219,77 @@ curl
http://localhost:8983/solr/gettingstarted/admin/system
"-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",
+ "-XX:+ExplicitGCInvokesConcurrent",
+
"-Xlog:gc*:file=/opt/solr/../logs/solr_gc.log:time,uptime:filecount=9,filesize=20M",
+ "-Dsolr.jetty.inetaccess.includes=",
+ "-Dsolr.jetty.inetaccess.excludes=",
+ "-Dsolr.zookeeper.client.timeout=30000",
+ "-Dsolr.zookeeper.server.enabled=true",
+ "-Dsolr.logs.dir=/opt/solr/../logs",
"-Dsolr.port.listen=8983",
"-DSTOP.PORT=7983",
"-DSTOP.KEY=solrrocks",
+ "-Djava.io.tmpdir=/tmp",
+ "-Dsolr.host.advertise=localhost",
"-Duser.timezone=UTC",
+ "-XX:-OmitStackTraceInFastThrow",
+ "-XX:+CrashOnOutOfMemoryError",
+ "-XX:ErrorFile=/opt/solr/../logs/jvm_crash_%p.log",
"-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",
+ "-Dsolr.solr.home=/opt/solr/example/cloud/node1/solr",
+ "-Dsolr.install.dir=/opt/solr/",
+ "-Dsolr.install.symDir=/opt/solr/",
+ "-Dlog4j.configurationFile=/opt/solr/server/resources/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"}}
+ "--add-modules=jdk.incubator.vector",
+ "--enable-native-access=ALL-UNNAMED",
+ "-Djava.security.manager",
+ "-Djava.security.policy=/opt/solr/server/etc/security.policy",
+ "-Djava.security.properties=/opt/solr/server/etc/security.properties",
+ "-Dsolr.internal.network.permission=*",
+ "-Dsolr.log.muteconsole"
+ ]
+ "memory": {
+ "free": "229.5 MB",
+ "total": "512 MB",
+ "max": "512 MB",
+ "used": "282.5 MB (%55.2)",
+ "raw": {
+ "free": 240673856,
+ "total": 536870912,
+ "used": 296197056,
+ "max": 536870912,
+ "used%": 55.171000957489014
+ }
+ }
+ },
+ "security": {
+ "tls": false
+ },
+ "gpu": {
+ "available": false,
+ "count": 0
+ },
+ "system": {
+ "freePhysicalMemorySize": "2985586688",
+ "totalMemorySize": "8307912704",
+ "availableProcessors": "4",
+ "freeMemorySize": "2985586688",
+ "openFileDescriptorCount": "196",
+ "freeSwapSpaceSize": "2660519936",
+ "maxFileDescriptorCount": "65536",
+ "version": "6.14.0-33-generic",
+ "totalSwapSpaceSize": "4294963200",
+ "committedVirtualMemorySize": "4357632000",
+ "cpuLoad": "0.06624527740181138",
+ "systemLoadAverage": "0.3193359375",
+ "processCpuLoad": "0.004622084725943523",
+ "systemCpuLoad": "0.0",
+ "processCpuTime": "43450000000",
+ "name": "Linux",
+ "totalPhysicalMemorySize": "8307912704",
+ "arch": "amd64"
+ }
+ }
+}
----
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
index 345c0650256..08a9dd0c107 100644
---
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
@@ -32,13 +32,12 @@ public class SystemInfoRequest extends
SolrRequest<SystemInfoResponse> {
/** 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"
+ * @param path the HTTP path to use for this request. Defaults to the v1
path,
+ * "/admin/info/system"
*/
public SystemInfoRequest(String path) {
this(path, new ModifiableSolrParams());
@@ -52,8 +51,8 @@ public class SystemInfoRequest extends
SolrRequest<SystemInfoResponse> {
}
/**
- * @param path the HTTP path to use for this request. Supports V1
"/admin/info/system" (default)
- * or V2 "/node/system"
+ * @param path the HTTP path to use for this request. Defaults to the v1
path,
+ * "/admin/info/system"
* @param params query parameter names and values for making this request.
*/
public SystemInfoRequest(String path, SolrParams params) {
@@ -70,14 +69,4 @@ public class SystemInfoRequest extends
SolrRequest<SystemInfoResponse> {
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
index 71274bfbf90..18cd0a0a9d5 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
@@ -30,7 +30,9 @@ public class SystemInfoResponse extends SolrResponseBase {
private static final long serialVersionUID = 1L;
- private final Map<String, NodeSystemResponse> nodesInfo = new HashMap<>();
+ // AdminHandlersProxy wraps nodes responses in a map.
+ // Mimic that here, even if the response might be just a single node.
+ protected final Map<String, NodeSystemResponse> nodesInfo = new HashMap<>();
public SystemInfoResponse(NamedList<Object> namedList) {
if (namedList == null) throw new IllegalArgumentException("Null NamedList
is not allowed.");
@@ -41,19 +43,24 @@ public class SystemInfoResponse extends SolrResponseBase {
public void setResponse(NamedList<Object> response) {
if (getResponse() == null) {
super.setResponse(response);
+ parseResponse(response);
} else {
assert response.equals(getResponse());
return;
}
+ }
- if (getResponse().get("node") == null) {
- // multi-nodes response, NamedList of
"host:port_solr"->NodeSystemResponse
+ /** Parse the V1 response */
+ @SuppressWarnings("unchecked")
+ protected void parseResponse(NamedList<Object> response) {
+ if (response.get("node") == null) {
+ // multi-nodes response, NamedList of "host:port_solr"->
NodeSystemResponse
for (Entry<String, Object> node : response) {
if (node.getKey().endsWith("_solr")) {
nodesInfo.put(
node.getKey(),
JacksonContentWriter.DEFAULT_MAPPER.convertValue(
- node.getValue(), NodeSystemResponse.class));
+ removeHeader((NamedList<Object>) node.getValue()),
NodeSystemResponse.class));
}
}
@@ -62,7 +69,8 @@ public class SystemInfoResponse extends SolrResponseBase {
if (nodesInfo.isEmpty()) {
nodesInfo.put(
null,
- JacksonContentWriter.DEFAULT_MAPPER.convertValue(response,
NodeSystemResponse.class));
+ JacksonContentWriter.DEFAULT_MAPPER.convertValue(
+ removeHeader(response), NodeSystemResponse.class));
}
} else {
@@ -70,10 +78,15 @@ public class SystemInfoResponse extends SolrResponseBase {
nodesInfo.put(
response.get("node").toString(),
JacksonContentWriter.DEFAULT_MAPPER.convertValue(
- getResponse(), NodeSystemResponse.class));
+ removeHeader(response), NodeSystemResponse.class));
}
}
+ private NamedList<Object> removeHeader(NamedList<Object> value) {
+ value.remove("responseHeader");
+ return value;
+ }
+
/** Get the mode from a single node system info */
public String getMode() {
if (nodesInfo.size() == 1) {
@@ -217,7 +230,7 @@ public class SystemInfoResponse extends SolrResponseBase {
.get();
}
- /** Get the {@code NodeSystemResponse} for a single node */
+ /** Get the {@code NodeSystemResponse.NodeSystemInfo} for a single node */
public NodeSystemResponse getNodeResponse() {
if (nodesInfo.size() == 1) {
return nodesInfo.values().stream().findFirst().get();
@@ -232,8 +245,12 @@ public class SystemInfoResponse extends SolrResponseBase {
return nodesInfo;
}
- /** Get the {@code NodeSystemResponse} for the given node name */
+ /** Get the {@code NodeSystemResponse.NodeSystemInfo} for the given node
name */
public NodeSystemResponse getNodeResponseForNode(String node) {
+ // in standalone mode, the key in the map is null
+ if (node == null && nodesInfo.size() == 1) {
+ return nodesInfo.values().stream().findFirst().get();
+ }
return nodesInfo.get(node);
}
diff --git
a/solr/solrj/src/java/org/apache/solr/client/solrj/response/json/JacksonDataBindResponseParser.java
b/solr/solrj/src/java/org/apache/solr/client/solrj/response/json/JacksonDataBindResponseParser.java
index 954db55f10c..e98eb104cae 100644
---
a/solr/solrj/src/java/org/apache/solr/client/solrj/response/json/JacksonDataBindResponseParser.java
+++
b/solr/solrj/src/java/org/apache/solr/client/solrj/response/json/JacksonDataBindResponseParser.java
@@ -55,6 +55,9 @@ public class JacksonDataBindResponseParser<T> extends
ResponseParser {
// TODO it'd be nice if the ResponseParser could receive the mime type so it
can parse
// accordingly, maybe json, cbor, smile
+ /**
+ * Parse the Json {@code stream} to the expected Java type, then, converts
to a {@link NamedList}.
+ */
@Override
public NamedList<Object> processResponse(InputStream stream, String
encoding) throws IOException {
// TODO generalize to CBOR, Smile, ...
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 b26360864c5..052d0104bff 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,7 +205,6 @@ 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/response/SystemInfoResponseTest.java
b/solr/solrj/src/test/org/apache/solr/client/solrj/response/SystemInfoResponseTest.java
index f129d63f10e..05e8d319370 100644
---
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
@@ -30,6 +30,7 @@ import org.junit.Test;
public class SystemInfoResponseTest extends SolrCloudTestCase {
+ // private static MiniSolrCloudCluster cluster;
private CloudSolrClient solrClient;
@BeforeClass
@@ -44,6 +45,16 @@ public class SystemInfoResponseTest extends
SolrCloudTestCase {
solrClient = cluster.getSolrClient();
}
+ @Test
+ public void testDefaultResponse() throws SolrServerException, IOException {
+ SystemInfoRequest req = new SystemInfoRequest();
+ SystemInfoResponse rsp = req.process(solrClient);
+
+ Assert.assertEquals(1, rsp.getAllNodeResponses().size());
+ Assert.assertEquals(1, rsp.getAllCoreRoots().size());
+ Assert.assertEquals(1, rsp.getAllModes().size());
+ }
+
@Test
public void testAllNodesResponse() throws SolrServerException, IOException {
MapSolrParams params = new MapSolrParams(Map.of("nodes", "all"));
@@ -61,20 +72,29 @@ public class SystemInfoResponseTest extends
SolrCloudTestCase {
Assert.assertEquals(2, rsp.getAllNodeResponses().size());
Assert.assertEquals(2, rsp.getAllCoreRoots().size());
Assert.assertEquals(2, rsp.getAllModes().size());
+
+ 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));
+ }
}
@Test
public void testResponseForGivenNode() throws SolrServerException,
IOException {
- MapSolrParams params = new MapSolrParams(Map.of("nodes", "all"));
+ String queryNode = cluster.getJettySolrRunner(0).getNodeName();
+ MapSolrParams params = new MapSolrParams(Map.of("nodes", queryNode));
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));
- }
+ Assert.assertEquals(1, rsp.getAllNodeResponses().size());
+ Assert.assertEquals(1, rsp.getAllCoreRoots().size());
+ Assert.assertEquals(1, rsp.getAllModes().size());
+ String coreRoot = rsp.getCoreRootForNode(queryNode);
+ Assert.assertEquals(queryNode, rsp.getNodeForCoreRoot(coreRoot));
+ String solrHome = rsp.getCoreRootForNode(queryNode);
+ Assert.assertEquals(queryNode, rsp.getNodeForSolrHome(solrHome));
}
}