You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by da...@apache.org on 2018/11/05 11:01:45 UTC

[18/19] lucene-solr:jira/http2: SOLR-12938 - Cluster status now returns results for aliases instead of throwing an exception

SOLR-12938 - Cluster status now returns results for aliases instead of
throwing an exception


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/45b772f4
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/45b772f4
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/45b772f4

Branch: refs/heads/jira/http2
Commit: 45b772f4a995c618b48ff05c6129c5683df92f88
Parents: eb359ca
Author: Gus Heck <gu...@apache.org>
Authored: Sun Nov 4 12:01:51 2018 -0500
Committer: Gus Heck <gu...@apache.org>
Committed: Sun Nov 4 12:01:51 2018 -0500

----------------------------------------------------------------------
 solr/CHANGES.txt                                |  2 ++
 .../solr/handler/admin/ClusterStatus.java       | 12 +++++++
 .../api/collections/TestCollectionAPI.java      | 37 +++++++++++++++++++-
 solr/solr-ref-guide/src/collections-api.adoc    |  2 +-
 .../solrj/impl/HttpClusterStateProvider.java    | 34 ++++++++++++------
 5 files changed, 74 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/45b772f4/solr/CHANGES.txt
----------------------------------------------------------------------
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index be31fe7..a5616bf 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -90,6 +90,8 @@ New Features
 
 * SOLR-12862: Add log10 Stream Evaluator and allow the pow Stream Evaluator to accept a vector of exponents (Joel Bernstein)
 
+* SOLR-12938: Cluster Status returns results for aliases, instead of throwing exceptions (Gus Heck)
+
 Other Changes
 ----------------------
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/45b772f4/solr/core/src/java/org/apache/solr/handler/admin/ClusterStatus.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/ClusterStatus.java b/solr/core/src/java/org/apache/solr/handler/admin/ClusterStatus.java
index 9ebac77..4daae31 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/ClusterStatus.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/ClusterStatus.java
@@ -26,6 +26,7 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.cloud.Aliases;
@@ -92,6 +93,17 @@ public class ClusterStatus {
       collectionsMap = Collections.singletonMap(collection, clusterState.getCollectionOrNull(collection));
     }
 
+    boolean isAlias = aliasVsCollections.containsKey(collection);
+    boolean didNotFindCollection = collectionsMap.get(collection) == null;
+
+    if (didNotFindCollection && isAlias) {
+      // In this case this.collection is an alias name not a collection
+      // get all collections and filter out collections not in the alias
+      collectionsMap = clusterState.getCollectionsMap().entrySet().stream()
+          .filter((entry) -> aliasVsCollections.get(collection).contains(entry.getKey()))
+          .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+    }
+
     NamedList<Object> collectionProps = new SimpleOrderedMap<>();
 
     for (Map.Entry<String, DocCollection> entry : collectionsMap.entrySet()) {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/45b772f4/solr/core/src/test/org/apache/solr/cloud/api/collections/TestCollectionAPI.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/TestCollectionAPI.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/TestCollectionAPI.java
index 574ae37..531e154 100644
--- a/solr/core/src/test/org/apache/solr/cloud/api/collections/TestCollectionAPI.java
+++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/TestCollectionAPI.java
@@ -418,13 +418,17 @@ public class TestCollectionAPI extends ReplicaPropertiesBase {
 
   private void clusterStatusAliasTest() throws Exception  {
     try (CloudSolrClient client = createCloudClient(null)) {
+      // create an alias named myalias
       ModifiableSolrParams params = new ModifiableSolrParams();
       params.set("action", CollectionParams.CollectionAction.CREATEALIAS.toString());
       params.set("name", "myalias");
       params.set("collections", DEFAULT_COLLECTION + "," + COLLECTION_NAME);
       SolrRequest request = new QueryRequest(params);
       request.setPath("/admin/collections");
+
       client.request(request);
+
+      // request a collection that's part of an alias
       params = new ModifiableSolrParams();
       params.set("action", CollectionParams.CollectionAction.CLUSTERSTATUS.toString());
       params.set("collection", DEFAULT_COLLECTION);
@@ -433,7 +437,6 @@ public class TestCollectionAPI extends ReplicaPropertiesBase {
 
       NamedList<Object> rsp = client.request(request);
 
-
       NamedList<Object> cluster = (NamedList<Object>) rsp.get("cluster");
       assertNotNull("Cluster state should not be null", cluster);
       Map<String, String> aliases = (Map<String, String>) cluster.get("aliases");
@@ -448,6 +451,38 @@ public class TestCollectionAPI extends ReplicaPropertiesBase {
       assertEquals("conf1", collection.get("configName"));
       List<String> collAlias = (List<String>) collection.get("aliases");
       assertEquals("Aliases not found", Lists.newArrayList("myalias"), collAlias);
+
+      // status request on the alias itself
+      params = new ModifiableSolrParams();
+      params.set("action", CollectionParams.CollectionAction.CLUSTERSTATUS.toString());
+      params.set("collection", "myalias");
+      request = new QueryRequest(params);
+      request.setPath("/admin/collections");
+
+      // SOLR-12938 - this should NOT cause an exception
+      rsp = client.request(request);
+
+      cluster = (NamedList<Object>) rsp.get("cluster");
+      assertNotNull("Cluster state should not be null", cluster);
+      collections = (NamedList<Object>) cluster.get("collections");
+      assertNotNull("Collections should not be null in cluster state", collections);
+      assertNotNull(collections.get(DEFAULT_COLLECTION));
+      assertNotNull(collections.get(COLLECTION_NAME));
+
+      // status request on something neither an alias nor a collection itself
+      params = new ModifiableSolrParams();
+      params.set("action", CollectionParams.CollectionAction.CLUSTERSTATUS.toString());
+      params.set("collection", "notAnAliasOrCollection");
+      request = new QueryRequest(params);
+      request.setPath("/admin/collections");
+
+      // SOLR-12938 - this should still cause an exception
+      try {
+        client.request(request);
+        fail("requesting status for 'notAnAliasOrCollection' should cause an exception from CLUSTERSTATUS" );
+      } catch (RuntimeException e) {
+        // success
+      }
     }
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/45b772f4/solr/solr-ref-guide/src/collections-api.adoc
----------------------------------------------------------------------
diff --git a/solr/solr-ref-guide/src/collections-api.adoc b/solr/solr-ref-guide/src/collections-api.adoc
index ec8517d..b5dda3e 100644
--- a/solr/solr-ref-guide/src/collections-api.adoc
+++ b/solr/solr-ref-guide/src/collections-api.adoc
@@ -1663,7 +1663,7 @@ Fetch the cluster status including collections, shards, replicas, configuration
 === CLUSTERSTATUS Parameters
 
 `collection`::
-The collection name for which information is requested. If omitted, information on all collections in the cluster will be returned.
+The collection or alias name for which information is requested. If omitted, information on all collections in the cluster will be returned. If an alias is supplied, information on the collections in the alias will be returned.
 
 `shard`::
 The shard(s) for which information is requested. Multiple shard names can be specified as a comma-separated list.

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/45b772f4/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpClusterStateProvider.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpClusterStateProvider.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpClusterStateProvider.java
index deb8fbc..484eaad 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpClusterStateProvider.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpClusterStateProvider.java
@@ -96,14 +96,13 @@ public class HttpClusterStateProvider implements ClusterStateProvider {
         ClusterState cs = fetchClusterState(client, collection, null);
         return cs.getCollectionRef(collection);
       } catch (SolrServerException | RemoteSolrException | IOException e) {
-        if (e.getMessage().contains(collection + " not found")) {
-          // Cluster state for the given collection was not found.
-          // Lets fetch/update our aliases:
-          getAliases(true);
-          return null;
-        }
         log.warn("Attempt to fetch cluster state from " +
             Utils.getBaseUrlForNodeName(nodeName, urlScheme) + " failed.", e);
+      } catch (NotACollectionException e) {
+        // Cluster state for the given collection was not found, could be an alias.
+        // Lets fetch/update our aliases:
+        getAliases(true);
+        return null;
       }
     }
     throw new RuntimeException("Tried fetching cluster state using the node names we knew of, i.e. " + liveNodes +". However, "
@@ -114,7 +113,7 @@ public class HttpClusterStateProvider implements ClusterStateProvider {
   }
 
   @SuppressWarnings({"rawtypes", "unchecked"})
-  private ClusterState fetchClusterState(SolrClient client, String collection, Map<String, Object> clusterProperties) throws SolrServerException, IOException {
+  private ClusterState fetchClusterState(SolrClient client, String collection, Map<String, Object> clusterProperties) throws SolrServerException, IOException, NotACollectionException {
     ModifiableSolrParams params = new ModifiableSolrParams();
     if (collection != null) {
       params.set("collection", collection);
@@ -131,8 +130,12 @@ public class HttpClusterStateProvider implements ClusterStateProvider {
       collectionsMap = ((NamedList)cluster.get("collections")).asMap(10);
     }
     int znodeVersion;
-    if (collection != null) {
-      znodeVersion =  (int)((Map<String, Object>)(collectionsMap).get(collection)).get("znodeVersion");
+    Map<String, Object> collFromStatus = (Map<String, Object>) (collectionsMap).get(collection);
+    if (collection != null && collFromStatus == null) {
+      throw new NotACollectionException(); // probably an alias
+    }
+    if (collection != null) { // can be null if alias
+      znodeVersion =  (int) collFromStatus.get("znodeVersion");
     } else {
       znodeVersion = -1;
     }
@@ -253,6 +256,10 @@ public class HttpClusterStateProvider implements ClusterStateProvider {
       } catch (SolrServerException | RemoteSolrException | IOException e) {
         log.warn("Attempt to fetch cluster state from " +
             Utils.getBaseUrlForNodeName(nodeName, urlScheme) + " failed.", e);
+      } catch (NotACollectionException e) {
+        // Cluster state for the given collection was not found, could be an alias.
+        // Lets fetch/update our aliases:
+        getAliases(true);
       }
     }
     throw new RuntimeException("Tried fetching cluster state using the node names we knew of, i.e. " + liveNodes +". However, "
@@ -264,7 +271,7 @@ public class HttpClusterStateProvider implements ClusterStateProvider {
 
   @Override
   public Map<String, Object> getClusterProperties() {
-    for (String nodeName: liveNodes) {
+    for (String nodeName : liveNodes) {
       try (HttpSolrClient client = new HttpSolrClient.Builder().
           withBaseSolrUrl(Utils.getBaseUrlForNodeName(nodeName, urlScheme)).
           withHttpClient(httpClient).build()) {
@@ -274,9 +281,11 @@ public class HttpClusterStateProvider implements ClusterStateProvider {
       } catch (SolrServerException | RemoteSolrException | IOException e) {
         log.warn("Attempt to fetch cluster state from " +
             Utils.getBaseUrlForNodeName(nodeName, urlScheme) + " failed.", e);
+      } catch (NotACollectionException e) {
+        // should be an an alias, don't care
       }
     }
-    throw new RuntimeException("Tried fetching cluster state using the node names we knew of, i.e. " + liveNodes +". However, "
+    throw new RuntimeException("Tried fetching cluster state using the node names we knew of, i.e. " + liveNodes + ". However, "
         + "succeeded in obtaining the cluster state from none of them."
         + "If you think your Solr cluster is up and is accessible,"
         + " you could try re-creating a new CloudSolrClient using working"
@@ -309,4 +318,7 @@ public class HttpClusterStateProvider implements ClusterStateProvider {
     this.cacheTimeout = cacheTimeout;
   }
 
+  // This exception is not meant to escape this class it should be caught and wrapped.
+  private class NotACollectionException extends Exception {
+  }
 }