diff --git a/solr/core/src/java/org/apache/solr/handler/admin/LoggingHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/LoggingHandler.java
index 7593bb7cbdd..4d93ff60b1a 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/LoggingHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/LoggingHandler.java
@@ -31,6 +31,7 @@
import org.apache.solr.core.CoreContainer;
import org.apache.solr.handler.RequestHandlerBase;
import org.apache.solr.handler.admin.api.NodeLogging;
+import org.apache.solr.handler.admin.proxy.AdminHandlersProxy;
import org.apache.solr.handler.api.V2ApiUtils;
import org.apache.solr.logging.LogWatcher;
import org.apache.solr.request.SolrQueryRequest;
@@ -91,8 +92,11 @@ public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throw
}
rsp.setHttpCaching(false);
- if (cc != null && AdminHandlersProxy.maybeProxyToNodes(req, rsp, cc)) {
- return; // Request was proxied to other node
+ if (cc != null) {
+ final var adminProxy = AdminHandlersProxy.create(cc, req, rsp);
+ if (adminProxy.shouldProxy()) {
+ adminProxy.proxyRequest();
+ }
}
}
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java
index 13b4d044c7e..5218f53da88 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java
@@ -39,6 +39,7 @@
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.handler.RequestHandlerBase;
+import org.apache.solr.handler.admin.proxy.AdminHandlersProxy;
import org.apache.solr.metrics.SolrMetricManager;
import org.apache.solr.metrics.otel.FilterablePrometheusMetricReader;
import org.apache.solr.request.SolrQueryRequest;
@@ -122,8 +123,12 @@ public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throw
+ format);
}
- if (cc != null && AdminHandlersProxy.maybeProxyToNodes(req, rsp, cc)) {
- return; // Request was proxied to other node
+ if (cc != null) {
+ final var adminProxy = AdminHandlersProxy.create(cc, req, rsp);
+ if (adminProxy.shouldProxy()) {
+ adminProxy.proxyRequest();
+ return;
+ }
}
SolrRequestInfo.setRequestInfo(new SolrRequestInfo(req, rsp));
try {
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 16e78ab4268..e635e5b6b16 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
@@ -55,6 +55,7 @@
import org.apache.solr.core.SolrCore;
import org.apache.solr.handler.RequestHandlerBase;
import org.apache.solr.handler.admin.api.NodeSystemInfoAPI;
+import org.apache.solr.handler.admin.proxy.AdminHandlersProxy;
import org.apache.solr.metrics.GpuMetricsProvider;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
@@ -220,8 +221,10 @@ private void initHostname() {
public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {
rsp.setHttpCaching(false);
SolrCore core = req.getCore();
- if (AdminHandlersProxy.maybeProxyToNodes(req, rsp, getCoreContainer(req))) {
- return; // Request was proxied to other node
+ final var adminProxy = AdminHandlersProxy.create(getCoreContainer(req), req, rsp);
+ if (adminProxy.shouldProxy()) {
+ adminProxy.proxyRequest();
+ return;
}
if (core != null) rsp.add("core", getCoreInfo(core, req.getSchema()));
boolean solrCloudMode = getCoreContainer(req).isZooKeeperAware();
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlersProxy.java b/solr/core/src/java/org/apache/solr/handler/admin/proxy/AdminHandlersProxy.java
similarity index 52%
rename from solr/core/src/java/org/apache/solr/handler/admin/AdminHandlersProxy.java
rename to solr/core/src/java/org/apache/solr/handler/admin/proxy/AdminHandlersProxy.java
index 5f253c4ec4e..6e5ef805be2 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/AdminHandlersProxy.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/proxy/AdminHandlersProxy.java
@@ -15,12 +15,15 @@
* limitations under the License.
*/
-package org.apache.solr.handler.admin;
+package org.apache.solr.handler.admin.proxy;
+
+import static org.apache.solr.common.params.CommonParams.WT;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.net.URI;
import java.util.Arrays;
+import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -33,10 +36,7 @@
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.request.GenericSolrRequest;
-import org.apache.solr.client.solrj.response.InputStreamResponseParser;
-import org.apache.solr.cloud.ZkController;
import org.apache.solr.common.SolrException;
-import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.CoreContainer;
@@ -49,65 +49,55 @@
* Static methods to proxy calls to an Admin (GET) API to other nodes in the cluster and return a
* combined response
*/
-public class AdminHandlersProxy {
+public abstract class AdminHandlersProxy {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
- private static final String PARAM_NODES = "nodes";
- private static final String PARAM_NODE = "node";
+ protected static final String PARAM_NODES = "nodes";
+ // TODO Move to NormalV1RequestProxy if not used elsewhere when finished
+ protected static final String PARAM_NODE = "node";
+ // TODO Move to PrometheusRequestProxy if not used elsewhere when finished
private static final long PROMETHEUS_FETCH_TIMEOUT_SECONDS = 10;
- /** Proxy this request to a different remote node if 'node' or 'nodes' parameter is provided */
- public static boolean maybeProxyToNodes(
- SolrQueryRequest req, SolrQueryResponse rsp, CoreContainer container)
- throws IOException, SolrServerException, InterruptedException {
+ protected final CoreContainer
+ coreContainer; // TODO reduce this to just ZkStateReader or something similar
+ protected final SolrQueryRequest req;
- String pathStr = req.getPath();
- ModifiableSolrParams params = new ModifiableSolrParams(req.getParams());
+ public AdminHandlersProxy(CoreContainer coreContainer, SolrQueryRequest req) {
+ this.coreContainer = coreContainer;
+ this.req = req;
+ }
- // Check if response format is Prometheus/OpenMetrics
- String wt = params.get("wt");
- boolean isPrometheusFormat = "prometheus".equals(wt) || "openmetrics".equals(wt);
+ public abstract boolean shouldProxy();
- if (isPrometheusFormat) {
- // Prometheus format: use singular 'node' parameter for single-node proxy
- String nodeName = req.getParams().get(PARAM_NODE);
- if (nodeName == null || nodeName.isEmpty()) {
- return false; // No node parameter, handle locally
- }
+ /**
+ * TODO fill in these javadocs
+ *
+ *
Only called if 'shouldProxy()' returns true
+ */
+ public abstract Collection getDestinationNodes();
- params.remove(PARAM_NODE);
- handlePrometheusSingleNode(nodeName, pathStr, params, container, rsp);
- } else {
- // Other formats (JSON/XML): use plural 'nodes' parameter for multi-node aggregation
- String nodeNames = req.getParams().get(PARAM_NODES);
- if (nodeNames == null || nodeNames.isEmpty()) {
- return false; // No nodes parameter, handle locally
- }
+ public abstract SolrRequest> prepareProxiedRequest();
- params.remove(PARAM_NODES);
- Set nodes = resolveNodes(nodeNames, container);
- handleNamedListFormat(nodes, pathStr, params, container.getZkController(), rsp);
+ public abstract void processProxiedResponse(String nodeName, NamedList