diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 3fb6a6c446a..41c21f7f90b 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -72,6 +72,8 @@ New Features --------------------- * SOLR-16654: Add support for node-level caches (Michael Gibney) +* SOLR-16954: Make Circuit Breakers available for Update Requests (janhoy, Christine Poerschke, Pierre Salagnac) + * SOLR-15771: bin/auth creates reasonable roles and permissions for security: 'search', 'index', 'admin', and 'superadmin' and assigns user superadmin role. (Eric Pugh, janhoy) Improvements @@ -115,6 +117,13 @@ Improvements dedicated thread pool. Backup, Restore and Split are expensive operations. (Pierre Salagnac, David Smiley) +* SOLR-16964: The solr.jetty.ssl.sniHostCheck option now defaults to the value of SOLR_SSL_CHECK_PEER_NAME, if it is provided. + This will enable client and server hostName check settings to be governed by the same environment variable. + If users want separate client/server settings, they can manually override the solr.jetty.ssl.sniHostCheck option in SOLR_OPTS. (Houston Putman) + +* SOLR-16970: SOLR_OPTS is now able to override options set by the Solr control scripts, "bin/solr" and "bin/solr.cmd". (Houston Putman) + + Optimizations --------------------- @@ -157,6 +166,13 @@ Bug Fixes * SOLR-16958: Fix spurious warning about LATEST luceneMatchVersion (Colvin Cowie) +* SOLR-16955: Tracing v2 apis breaks SecurityConfHandler (Alex Deparvu, David Smiley) + +* SOLR-16044: SlowRequest logging is no longer disabled if SolrCore logger set to ERROR (janhoy, hossman) + +* SOLR-16415: asyncId must not have '/'; enforce this. Enhance ZK cleanup to process directories + instead of fail. (David Smiley, Paul McArthur) + Dependency Upgrades --------------------- diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/AddReplicaPropertyApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/AddReplicaPropertyApi.java index 9403358770a..8dce6a28e54 100644 --- a/solr/api/src/java/org/apache/solr/client/api/endpoint/AddReplicaPropertyApi.java +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/AddReplicaPropertyApi.java @@ -17,15 +17,12 @@ package org.apache.solr.client.api.endpoint; -import static org.apache.solr.client.api.util.Constants.BINARY_CONTENT_TYPE_V2; - import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.parameters.RequestBody; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; import org.apache.solr.client.api.model.AddReplicaPropertyRequestBody; import org.apache.solr.client.api.model.SolrJerseyResponse; @@ -33,7 +30,6 @@ public interface AddReplicaPropertyApi { @PUT - @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2}) @Operation( summary = "Adds a property to the specified replica", tags = {"replica-properties"}) diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/AliasPropertyApis.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/AliasPropertyApis.java index d993997d111..7bc167a2b36 100644 --- a/solr/api/src/java/org/apache/solr/client/api/endpoint/AliasPropertyApis.java +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/AliasPropertyApis.java @@ -16,8 +16,6 @@ */ package org.apache.solr.client.api.endpoint; -import static org.apache.solr.client.api.util.Constants.BINARY_CONTENT_TYPE_V2; - import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.parameters.RequestBody; @@ -26,8 +24,6 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; import org.apache.solr.client.api.model.GetAliasPropertyResponse; import org.apache.solr.client.api.model.GetAllAliasPropertiesResponse; import org.apache.solr.client.api.model.SolrJerseyResponse; @@ -39,7 +35,6 @@ public interface AliasPropertyApis { @GET - @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2}) @Operation( summary = "Get properties for a collection alias.", tags = {"alias-properties"}) @@ -49,7 +44,6 @@ GetAllAliasPropertiesResponse getAllAliasProperties( @GET @Path("/{propName}") - @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2}) @Operation( summary = "Get a specific property for a collection alias.", tags = {"alias-properties"}) @@ -59,7 +53,6 @@ GetAliasPropertyResponse getAliasProperty( throws Exception; @PUT - @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2}) @Operation( summary = "Update properties for a collection alias.", tags = {"alias-properties"}) @@ -71,7 +64,6 @@ SolrJerseyResponse updateAliasProperties( @PUT @Path("/{propName}") - @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2}) @Operation( summary = "Update a specific property for a collection alias.", tags = {"alias-properties"}) @@ -84,7 +76,6 @@ SolrJerseyResponse createOrUpdateAliasProperty( @DELETE @Path("/{propName}") - @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2}) @Operation( summary = "Delete a specific property for a collection alias.", tags = {"alias-properties"}) diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/BalanceReplicasApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/BalanceReplicasApi.java new file mode 100644 index 00000000000..d05719efea8 --- /dev/null +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/BalanceReplicasApi.java @@ -0,0 +1,36 @@ +/* + * 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.api.endpoint; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import org.apache.solr.client.api.model.BalanceReplicasRequestBody; +import org.apache.solr.client.api.model.SolrJerseyResponse; + +@Path("cluster/replicas/balance") +public interface BalanceReplicasApi { + @POST + @Operation( + summary = "Balance Replicas across the given set of Nodes.", + tags = {"cluster"}) + SolrJerseyResponse balanceReplicas( + @RequestBody(description = "Contains user provided parameters") + BalanceReplicasRequestBody requestBody) + throws Exception; +} diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteAliasApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteAliasApi.java index 24759ead2ad..05d32068683 100644 --- a/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteAliasApi.java +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteAliasApi.java @@ -17,14 +17,11 @@ package org.apache.solr.client.api.endpoint; -import static org.apache.solr.client.api.util.Constants.BINARY_CONTENT_TYPE_V2; - import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import javax.ws.rs.DELETE; import javax.ws.rs.Path; import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import org.apache.solr.client.api.model.SolrJerseyResponse; @@ -32,7 +29,6 @@ public interface DeleteAliasApi { @DELETE - @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2}) @Operation( summary = "Deletes an alias by its name", tags = {"aliases"}) diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteCollectionApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteCollectionApi.java index 9e28e7b1722..8cf0010066e 100644 --- a/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteCollectionApi.java +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteCollectionApi.java @@ -17,14 +17,11 @@ package org.apache.solr.client.api.endpoint; -import static org.apache.solr.client.api.util.Constants.BINARY_CONTENT_TYPE_V2; - import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import javax.ws.rs.DELETE; import javax.ws.rs.Path; import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import org.apache.solr.client.api.model.SubResponseAccumulatingJerseyResponse; @@ -32,7 +29,6 @@ public interface DeleteCollectionApi { @DELETE - @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2}) @Operation( summary = "Deletes a collection from SolrCloud", tags = {"collections"}) diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteCollectionBackupApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteCollectionBackupApi.java index 1135e4d89d7..e53f8ea96d7 100644 --- a/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteCollectionBackupApi.java +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteCollectionBackupApi.java @@ -20,7 +20,6 @@ import static org.apache.solr.client.api.model.Constants.ASYNC; import static org.apache.solr.client.api.model.Constants.BACKUP_LOCATION; import static org.apache.solr.client.api.model.Constants.BACKUP_REPOSITORY; -import static org.apache.solr.client.api.util.Constants.BINARY_CONTENT_TYPE_V2; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.parameters.RequestBody; @@ -28,7 +27,6 @@ import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import org.apache.solr.client.api.model.BackupDeletionResponseBody; import org.apache.solr.client.api.model.PurgeUnusedFilesRequestBody; @@ -39,7 +37,6 @@ public interface DeleteCollectionBackupApi { @Path("/versions/{backupId}") @DELETE - @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2}) @Operation( summary = "Delete incremental backup point by ID", tags = {"collection-backups"}) @@ -54,7 +51,6 @@ BackupDeletionResponseBody deleteSingleBackupById( @Path("/versions") @DELETE - @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2}) @Operation( summary = "Delete all incremental backup points older than the most recent N", tags = {"collection-backups"}) @@ -69,7 +65,6 @@ BackupDeletionResponseBody deleteMultipleBackupsByRecency( @Path("/purgeUnused") @PUT - @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2}) @Operation( summary = "Garbage collect orphaned incremental backup files", tags = {"collection-backups"}) diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteCollectionSnapshotApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteCollectionSnapshotApi.java index f9d1afc8387..fb77fbd6dc8 100644 --- a/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteCollectionSnapshotApi.java +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteCollectionSnapshotApi.java @@ -17,14 +17,11 @@ package org.apache.solr.client.api.endpoint; -import static org.apache.solr.client.api.util.Constants.BINARY_CONTENT_TYPE_V2; - import io.swagger.v3.oas.annotations.Parameter; import javax.ws.rs.DELETE; import javax.ws.rs.DefaultValue; import javax.ws.rs.Path; import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import org.apache.solr.client.api.model.DeleteCollectionSnapshotResponse; @@ -33,7 +30,6 @@ public interface DeleteCollectionSnapshotApi { /** This API is analogous to V1's (POST /solr/admin/collections?action=DELETESNAPSHOT) */ @DELETE @Path("/collections/{collName}/snapshots/{snapshotName}") - @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2}) DeleteCollectionSnapshotResponse deleteSnapshot( @Parameter(description = "The name of the collection.", required = true) @PathParam("collName") diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteNodeApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteNodeApi.java index 323b70dbabb..0495d298cb9 100644 --- a/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteNodeApi.java +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteNodeApi.java @@ -17,15 +17,12 @@ package org.apache.solr.client.api.endpoint; -import static org.apache.solr.client.api.util.Constants.BINARY_CONTENT_TYPE_V2; - import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.parameters.RequestBody; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; import org.apache.solr.client.api.model.DeleteNodeRequestBody; import org.apache.solr.client.api.model.SolrJerseyResponse; @@ -33,7 +30,6 @@ public interface DeleteNodeApi { @POST - @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2}) @Operation( summary = "Delete all replicas off of the specified SolrCloud node", tags = {"node"}) diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteReplicaApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteReplicaApi.java index a728c12aadc..f17abdfab26 100644 --- a/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteReplicaApi.java +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteReplicaApi.java @@ -24,14 +24,12 @@ import static org.apache.solr.client.api.model.Constants.DELETE_INSTANCE_DIR; import static org.apache.solr.client.api.model.Constants.FOLLOW_ALIASES; import static org.apache.solr.client.api.model.Constants.ONLY_IF_DOWN; -import static org.apache.solr.client.api.util.Constants.BINARY_CONTENT_TYPE_V2; import io.swagger.v3.oas.annotations.Operation; import javax.ws.rs.DELETE; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import org.apache.solr.client.api.model.ScaleCollectionRequestBody; import org.apache.solr.client.api.model.SubResponseAccumulatingJerseyResponse; @@ -46,7 +44,6 @@ public interface DeleteReplicaApi { @DELETE @Path("/shards/{shardName}/replicas/{replicaName}") - @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2}) @Operation( summary = "Delete an single replica by name", tags = {"replicas"}) @@ -65,7 +62,6 @@ SubResponseAccumulatingJerseyResponse deleteReplicaByName( @DELETE @Path("/shards/{shardName}/replicas") - @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2}) @Operation( summary = "Delete one or more replicas from the specified collection and shard", tags = {"replicas"}) @@ -84,7 +80,6 @@ SubResponseAccumulatingJerseyResponse deleteReplicasByCount( @PUT @Path("/scale") - @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2}) @Operation( summary = "Scale the replica count for all shards in the specified collection", tags = {"replicas"}) diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteReplicaPropertyApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteReplicaPropertyApi.java index 15d98564ffe..8e8f52fd33a 100644 --- a/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteReplicaPropertyApi.java +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/DeleteReplicaPropertyApi.java @@ -17,14 +17,11 @@ package org.apache.solr.client.api.endpoint; -import static org.apache.solr.client.api.util.Constants.BINARY_CONTENT_TYPE_V2; - import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import javax.ws.rs.DELETE; import javax.ws.rs.Path; import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; import org.apache.solr.client.api.model.SolrJerseyResponse; /** @@ -36,7 +33,6 @@ public interface DeleteReplicaPropertyApi { @DELETE - @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2}) @Operation( summary = "Delete an existing replica property", tags = {"replica-properties"}) diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/ForceLeaderApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/ForceLeaderApi.java new file mode 100644 index 00000000000..2a0336a2d3d --- /dev/null +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/ForceLeaderApi.java @@ -0,0 +1,34 @@ +/* + * 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.api.endpoint; + +import io.swagger.v3.oas.annotations.Operation; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import org.apache.solr.client.api.model.SolrJerseyResponse; + +/** V2 API definition for triggering a leader election on a particular collection and shard. */ +@Path("/collections/{collectionName}/shards/{shardName}/force-leader") +public interface ForceLeaderApi { + @POST + @Operation( + summary = "Force leader election to occur on the specified collection and shard", + tags = {"shards"}) + SolrJerseyResponse forceShardLeader( + @PathParam("collectionName") String collectionName, @PathParam("shardName") String shardName); +} diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/GetPublicKeyApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/GetPublicKeyApi.java new file mode 100644 index 00000000000..562a2945d9e --- /dev/null +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/GetPublicKeyApi.java @@ -0,0 +1,33 @@ +/* + * 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.api.endpoint; + +import io.swagger.v3.oas.annotations.Operation; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import org.apache.solr.client.api.model.PublicKeyResponse; + +/** V2 API definition to fetch the public key of the receiving node. */ +@Path("/node/key") +public interface GetPublicKeyApi { + + @GET + @Operation( + summary = "Retrieve the public key of the receiving Solr node.", + tags = {"node"}) + PublicKeyResponse getPublicKey(); +} diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/ListAliasesApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/ListAliasesApi.java index eaeddf7bd2a..3f786b9d5e7 100644 --- a/solr/api/src/java/org/apache/solr/client/api/endpoint/ListAliasesApi.java +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/ListAliasesApi.java @@ -16,15 +16,11 @@ */ package org.apache.solr.client.api.endpoint; -import static org.apache.solr.client.api.util.Constants.BINARY_CONTENT_TYPE_V2; - import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; import org.apache.solr.client.api.model.GetAliasByNameResponse; import org.apache.solr.client.api.model.ListAliasesResponse; @@ -33,7 +29,6 @@ public interface ListAliasesApi { @GET - @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2}) @Operation( summary = "List the existing collection aliases.", tags = {"aliases"}) @@ -41,7 +36,6 @@ public interface ListAliasesApi { @GET @Path("/{aliasName}") - @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2}) @Operation( summary = "Get details for a specific collection alias.", tags = {"aliases"}) diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/ListCollectionBackupsApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/ListCollectionBackupsApi.java index 24701fb18cc..59657085b95 100644 --- a/solr/api/src/java/org/apache/solr/client/api/endpoint/ListCollectionBackupsApi.java +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/ListCollectionBackupsApi.java @@ -18,14 +18,12 @@ import static org.apache.solr.client.api.model.Constants.BACKUP_LOCATION; import static org.apache.solr.client.api.model.Constants.BACKUP_REPOSITORY; -import static org.apache.solr.client.api.util.Constants.BINARY_CONTENT_TYPE_V2; import io.swagger.v3.oas.annotations.Operation; import java.io.IOException; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import org.apache.solr.client.api.model.ListCollectionBackupsResponse; @@ -34,7 +32,6 @@ public interface ListCollectionBackupsApi { @GET - @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2}) @Operation( summary = "List existing incremental backups at the specified location.", tags = {"collection-backups"}) diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/ListCollectionsApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/ListCollectionsApi.java index fabb670a4b5..bb8baa210f3 100644 --- a/solr/api/src/java/org/apache/solr/client/api/endpoint/ListCollectionsApi.java +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/ListCollectionsApi.java @@ -16,18 +16,14 @@ */ package org.apache.solr.client.api.endpoint; -import static org.apache.solr.client.api.util.Constants.BINARY_CONTENT_TYPE_V2; - import io.swagger.v3.oas.annotations.Operation; import javax.ws.rs.GET; import javax.ws.rs.Path; -import javax.ws.rs.Produces; import org.apache.solr.client.api.model.ListCollectionsResponse; @Path("/collections") public interface ListCollectionsApi { @GET - @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2}) @Operation( summary = "List all collections in this Solr cluster", tags = {"collections"}) diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/ListConfigsetsApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/ListConfigsetsApi.java index c1e99b805a1..b00a47cac19 100644 --- a/solr/api/src/java/org/apache/solr/client/api/endpoint/ListConfigsetsApi.java +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/ListConfigsetsApi.java @@ -19,14 +19,12 @@ import io.swagger.v3.oas.annotations.Operation; import javax.ws.rs.GET; import javax.ws.rs.Path; -import javax.ws.rs.Produces; import org.apache.solr.client.api.model.ListConfigsetsResponse; /** V2 API definition for listing configsets. */ @Path("/cluster/configs") public interface ListConfigsetsApi { @GET - @Produces({"application/json", "application/javabin"}) @Operation( summary = "List the configsets available to Solr.", tags = {"configsets"}) diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/ReloadCollectionApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/ReloadCollectionApi.java index 39f27d2911d..2bf85b90626 100644 --- a/solr/api/src/java/org/apache/solr/client/api/endpoint/ReloadCollectionApi.java +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/ReloadCollectionApi.java @@ -16,14 +16,10 @@ */ package org.apache.solr.client.api.endpoint; -import static org.apache.solr.client.api.util.Constants.BINARY_CONTENT_TYPE_V2; - import io.swagger.v3.oas.annotations.Operation; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; import org.apache.solr.client.api.model.ReloadCollectionRequestBody; import org.apache.solr.client.api.model.SubResponseAccumulatingJerseyResponse; @@ -31,7 +27,6 @@ @Path("/collections/{collectionName}/reload") public interface ReloadCollectionApi { @POST - @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2}) @Operation( summary = "Reload all cores in the specified collection.", tags = {"collections"}) diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/RenameCollectionApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/RenameCollectionApi.java new file mode 100644 index 00000000000..6eee0d431f2 --- /dev/null +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/RenameCollectionApi.java @@ -0,0 +1,37 @@ +/* + * 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.api.endpoint; + +import io.swagger.v3.oas.annotations.Operation; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import org.apache.solr.client.api.model.RenameCollectionRequestBody; +import org.apache.solr.client.api.model.SubResponseAccumulatingJerseyResponse; + +/** V2 API definition for "renaming" an existing collection */ +@Path("/collections/{collectionName}/rename") +public interface RenameCollectionApi { + + @POST + @Operation( + summary = "Rename a SolrCloud collection", + tags = {"collections"}) + SubResponseAccumulatingJerseyResponse renameCollection( + @PathParam("collectionName") String collectionName, RenameCollectionRequestBody requestBody) + throws Exception; +} diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/ReplaceNodeApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/ReplaceNodeApi.java new file mode 100644 index 00000000000..56762fa524d --- /dev/null +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/ReplaceNodeApi.java @@ -0,0 +1,45 @@ +/* + * 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.api.endpoint; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import org.apache.solr.client.api.model.ReplaceNodeRequestBody; +import org.apache.solr.client.api.model.SolrJerseyResponse; + +/** + * V2 API definition for recreating replicas in one node (the source) on another node(s) (the + * target). + */ +@Path("cluster/nodes/{sourceNodeName}/replace/") +public interface ReplaceNodeApi { + @POST + @Operation( + summary = "'Replace' a specified node by moving all replicas elsewhere", + tags = {"node"}) + SolrJerseyResponse replaceNode( + @Parameter(description = "The name of the node to be replaced.", required = true) + @PathParam("sourceNodeName") + String sourceNodeName, + @RequestBody(description = "Contains user provided parameters", required = true) + ReplaceNodeRequestBody requestBody) + throws Exception; +} diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/SyncShardApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/SyncShardApi.java new file mode 100644 index 00000000000..1e9805be65a --- /dev/null +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/SyncShardApi.java @@ -0,0 +1,37 @@ +/* + * 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.api.endpoint; + +import io.swagger.v3.oas.annotations.Operation; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import org.apache.solr.client.api.model.SolrJerseyResponse; + +/** + * V2 API definition for triggering a shard-sync operation within a particular collection and shard. + */ +@Path("/collections/{collectionName}/shards/{shardName}/sync") +public interface SyncShardApi { + @POST + @Operation( + summary = "Trigger a 'sync' operation for the specified shard", + tags = {"shards"}) + SolrJerseyResponse syncShard( + @PathParam("collectionName") String collectionName, @PathParam("shardName") String shardName) + throws Exception; +} diff --git a/solr/api/src/java/org/apache/solr/client/api/model/BalanceReplicasRequestBody.java b/solr/api/src/java/org/apache/solr/client/api/model/BalanceReplicasRequestBody.java new file mode 100644 index 00000000000..f270a48b269 --- /dev/null +++ b/solr/api/src/java/org/apache/solr/client/api/model/BalanceReplicasRequestBody.java @@ -0,0 +1,50 @@ +/* + * 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.api.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import java.util.Set; + +public class BalanceReplicasRequestBody { + + public BalanceReplicasRequestBody() {} + + public BalanceReplicasRequestBody(Set nodes, Boolean waitForFinalState, String async) { + this.nodes = nodes; + this.waitForFinalState = waitForFinalState; + this.async = async; + } + + @Schema( + description = + "The set of nodes across which replicas will be balanced. Defaults to all live data nodes.") + @JsonProperty(value = "nodes") + public Set nodes; + + @Schema( + description = + "If true, the request will complete only when all affected replicas become active. " + + "If false, the API will return the status of the single action, which may be " + + "before the new replica is online and active.") + @JsonProperty("waitForFinalState") + public Boolean waitForFinalState = false; + + @Schema(description = "Request ID to track this action which will be processed asynchronously.") + @JsonProperty("async") + public String async; +} diff --git a/solr/api/src/java/org/apache/solr/client/api/model/PublicKeyResponse.java b/solr/api/src/java/org/apache/solr/client/api/model/PublicKeyResponse.java new file mode 100644 index 00000000000..d561b16fcbb --- /dev/null +++ b/solr/api/src/java/org/apache/solr/client/api/model/PublicKeyResponse.java @@ -0,0 +1,26 @@ +/* + * 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.api.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; + +public class PublicKeyResponse extends SolrJerseyResponse { + @JsonProperty("key") + @Schema(description = "The public key of the receiving Solr node.") + public String key; +} diff --git a/solr/api/src/java/org/apache/solr/client/api/model/RenameCollectionRequestBody.java b/solr/api/src/java/org/apache/solr/client/api/model/RenameCollectionRequestBody.java new file mode 100644 index 00000000000..145618d029e --- /dev/null +++ b/solr/api/src/java/org/apache/solr/client/api/model/RenameCollectionRequestBody.java @@ -0,0 +1,31 @@ +/* + * 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.api.model; + +import static org.apache.solr.client.api.model.Constants.ASYNC; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class RenameCollectionRequestBody { + @JsonProperty(required = true) + public String to; + + @JsonProperty(ASYNC) + public String async; + + @JsonProperty public Boolean followAliases; +} diff --git a/solr/api/src/java/org/apache/solr/client/api/model/ReplaceNodeRequestBody.java b/solr/api/src/java/org/apache/solr/client/api/model/ReplaceNodeRequestBody.java new file mode 100644 index 00000000000..303fd64e8db --- /dev/null +++ b/solr/api/src/java/org/apache/solr/client/api/model/ReplaceNodeRequestBody.java @@ -0,0 +1,50 @@ +/* + * 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.api.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; + +public class ReplaceNodeRequestBody { + + public ReplaceNodeRequestBody() {} + + public ReplaceNodeRequestBody(String targetNodeName, Boolean waitForFinalState, String async) { + this.targetNodeName = targetNodeName; + this.waitForFinalState = waitForFinalState; + this.async = async; + } + + @Schema( + description = + "The target node where replicas will be copied. If this parameter is not provided, Solr " + + "will identify nodes automatically based on policies or number of cores in each node.") + @JsonProperty("targetNodeName") + public String targetNodeName; + + @Schema( + description = + "If true, the request will complete only when all affected replicas become active. " + + "If false, the API will return the status of the single action, which may be " + + "before the new replica is online and active.") + @JsonProperty("waitForFinalState") + public Boolean waitForFinalState = false; + + @Schema(description = "Request ID to track this action which will be processed asynchronously.") + @JsonProperty("async") + public String async; +} diff --git a/solr/bin/solr b/solr/bin/solr index e11eec4e8d4..32a2465eccb 100644 --- a/solr/bin/solr +++ b/solr/bin/solr @@ -259,7 +259,7 @@ if [ "$SOLR_SSL_ENABLED" == "true" ]; then fi if [ -n "$SOLR_SSL_CHECK_PEER_NAME" ]; then - SOLR_SSL_OPTS+=" -Dsolr.ssl.checkPeerName=$SOLR_SSL_CHECK_PEER_NAME" + SOLR_SSL_OPTS+=" -Dsolr.ssl.checkPeerName=$SOLR_SSL_CHECK_PEER_NAME -Dsolr.jetty.ssl.sniHostCheck=$SOLR_SSL_CHECK_PEER_NAME" fi if [ -n "$SOLR_SSL_CLIENT_TRUST_STORE" ]; then @@ -628,7 +628,7 @@ function jetty_port() { function run_tool() { # shellcheck disable=SC2086 - "$JAVA" ${SOLR_TOOL_OPTS:-} $SOLR_SSL_OPTS $AUTHC_OPTS ${SOLR_ZK_CREDS_AND_ACLS:-} -Dsolr.install.dir="$SOLR_TIP" \ + "$JAVA" $SOLR_SSL_OPTS $AUTHC_OPTS ${SOLR_ZK_CREDS_AND_ACLS:-} ${SOLR_TOOL_OPTS:-} -Dsolr.install.dir="$SOLR_TIP" \ -Dlog4j.configurationFile="$DEFAULT_SERVER_DIR/resources/log4j2-console.xml" \ -classpath "$DEFAULT_SERVER_DIR/solr-webapp/webapp/WEB-INF/lib/*:$DEFAULT_SERVER_DIR/lib/ext/*:$DEFAULT_SERVER_DIR/lib/*" \ org.apache.solr.cli.SolrCLI "$@" @@ -742,7 +742,7 @@ function stop_solr() { if [ -n "$SOLR_PID" ]; then echo -e "Sending stop command to Solr running on port $SOLR_PORT ... waiting up to $SOLR_STOP_WAIT seconds to allow Jetty process $SOLR_PID to stop gracefully." # shellcheck disable=SC2086 - "$JAVA" ${SOLR_TOOL_OPTS:-} $SOLR_SSL_OPTS $AUTHC_OPTS -jar "$DIR/start.jar" "STOP.PORT=$THIS_STOP_PORT" "STOP.KEY=$STOP_KEY" --stop || true + "$JAVA" $SOLR_SSL_OPTS $AUTHC_OPTS ${SOLR_TOOL_OPTS:-} -jar "$DIR/start.jar" "STOP.PORT=$THIS_STOP_PORT" "STOP.KEY=$STOP_KEY" --stop || true (loops=0 while true do @@ -1222,6 +1222,7 @@ fi FG="false" FORCE=false SOLR_OPTS=(${SOLR_OPTS:-}) +SCRIPT_SOLR_OPTS=() PASS_TO_RUN_EXAMPLE=() if [ $# -gt 0 ]; then @@ -1370,6 +1371,7 @@ if [ $# -gt 0 ]; then break # out-of-args, stop looping elif [ "${1:0:2}" == "-D" ]; then # pass thru any opts that begin with -D (java system props) + # These should go to the end of SOLR_OPTS, as they should override everything else SOLR_OPTS+=("$1") PASS_TO_RUN_EXAMPLE+=("$1") shift @@ -1388,20 +1390,20 @@ fi # Solr modules option if [[ -n "${SOLR_MODULES:-}" ]] ; then - SOLR_OPTS+=("-Dsolr.modules=$SOLR_MODULES") + SCRIPT_SOLR_OPTS+=("-Dsolr.modules=$SOLR_MODULES") fi # Default placement plugin if [[ -n "${SOLR_PLACEMENTPLUGIN_DEFAULT:-}" ]] ; then - SOLR_OPTS+=("-Dsolr.placementplugin.default=$SOLR_PLACEMENTPLUGIN_DEFAULT") + SCRIPT_SOLR_OPTS+=("-Dsolr.placementplugin.default=$SOLR_PLACEMENTPLUGIN_DEFAULT") fi # Remote streaming and stream body if [ "${SOLR_ENABLE_REMOTE_STREAMING:-false}" == "true" ]; then - SOLR_OPTS+=("-Dsolr.enableRemoteStreaming=true") + SCRIPT_SOLR_OPTS+=("-Dsolr.enableRemoteStreaming=true") fi if [ "${SOLR_ENABLE_STREAM_BODY:-false}" == "true" ]; then - SOLR_OPTS+=("-Dsolr.enableStreamBody=true") + SCRIPT_SOLR_OPTS+=("-Dsolr.enableStreamBody=true") fi : ${SOLR_SERVER_DIR:=$DEFAULT_SERVER_DIR} @@ -1494,15 +1496,15 @@ if [[ "$SCRIPT_CMD" == "stop" ]]; then fi if [ -n "${SOLR_PORT_ADVERTISE:-}" ]; then - SOLR_OPTS+=("-Dsolr.port.advertise=$SOLR_PORT_ADVERTISE") + SCRIPT_SOLR_OPTS+=("-Dsolr.port.advertise=$SOLR_PORT_ADVERTISE") fi if [ -n "${SOLR_JETTY_HOST:-}" ]; then - SOLR_OPTS+=("-Dsolr.jetty.host=$SOLR_JETTY_HOST") + SCRIPT_SOLR_OPTS+=("-Dsolr.jetty.host=$SOLR_JETTY_HOST") fi if [ -n "${SOLR_ZK_EMBEDDED_HOST:-}" ]; then - SOLR_OPTS+=("-Dsolr.zk.embedded.host=$SOLR_ZK_EMBEDDED_HOST") + SCRIPT_SOLR_OPTS+=("-Dsolr.zk.embedded.host=$SOLR_ZK_EMBEDDED_HOST") fi : "${STOP_PORT:=$((SOLR_PORT - 1000))}" @@ -1736,8 +1738,8 @@ else JAVA_MEM_OPTS=("-Xms$SOLR_HEAP" "-Xmx$SOLR_HEAP") fi -# Pick default for Java thread stack size, and then add to SOLR_OPTS -SOLR_OPTS+=(${SOLR_JAVA_STACK_SIZE:-"-Xss256k"}) +# Pick default for Java thread stack size, and then add to SCRIPT_SOLR_OPTS +SCRIPT_SOLR_OPTS+=(${SOLR_JAVA_STACK_SIZE:-"-Xss256k"}) : "${SOLR_TIMEZONE:=UTC}" @@ -1778,79 +1780,83 @@ function start_solr() { fi if [ -n "${SOLR_WAIT_FOR_ZK:-}" ]; then - SOLR_OPTS+=("-DwaitForZk=$SOLR_WAIT_FOR_ZK") + SCRIPT_SOLR_OPTS+=("-DwaitForZk=$SOLR_WAIT_FOR_ZK") fi if [ -n "${SOLR_DATA_HOME:-}" ]; then - SOLR_OPTS+=("-Dsolr.data.home=$SOLR_DATA_HOME") + SCRIPT_SOLR_OPTS+=("-Dsolr.data.home=$SOLR_DATA_HOME") fi if [ -n "${SOLR_DELETE_UNKNOWN_CORES:-}" ]; then - SOLR_OPTS+=("-Dsolr.deleteUnknownCores=$SOLR_DELETE_UNKNOWN_CORES") + SCRIPT_SOLR_OPTS+=("-Dsolr.deleteUnknownCores=$SOLR_DELETE_UNKNOWN_CORES") fi - # If SSL-related system props are set, add them to SOLR_OPTS + # If SSL-related system props are set, add them to SCRIPT_SOLR_OPTS if [ "$SOLR_SSL_ENABLED" == "true" ]; then # If using SSL and solr.jetty.https.port not set explicitly, use the jetty.port SSL_PORT_PROP="-Dsolr.jetty.https.port=$SOLR_PORT" - SOLR_OPTS+=($SOLR_SSL_OPTS "$SSL_PORT_PROP") + SCRIPT_SOLR_OPTS+=($SOLR_SSL_OPTS "$SSL_PORT_PROP") fi - # If authentication system props are set, add them to SOLR_OPTS + # If authentication system props are set, add them to SCRIPT_SOLR_OPTS if [ -n "$AUTHC_OPTS" ]; then - SOLR_OPTS+=($AUTHC_OPTS) + SCRIPT_SOLR_OPTS+=($AUTHC_OPTS) fi - # If there are internal options set by Solr (users should not use this variable), add them to SOLR_OPTS + # If there are internal options set by Solr (users should not use this variable), add them to SCRIPT_SOLR_OPTS if [ -n "$SOLR_OPTS_INTERNAL" ]; then - SOLR_OPTS+=($SOLR_OPTS_INTERNAL) + SCRIPT_SOLR_OPTS+=($SOLR_OPTS_INTERNAL) fi - # If a heap dump directory is specified, enable it in SOLR_OPTS + # If a heap dump directory is specified, enable it in SCRIPT_SOLR_OPTS if [[ -z "${SOLR_HEAP_DUMP_DIR:-}" ]] && [[ "${SOLR_HEAP_DUMP:-}" == "true" ]]; then SOLR_HEAP_DUMP_DIR="${SOLR_LOGS_DIR}/dumps" fi if [[ -n "${SOLR_HEAP_DUMP_DIR:-}" ]]; then - SOLR_OPTS+=("-XX:+HeapDumpOnOutOfMemoryError") - SOLR_OPTS+=("-XX:HeapDumpPath=$SOLR_HEAP_DUMP_DIR/solr-$(date +%s)-pid$$.hprof") + SCRIPT_SOLR_OPTS+=("-XX:+HeapDumpOnOutOfMemoryError") + SCRIPT_SOLR_OPTS+=("-XX:HeapDumpPath=$SOLR_HEAP_DUMP_DIR/solr-$(date +%s)-pid$$.hprof") fi if $verbose ; then echo -e "\nStarting Solr using the following settings:" - echo -e " JAVA = $JAVA" - echo -e " SOLR_SERVER_DIR = $SOLR_SERVER_DIR" - echo -e " SOLR_HOME = $SOLR_HOME" - echo -e " SOLR_HOST = ${SOLR_HOST:-}" - echo -e " SOLR_PORT = $SOLR_PORT" - echo -e " STOP_PORT = $STOP_PORT" - echo -e " JAVA_MEM_OPTS = ${JAVA_MEM_OPTS[*]}" - echo -e " GC_TUNE = ${GC_TUNE_ARR[*]}" - echo -e " GC_LOG_OPTS = ${GC_LOG_OPTS[*]}" - echo -e " SOLR_TIMEZONE = $SOLR_TIMEZONE" + echo -e " JAVA = $JAVA" + echo -e " SOLR_SERVER_DIR = $SOLR_SERVER_DIR" + echo -e " SOLR_HOME = $SOLR_HOME" + echo -e " SOLR_HOST = ${SOLR_HOST:-}" + echo -e " SOLR_PORT = $SOLR_PORT" + echo -e " STOP_PORT = $STOP_PORT" + echo -e " JAVA_MEM_OPTS = ${JAVA_MEM_OPTS[*]}" + echo -e " GC_TUNE = ${GC_TUNE_ARR[*]}" + echo -e " GC_LOG_OPTS = ${GC_LOG_OPTS[*]}" + echo -e " SOLR_TIMEZONE = $SOLR_TIMEZONE" if [ "$SOLR_MODE" == "solrcloud" ]; then - echo -e " CLOUD_MODE_OPTS = ${CLOUD_MODE_OPTS[*]}" + echo -e " CLOUD_MODE_OPTS = ${CLOUD_MODE_OPTS[*]}" fi if [ -n "${SOLR_OPTS:-}" ]; then - echo -e " SOLR_OPTS = ${SOLR_OPTS[*]}" + echo -e " SOLR_OPTS (USER) = ${SOLR_OPTS[*]}" + fi + + if [ -n "${SCRIPT_SOLR_OPTS:-}" ]; then + echo -e " SOLR_OPTS (SCRIPT) = ${SCRIPT_SOLR_OPTS[*]}" fi if [ -n "${SOLR_ADDL_ARGS:-}" ]; then - echo -e " SOLR_ADDL_ARGS = $SOLR_ADDL_ARGS" + echo -e " SOLR_ADDL_ARGS = $SOLR_ADDL_ARGS" fi if [ "${ENABLE_REMOTE_JMX_OPTS:-false}" == "true" ]; then - echo -e " RMI_PORT = ${RMI_PORT:-}" - echo -e " REMOTE_JMX_OPTS = ${REMOTE_JMX_OPTS[*]}" + echo -e " RMI_PORT = ${RMI_PORT:-}" + echo -e " REMOTE_JMX_OPTS = ${REMOTE_JMX_OPTS[*]}" fi if [ -n "${SOLR_LOG_LEVEL:-}" ]; then - echo -e " SOLR_LOG_LEVEL = $SOLR_LOG_LEVEL" + echo -e " SOLR_LOG_LEVEL = $SOLR_LOG_LEVEL" fi if [ -n "${SOLR_DATA_HOME:-}" ]; then - echo -e " SOLR_DATA_HOME = $SOLR_DATA_HOME" + echo -e " SOLR_DATA_HOME = $SOLR_DATA_HOME" fi echo fi @@ -1865,14 +1871,14 @@ function start_solr() { # Workaround for JIT crash, see https://issues.apache.org/jira/browse/SOLR-16463 if [[ "$JAVA_VER_NUM" -ge "17" ]] ; then - SOLR_OPTS+=("-XX:CompileCommand=exclude,com.github.benmanes.caffeine.cache.BoundedLocalCache::put") + SCRIPT_SOLR_OPTS+=("-XX:CompileCommand=exclude,com.github.benmanes.caffeine.cache.BoundedLocalCache::put") echo "Java $JAVA_VER_NUM detected. Enabled workaround for SOLR-16463" fi # Vector optimizations are only supported for Java 20 and 21 for now. # This will need to change as Lucene is upgraded and newer Java versions are released if [[ "$JAVA_VER_NUM" -ge "20" ]] && [[ "$JAVA_VER_NUM" -le "21" ]] ; then - SOLR_OPTS+=("--add-modules" "jdk.incubator.vector") + SCRIPT_SOLR_OPTS+=("--add-modules" "jdk.incubator.vector") echo "Java $JAVA_VER_NUM detected. Incubating Panama Vector APIs have been enabled" fi @@ -1886,7 +1892,7 @@ function start_solr() { # OOME is thrown. Program operation after OOME is unpredictable. "-XX:+CrashOnOutOfMemoryError" "-XX:ErrorFile=${SOLR_LOGS_DIR}/jvm_crash_%p.log" \ "-Djetty.home=$SOLR_SERVER_DIR" "-Dsolr.solr.home=$SOLR_HOME" "-Dsolr.install.dir=$SOLR_TIP" "-Dsolr.install.symDir=$SOLR_TIP_SYM" \ - "-Dsolr.default.confdir=$DEFAULT_CONFDIR" "${LOG4J_CONFIG[@]}" "${SOLR_OPTS[@]}" "${SECURITY_MANAGER_OPTS[@]}" "${SOLR_ADMIN_UI}") + "-Dsolr.default.confdir=$DEFAULT_CONFDIR" "${LOG4J_CONFIG[@]}" "${SCRIPT_SOLR_OPTS[@]}" "${SECURITY_MANAGER_OPTS[@]}" "${SOLR_ADMIN_UI}" "${SOLR_OPTS[@]}") mk_writable_dir "$SOLR_LOGS_DIR" "Logs" if [[ -n "${SOLR_HEAP_DUMP_DIR:-}" ]]; then diff --git a/solr/bin/solr.cmd b/solr/bin/solr.cmd index ce37a20d20e..bb297a64d62 100755 --- a/solr/bin/solr.cmd +++ b/solr/bin/solr.cmd @@ -146,7 +146,7 @@ IF "%SOLR_SSL_ENABLED%"=="true" ( ) ) IF DEFINED SOLR_SSL_CHECK_PEER_NAME ( - set "SOLR_SSL_OPTS=!SOLR_SSL_OPTS! -Dsolr.ssl.checkPeerName=%SOLR_SSL_CHECK_PEER_NAME%" + set "SOLR_SSL_OPTS=!SOLR_SSL_OPTS! -Dsolr.ssl.checkPeerName=%SOLR_SSL_CHECK_PEER_NAME% -Dsolr.jetty.ssl.sniHostCheck=%SOLR_SSL_CHECK_PEER_NAME%" ) ) ELSE ( set SOLR_SSL_OPTS= @@ -805,22 +805,24 @@ IF NOT "%SOLR_HOST%"=="" ( set SOLR_HOST_ARG= ) +set SCRIPT_SOLR_OPTS= + REM Solr modules option IF DEFINED SOLR_MODULES ( - set "SOLR_OPTS=%SOLR_OPTS% -Dsolr.modules=%SOLR_MODULES%" + set "SCRIPT_SOLR_OPTS=%SCRIPT_SOLR_OPTS% -Dsolr.modules=%SOLR_MODULES%" ) REM Default placement plugin IF DEFINED SOLR_PLACEMENTPLUGIN_DEFAULT ( - set "SOLR_OPTS=%SOLR_OPTS% -Dsolr.placementplugin.default=%SOLR_PLACEMENTPLUGIN_DEFAULT%" + set "SCRIPT_SOLR_OPTS=%SCRIPT_SOLR_OPTS% -Dsolr.placementplugin.default=%SOLR_PLACEMENTPLUGIN_DEFAULT%" ) REM Remote streaming and stream body IF "%SOLR_ENABLE_REMOTE_STREAMING%"=="true" ( - set "SOLR_OPTS=%SOLR_OPTS% -Dsolr.enableRemoteStreaming=true" + set "SCRIPT_SOLR_OPTS=%SCRIPT_SOLR_OPTS% -Dsolr.enableRemoteStreaming=true" ) IF "%SOLR_ENABLE_STREAM_BODY%"=="true" ( - set "SOLR_OPTS=%SOLR_OPTS% -Dsolr.enableStreamBody=true" + set "SCRIPT_SOLR_OPTS=%SCRIPT_SOLR_OPTS% -Dsolr.enableStreamBody=true" ) IF "%SOLR_SERVER_DIR%"=="" set "SOLR_SERVER_DIR=%DEFAULT_SERVER_DIR%" @@ -923,7 +925,7 @@ IF "%SCRIPT_CMD%"=="stop" ( set found_it=1 @echo Stopping Solr process %%N running on port %SOLR_PORT% IF "%STOP_PORT%"=="" set /A STOP_PORT=%SOLR_PORT% - 1000 - "%JAVA%" %SOLR_TOOL_OPTS% %SOLR_SSL_OPTS% -Djetty.home="%SOLR_SERVER_DIR%" -jar "%SOLR_SERVER_DIR%\start.jar" %SOLR_JETTY_CONFIG% STOP.PORT=!STOP_PORT! STOP.KEY=%STOP_KEY% --stop + "%JAVA%" %SOLR_SSL_OPTS% %SOLR_TOOL_OPTS% -Djetty.home="%SOLR_SERVER_DIR%" -jar "%SOLR_SERVER_DIR%\start.jar" %SOLR_JETTY_CONFIG% STOP.PORT=!STOP_PORT! STOP.KEY=%STOP_KEY% --stop del "%SOLR_TIP%"\bin\solr-%SOLR_PORT%.port REM wait for the process to terminate CALL :wait_for_process_exit %%N !SOLR_STOP_WAIT! @@ -948,15 +950,15 @@ IF "%SOLR_PORT%"=="" set SOLR_PORT=8983 IF "%STOP_PORT%"=="" set /A STOP_PORT=%SOLR_PORT% - 1000 IF DEFINED SOLR_PORT_ADVERTISE ( - set "SOLR_OPTS=%SOLR_OPTS% -Dsolr.port.advertise=%SOLR_PORT_ADVERTISE%" + set "SCRIPT_SOLR_OPTS=%SCRIPT_SOLR_OPTS% -Dsolr.port.advertise=%SOLR_PORT_ADVERTISE%" ) IF DEFINED SOLR_JETTY_HOST ( - set "SOLR_OPTS=%SOLR_OPTS% -Dsolr.jetty.host=%SOLR_JETTY_HOST%" + set "SCRIPT_SOLR_OPTS=%SCRIPT_SOLR_OPTS% -Dsolr.jetty.host=%SOLR_JETTY_HOST%" ) IF DEFINED SOLR_ZK_EMBEDDED_HOST ( - set "SOLR_OPTS=%SOLR_OPTS% -Dsolr.zk.embedded.host=%SOLR_ZK_EMBEDDED_HOST%" + set "SCRIPT_SOLR_OPTS=%SCRIPT_SOLR_OPTS% -Dsolr.zk.embedded.host=%SOLR_ZK_EMBEDDED_HOST%" ) IF "%SCRIPT_CMD%"=="start" ( @@ -1097,7 +1099,7 @@ IF "%SOLR_ADMIN_UI_DISABLED%"=="true" ( IF NOT "%SOLR_HEAP%"=="" set SOLR_JAVA_MEM=-Xms%SOLR_HEAP% -Xmx%SOLR_HEAP% IF "%SOLR_JAVA_MEM%"=="" set SOLR_JAVA_MEM=-Xms512m -Xmx512m IF "%SOLR_JAVA_STACK_SIZE%"=="" set SOLR_JAVA_STACK_SIZE=-Xss256k -set SOLR_OPTS=%SOLR_JAVA_STACK_SIZE% %SOLR_OPTS% +set SCRIPT_SOLR_OPTS=%SOLR_JAVA_STACK_SIZE% %SCRIPT_SOLR_OPTS% IF "%SOLR_TIMEZONE%"=="" set SOLR_TIMEZONE=UTC IF "%GC_TUNE%"=="" ( @@ -1112,14 +1114,14 @@ IF "%GC_TUNE%"=="" ( REM Workaround for JIT crash, see https://issues.apache.org/jira/browse/SOLR-16463 if !JAVA_MAJOR_VERSION! GEQ 17 ( - set SOLR_OPTS=%SOLR_OPTS% -XX:CompileCommand=exclude,com.github.benmanes.caffeine.cache.BoundedLocalCache::put + set SCRIPT_SOLR_OPTS=%SCRIPT_SOLR_OPTS% -XX:CompileCommand=exclude,com.github.benmanes.caffeine.cache.BoundedLocalCache::put echo Java %JAVA_MAJOR_VERSION% detected. Enabled workaround for SOLR-16463 ) REM Vector optimizations are only supported for Java 20 and 21 for now. REM This will need to change as Lucene is upgraded and newer Java versions are released if !JAVA_MAJOR_VERSION! GEQ 20 if !JAVA_MAJOR_VERSION! LEQ 21 ( - set SOLR_OPTS=%SOLR_OPTS% --add-modules jdk.incubator.vector + set SCRIPT_SOLR_OPTS=%SCRIPT_SOLR_OPTS% --add-modules jdk.incubator.vector echo Java %JAVA_MAJOR_VERSION% detected. Incubating Panama Vector APIs have been enabled ) @@ -1149,44 +1151,48 @@ if !JAVA_MAJOR_VERSION! GEQ 9 if NOT "%JAVA_VENDOR%" == "OpenJ9" ( IF "%verbose%"=="1" ( @echo Starting Solr using the following settings: - CALL :safe_echo " JAVA = %JAVA%" - CALL :safe_echo " SOLR_SERVER_DIR = %SOLR_SERVER_DIR%" - CALL :safe_echo " SOLR_HOME = %SOLR_HOME%" - @echo SOLR_HOST = %SOLR_HOST% - @echo SOLR_PORT = %SOLR_PORT% - @echo STOP_PORT = %STOP_PORT% - @echo SOLR_JAVA_MEM = %SOLR_JAVA_MEM% - @echo GC_TUNE = !GC_TUNE! - @echo GC_LOG_OPTS = %GC_LOG_OPTS% - @echo SOLR_TIMEZONE = %SOLR_TIMEZONE% + CALL :safe_echo " JAVA = %JAVA%" + CALL :safe_echo " SOLR_SERVER_DIR = %SOLR_SERVER_DIR%" + CALL :safe_echo " SOLR_HOME = %SOLR_HOME%" + @echo SOLR_HOST = %SOLR_HOST% + @echo SOLR_PORT = %SOLR_PORT% + @echo STOP_PORT = %STOP_PORT% + @echo SOLR_JAVA_MEM = %SOLR_JAVA_MEM% + @echo GC_TUNE = !GC_TUNE! + @echo GC_LOG_OPTS = %GC_LOG_OPTS% + @echo SOLR_TIMEZONE = %SOLR_TIMEZONE% IF "%SOLR_MODE%"=="solrcloud" ( - @echo CLOUD_MODE_OPTS = %CLOUD_MODE_OPTS% + @echo CLOUD_MODE_OPTS = %CLOUD_MODE_OPTS% ) IF NOT "%SOLR_OPTS%"=="" ( - @echo SOLR_OPTS = %SOLR_OPTS% + @echo SOLR_OPTS (USER) = %SOLR_OPTS% + ) + + IF NOT "%SCRIPT_SOLR_OPTS%"=="" ( + @echo SOLR_OPTS (SCRIPT) = %SCRIPT_SOLR_OPTS% ) IF NOT "%SOLR_ADDL_ARGS%"=="" ( - CALL :safe_echo " SOLR_ADDL_ARGS = %SOLR_ADDL_ARGS%" + CALL :safe_echo " SOLR_ADDL_ARGS = %SOLR_ADDL_ARGS%" ) IF NOT "%SOLR_JETTY_ADDL_CONFIG%"=="" ( - CALL :safe_echo " SOLR_JETTY_ADDL_CONFIG = %SOLR_JETTY_ADDL_CONFIG%" + CALL :safe_echo " SOLR_JETTY_ADDL_CONFIG = %SOLR_JETTY_ADDL_CONFIG%" ) IF "%ENABLE_REMOTE_JMX_OPTS%"=="true" ( - @echo RMI_PORT = !RMI_PORT! - @echo REMOTE_JMX_OPTS = %REMOTE_JMX_OPTS% + @echo RMI_PORT = !RMI_PORT! + @echo REMOTE_JMX_OPTS = %REMOTE_JMX_OPTS% ) IF NOT "%SOLR_LOG_LEVEL%"=="" ( - @echo SOLR_LOG_LEVEL = !SOLR_LOG_LEVEL! + @echo SOLR_LOG_LEVEL = !SOLR_LOG_LEVEL! ) IF NOT "%SOLR_DATA_HOME%"=="" ( - @echo SOLR_DATA_HOME = !SOLR_DATA_HOME! + @echo SOLR_DATA_HOME = !SOLR_DATA_HOME! ) @echo. @@ -1207,7 +1213,7 @@ IF NOT "!IP_ACL_OPTS!"=="" set "START_OPTS=%START_OPTS% !IP_ACL_OPTS!" IF NOT "%REMOTE_JMX_OPTS%"=="" set "START_OPTS=%START_OPTS% %REMOTE_JMX_OPTS%" IF NOT "%SOLR_ADDL_ARGS%"=="" set "START_OPTS=%START_OPTS% %SOLR_ADDL_ARGS%" IF NOT "%SOLR_HOST_ARG%"=="" set "START_OPTS=%START_OPTS% %SOLR_HOST_ARG%" -IF NOT "%SOLR_OPTS%"=="" set "START_OPTS=%START_OPTS% %SOLR_OPTS%" +IF NOT "%SCRIPT_SOLR_OPTS%"=="" set "START_OPTS=%START_OPTS% %SCRIPT_SOLR_OPTS%" IF NOT "%SOLR_OPTS_INTERNAL%"=="" set "START_OPTS=%START_OPTS% %SOLR_OPTS_INTERNAL%" IF NOT "!SECURITY_MANAGER_OPTS!"=="" set "START_OPTS=%START_OPTS% !SECURITY_MANAGER_OPTS!" IF "%SOLR_SSL_ENABLED%"=="true" ( @@ -1223,6 +1229,9 @@ set "START_OPTS=%START_OPTS% -Dsolr.log.dir=%SOLR_LOGS_DIR_QUOTED% -Djava.util.l IF NOT "%SOLR_DATA_HOME%"=="" set "START_OPTS=%START_OPTS% -Dsolr.data.home=%SOLR_DATA_HOME_QUOTED%" IF NOT DEFINED LOG4J_CONFIG set "LOG4J_CONFIG=%SOLR_SERVER_DIR%\resources\log4j2.xml" +REM This should be the last thing added to START_OPTS, so that users can override as much as possible +IF NOT "%SOLR_OPTS%"=="" set "START_OPTS=%START_OPTS% %SOLR_OPTS%" + cd /d "%SOLR_SERVER_DIR%" IF NOT EXIST "%SOLR_LOGS_DIR%" ( @@ -1272,7 +1281,7 @@ IF "%FG%"=="1" ( set SOLR_START_WAIT=30 ) REM now wait to see Solr come online ... - "%JAVA%" %SOLR_TOOL_OPTS% %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% -Dsolr.install.dir="%SOLR_TIP%" -Dsolr.default.confdir="%DEFAULT_CONFDIR%"^ + "%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% %SOLR_TOOL_OPTS% -Dsolr.install.dir="%SOLR_TIP%" -Dsolr.default.confdir="%DEFAULT_CONFDIR%"^ -Dlog4j.configurationFile="file:///%DEFAULT_SERVER_DIR%\resources\log4j2-console.xml" ^ -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^ org.apache.solr.cli.SolrCLI status -maxWaitSecs !SOLR_START_WAIT! -solrUrl !SOLR_URL_SCHEME!://%SOLR_TOOL_HOST%:%SOLR_PORT%/solr @@ -1287,7 +1296,7 @@ goto done :run_example REM Run the requested example -"%JAVA%" %SOLR_TOOL_OPTS% %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% -Dsolr.install.dir="%SOLR_TIP%" ^ +"%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% %SOLR_TOOL_OPTS% -Dsolr.install.dir="%SOLR_TIP%" ^ -Dlog4j.configurationFile="file:///%DEFAULT_SERVER_DIR%\resources\log4j2-console.xml" ^ -Dsolr.install.symDir="%SOLR_TIP%" ^ -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^ @@ -1311,7 +1320,7 @@ for /f "usebackq" %%i in (`dir /b "%SOLR_TIP%\bin" ^| findstr /i "^solr-.*\.port set has_info=1 echo Found Solr process %%k running on port !SOME_SOLR_PORT! REM Passing in %2 (-h or -help) directly is captured by a custom help path for usage output - "%JAVA%" %SOLR_TOOL_OPTS% %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% -Dsolr.install.dir="%SOLR_TIP%" ^ + "%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% %SOLR_TOOL_OPTS% -Dsolr.install.dir="%SOLR_TIP%" ^ -Dlog4j.configurationFile="file:///%DEFAULT_SERVER_DIR%\resources\log4j2-console.xml" ^ -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^ org.apache.solr.cli.SolrCLI status -solrUrl !SOLR_URL_SCHEME!://%SOLR_TOOL_HOST%:!SOME_SOLR_PORT!/solr %2 @@ -1326,7 +1335,7 @@ set has_info= goto done :run_solrcli -"%JAVA%" %SOLR_TOOL_OPTS% %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% -Dsolr.install.dir="%SOLR_TIP%" ^ +"%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% %SOLR_TOOL_OPTS% -Dsolr.install.dir="%SOLR_TIP%" ^ -Dlog4j.configurationFile="file:///%DEFAULT_SERVER_DIR%\resources\log4j2-console.xml" ^ -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^ org.apache.solr.cli.SolrCLI %* @@ -1475,7 +1484,7 @@ IF "!ZK_OP!"=="upconfig" ( set ERROR_MSG="The -d option must be set for upconfig." goto zk_short_usage ) - "%JAVA%" %SOLR_TOOL_OPTS% %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% -Dsolr.install.dir="%SOLR_TIP%" ^ + "%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% %SOLR_TOOL_OPTS% -Dsolr.install.dir="%SOLR_TIP%" ^ -Dlog4j.configurationFile="file:///%DEFAULT_SERVER_DIR%\resources\log4j2-console.xml" ^ -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^ org.apache.solr.cli.SolrCLI !ZK_OP! -confname !CONFIGSET_NAME! -confdir !CONFIGSET_DIR! -zkHost !ZK_HOST! %ZK_VERBOSE%^ @@ -1489,7 +1498,7 @@ IF "!ZK_OP!"=="upconfig" ( set ERROR_MSG="The -d option must be set for downconfig." goto zk_short_usage ) - "%JAVA%" %SOLR_TOOL_OPTS% %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% -Dsolr.install.dir="%SOLR_TIP%" ^ + "%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% %SOLR_TOOL_OPTS% -Dsolr.install.dir="%SOLR_TIP%" ^ -Dlog4j.configurationFile="file:///%DEFAULT_SERVER_DIR%\resources\log4j2-console.xml" ^ -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^ org.apache.solr.cli.SolrCLI !ZK_OP! -confname !CONFIGSET_NAME! -confdir !CONFIGSET_DIR! -zkHost !ZK_HOST! %ZK_VERBOSE% @@ -1508,7 +1517,7 @@ IF "!ZK_OP!"=="upconfig" ( goto zk_short_usage ) ) - "%JAVA%" %SOLR_TOOL_OPTS% %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% -Dsolr.install.dir="%SOLR_TIP%" ^ + "%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% %SOLR_TOOL_OPTS% -Dsolr.install.dir="%SOLR_TIP%" ^ -Dlog4j.configurationFile="file:///%DEFAULT_SERVER_DIR%\resources\log4j2-console.xml" ^ -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^ org.apache.solr.cli.SolrCLI !ZK_OP! -zkHost !ZK_HOST! -src !ZK_SRC! -dst !ZK_DST! -recurse !ZK_RECURSE! %ZK_VERBOSE% @@ -1521,7 +1530,7 @@ IF "!ZK_OP!"=="upconfig" ( set ERROR_MSG=" must be specified for 'mv' command" goto zk_short_usage ) - "%JAVA%" %SOLR_TOOL_OPTS% %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% -Dsolr.install.dir="%SOLR_TIP%" ^ + "%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% %SOLR_TOOL_OPTS% -Dsolr.install.dir="%SOLR_TIP%" ^ -Dlog4j.configurationFile="file:///%DEFAULT_SERVER_DIR%\resources\log4j2-console.xml" ^ -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^ org.apache.solr.cli.SolrCLI !ZK_OP! -zkHost !ZK_HOST! -src !ZK_SRC! -dst !ZK_DST! %ZK_VERBOSE% @@ -1530,7 +1539,7 @@ IF "!ZK_OP!"=="upconfig" ( set ERROR_MSG="Zookeeper path to remove must be specified when using the 'rm' command" goto zk_short_usage ) - "%JAVA%" %SOLR_TOOL_OPTS% %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% -Dsolr.install.dir="%SOLR_TIP%" ^ + "%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% %SOLR_TOOL_OPTS% -Dsolr.install.dir="%SOLR_TIP%" ^ -Dlog4j.configurationFile="file:///%DEFAULT_SERVER_DIR%\resources\log4j2-console.xml" ^ -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^ org.apache.solr.cli.SolrCLI !ZK_OP! -zkHost !ZK_HOST! -path !ZK_SRC! -recurse !ZK_RECURSE! %ZK_VERBOSE% @@ -1539,7 +1548,7 @@ IF "!ZK_OP!"=="upconfig" ( set ERROR_MSG="Zookeeper path to remove must be specified when using the 'ls' command" goto zk_short_usage ) - "%JAVA%" %SOLR_TOOL_OPTS% %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% -Dsolr.install.dir="%SOLR_TIP%" ^ + "%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% %SOLR_TOOL_OPTS% -Dsolr.install.dir="%SOLR_TIP%" ^ -Dlog4j.configurationFile="file:///%DEFAULT_SERVER_DIR%\resources\log4j2-console.xml" ^ -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^ org.apache.solr.cli.SolrCLI !ZK_OP! -zkHost !ZK_HOST! -path !ZK_SRC! -recurse !ZK_RECURSE! %ZK_VERBOSE% @@ -1548,7 +1557,7 @@ IF "!ZK_OP!"=="upconfig" ( set ERROR_MSG="Zookeeper path to create must be specified when using the 'mkroot' command" goto zk_short_usage ) - "%JAVA%" %SOLR_TOOL_OPTS% %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% -Dsolr.install.dir="%SOLR_TIP%" ^ + "%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% %SOLR_TOOL_OPTS% -Dsolr.install.dir="%SOLR_TIP%" ^ -Dlog4j.configurationFile="file:///%SOLR_SERVER_DIR%\resources\log4j2-console.xml" ^ -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^ org.apache.solr.cli.SolrCLI !ZK_OP! -zkHost !ZK_HOST! -path !ZK_SRC! %ZK_VERBOSE% @@ -1609,7 +1618,7 @@ if "!AUTH_PORT!"=="" ( ) ) ) -"%JAVA%" %SOLR_TOOL_OPTS% %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% -Dsolr.install.dir="%SOLR_TIP%" ^ +"%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% %SOLR_TOOL_OPTS% -Dsolr.install.dir="%SOLR_TIP%" ^ -Dlog4j.configurationFile="file:///%DEFAULT_SERVER_DIR%\resources\log4j2-console.xml" ^ -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^ org.apache.solr.cli.SolrCLI auth %AUTH_PARAMS% -solrIncludeFile "%SOLR_INCLUDE%" -authConfDir "%SOLR_HOME%" ^ diff --git a/solr/bin/solr.in.cmd b/solr/bin/solr.in.cmd index 5f982cb16b5..f9892d33d66 100755 --- a/solr/bin/solr.in.cmd +++ b/solr/bin/solr.in.cmd @@ -159,7 +159,8 @@ REM set SOLR_SSL_WANT_CLIENT_AUTH=false REM Verify client hostname during SSL handshake REM set SOLR_SSL_CLIENT_HOSTNAME_VERIFICATION=false REM SSL Certificates contain host/ip "peer name" information that is validated by default. Setting -REM this to false can be useful to disable these checks when re-using a certificate on many hosts +REM this to false can be useful to disable these checks when re-using a certificate on many hosts. +REM This will also be used for the default value of whether SNI Host checking should be enabled. REM set SOLR_SSL_CHECK_PEER_NAME=true REM Override Key/Trust Store types if necessary REM set SOLR_SSL_KEY_STORE_TYPE=PKCS12 diff --git a/solr/bin/solr.in.sh b/solr/bin/solr.in.sh index 117ef1761a9..f6da91c2f3b 100644 --- a/solr/bin/solr.in.sh +++ b/solr/bin/solr.in.sh @@ -173,7 +173,8 @@ # Verify client's hostname during SSL handshake #SOLR_SSL_CLIENT_HOSTNAME_VERIFICATION=false # SSL Certificates contain host/ip "peer name" information that is validated by default. Setting -# this to false can be useful to disable these checks when re-using a certificate on many hosts +# this to false can be useful to disable these checks when re-using a certificate on many hosts. +# This will also be used for the default value of whether SNI Host checking should be enabled. #SOLR_SSL_CHECK_PEER_NAME=true # Override Key/Trust Store types if necessary #SOLR_SSL_KEY_STORE_TYPE=PKCS12 diff --git a/solr/core/src/java/org/apache/solr/api/V2HttpCall.java b/solr/core/src/java/org/apache/solr/api/V2HttpCall.java index 92008542a60..a57b286a9a3 100644 --- a/solr/core/src/java/org/apache/solr/api/V2HttpCall.java +++ b/solr/core/src/java/org/apache/solr/api/V2HttpCall.java @@ -44,7 +44,6 @@ import org.apache.solr.common.cloud.DocCollection; import org.apache.solr.common.cloud.ZkStateReader; import org.apache.solr.common.params.CommonParams; -import org.apache.solr.common.util.CommandOperation; import org.apache.solr.common.util.JsonSchemaValidator; import org.apache.solr.common.util.PathTrie; import org.apache.solr.common.util.SuppressForbidden; @@ -503,22 +502,7 @@ protected void populateTracingSpan(Span span) { // Get the templatize-ed path, ex: "/c/{collection}" final String path = computeEndpointPath(); - - String verb = null; - // if this api has commands ... - final Map validators = getValidators(); // should be cached - if (validators != null && validators.isEmpty() == false && solrReq != null) { - boolean validateInput = true; // because getCommands caches it; and we want it validated later - // does this request have one command? - List cmds = solrReq.getCommands(validateInput); - if (cmds.size() == 1) { - verb = cmds.get(0).name; - } - } - if (verb == null) { - verb = req.getMethod().toLowerCase(Locale.ROOT); - } - + final String verb = req.getMethod().toLowerCase(Locale.ROOT); span.updateName(verb + ":" + path); } diff --git a/solr/core/src/java/org/apache/solr/cloud/DistributedMap.java b/solr/core/src/java/org/apache/solr/cloud/DistributedMap.java index 323c378f71d..fb2347c3e82 100644 --- a/solr/core/src/java/org/apache/solr/cloud/DistributedMap.java +++ b/solr/core/src/java/org/apache/solr/cloud/DistributedMap.java @@ -16,6 +16,7 @@ */ package org.apache.solr.cloud; +import java.lang.invoke.MethodHandles; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -27,12 +28,17 @@ import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.KeeperException.NodeExistsException; import org.apache.zookeeper.data.Stat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * A distributed map. This supports basic map functions e.g. get, put, contains for interaction with * zk which don't have to be ordered i.e. DistributedQueue. */ public class DistributedMap { + + private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + protected final String dir; protected SolrZkClient zookeeper; @@ -54,7 +60,14 @@ public DistributedMap(SolrZkClient zookeeper, String dir) { this.zookeeper = zookeeper; } + private void assertKeyFormat(String trackingId) { + if (trackingId == null || trackingId.length() == 0 || trackingId.contains("/")) { + throw new SolrException(ErrorCode.BAD_REQUEST, "Unsupported key format: " + trackingId); + } + } + public void put(String trackingId, byte[] data) throws KeeperException, InterruptedException { + assertKeyFormat(trackingId); zookeeper.makePath( dir + "/" + PREFIX + trackingId, data, CreateMode.PERSISTENT, null, false, true); } @@ -62,10 +75,11 @@ public void put(String trackingId, byte[] data) throws KeeperException, Interrup /** * Puts an element in the map only if there isn't one with the same trackingId already * - * @return True if the the element was added. False if it wasn't (because the key already exists) + * @return True if the element was added. False if it wasn't (because the key already exists) */ public boolean putIfAbsent(String trackingId, byte[] data) throws KeeperException, InterruptedException { + assertKeyFormat(trackingId); try { zookeeper.makePath( dir + "/" + PREFIX + trackingId, data, CreateMode.PERSISTENT, null, true, true); @@ -94,10 +108,15 @@ public int size() throws KeeperException, InterruptedException { * not deleted exception an exception occurred while deleting */ public boolean remove(String trackingId) throws KeeperException, InterruptedException { + final var path = dir + "/" + PREFIX + trackingId; try { - zookeeper.delete(dir + "/" + PREFIX + trackingId, -1, true); + zookeeper.delete(path, -1, true); } catch (KeeperException.NoNodeException e) { return false; + } catch (KeeperException.NotEmptyException hack) { + // because dirty data before we enforced the rules on put() (trackingId shouldn't have slash) + log.warn("Cleaning malformed key ID starting with {}", path); + zookeeper.clean(path); } return true; } diff --git a/solr/core/src/java/org/apache/solr/cloud/SizeLimitedDistributedMap.java b/solr/core/src/java/org/apache/solr/cloud/SizeLimitedDistributedMap.java index ab495fffea8..c4c8923b218 100644 --- a/solr/core/src/java/org/apache/solr/cloud/SizeLimitedDistributedMap.java +++ b/solr/core/src/java/org/apache/solr/cloud/SizeLimitedDistributedMap.java @@ -91,13 +91,11 @@ protected boolean lessThan(Long a, Long b) { for (String child : children) { Long id = childToModificationZxid.get(child); if (id != null && id <= topElementMzxId) { - try { - zookeeper.delete(dir + "/" + child, -1, true); - if (onOverflowObserver != null) - onOverflowObserver.onChildDelete(child.substring(PREFIX.length())); - } catch (KeeperException.NoNodeException ignored) { - // this could happen if multiple threads try to clean the same map - } + String trackingId = child.substring(PREFIX.length()); + boolean removed = remove(trackingId); + if (removed && onOverflowObserver != null) { + onOverflowObserver.onChildDelete(trackingId); + } // else, probably multiple threads cleaning the queue simultaneously } } } 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 b1c723aa7a5..944d4684016 100644 --- a/solr/core/src/java/org/apache/solr/core/SolrCore.java +++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java @@ -2901,7 +2901,7 @@ public void execute(SolrRequestHandler handler, SolrQueryRequest req, SolrQueryR } /* slowQueryThresholdMillis defaults to -1 in SolrConfig -- not enabled.*/ - if (log.isWarnEnabled() && slowQueryThresholdMillis >= 0) { + if (slowLog.isWarnEnabled() && slowQueryThresholdMillis >= 0) { final long qtime = (long) (req.getRequestTimer().getTime()); if (qtime >= slowQueryThresholdMillis) { slowLog.warn("slow: {}", rsp.getToLogAsString()); diff --git a/solr/core/src/java/org/apache/solr/handler/ContentStreamHandlerBase.java b/solr/core/src/java/org/apache/solr/handler/ContentStreamHandlerBase.java index f00c68b39e4..fb40af3c081 100644 --- a/solr/core/src/java/org/apache/solr/handler/ContentStreamHandlerBase.java +++ b/solr/core/src/java/org/apache/solr/handler/ContentStreamHandlerBase.java @@ -16,6 +16,11 @@ */ package org.apache.solr.handler; +import static org.apache.solr.common.params.CommonParams.FAILURE; +import static org.apache.solr.common.params.CommonParams.STATUS; + +import java.util.List; +import org.apache.solr.client.solrj.SolrRequest.SolrRequestType; import org.apache.solr.common.SolrException; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.util.ContentStream; @@ -26,6 +31,8 @@ import org.apache.solr.update.SolrCoreState; import org.apache.solr.update.processor.UpdateRequestProcessor; import org.apache.solr.update.processor.UpdateRequestProcessorChain; +import org.apache.solr.util.circuitbreaker.CircuitBreaker; +import org.apache.solr.util.circuitbreaker.CircuitBreakerRegistry; /** * Shares common code between various handlers that manipulate {@link @@ -49,6 +56,10 @@ public void init(NamedList args) { @Override public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { + if (checkCircuitBreakers(req, rsp)) { + return; // Circuit breaker tripped, return immediately + } + /* We track update requests so that we can preserve consistency by waiting for them to complete on a node shutdown and then immediately trigger a leader election without waiting for the core to close. @@ -101,6 +112,30 @@ public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throw } } + /** + * Check if {@link SolrRequestType#UPDATE} circuit breakers are tripped. Override this method in + * sub classes that do not want to check circuit breakers. + * + * @return true if circuit breakers are tripped, false otherwise. + */ + protected boolean checkCircuitBreakers(SolrQueryRequest req, SolrQueryResponse rsp) { + CircuitBreakerRegistry circuitBreakerRegistry = req.getCore().getCircuitBreakerRegistry(); + if (circuitBreakerRegistry.isEnabled(SolrRequestType.UPDATE)) { + List trippedCircuitBreakers = + circuitBreakerRegistry.checkTripped(SolrRequestType.UPDATE); + if (trippedCircuitBreakers != null) { + String errorMessage = CircuitBreakerRegistry.toErrorMessage(trippedCircuitBreakers); + rsp.add(STATUS, FAILURE); + rsp.setException( + new SolrException( + CircuitBreaker.getErrorCode(trippedCircuitBreakers), + "Circuit Breakers tripped " + errorMessage)); + return true; + } + } + return false; + } + protected abstract ContentStreamLoader newLoader( SolrQueryRequest req, UpdateRequestProcessor processor); } diff --git a/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java index b1949c993a1..97de7a36bb3 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/CollectionsHandler.java @@ -123,6 +123,7 @@ import org.apache.solr.api.Api; import org.apache.solr.api.JerseyResource; import org.apache.solr.client.api.model.AddReplicaPropertyRequestBody; +import org.apache.solr.client.api.model.ReplaceNodeRequestBody; import org.apache.solr.client.api.model.SolrJerseyResponse; import org.apache.solr.client.api.model.UpdateAliasPropertiesRequestBody; import org.apache.solr.client.solrj.SolrResponse; @@ -166,7 +167,7 @@ import org.apache.solr.handler.admin.api.AddReplicaProperty; import org.apache.solr.handler.admin.api.AdminAPIBase; import org.apache.solr.handler.admin.api.AliasProperty; -import org.apache.solr.handler.admin.api.BalanceReplicasAPI; +import org.apache.solr.handler.admin.api.BalanceReplicas; import org.apache.solr.handler.admin.api.BalanceShardUniqueAPI; import org.apache.solr.handler.admin.api.CollectionPropertyAPI; import org.apache.solr.handler.admin.api.CollectionStatusAPI; @@ -184,7 +185,7 @@ import org.apache.solr.handler.admin.api.DeleteReplica; import org.apache.solr.handler.admin.api.DeleteReplicaProperty; import org.apache.solr.handler.admin.api.DeleteShardAPI; -import org.apache.solr.handler.admin.api.ForceLeaderAPI; +import org.apache.solr.handler.admin.api.ForceLeader; import org.apache.solr.handler.admin.api.InstallShardDataAPI; import org.apache.solr.handler.admin.api.ListAliases; import org.apache.solr.handler.admin.api.ListCollectionBackups; @@ -196,11 +197,11 @@ 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.RenameCollectionAPI; -import org.apache.solr.handler.admin.api.ReplaceNodeAPI; +import org.apache.solr.handler.admin.api.RenameCollection; +import org.apache.solr.handler.admin.api.ReplaceNode; import org.apache.solr.handler.admin.api.RestoreCollectionAPI; import org.apache.solr.handler.admin.api.SplitShardAPI; -import org.apache.solr.handler.admin.api.SyncShardAPI; +import org.apache.solr.handler.admin.api.SyncShard; import org.apache.solr.handler.api.V2ApiUtils; import org.apache.solr.logging.MDCLoggingContext; import org.apache.solr.request.SolrQueryRequest; @@ -607,7 +608,7 @@ public enum CollectionOperation implements CollectionOp { SYNCSHARD_OP( SYNCSHARD, (req, rsp, h) -> { - SyncShardAPI.invokeFromV1Params(h.coreContainer, req, rsp); + SyncShard.invokeFromV1Params(h.coreContainer, req, rsp); return null; }), @@ -722,7 +723,7 @@ public enum CollectionOperation implements CollectionOp { FORCELEADER_OP( FORCELEADER, (req, rsp, h) -> { - ForceLeaderAPI.invokeFromV1Params(h.coreContainer, req, rsp); + ForceLeader.invokeFromV1Params(h.coreContainer, req, rsp); return null; }), CREATESHARD_OP( @@ -1175,12 +1176,11 @@ public Map execute( (req, rsp, h) -> { final SolrParams params = req.getParams(); final RequiredSolrParams requiredParams = req.getParams().required(); - final ReplaceNodeAPI.ReplaceNodeRequestBody requestBody = - new ReplaceNodeAPI.ReplaceNodeRequestBody(); + final var requestBody = new ReplaceNodeRequestBody(); requestBody.targetNodeName = params.get(TARGET_NODE); requestBody.waitForFinalState = params.getBool(WAIT_FOR_FINAL_STATE); requestBody.async = params.get(ASYNC); - final ReplaceNodeAPI replaceNodeAPI = new ReplaceNodeAPI(h.coreContainer, req, rsp); + final ReplaceNode replaceNodeAPI = new ReplaceNode(h.coreContainer, req, rsp); final SolrJerseyResponse replaceNodeResponse = replaceNodeAPI.replaceNode(requiredParams.get(SOURCE_NODE), requestBody); V2ApiUtils.squashIntoSolrResponseWithoutHeader(rsp, replaceNodeResponse); @@ -1375,17 +1375,17 @@ public Collection> getJerseyResources() { DeleteReplica.class, DeleteReplicaProperty.class, DeleteShardAPI.class, - ForceLeaderAPI.class, + ForceLeader.class, InstallShardDataAPI.class, ListCollections.class, ListCollectionBackups.class, ReloadCollectionAPI.class, - RenameCollectionAPI.class, - ReplaceNodeAPI.class, + RenameCollection.class, + ReplaceNode.class, MigrateReplicasAPI.class, - BalanceReplicasAPI.class, + BalanceReplicas.class, RestoreCollectionAPI.class, - SyncShardAPI.class, + SyncShard.class, CollectionPropertyAPI.class, DeleteNode.class, ListAliases.class, diff --git a/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java index 9142449cba6..95e1d10f351 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.stream.Collectors; import org.apache.solr.api.AnnotatedApi; import org.apache.solr.api.Api; import org.apache.solr.api.ApiBag; @@ -52,6 +53,7 @@ import org.apache.solr.security.AuthorizationPlugin; import org.apache.solr.security.ConfigEditablePlugin; import org.apache.solr.security.PermissionNameProvider; +import org.apache.solr.util.tracing.TraceUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -147,6 +149,7 @@ private void doEdit( if (persistConf(securityConfig)) { securityConfEdited(); + updateTraceOps(req, configEditablePlugin.getClass().getSimpleName(), commandsCopy); return; } } @@ -156,6 +159,11 @@ private void doEdit( SERVER_ERROR, "Failed to persist security config after 3 attempts. Giving up"); } + private void updateTraceOps(SolrQueryRequest req, String clazz, List commands) { + TraceUtils.setOperations( + req, clazz, commands.stream().map(c -> c.name).collect(Collectors.toUnmodifiableList())); + } + /** Hook where you can do stuff after a config has been edited. Defaults to NOP */ protected void securityConfEdited() {} diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/BalanceReplicasAPI.java b/solr/core/src/java/org/apache/solr/handler/admin/api/BalanceReplicas.java similarity index 63% rename from solr/core/src/java/org/apache/solr/handler/admin/api/BalanceReplicasAPI.java rename to solr/core/src/java/org/apache/solr/handler/admin/api/BalanceReplicas.java index 53e23886585..6e163857296 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/api/BalanceReplicasAPI.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/api/BalanceReplicas.java @@ -16,7 +16,6 @@ */ package org.apache.solr.handler.admin.api; -import static org.apache.solr.client.solrj.impl.BinaryResponseParser.BINARY_CONTENT_TYPE_V2; import static org.apache.solr.cloud.Overseer.QUEUE_OPERATION; import static org.apache.solr.common.params.CollectionParams.NODES; import static org.apache.solr.common.params.CommonAdminParams.ASYNC; @@ -24,47 +23,35 @@ import static org.apache.solr.handler.admin.CollectionsHandler.DEFAULT_COLLECTION_OP_TIMEOUT; import static org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.parameters.RequestBody; import java.util.HashMap; import java.util.Map; -import java.util.Set; import javax.inject.Inject; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; +import org.apache.solr.client.api.endpoint.BalanceReplicasApi; +import org.apache.solr.client.api.model.BalanceReplicasRequestBody; import org.apache.solr.client.api.model.SolrJerseyResponse; import org.apache.solr.client.solrj.SolrResponse; import org.apache.solr.common.cloud.ZkNodeProps; import org.apache.solr.common.params.CollectionParams.CollectionAction; import org.apache.solr.core.CoreContainer; import org.apache.solr.handler.admin.CollectionsHandler; -import org.apache.solr.jersey.JacksonReflectMapWriter; import org.apache.solr.jersey.PermissionName; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.SolrQueryResponse; /** V2 API for balancing the replicas that already exist across a set of nodes. */ -@Path("cluster/replicas/balance") -public class BalanceReplicasAPI extends AdminAPIBase { +public class BalanceReplicas extends AdminAPIBase implements BalanceReplicasApi { @Inject - public BalanceReplicasAPI( + public BalanceReplicas( CoreContainer coreContainer, SolrQueryRequest solrQueryRequest, SolrQueryResponse solrQueryResponse) { super(coreContainer, solrQueryRequest, solrQueryResponse); } - @POST - @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2}) + @Override @PermissionName(COLL_EDIT_PERM) - @Operation(summary = "Balance Replicas across the given set of Nodes.") - public SolrJerseyResponse balanceReplicas( - @RequestBody(description = "Contains user provided parameters") - BalanceReplicasRequestBody requestBody) + public SolrJerseyResponse balanceReplicas(BalanceReplicasRequestBody requestBody) throws Exception { final SolrJerseyResponse response = instantiateJerseyResponse(SolrJerseyResponse.class); final CoreContainer coreContainer = fetchAndValidateZooKeeperAwareCoreContainer(); @@ -96,33 +83,4 @@ public ZkNodeProps createRemoteMessage(BalanceReplicasRequestBody requestBody) { return new ZkNodeProps(remoteMessage); } - - public static class BalanceReplicasRequestBody implements JacksonReflectMapWriter { - - public BalanceReplicasRequestBody() {} - - public BalanceReplicasRequestBody(Set nodes, Boolean waitForFinalState, String async) { - this.nodes = nodes; - this.waitForFinalState = waitForFinalState; - this.async = async; - } - - @Schema( - description = - "The set of nodes across which replicas will be balanced. Defaults to all live data nodes.") - @JsonProperty(value = "nodes") - public Set nodes; - - @Schema( - description = - "If true, the request will complete only when all affected replicas become active. " - + "If false, the API will return the status of the single action, which may be " - + "before the new replica is online and active.") - @JsonProperty("waitForFinalState") - public Boolean waitForFinalState = false; - - @Schema(description = "Request ID to track this action which will be processed asynchronously.") - @JsonProperty("async") - public String async; - } } diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/ForceLeaderAPI.java b/solr/core/src/java/org/apache/solr/handler/admin/api/ForceLeader.java similarity index 88% rename from solr/core/src/java/org/apache/solr/handler/admin/api/ForceLeaderAPI.java rename to solr/core/src/java/org/apache/solr/handler/admin/api/ForceLeader.java index b0881a34bac..c3080e3ef16 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/api/ForceLeaderAPI.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/api/ForceLeader.java @@ -17,7 +17,6 @@ package org.apache.solr.handler.admin.api; -import static org.apache.solr.client.solrj.impl.BinaryResponseParser.BINARY_CONTENT_TYPE_V2; import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP; import static org.apache.solr.common.cloud.ZkStateReader.SHARD_ID_PROP; import static org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM; @@ -27,11 +26,7 @@ import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; +import org.apache.solr.client.api.endpoint.ForceLeaderApi; import org.apache.solr.client.api.model.SolrJerseyResponse; import org.apache.solr.cloud.ZkController; import org.apache.solr.cloud.ZkShardTerms; @@ -49,29 +44,25 @@ import org.slf4j.LoggerFactory; /** - * V2 API for triggering a leader election on a particular collection and shard. + * V2 API implementation for triggering a leader election on a particular collection and shard. * *

This API (POST /v2/collections/collectionName/shards/shardName/force-leader) is analogous to * the v1 /admin/collections?action=FORCELEADER command. */ -@Path("/collections/{collectionName}/shards/{shardName}/force-leader") -public class ForceLeaderAPI extends AdminAPIBase { +public class ForceLeader extends AdminAPIBase implements ForceLeaderApi { private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); @Inject - public ForceLeaderAPI( + public ForceLeader( CoreContainer coreContainer, SolrQueryRequest solrQueryRequest, SolrQueryResponse solrQueryResponse) { super(coreContainer, solrQueryRequest, solrQueryResponse); } - @POST - @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2}) + @Override @PermissionName(COLL_EDIT_PERM) - public SolrJerseyResponse forceLeader( - @PathParam("collectionName") String collectionName, - @PathParam("shardName") String shardName) { + public SolrJerseyResponse forceShardLeader(String collectionName, String shardName) { final SolrJerseyResponse response = instantiateJerseyResponse(SolrJerseyResponse.class); ensureRequiredParameterProvided(COLLECTION_PROP, collectionName); ensureRequiredParameterProvided(SHARD_ID_PROP, shardName); @@ -84,12 +75,12 @@ public SolrJerseyResponse forceLeader( public static void invokeFromV1Params( CoreContainer coreContainer, SolrQueryRequest request, SolrQueryResponse response) { - final var api = new ForceLeaderAPI(coreContainer, request, response); + final var api = new ForceLeader(coreContainer, request, response); final var params = request.getParams(); params.required().check(COLLECTION_PROP, SHARD_ID_PROP); V2ApiUtils.squashIntoSolrResponseWithoutHeader( - response, api.forceLeader(params.get(COLLECTION_PROP), params.get(SHARD_ID_PROP))); + response, api.forceShardLeader(params.get(COLLECTION_PROP), params.get(SHARD_ID_PROP))); } private void doForceLeaderElection(String extCollectionName, String shardName) { diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/RenameCollectionAPI.java b/solr/core/src/java/org/apache/solr/handler/admin/api/RenameCollection.java similarity index 76% rename from solr/core/src/java/org/apache/solr/handler/admin/api/RenameCollectionAPI.java rename to solr/core/src/java/org/apache/solr/handler/admin/api/RenameCollection.java index 2fd2d7fb405..8cec8535a7f 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/api/RenameCollectionAPI.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/api/RenameCollection.java @@ -16,7 +16,6 @@ */ package org.apache.solr.handler.admin.api; -import static org.apache.solr.client.solrj.impl.BinaryResponseParser.BINARY_CONTENT_TYPE_V2; import static org.apache.solr.cloud.Overseer.QUEUE_OPERATION; import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP; import static org.apache.solr.common.params.CollectionAdminParams.FOLLOW_ALIASES; @@ -25,48 +24,40 @@ import static org.apache.solr.common.params.CommonParams.NAME; import static org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM; -import com.fasterxml.jackson.annotation.JsonProperty; import java.util.HashMap; import java.util.Map; import javax.inject.Inject; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; +import org.apache.solr.client.api.endpoint.RenameCollectionApi; +import org.apache.solr.client.api.model.RenameCollectionRequestBody; import org.apache.solr.client.api.model.SubResponseAccumulatingJerseyResponse; import org.apache.solr.common.SolrException; import org.apache.solr.common.cloud.ZkNodeProps; import org.apache.solr.common.params.CollectionParams; import org.apache.solr.core.CoreContainer; import org.apache.solr.handler.api.V2ApiUtils; -import org.apache.solr.jersey.JacksonReflectMapWriter; import org.apache.solr.jersey.PermissionName; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.SolrQueryResponse; /** - * V2 API for "renaming" an existing collection + * V2 API implementation to "rename" an existing collection * *

This API is analogous to the v1 /admin/collections?action=RENAME command. */ -@Path("/collections/{collectionName}/rename") -public class RenameCollectionAPI extends AdminAPIBase { +public class RenameCollection extends AdminAPIBase implements RenameCollectionApi { @Inject - public RenameCollectionAPI( + public RenameCollection( CoreContainer coreContainer, SolrQueryRequest solrQueryRequest, SolrQueryResponse solrQueryResponse) { super(coreContainer, solrQueryRequest, solrQueryResponse); } - @POST - @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2}) + @Override @PermissionName(COLL_EDIT_PERM) public SubResponseAccumulatingJerseyResponse renameCollection( - @PathParam("collectionName") String collectionName, RenameCollectionRequestBody requestBody) - throws Exception { + String collectionName, RenameCollectionRequestBody requestBody) throws Exception { final var response = instantiateJerseyResponse(SubResponseAccumulatingJerseyResponse.class); if (requestBody == null) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Missing required request body"); @@ -81,7 +72,7 @@ public SubResponseAccumulatingJerseyResponse renameCollection( response, CollectionParams.CollectionAction.RENAME, remoteMessage, - requestBody != null ? requestBody.asyncId : null); + requestBody != null ? requestBody.async : null); return response; } @@ -92,7 +83,7 @@ public static ZkNodeProps createRemoteMessage( remoteMessage.put(NAME, collectionName); remoteMessage.put(TARGET, requestBody.to); insertIfNotNull(remoteMessage, FOLLOW_ALIASES, requestBody.followAliases); - insertIfNotNull(remoteMessage, ASYNC, requestBody.asyncId); + insertIfNotNull(remoteMessage, ASYNC, requestBody.async); return new ZkNodeProps(remoteMessage); } @@ -100,26 +91,16 @@ public static ZkNodeProps createRemoteMessage( public static void invokeFromV1Params( CoreContainer coreContainer, SolrQueryRequest request, SolrQueryResponse response) throws Exception { - final var api = new RenameCollectionAPI(coreContainer, request, response); + final var api = new RenameCollection(coreContainer, request, response); final var params = request.getParams(); params.required().check(COLLECTION_PROP, TARGET); final var requestBody = new RenameCollectionRequestBody(); requestBody.to = params.get(TARGET); // Optional parameters - requestBody.asyncId = params.get(ASYNC); + requestBody.async = params.get(ASYNC); requestBody.followAliases = params.getBool(FOLLOW_ALIASES); V2ApiUtils.squashIntoSolrResponseWithoutHeader( response, api.renameCollection(params.get(COLLECTION_PROP), requestBody)); } - - public static class RenameCollectionRequestBody implements JacksonReflectMapWriter { - @JsonProperty(required = true) - public String to; - - @JsonProperty(ASYNC) - public String asyncId; - - @JsonProperty public Boolean followAliases; - } } diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/ReplaceNodeAPI.java b/solr/core/src/java/org/apache/solr/handler/admin/api/ReplaceNode.java similarity index 64% rename from solr/core/src/java/org/apache/solr/handler/admin/api/ReplaceNodeAPI.java rename to solr/core/src/java/org/apache/solr/handler/admin/api/ReplaceNode.java index e2e63760ab7..ab597b54038 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/api/ReplaceNodeAPI.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/api/ReplaceNode.java @@ -16,7 +16,6 @@ */ package org.apache.solr.handler.admin.api; -import static org.apache.solr.client.solrj.impl.BinaryResponseParser.BINARY_CONTENT_TYPE_V2; import static org.apache.solr.cloud.Overseer.QUEUE_OPERATION; import static org.apache.solr.common.params.CollectionParams.SOURCE_NODE; import static org.apache.solr.common.params.CollectionParams.TARGET_NODE; @@ -25,17 +24,11 @@ import static org.apache.solr.handler.admin.CollectionsHandler.DEFAULT_COLLECTION_OP_TIMEOUT; import static org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.parameters.RequestBody; import java.util.HashMap; import java.util.Map; import javax.inject.Inject; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; +import org.apache.solr.client.api.endpoint.ReplaceNodeApi; +import org.apache.solr.client.api.model.ReplaceNodeRequestBody; import org.apache.solr.client.api.model.SolrJerseyResponse; import org.apache.solr.client.solrj.SolrResponse; import org.apache.solr.common.cloud.ZkNodeProps; @@ -43,7 +36,6 @@ import org.apache.solr.common.params.CollectionParams.CollectionAction; import org.apache.solr.core.CoreContainer; import org.apache.solr.handler.admin.CollectionsHandler; -import org.apache.solr.jersey.JacksonReflectMapWriter; import org.apache.solr.jersey.PermissionName; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.response.SolrQueryResponse; @@ -53,26 +45,19 @@ * *

This API is analogous to the v1 /admin/collections?action=REPLACENODE command. */ -@Path("cluster/nodes/{sourceNodeName}/replace/") -public class ReplaceNodeAPI extends AdminAPIBase { +public class ReplaceNode extends AdminAPIBase implements ReplaceNodeApi { @Inject - public ReplaceNodeAPI( + public ReplaceNode( CoreContainer coreContainer, SolrQueryRequest solrQueryRequest, SolrQueryResponse solrQueryResponse) { super(coreContainer, solrQueryRequest, solrQueryResponse); } - @POST - @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2}) + @Override @PermissionName(COLL_EDIT_PERM) - public SolrJerseyResponse replaceNode( - @Parameter(description = "The name of the node to be replaced.", required = true) - @PathParam("sourceNodeName") - String sourceNodeName, - @RequestBody(description = "Contains user provided parameters", required = true) - ReplaceNodeRequestBody requestBody) + public SolrJerseyResponse replaceNode(String sourceNodeName, ReplaceNodeRequestBody requestBody) throws Exception { final SolrJerseyResponse response = instantiateJerseyResponse(SolrJerseyResponse.class); final CoreContainer coreContainer = fetchAndValidateZooKeeperAwareCoreContainer(); @@ -111,34 +96,4 @@ private void insertIfValueNotNull(Map dest, String key, Object v dest.put(key, value); } } - - public static class ReplaceNodeRequestBody implements JacksonReflectMapWriter { - - public ReplaceNodeRequestBody() {} - - public ReplaceNodeRequestBody(String targetNodeName, Boolean waitForFinalState, String async) { - this.targetNodeName = targetNodeName; - this.waitForFinalState = waitForFinalState; - this.async = async; - } - - @Schema( - description = - "The target node where replicas will be copied. If this parameter is not provided, Solr " - + "will identify nodes automatically based on policies or number of cores in each node.") - @JsonProperty("targetNodeName") - public String targetNodeName; - - @Schema( - description = - "If true, the request will complete only when all affected replicas become active. " - + "If false, the API will return the status of the single action, which may be " - + "before the new replica is online and active.") - @JsonProperty("waitForFinalState") - public Boolean waitForFinalState = false; - - @Schema(description = "Request ID to track this action which will be processed asynchronously.") - @JsonProperty("async") - public String async; - } } diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/SyncShardAPI.java b/solr/core/src/java/org/apache/solr/handler/admin/api/SyncShard.java similarity index 83% rename from solr/core/src/java/org/apache/solr/handler/admin/api/SyncShardAPI.java rename to solr/core/src/java/org/apache/solr/handler/admin/api/SyncShard.java index 1b7b44b0dea..b506f585673 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/api/SyncShardAPI.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/api/SyncShard.java @@ -17,7 +17,6 @@ package org.apache.solr.handler.admin.api; -import static org.apache.solr.client.solrj.impl.BinaryResponseParser.BINARY_CONTENT_TYPE_V2; import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP; import static org.apache.solr.common.cloud.ZkStateReader.SHARD_ID_PROP; import static org.apache.solr.security.PermissionNameProvider.Name.COLL_EDIT_PERM; @@ -25,11 +24,7 @@ import java.io.IOException; import java.util.concurrent.TimeUnit; import javax.inject.Inject; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; +import org.apache.solr.client.api.endpoint.SyncShardApi; import org.apache.solr.client.api.model.SolrJerseyResponse; import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrServerException; @@ -46,28 +41,25 @@ import org.apache.solr.response.SolrQueryResponse; /** - * V2 API for triggering a shard-sync operation within a particular collection and shard. + * V2 API implementation for triggering a shard-sync operation within a particular collection and + * shard. * *

This API (POST /v2/collections/cName/shards/sName/sync {...}) is analogous to the v1 * /admin/collections?action=SYNCSHARD command. */ -@Path("/collections/{collectionName}/shards/{shardName}/sync") -public class SyncShardAPI extends AdminAPIBase { +public class SyncShard extends AdminAPIBase implements SyncShardApi { @Inject - public SyncShardAPI( + public SyncShard( CoreContainer coreContainer, SolrQueryRequest solrQueryRequest, SolrQueryResponse solrQueryResponse) { super(coreContainer, solrQueryRequest, solrQueryResponse); } - @POST - @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2}) + @Override @PermissionName(COLL_EDIT_PERM) - public SolrJerseyResponse syncShard( - @PathParam("collectionName") String collectionName, @PathParam("shardName") String shardName) - throws Exception { + public SolrJerseyResponse syncShard(String collectionName, String shardName) throws Exception { final SolrJerseyResponse response = instantiateJerseyResponse(SolrJerseyResponse.class); ensureRequiredParameterProvided(COLLECTION_PROP, collectionName); ensureRequiredParameterProvided(SHARD_ID_PROP, shardName); @@ -105,7 +97,7 @@ private void doSyncShard(String extCollectionName, String shardName) public static void invokeFromV1Params( CoreContainer coreContainer, SolrQueryRequest request, SolrQueryResponse response) throws Exception { - final var api = new SyncShardAPI(coreContainer, request, response); + final var api = new SyncShard(coreContainer, request, response); final var params = request.getParams(); params.required().check(COLLECTION_PROP, SHARD_ID_PROP); diff --git a/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java b/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java index 0d5b6c27c00..10f99ac49f8 100644 --- a/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/component/SearchHandler.java @@ -35,6 +35,7 @@ import java.util.concurrent.atomic.AtomicLong; import org.apache.lucene.index.ExitableDirectoryReader; import org.apache.lucene.search.TotalHits; +import org.apache.solr.client.solrj.SolrRequest.SolrRequestType; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.cloud.ZkController; import org.apache.solr.common.SolrDocumentList; @@ -330,8 +331,8 @@ protected ResponseBuilder newResponseBuilder( } /** - * Check if circuit breakers are tripped. Override this method in sub classes that do not want to - * check circuit breakers. + * Check if {@link SolrRequestType#QUERY} circuit breakers are tripped. Override this method in + * sub classes that do not want to check circuit breakers. * * @return true if circuit breakers are tripped, false otherwise. */ @@ -340,18 +341,18 @@ protected boolean checkCircuitBreakers( final RTimerTree timer = rb.isDebug() ? req.getRequestTimer() : null; final CircuitBreakerRegistry circuitBreakerRegistry = req.getCore().getCircuitBreakerRegistry(); - if (circuitBreakerRegistry.isEnabled()) { + if (circuitBreakerRegistry.isEnabled(SolrRequestType.QUERY)) { List trippedCircuitBreakers; if (timer != null) { RTimerTree subt = timer.sub("circuitbreaker"); rb.setTimer(subt); - trippedCircuitBreakers = circuitBreakerRegistry.checkTripped(); + trippedCircuitBreakers = circuitBreakerRegistry.checkTripped(SolrRequestType.QUERY); rb.getTimer().stop(); } else { - trippedCircuitBreakers = circuitBreakerRegistry.checkTripped(); + trippedCircuitBreakers = circuitBreakerRegistry.checkTripped(SolrRequestType.QUERY); } if (trippedCircuitBreakers != null) { @@ -359,7 +360,7 @@ protected boolean checkCircuitBreakers( rsp.add(STATUS, FAILURE); rsp.setException( new SolrException( - SolrException.ErrorCode.SERVICE_UNAVAILABLE, + CircuitBreaker.getErrorCode(trippedCircuitBreakers), "Circuit Breakers tripped " + errorMessage)); return true; } diff --git a/solr/core/src/java/org/apache/solr/jersey/PostRequestLoggingFilter.java b/solr/core/src/java/org/apache/solr/jersey/PostRequestLoggingFilter.java index 4ce9490c115..3925b297d6a 100644 --- a/solr/core/src/java/org/apache/solr/jersey/PostRequestLoggingFilter.java +++ b/solr/core/src/java/org/apache/solr/jersey/PostRequestLoggingFilter.java @@ -101,7 +101,7 @@ public void filter( response.responseHeader.qTime); /* slowQueryThresholdMillis defaults to -1 in SolrConfig -- not enabled.*/ - if (log.isWarnEnabled() + if (slowCoreRequestLogger.isWarnEnabled() && solrConfig != null && solrConfig.slowQueryThresholdMillis >= 0 && response.responseHeader.qTime >= solrConfig.slowQueryThresholdMillis) { diff --git a/solr/core/src/java/org/apache/solr/security/PublicKeyAPI.java b/solr/core/src/java/org/apache/solr/security/GetPublicKey.java similarity index 63% rename from solr/core/src/java/org/apache/solr/security/PublicKeyAPI.java rename to solr/core/src/java/org/apache/solr/security/GetPublicKey.java index 46483462e5f..1f7e991667d 100644 --- a/solr/core/src/java/org/apache/solr/security/PublicKeyAPI.java +++ b/solr/core/src/java/org/apache/solr/security/GetPublicKey.java @@ -17,45 +17,31 @@ package org.apache.solr.security; -import static org.apache.solr.client.solrj.impl.BinaryResponseParser.BINARY_CONTENT_TYPE_V2; - -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.media.Schema; import javax.inject.Inject; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; import org.apache.solr.api.JerseyResource; -import org.apache.solr.client.api.model.SolrJerseyResponse; +import org.apache.solr.client.api.endpoint.GetPublicKeyApi; +import org.apache.solr.client.api.model.PublicKeyResponse; import org.apache.solr.jersey.PermissionName; /** - * V2 API for fetching the public key of the receiving node. + * V2 API implementation to fetch the public key of the receiving node. * *

This API is analogous to the v1 /admin/info/key endpoint. */ -@Path("/node/key") -public class PublicKeyAPI extends JerseyResource { +public class GetPublicKey extends JerseyResource implements GetPublicKeyApi { private final SolrNodeKeyPair nodeKeyPair; @Inject - public PublicKeyAPI(SolrNodeKeyPair nodeKeyPair) { + public GetPublicKey(SolrNodeKeyPair nodeKeyPair) { this.nodeKeyPair = nodeKeyPair; } - @GET - @Produces({"application/json", "application/xml", BINARY_CONTENT_TYPE_V2}) + @Override @PermissionName(PermissionNameProvider.Name.ALL) public PublicKeyResponse getPublicKey() { final PublicKeyResponse response = instantiateJerseyResponse(PublicKeyResponse.class); response.key = nodeKeyPair.getKeyPair().getPublicKeyStr(); return response; } - - public static class PublicKeyResponse extends SolrJerseyResponse { - @JsonProperty("key") - @Schema(description = "The public key of the receiving Solr node.") - public String key; - } } diff --git a/solr/core/src/java/org/apache/solr/security/PublicKeyHandler.java b/solr/core/src/java/org/apache/solr/security/PublicKeyHandler.java index 9dbde9d0966..5f2941fec23 100644 --- a/solr/core/src/java/org/apache/solr/security/PublicKeyHandler.java +++ b/solr/core/src/java/org/apache/solr/security/PublicKeyHandler.java @@ -50,7 +50,7 @@ public CryptoKeys.RSAKeyPair getKeyPair() { @Override public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception { V2ApiUtils.squashIntoSolrResponseWithoutHeader( - rsp, new PublicKeyAPI(nodeKeyPair).getPublicKey()); + rsp, new GetPublicKey(nodeKeyPair).getPublicKey()); } @Override @@ -80,6 +80,6 @@ public Collection getApis() { @Override public Collection> getJerseyResources() { - return List.of(PublicKeyAPI.class); + return List.of(GetPublicKey.class); } } 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 7b9c2b7e90c..4bb869ca1ec 100644 --- a/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java +++ b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java @@ -239,7 +239,13 @@ private void dispatch( if (log.isDebugEnabled()) { log.debug("User principal: {}", request.getUserPrincipal()); } - TraceUtils.setUser(span, String.valueOf(request.getUserPrincipal())); + final String principalName; + if (request.getUserPrincipal() != null) { + principalName = request.getUserPrincipal().getName(); + } else { + principalName = null; + } + TraceUtils.setUser(span, String.valueOf(principalName)); } HttpSolrCall call = getHttpSolrCall(request, response, retry); diff --git a/solr/core/src/java/org/apache/solr/util/circuitbreaker/CPUCircuitBreaker.java b/solr/core/src/java/org/apache/solr/util/circuitbreaker/CPUCircuitBreaker.java index 3e9cf47a2e5..262bd80444d 100644 --- a/solr/core/src/java/org/apache/solr/util/circuitbreaker/CPUCircuitBreaker.java +++ b/solr/core/src/java/org/apache/solr/util/circuitbreaker/CPUCircuitBreaker.java @@ -89,7 +89,7 @@ public String getDebugInfo() { @Override public String getErrorMessage() { - return "CPU Circuit Breaker triggered as seen CPU usage is above allowed threshold." + return "CPU Circuit Breaker triggered as seen CPU usage is above allowed threshold. " + "Seen CPU usage " + seenCPUUsage.get() + " and allocated threshold " diff --git a/solr/core/src/java/org/apache/solr/util/circuitbreaker/CircuitBreaker.java b/solr/core/src/java/org/apache/solr/util/circuitbreaker/CircuitBreaker.java index 8959c35e7a8..3082bf82e4a 100644 --- a/solr/core/src/java/org/apache/solr/util/circuitbreaker/CircuitBreaker.java +++ b/solr/core/src/java/org/apache/solr/util/circuitbreaker/CircuitBreaker.java @@ -17,6 +17,12 @@ package org.apache.solr.util.circuitbreaker; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.stream.Collectors; +import org.apache.solr.client.solrj.SolrRequest.SolrRequestType; +import org.apache.solr.common.SolrException; import org.apache.solr.common.util.NamedList; import org.apache.solr.util.SolrPluginUtils; import org.apache.solr.util.plugin.NamedListInitializedPlugin; @@ -36,6 +42,10 @@ * @lucene.experimental */ public abstract class CircuitBreaker implements NamedListInitializedPlugin { + // Only query requests are checked by default + private Set requestTypes = Set.of(SolrRequestType.QUERY); + private final List SUPPORTED_TYPES = + List.of(SolrRequestType.QUERY, SolrRequestType.UPDATE); @Override public void init(NamedList args) { @@ -52,4 +62,48 @@ public CircuitBreaker() {} /** Get error message when the circuit breaker triggers */ public abstract String getErrorMessage(); + + /** + * Set the request types for which this circuit breaker should be checked. If not called, the + * circuit breaker will be checked for the {@link SolrRequestType#QUERY} request type only. + * + * @param requestTypes list of strings representing request types + * @throws IllegalArgumentException if the request type is not valid + */ + public void setRequestTypes(List requestTypes) { + this.requestTypes = + requestTypes.stream() + .map(t -> SolrRequestType.valueOf(t.toUpperCase(Locale.ROOT))) + .peek( + t -> { + if (!SUPPORTED_TYPES.contains(t)) { + throw new IllegalArgumentException( + String.format( + Locale.ROOT, + "Request type %s is not supported for circuit breakers", + t.name())); + } + }) + .collect(Collectors.toSet()); + } + + public Set getRequestTypes() { + return requestTypes; + } + + /** + * Return the proper error code to use in exception. For legacy use of {@link CircuitBreaker} we + * return 503 for backward compatibility, else return 429. + * + * @deprecated Remove in 10.0 + */ + @Deprecated(since = "9.4") + public static SolrException.ErrorCode getErrorCode(List trippedCircuitBreakers) { + if (trippedCircuitBreakers != null + && trippedCircuitBreakers.stream().anyMatch(cb -> cb instanceof CircuitBreakerManager)) { + return SolrException.ErrorCode.SERVICE_UNAVAILABLE; + } else { + return SolrException.ErrorCode.TOO_MANY_REQUESTS; + } + } } diff --git a/solr/core/src/java/org/apache/solr/util/circuitbreaker/CircuitBreakerRegistry.java b/solr/core/src/java/org/apache/solr/util/circuitbreaker/CircuitBreakerRegistry.java index 0cb3fb0a378..84c2f61fb9b 100644 --- a/solr/core/src/java/org/apache/solr/util/circuitbreaker/CircuitBreakerRegistry.java +++ b/solr/core/src/java/org/apache/solr/util/circuitbreaker/CircuitBreakerRegistry.java @@ -19,7 +19,11 @@ import com.google.common.annotations.VisibleForTesting; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import org.apache.solr.client.solrj.SolrRequest.SolrRequestType; /** * Keeps track of all registered circuit breaker instances for various request types. Responsible @@ -30,27 +34,37 @@ */ public class CircuitBreakerRegistry { - private final List circuitBreakerList = new ArrayList<>(); + private final Map> circuitBreakerMap = new HashMap<>(); public CircuitBreakerRegistry() {} public void register(CircuitBreaker circuitBreaker) { - circuitBreakerList.add(circuitBreaker); + circuitBreaker + .getRequestTypes() + .forEach( + r -> { + List list = + circuitBreakerMap.computeIfAbsent(r, k -> new ArrayList<>()); + list.add(circuitBreaker); + }); } @VisibleForTesting public void deregisterAll() { - circuitBreakerList.clear(); + circuitBreakerMap.clear(); } + /** * Check and return circuit breakers that have triggered * + * @param requestType {@link SolrRequestType} to check for. * @return CircuitBreakers which have triggered, null otherwise. */ - public List checkTripped() { + public List checkTripped(SolrRequestType requestType) { List triggeredCircuitBreakers = null; - for (CircuitBreaker circuitBreaker : circuitBreakerList) { + for (CircuitBreaker circuitBreaker : + circuitBreakerMap.getOrDefault(requestType, Collections.emptyList())) { if (circuitBreaker.isTripped()) { if (triggeredCircuitBreakers == null) { triggeredCircuitBreakers = new ArrayList<>(); @@ -63,22 +77,6 @@ public List checkTripped() { return triggeredCircuitBreakers; } - /** - * Returns true if *any* circuit breaker has triggered, false if none have triggered. - * - *

NOTE: This method short circuits the checking of circuit breakers -- the method will return - * as soon as it finds a circuit breaker that has triggered. - */ - public boolean checkAnyTripped() { - for (CircuitBreaker circuitBreaker : circuitBreakerList) { - if (circuitBreaker.isTripped()) { - return true; - } - } - - return false; - } - /** * Construct the final error message to be printed when circuit breakers trip. * @@ -96,7 +94,7 @@ public static String toErrorMessage(List circuitBreakerList) { return sb.toString(); } - public boolean isEnabled() { - return !circuitBreakerList.isEmpty(); + public boolean isEnabled(SolrRequestType requestType) { + return circuitBreakerMap.containsKey(requestType); } } diff --git a/solr/core/src/java/org/apache/solr/util/circuitbreaker/MemoryCircuitBreaker.java b/solr/core/src/java/org/apache/solr/util/circuitbreaker/MemoryCircuitBreaker.java index 49311ddc934..0a568e5bf9e 100644 --- a/solr/core/src/java/org/apache/solr/util/circuitbreaker/MemoryCircuitBreaker.java +++ b/solr/core/src/java/org/apache/solr/util/circuitbreaker/MemoryCircuitBreaker.java @@ -89,7 +89,7 @@ public String getDebugInfo() { @Override public String getErrorMessage() { - return "Memory Circuit Breaker triggered as JVM heap usage values are greater than allocated threshold." + return "Memory Circuit Breaker triggered as JVM heap usage values are greater than allocated threshold. " + "Seen JVM heap memory usage " + seenMemory.get() + " and allocated threshold " diff --git a/solr/core/src/java/org/apache/solr/util/tracing/TraceUtils.java b/solr/core/src/java/org/apache/solr/util/tracing/TraceUtils.java index 3505f4daac6..e63d8c6cbde 100644 --- a/solr/core/src/java/org/apache/solr/util/tracing/TraceUtils.java +++ b/solr/core/src/java/org/apache/solr/util/tracing/TraceUtils.java @@ -25,6 +25,7 @@ import io.opentelemetry.api.trace.TracerProvider; import io.opentelemetry.context.Context; import io.opentelemetry.context.propagation.TextMapPropagator; +import java.util.List; import java.util.function.Consumer; import javax.servlet.http.HttpServletRequest; import org.apache.solr.client.solrj.SolrRequest; @@ -52,6 +53,8 @@ public class TraceUtils { public static final AttributeKey TAG_RESPONSE_WRITER = AttributeKey.stringKey("responseWriter"); public static final AttributeKey TAG_CONTENT_TYPE = AttributeKey.stringKey("contentType"); + public static final AttributeKey> TAG_OPS = AttributeKey.stringArrayKey("ops"); + public static final AttributeKey TAG_CLASS = AttributeKey.stringKey("class"); @Deprecated private static final AttributeKey TAG_HTTP_METHOD_DEP = @@ -140,4 +143,11 @@ public static Span startHttpRequestSpan(HttpServletRequest request, Context cont spanBuilder.setAttribute(TAG_DB_TYPE, TAG_DB_TYPE_SOLR); return spanBuilder.startSpan(); } + + public static void setOperations(SolrQueryRequest req, String clazz, List ops) { + if (!ops.isEmpty()) { + req.getSpan().setAttribute(TAG_OPS, ops); + req.getSpan().setAttribute(TAG_CLASS, clazz); + } + } } diff --git a/solr/core/src/test-files/solr/collection1/conf/solrconfig-nodelevelcaches.xml b/solr/core/src/test-files/solr/collection1/conf/solrconfig-nodelevelcaches.xml deleted file mode 100644 index d6d33fe7bc6..00000000000 --- a/solr/core/src/test-files/solr/collection1/conf/solrconfig-nodelevelcaches.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - ${tests.luceneMatchVersion:LATEST} - ${solr.data.dir:} - - - - - - - - diff --git a/solr/core/src/test-files/solr/collection1/conf/solrconfig-pluggable-circuitbreaker.xml b/solr/core/src/test-files/solr/collection1/conf/solrconfig-pluggable-circuitbreaker.xml index 660e7952e70..8719a00ea7b 100644 --- a/solr/core/src/test-files/solr/collection1/conf/solrconfig-pluggable-circuitbreaker.xml +++ b/solr/core/src/test-files/solr/collection1/conf/solrconfig-pluggable-circuitbreaker.xml @@ -79,7 +79,19 @@ - 75 + 99 + + update + + + + + 80 + diff --git a/solr/core/src/test-files/solr/solr-nodelevelcaches.xml b/solr/core/src/test-files/solr/solr-nodelevelcaches.xml deleted file mode 100644 index cc99abb7a5a..00000000000 --- a/solr/core/src/test-files/solr/solr-nodelevelcaches.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - diff --git a/solr/core/src/test/org/apache/solr/cloud/BalanceReplicasTest.java b/solr/core/src/test/org/apache/solr/cloud/BalanceReplicasTest.java index 82a75027e68..a14b372df2e 100644 --- a/solr/core/src/test/org/apache/solr/cloud/BalanceReplicasTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/BalanceReplicasTest.java @@ -33,14 +33,15 @@ import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.ContentType; import org.apache.http.util.EntityUtils; +import org.apache.solr.client.api.model.BalanceReplicasRequestBody; import org.apache.solr.client.solrj.impl.CloudLegacySolrClient; import org.apache.solr.client.solrj.impl.CloudSolrClient; import org.apache.solr.client.solrj.request.CollectionAdminRequest; +import org.apache.solr.common.MapWriterMap; import org.apache.solr.common.cloud.DocCollection; import org.apache.solr.common.cloud.Replica; import org.apache.solr.common.util.StrUtils; import org.apache.solr.common.util.Utils; -import org.apache.solr.handler.admin.api.BalanceReplicasAPI; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -101,7 +102,7 @@ public void testAllNodes() throws Exception { postDataAndGetResponse( cluster.getSolrClient(), "/api/cluster/replicas/balance", - BalanceReplicasAPI.BalanceReplicasRequestBody.EMPTY); + new MapWriterMap(Collections.emptyMap())); collection = cloudClient.getClusterState().getCollectionOrNull(coll, false); log.debug("### After balancing: {}", collection); @@ -149,8 +150,8 @@ public void testSomeNodes() throws Exception { postDataAndGetResponse( cluster.getSolrClient(), "/api/cluster/replicas/balance", - new BalanceReplicasAPI.BalanceReplicasRequestBody( - new HashSet<>(l.subList(1, 4)), true, null)); + Utils.getReflectWriter( + new BalanceReplicasRequestBody(new HashSet<>(l.subList(1, 4)), true, null))); collection = cloudClient.getClusterState().getCollectionOrNull(coll, false); log.debug("### After balancing: {}", collection); diff --git a/solr/core/src/test/org/apache/solr/cloud/TestDistributedMap.java b/solr/core/src/test/org/apache/solr/cloud/TestDistributedMap.java index 0b3325e96e5..aa5915f007b 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestDistributedMap.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestDistributedMap.java @@ -23,6 +23,7 @@ import java.util.concurrent.TimeUnit; import org.apache.commons.io.file.PathUtils; import org.apache.solr.SolrTestCaseJ4; +import org.apache.solr.common.SolrException; import org.apache.solr.common.cloud.SolrZkClient; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; @@ -218,6 +219,36 @@ public void testClear() throws KeeperException, InterruptedException { } } + public void testMalformed() throws InterruptedException, KeeperException { + try (SolrZkClient zkClient = + new SolrZkClient.Builder() + .withUrl(zkServer.getZkHost()) + .withTimeout(10000, TimeUnit.MILLISECONDS) + .build()) { + String path = getAndMakeInitialPath(zkClient); + DistributedMap map = createMap(zkClient, path); + expectThrows(SolrException.class, () -> map.put("has/slash", new byte[0])); + } + } + + public void testRemoveMalformed() throws InterruptedException, KeeperException { + try (SolrZkClient zkClient = + new SolrZkClient.Builder() + .withUrl(zkServer.getZkHost()) + .withTimeout(10000, TimeUnit.MILLISECONDS) + .build()) { + String path = getAndMakeInitialPath(zkClient); + // Add a "legacy" / malformed key + final var key = "slash/test/0"; + zkClient.makePath(path + "/" + DistributedMap.PREFIX + key, new byte[0], true); + + DistributedMap map = createMap(zkClient, path); + assertEquals(1, map.size()); + map.remove("slash"); + assertEquals(0, map.size()); + } + } + protected DistributedMap createMap(SolrZkClient zkClient, String path) { return new DistributedMap(zkClient, path); } diff --git a/solr/core/src/test/org/apache/solr/cloud/TestSizeLimitedDistributedMap.java b/solr/core/src/test/org/apache/solr/cloud/TestSizeLimitedDistributedMap.java index 493b7bf062b..a534e2e2a30 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestSizeLimitedDistributedMap.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestSizeLimitedDistributedMap.java @@ -25,9 +25,11 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import org.apache.solr.common.cloud.SolrZkClient; import org.apache.solr.common.util.ExecutorUtil; import org.apache.solr.common.util.SolrNamedThreadFactory; +import org.apache.zookeeper.KeeperException; public class TestSizeLimitedDistributedMap extends TestDistributedMap { @@ -136,4 +138,32 @@ public void testConcurrentCleanup() throws Exception { protected DistributedMap createMap(SolrZkClient zkClient, String path) { return new SizeLimitedDistributedMap(zkClient, path, Overseer.NUM_RESPONSES_TO_STORE, null); } + + public void testCleanupForKeysWithSlashes() throws InterruptedException, KeeperException { + try (SolrZkClient zkClient = + new SolrZkClient.Builder() + .withUrl(zkServer.getZkHost()) + .withTimeout(10000, TimeUnit.MILLISECONDS) + .build()) { + int maxEntries = 10; + String path = getAndMakeInitialPath(zkClient); + + // Add a "legacy" / malformed key + zkClient.makePath(path + "/" + DistributedMap.PREFIX + "slash/test/0", new byte[0], true); + + AtomicInteger overFlowCounter = new AtomicInteger(); + DistributedMap map = + new SizeLimitedDistributedMap( + zkClient, path, maxEntries, (element) -> overFlowCounter.incrementAndGet()); + + // Now add regular keys until we reach the size limit of the map. + // Once we hit the limit, the oldest item (the one we added above with slashes) is deleted, + // but that fails. + for (int i = 1; i <= maxEntries; ++i) { + map.put(String.valueOf(i), new byte[0]); + } + assertTrue(map.size() <= maxEntries); + assertEquals(1, overFlowCounter.get()); + } + } } diff --git a/solr/core/src/test/org/apache/solr/core/TestSolrXml.java b/solr/core/src/test/org/apache/solr/core/TestSolrXml.java index 1e547f3ed88..51ac2bb0e65 100644 --- a/solr/core/src/test/org/apache/solr/core/TestSolrXml.java +++ b/solr/core/src/test/org/apache/solr/core/TestSolrXml.java @@ -34,6 +34,7 @@ import org.apache.solr.search.CacheConfig; import org.apache.solr.search.CaffeineCache; import org.apache.solr.search.SolrCache; +import org.apache.solr.search.TestThinCache; import org.apache.solr.search.ThinCache; import org.apache.solr.update.UpdateShardHandlerConfig; import org.hamcrest.MatcherAssert; @@ -155,11 +156,9 @@ public void testPropertySub() throws IOException { assertFalse("schema cache", cfg.hasSchemaCache()); } - public void testNodeLevelCache() throws IOException { - Path testSrcRoot = TEST_PATH(); - Files.copy(testSrcRoot.resolve("solr-nodelevelcaches.xml"), solrHome.resolve("solr.xml")); - - NodeConfig cfg = SolrXmlConfig.fromSolrHome(solrHome, new Properties()); + public void testNodeLevelCache() { + NodeConfig cfg = + SolrXmlConfig.fromString(createTempDir(), TestThinCache.SOLR_NODE_LEVEL_CACHE_XML); Map cachesConfig = cfg.getCachesConfig(); SolrCache nodeLevelCache = cachesConfig.get("myNodeLevelCache").newInstance(); assertTrue(nodeLevelCache instanceof CaffeineCache); diff --git a/solr/core/src/test/org/apache/solr/handler/admin/api/ForceLeaderAPITest.java b/solr/core/src/test/org/apache/solr/handler/admin/api/ForceLeaderAPITest.java index 09f97a4757f..be1fce44fb8 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/api/ForceLeaderAPITest.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/api/ForceLeaderAPITest.java @@ -21,7 +21,7 @@ import org.apache.solr.common.SolrException; import org.junit.Test; -/** Unit tests for {@link ForceLeaderAPI} */ +/** Unit tests for {@link ForceLeader} */ public class ForceLeaderAPITest extends SolrTestCaseJ4 { @Test public void testReportsErrorIfCollectionNameMissing() { @@ -29,8 +29,8 @@ public void testReportsErrorIfCollectionNameMissing() { expectThrows( SolrException.class, () -> { - final var api = new ForceLeaderAPI(null, null, null); - api.forceLeader(null, "someShard"); + final var api = new ForceLeader(null, null, null); + api.forceShardLeader(null, "someShard"); }); assertEquals(400, thrown.code()); @@ -43,8 +43,8 @@ public void testReportsErrorIfShardNameMissing() { expectThrows( SolrException.class, () -> { - final var api = new ForceLeaderAPI(null, null, null); - api.forceLeader("someCollection", null); + final var api = new ForceLeader(null, null, null); + api.forceShardLeader("someCollection", null); }); assertEquals(400, thrown.code()); diff --git a/solr/core/src/test/org/apache/solr/handler/admin/api/MigrateReplicasAPITest.java b/solr/core/src/test/org/apache/solr/handler/admin/api/MigrateReplicasAPITest.java index e87a4c67532..f9bf865d4e0 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/api/MigrateReplicasAPITest.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/api/MigrateReplicasAPITest.java @@ -40,7 +40,7 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; -/** Unit tests for {@link ReplaceNodeAPI} */ +/** Unit tests for {@link ReplaceNode} */ public class MigrateReplicasAPITest extends SolrTestCaseJ4 { private CoreContainer mockCoreContainer; diff --git a/solr/core/src/test/org/apache/solr/handler/admin/api/ReplaceNodeAPITest.java b/solr/core/src/test/org/apache/solr/handler/admin/api/ReplaceNodeAPITest.java index 3a460245775..e49eb56de0d 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/api/ReplaceNodeAPITest.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/api/ReplaceNodeAPITest.java @@ -25,6 +25,7 @@ import java.util.Map; import java.util.Optional; import org.apache.solr.SolrTestCaseJ4; +import org.apache.solr.client.api.model.ReplaceNodeRequestBody; import org.apache.solr.cloud.OverseerSolrResponse; import org.apache.solr.cloud.api.collections.DistributedCollectionConfigSetCommandRunner; import org.apache.solr.common.cloud.ZkNodeProps; @@ -37,13 +38,13 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; -/** Unit tests for {@link ReplaceNodeAPI} */ +/** Unit tests for {@link ReplaceNode} */ public class ReplaceNodeAPITest extends SolrTestCaseJ4 { private CoreContainer mockCoreContainer; private SolrQueryRequest mockQueryRequest; private SolrQueryResponse queryResponse; - private ReplaceNodeAPI replaceNodeApi; + private ReplaceNode replaceNodeApi; private DistributedCollectionConfigSetCommandRunner mockCommandRunner; private ArgumentCaptor messageCapturer; @@ -65,7 +66,7 @@ public void setUp() throws Exception { .thenReturn(new OverseerSolrResponse(new NamedList<>())); mockQueryRequest = mock(SolrQueryRequest.class); queryResponse = new SolrQueryResponse(); - replaceNodeApi = new ReplaceNodeAPI(mockCoreContainer, mockQueryRequest, queryResponse); + replaceNodeApi = new ReplaceNode(mockCoreContainer, mockQueryRequest, queryResponse); messageCapturer = ArgumentCaptor.forClass(ZkNodeProps.class); when(mockCoreContainer.isZooKeeperAware()).thenReturn(true); @@ -73,8 +74,7 @@ public void setUp() throws Exception { @Test public void testCreatesValidOverseerMessage() throws Exception { - ReplaceNodeAPI.ReplaceNodeRequestBody requestBody = - new ReplaceNodeAPI.ReplaceNodeRequestBody("demoTargetNode", false, "async"); + final var requestBody = new ReplaceNodeRequestBody("demoTargetNode", false, "async"); replaceNodeApi.replaceNode("demoSourceNode", requestBody); verify(mockCommandRunner).runCollectionCommand(messageCapturer.capture(), any(), anyLong()); @@ -102,8 +102,7 @@ public void testRequestBodyCanBeOmittedAltogether() throws Exception { @Test public void testOptionalValuesNotAddedToRemoteMessageIfNotProvided() throws Exception { - ReplaceNodeAPI.ReplaceNodeRequestBody requestBody = - new ReplaceNodeAPI.ReplaceNodeRequestBody("demoTargetNode", null, null); + final var requestBody = new ReplaceNodeRequestBody("demoTargetNode", null, null); replaceNodeApi.replaceNode("demoSourceNode", requestBody); verify(mockCommandRunner).runCollectionCommand(messageCapturer.capture(), any(), anyLong()); diff --git a/solr/core/src/test/org/apache/solr/handler/admin/api/SyncShardAPITest.java b/solr/core/src/test/org/apache/solr/handler/admin/api/SyncShardAPITest.java index 25ca5bb9cd1..23d3f8982a2 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/api/SyncShardAPITest.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/api/SyncShardAPITest.java @@ -21,7 +21,7 @@ import org.apache.solr.common.SolrException; import org.junit.Test; -/** Unit tests for {@link SyncShardAPI} */ +/** Unit tests for {@link SyncShard} */ public class SyncShardAPITest extends SolrTestCaseJ4 { @Test public void testReportsErrorIfCollectionNameMissing() { @@ -29,7 +29,7 @@ public void testReportsErrorIfCollectionNameMissing() { expectThrows( SolrException.class, () -> { - final var api = new SyncShardAPI(null, null, null); + final var api = new SyncShard(null, null, null); api.syncShard(null, "someShard"); }); @@ -43,7 +43,7 @@ public void testReportsErrorIfShardNameMissing() { expectThrows( SolrException.class, () -> { - final var api = new SyncShardAPI(null, null, null); + final var api = new SyncShard(null, null, null); api.syncShard("someCollection", null); }); diff --git a/solr/core/src/test/org/apache/solr/handler/configsets/ListConfigSetsAPITest.java b/solr/core/src/test/org/apache/solr/handler/configsets/ListConfigSetsAPITest.java index 635dc8305e5..a0cf41622cd 100644 --- a/solr/core/src/test/org/apache/solr/handler/configsets/ListConfigSetsAPITest.java +++ b/solr/core/src/test/org/apache/solr/handler/configsets/ListConfigSetsAPITest.java @@ -91,7 +91,7 @@ public void testSuccessfulListConfigsetsRaw() throws Exception { when(mockCoreContainer.getConfigSetService()).thenReturn(configSetService); when(configSetService.listConfigs()).thenReturn(List.of("cs1", "cs2")); - final Response response = target("/cluster/configs").request().get(); + final Response response = target("/cluster/configs").request("application/json").get(); final String jsonBody = response.readEntity(String.class); assertEquals(200, response.getStatus()); @@ -108,7 +108,8 @@ public void testSuccessfulListConfigsetsTyped() throws Exception { when(mockCoreContainer.getConfigSetService()).thenReturn(configSetService); when(configSetService.listConfigs()).thenReturn(List.of("cs1", "cs2")); - final var response = target("/cluster/configs").request().get(ListConfigsetsResponse.class); + final var response = + target("/cluster/configs").request("application/json").get(ListConfigsetsResponse.class); assertNotNull(response.configSets); assertNull(response.error); @@ -132,7 +133,8 @@ public void testListConfigsetsV1Compatibility() throws Exception { when(mockCoreContainer.getConfigSetService()).thenReturn(configSetService); when(configSetService.listConfigs()).thenReturn(List.of("cs1", "cs2")); - final var response = target("/cluster/configs").request().get(ListConfigsetsResponse.class); + final var response = + target("/cluster/configs").request("application/json").get(ListConfigsetsResponse.class); final NamedList squashedResponse = new NamedList<>(); V2ApiUtils.squashIntoNamedList(squashedResponse, response); final ConfigSetAdminResponse.List solrjResponse = new ConfigSetAdminResponse.List(); diff --git a/solr/core/src/test/org/apache/solr/search/TestThinCache.java b/solr/core/src/test/org/apache/solr/search/TestThinCache.java index 95f795054ad..c485b9fe46a 100644 --- a/solr/core/src/test/org/apache/solr/search/TestThinCache.java +++ b/solr/core/src/test/org/apache/solr/search/TestThinCache.java @@ -26,13 +26,63 @@ import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.metrics.SolrMetricManager; import org.apache.solr.metrics.SolrMetricsContext; +import org.apache.solr.util.EmbeddedSolrServerTestRule; +import org.apache.solr.util.TestHarness; import org.apache.solr.util.stats.MetricUtils; import org.junit.BeforeClass; +import org.junit.ClassRule; import org.junit.Test; /** Test for {@link ThinCache}. */ public class TestThinCache extends SolrTestCaseJ4 { + @ClassRule public static EmbeddedSolrServerTestRule solrRule = new EmbeddedSolrServerTestRule(); + public static final String SOLR_NODE_LEVEL_CACHE_XML = + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + @BeforeClass + public static void setupSolrHome() throws Exception { + Path home = createTempDir("home"); + Files.writeString(home.resolve("solr.xml"), SOLR_NODE_LEVEL_CACHE_XML); + + solrRule.startSolr(home); + + Path configSet = createTempDir("configSet"); + copyMinConf(configSet.toFile()); + // insert a special filterCache configuration + Path solrConfig = configSet.resolve("conf/solrconfig.xml"); + Files.writeString( + solrConfig, + Files.readString(solrConfig) + .replace( + "", + "\n" + + "\n" + + "")); + + solrRule.newCollection().withConfigSet(configSet.toString()).create(); + + // legacy; get rid of this someday! + h = new TestHarness(solrRule.getCoreContainer()); + lrf = h.getRequestFactory("/select", 0, 20); + } + SolrMetricManager metricManager = new SolrMetricManager(); String registry = TestUtil.randomSimpleString(random(), 2, 10); String scope = TestUtil.randomSimpleString(random(), 2, 10); @@ -126,35 +176,4 @@ public void testInitCore() throws Exception { // for the other node-level cache, simply check that metrics are accessible assertEquals(0, nodeMetricsSnapshot.get("CACHE.nodeLevelCache/myNodeLevelCache.size")); } - - @BeforeClass - public static void setupSolrHome() throws Exception { - // make a solr home underneath the test's TEMP_DIR, else we don't have write access to copy in - // `solr.xml` - Path tmpFile = createTempDir(); - - // make data and conf dirs - Files.createDirectories(tmpFile.resolve("data")); - Path confDir = tmpFile.resolve("collection1").resolve("conf"); - Files.createDirectories(confDir); - - // copy over configuration files - copyXmlToHome( - tmpFile.toFile(), - TEST_PATH().resolve("solr-nodelevelcaches.xml").toAbsolutePath().toString()); - Files.copy( - getFile("solr/collection1/conf/solrconfig-nodelevelcaches.xml").toPath(), - confDir.resolve("solrconfig.xml")); - Files.copy( - getFile("solr/collection1/conf/solrconfig.snippet.randomindexconfig.xml").toPath(), - confDir.resolve("solrconfig.snippet.randomindexconfig.xml")); - Files.copy( - getFile("solr/collection1/conf/schema-minimal.xml").toPath(), - confDir.resolve("schema.xml")); - - // we want the actual `solr.xml` file to be read, instead of the normal operation, which creates - // a synthetic "test NodeConfig" - System.setProperty("solr.tests.loadSolrXml", "true"); - initCore("solrconfig.xml", "schema.xml", tmpFile.toAbsolutePath().toString()); - } } diff --git a/solr/core/src/test/org/apache/solr/security/PublicKeyAPITest.java b/solr/core/src/test/org/apache/solr/security/GetPublicKeyTest.java similarity index 84% rename from solr/core/src/test/org/apache/solr/security/PublicKeyAPITest.java rename to solr/core/src/test/org/apache/solr/security/GetPublicKeyTest.java index f75b32b85d9..77bf4646a74 100644 --- a/solr/core/src/test/org/apache/solr/security/PublicKeyAPITest.java +++ b/solr/core/src/test/org/apache/solr/security/GetPublicKeyTest.java @@ -20,14 +20,14 @@ import org.apache.solr.SolrTestCaseJ4; import org.junit.Test; -/** Unit test for {@link PublicKeyAPI} */ -public class PublicKeyAPITest extends SolrTestCaseJ4 { +/** Unit test for {@link GetPublicKey} */ +public class GetPublicKeyTest extends SolrTestCaseJ4 { @Test public void testRetrievesPublicKey() { final SolrNodeKeyPair nodeKeyPair = new SolrNodeKeyPair(null); - final PublicKeyAPI.PublicKeyResponse response = new PublicKeyAPI(nodeKeyPair).getPublicKey(); + final var response = new GetPublicKey(nodeKeyPair).getPublicKey(); assertEquals(nodeKeyPair.getKeyPair().getPublicKeyStr(), response.key); } diff --git a/solr/core/src/test/org/apache/solr/util/BaseTestCircuitBreaker.java b/solr/core/src/test/org/apache/solr/util/BaseTestCircuitBreaker.java index 372ddf80810..025db34ed76 100644 --- a/solr/core/src/test/org/apache/solr/util/BaseTestCircuitBreaker.java +++ b/solr/core/src/test/org/apache/solr/util/BaseTestCircuitBreaker.java @@ -32,6 +32,7 @@ import org.apache.solr.common.util.SolrNamedThreadFactory; import org.apache.solr.util.circuitbreaker.CPUCircuitBreaker; import org.apache.solr.util.circuitbreaker.CircuitBreaker; +import org.apache.solr.util.circuitbreaker.CircuitBreakerManager; import org.apache.solr.util.circuitbreaker.MemoryCircuitBreaker; import org.hamcrest.MatcherAssert; import org.junit.After; @@ -79,21 +80,42 @@ public void testCBAlwaysTrips() { }); } - public void testCBFakeMemoryPressure() { + public void testCBFakeMemoryPressure() throws Exception { removeAllExistingCircuitBreakers(); - CircuitBreaker circuitBreaker = new FakeMemoryPressureCircuitBreaker(); - MemoryCircuitBreaker memoryCircuitBreaker = (MemoryCircuitBreaker) circuitBreaker; + // Update and query will not trip + h.update( + "1john smith"); + h.query(req("name:\"john smith\"")); - memoryCircuitBreaker.setThreshold(75); + MemoryCircuitBreaker searchBreaker = new FakeMemoryPressureCircuitBreaker(); + searchBreaker.setThreshold(80); + // Default request type is "query" + // searchBreaker.setRequestTypes(List.of("query")); + h.getCore().getCircuitBreakerRegistry().register(searchBreaker); - h.getCore().getCircuitBreakerRegistry().register(circuitBreaker); + // Query will trip, but not update due to defaults + expectThrows(SolrException.class, () -> h.query(req("name:\"john smith\""))); + h.update( + "2john smith"); + + MemoryCircuitBreaker updateBreaker = new FakeMemoryPressureCircuitBreaker(); + updateBreaker.setThreshold(75); + updateBreaker.setRequestTypes(List.of("update")); + h.getCore().getCircuitBreakerRegistry().register(updateBreaker); + // Now also update will trip expectThrows( SolrException.class, - () -> { - h.query(req("name:\"john smith\"")); - }); + () -> + h.update( + "1john smith")); + } + + public void testBadRequestType() { + expectThrows( + IllegalArgumentException.class, + () -> new MemoryCircuitBreaker().setRequestTypes(List.of("badRequestType"))); } public void testBuildingMemoryPressure() { @@ -238,6 +260,15 @@ public void testResponseWithCBTiming() { "//lst[@name='process']/double[@name='time']"); } + public void testErrorCode() { + assertEquals( + SolrException.ErrorCode.SERVICE_UNAVAILABLE, + CircuitBreaker.getErrorCode(List.of(new CircuitBreakerManager()))); + assertEquals( + SolrException.ErrorCode.TOO_MANY_REQUESTS, + CircuitBreaker.getErrorCode(List.of(new MemoryCircuitBreaker()))); + } + private void removeAllExistingCircuitBreakers() { h.getCore().getCircuitBreakerRegistry().deregisterAll(); } diff --git a/solr/licenses/http2-client-10.0.15.jar.sha1 b/solr/licenses/http2-client-10.0.15.jar.sha1 deleted file mode 100644 index 1fb6b95c441..00000000000 --- a/solr/licenses/http2-client-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -70ba44dc67e6c4ff3c9d0fddf0b530ff1718a5b7 diff --git a/solr/licenses/http2-client-10.0.16.jar.sha1 b/solr/licenses/http2-client-10.0.16.jar.sha1 new file mode 100644 index 00000000000..9c0d69e62e6 --- /dev/null +++ b/solr/licenses/http2-client-10.0.16.jar.sha1 @@ -0,0 +1 @@ +1d5ada7bfa44f016ec5089d71e83c7d2596bb993 diff --git a/solr/licenses/http2-common-10.0.15.jar.sha1 b/solr/licenses/http2-common-10.0.15.jar.sha1 deleted file mode 100644 index a1cdb73ed15..00000000000 --- a/solr/licenses/http2-common-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -997745dc17547fbf7d2ab945ef1ecc875a1d0872 diff --git a/solr/licenses/http2-common-10.0.16.jar.sha1 b/solr/licenses/http2-common-10.0.16.jar.sha1 new file mode 100644 index 00000000000..69ff610174b --- /dev/null +++ b/solr/licenses/http2-common-10.0.16.jar.sha1 @@ -0,0 +1 @@ +c510d982936eb1ee44f6d8f78816f59ca06c0c2f diff --git a/solr/licenses/http2-hpack-10.0.15.jar.sha1 b/solr/licenses/http2-hpack-10.0.15.jar.sha1 deleted file mode 100644 index 1d138302c34..00000000000 --- a/solr/licenses/http2-hpack-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -f83ed0b45e29af41e7b078e30e844f07bb9c10d5 diff --git a/solr/licenses/http2-hpack-10.0.16.jar.sha1 b/solr/licenses/http2-hpack-10.0.16.jar.sha1 new file mode 100644 index 00000000000..c7fcc824692 --- /dev/null +++ b/solr/licenses/http2-hpack-10.0.16.jar.sha1 @@ -0,0 +1 @@ +71d71f1ac93bb5e0b1539b2a9c257018b9969022 diff --git a/solr/licenses/http2-http-client-transport-10.0.15.jar.sha1 b/solr/licenses/http2-http-client-transport-10.0.15.jar.sha1 deleted file mode 100644 index bdc15087200..00000000000 --- a/solr/licenses/http2-http-client-transport-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -d06da4f9927d78db8d4e905d156af77ebdef7109 diff --git a/solr/licenses/http2-http-client-transport-10.0.16.jar.sha1 b/solr/licenses/http2-http-client-transport-10.0.16.jar.sha1 new file mode 100644 index 00000000000..5b440b9d6e6 --- /dev/null +++ b/solr/licenses/http2-http-client-transport-10.0.16.jar.sha1 @@ -0,0 +1 @@ +780b6092e64ffb46ff490290add3ed2a2df2f646 diff --git a/solr/licenses/http2-server-10.0.15.jar.sha1 b/solr/licenses/http2-server-10.0.15.jar.sha1 deleted file mode 100644 index 6bdc00a0465..00000000000 --- a/solr/licenses/http2-server-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -508fcf41cefc997bab33b9f7722dff231086f8cd diff --git a/solr/licenses/http2-server-10.0.16.jar.sha1 b/solr/licenses/http2-server-10.0.16.jar.sha1 new file mode 100644 index 00000000000..6b7996abcf2 --- /dev/null +++ b/solr/licenses/http2-server-10.0.16.jar.sha1 @@ -0,0 +1 @@ +2117c48664430a2a32bca2239b75ee57b8084e8b diff --git a/solr/licenses/jetty-alpn-client-10.0.15.jar.sha1 b/solr/licenses/jetty-alpn-client-10.0.15.jar.sha1 deleted file mode 100644 index 11ac116c904..00000000000 --- a/solr/licenses/jetty-alpn-client-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -24fd9dc56ce6bcd8fab03c202edc248b77f56bd3 diff --git a/solr/licenses/jetty-alpn-client-10.0.16.jar.sha1 b/solr/licenses/jetty-alpn-client-10.0.16.jar.sha1 new file mode 100644 index 00000000000..31a82a8316c --- /dev/null +++ b/solr/licenses/jetty-alpn-client-10.0.16.jar.sha1 @@ -0,0 +1 @@ +6df5cc027975573d8994e4d9a89d76d5a9c5121a diff --git a/solr/licenses/jetty-alpn-java-client-10.0.15.jar.sha1 b/solr/licenses/jetty-alpn-java-client-10.0.15.jar.sha1 deleted file mode 100644 index ce016268d5e..00000000000 --- a/solr/licenses/jetty-alpn-java-client-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -4d67e504e06c4a1fb2fb3a1d5bf06dda2b254121 diff --git a/solr/licenses/jetty-alpn-java-client-10.0.16.jar.sha1 b/solr/licenses/jetty-alpn-java-client-10.0.16.jar.sha1 new file mode 100644 index 00000000000..ea52966c985 --- /dev/null +++ b/solr/licenses/jetty-alpn-java-client-10.0.16.jar.sha1 @@ -0,0 +1 @@ +df847a02e1092e4255858f216b1f0df43a98be04 diff --git a/solr/licenses/jetty-alpn-java-server-10.0.15.jar.sha1 b/solr/licenses/jetty-alpn-java-server-10.0.15.jar.sha1 deleted file mode 100644 index 1b9112b6447..00000000000 --- a/solr/licenses/jetty-alpn-java-server-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -13994a7ce7c3fa6f23fcf51204b1afc3c6f89c68 diff --git a/solr/licenses/jetty-alpn-java-server-10.0.16.jar.sha1 b/solr/licenses/jetty-alpn-java-server-10.0.16.jar.sha1 new file mode 100644 index 00000000000..3fb471965be --- /dev/null +++ b/solr/licenses/jetty-alpn-java-server-10.0.16.jar.sha1 @@ -0,0 +1 @@ +5cbcaffb0b45e923862d8bbdac53556642c8edca diff --git a/solr/licenses/jetty-alpn-server-10.0.15.jar.sha1 b/solr/licenses/jetty-alpn-server-10.0.15.jar.sha1 deleted file mode 100644 index 963dfd8eb97..00000000000 --- a/solr/licenses/jetty-alpn-server-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -4f6d594d09d5e302013bf74820d48b11f47dde75 diff --git a/solr/licenses/jetty-alpn-server-10.0.16.jar.sha1 b/solr/licenses/jetty-alpn-server-10.0.16.jar.sha1 new file mode 100644 index 00000000000..19aeb175a23 --- /dev/null +++ b/solr/licenses/jetty-alpn-server-10.0.16.jar.sha1 @@ -0,0 +1 @@ +6af901179b5270fafa8c82e89bd23f37b57f66e9 diff --git a/solr/licenses/jetty-client-10.0.15.jar.sha1 b/solr/licenses/jetty-client-10.0.15.jar.sha1 deleted file mode 100644 index b81cd44cbe8..00000000000 --- a/solr/licenses/jetty-client-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -5b1834dc03744e1201adafc04c5f6f564d38f1d5 diff --git a/solr/licenses/jetty-client-10.0.16.jar.sha1 b/solr/licenses/jetty-client-10.0.16.jar.sha1 new file mode 100644 index 00000000000..acf38316f62 --- /dev/null +++ b/solr/licenses/jetty-client-10.0.16.jar.sha1 @@ -0,0 +1 @@ +62b5879f0530efa5296d0b296e588b79f3e4f0e5 diff --git a/solr/licenses/jetty-deploy-10.0.15.jar.sha1 b/solr/licenses/jetty-deploy-10.0.15.jar.sha1 deleted file mode 100644 index b609e60a63b..00000000000 --- a/solr/licenses/jetty-deploy-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -4c3c9641cc7216249a6abf4b124a44fe8d60be8e diff --git a/solr/licenses/jetty-deploy-10.0.16.jar.sha1 b/solr/licenses/jetty-deploy-10.0.16.jar.sha1 new file mode 100644 index 00000000000..ce800f8a663 --- /dev/null +++ b/solr/licenses/jetty-deploy-10.0.16.jar.sha1 @@ -0,0 +1 @@ +2f1690ae512b2149550114b15cbdc0bf22069873 diff --git a/solr/licenses/jetty-http-10.0.15.jar.sha1 b/solr/licenses/jetty-http-10.0.15.jar.sha1 deleted file mode 100644 index 55ebe6f33dd..00000000000 --- a/solr/licenses/jetty-http-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -53c4702201c33501bc37a982e5325b5f11084a4e diff --git a/solr/licenses/jetty-http-10.0.16.jar.sha1 b/solr/licenses/jetty-http-10.0.16.jar.sha1 new file mode 100644 index 00000000000..f292b913874 --- /dev/null +++ b/solr/licenses/jetty-http-10.0.16.jar.sha1 @@ -0,0 +1 @@ +0bf1c1db5bb6e97c1040ee5c1053ec46b9895c5a diff --git a/solr/licenses/jetty-io-10.0.15.jar.sha1 b/solr/licenses/jetty-io-10.0.15.jar.sha1 deleted file mode 100644 index 78badcd9857..00000000000 --- a/solr/licenses/jetty-io-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -4481d9593bb89c4da016e49463b0d477faca06dc diff --git a/solr/licenses/jetty-io-10.0.16.jar.sha1 b/solr/licenses/jetty-io-10.0.16.jar.sha1 new file mode 100644 index 00000000000..8db002cd026 --- /dev/null +++ b/solr/licenses/jetty-io-10.0.16.jar.sha1 @@ -0,0 +1 @@ +a96c25a805a64a39a7c6e81dbd779bd228ca13aa diff --git a/solr/licenses/jetty-jmx-10.0.15.jar.sha1 b/solr/licenses/jetty-jmx-10.0.15.jar.sha1 deleted file mode 100644 index bfeb8684899..00000000000 --- a/solr/licenses/jetty-jmx-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -e42b10a3442639747dd2d925d6b8becd51e3cf52 diff --git a/solr/licenses/jetty-jmx-10.0.16.jar.sha1 b/solr/licenses/jetty-jmx-10.0.16.jar.sha1 new file mode 100644 index 00000000000..031e28e1069 --- /dev/null +++ b/solr/licenses/jetty-jmx-10.0.16.jar.sha1 @@ -0,0 +1 @@ +aa728ec15d722b6114436521db044750d815b92b diff --git a/solr/licenses/jetty-rewrite-10.0.15.jar.sha1 b/solr/licenses/jetty-rewrite-10.0.15.jar.sha1 deleted file mode 100644 index ec99309f2f7..00000000000 --- a/solr/licenses/jetty-rewrite-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -1a06287e5475ad32397213d5b261d9ae357feea7 diff --git a/solr/licenses/jetty-rewrite-10.0.16.jar.sha1 b/solr/licenses/jetty-rewrite-10.0.16.jar.sha1 new file mode 100644 index 00000000000..9bb5bc57d25 --- /dev/null +++ b/solr/licenses/jetty-rewrite-10.0.16.jar.sha1 @@ -0,0 +1 @@ +6d482b3d7928d9fcdd00a3f5fd702e7a96d4727f diff --git a/solr/licenses/jetty-security-10.0.15.jar.sha1 b/solr/licenses/jetty-security-10.0.15.jar.sha1 deleted file mode 100644 index 44ed78bcdbe..00000000000 --- a/solr/licenses/jetty-security-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -ae9c2fd327090fc749a6656109adf88f84f05854 diff --git a/solr/licenses/jetty-security-10.0.16.jar.sha1 b/solr/licenses/jetty-security-10.0.16.jar.sha1 new file mode 100644 index 00000000000..fbdc2b91405 --- /dev/null +++ b/solr/licenses/jetty-security-10.0.16.jar.sha1 @@ -0,0 +1 @@ +7735aba773abefb79f0f68e058bf7b303df9364e diff --git a/solr/licenses/jetty-server-10.0.15.jar.sha1 b/solr/licenses/jetty-server-10.0.15.jar.sha1 deleted file mode 100644 index d3cf9fc738c..00000000000 --- a/solr/licenses/jetty-server-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -d1e941f30300d64b122d5346f1599ecaa8e270ba diff --git a/solr/licenses/jetty-server-10.0.16.jar.sha1 b/solr/licenses/jetty-server-10.0.16.jar.sha1 new file mode 100644 index 00000000000..0220349e506 --- /dev/null +++ b/solr/licenses/jetty-server-10.0.16.jar.sha1 @@ -0,0 +1 @@ +fefaa98e95b9737562d196d24f7846734ce99e17 diff --git a/solr/licenses/jetty-servlet-10.0.15.jar.sha1 b/solr/licenses/jetty-servlet-10.0.15.jar.sha1 deleted file mode 100644 index 44ed0b1ece6..00000000000 --- a/solr/licenses/jetty-servlet-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -17e21100d9eabae2c0f560ab2c1d5f0edfc4a57b diff --git a/solr/licenses/jetty-servlet-10.0.16.jar.sha1 b/solr/licenses/jetty-servlet-10.0.16.jar.sha1 new file mode 100644 index 00000000000..4fe3c7337b4 --- /dev/null +++ b/solr/licenses/jetty-servlet-10.0.16.jar.sha1 @@ -0,0 +1 @@ +3b995aca89a81109672587f81d411efbd0530d2a diff --git a/solr/licenses/jetty-servlets-10.0.15.jar.sha1 b/solr/licenses/jetty-servlets-10.0.15.jar.sha1 deleted file mode 100644 index 8b083d602eb..00000000000 --- a/solr/licenses/jetty-servlets-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -73b1391880e636d2e804154704dbf3bfe429e622 diff --git a/solr/licenses/jetty-servlets-10.0.16.jar.sha1 b/solr/licenses/jetty-servlets-10.0.16.jar.sha1 new file mode 100644 index 00000000000..4527090c936 --- /dev/null +++ b/solr/licenses/jetty-servlets-10.0.16.jar.sha1 @@ -0,0 +1 @@ +dcb14edd4b5453f38f7dc084bb43003090c6f8fa diff --git a/solr/licenses/jetty-start-10.0.15-shaded.jar.sha1 b/solr/licenses/jetty-start-10.0.15-shaded.jar.sha1 deleted file mode 100644 index ff9a3675dbc..00000000000 --- a/solr/licenses/jetty-start-10.0.15-shaded.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -5e0ca1e20769d4189e68b8c42457de75cca24c08 diff --git a/solr/licenses/jetty-start-10.0.16-shaded.jar.sha1 b/solr/licenses/jetty-start-10.0.16-shaded.jar.sha1 new file mode 100644 index 00000000000..2a43ac78457 --- /dev/null +++ b/solr/licenses/jetty-start-10.0.16-shaded.jar.sha1 @@ -0,0 +1 @@ +d9960222bae7b11846d919557dbef0296d157a3e diff --git a/solr/licenses/jetty-util-10.0.15.jar.sha1 b/solr/licenses/jetty-util-10.0.15.jar.sha1 deleted file mode 100644 index 5418cf4190e..00000000000 --- a/solr/licenses/jetty-util-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -eb8901d419e83f2f06809e0cdceaf38b06426f01 diff --git a/solr/licenses/jetty-util-10.0.16.jar.sha1 b/solr/licenses/jetty-util-10.0.16.jar.sha1 new file mode 100644 index 00000000000..a2c6113afe7 --- /dev/null +++ b/solr/licenses/jetty-util-10.0.16.jar.sha1 @@ -0,0 +1 @@ +1513b0c4d8ce627835a5511950d4c40be6450258 diff --git a/solr/licenses/jetty-webapp-10.0.15.jar.sha1 b/solr/licenses/jetty-webapp-10.0.15.jar.sha1 deleted file mode 100644 index c04a11ad334..00000000000 --- a/solr/licenses/jetty-webapp-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -ecda5b8297bc963cf411542a1143ad224532508a diff --git a/solr/licenses/jetty-webapp-10.0.16.jar.sha1 b/solr/licenses/jetty-webapp-10.0.16.jar.sha1 new file mode 100644 index 00000000000..77c5f35abf2 --- /dev/null +++ b/solr/licenses/jetty-webapp-10.0.16.jar.sha1 @@ -0,0 +1 @@ +5e84843afea5f39fda05c301abd0b7cfe929ec8c diff --git a/solr/licenses/jetty-xml-10.0.15.jar.sha1 b/solr/licenses/jetty-xml-10.0.15.jar.sha1 deleted file mode 100644 index 2eb14f63413..00000000000 --- a/solr/licenses/jetty-xml-10.0.15.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -d30d139b35bf183757b7ef5372dec5096bc39a60 diff --git a/solr/licenses/jetty-xml-10.0.16.jar.sha1 b/solr/licenses/jetty-xml-10.0.16.jar.sha1 new file mode 100644 index 00000000000..2369cf061df --- /dev/null +++ b/solr/licenses/jetty-xml-10.0.16.jar.sha1 @@ -0,0 +1 @@ +66dc24cea5422d14e9482dc4273d7ccea4b1def7 diff --git a/solr/licenses/semver4j-4.3.0.jar.sha1 b/solr/licenses/semver4j-4.3.0.jar.sha1 deleted file mode 100644 index abf80df034a..00000000000 --- a/solr/licenses/semver4j-4.3.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -71760ca3e4136264c17107659d9df540594340a6 diff --git a/solr/licenses/semver4j-5.1.0.jar.sha1 b/solr/licenses/semver4j-5.1.0.jar.sha1 new file mode 100644 index 00000000000..69c3649226d --- /dev/null +++ b/solr/licenses/semver4j-5.1.0.jar.sha1 @@ -0,0 +1 @@ +e4afaf5d7297c8fbb67517ba6f1150b50e034b84 diff --git a/solr/modules/opentelemetry/src/test/org/apache/solr/opentelemetry/BasicAuthIntegrationTracingTest.java b/solr/modules/opentelemetry/src/test/org/apache/solr/opentelemetry/BasicAuthIntegrationTracingTest.java new file mode 100644 index 00000000000..cdbf9f27141 --- /dev/null +++ b/solr/modules/opentelemetry/src/test/org/apache/solr/opentelemetry/BasicAuthIntegrationTracingTest.java @@ -0,0 +1,121 @@ +/* + * 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.opentelemetry; + +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; +import static org.apache.solr.opentelemetry.TestDistributedTracing.getAndClearSpans; +import static org.apache.solr.security.Sha256AuthenticationProvider.getSaltedHashedValue; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.trace.TracerProvider; +import java.util.List; +import java.util.Map; +import org.apache.solr.client.solrj.SolrRequest; +import org.apache.solr.client.solrj.impl.CloudSolrClient; +import org.apache.solr.client.solrj.request.CollectionAdminRequest; +import org.apache.solr.client.solrj.request.V2Request; +import org.apache.solr.cloud.SolrCloudTestCase; +import org.apache.solr.common.util.Utils; +import org.apache.solr.security.BasicAuthPlugin; +import org.apache.solr.security.RuleBasedAuthorizationPlugin; +import org.apache.solr.util.tracing.TraceUtils; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class BasicAuthIntegrationTracingTest extends SolrCloudTestCase { + + private static final String COLLECTION = "collection1"; + private static final String USER = "solr"; + private static final String PASS = "SolrRocksAgain"; + private static final String SECURITY_JSON = + Utils.toJSONString( + Map.of( + "authorization", + Map.of( + "class", + RuleBasedAuthorizationPlugin.class.getName(), + "user-role", + singletonMap(USER, "admin"), + "permissions", + singletonList(Map.of("name", "all", "role", "admin"))), + "authentication", + Map.of( + "class", + BasicAuthPlugin.class.getName(), + "blockUnknown", + true, + "credentials", + singletonMap(USER, getSaltedHashedValue(PASS))))); + + @BeforeClass + public static void setupCluster() throws Exception { + // force early init + CustomTestOtelTracerConfigurator.prepareForTest(); + + configureCluster(4) + .addConfig("config", TEST_PATH().resolve("collection1").resolve("conf")) + .withSolrXml(TEST_PATH().resolve("solr.xml")) + .withTraceIdGenerationDisabled() + .withSecurityJson(SECURITY_JSON) + .configure(); + + assertNotEquals( + "Expecting active otel, not noop impl", + TracerProvider.noop(), + GlobalOpenTelemetry.get().getTracerProvider()); + + CollectionAdminRequest.createCollection(COLLECTION, "config", 2, 2) + .setBasicAuthCredentials(USER, PASS) + .process(cluster.getSolrClient()); + cluster.waitForActiveCollection(COLLECTION, 2, 4); + } + + @AfterClass + public static void afterClass() { + CustomTestOtelTracerConfigurator.resetForTest(); + } + + /** See SOLR-16955 */ + @Test + public void testSetupBasicAuth() throws Exception { + getAndClearSpans(); // reset + + CloudSolrClient cloudClient = cluster.getSolrClient(); + Map ops = + Map.of( + "set-user", Map.of("harry", "HarryIsCool"), + "set-property", Map.of("blockUnknown", true)); + V2Request req = + new V2Request.Builder("/cluster/security/authentication") + .withMethod(SolrRequest.METHOD.POST) + .withPayload(Utils.toJSONString(ops)) + .build(); + req.setBasicAuthCredentials(USER, PASS); + assertEquals(0, req.process(cloudClient, COLLECTION).getStatus()); + + var finishedSpans = getAndClearSpans(); + assertEquals(1, finishedSpans.size()); + var span = finishedSpans.get(0); + assertEquals("post:/cluster/security/authentication", span.getName()); + assertEquals("solr", span.getAttributes().get(TraceUtils.TAG_USER)); + assertEquals( + BasicAuthPlugin.class.getSimpleName(), span.getAttributes().get(TraceUtils.TAG_CLASS)); + assertEquals(List.copyOf(ops.keySet()), span.getAttributes().get(TraceUtils.TAG_OPS)); + } +} diff --git a/solr/modules/opentelemetry/src/test/org/apache/solr/opentelemetry/TestDistributedTracing.java b/solr/modules/opentelemetry/src/test/org/apache/solr/opentelemetry/TestDistributedTracing.java index f6e088e5168..23cf76f1cbf 100644 --- a/solr/modules/opentelemetry/src/test/org/apache/solr/opentelemetry/TestDistributedTracing.java +++ b/solr/modules/opentelemetry/src/test/org/apache/solr/opentelemetry/TestDistributedTracing.java @@ -201,7 +201,7 @@ private void assertOneSpanIsChildOfAnother(List finishedSpans) { assertEquals(child.getTraceId(), parent.getTraceId()); } - private List getAndClearSpans() { + static List getAndClearSpans() { InMemorySpanExporter exporter = CustomTestOtelTracerConfigurator.getInMemorySpanExporter(); List result = new ArrayList<>(exporter.getFinishedSpanItems()); Collections.reverse(result); // nicer to see spans chronologically diff --git a/solr/packaging/build.gradle b/solr/packaging/build.gradle index 310aa45049c..aa366eaafd6 100644 --- a/solr/packaging/build.gradle +++ b/solr/packaging/build.gradle @@ -256,6 +256,7 @@ task integrationTests(type: BatsTask) { environment SOLR_TIP: distDir.toString() environment SOLR_HOME: solrHome environment SOLR_LOGS_DIR: "$solrHome/logs" + environment TEST_OUTPUT_DIR: integrationTestOutput environment TEST_FAILURE_DIR: solrTestFailuresDir environment BATS_LIB_PREFIX: "$nodeProjectDir/node_modules" } diff --git a/solr/packaging/test/test_ssl.bats b/solr/packaging/test/test_ssl.bats index f2eea934304..9fdcbd43a59 100644 --- a/solr/packaging/test/test_ssl.bats +++ b/solr/packaging/test/test_ssl.bats @@ -57,8 +57,51 @@ teardown() { run solr create -c test -s 2 assert_output --partial "Created collection 'test'" - run curl --http2 --cacert "$ssl_dir/solr-ssl.pem" 'https://localhost:8983/solr/test/select?q=*:*' + run curl --http2 --cacert "$ssl_dir/solr-ssl.pem" 'https://127.0.0.1:8983/solr/test/select?q=*:*' + assert_output --partial '"numFound":0' +} + +@test "use different hostname when not checking peer-name" { + # Create a keystore + export ssl_dir="${BATS_TEST_TMPDIR}/ssl" + mkdir -p "$ssl_dir" + ( + cd "$ssl_dir" + rm -f solr-ssl.keystore.p12 solr-ssl.pem + # Using a CN that is not localhost, as we will not be checking peer-name + keytool -genkeypair -alias solr-ssl -keyalg RSA -keysize 2048 -keypass secret -storepass secret -validity 9999 -keystore solr-ssl.keystore.p12 -storetype PKCS12 -ext "SAN=DNS:test.solr.apache.org,IP:127.0.0.1" -dname "CN=test.solr.apache.org, OU=Organizational Unit, O=Organization, L=Location, ST=State, C=Country" + openssl pkcs12 -in solr-ssl.keystore.p12 -out solr-ssl.pem -passin pass:secret -passout pass:secret + ) + + # Set ENV_VARs so that Solr uses this keystore + export SOLR_SSL_ENABLED=true + export SOLR_SSL_KEY_STORE=$ssl_dir/solr-ssl.keystore.p12 + export SOLR_SSL_KEY_STORE_PASSWORD=secret + export SOLR_SSL_TRUST_STORE=$ssl_dir/solr-ssl.keystore.p12 + export SOLR_SSL_TRUST_STORE_PASSWORD=secret + export SOLR_SSL_NEED_CLIENT_AUTH=false + export SOLR_SSL_WANT_CLIENT_AUTH=false + export SOLR_SSL_CHECK_PEER_NAME=false + # Remove later when SOLR-16963 is resolved + export SOLR_SSL_CLIENT_HOSTNAME_VERIFICATION=false + export SOLR_HOST=localhost + + solr start -c + solr assert --started https://localhost:8983/solr --timeout 5000 + + run solr create -c test -s 2 + assert_output --partial "Created collection 'test'" + + run curl --http2 --cacert "$ssl_dir/solr-ssl.pem" -k 'https://localhost:8983/solr/test/select?q=*:*' assert_output --partial '"numFound":0' + + export SOLR_SSL_CHECK_PEER_NAME=true + # Remove later when SOLR-16963 is resolved + export SOLR_SSL_CLIENT_HOSTNAME_VERIFICATION=true + + # This should fail the peername check + run ! solr api -get 'https://localhost:8983/solr/test/select?q=*:*' + assert_output --partial 'Server refused connection' } @test "start solr with ssl and auth" { @@ -155,3 +198,247 @@ teardown() { run solr api -get 'https://localhost:8983/solr/admin/collections?action=CLUSTERSTATUS' assert_output --partial '"urlScheme":"https"' } + +@test "start solr with mTLS needed" { + # Make a test tmp dir, as the security policy includes TMP, so that might already contain the BATS_TEST_TMPDIR + test_tmp_dir="${BATS_TEST_TMPDIR}/tmp" + mkdir -p "${test_tmp_dir}" + test_tmp_dir="$(cd -P "${test_tmp_dir}" && pwd)" + + export SOLR_SECURITY_MANAGER_ENABLED=true + export SOLR_OPTS="-Djava.io.tmpdir=${test_tmp_dir}" + export SOLR_TOOL_OPTS="-Djava.io.tmpdir=${test_tmp_dir} -Djavax.net.debug=SSL,keymanager,trustmanager,ssl:handshake" + + export ssl_dir="${BATS_TEST_TMPDIR}/ssl" + export server_ssl_dir="${ssl_dir}/server" + export client_ssl_dir="${ssl_dir}/client" + + # Create a root & intermediary CA + echo "${ssl_dir}" + mkdir -p "${ssl_dir}" + ( + cd "$ssl_dir" + rm -f root.p12 root.pem ca.p12 ca.pem + + keytool -genkeypair -keystore root.p12 -storetype PKCS12 -keypass secret -storepass secret -alias root -ext bc:c -ext SAN=DNS:localhost,IP:127.0.0.1 -dname "CN=localhost, OU=Organizational Unit, O=Organization, L=Location, ST=State, C=Country" -keyalg rsa + keytool -genkeypair -keystore ca.p12 -storetype PKCS12 -keypass secret -storepass secret -alias ca -ext bc:c -ext SAN=DNS:localhost,IP:127.0.0.1 -dname "CN=localhost, OU=Organizational Unit, O=Organization, L=Location, ST=State, C=Country" -keyalg rsa + + keytool -keystore root.p12 -storetype PKCS12 -storepass secret -alias root -exportcert -rfc > root.pem + + keytool -storepass secret -storetype PKCS12 -keystore ca.p12 -certreq -alias ca | \ + keytool -storepass secret -keystore root.p12 -storetype PKCS12 \ + -gencert -alias root -ext BC=0 -rfc > ca.pem + keytool -keystore ca.p12 -importcert -storetype PKCS12 -storepass secret -alias root -file root.pem -noprompt + keytool -keystore ca.p12 -importcert -storetype PKCS12 -storepass secret -alias ca -file ca.pem + ) + # Create a server keystore & truststore + mkdir -p "$server_ssl_dir" + ( + cd "$server_ssl_dir" + rm -f solr-server.keystore.p12 server.pem solr-server.truststore.p12 + + # Create a keystore and certificate + keytool -genkeypair -keystore solr-server.keystore.p12 -storetype PKCS12 -keypass server-key -storepass server-key -alias server -ext SAN=DNS:localhost,IP:127.0.0.1 -dname "CN=localhost, OU=Organizational Unit, O=Organization, L=Location, ST=State, C=Country" -keyalg rsa + + # Trust the keystore cert with the CA + keytool -storepass server-key -keystore solr-server.keystore.p12 -storetype PKCS12 -certreq -alias server | \ + keytool -storepass secret -keystore "$ssl_dir/ca.p12" -storetype PKCS12 -gencert -alias ca \ + -ext "ku:c=nonRepudiation,digitalSignature,keyEncipherment" -ext eku:c=serverAuth -rfc > server.pem + keytool -keystore solr-server.keystore.p12 -storetype PKCS12 -keypass server-key -storepass server-key -importcert -alias root -file "$ssl_dir/root.pem" -noprompt + keytool -keystore solr-server.keystore.p12 -storetype PKCS12 -keypass server-key -storepass server-key -importcert -alias ca -file "$ssl_dir/ca.pem" -noprompt + keytool -keystore solr-server.keystore.p12 -storetype PKCS12 -keypass server-key -storepass server-key -importcert -alias server -file server.pem + + # Create a truststore with just the Root CA + keytool -keystore solr-server.truststore.p12 -storetype PKCS12 -keypass server-trust -storepass server-trust -importcert -alias root -file "$ssl_dir/root.pem" -noprompt + keytool -keystore solr-server.truststore.p12 -storetype PKCS12 -keypass server-trust -storepass server-trust -importcert -alias ca -file "$ssl_dir/ca.pem" -noprompt + ) + # Create a client keystore & truststore + mkdir -p "$client_ssl_dir" + ( + cd "$client_ssl_dir" + rm -f solr-client.keystore.p12 client.pem solr-client.truststore.p12 + + # Create a keystore and certificate + keytool -genkeypair -keystore solr-client.keystore.p12 -storetype PKCS12 -keypass client-key -storepass client-key -alias client -ext SAN=DNS:localhost,IP:127.0.0.1 -dname "CN=localhost, OU=Organizational Unit, O=Organization, L=Location, ST=State, C=Country" -keyalg rsa + + # Trust the keystore cert with the CA + keytool -storepass client-key -keystore solr-client.keystore.p12 -storetype PKCS12 -certreq -alias client | \ + keytool -storepass secret -keystore "$ssl_dir/ca.p12" -storetype PKCS12 -gencert -alias ca \ + -ext "ku:c=nonRepudiation,digitalSignature,keyEncipherment" -ext eku:c=clientAuth -rfc > client.pem + keytool -keystore solr-client.keystore.p12 -storetype PKCS12 -keypass client-key -storepass client-key -importcert -alias root -file "$ssl_dir/root.pem" -noprompt + keytool -keystore solr-client.keystore.p12 -storetype PKCS12 -keypass client-key -storepass client-key -importcert -alias ca -file "$ssl_dir/ca.pem" -noprompt + keytool -keystore solr-client.keystore.p12 -storetype PKCS12 -keypass client-key -storepass client-key -importcert -alias client -file client.pem + + # Create a truststore with just the Root CA + keytool -keystore solr-client.truststore.p12 -storetype PKCS12 -keypass client-trust -storepass client-trust -importcert -alias root -file "$ssl_dir/root.pem" -noprompt + keytool -keystore solr-client.truststore.p12 -storetype PKCS12 -keypass client-trust -storepass client-trust -importcert -alias ca -file "$ssl_dir/ca.pem" -noprompt + ) + + # Set ENV_VARs so that Solr uses this keystore + export SOLR_SSL_ENABLED=true + export SOLR_SSL_KEY_STORE="$server_ssl_dir/solr-server.keystore.p12" + export SOLR_SSL_KEY_STORE_PASSWORD=server-key + export SOLR_SSL_KEY_STORE_TYPE=PKCS12 + export SOLR_SSL_TRUST_STORE="$server_ssl_dir/solr-server.truststore.p12" + export SOLR_SSL_TRUST_STORE_PASSWORD=server-trust + export SOLR_SSL_TRUST_STORE_TYPE=PKCS12 + export SOLR_SSL_CLIENT_KEY_STORE="$client_ssl_dir/solr-client.keystore.p12" + export SOLR_SSL_CLIENT_KEY_STORE_PASSWORD=client-key + export SOLR_SSL_CLIENT_KEY_STORE_TYPE=PKCS12 + export SOLR_SSL_CLIENT_TRUST_STORE="$client_ssl_dir/solr-client.truststore.p12" + export SOLR_SSL_CLIENT_TRUST_STORE_PASSWORD=client-trust + export SOLR_SSL_CLIENT_TRUST_STORE_TYPE=PKCS12 + export SOLR_SSL_NEED_CLIENT_AUTH=true + export SOLR_SSL_WANT_CLIENT_AUTH=false + export SOLR_SSL_CHECK_PEER_NAME=true + export SOLR_SSL_CLIENT_HOSTNAME_VERIFICATION=true + export SOLR_HOST=localhost + + solr start -c + solr start -c -z localhost:9983 -p 8984 + + export SOLR_SSL_KEY_STORE= + export SOLR_SSL_KEY_STORE_PASSWORD= + export SOLR_SSL_TRUST_STORE= + export SOLR_SSL_TRUST_STORE_PASSWORD= + + solr assert --started https://localhost:8983/solr --timeout 5000 + solr assert --started https://localhost:8984/solr --timeout 5000 + + run solr create -c test -s 2 + assert_output --partial "Created collection 'test'" + + run solr api -get 'https://localhost:8983/solr/admin/collections?action=CLUSTERSTATUS' + assert_output --partial '"urlScheme":"https"' + + run solr api -get 'https://localhost:8984/solr/test/select?q=*:*&rows=0' + assert_output --partial '"numFound":0' + + export SOLR_SSL_CLIENT_KEY_STORE= + export SOLR_SSL_CLIENT_KEY_STORE_PASSWORD= + + run ! solr api -get 'https://localhost:8983/solr/test/select?q=*:*&rows=0' + assert_output --partial 'Server refused connection' +} + +@test "start solr with mTLS wanted" { + # Make a test tmp dir, as the security policy includes TMP, so that might already contain the BATS_TEST_TMPDIR + test_tmp_dir="${BATS_TEST_TMPDIR}/tmp" + mkdir -p "${test_tmp_dir}" + test_tmp_dir="$(cd -P "${test_tmp_dir}" && pwd)" + + export SOLR_SECURITY_MANAGER_ENABLED=true + export SOLR_OPTS="-Djava.io.tmpdir=${test_tmp_dir}" + export SOLR_TOOL_OPTS="-Djava.io.tmpdir=${test_tmp_dir} -Djavax.net.debug=SSL,keymanager,trustmanager,ssl:handshake" + + export ssl_dir="${BATS_TEST_TMPDIR}/ssl" + export server_ssl_dir="${ssl_dir}/server" + export client_ssl_dir="${ssl_dir}/client" + + # Create a root & intermediary CA + echo "${ssl_dir}" + mkdir -p "${ssl_dir}" + ( + cd "$ssl_dir" + rm -f root.p12 root.pem ca.p12 ca.pem + + keytool -genkeypair -keystore root.p12 -storetype PKCS12 -keypass secret -storepass secret -alias root -ext bc:c -ext SAN=DNS:localhost,IP:127.0.0.1 -dname "CN=localhost, OU=Organizational Unit, O=Organization, L=Location, ST=State, C=Country" -keyalg rsa + keytool -genkeypair -keystore ca.p12 -storetype PKCS12 -keypass secret -storepass secret -alias ca -ext bc:c -ext SAN=DNS:localhost,IP:127.0.0.1 -dname "CN=localhost, OU=Organizational Unit, O=Organization, L=Location, ST=State, C=Country" -keyalg rsa + + keytool -keystore root.p12 -storetype PKCS12 -storepass secret -alias root -exportcert -rfc > root.pem + + keytool -storepass secret -storetype PKCS12 -keystore ca.p12 -certreq -alias ca | \ + keytool -storepass secret -keystore root.p12 -storetype PKCS12 \ + -gencert -alias root -ext BC=0 -rfc > ca.pem + keytool -keystore ca.p12 -importcert -storetype PKCS12 -storepass secret -alias root -file root.pem -noprompt + keytool -keystore ca.p12 -importcert -storetype PKCS12 -storepass secret -alias ca -file ca.pem + ) + # Create a server keystore & truststore + mkdir -p "$server_ssl_dir" + ( + cd "$server_ssl_dir" + rm -f solr-server.keystore.p12 server.pem solr-server.truststore.p12 + + # Create a keystore and certificate + keytool -genkeypair -keystore solr-server.keystore.p12 -storetype PKCS12 -keypass server-key -storepass server-key -alias server -ext SAN=DNS:localhost,IP:127.0.0.1 -dname "CN=localhost, OU=Organizational Unit, O=Organization, L=Location, ST=State, C=Country" -keyalg rsa + + # Trust the keystore cert with the CA + keytool -storepass server-key -keystore solr-server.keystore.p12 -storetype PKCS12 -certreq -alias server | \ + keytool -storepass secret -keystore "$ssl_dir/ca.p12" -storetype PKCS12 -gencert -alias ca \ + -ext "ku:c=nonRepudiation,digitalSignature,keyEncipherment" -ext eku:c=serverAuth -rfc > server.pem + keytool -keystore solr-server.keystore.p12 -storetype PKCS12 -keypass server-key -storepass server-key -importcert -alias root -file "$ssl_dir/root.pem" -noprompt + keytool -keystore solr-server.keystore.p12 -storetype PKCS12 -keypass server-key -storepass server-key -importcert -alias ca -file "$ssl_dir/ca.pem" -noprompt + keytool -keystore solr-server.keystore.p12 -storetype PKCS12 -keypass server-key -storepass server-key -importcert -alias server -file server.pem + + # Create a truststore with just the Root CA + keytool -keystore solr-server.truststore.p12 -storetype PKCS12 -keypass server-trust -storepass server-trust -importcert -alias root -file "$ssl_dir/root.pem" -noprompt + keytool -keystore solr-server.truststore.p12 -storetype PKCS12 -keypass server-trust -storepass server-trust -importcert -alias ca -file "$ssl_dir/ca.pem" -noprompt + ) + # Create a client keystore & truststore + mkdir -p "$client_ssl_dir" + ( + cd "$client_ssl_dir" + rm -f solr-client.keystore.p12 client.pem solr-client.truststore.p12 + + # Create a keystore and certificate + keytool -genkeypair -keystore solr-client.keystore.p12 -storetype PKCS12 -keypass client-key -storepass client-key -alias client -ext SAN=DNS:localhost,IP:127.0.0.1 -dname "CN=localhost, OU=Organizational Unit, O=Organization, L=Location, ST=State, C=Country" -keyalg rsa + + # Trust the keystore cert with the CA + keytool -storepass client-key -keystore solr-client.keystore.p12 -storetype PKCS12 -certreq -alias client | \ + keytool -storepass secret -keystore "$ssl_dir/ca.p12" -storetype PKCS12 -gencert -alias ca \ + -ext "ku:c=nonRepudiation,digitalSignature,keyEncipherment" -ext eku:c=clientAuth -rfc > client.pem + keytool -keystore solr-client.keystore.p12 -storetype PKCS12 -keypass client-key -storepass client-key -importcert -alias root -file "$ssl_dir/root.pem" -noprompt + keytool -keystore solr-client.keystore.p12 -storetype PKCS12 -keypass client-key -storepass client-key -importcert -alias ca -file "$ssl_dir/ca.pem" -noprompt + keytool -keystore solr-client.keystore.p12 -storetype PKCS12 -keypass client-key -storepass client-key -importcert -alias client -file client.pem + + # Create a truststore with just the Root CA + keytool -keystore solr-client.truststore.p12 -storetype PKCS12 -keypass client-trust -storepass client-trust -importcert -alias root -file "$ssl_dir/root.pem" -noprompt + keytool -keystore solr-client.truststore.p12 -storetype PKCS12 -keypass client-trust -storepass client-trust -importcert -alias ca -file "$ssl_dir/ca.pem" -noprompt + ) + + # Set ENV_VARs so that Solr uses this keystore + export SOLR_SSL_ENABLED=true + export SOLR_SSL_KEY_STORE="$server_ssl_dir/solr-server.keystore.p12" + export SOLR_SSL_KEY_STORE_PASSWORD=server-key + export SOLR_SSL_KEY_STORE_TYPE=PKCS12 + export SOLR_SSL_TRUST_STORE="$server_ssl_dir/solr-server.truststore.p12" + export SOLR_SSL_TRUST_STORE_PASSWORD=server-trust + export SOLR_SSL_TRUST_STORE_TYPE=PKCS12 + export SOLR_SSL_CLIENT_KEY_STORE="$client_ssl_dir/solr-client.keystore.p12" + export SOLR_SSL_CLIENT_KEY_STORE_PASSWORD=client-key + export SOLR_SSL_CLIENT_KEY_STORE_TYPE=PKCS12 + export SOLR_SSL_CLIENT_TRUST_STORE="$client_ssl_dir/solr-client.truststore.p12" + export SOLR_SSL_CLIENT_TRUST_STORE_PASSWORD=client-trust + export SOLR_SSL_CLIENT_TRUST_STORE_TYPE=PKCS12 + export SOLR_SSL_NEED_CLIENT_AUTH=false + export SOLR_SSL_WANT_CLIENT_AUTH=true + export SOLR_SSL_CHECK_PEER_NAME=true + export SOLR_SSL_CLIENT_HOSTNAME_VERIFICATION=true + export SOLR_HOST=localhost + + solr start -c + solr start -c -z localhost:9983 -p 8984 + + export SOLR_SSL_KEY_STORE= + export SOLR_SSL_KEY_STORE_PASSWORD= + export SOLR_SSL_TRUST_STORE= + export SOLR_SSL_TRUST_STORE_PASSWORD= + + solr assert --started https://localhost:8983/solr --timeout 5000 + solr assert --started https://localhost:8984/solr --timeout 5000 + + run solr create -c test -s 2 + assert_output --partial "Created collection 'test'" + + run solr api -get 'https://localhost:8983/solr/admin/collections?action=CLUSTERSTATUS' + assert_output --partial '"urlScheme":"https"' + + run solr api -get 'https://localhost:8984/solr/test/select?q=*:*&rows=0' + assert_output --partial '"numFound":0' + + export SOLR_SSL_CLIENT_KEY_STORE= + export SOLR_SSL_CLIENT_KEY_STORE_PASSWORD= + + run solr api -get 'https://localhost:8983/solr/test/select?q=*:*&rows=0' + assert_output --partial '"numFound":0' +} diff --git a/solr/solr-ref-guide/modules/configuration-guide/pages/collections-api.adoc b/solr/solr-ref-guide/modules/configuration-guide/pages/collections-api.adoc index 59955461b91..452c384bcc0 100644 --- a/solr/solr-ref-guide/modules/configuration-guide/pages/collections-api.adoc +++ b/solr/solr-ref-guide/modules/configuration-guide/pages/collections-api.adoc @@ -36,6 +36,7 @@ Because this API has a large number of commands and options, we've grouped the c Since some collection API calls can be long running tasks (such as SPLITSHARD), you can optionally have the calls run asynchronously. Specifying `async=` enables you to make an asynchronous call, the status of which can be requested using the <> call at any time. +The ID provided can be any string so long as it doesn't have a `/` in it. As of now, REQUESTSTATUS does not automatically clean up the tracking data structures, meaning the status of completed or failed tasks stays stored in ZooKeeper unless cleared manually. DELETESTATUS can be used to clear the stored statuses. diff --git a/solr/solr-ref-guide/modules/deployment-guide/pages/circuit-breakers.adoc b/solr/solr-ref-guide/modules/deployment-guide/pages/circuit-breakers.adoc index a96658e61bf..b517a2dd195 100644 --- a/solr/solr-ref-guide/modules/deployment-guide/pages/circuit-breakers.adoc +++ b/solr/solr-ref-guide/modules/deployment-guide/pages/circuit-breakers.adoc @@ -22,18 +22,19 @@ resource configuration. == When To Use Circuit Breakers Circuit breakers should be used when the user wishes to trade request throughput for a higher Solr stability. -If circuit breakers are enabled, requests may be rejected under the condition of high node duress with an appropriate HTTP error code (typically 503). +If circuit breakers are enabled, requests may be rejected under the condition of high node duress with HTTP error code 429 'Too Many Requests'. It is up to the client to handle this error and potentially build a retrial logic as this should ideally be a transient situation. == Circuit Breaker Configurations All circuit breaker configurations are listed as independent `` entries in `solrconfig.xml` as shown below. +A circuit breaker can register itself to trip for query requests and/or update requests. By default only search requests are affected. A user may register multiple circuit breakers of the same type with different thresholds for each request type. == Currently Supported Circuit Breakers === JVM Heap Usage -This circuit breaker tracks JVM heap memory usage and rejects incoming search requests with a 503 error code if the heap usage exceeds a configured percentage of maximum heap allocated to the JVM (-Xmx). +This circuit breaker tracks JVM heap memory usage and rejects incoming requests with a 429 error code if the heap usage exceeds a configured percentage of maximum heap allocated to the JVM (-Xmx). The main configuration for this circuit breaker is controlling the threshold percentage at which the breaker will trip. To enable and configure the JVM heap usage based circuit breaker, add the following: @@ -72,8 +73,32 @@ To enable and configure the CPU utilization based circuit breaker: The `threshold` is defined in units of CPU utilization. +== Advanced example + +In this example we will prevent update requests above 80% CPU load, and prevent query requests above 95% CPU load. Supported request types are `query` and `update`. +This would prevent expensive bulk updates from impacting search. Note also the support for short-form class name. + +[source,xml] +---- + + + 80 + + update + + + + + 95 + + query + + + +---- + == Performance Considerations -It is worth noting that while JVM or CPU circuit breakers do not add any noticeable overhead per query, having too many circuit breakers checked for a single request can cause a performance overhead. +It is worth noting that while JVM or CPU circuit breakers do not add any noticeable overhead per request, having too many circuit breakers checked for a single request can cause a performance overhead. In addition, it is a good practice to exponentially back off while retrying requests on a busy node. diff --git a/solr/solr-ref-guide/modules/deployment-guide/pages/enabling-ssl.adoc b/solr/solr-ref-guide/modules/deployment-guide/pages/enabling-ssl.adoc index 4450d677866..1177f423c62 100644 --- a/solr/solr-ref-guide/modules/deployment-guide/pages/enabling-ssl.adoc +++ b/solr/solr-ref-guide/modules/deployment-guide/pages/enabling-ssl.adoc @@ -90,7 +90,8 @@ SOLR_SSL_NEED_CLIENT_AUTH=false # Enable clients to authenticate (but not require) SOLR_SSL_WANT_CLIENT_AUTH=false # SSL Certificates contain host/ip "peer name" information that is validated by default. Setting -# this to false can be useful to disable these checks when re-using a certificate on many hosts +# this to false can be useful to disable these checks when re-using a certificate on many hosts. +# This will also be used for the default value of whether SNI Host checking should be enabled. SOLR_SSL_CHECK_PEER_NAME=true ---- ==== @@ -114,7 +115,8 @@ set SOLR_SSL_NEED_CLIENT_AUTH=false REM Enable clients to authenticate (but not require) set SOLR_SSL_WANT_CLIENT_AUTH=false REM SSL Certificates contain host/ip "peer name" information that is validated by default. Setting -REM this to false can be useful to disable these checks when re-using a certificate on many hosts +REM this to false can be useful to disable these checks when re-using a certificate on many hosts. +REM This will also be used for the default value of whether SNI Host checking should be enabled. set SOLR_SSL_CHECK_PEER_NAME=true ---- ==== diff --git a/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-9.adoc b/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-9.adoc index 2e670ca9f06..002f6cd3e23 100644 --- a/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-9.adoc +++ b/solr/solr-ref-guide/modules/upgrade-notes/pages/major-changes-in-solr-9.adoc @@ -80,6 +80,10 @@ Therefore, when using the default settings, nodes that were previously excluded * The Embedded Zookeeper can now be configured to listen to (or bind to) more hosts than just `localhost`, see the xref:deployment-guide:securing-solr.adoc#network-configuration[Network Configuration documentation] for more information. +=== Security +* The `solr.jetty.ssl.sniHostCheck` option now defaults to the value of `SOLR_SSL_CHECK_PEER_NAME`, if it is provided. +This will enable client and server hostName check settings to be governed by the same environment variable. +If users want separate client/server settings, they can manually override the `solr.jetty.ssl.sniHostCheck` option in `SOLR_OPTS`. == Solr 9.3 === Binary Releases diff --git a/solr/solrj/src/resources/java-template/api.mustache b/solr/solrj/src/resources/java-template/api.mustache index 84f7f06ebf3..93108eae513 100644 --- a/solr/solrj/src/resources/java-template/api.mustache +++ b/solr/solrj/src/resources/java-template/api.mustache @@ -22,6 +22,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrRequest; diff --git a/solr/test-framework/src/java/org/apache/solr/util/TestHarness.java b/solr/test-framework/src/java/org/apache/solr/util/TestHarness.java index 5d049e01ff4..2f8dc0121a7 100644 --- a/solr/test-framework/src/java/org/apache/solr/util/TestHarness.java +++ b/solr/test-framework/src/java/org/apache/solr/util/TestHarness.java @@ -25,7 +25,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Properties; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.client.solrj.impl.SolrZkClientTimeout; import org.apache.solr.common.SolrException; @@ -94,6 +93,11 @@ public static SolrConfig createConfig(Path solrHome, String confFile) { return createConfig(solrHome, SolrTestCaseJ4.DEFAULT_TEST_CORENAME, confFile); } + public TestHarness(CoreContainer coreContainer) { + this.container = coreContainer; + this.coreName = SolrTestCaseJ4.DEFAULT_TEST_CORENAME; + } + /** * @param coreName to initialize * @param dataDirectory path for index data, will not be cleaned up @@ -187,9 +191,6 @@ public TestHarness(NodeConfig config, CoresLocator coresLocator) { } public static NodeConfig buildTestNodeConfig(Path solrHome) { - if ("true".equals(System.getProperty("solr.tests.loadSolrXml"))) { - return SolrXmlConfig.fromSolrHome(solrHome, new Properties()); - } CloudConfig cloudConfig = (null == System.getProperty("zkHost")) ? null diff --git a/versions.lock b/versions.lock index 25d922b05a8..d82e118dee1 100644 --- a/versions.lock +++ b/versions.lock @@ -275,28 +275,28 @@ org.codehaus.janino:janino:3.1.8 (1 constraints: 640dbc2c) org.codehaus.woodstox:stax2-api:4.2.1 (2 constraints: 36152eaf) org.codelibs:jhighlight:1.1.0 (1 constraints: 590ce401) org.conscrypt:conscrypt-openjdk-uber:2.5.2 (1 constraints: ed0fea95) -org.eclipse.jetty:jetty-alpn-client:10.0.15 (3 constraints: f12e1a60) -org.eclipse.jetty:jetty-alpn-java-client:10.0.15 (2 constraints: 1f1b936e) -org.eclipse.jetty:jetty-alpn-java-server:10.0.15 (1 constraints: 69059140) -org.eclipse.jetty:jetty-alpn-server:10.0.15 (2 constraints: f5160f49) -org.eclipse.jetty:jetty-client:10.0.15 (2 constraints: 1f1b936e) -org.eclipse.jetty:jetty-deploy:10.0.15 (1 constraints: 69059140) -org.eclipse.jetty:jetty-http:10.0.15 (6 constraints: 764fc18c) -org.eclipse.jetty:jetty-io:10.0.15 (9 constraints: b57d78e3) -org.eclipse.jetty:jetty-jmx:10.0.15 (1 constraints: 69059140) -org.eclipse.jetty:jetty-rewrite:10.0.15 (1 constraints: 69059140) -org.eclipse.jetty:jetty-security:10.0.15 (2 constraints: bc131b79) -org.eclipse.jetty:jetty-server:10.0.15 (7 constraints: d26d3b23) -org.eclipse.jetty:jetty-servlet:10.0.15 (2 constraints: 36134761) -org.eclipse.jetty:jetty-servlets:10.0.15 (1 constraints: 69059140) -org.eclipse.jetty:jetty-util:10.0.15 (9 constraints: a5819691) -org.eclipse.jetty:jetty-webapp:10.0.15 (2 constraints: 4413cf61) -org.eclipse.jetty:jetty-xml:10.0.15 (3 constraints: 1121b6ba) -org.eclipse.jetty.http2:http2-client:10.0.15 (2 constraints: 1f1b936e) -org.eclipse.jetty.http2:http2-common:10.0.15 (3 constraints: df24e261) -org.eclipse.jetty.http2:http2-hpack:10.0.15 (2 constraints: 221568e0) -org.eclipse.jetty.http2:http2-http-client-transport:10.0.15 (1 constraints: 69059140) -org.eclipse.jetty.http2:http2-server:10.0.15 (1 constraints: 69059140) +org.eclipse.jetty:jetty-alpn-client:10.0.16 (3 constraints: f42ea460) +org.eclipse.jetty:jetty-alpn-java-client:10.0.16 (2 constraints: 211bd36e) +org.eclipse.jetty:jetty-alpn-java-server:10.0.16 (1 constraints: 6a059240) +org.eclipse.jetty:jetty-alpn-server:10.0.16 (2 constraints: f7164449) +org.eclipse.jetty:jetty-client:10.0.16 (2 constraints: 211bd36e) +org.eclipse.jetty:jetty-deploy:10.0.16 (1 constraints: 6a059240) +org.eclipse.jetty:jetty-http:10.0.16 (6 constraints: 7b4faa8e) +org.eclipse.jetty:jetty-io:10.0.16 (9 constraints: bd7d6ce8) +org.eclipse.jetty:jetty-jmx:10.0.16 (1 constraints: 6a059240) +org.eclipse.jetty:jetty-rewrite:10.0.16 (1 constraints: 6a059240) +org.eclipse.jetty:jetty-security:10.0.16 (2 constraints: be134779) +org.eclipse.jetty:jetty-server:10.0.16 (7 constraints: d76dba26) +org.eclipse.jetty:jetty-servlet:10.0.16 (2 constraints: 38137261) +org.eclipse.jetty:jetty-servlets:10.0.16 (1 constraints: 6a059240) +org.eclipse.jetty:jetty-util:10.0.16 (9 constraints: ac815797) +org.eclipse.jetty:jetty-webapp:10.0.16 (2 constraints: 4613fa61) +org.eclipse.jetty:jetty-xml:10.0.16 (3 constraints: 142134bb) +org.eclipse.jetty.http2:http2-client:10.0.16 (2 constraints: 211bd36e) +org.eclipse.jetty.http2:http2-common:10.0.16 (3 constraints: e2247262) +org.eclipse.jetty.http2:http2-hpack:10.0.16 (2 constraints: 241599e0) +org.eclipse.jetty.http2:http2-http-client-transport:10.0.16 (1 constraints: 6a059240) +org.eclipse.jetty.http2:http2-server:10.0.16 (1 constraints: 6a059240) org.eclipse.jetty.toolchain:jetty-servlet-api:4.0.6 (4 constraints: 883053bf) org.gagravarr:vorbis-java-core:0.8 (1 constraints: 010c57e9) org.gagravarr:vorbis-java-tika:0.8 (1 constraints: 010c57e9) @@ -343,7 +343,7 @@ org.ow2.asm:asm-commons:7.2 (1 constraints: 6b0f7267) org.ow2.asm:asm-tree:7.2 (2 constraints: 2f14468c) org.quicktheories:quicktheories:0.26 (1 constraints: dc04f530) org.reactivestreams:reactive-streams:1.0.3 (3 constraints: 3c2b02fd) -org.semver4j:semver4j:4.3.0 (1 constraints: 09050836) +org.semver4j:semver4j:5.1.0 (1 constraints: 08050736) org.slf4j:jcl-over-slf4j:2.0.7 (3 constraints: cd1757a6) org.slf4j:jul-to-slf4j:2.0.7 (3 constraints: 27289948) org.slf4j:slf4j-api:2.0.7 (59 constraints: 0d112d8b) diff --git a/versions.props b/versions.props index 3e61cbe6326..334ed14d0be 100644 --- a/versions.props +++ b/versions.props @@ -54,7 +54,7 @@ org.apache.zookeeper:*=3.9.0 org.bitbucket.b_c:jose4j=0.9.3 org.carrot2:carrot2-core=4.5.1 org.codehaus.woodstox:stax2-api=4.2.1 -org.eclipse.jetty*:*=10.0.15 +org.eclipse.jetty*:*=10.0.16 org.eclipse.jetty.toolchain:jetty-servlet-api=4.0.6 org.glassfish.hk2*:*=2.6.1 org.glassfish.jersey*:*=2.35 @@ -66,7 +66,7 @@ org.mockito:mockito*=5.3.1 org.openjdk.jmh:*=1.37 org.osgi:osgi.annotation=8.1.0 org.quicktheories:quicktheories=0.26 -org.semver4j:semver4j=4.3.0 +org.semver4j:semver4j=5.1.0 org.slf4j:*=2.0.7 org.xerial.snappy:snappy-java=1.1.10.1 software.amazon.awssdk:*=2.20.128