You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by is...@apache.org on 2020/07/07 02:17:03 UTC

[lucene-solr] branch branch_8x updated: SOLR-14599: Ref guide updates and some error handling fixes

This is an automated email from the ASF dual-hosted git repository.

ishan pushed a commit to branch branch_8x
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git


The following commit(s) were added to refs/heads/branch_8x by this push:
     new c51981a  SOLR-14599: Ref guide updates and some error handling fixes
c51981a is described below

commit c51981a08cfbd834c814c4282b38e9792891a0bb
Author: Ishan Chattopadhyaya <is...@apache.org>
AuthorDate: Tue Jul 7 07:39:45 2020 +0530

    SOLR-14599: Ref guide updates and some error handling fixes
    
    * Ref guide section for types of plugins (that now includes a cluster level plugins section)
    * Ref guide updates for deploying, undeploying, updating cluster level plugins
    * Better error handling for cluster level plugin deployments
---
 .../apache/solr/packagemanager/PackageManager.java | 124 ++++++++++++---------
 .../solr/packagemanager/RepositoryManager.java     |  15 ++-
 .../src/java/org/apache/solr/util/PackageTool.java |  42 ++++---
 solr/solr-ref-guide/src/package-manager.adoc       |  38 ++++++-
 solr/solr-ref-guide/src/solr-plugins.adoc          |  10 +-
 5 files changed, 156 insertions(+), 73 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java b/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java
index 715e6a4..069122d 100644
--- a/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java
+++ b/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java
@@ -190,13 +190,13 @@ public class PackageManager implements Closeable {
       List<String> collections, boolean shouldDeployClusterPlugins, String[] overrides) {
 
     // Install plugins of type "cluster"
-    boolean clusterSuccess = deployClusterPackage(packageInstance, isUpdate, noprompt, shouldDeployClusterPlugins,
-        overrides);
-
+    boolean clusterSuccess = true;
+    if (shouldDeployClusterPlugins) {
+      clusterSuccess = deployClusterPackage(packageInstance, isUpdate, noprompt, overrides);
+    }
     
     // Install plugins of type "collection"
-    Pair<List<String>, List<String>> deployResult = deployCollectionPackage(packageInstance, pegToLatest, isUpdate, noprompt, collections,
-        shouldDeployClusterPlugins, overrides);
+    Pair<List<String>, List<String>> deployResult = deployCollectionPackage(packageInstance, pegToLatest, isUpdate, noprompt, collections, overrides);
     List<String> deployedCollections = deployResult.first();
     List<String> previouslyDeployedOnCollections = deployResult.second();
     
@@ -215,7 +215,7 @@ public class PackageManager implements Closeable {
    * @return list of collections on which packages deployed on
    */
   private Pair<List<String>, List<String>> deployCollectionPackage(SolrPackageInstance packageInstance, boolean pegToLatest, boolean isUpdate,
-      boolean noprompt, List<String> collections, boolean shouldDeployClusterPlugins, String[] overrides) {
+      boolean noprompt, List<String> collections, String[] overrides) {
     List<String> previouslyDeployed =  new ArrayList<>(); // collections where package is already deployed in
     for (String collection: collections) {
       SolrPackageInstance deployedPackage = getPackagesDeployed(collection).get(packageInstance.name);
@@ -277,18 +277,7 @@ public class PackageManager implements Closeable {
                 String payload = PackageUtils.resolve(getMapper().writeValueAsString(cmd.payload), packageInstance.parameterDefaults, collectionParameterOverrides, systemParams);
                 String path = PackageUtils.resolve(cmd.path, packageInstance.parameterDefaults, collectionParameterOverrides, systemParams);
                 PackageUtils.printGreen("Executing " + payload + " for path:" + path);
-                boolean shouldExecute = true;
-                if (!noprompt) { // show a prompt asking user to execute the setup command for the plugin
-                  PackageUtils.print(PackageUtils.YELLOW, "Execute this command (y/n): ");
-                  try (Scanner scanner = new Scanner(System.in, "UTF-8")) {
-                    String userInput = scanner.next();
-                    if (!"yes".equalsIgnoreCase(userInput) && !"y".equalsIgnoreCase(userInput)) {
-                      shouldExecute = false;
-                      PackageUtils.printRed("Skipping setup command for deploying (deployment verification may fail)."
-                          + " Please run this step manually or refer to package documentation.");
-                    }
-                  }
-                }
+                boolean shouldExecute = prompt(noprompt);
                 if (shouldExecute) {
                   SolrCLI.postJsonToSolr(solrClient, path, payload);
                 }
@@ -322,17 +311,17 @@ public class PackageManager implements Closeable {
   }
 
   @SuppressWarnings("unchecked")
-  private boolean deployClusterPackage(SolrPackageInstance packageInstance, boolean isUpdate, boolean noprompt,
-      boolean shouldDeployClusterPlugins, String[] overrides) {
-    boolean cluasterPluginFailed = false;
+  private boolean deployClusterPackage(SolrPackageInstance packageInstance, boolean isUpdate, boolean noprompt, String[] overrides) {
+    boolean clusterPluginFailed = false;
+    int numberOfClusterPluginsDeployed = 0;
 
     if (isUpdate) {
       for (Plugin plugin: packageInstance.plugins) {
-        if (!shouldDeployClusterPlugins || "cluster".equalsIgnoreCase(plugin.type) == false) continue;
+        if ("cluster".equalsIgnoreCase(plugin.type) == false) continue;
         SolrPackageInstance deployedPackage = getPackagesDeployedAsClusterLevelPlugins().get(packageInstance.name);
         if (deployedPackage == null) {
           PackageUtils.printRed("Cluster level plugin " + plugin.name + " from package " + packageInstance.name + " not deployed. To deploy, remove the --update parameter.");
-          cluasterPluginFailed = true;
+          clusterPluginFailed = true;
           continue;
         }
         for (PluginMeta pluginMeta: (List<PluginMeta>)deployedPackage.getCustomData()) {
@@ -346,10 +335,17 @@ public class PackageManager implements Closeable {
             throw new SolrException(ErrorCode.SERVER_ERROR, e);
           }
         }
+        numberOfClusterPluginsDeployed++;
+      }
+      if (numberOfClusterPluginsDeployed > 0) {
+        PackageUtils.printGreen(numberOfClusterPluginsDeployed + " cluster level plugins updated.");
+      } else {
+        PackageUtils.printRed("No cluster level plugin updated.");
+        clusterPluginFailed = true;
       }
     } else {
       for (Plugin plugin: packageInstance.plugins) {
-        if (!shouldDeployClusterPlugins || "cluster".equalsIgnoreCase(plugin.type) == false) continue;
+        if ("cluster".equalsIgnoreCase(plugin.type) == false) continue;
         // Check if this cluster level plugin is already deployed
         {
           Map<String, Object> clusterprops = null;
@@ -364,13 +360,13 @@ public class PackageManager implements Closeable {
             Object pkg = ((Map<String, Object>)clusterprops.getOrDefault("plugin", Collections.emptyMap())).get(packageInstance.name+":"+plugin.name);
             if (pkg != null) {
               PackageUtils.printRed("Cluster level plugin " + plugin.name + " from package " + packageInstance.name + " already deployed. To update to " + packageInstance + ", pass --update parameter.");
-              cluasterPluginFailed = true;
+              clusterPluginFailed = true;
               continue;
             }
           }
         }
 
-        // Lets install this plugin now
+        // Lets setup this plugin now
         Map<String, String> systemParams = PackageUtils.map("package-name", packageInstance.name, "package-version", packageInstance.version, "plugin-name", plugin.name);
         Command cmd = plugin.setupCommand;
         if (cmd != null && !Strings.isNullOrEmpty(cmd.method)) {
@@ -380,20 +376,10 @@ public class PackageManager implements Closeable {
               String payload = PackageUtils.resolve(getMapper().writeValueAsString(cmd.payload), packageInstance.parameterDefaults, overridesMap, systemParams);
               String path = PackageUtils.resolve(cmd.path, packageInstance.parameterDefaults, overridesMap, systemParams);
               PackageUtils.printGreen("Executing " + payload + " for path:" + path);
-              boolean shouldExecute = true;
-              if (!noprompt) { // show a prompt asking user to execute the setup command for the plugin
-                PackageUtils.print(PackageUtils.YELLOW, "Execute this command (y/n): ");
-                try (Scanner scanner = new Scanner(System.in, "UTF-8")) {
-                  String userInput = scanner.next();
-                  if (!"yes".equalsIgnoreCase(userInput) && !"y".equalsIgnoreCase(userInput)) {
-                    shouldExecute = false;
-                    PackageUtils.printRed("Skipping setup command for deploying (deployment verification may fail)."
-                        + " Please run this step manually or refer to package documentation.");
-                  }
-                }
-              }
+              boolean shouldExecute = prompt(noprompt);
               if (shouldExecute) {
                 SolrCLI.postJsonToSolr(solrClient, path, payload);
+                numberOfClusterPluginsDeployed++;
               }
             } catch (Exception ex) {
               throw new SolrException(ErrorCode.SERVER_ERROR, ex);
@@ -405,8 +391,30 @@ public class PackageManager implements Closeable {
           PackageUtils.printRed("There is no setup command to execute for plugin: " + plugin.name);
         }
       }
+      if (numberOfClusterPluginsDeployed > 0) {
+        PackageUtils.printGreen(numberOfClusterPluginsDeployed + " cluster level plugins setup.");
+      } else {
+        PackageUtils.printRed("No cluster level plugin setup.");
+        clusterPluginFailed = true;
+      }
+    }
+    return !clusterPluginFailed;
+  }
+
+  private boolean prompt(boolean noprompt) {
+    boolean shouldExecute = true;
+    if (!noprompt) { // show a prompt asking user to execute the setup command for the plugin
+      PackageUtils.print(PackageUtils.YELLOW, "Execute this command. (If you choose no, you can manually deploy/undeploy this plugin later) (y/n): ");
+      try (Scanner scanner = new Scanner(System.in, "UTF-8")) {
+        String userInput = scanner.next();
+        if ("no".trim().equalsIgnoreCase(userInput) || "n".trim().equalsIgnoreCase(userInput)) {
+          shouldExecute = false;
+          PackageUtils.printRed("Skipping setup command for deploying (deployment verification may fail)."
+              + " Please run this step manually or refer to package documentation.");
+        }
+      }
     }
-    return !cluasterPluginFailed;
+    return shouldExecute;
   }
 
 
@@ -465,16 +473,24 @@ public class PackageManager implements Closeable {
           if ("GET".equalsIgnoreCase(cmd.method)) {
             String response = PackageUtils.getJsonStringFromUrl(solrClient.getHttpClient(), url);
             PackageUtils.printGreen(response);
-            String actualValue = JsonPath.parse(response, PackageUtils.jsonPathConfiguration())
+            String actualValue = null;
+            try {
+              actualValue = JsonPath.parse(response, PackageUtils.jsonPathConfiguration())
                 .read(PackageUtils.resolve(cmd.condition, pkg.parameterDefaults, overridesMap, systemParams));
-            String expectedValue = PackageUtils.resolve(cmd.expected, pkg.parameterDefaults, overridesMap, systemParams);
-            PackageUtils.printGreen("Actual: " + actualValue+", expected: " + expectedValue);
-            if (!expectedValue.equals(actualValue)) {
+            } catch (PathNotFoundException ex) {
               PackageUtils.printRed("Failed to deploy plugin: " + plugin.name);
               success = false;
             }
+            if (actualValue != null) {
+              String expectedValue = PackageUtils.resolve(cmd.expected, pkg.parameterDefaults, overridesMap, systemParams);
+              PackageUtils.printGreen("Actual: " + actualValue+", expected: " + expectedValue);
+              if (!expectedValue.equals(actualValue)) {
+                PackageUtils.printRed("Failed to deploy plugin: " + plugin.name);
+                success = false;
+              }
+            }
           } else {
-            throw new SolrException(ErrorCode.BAD_REQUEST, "Non-GET method not supported for setup commands");
+            throw new SolrException(ErrorCode.BAD_REQUEST, "Non-GET method not supported for verify commands");
           }          
         } else {
           // Plugins of type "collection"
@@ -488,16 +504,24 @@ public class PackageManager implements Closeable {
             if ("GET".equalsIgnoreCase(cmd.method)) {
               String response = PackageUtils.getJsonStringFromUrl(solrClient.getHttpClient(), url);
               PackageUtils.printGreen(response);
-              String actualValue = JsonPath.parse(response, PackageUtils.jsonPathConfiguration())
-                  .read(PackageUtils.resolve(cmd.condition, pkg.parameterDefaults, collectionParameterOverrides, systemParams));
-              String expectedValue = PackageUtils.resolve(cmd.expected, pkg.parameterDefaults, collectionParameterOverrides, systemParams);
-              PackageUtils.printGreen("Actual: "+actualValue+", expected: "+expectedValue);
-              if (!expectedValue.equals(actualValue)) {
+              String actualValue = null;
+              try {
+                actualValue = JsonPath.parse(response, PackageUtils.jsonPathConfiguration())
+                    .read(PackageUtils.resolve(cmd.condition, pkg.parameterDefaults, collectionParameterOverrides, systemParams));
+              } catch (PathNotFoundException ex) {
                 PackageUtils.printRed("Failed to deploy plugin: " + plugin.name);
                 success = false;
               }
+              if (actualValue != null) {
+                String expectedValue = PackageUtils.resolve(cmd.expected, pkg.parameterDefaults, collectionParameterOverrides, systemParams);
+                PackageUtils.printGreen("Actual: "+actualValue+", expected: "+expectedValue);
+                if (!expectedValue.equals(actualValue)) {
+                  PackageUtils.printRed("Failed to deploy plugin: " + plugin.name);
+                  success = false;
+                }
+              }
             } else {
-              throw new SolrException(ErrorCode.BAD_REQUEST, "Non-GET method not supported for setup commands");
+              throw new SolrException(ErrorCode.BAD_REQUEST, "Non-GET method not supported for verify commands");
             }
           }
         }
diff --git a/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java b/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java
index beabc7a..0d1fc17 100644
--- a/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java
+++ b/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java
@@ -302,8 +302,13 @@ public class RepositoryManager {
    * Install a version of the package. Also, run verify commands in case some
    * collection was using {@link PackagePluginHolder#LATEST} version of this package and got auto-updated.
    */
-  public void install(String packageName, String version) throws SolrException {
-    String latestVersion = getLastPackageRelease(packageName).version;
+  public boolean install(String packageName, String version) throws SolrException {
+    SolrPackageRelease pkg = getLastPackageRelease(packageName);
+    if (pkg == null) {
+      PackageUtils.printRed("Package " + packageName + " not found in any repository. Check list of available packages via \"solr package list-available\".");
+      return false;
+    }
+    String latestVersion = pkg.version;
 
     Map<String, String> collectionsDeployedIn = packageManager.getDeployedCollections(packageName);
     List<String> collectionsPeggedToLatest = collectionsDeployedIn.keySet().stream().
@@ -323,7 +328,11 @@ public class RepositoryManager {
       boolean res = packageManager.verify(updatedPackage, collectionsPeggedToLatest, false, new String[] {}); // Cluster level plugins don't work with peggedToLatest functionality
       PackageUtils.printGreen("Verifying version " + updatedPackage.version + 
           " on " + collectionsPeggedToLatest + ", result: " + res);
-      if (!res) throw new SolrException(ErrorCode.BAD_REQUEST, "Failed verification after deployment");
+      if (!res) {
+        PackageUtils.printRed("Failed verification after deployment");
+        return false;
+      }
     }
+    return true;
   }
 }
diff --git a/solr/core/src/java/org/apache/solr/util/PackageTool.java b/solr/core/src/java/org/apache/solr/util/PackageTool.java
index fed4f0a..b92f21e 100644
--- a/solr/core/src/java/org/apache/solr/util/PackageTool.java
+++ b/solr/core/src/java/org/apache/solr/util/PackageTool.java
@@ -138,30 +138,42 @@ public class PackageTool extends SolrCLI.ToolBase {
                 Pair<String, String> parsedVersion = parsePackageVersion(cli.getArgList().get(1).toString());
                 String packageName = parsedVersion.first();
                 String version = parsedVersion.second();
-                repositoryManager.install(packageName, version);
-                PackageUtils.printGreen(packageName + " installed.");
+                boolean success = repositoryManager.install(packageName, version);
+                if (success) {
+                  PackageUtils.printGreen(packageName + " installed.");
+                } else {
+                  PackageUtils.printRed(packageName + " installation failed.");
+                }
                 break;
               }
               case "deploy":
               {
-                Pair<String, String> parsedVersion = parsePackageVersion(cli.getArgList().get(1).toString());
-                String packageName = parsedVersion.first();
-                String version = parsedVersion.second();
-                boolean noprompt = cli.hasOption('y');
-                boolean isUpdate = cli.hasOption("update") || cli.hasOption('u');
-                String collections[] = cli.hasOption("collections")? PackageUtils.validateCollections(cli.getOptionValue("collections").split(",")): new String[] {};
-                packageManager.deploy(packageName, version, collections, cli.hasOption("cluster"), cli.getOptionValues("param"), isUpdate, noprompt);
+                if (cli.hasOption("cluster") || cli.hasOption("collections")) {
+                  Pair<String, String> parsedVersion = parsePackageVersion(cli.getArgList().get(1).toString());
+                  String packageName = parsedVersion.first();
+                  String version = parsedVersion.second();
+                  boolean noprompt = cli.hasOption('y');
+                  boolean isUpdate = cli.hasOption("update") || cli.hasOption('u');
+                  String collections[] = cli.hasOption("collections")? PackageUtils.validateCollections(cli.getOptionValue("collections").split(",")): new String[] {};
+                  packageManager.deploy(packageName, version, collections, cli.hasOption("cluster"), cli.getOptionValues("param"), isUpdate, noprompt);
+                } else {
+                  PackageUtils.printRed("Either specify -cluster to deploy cluster level plugins or -collections <list-of-collections> to deploy collection level plugins");
+                }
                 break;
               }
               case "undeploy":
               {
-                Pair<String, String> parsedVersion = parsePackageVersion(cli.getArgList().get(1).toString());
-                if (parsedVersion.second() != null) {
-                  throw new SolrException(ErrorCode.BAD_REQUEST, "Only package name expected, without a version. Actual: " + cli.getArgList().get(1));
+                if (cli.hasOption("cluster") || cli.hasOption("collections")) {
+                  Pair<String, String> parsedVersion = parsePackageVersion(cli.getArgList().get(1).toString());
+                  if (parsedVersion.second() != null) {
+                    throw new SolrException(ErrorCode.BAD_REQUEST, "Only package name expected, without a version. Actual: " + cli.getArgList().get(1));
+                  }
+                  String packageName = parsedVersion.first();
+                  String collections[] = cli.hasOption("collections")? PackageUtils.validateCollections(cli.getOptionValue("collections").split(",")): new String[] {};
+                  packageManager.undeploy(packageName, collections, cli.hasOption("cluster"));
+                } else {
+                  PackageUtils.printRed("Either specify -cluster to undeploy cluster level plugins or -collections <list-of-collections> to undeploy collection level plugins");
                 }
-                String packageName = parsedVersion.first();
-                String collections[] = cli.hasOption("collections")? PackageUtils.validateCollections(cli.getOptionValue("collections").split(",")): new String[] {};
-                packageManager.undeploy(packageName, collections, cli.hasOption("cluster"));
                 break;
               }
               case "help":
diff --git a/solr/solr-ref-guide/src/package-manager.adoc b/solr/solr-ref-guide/src/package-manager.adoc
index 75d1150..41fee10 100644
--- a/solr/solr-ref-guide/src/package-manager.adoc
+++ b/solr/solr-ref-guide/src/package-manager.adoc
@@ -89,7 +89,7 @@ $ bin/solr package install <package-name>[:<version>]
 
 === Deploy a Package
 
-Once a package has been installed, the plugins contained in it can be used in a collection.
+Once a package has been installed, the plugins contained in it can be used in a collection or at the cluster level.
 
 There are two ways to do this: either use the CLI's `deploy` command or manually.
 
@@ -102,12 +102,19 @@ If the package author states support for it, the package can be deployed with th
 $ bin/solr package deploy <package-name>:[version] -collections <collection1>[,<collection2>,...]
 ----
 
+or
+
+[source,bash]
+----
+$ bin/solr package deploy <package-name>:[version] -cluster
+----
+
 The author may want you to confirm deployment of a package via a prompt.
 If you pass `-y` to the command, confirmation can be skipped.
 
 ==== Manual Deploy
 
-It is also possible to deploy a package manually by editing a configset (e.g., `solrconfig.xml`, `managed-schema`/`schema.xml`, etc.) and reloading the collection.
+It is also possible to deploy a package's collection level plugins manually by editing a configset (e.g., `solrconfig.xml`, `managed-schema`/`schema.xml`, etc.) and reloading the collection.
 
 For example, if a package named `mypackage` contains a request handler, we would add it to a configset's `solrconfig.xml` like this:
 
@@ -118,7 +125,7 @@ For example, if a package named `mypackage` contains a request handler, we would
 
 Then use either the Collections API <<collection-management.adoc#reload,RELOAD command>> or the <<collections-core-admin.adoc#collections-core-admin,Admin UI>> to reload the collection.
 
-Next set the package version that this collection is using. If the collection is named `collection1`, the package name is `mypackage`, and the installed version is `1.0.0`, the command would look like this:
+Next, set the package version that this collection is using. If the collection is named `collection1`, the package name is `mypackage`, and the installed version is `1.0.0`, the command would look like this:
 
 [source,bash]
 ----
@@ -126,6 +133,8 @@ curl  "http://localhost:8983/api/collections/collection1/config/params" \
    -H 'Content-type:application/json' -d "{set: {PKG_VERSIONS: {mypackage: '1.0.0'}}}"
 ----
 
+For installing cluster level plugins manually, see https://issues.apache.org/jira/browse/SOLR-14404[cluster level request handlers].
+
 ==== Verify the Deployment
 After deploying, verify that the collection is using the package:
 
@@ -145,15 +154,36 @@ Next, install the new version of the package from the repositories.
 $ bin/solr package install <package-name>:<version>
 ----
 
-Once you have installed the new version, you can selectively update each of your collections. Assuming the old version is `1.0.0` of the package `mypackage`, and the new version is `2.0.0`, the command would be as follows:
+Once you have installed the new version, you can selectively update each of your collections or the cluster level plugins. Assuming the old version is `1.0.0` of the package `mypackage`, and the new version is `2.0.0`, the command would be as follows:
 
 [source,bash]
 ----
 $ bin/solr package deploy mypackage:2.0.0 --update -collections mycollection
 ----
+or
+[source,bash]
+----
+$ bin/solr package deploy mypackage:2.0.0 --update -cluster
+----
 
 You can run the `list-deployed` command to verify that this collection is using the newly added version.
 
+=== Undeploy a Package
+
+If a package supports undeploying the plugins it contains (check package manager's documentation for every package), then a previously deployed package can be undeployed as follows:
+
+[source,bash]
+----
+$ bin/solr package undeploy <package-name> -collections <collection1>[,<collection2>,...]
+----
+
+or
+
+[source,bash]
+----
+$ bin/solr package deploy <package-name> -cluster
+----
+
 == Security
 
 The `add-repo` step should only be executed using HTTPS enabled repository urls only so as to prevent against MITM attacks when Solr is fetching the public key for the repository. This `add-repo` step registers the public key of the trusted repository, and hence can only be executed using the package manager (CLI) having direct write access to the trusted store of the package store (a special location in the package store that cannot be written to using the package store APIs). Also, it  [...]
diff --git a/solr/solr-ref-guide/src/solr-plugins.adoc b/solr/solr-ref-guide/src/solr-plugins.adoc
index b3693cf..fc05cbf 100644
--- a/solr/solr-ref-guide/src/solr-plugins.adoc
+++ b/solr/solr-ref-guide/src/solr-plugins.adoc
@@ -31,6 +31,14 @@ However if you do, start by looking at the code for existing similar plugins.
 Writing your own is an advanced subject that is out of scope of the reference guide.
 One resource is the Solr Wiki documentation on plugins at https://cwiki.apache.org/confluence/display/solr/SolrPlugins[SolrPlugins], which is rather out-of-date but has some utility.
 
+== Types of Plugins ==
+
+There are essentially two types of plugins in Solr:
+
+* Collection level plugins. These are registered on individual collections, either by hand-editing the `solrconfig.xml` or schema files for the collection's configset or by using the <<config-api.adoc#config-api,config API>> or <<schema-api.adoc#schema-api,schema API>>. Examples of these are query parsers, request handlers, update request processors, value source parsers, response writers etc.
+
+* Cluster level (or Core Container level) plugins. These are plugins that are installed at a cluster level and usually every Solr node has one instance each of these plugins. Examples of these are <<authentication-and-authorization-plugins.adoc#authentication-and-authorization-plugins,authentication and authorization plugins>>, <<metrics-reporting.adoc#reporters,metrics reporters>>, https://issues.apache.org/jira/browse/SOLR-14404[cluster level request handlers] etc.
+
 == Installing Plugins ==
 
 Most plugins are built-in to Solr and there is nothing to install.
@@ -48,7 +56,7 @@ Contrib modules ship with Solr so there's no effort for them but not so for othe
 * <<package-manager.adoc#package-manager,Package Management>>:
 Describes a new and experimental system to manage packages of plugins in SolrCloud.
 It includes CLI commands, cluster-wide installation, use of plugin registries that host plugins, cryptographically signed plugins for security, and more.
-Only some plugins support this.
+Only some plugins support this as of now (support for more types of plugins coming soon).
 
 * <<adding-custom-plugins-in-solrcloud-mode.adoc#adding-custom-plugins-in-solrcloud-mode,Blob and Runtimelib>>:
 Describes a deprecated system that predates the above package management system.