This is an automated email from the ASF dual-hosted git repository.
dsmiley pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/main by this push:
new 09e8d0cb0d9 SOLR-17153: Fix IndexOutOfBoundsException, add bats test
(#2393)
09e8d0cb0d9 is described below
commit 09e8d0cb0d938711e9f65636bff1d45e49512eed
Author: aparnasuresh85 <[email protected]>
AuthorDate: Wed Apr 10 09:44:22 2024 -0400
SOLR-17153: Fix IndexOutOfBoundsException, add bats test (#2393)
Resolve IndexOutOfBoundsException, a regression from the first change in
this issue.
* Call resolveDocCollection inside getCoreByCollection
* New BATS test to check URLs that the Solr Admin UI (or a user trying to
navigate to such) might use
---
.../src/java/org/apache/solr/api/V2HttpCall.java | 23 ++++++-------
.../java/org/apache/solr/servlet/HttpSolrCall.java | 29 ++++++++++-------
solr/packaging/test/test_adminconsole_urls.bats | 38 ++++++++++++++++++++++
3 files changed, 66 insertions(+), 24 deletions(-)
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 20cec8f846c..6912af39510 100644
--- a/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
+++ b/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
@@ -40,7 +40,6 @@ import javax.servlet.http.HttpServletResponse;
import net.jcip.annotations.ThreadSafe;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.common.SolrException;
-import org.apache.solr.common.cloud.DocCollection;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.JsonSchemaValidator;
import org.apache.solr.common.util.PathTrie;
@@ -141,7 +140,12 @@ public class V2HttpCall extends HttpSolrCall {
String collectionStr = queryParams.get(COLLECTION_PROP, origCorename);
collectionsList =
resolveCollectionListOrAlias(collectionStr); // &collection= takes
precedence
- if (collectionsList.size() > 1) {
+ if (collectionsList.isEmpty()) {
+ if (!path.endsWith(CommonParams.INTROSPECT)) {
+ throw new SolrException(
+ SolrException.ErrorCode.BAD_REQUEST, "Resolved list of
collections is empty");
+ }
+ } else if (collectionsList.size() > 1) {
throw new SolrException(
SolrException.ErrorCode.BAD_REQUEST,
"Request must be sent to a single collection "
@@ -150,29 +154,22 @@ public class V2HttpCall extends HttpSolrCall {
+ collectionStr
+ "' resolves to "
+ this.collectionsList);
- }
- DocCollection collection = resolveDocCollection(collectionsList);
- if (collection == null) {
- if (!path.endsWith(CommonParams.INTROSPECT)) {
- throw new SolrException(
- SolrException.ErrorCode.BAD_REQUEST, "no such collection or
alias");
- }
} else {
+ String collectionName = collectionsList.get(0);
// Certain HTTP methods are only used for admin APIs, check for
those and short-circuit
if
(List.of("delete").contains(req.getMethod().toLowerCase(Locale.ROOT))) {
initAdminRequest(path);
return;
}
boolean isPreferLeader = (path.endsWith("/update") ||
path.contains("/update/"));
- core = getCoreByCollection(collection.getName(), isPreferLeader);
+ core = getCoreByCollection(collectionName, isPreferLeader);
if (core == null) {
// this collection exists , but this node does not have a replica
for that collection
- extractRemotePath(collection.getName(), collection.getName());
+ extractRemotePath(collectionName, collectionName);
if (action == REMOTEQUERY) {
action = ADMIN_OR_REMOTEQUERY;
coreUrl = coreUrl.replace("/solr/", "/solr/____v2/c/");
- this.path =
- path = path.substring(prefix.length() +
collection.getName().length() + 2);
+ this.path = path = path.substring(prefix.length() +
collectionName.length() + 2);
return;
}
}
diff --git a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
index 2e5856f9ad0..72633c76f59 100644
--- a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
+++ b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
@@ -282,8 +282,6 @@ public class HttpSolrCall {
queryParams.get(COLLECTION_PROP, def)); // &collection= takes
precedence
if (core == null) {
- // force update collection only if local clusterstate is outdated
- resolveDocCollection(collectionsList);
// lookup core from collection, or route away if need to
// route to 1st
String collectionName = collectionsList.isEmpty() ? null :
collectionsList.get(0);
@@ -349,18 +347,21 @@ public class HttpSolrCall {
}
/**
- * Lookup the collection from the collection string (maybe comma delimited).
Also sets {@link
- * #collectionsList} by side-effect. if {@code secondTry} is false then
we'll potentially
- * recursively try this all one more time while ensuring the alias and
collection info is sync'ed
- * from ZK.
+ * Resolves the specified collection name to a {@link DocCollection} object.
If Solr is not in
+ * cloud mode, a {@link SolrException} is thrown. Returns null if the
collection name is null or
+ * empty. Retrieves the {@link DocCollection} using the {@link
ZkStateReader} from {@link
+ * CoreContainer}. If the collection is null, updates the state by
refreshing aliases and forcing
+ * a collection update.
*/
- protected DocCollection resolveDocCollection(List<String> collectionsList) {
+ protected DocCollection resolveDocCollection(String collectionName) {
if (!cores.isZooKeeperAware()) {
throw new SolrException(
SolrException.ErrorCode.BAD_REQUEST, "Solr not running in cloud mode
");
}
+ if (collectionName == null || collectionName.trim().isEmpty()) {
+ return null;
+ }
ZkStateReader zkStateReader = cores.getZkController().getZkStateReader();
- String collectionName = collectionsList.get(0);
Supplier<DocCollection> logic =
() ->
zkStateReader.getClusterState().getCollectionOrNull(collectionName);
@@ -1064,15 +1065,21 @@ public class HttpSolrCall {
return result;
}
+ /**
+ * Retrieves a SolrCore instance associated with the specified collection
name, with an option to
+ * prefer leader replicas. Makes a call to {@link #resolveDocCollection}
which make an attempt to
+ * force update collection if it is not found in local cluster state
+ */
protected SolrCore getCoreByCollection(String collectionName, boolean
isPreferLeader) {
ZkStateReader zkStateReader = cores.getZkController().getZkStateReader();
-
ClusterState clusterState = zkStateReader.getClusterState();
- DocCollection collection =
clusterState.getCollectionOrNull(collectionName, true);
+ DocCollection collection = resolveDocCollection(collectionName);
+ // the usage of getCoreByCollection assumes that if null is returned,
collection is found, but
+ // replicas might not
+ // have been created. Hence returning null here would be misleading...
if (collection == null) {
return null;
}
-
Set<String> liveNodes = clusterState.getLiveNodes();
if (isPreferLeader) {
diff --git a/solr/packaging/test/test_adminconsole_urls.bats
b/solr/packaging/test/test_adminconsole_urls.bats
new file mode 100644
index 00000000000..68fb79df3ed
--- /dev/null
+++ b/solr/packaging/test/test_adminconsole_urls.bats
@@ -0,0 +1,38 @@
+#!/usr/bin/env bats
+
+# 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.
+
+load bats_helper
+
+setup() {
+ common_clean_setup
+}
+
+teardown() {
+ # save a snapshot of SOLR_HOME for failed tests
+ save_home_on_failure
+
+ solr stop -all >/dev/null 2>&1
+}
+
+@test "assert able to launch solr admin console" {
+ run solr start -c
+
+ run curl -s -o /dev/null -w "%{http_code}"
http://localhost:${SOLR_PORT}/solr/
+
+ # Check if the HTTP response code is 200 (OK)
+ assert_output "200"
+}