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 417e5c1 SOLR-15747: Convert /node v2 APIs to annotations (#433)
417e5c1 is described below
commit 417e5c187f5072def6f159e16cc27a24bd6f08f7
Author: Jason Gerlowski <[email protected]>
AuthorDate: Sun Dec 5 21:25:23 2021 -0500
SOLR-15747: Convert /node v2 APIs to annotations (#433)
---
.../solr/handler/admin/CoreAdminHandler.java | 35 ++-
.../solr/handler/admin/HealthCheckHandler.java | 28 ++-
.../org/apache/solr/handler/admin/InfoHandler.java | 49 ++--
.../apache/solr/handler/admin/LoggingHandler.java | 26 +-
.../handler/admin/PropertiesRequestHandler.java | 20 +-
.../solr/handler/admin/SystemInfoHandler.java | 44 ++--
.../solr/handler/admin/ThreadDumpHandler.java | 32 ++-
.../solr/handler/admin/api/InvokeClassAPI.java | 64 +++++
.../solr/handler/admin/api/NodeHealthAPI.java | 48 ++++
.../solr/handler/admin/api/NodeLoggingAPI.java | 49 ++++
.../solr/handler/admin/api/NodePropertiesAPI.java | 47 ++++
.../solr/handler/admin/api/NodeSystemInfoAPI.java | 49 ++++
.../solr/handler/admin/api/NodeThreadsAPI.java | 47 ++++
.../handler/admin/api/OverseerOperationAPI.java | 64 +++++
.../handler/admin/api/RejoinLeaderElectionAPI.java | 73 ++++++
.../org/apache/solr/handler/api/ApiRegistrar.java | 19 +-
.../handler/admin/api/V2NodeAPIMappingTest.java | 272 +++++++++++++++++++++
.../solr/client/solrj/request/CoreApiMapping.java | 23 +-
.../solrj/request/beans/InvokeClassPayload.java | 29 +++
.../request/beans/OverseerOperationPayload.java | 29 +++
.../request/beans/RejoinLeaderElectionPayload.java | 44 ++++
.../solrj/src/resources/apispec/node.Commands.json | 24 --
solr/solrj/src/resources/apispec/node.Info.json | 12 -
solr/solrj/src/resources/apispec/node.invoke.json | 16 --
.../apache/solr/common/util/JsonValidatorTest.java | 1 -
25 files changed, 998 insertions(+), 146 deletions(-)
diff --git
a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
index a738e43..5950b11 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
@@ -16,19 +16,10 @@
*/
package org.apache.solr.handler.admin;
-import java.io.File;
-import java.lang.invoke.MethodHandles;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.Locale;
-import java.util.Map;
-import java.util.concurrent.ExecutorService;
-
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
+import org.apache.solr.api.AnnotatedApi;
import org.apache.solr.api.Api;
import org.apache.solr.cloud.CloudDescriptor;
import org.apache.solr.cloud.ZkController;
@@ -45,6 +36,9 @@ import org.apache.solr.common.util.SolrNamedThreadFactory;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.CoreDescriptor;
import org.apache.solr.handler.RequestHandlerBase;
+import org.apache.solr.handler.admin.api.InvokeClassAPI;
+import org.apache.solr.handler.admin.api.OverseerOperationAPI;
+import org.apache.solr.handler.admin.api.RejoinLeaderElectionAPI;
import org.apache.solr.logging.MDCLoggingContext;
import org.apache.solr.metrics.SolrMetricManager;
import org.apache.solr.metrics.SolrMetricsContext;
@@ -58,6 +52,18 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
+import java.io.File;
+import java.lang.invoke.MethodHandles;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
+
import static org.apache.solr.common.params.CoreAdminParams.ACTION;
import static
org.apache.solr.common.params.CoreAdminParams.CoreAdminAction.STATUS;
import static
org.apache.solr.security.PermissionNameProvider.Name.CORE_EDIT_PERM;
@@ -402,7 +408,12 @@ public class CoreAdminHandler extends RequestHandlerBase
implements PermissionNa
@Override
public Collection<Api> getApis() {
- return coreAdminHandlerApi.getApis();
+ final List<Api> apis = Lists.newArrayList(coreAdminHandlerApi.getApis());
+ // Only some core-admin APIs use the v2 AnnotatedApi framework
+ apis.addAll(AnnotatedApi.getApis(new InvokeClassAPI(this)));
+ apis.addAll(AnnotatedApi.getApis(new RejoinLeaderElectionAPI(this)));
+ apis.addAll(AnnotatedApi.getApis(new OverseerOperationAPI(this)));
+ return apis;
}
static {
diff --git
a/solr/core/src/java/org/apache/solr/handler/admin/HealthCheckHandler.java
b/solr/core/src/java/org/apache/solr/handler/admin/HealthCheckHandler.java
index 147ad8a..5c2831d 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/HealthCheckHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/HealthCheckHandler.java
@@ -17,15 +17,9 @@
package org.apache.solr.handler.admin;
-import java.lang.invoke.MethodHandles;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Locale;
-import java.util.stream.Collectors;
-
import org.apache.lucene.index.IndexCommit;
+import org.apache.solr.api.AnnotatedApi;
+import org.apache.solr.api.Api;
import org.apache.solr.client.solrj.request.HealthCheckRequest;
import org.apache.solr.cloud.CloudDescriptor;
import org.apache.solr.common.SolrException;
@@ -38,14 +32,21 @@ import org.apache.solr.core.SolrCore;
import org.apache.solr.handler.IndexFetcher;
import org.apache.solr.handler.ReplicationHandler;
import org.apache.solr.handler.RequestHandlerBase;
+import org.apache.solr.handler.admin.api.NodeHealthAPI;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import static org.apache.solr.common.params.CommonParams.FAILURE;
-import static org.apache.solr.common.params.CommonParams.OK;
-import static org.apache.solr.common.params.CommonParams.STATUS;
+import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.stream.Collectors;
+
+import static org.apache.solr.common.params.CommonParams.*;
import static org.apache.solr.handler.ReplicationHandler.GENERATION;
/**
@@ -275,4 +276,9 @@ public class HealthCheckHandler extends RequestHandlerBase {
public Boolean registerV2() {
return Boolean.TRUE;
}
+
+ @Override
+ public Collection<Api> getApis() {
+ return AnnotatedApi.getApis(new NodeHealthAPI(this));
+ }
}
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/InfoHandler.java
b/solr/core/src/java/org/apache/solr/handler/admin/InfoHandler.java
index 29032da..235a615 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/InfoHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/InfoHandler.java
@@ -16,12 +16,8 @@
*/
package org.apache.solr.handler.admin;
-import java.util.Collection;
-import java.util.Locale;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.solr.api.ApiBag.ReqHandlerToApi;
+import com.google.common.collect.ImmutableList;
+import org.apache.solr.api.Api;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.CoreContainer;
@@ -29,15 +25,18 @@ import org.apache.solr.handler.RequestHandlerBase;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrRequestHandler;
import org.apache.solr.response.SolrQueryResponse;
-import org.apache.solr.api.Api;
-import static java.util.Collections.singletonList;
-import static org.apache.solr.common.util.Utils.getSpec;
+import java.util.Collection;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
import static org.apache.solr.common.params.CommonParams.PATH;
public class InfoHandler extends RequestHandlerBase {
protected final CoreContainer coreContainer;
+ private Map<String, RequestHandlerBase> handlers = new ConcurrentHashMap<>();
/**
* Overloaded ctor to inject CoreContainer into the handler.
@@ -108,23 +107,27 @@ public class InfoHandler extends RequestHandlerBase {
return Category.ADMIN;
}
- protected PropertiesRequestHandler getPropertiesHandler() {
+ public PropertiesRequestHandler getPropertiesHandler() {
return (PropertiesRequestHandler) handlers.get("properties");
}
- protected ThreadDumpHandler getThreadDumpHandler() {
+ public ThreadDumpHandler getThreadDumpHandler() {
return (ThreadDumpHandler) handlers.get("threads");
}
- protected LoggingHandler getLoggingHandler() {
+ public LoggingHandler getLoggingHandler() {
return (LoggingHandler) handlers.get("logging");
}
- protected SystemInfoHandler getSystemInfoHandler() {
+ public SystemInfoHandler getSystemInfoHandler() {
return (SystemInfoHandler) handlers.get("system");
}
+ public HealthCheckHandler getHealthCheckHandler() {
+ return (HealthCheckHandler) handlers.get("health");
+ }
+
protected void setPropertiesHandler(PropertiesRequestHandler
propertiesHandler) {
handlers.put("properties", propertiesHandler);
}
@@ -141,20 +144,28 @@ public class InfoHandler extends RequestHandlerBase {
handlers.put("system", systemInfoHandler);
}
+ protected void setHealthCheckHandler(HealthCheckHandler healthCheckHandler) {
+ handlers.put("health", healthCheckHandler);
+ }
+
@Override
public SolrRequestHandler getSubHandler(String subPath) {
return this;
}
- private Map<String, RequestHandlerBase> handlers = new ConcurrentHashMap<>();
-
@Override
- public Collection<Api> getApis() {
- return singletonList(new ReqHandlerToApi(this, getSpec("node.Info")));
+ public Boolean registerV2() {
+ return Boolean.TRUE;
}
@Override
- public Boolean registerV2() {
- return Boolean.TRUE;
+ public Collection<Api> getApis() {
+ final ImmutableList.Builder<Api> list = new ImmutableList.Builder<>();
+ list.addAll(handlers.get("threads").getApis());
+ list.addAll(handlers.get("properties").getApis());
+ list.addAll(handlers.get("logging").getApis());
+ list.addAll(handlers.get("system").getApis());
+ list.addAll(handlers.get("health").getApis());
+ return list.build();
}
}
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 3d2d764..c86a908 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
@@ -16,12 +16,8 @@
*/
package org.apache.solr.handler.admin;
-import java.lang.invoke.MethodHandles;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicBoolean;
-
+import org.apache.solr.api.AnnotatedApi;
+import org.apache.solr.api.Api;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
@@ -30,6 +26,7 @@ import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.SolrCore;
import org.apache.solr.handler.RequestHandlerBase;
+import org.apache.solr.handler.admin.api.NodeLoggingAPI;
import org.apache.solr.logging.LogWatcher;
import org.apache.solr.logging.LoggerInfo;
import org.apache.solr.request.SolrQueryRequest;
@@ -38,6 +35,13 @@ import org.apache.solr.util.plugin.SolrCoreAware;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.lang.invoke.MethodHandles;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
/**
* A request handler to show which loggers are registered and allows you to
set them
@@ -168,4 +172,14 @@ public class LoggingHandler extends RequestHandlerBase
implements SolrCoreAware
return Category.ADMIN;
}
+ @Override
+ public Collection<Api> getApis() {
+ return AnnotatedApi.getApis(new NodeLoggingAPI(this));
+ }
+
+ @Override
+ public Boolean registerV2() {
+ return Boolean.TRUE;
+ }
+
}
\ No newline at end of file
diff --git
a/solr/core/src/java/org/apache/solr/handler/admin/PropertiesRequestHandler.java
b/solr/core/src/java/org/apache/solr/handler/admin/PropertiesRequestHandler.java
index 57a7492..ce35a35 100644
---
a/solr/core/src/java/org/apache/solr/handler/admin/PropertiesRequestHandler.java
+++
b/solr/core/src/java/org/apache/solr/handler/admin/PropertiesRequestHandler.java
@@ -16,16 +16,20 @@
*/
package org.apache.solr.handler.admin;
-import java.io.IOException;
-import java.util.Enumeration;
-
+import org.apache.solr.api.AnnotatedApi;
+import org.apache.solr.api.Api;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.handler.RequestHandlerBase;
+import org.apache.solr.handler.admin.api.NodePropertiesAPI;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.util.RedactionUtils;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Enumeration;
+
import static org.apache.solr.common.params.CommonParams.NAME;
/**
@@ -75,4 +79,14 @@ public class PropertiesRequestHandler extends
RequestHandlerBase
public Category getCategory() {
return Category.ADMIN;
}
+
+ @Override
+ public Collection<Api> getApis() {
+ return AnnotatedApi.getApis(new NodePropertiesAPI(this));
+ }
+
+ @Override
+ public Boolean registerV2() {
+ return Boolean.TRUE;
+ }
}
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 5a3c7b9..46c6670 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,28 +16,16 @@
*/
package org.apache.solr.handler.admin;
-import java.io.File;
-import java.io.IOException;
-import java.lang.invoke.MethodHandles;
-import java.lang.management.ManagementFactory;
-import java.lang.management.OperatingSystemMXBean;
-import java.lang.management.RuntimeMXBean;
-import java.net.InetAddress;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.util.Date;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Locale;
-import java.util.Set;
-
import com.codahale.metrics.Gauge;
import org.apache.lucene.LucenePackage;
+import org.apache.solr.api.AnnotatedApi;
+import org.apache.solr.api.Api;
import org.apache.solr.common.cloud.UrlScheme;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.SolrCore;
import org.apache.solr.handler.RequestHandlerBase;
+import org.apache.solr.handler.admin.api.NodeSystemInfoAPI;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.schema.IndexSchema;
@@ -49,6 +37,22 @@ import org.apache.solr.util.stats.MetricUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.File;
+import java.io.IOException;
+import java.lang.invoke.MethodHandles;
+import java.lang.management.ManagementFactory;
+import java.lang.management.OperatingSystemMXBean;
+import java.lang.management.RuntimeMXBean;
+import java.net.InetAddress;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.Collection;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
import static org.apache.solr.common.params.CommonParams.NAME;
@@ -420,6 +424,16 @@ 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;
+ }
}
diff --git
a/solr/core/src/java/org/apache/solr/handler/admin/ThreadDumpHandler.java
b/solr/core/src/java/org/apache/solr/handler/admin/ThreadDumpHandler.java
index e13a0a0..5a6f3e5 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/ThreadDumpHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/ThreadDumpHandler.java
@@ -16,21 +16,25 @@
*/
package org.apache.solr.handler.admin;
+import org.apache.solr.api.AnnotatedApi;
+import org.apache.solr.api.Api;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.common.util.SimpleOrderedMap;
+import org.apache.solr.handler.RequestHandlerBase;
+import org.apache.solr.handler.admin.api.NodeThreadsAPI;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
+
import java.io.IOException;
+import java.lang.management.LockInfo;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
-import java.lang.management.LockInfo;
import java.lang.management.ThreadMXBean;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Locale;
-import org.apache.solr.common.util.NamedList;
-import org.apache.solr.common.util.SimpleOrderedMap;
-import org.apache.solr.handler.RequestHandlerBase;
-import org.apache.solr.request.SolrQueryRequest;
-import org.apache.solr.response.SolrQueryResponse;
-
import static org.apache.solr.common.params.CommonParams.ID;
import static org.apache.solr.common.params.CommonParams.NAME;
@@ -38,8 +42,8 @@ import static org.apache.solr.common.params.CommonParams.NAME;
*
* @since solr 1.2
*/
-public class ThreadDumpHandler extends RequestHandlerBase
-{
+public class ThreadDumpHandler extends RequestHandlerBase {
+
@Override
public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp)
throws IOException
{
@@ -172,4 +176,14 @@ public class ThreadDumpHandler extends RequestHandlerBase
public Category getCategory() {
return Category.ADMIN;
}
+
+ @Override
+ public Collection<Api> getApis() {
+ return AnnotatedApi.getApis(new NodeThreadsAPI(this));
+ }
+
+ @Override
+ public Boolean registerV2() {
+ return Boolean.TRUE;
+ }
}
diff --git
a/solr/core/src/java/org/apache/solr/handler/admin/api/InvokeClassAPI.java
b/solr/core/src/java/org/apache/solr/handler/admin/api/InvokeClassAPI.java
new file mode 100644
index 0000000..cdcb4a1
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/handler/admin/api/InvokeClassAPI.java
@@ -0,0 +1,64 @@
+/*
+ * 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 org.apache.solr.api.Command;
+import org.apache.solr.api.EndPoint;
+import org.apache.solr.api.PayloadObj;
+import org.apache.solr.client.solrj.request.beans.InvokeClassPayload;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.handler.admin.CoreAdminHandler;
+
+import java.util.Locale;
+
+import static org.apache.solr.client.solrj.SolrRequest.METHOD.POST;
+import static org.apache.solr.common.params.CoreAdminParams.ACTION;
+import static
org.apache.solr.common.params.CoreAdminParams.CoreAdminAction.INVOKE;
+import static
org.apache.solr.security.PermissionNameProvider.Name.CORE_EDIT_PERM;
+
+/**
+ * V2 API for triggering "invocable" classes.
+ *
+ * This API (POST /v2/node {'invoke': {...}}) is analogous to the v1
/admin/cores?action=INVOKE command.
+ */
+@EndPoint(
+ path = {"/node"},
+ method = POST,
+ permission = CORE_EDIT_PERM)
+public class InvokeClassAPI {
+ public static final String INVOKE_CMD = "invoke";
+
+ private final CoreAdminHandler coreAdminHandler;
+
+ public InvokeClassAPI(CoreAdminHandler coreAdminHandler) {
+ this.coreAdminHandler = coreAdminHandler;
+ }
+
+ @Command(name = INVOKE_CMD)
+ public void invokeClasses(PayloadObj<InvokeClassPayload> payload) throws
Exception {
+ final InvokeClassPayload v2Body = payload.get();
+ final ModifiableSolrParams v1Params = new
ModifiableSolrParams(payload.getRequest().getParams());
+ v1Params.add(ACTION, INVOKE.name().toLowerCase(Locale.ROOT));
+ for (String clazzStr : v2Body.classes) {
+ v1Params.add("class", clazzStr);
+ }
+
+ payload.getRequest().setParams(v1Params);
+ coreAdminHandler.handleRequestBody(payload.getRequest(),
payload.getResponse());
+ }
+}
diff --git
a/solr/core/src/java/org/apache/solr/handler/admin/api/NodeHealthAPI.java
b/solr/core/src/java/org/apache/solr/handler/admin/api/NodeHealthAPI.java
new file mode 100644
index 0000000..4139867
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/handler/admin/api/NodeHealthAPI.java
@@ -0,0 +1,48 @@
+/*
+ * 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 org.apache.solr.api.EndPoint;
+import org.apache.solr.handler.admin.HealthCheckHandler;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
+
+import static org.apache.solr.client.solrj.SolrRequest.METHOD.GET;
+import static
org.apache.solr.security.PermissionNameProvider.Name.CONFIG_READ_PERM;
+
+/**
+ * V2 API for checking the health of the receiving node.
+ *
+ * This API (GET /v2/node/health) is analogous to the v1 /admin/info/health.
+ */
+public class NodeHealthAPI {
+ private final HealthCheckHandler handler;
+
+ public NodeHealthAPI(HealthCheckHandler handler) {
+ this.handler = handler;
+ }
+
+ // TODO Update permission here once SOLR-11623 lands.
+ @EndPoint(
+ path = {"/node/health"},
+ 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/handler/admin/api/NodeLoggingAPI.java
b/solr/core/src/java/org/apache/solr/handler/admin/api/NodeLoggingAPI.java
new file mode 100644
index 0000000..e891ee4
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/handler/admin/api/NodeLoggingAPI.java
@@ -0,0 +1,49 @@
+/*
+ * 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 org.apache.solr.api.EndPoint;
+import org.apache.solr.handler.admin.LoggingHandler;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
+
+import static org.apache.solr.client.solrj.SolrRequest.METHOD.GET;
+import static
org.apache.solr.security.PermissionNameProvider.Name.CONFIG_EDIT_PERM;
+
+/**
+ * V2 API for getting or setting log levels on an individual node.
+ *
+ * This API (GET /v2/node/logging) is analogous to the v1 /admin/info/logging.
+ */
+public class NodeLoggingAPI {
+
+ private final LoggingHandler handler;
+
+ public NodeLoggingAPI(LoggingHandler handler) {
+ this.handler = handler;
+ }
+
+ // TODO See SOLR-15823 for background on the (less than ideal) permission
chosen here.
+ @EndPoint(
+ path = {"/node/logging"},
+ method = GET,
+ permission = CONFIG_EDIT_PERM)
+ public void getOrSetLogLevels(SolrQueryRequest req, SolrQueryResponse rsp)
throws Exception {
+ handler.handleRequestBody(req, rsp);
+ }
+}
diff --git
a/solr/core/src/java/org/apache/solr/handler/admin/api/NodePropertiesAPI.java
b/solr/core/src/java/org/apache/solr/handler/admin/api/NodePropertiesAPI.java
new file mode 100644
index 0000000..4f86883
--- /dev/null
+++
b/solr/core/src/java/org/apache/solr/handler/admin/api/NodePropertiesAPI.java
@@ -0,0 +1,47 @@
+/*
+ * 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 org.apache.solr.api.EndPoint;
+import org.apache.solr.handler.admin.PropertiesRequestHandler;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
+
+import static org.apache.solr.client.solrj.SolrRequest.METHOD.GET;
+import static
org.apache.solr.security.PermissionNameProvider.Name.CONFIG_READ_PERM;
+
+/**
+ * V2 API for listing system properties for each node.
+ *
+ * This API (GET /v2/node/properties) is analogous to the v1
/admin/info/properties.
+ */
+public class NodePropertiesAPI {
+ private final PropertiesRequestHandler handler;
+
+ public NodePropertiesAPI(PropertiesRequestHandler handler) {
+ this.handler = handler;
+ }
+
+ @EndPoint(
+ path = {"/node/properties"},
+ method = GET,
+ permission = CONFIG_READ_PERM)
+ public void getRequestedProperties(SolrQueryRequest req, SolrQueryResponse
rsp) throws Exception {
+ handler.handleRequestBody(req, rsp);
+ }
+}
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
new file mode 100644
index 0000000..9d05fc6
--- /dev/null
+++
b/solr/core/src/java/org/apache/solr/handler/admin/api/NodeSystemInfoAPI.java
@@ -0,0 +1,49 @@
+/*
+ * 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 org.apache.solr.api.EndPoint;
+import org.apache.solr.handler.admin.SystemInfoHandler;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
+
+import static org.apache.solr.client.solrj.SolrRequest.METHOD.GET;
+import static
org.apache.solr.security.PermissionNameProvider.Name.CONFIG_READ_PERM;
+
+/**
+ * V2 API for getting "system" information from the receiving node.
+ *
+ * This includes current resource utilization, information about the
installation (location, version, etc.), and JVM settings.
+ *
+ * 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/handler/admin/api/NodeThreadsAPI.java
b/solr/core/src/java/org/apache/solr/handler/admin/api/NodeThreadsAPI.java
new file mode 100644
index 0000000..64f992d
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/handler/admin/api/NodeThreadsAPI.java
@@ -0,0 +1,47 @@
+/*
+ * 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 org.apache.solr.api.EndPoint;
+import org.apache.solr.handler.admin.ThreadDumpHandler;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
+
+import static org.apache.solr.client.solrj.SolrRequest.METHOD.GET;
+import static
org.apache.solr.security.PermissionNameProvider.Name.METRICS_READ_PERM;
+
+/**
+ * V2 API for triggering a thread dump on the receiving node.
+ *
+ * This API (GET /v2/node/threads) is analogous to the v1 /admin/info/threads.
+ */
+public class NodeThreadsAPI {
+ private final ThreadDumpHandler handler;
+
+ public NodeThreadsAPI(ThreadDumpHandler handler) {
+ this.handler = handler;
+ }
+
+ @EndPoint(
+ path = {"/node/threads"},
+ method = GET,
+ permission = METRICS_READ_PERM)
+ public void triggerThreadDump(SolrQueryRequest req, SolrQueryResponse rsp)
throws Exception {
+ handler.handleRequestBody(req, rsp);
+ }
+}
diff --git
a/solr/core/src/java/org/apache/solr/handler/admin/api/OverseerOperationAPI.java
b/solr/core/src/java/org/apache/solr/handler/admin/api/OverseerOperationAPI.java
new file mode 100644
index 0000000..b8b2e5c
--- /dev/null
+++
b/solr/core/src/java/org/apache/solr/handler/admin/api/OverseerOperationAPI.java
@@ -0,0 +1,64 @@
+/*
+ * 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 org.apache.solr.api.Command;
+import org.apache.solr.api.EndPoint;
+import org.apache.solr.api.PayloadObj;
+import org.apache.solr.client.solrj.request.beans.OverseerOperationPayload;
+import org.apache.solr.common.params.CoreAdminParams;
+import org.apache.solr.handler.admin.CoreAdminHandler;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import static org.apache.solr.client.solrj.SolrRequest.METHOD.POST;
+import static org.apache.solr.common.params.CoreAdminParams.ACTION;
+import static org.apache.solr.handler.ClusterAPI.wrapParams;
+import static
org.apache.solr.security.PermissionNameProvider.Name.CORE_EDIT_PERM;
+
+/**
+ * V2 API for triggering a node to rejoin leader election for the 'overseer'
role.
+ *
+ * This API (POST /v2/node {'overseer-op': {...}}) is analogous to the v1
/admin/cores?action=overseerop command.
+ *
+ * @see OverseerOperationPayload
+ */
+@EndPoint(
+ path = {"/node"},
+ method = POST,
+ permission = CORE_EDIT_PERM)
+public class OverseerOperationAPI {
+
+ // TODO rename this command, this API doesn't really have anything to do
with overseer-ops, its about leader election
+ public static final String OVERSEER_OP_CMD = "overseer-op";
+
+ private final CoreAdminHandler coreAdminHandler;
+
+ public OverseerOperationAPI(CoreAdminHandler coreAdminHandler) {
+ this.coreAdminHandler = coreAdminHandler;
+ }
+
+ @Command(name = OVERSEER_OP_CMD)
+ public void
joinOverseerLeaderElection(PayloadObj<OverseerOperationPayload> payload) throws
Exception {
+ final Map<String, Object> v1Params = payload.get().toMap(new
HashMap<>());
+ v1Params.put(ACTION,
CoreAdminParams.CoreAdminAction.OVERSEEROP.name().toLowerCase(Locale.ROOT));
+ coreAdminHandler.handleRequestBody(wrapParams(payload.getRequest(),
v1Params), payload.getResponse());
+ }
+}
diff --git
a/solr/core/src/java/org/apache/solr/handler/admin/api/RejoinLeaderElectionAPI.java
b/solr/core/src/java/org/apache/solr/handler/admin/api/RejoinLeaderElectionAPI.java
new file mode 100644
index 0000000..fdb8207
--- /dev/null
+++
b/solr/core/src/java/org/apache/solr/handler/admin/api/RejoinLeaderElectionAPI.java
@@ -0,0 +1,73 @@
+/*
+ * 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 org.apache.solr.api.Command;
+import org.apache.solr.api.EndPoint;
+import org.apache.solr.api.PayloadObj;
+import org.apache.solr.client.solrj.request.beans.RejoinLeaderElectionPayload;
+import org.apache.solr.handler.admin.CoreAdminHandler;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import static org.apache.solr.client.solrj.SolrRequest.METHOD.POST;
+import static org.apache.solr.common.cloud.ZkStateReader.CORE_NODE_NAME_PROP;
+import static org.apache.solr.common.cloud.ZkStateReader.ELECTION_NODE_PROP;
+import static org.apache.solr.common.params.CoreAdminParams.ACTION;
+import static
org.apache.solr.common.params.CoreAdminParams.CoreAdminAction.REJOINLEADERELECTION;
+import static org.apache.solr.handler.ClusterAPI.wrapParams;
+import static
org.apache.solr.security.PermissionNameProvider.Name.CORE_EDIT_PERM;
+
+/**
+ * V2 API for triggering a core to rejoin leader election for the shard it
constitutes.
+ *
+ * This API (POST /v2/node {'rejoin-leader-election': {...}}) is analogous to
the v1
+ * /admin/cores?action=REJOINLEADERELECTION command.
+ */
+@EndPoint(
+ path = {"/node"},
+ method = POST,
+ permission = CORE_EDIT_PERM)
+public class RejoinLeaderElectionAPI {
+ public static final String REJOIN_LEADER_ELECTION_CMD =
"rejoin-leader-election";
+
+ private final CoreAdminHandler coreAdminHandler;
+
+ public RejoinLeaderElectionAPI(CoreAdminHandler coreAdminHandler) {
+ this.coreAdminHandler = coreAdminHandler;
+ }
+
+ @Command(name = REJOIN_LEADER_ELECTION_CMD)
+ public void rejoinLeaderElection(PayloadObj<RejoinLeaderElectionPayload>
payload) throws Exception {
+ final RejoinLeaderElectionPayload v2Body = payload.get();
+ final Map<String, Object> v1Params = v2Body.toMap(new HashMap<>());
+ v1Params.put(ACTION,
REJOINLEADERELECTION.name().toLowerCase(Locale.ROOT));
+ if (v2Body.electionNode != null) {
+ v1Params.remove("electionNode");
+ v1Params.put(ELECTION_NODE_PROP, v2Body.electionNode);
+ }
+ if (v2Body.coreNodeName != null) {
+ v1Params.remove("coreNodeName");
+ v1Params.put(CORE_NODE_NAME_PROP, v2Body.coreNodeName);
+ }
+
+
coreAdminHandler.handleRequestBody(wrapParams(payload.getRequest(), v1Params),
payload.getResponse());
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/handler/api/ApiRegistrar.java
b/solr/core/src/java/org/apache/solr/handler/api/ApiRegistrar.java
index 25718f2..c59ae31 100644
--- a/solr/core/src/java/org/apache/solr/handler/api/ApiRegistrar.java
+++ b/solr/core/src/java/org/apache/solr/handler/api/ApiRegistrar.java
@@ -19,7 +19,24 @@ package org.apache.solr.handler.api;
import org.apache.solr.api.ApiBag;
import org.apache.solr.handler.admin.CollectionsHandler;
-import org.apache.solr.handler.admin.api.*;
+import org.apache.solr.handler.admin.api.AddReplicaAPI;
+import org.apache.solr.handler.admin.api.AddReplicaPropertyAPI;
+import org.apache.solr.handler.admin.api.BalanceShardUniqueAPI;
+import org.apache.solr.handler.admin.api.CollectionStatusAPI;
+import org.apache.solr.handler.admin.api.CreateShardAPI;
+import org.apache.solr.handler.admin.api.DeleteCollectionAPI;
+import org.apache.solr.handler.admin.api.DeleteReplicaAPI;
+import org.apache.solr.handler.admin.api.DeleteReplicaPropertyAPI;
+import org.apache.solr.handler.admin.api.DeleteShardAPI;
+import org.apache.solr.handler.admin.api.ForceLeaderAPI;
+import org.apache.solr.handler.admin.api.MigrateDocsAPI;
+import org.apache.solr.handler.admin.api.ModifyCollectionAPI;
+import org.apache.solr.handler.admin.api.MoveReplicaAPI;
+import org.apache.solr.handler.admin.api.RebalanceLeadersAPI;
+import org.apache.solr.handler.admin.api.ReloadCollectionAPI;
+import org.apache.solr.handler.admin.api.SetCollectionPropertyAPI;
+import org.apache.solr.handler.admin.api.SplitShardAPI;
+import org.apache.solr.handler.admin.api.SyncShardAPI;
/**
* Registers annotation-based V2 APIs with an {@link ApiBag}
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
new file mode 100644
index 0000000..193a815
--- /dev/null
+++
b/solr/core/src/test/org/apache/solr/handler/admin/api/V2NodeAPIMappingTest.java
@@ -0,0 +1,272 @@
+/*
+ * 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 com.google.common.collect.Maps;
+import org.apache.solr.api.Api;
+import org.apache.solr.api.ApiBag;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.CommandOperation;
+import org.apache.solr.common.util.ContentStreamBase;
+import org.apache.solr.handler.RequestHandlerBase;
+import org.apache.solr.handler.admin.CoreAdminHandler;
+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.LocalSolrQueryRequest;
+import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.response.SolrQueryResponse;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.solr.SolrTestCaseJ4.assumeWorkingMockito;
+import static org.apache.solr.common.params.CommonParams.ACTION;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+/**
+ * Unit tests for the v2 to v1 mapping for Solr's /node/ APIs
+ */
+public class V2NodeAPIMappingTest {
+ private ApiBag apiBag;
+ private ArgumentCaptor<SolrQueryRequest> queryRequestCaptor;
+ private CoreAdminHandler mockCoresHandler;
+ private InfoHandler infoHandler;
+ private SystemInfoHandler mockSystemInfoHandler;
+ private LoggingHandler mockLoggingHandler;
+ private PropertiesRequestHandler mockPropertiesHandler;
+ private HealthCheckHandler mockHealthCheckHandler;
+ private ThreadDumpHandler mockThreadDumpHandler;
+
+ @BeforeClass
+ public static void ensureWorkingMockito() {
+ assumeWorkingMockito();
+ }
+
+ @Before
+ public void setupApiBag() throws Exception {
+ 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);
+
when(infoHandler.getThreadDumpHandler()).thenReturn(mockThreadDumpHandler);
+
+ apiBag = new ApiBag(false);
+ registerAllNodeApis(apiBag, mockCoresHandler, infoHandler);
+ }
+
+ @Test
+ public void testOverseerOpApiAllProperties() throws Exception {
+ final SolrParams v1Params = captureConvertedCoreV1Params("/node",
"POST",
+ "{" +
+ "\"overseer-op\": {" +
+ "\"op\": \"asdf\", " +
+ "\"electionNode\": \"someNodeName\"" +
+ "}}");
+
+ assertEquals("overseerop", v1Params.get(ACTION));
+ assertEquals("asdf", v1Params.get("op"));
+ assertEquals("someNodeName", v1Params.get("electionNode"));
+ }
+
+ @Test
+ public void testRejoinLeaderElectionApiAllProperties() throws Exception {
+ final SolrParams v1Params = captureConvertedCoreV1Params("/node",
"POST",
+ "{" +
+ "\"rejoin-leader-election\": {" +
+ "\"collection\": \"someCollection\", " +
+ "\"shard\": \"someShard\"," +
+ "\"coreNodeName\": \"someNodeName\"," +
+ "\"core\": \"someCore\"," +
+ "\"electionNode\": \"someElectionNode\"," +
+ "\"rejoinAtHead\": true" +
+ "}}");
+
+ assertEquals("rejoinleaderelection", v1Params.get(ACTION));
+ assertEquals("someCollection", v1Params.get("collection"));
+ assertEquals("someShard", v1Params.get("shard"));
+ assertEquals("someNodeName", v1Params.get("core_node_name"));
+ assertEquals("someCore", v1Params.get("core"));
+ assertEquals("someElectionNode", v1Params.get("election_node"));
+ assertEquals("true", v1Params.get("rejoinAtHead"));
+ }
+
+ @Test
+ public void testInvokeClassApiAllProperties() throws Exception {
+ final SolrParams v1Params = captureConvertedCoreV1Params("/node",
"POST",
+ "{" +
+ "\"invoke\": {" +
+ "\"classes\": [\"someClassName\",
\"someOtherClassName\"]" +
+ "}}");
+
+ assertEquals("invoke", v1Params.get(ACTION));
+ assertEquals(2, v1Params.getParams("class").length);
+ final List<String> classes =
Arrays.asList(v1Params.getParams("class"));
+ assertTrue(classes.contains("someClassName"));
+ assertTrue(classes.contains("someOtherClassName"));
+
+ }
+
+ @Test
+ public void testSystemPropsApiAllProperties() throws Exception {
+ final ModifiableSolrParams solrParams = new ModifiableSolrParams();
+ solrParams.add("name", "specificPropertyName");
+ final SolrParams v1Params =
captureConvertedPropertiesV1Params("/node/properties", "GET", solrParams);
+
+ assertEquals("specificPropertyName", v1Params.get("name"));
+ }
+
+ @Test
+ public void testThreadDumpApiAllProperties() throws Exception {
+ final ModifiableSolrParams solrParams = new ModifiableSolrParams();
+ solrParams.add("anyParamName", "anyParamValue");
+ final SolrParams v1Params =
captureConvertedThreadDumpV1Params("/node/threads", "GET", solrParams);
+
+ // All parameters are passed through to v1 API as-is
+ assertEquals("anyParamValue", v1Params.get("anyParamName"));
+ }
+
+ @Test
+ public void testLogLevelsApiAllProperties() throws Exception {
+ final ModifiableSolrParams solrParams = new ModifiableSolrParams();
+ solrParams.add("since", "12345678");
+ solrParams.add("threshold", "someThresholdValue");
+ solrParams.add("test", "someTestValue");
+ solrParams.add("set", "SomeClassName");
+ final SolrParams v1Params =
captureConvertedLoggingV1Params("/node/logging", "GET", solrParams);
+
+ // All parameters are passed through to v1 API as-is.
+ assertEquals("12345678", v1Params.get("since"));
+ assertEquals("someThresholdValue", v1Params.get("threshold"));
+ assertEquals("someTestValue", v1Params.get("test"));
+ assertEquals("SomeClassName", v1Params.get("set"));
+ }
+
+ @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();
+ solrParams.add("requireHealthyCores", "true");
+ solrParams.add("maxGenerationLag", "123");
+ final SolrParams v1Params =
captureConvertedHealthCheckV1Params("/node/health", "GET", solrParams);
+
+ // All parameters are passed through to v1 API as-is.
+ assertEquals(true, v1Params.getBool("requireHealthyCores"));
+ assertEquals(123, v1Params.getPrimitiveInt("maxGenerationLag"));
+ }
+
+ private SolrParams captureConvertedCoreV1Params(String path, String
method, String v2RequestBody) throws Exception {
+ return doCaptureParams(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 captureConvertedLoggingV1Params(String path, String
method, SolrParams inputParams) throws Exception {
+ return doCaptureParams(path, method, inputParams, null,
mockLoggingHandler);
+ }
+
+ private SolrParams captureConvertedPropertiesV1Params(String path, String
method, SolrParams inputParams) throws Exception {
+ return doCaptureParams(path, method, inputParams, null,
mockPropertiesHandler);
+ }
+
+ private SolrParams captureConvertedHealthCheckV1Params(String path, String
method, SolrParams inputParams) throws Exception {
+ return doCaptureParams(path, method, inputParams, null,
mockHealthCheckHandler);
+ }
+
+ private SolrParams captureConvertedThreadDumpV1Params(String path, String
method, SolrParams inputParams) throws Exception {
+ return doCaptureParams(path, method, inputParams, null,
mockThreadDumpHandler);
+ }
+
+ private SolrParams doCaptureParams(String path, String method, SolrParams
inputParams, String v2RequestBody, RequestHandlerBase mockHandler) throws
Exception {
+ final HashMap<String, String> parts = new HashMap<>();
+ final Map<String, String[]> inputParamsMap = Maps.newHashMap();
+ inputParams.stream().forEach(e -> {
+ inputParamsMap.put(e.getKey(), e.getValue());
+ });
+ final Api api = apiBag.lookup(path, method, parts);
+ final SolrQueryResponse rsp = new SolrQueryResponse();
+ final LocalSolrQueryRequest req = new LocalSolrQueryRequest(null,
inputParamsMap) {
+ @Override
+ public List<CommandOperation> getCommands(boolean validateInput) {
+ if (v2RequestBody == null) return Collections.emptyList();
+ return ApiBag.getCommandOperations(new
ContentStreamBase.StringStream(v2RequestBody), api.getCommandSchema(), true);
+ }
+
+ @Override
+ public Map<String, String> getPathTemplateValues() {
+ return parts;
+ }
+
+ @Override
+ public String getHttpMethod() {
+ return method;
+ }
+ };
+
+
+ api.call(req, rsp);
+ verify(mockHandler).handleRequestBody(queryRequestCaptor.capture(),
any());
+ return queryRequestCaptor.getValue().getParams();
+ }
+
+ private static void registerAllNodeApis(ApiBag apiBag, CoreAdminHandler
coreHandler,
+ InfoHandler infoHandler) {
+ apiBag.registerObject(new OverseerOperationAPI(coreHandler));
+ apiBag.registerObject(new RejoinLeaderElectionAPI(coreHandler));
+ apiBag.registerObject(new InvokeClassAPI(coreHandler));
+ apiBag.registerObject(new
NodePropertiesAPI(infoHandler.getPropertiesHandler()));
+ apiBag.registerObject(new
NodeThreadsAPI(infoHandler.getThreadDumpHandler()));
+ apiBag.registerObject(new
NodeLoggingAPI(infoHandler.getLoggingHandler()));
+ apiBag.registerObject(new
NodeSystemInfoAPI(infoHandler.getSystemInfoHandler()));
+ apiBag.registerObject(new
NodeHealthAPI(infoHandler.getHealthCheckHandler()));
+ }
+}
diff --git
a/solr/solrj/src/java/org/apache/solr/client/solrj/request/CoreApiMapping.java
b/solr/solrj/src/java/org/apache/solr/client/solrj/request/CoreApiMapping.java
index 89ae691..a20a427 100644
---
a/solr/solrj/src/java/org/apache/solr/client/solrj/request/CoreApiMapping.java
+++
b/solr/solrj/src/java/org/apache/solr/client/solrj/request/CoreApiMapping.java
@@ -18,20 +18,16 @@
package org.apache.solr.client.solrj.request;
-import java.util.Collections;
-import java.util.Map;
-
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.request.ApiMapping.CommandMeta;
import org.apache.solr.common.params.CoreAdminParams.CoreAdminAction;
+import java.util.Collections;
+import java.util.Map;
+
import static org.apache.solr.client.solrj.SolrRequest.METHOD.GET;
import static org.apache.solr.client.solrj.SolrRequest.METHOD.POST;
-import static
org.apache.solr.client.solrj.request.CoreApiMapping.EndPoint.CORES_COMMANDS;
-import static
org.apache.solr.client.solrj.request.CoreApiMapping.EndPoint.CORES_STATUS;
-import static
org.apache.solr.client.solrj.request.CoreApiMapping.EndPoint.NODEAPIS;
-import static
org.apache.solr.client.solrj.request.CoreApiMapping.EndPoint.NODEINVOKE;
-import static
org.apache.solr.client.solrj.request.CoreApiMapping.EndPoint.PER_CORE_COMMANDS;
+import static org.apache.solr.client.solrj.request.CoreApiMapping.EndPoint.*;
/** stores the mapping of v1 API parameters to v2 API parameters
* for core admin API
@@ -52,10 +48,7 @@ public class CoreApiMapping {
REQUESTSYNCSHARD(PER_CORE_COMMANDS, POST,
CoreAdminAction.REQUESTSYNCSHARD, "request-sync-shard", null),
REQUESTBUFFERUPDATES(PER_CORE_COMMANDS, POST,
CoreAdminAction.REQUESTBUFFERUPDATES, "request-buffer-updates", null),
REQUESTAPPLYUPDATES(PER_CORE_COMMANDS, POST,
CoreAdminAction.REQUESTAPPLYUPDATES, "request-apply-updates", null),
- REQUESTSTATUS(PER_CORE_COMMANDS, GET, CoreAdminAction.REQUESTSTATUS,
"request-status", null),/*TODO*/
- OVERSEEROP(NODEAPIS, POST, CoreAdminAction.OVERSEEROP, "overseer-op",
null),
- REJOINLEADERELECTION(NODEAPIS, POST, CoreAdminAction.REJOINLEADERELECTION,
"rejoin-leader-election", null),
- INVOKE(NODEINVOKE, GET, CoreAdminAction.INVOKE,"invoke", null);
+ REQUESTSTATUS(PER_CORE_COMMANDS, GET, CoreAdminAction.REQUESTSTATUS,
"request-status", null)/*TODO*/;
public final String commandName;
public final EndPoint endPoint;
@@ -91,16 +84,12 @@ public class CoreApiMapping {
public String getParamSubstitute(String param) {
return paramstoAttr.containsKey(param) ? paramstoAttr.get(param) : param;
}
-
-
}
public enum EndPoint implements ApiMapping.V2EndPoint {
CORES_STATUS("cores.Status"),
CORES_COMMANDS("cores.Commands"),
- PER_CORE_COMMANDS("cores.core.Commands"),
- NODEINVOKE("node.invoke"),
- NODEAPIS("node.Commands");
+ PER_CORE_COMMANDS("cores.core.Commands");
final String specName;
diff --git
a/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/InvokeClassPayload.java
b/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/InvokeClassPayload.java
new file mode 100644
index 0000000..5555daa
--- /dev/null
+++
b/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/InvokeClassPayload.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.client.solrj.request.beans;
+
+import org.apache.solr.common.annotation.JsonProperty;
+import org.apache.solr.common.util.ReflectMapWriter;
+
+import java.util.List;
+
+public class InvokeClassPayload implements ReflectMapWriter {
+
+ @JsonProperty(required = true)
+ public List<String> classes;
+}
diff --git
a/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/OverseerOperationPayload.java
b/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/OverseerOperationPayload.java
new file mode 100644
index 0000000..ce7cee4
--- /dev/null
+++
b/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/OverseerOperationPayload.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.client.solrj.request.beans;
+
+import org.apache.solr.common.annotation.JsonProperty;
+import org.apache.solr.common.util.ReflectMapWriter;
+
+public class OverseerOperationPayload implements ReflectMapWriter {
+ @JsonProperty
+ public String op;
+
+ @JsonProperty
+ public String electionNode;
+}
diff --git
a/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/RejoinLeaderElectionPayload.java
b/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/RejoinLeaderElectionPayload.java
new file mode 100644
index 0000000..fac9f79
--- /dev/null
+++
b/solr/solrj/src/java/org/apache/solr/client/solrj/request/beans/RejoinLeaderElectionPayload.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.client.solrj.request.beans;
+
+import org.apache.solr.common.annotation.JsonProperty;
+import org.apache.solr.common.util.ReflectMapWriter;
+
+public class RejoinLeaderElectionPayload implements ReflectMapWriter {
+
+ // TODO It seems like most of these properties should be required, but
it's hard to tell which ones are meant to be
+ // required without that being specified on the v1 API or elsewhere
+ @JsonProperty
+ public String collection;
+
+ @JsonProperty
+ public String shard;
+
+ @JsonProperty
+ public String coreNodeName;
+
+ @JsonProperty
+ public String core;
+
+ @JsonProperty
+ public String electionNode;
+
+ @JsonProperty
+ public Boolean rejoinAtHead;
+}
diff --git a/solr/solrj/src/resources/apispec/node.Commands.json
b/solr/solrj/src/resources/apispec/node.Commands.json
deleted file mode 100644
index 11b3c89..0000000
--- a/solr/solrj/src/resources/apispec/node.Commands.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "methods": [
- "POST"
- ],
- "url": {
- "paths": [
- "/node"
- ]
- },
- "commands": {
- "overseer-op": {
- "type": "object",
- "additionalProperties": true
- },
- "rejoin-leader-election": {
- "type": "object",
- "additionalProperties": true
- },
- "invoke":{
- "type": "object",
- "additionalProperties": true
- }
- }
-}
diff --git a/solr/solrj/src/resources/apispec/node.Info.json
b/solr/solrj/src/resources/apispec/node.Info.json
deleted file mode 100644
index 9fa3e94..0000000
--- a/solr/solrj/src/resources/apispec/node.Info.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "description": "Provides information about system properties, threads,
logging settings, system details and health (available in SolrCloud mode) for a
node.",
- "methods": ["GET"],
- "url": {
- "paths": [
- "/node/properties",
- "/node/threads",
- "/node/logging",
- "/node/system",
- "/node/health"]
- }
-}
diff --git a/solr/solrj/src/resources/apispec/node.invoke.json
b/solr/solrj/src/resources/apispec/node.invoke.json
deleted file mode 100644
index c8a9f69..0000000
--- a/solr/solrj/src/resources/apispec/node.invoke.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "methods": [
- "GET"
- ],
- "url": {
- "paths": [
- "/node/invoke"
- ],
- "params": {
- "class": {
- "type": "string",
- "description": "Name of the class that must be invoked. "
- }
- }
- }
-}
diff --git
a/solr/solrj/src/test/org/apache/solr/common/util/JsonValidatorTest.java
b/solr/solrj/src/test/org/apache/solr/common/util/JsonValidatorTest.java
index 18bc953..2ef8699 100644
--- a/solr/solrj/src/test/org/apache/solr/common/util/JsonValidatorTest.java
+++ b/solr/solrj/src/test/org/apache/solr/common/util/JsonValidatorTest.java
@@ -30,7 +30,6 @@ public class JsonValidatorTest extends SolrTestCaseJ4 {
public void testSchema() {
checkSchema("cores.Commands");
checkSchema("cores.core.Commands");
- checkSchema("node.Commands");
checkSchema("cluster.security.BasicAuth.Commands");
checkSchema("cluster.security.RuleBasedAuthorization");
checkSchema("core.config.Commands");