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 2017/06/26 21:32:31 UTC

lucene-solr:jira/solr-10272: SOLR-10272: Using _default configset when configName is not present during CREATE collection

Repository: lucene-solr
Updated Branches:
  refs/heads/jira/solr-10272 [created] bc9422419


SOLR-10272: Using _default configset when configName is not present during CREATE collection


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

Branch: refs/heads/jira/solr-10272
Commit: bc9422419acff92cc6192a38084a4d5e849b6e07
Parents: 945bf8f
Author: Ishan Chattopadhyaya <is...@lucidworks.com>
Authored: Tue Jun 27 03:02:07 2017 +0530
Committer: Ishan Chattopadhyaya <is...@lucidworks.com>
Committed: Tue Jun 27 03:02:07 2017 +0530

----------------------------------------------------------------------
 solr/bin/solr                                   | 26 ++++----
 solr/bin/solr.cmd                               | 12 ++--
 .../apache/solr/cloud/CreateCollectionCmd.java  | 65 ++++++++++++++++----
 .../org/apache/solr/cloud/ZkController.java     | 51 ++++++++++++++-
 .../handler/admin/ConfigSetsHandlerApi.java     |  2 +
 .../apache/solr/servlet/SolrDispatchFilter.java |  6 +-
 .../src/java/org/apache/solr/util/SolrCLI.java  | 24 +++++---
 .../solr/configsets/_default/conf/schema.xml    | 44 +++++++++++++
 .../configsets/_default/conf/solrconfig.xml     | 32 ++++++++++
 .../solr/cloud/BaseCdcrDistributedZkTest.java   |  4 +-
 .../solr/cloud/BasicDistributedZk2Test.java     |  2 +-
 .../solr/cloud/BasicDistributedZkTest.java      | 10 +--
 .../solr/cloud/ClusterStateUpdateTest.java      |  2 +-
 .../solr/cloud/CollectionsAPISolrJTest.java     | 19 ++++++
 .../solr/cloud/ShardRoutingCustomTest.java      |  2 +-
 .../org/apache/solr/cloud/ShardSplitTest.java   |  2 +-
 .../apache/solr/cloud/TestConfigSetsAPI.java    |  6 +-
 .../org/apache/solr/cloud/TestPullReplica.java  |  8 +--
 .../cloud/TestRandomRequestDistribution.java    |  6 +-
 .../cloud/TestSolrCloudWithKerberosAlt.java     |  2 +-
 .../org/apache/solr/cloud/TestTlogReplica.java  |  8 +--
 .../solr/cloud/UnloadDistributedZkTest.java     |  4 +-
 .../autoscaling/AutoScalingHandlerTest.java     |  5 +-
 .../solr/cloud/autoscaling/TestPolicyCloud.java |  6 +-
 .../handler/ThrowErrorOnInitRequestHandler.java |  4 ++
 .../cloud/AbstractFullDistribZkTestBase.java    | 10 +--
 26 files changed, 283 insertions(+), 79 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/bin/solr
----------------------------------------------------------------------
diff --git a/solr/bin/solr b/solr/bin/solr
index fff11ed..14f24eb 100755
--- a/solr/bin/solr
+++ b/solr/bin/solr
@@ -932,14 +932,12 @@ if [[ "$SCRIPT_CMD" == "create" || "$SCRIPT_CMD" == "create_core" || "$SCRIPT_CM
     done
   fi
 
-  if [ -z "$CREATE_CONFDIR" ]; then
-    CREATE_CONFDIR='_default'
-  fi
-
-  # validate the confdir arg
-  if [[ ! -d "$SOLR_TIP/server/solr/configsets/$CREATE_CONFDIR" && ! -d "$CREATE_CONFDIR" ]]; then
-    echo -e "\nSpecified configuration directory $CREATE_CONFDIR not found!\n"
-    exit 1
+  # validate the confdir arg (if provided)
+  if ! [ -z "$CREATE_CONFDIR" ]; then
+    if [[ ! -d "$SOLR_TIP/server/solr/configsets/$CREATE_CONFDIR" && ! -d "$CREATE_CONFDIR" ]]; then
+      echo -e "\nSpecified configuration directory $CREATE_CONFDIR not found!\n"
+      exit 1
+    fi
   fi
 
   if [ -z "$CREATE_NAME" ]; then
@@ -948,11 +946,6 @@ if [[ "$SCRIPT_CMD" == "create" || "$SCRIPT_CMD" == "create_core" || "$SCRIPT_CM
     exit 1
   fi
 
-  # If not defined, use the collection name for the name of the configuration in Zookeeper
-  if [ -z "$CREATE_CONFNAME" ]; then
-    CREATE_CONFNAME="$CREATE_NAME"
-  fi
-
   if [ -z "$CREATE_PORT" ]; then
     for ID in `ps auxww | grep java | grep start\.jar | awk '{print $2}' | sort -r`
       do
@@ -1661,6 +1654,11 @@ else
   fi
 fi
 
+# Set the default configset dir to be bootstrapped as _default
+if [ -z "$DEFAULT_CONFDIR" ]; then
+  DEFAULT_CONFDIR="$SOLR_SERVER_DIR/solr/configsets/_default/conf"
+fi
+
 # This is quite hacky, but examples rely on a different log4j.properties
 # so that we can write logs for examples to $SOLR_HOME/../logs
 if [ -z "$SOLR_LOGS_DIR" ]; then
@@ -1911,7 +1909,7 @@ function launch_solr() {
     "-Djetty.port=$SOLR_PORT" "-DSTOP.PORT=$stop_port" "-DSTOP.KEY=$STOP_KEY" \
     "${SOLR_HOST_ARG[@]}" "-Duser.timezone=$SOLR_TIMEZONE" \
     "-Djetty.home=$SOLR_SERVER_DIR" "-Dsolr.solr.home=$SOLR_HOME" "-Dsolr.data.home=$SOLR_DATA_HOME" "-Dsolr.install.dir=$SOLR_TIP" \
-    "${LOG4J_CONFIG[@]}" "${SOLR_OPTS[@]}")
+    "-Dsolr.default.confdir=$DEFAULT_CONFDIR" "${LOG4J_CONFIG[@]}" "${SOLR_OPTS[@]}")
 
   if [ "$SOLR_MODE" == "solrcloud" ]; then
     IN_CLOUD_MODE=" in SolrCloud mode"

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/bin/solr.cmd
----------------------------------------------------------------------
diff --git a/solr/bin/solr.cmd b/solr/bin/solr.cmd
index 0c05baa..99bd815 100644
--- a/solr/bin/solr.cmd
+++ b/solr/bin/solr.cmd
@@ -1212,13 +1212,15 @@ IF "%JAVA_VENDOR%" == "IBM J9" (
   set GCLOG_OPT="-Xloggc:!SOLR_LOGS_DIR!\solr_gc.log" -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=9 -XX:GCLogFileSize=20M
 )
 
+IF "%DEFAULT_CONFDIR%"=="" set "DEFAULT_CONFDIR=%SOLR_SERVER_DIR%\solr\configsets\_default\conf"
+
 IF "%FG%"=="1" (
   REM run solr in the foreground
   title "Solr-%SOLR_PORT%"
   echo %SOLR_PORT%>"%SOLR_TIP%"\bin\solr-%SOLR_PORT%.port
   "%JAVA%" %SERVEROPT% %SOLR_JAVA_MEM% %START_OPTS% %GCLOG_OPT% ^
     -Dlog4j.configuration="%LOG4J_CONFIG%" -DSTOP.PORT=!STOP_PORT! -DSTOP.KEY=%STOP_KEY% ^
-    -Dsolr.solr.home="%SOLR_HOME%" -Dsolr.install.dir="%SOLR_TIP%" ^
+    -Dsolr.solr.home="%SOLR_HOME%" -Dsolr.install.dir="%SOLR_TIP%" -Dsolr.default.confdir="%DEFAULT_CONFDIR%" ^
     -Djetty.host=%SOLR_JETTY_HOST% -Djetty.port=%SOLR_PORT% -Djetty.home="%SOLR_SERVER_DIR%" ^
     -Djava.io.tmpdir="%SOLR_SERVER_DIR%\tmp" -jar start.jar "%SOLR_JETTY_CONFIG%" "%SOLR_JETTY_ADDL_CONFIG%"
 ) ELSE (
@@ -1226,13 +1228,13 @@ IF "%FG%"=="1" (
     "%JAVA%" %SERVEROPT% %SOLR_JAVA_MEM% %START_OPTS% %GCLOG_OPT% ^
     -Dlog4j.configuration="%LOG4J_CONFIG%" -DSTOP.PORT=!STOP_PORT! -DSTOP.KEY=%STOP_KEY% ^
     -Dsolr.log.muteconsole ^
-    -Dsolr.solr.home="%SOLR_HOME%" -Dsolr.install.dir="%SOLR_TIP%" ^
+    -Dsolr.solr.home="%SOLR_HOME%" -Dsolr.install.dir="%SOLR_TIP%" -Dsolr.default.confdir="%DEFAULT_CONFDIR%" ^
     -Djetty.host=%SOLR_JETTY_HOST% -Djetty.port=%SOLR_PORT% -Djetty.home="%SOLR_SERVER_DIR%" ^
     -Djava.io.tmpdir="%SOLR_SERVER_DIR%\tmp" -jar start.jar "%SOLR_JETTY_CONFIG%" "%SOLR_JETTY_ADDL_CONFIG%" > "!SOLR_LOGS_DIR!\solr-%SOLR_PORT%-console.log"
   echo %SOLR_PORT%>"%SOLR_TIP%"\bin\solr-%SOLR_PORT%.port
 
   REM now wait to see Solr come online ...
-  "%JAVA%" %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% -Dsolr.install.dir="%SOLR_TIP%" -Dsolr.default.confdir="%DEFAULT_CONFDIR%"^
     -Dlog4j.configuration="file:%DEFAULT_SERVER_DIR%\scripts\cloud-scripts\log4j.properties" ^
     -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^
     org.apache.solr.util.SolrCLI status -maxWaitSecs 30 -solr !SOLR_URL_SCHEME!://%SOLR_TOOL_HOST%:%SOLR_PORT%/solr
@@ -1402,10 +1404,8 @@ IF "!CREATE_NAME!"=="" (
   set "SCRIPT_ERROR=Name (-c) is a required parameter for %SCRIPT_CMD%"
   goto invalid_cmd_line
 )
-IF "!CREATE_CONFDIR!"=="" set CREATE_CONFDIR=_default
 IF "!CREATE_NUM_SHARDS!"=="" set CREATE_NUM_SHARDS=1
 IF "!CREATE_REPFACT!"=="" set CREATE_REPFACT=1
-IF "!CREATE_CONFNAME!"=="" set CREATE_CONFNAME=!CREATE_NAME!
 
 REM Find a port that Solr is running on
 if "!CREATE_PORT!"=="" (
@@ -1431,7 +1431,7 @@ if "%SCRIPT_CMD%"=="create_core" (
     org.apache.solr.util.SolrCLI create_core -name !CREATE_NAME! -solrUrl !SOLR_URL_SCHEME!://%SOLR_TOOL_HOST%:!CREATE_PORT!/solr ^
     -confdir !CREATE_CONFDIR! -configsetsDir "%SOLR_TIP%\server\solr\configsets"
 ) else (
-  "%JAVA%" %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% -Dsolr.install.dir="%SOLR_TIP%" -Dsolr.default.confdir="%DEFAULT_CONFDIR%"^
     -Dlog4j.configuration="file:%DEFAULT_SERVER_DIR%\scripts\cloud-scripts\log4j.properties" ^
     -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^
     org.apache.solr.util.SolrCLI create -name !CREATE_NAME! -shards !CREATE_NUM_SHARDS! -replicationFactor !CREATE_REPFACT! ^

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/java/org/apache/solr/cloud/CreateCollectionCmd.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/CreateCollectionCmd.java b/solr/core/src/java/org/apache/solr/cloud/CreateCollectionCmd.java
index d6a82a7..0c87658 100644
--- a/solr/core/src/java/org/apache/solr/cloud/CreateCollectionCmd.java
+++ b/solr/core/src/java/org/apache/solr/cloud/CreateCollectionCmd.java
@@ -22,6 +22,7 @@ import java.lang.invoke.MethodHandles;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -47,6 +48,7 @@ import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
 import org.apache.solr.common.util.Utils;
+import org.apache.solr.handler.admin.ConfigSetsHandlerApi;
 import org.apache.solr.handler.component.ShardHandler;
 import org.apache.solr.handler.component.ShardRequest;
 import org.apache.solr.util.TimeOut;
@@ -296,20 +298,49 @@ public class CreateCollectionCmd implements Cmd {
       List<String> configNames = null;
       try {
         configNames = ocmh.zkStateReader.getZkClient().getChildren(ZkConfigManager.CONFIGS_ZKNODE, null, true);
-        if (configNames != null && configNames.size() == 1) {
+        if (configNames.contains(ConfigSetsHandlerApi.DEFAULT_CONFIGSET_NAME)) {
+          if (!".system".equals(coll)) {
+            copyDefaultConfigSetTo(configNames, coll);
+          }
+          return coll;
+        } else if (configNames != null && configNames.size() == 1) {
           configName = configNames.get(0);
           // no config set named, but there is only 1 - use it
           log.info("Only one config set found in zk - using it:" + configName);
-        } else if (configNames.contains(coll)) {
-          configName = coll;
         }
       } catch (KeeperException.NoNodeException e) {
 
       }
     }
-    return configName;
+    return "".equals(configName)? null: configName;
   }
   
+  /**
+   * Copies the _default configset to the specified configset name (overwrites if pre-existing)
+   */
+  private void copyDefaultConfigSetTo(List<String> configNames, String targetConfig) {
+    ZkConfigManager configManager = new ZkConfigManager(ocmh.zkStateReader.getZkClient());
+
+    // if a configset named coll exists, delete the configset so that _default can be copied over
+    if (configNames.contains(targetConfig)) {
+      log.info("There exists a configset by the same name as the collection we're trying to create: " + targetConfig +
+          ", deleting it so that we can copy the _default configs over and create the collection.");
+      try {
+        configManager.deleteConfigDir(targetConfig);
+      } catch (Exception e) {
+        throw new SolrException(ErrorCode.INVALID_STATE, "Error while deleting configset: " + targetConfig, e);
+      }
+    } else {
+      log.info("Only _default config set found, using it.");
+    }
+    // Copy _default into targetConfig
+    try {
+      configManager.copyConfigDir(ConfigSetsHandlerApi.DEFAULT_CONFIGSET_NAME, targetConfig, new HashSet<>());
+    } catch (Exception e) {
+      throw new SolrException(ErrorCode.INVALID_STATE, "Error while copying _default to " + targetConfig, e);
+    }
+  }
+
   public static void createCollectionZkNode(SolrZkClient zkClient, String collection, Map<String,String> params) {
     log.debug("Check for collection zkNode:" + collection);
     String collectionPath = ZkStateReader.COLLECTIONS_ZKNODE + "/" + collection;
@@ -384,14 +415,14 @@ public class CreateCollectionCmd implements Cmd {
   }
   
   private static void getConfName(SolrZkClient zkClient, String collection, String collectionPath, Map<String,Object> collectionProps) throws KeeperException,
-      InterruptedException {
+  InterruptedException {
     // check for configName
     log.debug("Looking for collection configName");
     if (collectionProps.containsKey("configName")) {
       log.info("configName was passed as a param {}", collectionProps.get("configName"));
       return;
     }
-    
+
     List<String> configNames = null;
     int retry = 1;
     int retryLimt = 6;
@@ -403,26 +434,34 @@ public class CreateCollectionCmd implements Cmd {
         }
       }
 
-      // if there is only one conf, use that
       try {
         configNames = zkClient.getChildren(ZkConfigManager.CONFIGS_ZKNODE, null,
             true);
       } catch (NoNodeException e) {
         // just keep trying
       }
-      if (configNames != null && configNames.size() == 1) {
-        // no config set named, but there is only 1 - use it
-        log.info("Only one config set found in zk - using it:" + configNames.get(0));
-        collectionProps.put(ZkController.CONFIGNAME_PROP, configNames.get(0));
-        break;
-      }
 
+      // check if there's a config set with the same name as the collection
       if (configNames != null && configNames.contains(collection)) {
         log.info(
             "Could not find explicit collection configName, but found config name matching collection name - using that set.");
         collectionProps.put(ZkController.CONFIGNAME_PROP, collection);
         break;
       }
+      // if _default exists, use that
+      if (configNames != null && configNames.contains(ConfigSetsHandlerApi.DEFAULT_CONFIGSET_NAME)) {
+        log.info(
+            "Could not find explicit collection configName, but found _default config set - using that set.");
+        collectionProps.put(ZkController.CONFIGNAME_PROP, ConfigSetsHandlerApi.DEFAULT_CONFIGSET_NAME);
+        break;
+      }
+      // if there is only one conf, use that
+      if (configNames != null && configNames.size() == 1) {
+        // no config set named, but there is only 1 - use it
+        log.info("Only one config set found in zk - using it:" + configNames.get(0));
+        collectionProps.put(ZkController.CONFIGNAME_PROP, configNames.get(0));
+        break;
+      }
 
       log.info("Could not find collection configName - pausing for 3 seconds and trying again - try: " + retry);
       Thread.sleep(3000);

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/java/org/apache/solr/cloud/ZkController.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/ZkController.java b/solr/core/src/java/org/apache/solr/cloud/ZkController.java
index b859599..391f29c 100644
--- a/solr/core/src/java/org/apache/solr/cloud/ZkController.java
+++ b/solr/core/src/java/org/apache/solr/cloud/ZkController.java
@@ -16,15 +16,19 @@
  */
 package org.apache.solr.cloud;
 
+import java.io.File;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.lang.invoke.MethodHandles;
 import java.net.InetAddress;
 import java.net.NetworkInterface;
+import java.net.URISyntaxException;
+import java.net.URL;
 import java.net.URLEncoder;
 import java.net.UnknownHostException;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -70,6 +74,7 @@ import org.apache.solr.common.cloud.ZkCmdExecutor;
 import org.apache.solr.common.cloud.ZkConfigManager;
 import org.apache.solr.common.cloud.ZkCoreNodeProps;
 import org.apache.solr.common.cloud.ZkCredentialsProvider;
+import org.apache.solr.common.cloud.ZkMaintenanceUtils;
 import org.apache.solr.common.cloud.ZkNodeProps;
 import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.cloud.ZooKeeperException;
@@ -87,7 +92,9 @@ import org.apache.solr.core.CoreContainer;
 import org.apache.solr.core.CoreDescriptor;
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.core.SolrCoreInitializationException;
+import org.apache.solr.handler.admin.ConfigSetsHandlerApi;
 import org.apache.solr.logging.MDCLoggingContext;
+import org.apache.solr.servlet.SolrDispatchFilter;
 import org.apache.solr.update.UpdateLog;
 import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.KeeperException;
@@ -660,7 +667,7 @@ public class ZkController {
    * @throws KeeperException      if there is a Zookeeper error
    * @throws InterruptedException on interrupt
    */
-  public static void createClusterZkNodes(SolrZkClient zkClient) throws KeeperException, InterruptedException {
+  public static void createClusterZkNodes(SolrZkClient zkClient) throws KeeperException, InterruptedException, IOException {
     ZkCmdExecutor cmdExecutor = new ZkCmdExecutor(zkClient.getZkClientTimeout());
     cmdExecutor.ensureExists(ZkStateReader.LIVE_NODES_ZKNODE, zkClient);
     cmdExecutor.ensureExists(ZkStateReader.COLLECTIONS_ZKNODE, zkClient);
@@ -669,6 +676,48 @@ public class ZkController {
     cmdExecutor.ensureExists(ZkStateReader.CLUSTER_STATE, emptyJson, CreateMode.PERSISTENT, zkClient);
     cmdExecutor.ensureExists(ZkStateReader.SOLR_SECURITY_CONF_PATH, emptyJson, CreateMode.PERSISTENT, zkClient);
     cmdExecutor.ensureExists(ZkStateReader.SOLR_AUTOSCALING_CONF_PATH, emptyJson, CreateMode.PERSISTENT, zkClient);
+   bootstrapDefaultConfigSet(zkClient);
+  }
+
+  private static void bootstrapDefaultConfigSet(SolrZkClient zkClient) throws KeeperException, InterruptedException, IOException {
+    if (zkClient.exists("/configs/_default", true) == false) {
+      String configDirPath = getDefaultConfigDirPath();
+      if (configDirPath == null) {
+        log.warn("The _default configset could not be uploaded. Please provide 'solr.default.confdir' parameter that points to a configset" +
+            " intended to be the default. Current 'solr.default.confdir' value: {}", System.getProperty(SolrDispatchFilter.SOLR_DEFAULT_CONFDIR_ATTRIBUTE));
+      } else {
+        ZkMaintenanceUtils.upConfig(zkClient, Paths.get(configDirPath), ConfigSetsHandlerApi.DEFAULT_CONFIGSET_NAME);
+      }
+    }
+  }
+
+  /**
+   * Gets the absolute filesystem path of the _default configset to bootstrap from.
+   * First tries the sysprop "solr.default.confdir". If not found, tries to find
+   * the _default dir relative to the sysprop "solr.install.dir".
+   * If that fails as well, tries to get the _default from the
+   * classpath. Returns null if not found anywhere.
+   */
+  private static String getDefaultConfigDirPath() {
+    String configDirPath = null;
+    String serverSubPath = "solr" + File.separator +
+        "configsets" + File.separator + "_default" +
+        File.separator + "conf";
+    String subPath = File.separator + "server" + File.separator + serverSubPath;
+    if (System.getProperty(SolrDispatchFilter.SOLR_DEFAULT_CONFDIR_ATTRIBUTE) != null && new File(System.getProperty(SolrDispatchFilter.SOLR_DEFAULT_CONFDIR_ATTRIBUTE)).exists()) {
+      configDirPath = new File(System.getProperty(SolrDispatchFilter.SOLR_DEFAULT_CONFDIR_ATTRIBUTE)).getAbsolutePath();
+    } else if (System.getProperty(SolrDispatchFilter.SOLR_INSTALL_DIR_ATTRIBUTE) != null &&
+        new File(System.getProperty(SolrDispatchFilter.SOLR_INSTALL_DIR_ATTRIBUTE) + subPath).exists()) {
+      configDirPath = new File(System.getProperty(SolrDispatchFilter.SOLR_INSTALL_DIR_ATTRIBUTE) + subPath).getAbsolutePath();
+    } else { // find "_default" in the classpath. This one is used for tests
+      URL classpathUrl = Thread.currentThread().getContextClassLoader().getResource(serverSubPath);
+      try {
+        if (classpathUrl != null && new File(classpathUrl.toURI()).exists()) {
+          configDirPath = new File(classpathUrl.toURI()).getAbsolutePath();
+        }
+      } catch (URISyntaxException ex) {}
+    }
+    return configDirPath;
   }
 
   private void init(CurrentCoreDescriptorProvider registerOnReconnect) {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandlerApi.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandlerApi.java b/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandlerApi.java
index a4138a2..2028f67 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandlerApi.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/ConfigSetsHandlerApi.java
@@ -31,6 +31,8 @@ import org.apache.solr.response.SolrQueryResponse;
 
 public class ConfigSetsHandlerApi extends BaseHandlerApiSupport {
 
+  final public static String DEFAULT_CONFIGSET_NAME = "_default";
+
   final ConfigSetsHandler configSetHandler;
   static Collection<ApiCommand> apiCommands = createMapping();
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
----------------------------------------------------------------------
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 cdf3ce8..1b5c664 100644
--- a/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
+++ b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
@@ -133,6 +133,10 @@ public class SolrDispatchFilter extends BaseSolrFilter {
 
   public static final String SOLRHOME_ATTRIBUTE = "solr.solr.home";
 
+  public static final String SOLR_INSTALL_DIR_ATTRIBUTE = "solr.install.dir";
+
+  public static final String SOLR_DEFAULT_CONFDIR_ATTRIBUTE = "solr.default.confdir";
+
   public static final String SOLR_LOG_MUTECONSOLE = "solr.log.muteconsole";
 
   public static final String SOLR_LOG_LEVEL = "solr.log.level";
@@ -223,7 +227,7 @@ public class SolrDispatchFilter extends BaseSolrFilter {
   private void logWelcomeBanner() {
     log.info(" ___      _       Welcome to Apache Solr™ version {}", solrVersion());
     log.info("/ __| ___| |_ _   Starting in {} mode on port {}", isCloudMode() ? "cloud" : "standalone", getSolrPort());
-    log.info("\\__ \\/ _ \\ | '_|  Install dir: {}", System.getProperty("solr.install.dir"));
+    log.info("\\__ \\/ _ \\ | '_|  Install dir: {}, Default config dir: {}", System.getProperty(SOLR_INSTALL_DIR_ATTRIBUTE), System.getProperty(SOLR_DEFAULT_CONFDIR_ATTRIBUTE));
     log.info("|___/\\___/_|_|    Start time: {}", Instant.now().toString());
   }
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/java/org/apache/solr/util/SolrCLI.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/util/SolrCLI.java b/solr/core/src/java/org/apache/solr/util/SolrCLI.java
index 668dd4f..30c5681 100644
--- a/solr/core/src/java/org/apache/solr/util/SolrCLI.java
+++ b/solr/core/src/java/org/apache/solr/util/SolrCLI.java
@@ -1503,17 +1503,23 @@ public class SolrCLI {
         maxShardsPerNode = ((numShards*replicationFactor)+numNodes-1)/numNodes;
       }
 
-      String confname = cli.getOptionValue("confname", collectionName);
-      boolean configExistsInZk =
+      String confname = cli.getOptionValue("confname");
+      String confdir = cli.getOptionValue("confdir");
+      String configsetsDir = cli.getOptionValue("configsetsDir");
+
+      boolean configExistsInZk = confname != null && !"".equals(confname.trim()) &&
           cloudSolrClient.getZkStateReader().getZkClient().exists("/configs/" + confname, true);
 
       if (".system".equals(collectionName)) {
         //do nothing
       } else if (configExistsInZk) {
         echo("Re-using existing configuration directory "+confname);
-      } else {
-        Path confPath = ZkConfigManager.getConfigsetPath(cli.getOptionValue("confdir", DEFAULT_CONFIG_SET),
-            cli.getOptionValue("configsetsDir"));
+      } else if (confdir != null && !"".equals(confdir.trim())){
+        if (confname == null || "".equals(confname.trim())) {
+          confname = collectionName;
+        }
+        Path confPath = ZkConfigManager.getConfigsetPath(confdir,
+            configsetsDir);
 
         echo("Uploading " + confPath.toAbsolutePath().toString() +
             " for config " + confname + " to ZooKeeper at " + cloudSolrClient.getZkHost());
@@ -1531,13 +1537,15 @@ public class SolrCLI {
       // doesn't seem to exist ... try to create
       String createCollectionUrl =
           String.format(Locale.ROOT,
-              "%s/admin/collections?action=CREATE&name=%s&numShards=%d&replicationFactor=%d&maxShardsPerNode=%d&collection.configName=%s",
+              "%s/admin/collections?action=CREATE&name=%s&numShards=%d&replicationFactor=%d&maxShardsPerNode=%d",
               baseUrl,
               collectionName,
               numShards,
               replicationFactor,
-              maxShardsPerNode,
-              confname);
+              maxShardsPerNode);
+      if (confname != null && !"".equals(confname.trim())) {
+        createCollectionUrl = createCollectionUrl + String.format(Locale.ROOT, "&collection.configName=%s", confname);
+      }
 
       echo("\nCreating new collection '"+collectionName+"' using command:\n"+createCollectionUrl+"\n");
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/test-files/solr/configsets/_default/conf/schema.xml
----------------------------------------------------------------------
diff --git a/solr/core/src/test-files/solr/configsets/_default/conf/schema.xml b/solr/core/src/test-files/solr/configsets/_default/conf/schema.xml
new file mode 100644
index 0000000..90a8b71
--- /dev/null
+++ b/solr/core/src/test-files/solr/configsets/_default/conf/schema.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ 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.
+-->
+
+<schema name="default-config" version="1.6">
+    <field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
+    <field name="_version_" type="long" indexed="false" stored="false"/>
+    <field name="_root_" type="string" indexed="true" stored="false" docValues="false" />
+    <field name="_text_" type="text_general" indexed="true" stored="false" multiValued="true"/>
+
+    <fieldType name="string" class="solr.StrField" sortMissingLast="true" docValues="true" />
+    <fieldType name="long" class="solr.TrieLongField" docValues="true" precisionStep="0" positionIncrementGap="0"/>
+    <fieldType name="text_general" class="solr.TextField" positionIncrementGap="100" multiValued="true">
+      <analyzer type="index">
+        <tokenizer class="solr.StandardTokenizerFactory"/>
+        <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" />
+        <!-- in this example, we will only use synonyms at query time
+        <filter class="solr.SynonymGraphFilterFactory" synonyms="index_synonyms.txt" ignoreCase="true" expand="false"/>
+        <filter class="solr.FlattenGraphFilterFactory"/>
+        -->
+        <filter class="solr.LowerCaseFilterFactory"/>
+      </analyzer>
+      <analyzer type="query">
+        <tokenizer class="solr.StandardTokenizerFactory"/>
+        <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" />
+        <filter class="solr.SynonymGraphFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
+        <filter class="solr.LowerCaseFilterFactory"/>
+      </analyzer>
+    </fieldType>
+</schema>

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/test-files/solr/configsets/_default/conf/solrconfig.xml
----------------------------------------------------------------------
diff --git a/solr/core/src/test-files/solr/configsets/_default/conf/solrconfig.xml b/solr/core/src/test-files/solr/configsets/_default/conf/solrconfig.xml
new file mode 100644
index 0000000..acf95ba
--- /dev/null
+++ b/solr/core/src/test-files/solr/configsets/_default/conf/solrconfig.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" ?>
+
+<!--
+ 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.
+-->
+
+<config>
+
+  <directoryFactory name="DirectoryFactory" class="${solr.directoryFactory:solr.RAMDirectoryFactory}"/>
+
+  <luceneMatchVersion>${tests.luceneMatchVersion:LATEST}</luceneMatchVersion>
+
+  <requestHandler name="my_error_handler" class="solr.ThrowErrorOnInitRequestHandler">
+    <str name="error">This is the _default configset, which is designed to throw error upon collection creation.</str>
+  </requestHandler>
+
+  <schemaFactory class="ClassicIndexSchemaFactory"/>
+
+</config>

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/test/org/apache/solr/cloud/BaseCdcrDistributedZkTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/BaseCdcrDistributedZkTest.java b/solr/core/src/test/org/apache/solr/cloud/BaseCdcrDistributedZkTest.java
index ef2e224..8ce346b 100644
--- a/solr/core/src/test/org/apache/solr/cloud/BaseCdcrDistributedZkTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/BaseCdcrDistributedZkTest.java
@@ -432,7 +432,7 @@ public class BaseCdcrDistributedZkTest extends AbstractDistribZkTestBase {
             REPLICATION_FACTOR, replicationFactor,
             CREATE_NODE_SET, createNodeSetStr,
             MAX_SHARDS_PER_NODE, maxShardsPerNode),
-        client, null);
+        client, "conf1");
   }
 
   private CollectionAdminResponse createCollection(Map<String, List<Integer>> collectionInfos, String collectionName,
@@ -588,7 +588,7 @@ public class BaseCdcrDistributedZkTest extends AbstractDistribZkTestBase {
 
     try (SolrClient client = createCloudClient(temporaryCollection)) {
       assertEquals(0, CollectionAdminRequest
-          .createCollection(temporaryCollection, shardCount, 1)
+          .createCollection(temporaryCollection, "conf1", shardCount, 1)
           .setCreateNodeSet("")
           .process(client).getStatus());
       for (int i = 0; i < jettys.size(); i++) {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZk2Test.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZk2Test.java b/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZk2Test.java
index 838ebb5..5bb938d 100644
--- a/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZk2Test.java
+++ b/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZk2Test.java
@@ -157,7 +157,7 @@ public class BasicDistributedZk2Test extends AbstractFullDistribZkTestBase {
   
   private void testNodeWithoutCollectionForwarding() throws Exception {
     assertEquals(0, CollectionAdminRequest
-        .createCollection(ONE_NODE_COLLECTION, 1, 1)
+        .createCollection(ONE_NODE_COLLECTION, "conf1", 1, 1)
         .setCreateNodeSet("")
         .process(cloudClient).getStatus());
     assertTrue(CollectionAdminRequest

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java b/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java
index a85165c..f1c33d8 100644
--- a/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java
@@ -576,7 +576,7 @@ public class BasicDistributedZkTest extends AbstractFullDistribZkTestBase {
   protected void createCores(final HttpSolrClient client,
       ThreadPoolExecutor executor, final String collection, final int numShards, int cnt) {
     try {
-      assertEquals(0, CollectionAdminRequest.createCollection(collection, numShards, 1)
+      assertEquals(0, CollectionAdminRequest.createCollection(collection, "conf1", numShards, 1)
           .setCreateNodeSet("")
           .process(client).getStatus());
     } catch (SolrServerException | IOException e) {
@@ -614,6 +614,7 @@ public class BasicDistributedZkTest extends AbstractFullDistribZkTestBase {
     return url2;
   }
 
+  @Override
   protected CollectionAdminResponse createCollection(Map<String, List<Integer>> collectionInfos,
                                                      String collectionName, int numShards, int numReplicas, int maxShardsPerNode, SolrClient client, String createNodeSetStr) throws SolrServerException, IOException {
     // TODO: Use CollectionAdminRequest for this test
@@ -633,6 +634,7 @@ public class BasicDistributedZkTest extends AbstractFullDistribZkTestBase {
       collectionInfos.put(collectionName, list);
     }
     params.set("name", collectionName);
+    params.set("collection.configName", "conf1");
     SolrRequest request = new QueryRequest(params);
     request.setPath("/admin/collections");
 
@@ -795,7 +797,7 @@ public class BasicDistributedZkTest extends AbstractFullDistribZkTestBase {
 
   private void testANewCollectionInOneInstanceWithManualShardAssignement() throws Exception {
     log.info("### STARTING testANewCollectionInOneInstanceWithManualShardAssignement");
-    assertEquals(0, CollectionAdminRequest.createCollection(oneInstanceCollection2, 2, 2)
+    assertEquals(0, CollectionAdminRequest.createCollection(oneInstanceCollection2, "conf1", 2, 2)
         .setCreateNodeSet("")
         .setMaxShardsPerNode(4)
         .process(cloudClient).getStatus());
@@ -921,7 +923,7 @@ public class BasicDistributedZkTest extends AbstractFullDistribZkTestBase {
 
   private void testANewCollectionInOneInstance() throws Exception {
     log.info("### STARTING testANewCollectionInOneInstance");
-    CollectionAdminResponse response = CollectionAdminRequest.createCollection(oneInstanceCollection, 2, 2)
+    CollectionAdminResponse response = CollectionAdminRequest.createCollection(oneInstanceCollection, "conf1", 2, 2)
         .setCreateNodeSet(jettys.get(0).getNodeName())
         .setMaxShardsPerNode(4)
         .process(cloudClient);
@@ -1087,7 +1089,7 @@ public class BasicDistributedZkTest extends AbstractFullDistribZkTestBase {
   private void createNewCollection(final String collection) throws InterruptedException {
     try {
       assertEquals(0, CollectionAdminRequest
-          .createCollection(collection, 2, 1)
+          .createCollection(collection, "conf1", 2, 1)
           .setCreateNodeSet("")
           .process(cloudClient).getStatus());
     } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/test/org/apache/solr/cloud/ClusterStateUpdateTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/ClusterStateUpdateTest.java b/solr/core/src/test/org/apache/solr/cloud/ClusterStateUpdateTest.java
index 763c3fc..0c331ae 100644
--- a/solr/core/src/test/org/apache/solr/cloud/ClusterStateUpdateTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/ClusterStateUpdateTest.java
@@ -61,7 +61,7 @@ public class ClusterStateUpdateTest extends SolrCloudTestCase  {
   public void testCoreRegistration() throws Exception {
     System.setProperty("solrcloud.update.delay", "1");
 
-    assertEquals(0, CollectionAdminRequest.createCollection("testcore", 1,1)
+    assertEquals(0, CollectionAdminRequest.createCollection("testcore", "conf", 1, 1)
         .setCreateNodeSet(cluster.getJettySolrRunner(0).getNodeName())
         .process(cluster.getSolrClient()).getStatus());
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/test/org/apache/solr/cloud/CollectionsAPISolrJTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/CollectionsAPISolrJTest.java b/solr/core/src/test/org/apache/solr/cloud/CollectionsAPISolrJTest.java
index d7a43c8..9c414cc 100644
--- a/solr/core/src/test/org/apache/solr/cloud/CollectionsAPISolrJTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/CollectionsAPISolrJTest.java
@@ -55,6 +55,25 @@ public class CollectionsAPISolrJTest extends SolrCloudTestCase {
         .configure();
   }
 
+  /**
+   * When a config name is not specified during collection creation, the _default should
+   * be used.
+   */
+  @Test
+  public void testCreateWithDefaultConfigSet() throws Exception {
+    String collectionName = "solrj_default_configset";
+    CollectionAdminResponse response = CollectionAdminRequest.createCollection(collectionName, 2, 2) // no configset specified
+        .process(cluster.getSolrClient());
+
+    // The _default configset (for the tests) is designed to error out upon collection creation,
+    // so we just ensure that the correct error message was obtained.
+    assertFalse(response.isSuccess());
+    System.out.println("Errors are: "+response.getErrorMessages());
+    assertTrue(response.getErrorMessages() != null && response.getErrorMessages().size() > 0);
+    assertTrue(response.getErrorMessages().getVal(0).contains("This is the _default configset, which is designed"
+        + " to throw error upon collection creation."));
+  }
+
   @Test
   public void testCreateAndDeleteCollection() throws Exception {
     String collectionName = "solrj_test";

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/test/org/apache/solr/cloud/ShardRoutingCustomTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/ShardRoutingCustomTest.java b/solr/core/src/test/org/apache/solr/cloud/ShardRoutingCustomTest.java
index 78e4128..d7cd4a8 100644
--- a/solr/core/src/test/org/apache/solr/cloud/ShardRoutingCustomTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/ShardRoutingCustomTest.java
@@ -63,7 +63,7 @@ public class ShardRoutingCustomTest extends AbstractFullDistribZkTestBase {
     setupJettySolrHome(jettyDir);
     JettySolrRunner j = createJetty(jettyDir, createTempDir().toFile().getAbsolutePath(), "shardA", "solrconfig.xml", null);
     assertEquals(0, CollectionAdminRequest
-        .createCollection(DEFAULT_COLLECTION, 1, 1)
+        .createCollection(DEFAULT_COLLECTION, "conf1", 1, 1)
         .setStateFormat(Integer.parseInt(getStateFormat()))
         .setCreateNodeSet("")
         .process(cloudClient).getStatus());

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/test/org/apache/solr/cloud/ShardSplitTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/ShardSplitTest.java b/solr/core/src/test/org/apache/solr/cloud/ShardSplitTest.java
index 35ac5c0..644221b 100644
--- a/solr/core/src/test/org/apache/solr/cloud/ShardSplitTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/ShardSplitTest.java
@@ -523,7 +523,7 @@ public class ShardSplitTest extends BasicDistributedZkTest {
 
     log.info("Starting testSplitShardWithRule");
     String collectionName = "shardSplitWithRule";
-    CollectionAdminRequest.Create createRequest = CollectionAdminRequest.createCollection(collectionName,1,2)
+    CollectionAdminRequest.Create createRequest = CollectionAdminRequest.createCollection(collectionName, "conf1", 1, 2)
         .setRule("shard:*,replica:<2,node:*");
     CollectionAdminResponse response = createRequest.process(cloudClient);
     assertEquals(0, response.getStatus());

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java b/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java
index 875c0ef..27fcfc0 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestConfigSetsAPI.java
@@ -695,7 +695,7 @@ public class TestConfigSetsAPI extends SolrTestCaseJ4 {
       ConfigSetAdminRequest.List list = new ConfigSetAdminRequest.List();
       ConfigSetAdminResponse.List response = list.process(solrClient);
       Collection<String> actualConfigSets = response.getConfigSets();
-      assertEquals(0, actualConfigSets.size());
+      assertEquals(1, actualConfigSets.size()); // only the _default configset
 
       // test multiple
       Set<String> configSets = new HashSet<String>();
@@ -706,8 +706,8 @@ public class TestConfigSetsAPI extends SolrTestCaseJ4 {
       }
       response = list.process(solrClient);
       actualConfigSets = response.getConfigSets();
-      assertEquals(configSets.size(), actualConfigSets.size());
-      assertTrue(configSets.containsAll(actualConfigSets));
+      assertEquals(configSets.size() + 1, actualConfigSets.size());
+      assertTrue(actualConfigSets.containsAll(configSets));
     } finally {
       zkClient.close();
     }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java b/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java
index 2156d3b..6c2298b 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java
@@ -130,9 +130,9 @@ public class TestPullReplica extends SolrCloudTestCase {
           break;
         case 1:
           // Sometimes use v1 API
-          String url = String.format(Locale.ROOT, "%s/admin/collections?action=CREATE&name=%s&numShards=%s&pullReplicas=%s&maxShardsPerNode=%s",
+          String url = String.format(Locale.ROOT, "%s/admin/collections?action=CREATE&name=%s&collection.configName=%s&numShards=%s&pullReplicas=%s&maxShardsPerNode=%s",
               cluster.getRandomJetty(random()).getBaseUrl(),
-              collectionName,
+              collectionName, "conf",
               2,    // numShards
               3,    // pullReplicas
               100); // maxShardsPerNode
@@ -143,8 +143,8 @@ public class TestPullReplica extends SolrCloudTestCase {
         case 2:
           // Sometimes use V2 API
           url = cluster.getRandomJetty(random()).getBaseUrl().toString() + "/____v2/c";
-          String requestBody = String.format(Locale.ROOT, "{create:{name:%s, numShards:%s, pullReplicas:%s, maxShardsPerNode:%s %s}}",
-              collectionName,
+          String requestBody = String.format(Locale.ROOT, "{create:{name:%s, config:%s, numShards:%s, pullReplicas:%s, maxShardsPerNode:%s %s}}",
+              collectionName, "conf",
               2,    // numShards
               3,    // pullReplicas
               100, // maxShardsPerNode

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/test/org/apache/solr/cloud/TestRandomRequestDistribution.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestRandomRequestDistribution.java b/solr/core/src/test/org/apache/solr/cloud/TestRandomRequestDistribution.java
index b486256..30898b9 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestRandomRequestDistribution.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestRandomRequestDistribution.java
@@ -73,11 +73,11 @@ public class TestRandomRequestDistribution extends AbstractFullDistribZkTestBase
    */
   private void testRequestTracking() throws Exception {
 
-    CollectionAdminRequest.createCollection("a1x2",1,2)
+    CollectionAdminRequest.createCollection("a1x2", "conf1", 1, 2)
         .setCreateNodeSet(nodeNames.get(0) + ',' + nodeNames.get(1))
         .process(cloudClient);
 
-    CollectionAdminRequest.createCollection("b1x1",1,1)
+    CollectionAdminRequest.createCollection("b1x1", "conf1", 1, 1)
         .setCreateNodeSet(nodeNames.get(2))
         .process(cloudClient);
 
@@ -128,7 +128,7 @@ public class TestRandomRequestDistribution extends AbstractFullDistribZkTestBase
   private void testQueryAgainstDownReplica() throws Exception {
 
     log.info("Creating collection 'football' with 1 shard and 2 replicas");
-    CollectionAdminRequest.createCollection("football",1,2)
+    CollectionAdminRequest.createCollection("football", "conf1", 1, 2)
         .setCreateNodeSet(nodeNames.get(0) + ',' + nodeNames.get(1))
         .process(cloudClient);
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithKerberosAlt.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithKerberosAlt.java b/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithKerberosAlt.java
index 16cee78..68af59f 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithKerberosAlt.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestSolrCloudWithKerberosAlt.java
@@ -174,7 +174,7 @@ public class TestSolrCloudWithKerberosAlt extends LuceneTestCase {
       String configName = "solrCloudCollectionConfig";
       miniCluster.uploadConfigSet(SolrTestCaseJ4.TEST_PATH().resolve("collection1/conf"), configName);
 
-      CollectionAdminRequest.Create createRequest = CollectionAdminRequest.createCollection(collectionName,NUM_SHARDS,REPLICATION_FACTOR);
+      CollectionAdminRequest.Create createRequest = CollectionAdminRequest.createCollection(collectionName, configName, NUM_SHARDS,REPLICATION_FACTOR);
       Properties properties = new Properties();
       properties.put(CoreDescriptor.CORE_CONFIG, "solrconfig-tlog.xml");
       properties.put("solr.tests.maxBufferedDocs", "100000");

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java b/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java
index 9990601..cc470d6 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java
@@ -157,9 +157,9 @@ public class TestTlogReplica extends SolrCloudTestCase {
           break;
         case 1:
           // Sometimes don't use SolrJ
-          String url = String.format(Locale.ROOT, "%s/admin/collections?action=CREATE&name=%s&numShards=%s&tlogReplicas=%s&maxShardsPerNode=%s",
+          String url = String.format(Locale.ROOT, "%s/admin/collections?action=CREATE&name=%s&collection.configName=%s&numShards=%s&tlogReplicas=%s&maxShardsPerNode=%s",
               cluster.getRandomJetty(random()).getBaseUrl(),
-              collectionName,
+              collectionName, "conf",
               2,    // numShards
               4,    // tlogReplicas
               100); // maxShardsPerNode
@@ -170,8 +170,8 @@ public class TestTlogReplica extends SolrCloudTestCase {
         case 2:
           // Sometimes use V2 API
           url = cluster.getRandomJetty(random()).getBaseUrl().toString() + "/____v2/c";
-          String requestBody = String.format(Locale.ROOT, "{create:{name:%s, numShards:%s, tlogReplicas:%s, maxShardsPerNode:%s}}",
-              collectionName,
+          String requestBody = String.format(Locale.ROOT, "{create:{name:%s, config:%s, numShards:%s, tlogReplicas:%s, maxShardsPerNode:%s}}",
+              collectionName, "conf",
               2,    // numShards
               4,    // tlogReplicas
               100); // maxShardsPerNode

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/test/org/apache/solr/cloud/UnloadDistributedZkTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/UnloadDistributedZkTest.java b/solr/core/src/test/org/apache/solr/cloud/UnloadDistributedZkTest.java
index 2591f2b..19dd998 100644
--- a/solr/core/src/test/org/apache/solr/cloud/UnloadDistributedZkTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/UnloadDistributedZkTest.java
@@ -109,7 +109,7 @@ public class UnloadDistributedZkTest extends BasicDistributedZkTest {
     final String coreName1 = collection+"_1";
     final String coreName2 = collection+"_2";
 
-    assertEquals(0, CollectionAdminRequest.createCollection(collection, numShards, 1)
+    assertEquals(0, CollectionAdminRequest.createCollection(collection, "conf1", numShards, 1)
         .setCreateNodeSet("")
         .process(cloudClient).getStatus());
     assertTrue(CollectionAdminRequest.addReplicaToShard(collection, "shard1")
@@ -168,7 +168,7 @@ public class UnloadDistributedZkTest extends BasicDistributedZkTest {
     JettySolrRunner jetty1 = jettys.get(0);
 
     assertEquals(0, CollectionAdminRequest
-        .createCollection("unloadcollection", 1,1)
+        .createCollection("unloadcollection", "conf1", 1,1)
         .setCreateNodeSet(jetty1.getNodeName())
         .process(cloudClient).getStatus());
     ZkStateReader zkStateReader = getCommonCloudSolrClient().getZkStateReader();

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoScalingHandlerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoScalingHandlerTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoScalingHandlerTest.java
index 05cdb87..ecc7afd 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoScalingHandlerTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/AutoScalingHandlerTest.java
@@ -49,10 +49,11 @@ import static org.apache.solr.common.cloud.ZkStateReader.SOLR_AUTOSCALING_CONF_P
  * Test for AutoScalingHandler
  */
 public class AutoScalingHandlerTest extends SolrCloudTestCase {
+  final static String CONFIGSET_NAME = "conf";
   @BeforeClass
   public static void setupCluster() throws Exception {
     configureCluster(2)
-        .addConfig("conf", configset("cloud-minimal"))
+        .addConfig(CONFIGSET_NAME, configset("cloud-minimal"))
         .configure();
   }
 
@@ -275,7 +276,7 @@ public class AutoScalingHandlerTest extends SolrCloudTestCase {
     assertEquals(0, violations.size());
 
     // lets create a collection which violates the rule replicas < 2
-    CollectionAdminRequest.Create create = CollectionAdminRequest.Create.createCollection("readApiTestViolations", 1, 6);
+    CollectionAdminRequest.Create create = CollectionAdminRequest.Create.createCollection("readApiTestViolations", CONFIGSET_NAME, 1, 6);
     create.setMaxShardsPerNode(10);
     CollectionAdminResponse adminResponse = create.process(solrClient);
     assertTrue(adminResponse.isSuccess());

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/test/org/apache/solr/cloud/autoscaling/TestPolicyCloud.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/TestPolicyCloud.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/TestPolicyCloud.java
index b584e49..cb519f2 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/TestPolicyCloud.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/TestPolicyCloud.java
@@ -73,7 +73,7 @@ public class TestPolicyCloud extends SolrCloudTestCase {
     cluster.getSolrClient().request(AutoScalingHandlerTest.createAutoScalingRequest(SolrRequest.METHOD.POST, commands));
 
     String collectionName = "testCreateCollectionAddReplica";
-    CollectionAdminRequest.createCollection(collectionName, 1, 1)
+    CollectionAdminRequest.createCollection(collectionName, "conf", 1, 1)
         .setPolicy("c1")
         .process(cluster.getSolrClient());
 
@@ -102,7 +102,7 @@ public class TestPolicyCloud extends SolrCloudTestCase {
     assertEquals("success", response.get("result"));
 
     String collectionName = "testCreateCollectionSplitShard";
-    CollectionAdminRequest.createCollection(collectionName, 1, 2)
+    CollectionAdminRequest.createCollection(collectionName, "conf", 1, 2)
         .setPolicy("c1")
         .setMaxShardsPerNode(10)
         .process(cluster.getSolrClient());
@@ -140,7 +140,7 @@ public class TestPolicyCloud extends SolrCloudTestCase {
     Map<String, Object> json = Utils.getJson(cluster.getZkClient(), ZkStateReader.SOLR_AUTOSCALING_CONF_PATH, true);
     assertEquals("full json:"+ Utils.toJSONString(json) , "#EACH",
         Utils.getObjectByPath(json, true, "/policies/c1[0]/shard"));
-    CollectionAdminRequest.createCollectionWithImplicitRouter("policiesTest", null, "s1,s2", 1)
+    CollectionAdminRequest.createCollectionWithImplicitRouter("policiesTest", "conf", "s1,s2", 1)
         .setPolicy("c1")
         .process(cluster.getSolrClient());
 

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/core/src/test/org/apache/solr/handler/ThrowErrorOnInitRequestHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/handler/ThrowErrorOnInitRequestHandler.java b/solr/core/src/test/org/apache/solr/handler/ThrowErrorOnInitRequestHandler.java
index 594a3f1..6409e17 100644
--- a/solr/core/src/test/org/apache/solr/handler/ThrowErrorOnInitRequestHandler.java
+++ b/solr/core/src/test/org/apache/solr/handler/ThrowErrorOnInitRequestHandler.java
@@ -42,6 +42,10 @@ public class ThrowErrorOnInitRequestHandler extends RequestHandlerBase
 
   @Override
   public void init(NamedList args) {
+    String errorMessage = (String) args.get("error");
+    if (errorMessage != null) {
+      throw new Error(errorMessage);
+    }
     throw new Error("Doing my job, throwing a java.lang.Error");
   }
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/bc942241/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java
----------------------------------------------------------------------
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java
index cd01a7f..3587945 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/AbstractFullDistribZkTestBase.java
@@ -312,7 +312,7 @@ public abstract class AbstractFullDistribZkTestBase extends AbstractDistribZkTes
         + "/control/data") : null);
     try (SolrClient client = createCloudClient("control_collection")) {
       assertEquals(0, CollectionAdminRequest
-          .createCollection("control_collection", 1, 1)
+          .createCollection("control_collection", "conf1", 1, 1)
           .setCreateNodeSet(controlJetty.getNodeName())
           .process(client).getStatus());
       }
@@ -380,7 +380,7 @@ public abstract class AbstractFullDistribZkTestBase extends AbstractDistribZkTes
     StringBuilder sb = new StringBuilder();
 
     assertEquals(0, CollectionAdminRequest
-        .createCollection(DEFAULT_COLLECTION, sliceCount, 1)
+        .createCollection(DEFAULT_COLLECTION, "conf1", sliceCount, 1)
         .setStateFormat(Integer.parseInt(getStateFormat()))
         .setCreateNodeSet("")
         .process(cloudClient).getStatus());
@@ -1605,7 +1605,7 @@ public abstract class AbstractFullDistribZkTestBase extends AbstractDistribZkTes
   }
 
   protected CollectionAdminResponse createCollection(Map<String,List<Integer>> collectionInfos, String collectionName, Map<String,Object> collectionProps, SolrClient client)  throws SolrServerException, IOException{
-    return createCollection(collectionInfos, collectionName, collectionProps, client, null);
+    return createCollection(collectionInfos, collectionName, collectionProps, client, "conf1");
   }
 
   // TODO: Use CollectionAdminRequest#createCollection() instead of a raw request
@@ -1640,6 +1640,8 @@ public abstract class AbstractFullDistribZkTestBase extends AbstractDistribZkTes
     }
     if (confSetName != null) {
       params.set("collection.configName", confSetName);
+    } else {
+      params.set("collection.configName", "conf1");
     }
 
     int clientIndex = random().nextInt(2);
@@ -1683,7 +1685,7 @@ public abstract class AbstractFullDistribZkTestBase extends AbstractDistribZkTes
         ZkStateReader.PULL_REPLICAS, getPullReplicaCount(),
         CREATE_NODE_SET, createNodeSetStr,
         ZkStateReader.MAX_SHARDS_PER_NODE, maxShardsPerNode),
-        client);
+        client, "conf1");
   }
 
   protected CollectionAdminResponse createCollection(Map<String, List<Integer>> collectionInfos,