Skip to content

Commit 730398a

Browse files
authored
SOLR-16738: Refactor AdminHandlersProxy for better extensibility (apache#3991)
Replaces the static AdminHandlersProxy utility with an OOP hierarchy under a new 'proxy' package. RemoteRequestProxy provides the core proxying logic; GenericV1RequestProxy and V2SolrRequestBasedProxy handle v1 and v2 requests respectively. Callers can now customize per-endpoint behaviour (response handling, param names, request construction) via subclassing rather than branching in a single class. Also adds WrappedSolrRequest, a delegating SolrRequest decorator used by V2SolrRequestBasedProxy to strip internal params before proxying.
1 parent 03dabef commit 730398a

16 files changed

Lines changed: 1086 additions & 281 deletions

File tree

solr/api/src/java/org/apache/solr/client/api/model/NodeSystemResponse.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
*/
1717
package org.apache.solr.client.api.model;
1818

19+
import com.fasterxml.jackson.annotation.JsonAnyGetter;
20+
import com.fasterxml.jackson.annotation.JsonAnySetter;
1921
import com.fasterxml.jackson.annotation.JsonProperty;
2022
import java.util.Date;
2123
import java.util.List;
@@ -25,6 +27,20 @@
2527
/** Response from /node/system */
2628
public class NodeSystemResponse extends SolrJerseyResponse {
2729

30+
// TODO The typing here is kindof wonky - can I tighten 'Object' here to be NodeSystemResponse or
31+
// will Jackson choke on that?
32+
public Map<String, Object> remoteNodeData;
33+
34+
@JsonAnyGetter
35+
public Map<String, Object> remoteNodeData() {
36+
return remoteNodeData;
37+
}
38+
39+
@JsonAnySetter
40+
public void setRemoteNodeResponse(String field, Object value) {
41+
remoteNodeData.put(field, value);
42+
}
43+
2844
@JsonProperty public String host;
2945
@JsonProperty public String node;
3046
@JsonProperty public String mode;

solr/core/src/java/org/apache/solr/handler/admin/AdminHandlersProxy.java

Lines changed: 0 additions & 261 deletions
This file was deleted.

solr/core/src/java/org/apache/solr/handler/admin/LoggingHandler.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.apache.solr.core.CoreContainer;
3232
import org.apache.solr.handler.RequestHandlerBase;
3333
import org.apache.solr.handler.admin.api.NodeLogging;
34+
import org.apache.solr.handler.admin.proxy.GenericV1RequestProxy;
3435
import org.apache.solr.handler.api.V2ApiUtils;
3536
import org.apache.solr.logging.LogWatcher;
3637
import org.apache.solr.request.SolrQueryRequest;
@@ -91,9 +92,7 @@ public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throw
9192
}
9293

9394
rsp.setHttpCaching(false);
94-
if (cc != null && AdminHandlersProxy.maybeProxyToNodes(req, rsp, cc)) {
95-
return; // Request was proxied to other node
96-
}
95+
new GenericV1RequestProxy(cc, req, rsp).proxyRequest();
9796
}
9897

9998
private void squashV2Response(SolrQueryResponse rsp, LoggingResponse response) {

solr/core/src/java/org/apache/solr/handler/admin/MetricsHandler.java

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
package org.apache.solr.handler.admin;
1919

20+
import static org.apache.solr.common.params.CommonParams.METRICS_PATH;
21+
2022
import io.prometheus.metrics.model.snapshots.MetricSnapshot;
2123
import io.prometheus.metrics.model.snapshots.MetricSnapshots;
2224
import java.util.ArrayList;
@@ -26,12 +28,17 @@
2628
import java.util.SortedMap;
2729
import java.util.function.BiConsumer;
2830
import org.apache.solr.api.JerseyResource;
31+
import org.apache.solr.client.solrj.SolrRequest;
32+
import org.apache.solr.client.solrj.response.InputStreamResponseParser;
2933
import org.apache.solr.common.SolrException;
3034
import org.apache.solr.common.params.CommonParams;
3135
import org.apache.solr.common.params.SolrParams;
36+
import org.apache.solr.common.util.NamedList;
3237
import org.apache.solr.core.CoreContainer;
3338
import org.apache.solr.handler.RequestHandlerBase;
3439
import org.apache.solr.handler.admin.api.GetMetrics;
40+
import org.apache.solr.handler.admin.proxy.GenericV1RequestProxy;
41+
import org.apache.solr.handler.admin.proxy.RemoteRequestProxy;
3542
import org.apache.solr.metrics.SolrMetricManager;
3643
import org.apache.solr.metrics.otel.FilterablePrometheusMetricReader;
3744
import org.apache.solr.request.SolrQueryRequest;
@@ -101,9 +108,12 @@ public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throw
101108
+ format);
102109
}
103110

104-
if (cc != null && AdminHandlersProxy.maybeProxyToNodes(req, rsp, cc)) {
111+
final var reqProxy = createMetricProxy(cc, req, rsp);
112+
if (cc != null && reqProxy.shouldProxy()) {
113+
reqProxy.proxyRequest();
105114
return; // Request was proxied to other node
106115
}
116+
107117
SolrRequestInfo.setRequestInfo(new SolrRequestInfo(req, rsp));
108118
try {
109119
handleRequest(req.getParams(), (k, v) -> rsp.add(k, v));
@@ -143,6 +153,37 @@ public void handleRequest(SolrParams params, BiConsumer<String, Object> consumer
143153
consumer.accept("metrics", mergedSnapshots);
144154
}
145155

156+
public static RemoteRequestProxy createMetricProxy(
157+
CoreContainer cc, SolrQueryRequest req, SolrQueryResponse rsp) {
158+
return new GenericV1RequestProxy(cc, req, rsp) {
159+
160+
// Metric requests use 'node' to proxy rather than the generally accepted "nodes"
161+
@Override
162+
protected String getDestinationNodeParamName() {
163+
return "node";
164+
}
165+
166+
// Metrics requests require a particular ResponseParser
167+
@Override
168+
protected SolrRequest<?> createGenericRequest(String apiPath, SolrParams params) {
169+
final var toProxy = super.createGenericRequest(apiPath, params);
170+
// Metrics proxy might be called from either v1 or v2, but end up proxying to v1 for
171+
// simplicity
172+
toProxy.setPath(METRICS_PATH);
173+
String wt = params.get(CommonParams.WT, MetricUtils.PROMETHEUS_METRICS_WT);
174+
toProxy.setResponseParser(new InputStreamResponseParser(wt));
175+
176+
return toProxy;
177+
}
178+
179+
// Metrics requests only proxy to single host, so proxied response is added at root level
180+
@Override
181+
public void processProxiedResponse(String nodeName, NamedList<Object> proxiedResponse) {
182+
rsp.getValues().addAll(proxiedResponse);
183+
}
184+
};
185+
}
186+
146187
@Override
147188
public String getDescription() {
148189
return "A handler to return all the metrics gathered by Solr";

0 commit comments

Comments
 (0)