Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
title: Remove experimental 'solr.api.v2.enabled' sysprop, formerly used to disable the v2 API.
type: removed
authors:
- name: Jason Gerlowski
links:
- name: SOLR-18163
url: https://issues.apache.org/jira/browse/SOLR-18163
111 changes: 54 additions & 57 deletions solr/core/src/java/org/apache/solr/core/CoreContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@
import org.apache.solr.handler.admin.ZookeeperInfoHandler;
import org.apache.solr.handler.admin.ZookeeperRead;
import org.apache.solr.handler.admin.ZookeeperStatusHandler;
import org.apache.solr.handler.api.V2ApiUtils;
import org.apache.solr.handler.component.ShardHandlerFactory;
import org.apache.solr.handler.designer.SchemaDesignerAPI;
import org.apache.solr.jersey.InjectionFactories;
Expand Down Expand Up @@ -721,15 +720,15 @@ public ObjectCache getObjectCache() {
return objectCache;
}

private void registerV2ApiIfEnabled(Object apiObject) {
private void registerV2Api(Object apiObject) {
if (apiObject == null || containerHandlers.getApiBag() == null) {
return;
}

containerHandlers.getApiBag().registerObject(apiObject);
}

private void registerV2ApiIfEnabled(Class<? extends JerseyResource> clazz) {
private void registerV2Api(Class<? extends JerseyResource> clazz) {
if (containerHandlers.getJerseyEndpoints() == null) {
return;
}
Expand Down Expand Up @@ -839,12 +838,12 @@ private void loadInternal() {
Attributes.builder().put(HANDLER_ATTR, "/authentication/pki").build());

fileStore = new DistribFileStore(this);
registerV2ApiIfEnabled(ClusterFileStore.class);
registerV2Api(ClusterFileStore.class);

packageLoader = new SolrPackageLoader(this);
registerV2ApiIfEnabled(packageLoader.getPackageAPI().editAPI);
registerV2ApiIfEnabled(packageLoader.getPackageAPI().readAPI);
registerV2ApiIfEnabled(ZookeeperRead.class);
registerV2Api(packageLoader.getPackageAPI().editAPI);
registerV2Api(packageLoader.getPackageAPI().readAPI);
registerV2Api(ZookeeperRead.class);
}

MDCLoggingContext.setNode(this);
Expand All @@ -866,11 +865,11 @@ private void loadInternal() {
createHandler(
CONFIGSETS_HANDLER_PATH, cfg.getConfigSetsHandlerClass(), ConfigSetsHandler.class);
ClusterAPI clusterAPI = new ClusterAPI(collectionsHandler, configSetsHandler);
registerV2ApiIfEnabled(clusterAPI);
registerV2ApiIfEnabled(clusterAPI.commands);
registerV2Api(clusterAPI);
registerV2Api(clusterAPI.commands);

if (isZooKeeperAware()) {
registerV2ApiIfEnabled(new SchemaDesignerAPI(this));
registerV2Api(new SchemaDesignerAPI(this));
} // else Schema Designer not available in standalone (non-cloud) mode

/*
Expand Down Expand Up @@ -1021,8 +1020,8 @@ private void loadInternal() {
if (isZooKeeperAware()) {
containerPluginsRegistry.refresh();
getZkController().zkStateReader.registerClusterPropertiesListener(containerPluginsRegistry);
registerV2ApiIfEnabled(pluginsSource.getReadApi());
registerV2ApiIfEnabled(pluginsSource.getEditApi());
registerV2Api(pluginsSource.getReadApi());
registerV2Api(pluginsSource.getEditApi());

// initialize the placement plugin factory wrapper
// with the plugin configuration from the registry
Expand All @@ -1045,51 +1044,49 @@ private void loadInternal() {
});
}

if (V2ApiUtils.isEnabled()) {
final CoreContainer thisCCRef = this;
// Init the Jersey app once all CC endpoints have been registered
containerHandlers
.getJerseyEndpoints()
.register(
new AbstractBinder() {
@Override
protected void configure() {
bindFactory(new InjectionFactories.SingletonFactory<>(thisCCRef))
.to(CoreContainer.class)
.in(Singleton.class);
}
})
.register(
new AbstractBinder() {
@Override
protected void configure() {
bindFactory(new InjectionFactories.SingletonFactory<>(nodeKeyPair))
.to(SolrNodeKeyPair.class)
.in(Singleton.class);
}
})
.register(
new AbstractBinder() {
@Override
protected void configure() {
bindFactory(new InjectionFactories.SingletonFactory<>(fileStore))
.to(DistribFileStore.class)
.in(Singleton.class);
}
})
.register(
new AbstractBinder() {
@Override
protected void configure() {
bindFactory(
new InjectionFactories.SingletonFactory<>(
coreAdminHandler.getCoreAdminAsyncTracker()))
.to(CoreAdminHandler.CoreAdminAsyncTracker.class)
.in(Singleton.class);
}
});
jerseyAppHandler = new ApplicationHandler(containerHandlers.getJerseyEndpoints());
}
final CoreContainer thisCCRef = this;
// Init the Jersey app once all CC endpoints have been registered
containerHandlers
.getJerseyEndpoints()
.register(
new AbstractBinder() {
@Override
protected void configure() {
bindFactory(new InjectionFactories.SingletonFactory<>(thisCCRef))
.to(CoreContainer.class)
.in(Singleton.class);
}
})
.register(
new AbstractBinder() {
@Override
protected void configure() {
bindFactory(new InjectionFactories.SingletonFactory<>(nodeKeyPair))
.to(SolrNodeKeyPair.class)
.in(Singleton.class);
}
})
.register(
new AbstractBinder() {
@Override
protected void configure() {
bindFactory(new InjectionFactories.SingletonFactory<>(fileStore))
.to(DistribFileStore.class)
.in(Singleton.class);
}
})
.register(
new AbstractBinder() {
@Override
protected void configure() {
bindFactory(
new InjectionFactories.SingletonFactory<>(
coreAdminHandler.getCoreAdminAsyncTracker()))
.to(CoreAdminHandler.CoreAdminAsyncTracker.class)
.in(Singleton.class);
}
});
jerseyAppHandler = new ApplicationHandler(containerHandlers.getJerseyEndpoints());

// Do Node setup logic after all handlers have been registered.
if (isZooKeeperAware()) {
Expand Down
5 changes: 2 additions & 3 deletions solr/core/src/java/org/apache/solr/core/PluginBag.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
import org.apache.solr.common.SolrException;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.handler.RequestHandlerBase;
import org.apache.solr.handler.api.V2ApiUtils;
import org.apache.solr.handler.component.SearchComponent;
import org.apache.solr.jersey.APIConfigProvider;
import org.apache.solr.jersey.APIConfigProviderBinder;
Expand Down Expand Up @@ -89,7 +88,7 @@ public JaxrsResourceToHandlerMappings getJaxrsRegistry() {

/** Pass needThreadSafety=true if plugins can be added and removed concurrently with lookups. */
public PluginBag(Class<T> klass, SolrCore core, boolean needThreadSafety) {
if (klass == SolrRequestHandler.class && V2ApiUtils.isEnabled()) {
if (klass == SolrRequestHandler.class) {
this.loadV2ApisIfPresent = true;
this.apiBag = new ApiBag(core != null);
this.jaxrsResourceRegistry = new JaxrsResourceToHandlerMappings();
Expand Down Expand Up @@ -243,7 +242,7 @@ public PluginHolder<T> put(String name, PluginHolder<T> plugin) {
if (registerApi == null) registerApi = apiSupport.registerV2();
if (disableHandler == null) disableHandler = !apiSupport.registerV1();

if (registerApi && V2ApiUtils.isEnabled()) {
if (registerApi) {
Collection<Api> apis = apiSupport.getApis();
if (apis != null) {
Map<String, String> nameSubstitutes = singletonMap(HANDLER_NAME, name);
Expand Down
31 changes: 13 additions & 18 deletions solr/core/src/java/org/apache/solr/core/SolrCore.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,6 @@
import org.apache.solr.handler.IndexFetcher;
import org.apache.solr.handler.RequestHandlerBase;
import org.apache.solr.handler.SolrConfigHandler;
import org.apache.solr.handler.api.V2ApiUtils;
import org.apache.solr.handler.component.HighlightComponent;
import org.apache.solr.handler.component.SearchComponent;
import org.apache.solr.logging.MDCLoggingContext;
Expand Down Expand Up @@ -1156,23 +1155,19 @@ protected SolrCore(
updateProcessorChains = loadUpdateProcessorChains();
reqHandlers = new RequestHandlers(this);
reqHandlers.initHandlersFromConfig(solrConfig);
if (V2ApiUtils.isEnabled()) {
final String effectiveConfigSetId = configSet.getName() + "-" + solrConfig.effectiveId();
jerseyAppHandler =
coreContainer
.getJerseyAppHandlerCache()
.computeIfAbsent(
effectiveConfigSetId,
() -> {
log.debug(
"Creating Jersey ApplicationHandler for 'effective solrConfig' [{}]",
effectiveConfigSetId);
return new ApplicationHandler(
reqHandlers.getRequestHandlers().getJerseyEndpoints());
});
} else {
jerseyAppHandler = null;
}
final String effectiveConfigSetId = configSet.getName() + "-" + solrConfig.effectiveId();
jerseyAppHandler =
coreContainer
.getJerseyAppHandlerCache()
.computeIfAbsent(
effectiveConfigSetId,
() -> {
log.debug(
"Creating Jersey ApplicationHandler for 'effective solrConfig' [{}]",
effectiveConfigSetId);
return new ApplicationHandler(
reqHandlers.getRequestHandlers().getJerseyEndpoints());
});

// cause the executor to stall so firstSearcher events won't fire
// until after inform() has been called for all components.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import org.apache.solr.client.api.model.SolrJerseyResponse;
import org.apache.solr.common.MapWriter.EntryWriter;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.EnvUtils;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.common.util.Utils;
Expand All @@ -42,10 +41,6 @@ private V2ApiUtils() {
/* Private ctor prevents instantiation */
}

public static boolean isEnabled() {
return EnvUtils.getPropertyAsBool("solr.api.v2.enabled", true);
}

public static void flattenMapWithPrefix(
Map<String, Object> toFlatten, Map<String, Object> destination, String additionalPrefix) {
if (toFlatten == null || toFlatten.isEmpty() || destination == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import org.apache.solr.common.util.ExecutorUtil;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.NodeRoles;
import org.apache.solr.handler.api.V2ApiUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -49,8 +48,6 @@ public class SolrDispatchFilter extends CoreContainerAwareHttpFilter {

private HttpSolrCallFactory solrCallFactory;

public final boolean isV2Enabled = V2ApiUtils.isEnabled();

/**
* Enum to define action that needs to be processed. PASSTHROUGH: Pass through to another filter
* via webapp. FORWARD: Forward rewritten URI (without path prefix and core/collection name) to
Expand Down Expand Up @@ -189,7 +186,7 @@ default HttpSolrCall createInstance(
HttpServletRequest request,
HttpServletResponse response,
boolean retry) {
if (filter.isV2Enabled && (path.startsWith("/____v2/") || path.equals("/____v2"))) {
if (path.startsWith("/____v2/") || path.equals("/____v2")) {
return new V2HttpCall(filter, cores, request, response, retry);
} else {
return new HttpSolrCall(filter, cores, request, response, retry);
Expand Down
13 changes: 0 additions & 13 deletions solr/core/src/test/org/apache/solr/handler/api/V2ApiUtilsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,6 @@

public class V2ApiUtilsTest extends SolrTestCaseJ4 {

@Test
public void testReadsEnableV2ApiSysprop() {
System.clearProperty("solr.api.v2.enabled");
assertTrue("v2 API should be enabled if sysprop not specified", V2ApiUtils.isEnabled());

System.setProperty("solr.api.v2.enabled", "true");
assertTrue("v2 API should be enabled if sysprop explicitly enables it", V2ApiUtils.isEnabled());

System.setProperty("solr.api.v2.enabled", "false");
assertFalse(
"v2 API should be disabled if sysprop explicitly disables it", V2ApiUtils.isEnabled());
}

@Test
public void testConvertsWtToMediaTypeString() {
assertEquals("someDefault", V2ApiUtils.getMediaTypeFromWtParam(SolrParams.of(), "someDefault"));
Expand Down
4 changes: 2 additions & 2 deletions solr/packaging/test/test_start_solr.bats
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ teardown() {
}

@test "deprecated system properties converted to modern properties" {
solr start -Ddisable.v2.api=true
assert_file_contains "${SOLR_LOGS_DIR}/solr.log" 'You are passing in deprecated system property disable.v2.api and should upgrade to using solr.api.v2.enabled instead.'
solr start -Ddisable.config.edit=true
assert_file_contains "${SOLR_LOGS_DIR}/solr.log" 'You are passing in deprecated system property disable.config.edit and should upgrade to using solr.api.config.edit.enabled instead.'
}

@test "start with custom jetty options" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ NOTE: Properties marked with "!" indicate inverted meaning between pre Solr 10 a

|solr.api.config.edit.enabled|!disable.config.edit|true|Controls whether configuration editing via API is enabled. When set to `true`, configuration editing is enabled.

|solr.api.v2.enabled|!disable.v2.api|true|Controls whether the V2 API is enabled. When set to `true`, the V2 API is enabled.

|solr.auth.jwt.outbound.http.enabled|solr.auth.jwt.allowOutboundHttp|false|Controls whether JWT authentication for outbound HTTP connections is enabled.

|solr.auth.superuser|solr.authorization.superuser|solr|Specifies the superuser for authorization. This user has all permissions when using SASL authentication.
Expand Down Expand Up @@ -159,13 +157,13 @@ Many Solr properties follow a standard naming convention. Newer properties typic

System properties can be set in several ways:

1. JVM command line arguments using `-D`: `-Dsolr.api.v2.enabled=true`
1. JVM command line arguments using `-D`: `-Dsolr.api.config.edit.enabled=true`
2. In `solr.in.sh` (Unix) or `solr.in.cmd` (Windows) using environment variables
3. Through environment variables (with appropriate naming conventions)

Environment variables can also be used to set these properties.
You may find this useful in environments such as Docker.
Environment variables should be uppercase with dot notations equivalents, e.g. `SOLR_API_V2_ENABLED` for the property `solr.api.v2.enabled`.
Environment variables should be uppercase with dot notations equivalents, e.g. `SOLR_API_CONFIG_EDIT_ENABLED` for the property `solr.api.config.edit.enabled`.

== See Also

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
The v2 API is a modernized self-documenting API interface covering most current Solr APIs.
It is anticipated that once the v2 API reaches full coverage, and Solr-internal API usages like SolrJ and the Admin UI have been converted from the old API to the v2 API, the old API will eventually be retired.
Today, the two API styles coexist, and all the old APIs will continue to work without any change.
You can disable all v2 API endpoints if desired by starting your servers with this system property: `-Dsolr.api.v2.enabled=false`.

NOTE: The v2 API is classified as "experimental".
It may change in backwards-incompatible ways as it evolves to cover additional functionality.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ This compatibility safeguard can be disabled via the environment variable `SOLR_

Solr 10.0 requires at least Java 21, while SolrJ 10.0 requires at least Java 17.

== Solr 10.1

=== v2 API
Starting in Solr 10.1 it is no longer possible for users to disable the v2 API by use of the `solr.api.v2.enabled` system property, and the Solr server and tooling (`bin/solr`, Admin UI, etc.) will start using these APIs internally.

Former users of `solr.api.v2.enabled` looking to upgrade to Solr 10.1 or newer should take care to review any custom `RuleBasedAuthorizationPlugin` permissions and ensure that v2 API paths are adequately secured.

Users who deploy a proxy in front of Solr should also review this setup to ensure that it allows access to the v2 API root path, `/api`.

== Solr 10.0

=== Solr Jetty parameters
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
solr.admin.handler.systeminfo.dns.reverse.lookup.enabled=!solr.dns.prevent.reverse.lookup

solr.api.config.edit.enabled=!disable.config.edit
solr.api.v2.enabled=!disable.v2.api

solr.auth.jwt.outbound.http.enabled=solr.auth.jwt.allow.outbound.http
solr.auth.superuser=solr.authorization.superuser
Expand Down
Loading