diff --git a/changelog/unreleased/SOLR-18163-remove-v2-disabling-sysprop.yml b/changelog/unreleased/SOLR-18163-remove-v2-disabling-sysprop.yml new file mode 100644 index 000000000000..7ab3bc801bff --- /dev/null +++ b/changelog/unreleased/SOLR-18163-remove-v2-disabling-sysprop.yml @@ -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 diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java index 9ca9b377cb2e..da91ce211995 100644 --- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java +++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java @@ -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; @@ -721,7 +720,7 @@ public ObjectCache getObjectCache() { return objectCache; } - private void registerV2ApiIfEnabled(Object apiObject) { + private void registerV2Api(Object apiObject) { if (apiObject == null || containerHandlers.getApiBag() == null) { return; } @@ -729,7 +728,7 @@ private void registerV2ApiIfEnabled(Object apiObject) { containerHandlers.getApiBag().registerObject(apiObject); } - private void registerV2ApiIfEnabled(Class clazz) { + private void registerV2Api(Class clazz) { if (containerHandlers.getJerseyEndpoints() == null) { return; } @@ -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); @@ -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 /* @@ -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 @@ -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()) { diff --git a/solr/core/src/java/org/apache/solr/core/PluginBag.java b/solr/core/src/java/org/apache/solr/core/PluginBag.java index 5583546e22f8..a751f342e34f 100644 --- a/solr/core/src/java/org/apache/solr/core/PluginBag.java +++ b/solr/core/src/java/org/apache/solr/core/PluginBag.java @@ -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; @@ -89,7 +88,7 @@ public JaxrsResourceToHandlerMappings getJaxrsRegistry() { /** Pass needThreadSafety=true if plugins can be added and removed concurrently with lookups. */ public PluginBag(Class 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(); @@ -243,7 +242,7 @@ public PluginHolder put(String name, PluginHolder plugin) { if (registerApi == null) registerApi = apiSupport.registerV2(); if (disableHandler == null) disableHandler = !apiSupport.registerV1(); - if (registerApi && V2ApiUtils.isEnabled()) { + if (registerApi) { Collection apis = apiSupport.getApis(); if (apis != null) { Map nameSubstitutes = singletonMap(HANDLER_NAME, name); diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java b/solr/core/src/java/org/apache/solr/core/SolrCore.java index 93699357426b..01b8e36b5628 100644 --- a/solr/core/src/java/org/apache/solr/core/SolrCore.java +++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java @@ -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; @@ -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. diff --git a/solr/core/src/java/org/apache/solr/handler/api/V2ApiUtils.java b/solr/core/src/java/org/apache/solr/handler/api/V2ApiUtils.java index 737a63cef1a1..25758ccee038 100644 --- a/solr/core/src/java/org/apache/solr/handler/api/V2ApiUtils.java +++ b/solr/core/src/java/org/apache/solr/handler/api/V2ApiUtils.java @@ -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; @@ -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 toFlatten, Map destination, String additionalPrefix) { if (toFlatten == null || toFlatten.isEmpty() || destination == null) { diff --git a/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java index 300c54ac5621..c8381c109504 100644 --- a/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java +++ b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java @@ -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; @@ -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 @@ -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); diff --git a/solr/core/src/test/org/apache/solr/handler/api/V2ApiUtilsTest.java b/solr/core/src/test/org/apache/solr/handler/api/V2ApiUtilsTest.java index 9c00837a4344..95750839dff5 100644 --- a/solr/core/src/test/org/apache/solr/handler/api/V2ApiUtilsTest.java +++ b/solr/core/src/test/org/apache/solr/handler/api/V2ApiUtilsTest.java @@ -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")); diff --git a/solr/packaging/test/test_start_solr.bats b/solr/packaging/test/test_start_solr.bats index 6d978bd146df..ef25ea32ee79 100644 --- a/solr/packaging/test/test_start_solr.bats +++ b/solr/packaging/test/test_start_solr.bats @@ -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" { diff --git a/solr/solr-ref-guide/modules/configuration-guide/pages/solr-properties.adoc b/solr/solr-ref-guide/modules/configuration-guide/pages/solr-properties.adoc index 7cb304cd2f7d..837c7282b5ed 100644 --- a/solr/solr-ref-guide/modules/configuration-guide/pages/solr-properties.adoc +++ b/solr/solr-ref-guide/modules/configuration-guide/pages/solr-properties.adoc @@ -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. @@ -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 diff --git a/solr/solr-ref-guide/modules/configuration-guide/pages/v2-api.adoc b/solr/solr-ref-guide/modules/configuration-guide/pages/v2-api.adoc index a9e1e8cff3c1..844297cdce09 100644 --- a/solr/solr-ref-guide/modules/configuration-guide/pages/v2-api.adoc +++ b/solr/solr-ref-guide/modules/configuration-guide/pages/v2-api.adoc @@ -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. diff --git a/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-10.adoc b/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-10.adoc index 86420c2815ae..6a9ff982707e 100644 --- a/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-10.adoc +++ b/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-10.adoc @@ -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 diff --git a/solr/solrj/src/resources/DeprecatedSystemPropertyMappings.properties b/solr/solrj/src/resources/DeprecatedSystemPropertyMappings.properties index f8d84642505d..662ea883e5ac 100644 --- a/solr/solrj/src/resources/DeprecatedSystemPropertyMappings.properties +++ b/solr/solrj/src/resources/DeprecatedSystemPropertyMappings.properties @@ -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