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

[lucene-solr] branch branch_8x updated: SOLR-12182: Don't persist base_url in ZK as the scheme is variable, compute from node_name instead ~ Backport to 8x (#2114)

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

thelabdude 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 6af56e1  SOLR-12182: Don't persist base_url in ZK as the scheme is variable, compute from node_name instead ~ Backport to 8x (#2114)
6af56e1 is described below

commit 6af56e141a52f4e616985ca5b03dda3677889bfa
Author: Timothy Potter <th...@gmail.com>
AuthorDate: Wed Dec 2 11:00:30 2020 -0700

    SOLR-12182: Don't persist base_url in ZK as the scheme is variable, compute from node_name instead ~ Backport to 8x (#2114)
---
 solr/CHANGES.txt                                   |   3 +
 .../src/java/org/apache/solr/cloud/CloudUtil.java  |   3 +-
 .../org/apache/solr/cloud/RecoveryStrategy.java    |  13 +-
 .../solr/cloud/ShardLeaderElectionContextBase.java |   4 +-
 .../java/org/apache/solr/cloud/ZkController.java   |  26 +-
 .../solr/cloud/api/collections/AddReplicaCmd.java  |   1 -
 .../cloud/api/collections/CreateCollectionCmd.java |   1 -
 .../OverseerCollectionMessageHandler.java          |  16 +-
 .../solr/cloud/api/collections/SplitShardCmd.java  |   1 -
 .../apache/solr/cloud/overseer/SliceMutator.java   |  18 +-
 .../java/org/apache/solr/core/BlobRepository.java  |   3 +-
 .../src/java/org/apache/solr/core/ZkContainer.java |  28 +-
 .../apache/solr/handler/admin/ClusterStatus.java   |  26 +-
 .../solr/handler/admin/MetricsHistoryHandler.java  |   3 +-
 .../solr/handler/admin/RebalanceLeaders.java       |   2 +-
 .../solr/handler/admin/RequestSyncShardOp.java     |   1 -
 .../java/org/apache/solr/servlet/HttpSolrCall.java |   5 +-
 .../src/java/org/apache/solr/util/SolrCLI.java     |   2 +
 .../test/org/apache/solr/TestRandomDVFaceting.java |   1 +
 .../solr/cloud/ClusterStateMockUtilTest.java       |   1 +
 .../org/apache/solr/cloud/DeleteReplicaTest.java   |   6 +-
 .../org/apache/solr/cloud/LeaderElectionTest.java  |  32 ++-
 .../org/apache/solr/cloud/NodeMutatorTest.java     |   2 +
 .../test/org/apache/solr/cloud/OverseerTest.java   |  70 ++---
 .../cloud/TestLeaderElectionWithEmptyReplica.java  |   4 +-
 .../solr/cloud/TestMiniSolrCloudClusterSSL.java    |   3 +
 .../solr/cloud/TestRandomRequestDistribution.java  |   5 +-
 .../CollectionsAPIDistributedZkTest.java           |   5 +-
 .../solr/cloud/api/collections/ShardSplitTest.java |   5 +-
 .../core/snapshots/TestSolrCloudSnapshots.java     |  13 +-
 .../solr/core/snapshots/TestSolrCoreSnapshots.java |   6 +-
 .../org/apache/solr/handler/TestBlobHandler.java   |   3 +-
 .../org/apache/solr/handler/TestConfigReload.java  |   2 +-
 .../solr/handler/TestHdfsBackupRestoreCore.java    |   7 +-
 .../org/apache/solr/handler/TestReqParamsAPI.java  |   2 +-
 .../solr/handler/TestSolrConfigHandlerCloud.java   |   4 +-
 .../handler/TestSolrConfigHandlerConcurrent.java   |   2 +-
 .../handler/component/CloudReplicaSourceTest.java  |   1 +
 .../apache/solr/index/hdfs/CheckHdfsIndexTest.java |   2 +
 .../apache/solr/update/SolrCmdDistributorTest.java |  25 +-
 .../client/solrj/impl/BaseCloudSolrClient.java     |   8 +-
 .../apache/solr/common/cloud/ClusterStateUtil.java |   2 +-
 .../java/org/apache/solr/common/cloud/Replica.java |   8 +-
 .../org/apache/solr/common/cloud/UrlScheme.java    |  73 +++++
 .../apache/solr/common/cloud/ZkCoreNodeProps.java  |  27 +-
 .../org/apache/solr/common/cloud/ZkNodeProps.java  |  54 ++--
 .../apache/solr/common/cloud/ZkStateReader.java    |  16 +-
 ...testAutoscalingPreferencesUsedWithNoPolicy.json |  22 +-
 .../solrj/solr/autoscaling/testEqualOnNonNode.json |  28 +-
 .../solr/autoscaling/testFreeDiskDeviation.json    |  18 +-
 .../solr/autoscaling/testFreeDiskSuggestions.json  |  16 +-
 .../testMoveReplicasInMultipleCollections.json     |  24 +-
 .../solrj/solr/autoscaling/testPolicy.json         |  18 +-
 .../solrj/solr/autoscaling/testWithCollection.json |   6 +-
 .../autoscaling/testWithCollectionMoveReplica.json |   9 +-
 .../testWithCollectionMoveVsAddSuggestions.json    |  21 +-
 .../autoscaling/testWithCollectionSuggestions.json |   6 +-
 .../client/solrj/cloud/autoscaling/TestPolicy.java | 300 ++++++++++-----------
 .../solrj/cloud/autoscaling/TestPolicy2.java       |  14 +-
 .../solrj/impl/CloudHttp2SolrClientTest.java       |  13 +-
 .../client/solrj/impl/CloudSolrClientTest.java     |  14 +-
 .../routing/NodePreferenceRulesComparatorTest.java |  45 ++--
 ...RequestReplicaListTransformerGeneratorTest.java |  64 ++---
 .../ShufflingReplicaListTransformerTest.java       |   4 +-
 .../apache/solr/common/cloud/UrlSchemeTest.java    |  56 ++++
 .../src/java/org/apache/solr/SolrTestCaseJ4.java   |  10 +-
 .../solr/cloud/AbstractFullDistribZkTestBase.java  |  22 +-
 67 files changed, 704 insertions(+), 551 deletions(-)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 70f7a99..6acea2c 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -56,6 +56,9 @@ Bug Fixes
 * SOLR-15017: Core lib directories were not being recognized unless the solrconfig included a <lib> directive.
   (Thomas Mortagne)
 
+* SOLR-12182: Don't persist base_url in ZK as the URL scheme is variable, compute from node_name instead when reading
+  state back from ZK. (Timothy Potter)
+
 Other Changes
 ---------------------
 
diff --git a/solr/core/src/java/org/apache/solr/cloud/CloudUtil.java b/solr/core/src/java/org/apache/solr/cloud/CloudUtil.java
index 7f4a8af..778e406 100644
--- a/solr/core/src/java/org/apache/solr/cloud/CloudUtil.java
+++ b/solr/core/src/java/org/apache/solr/cloud/CloudUtil.java
@@ -41,7 +41,6 @@ import org.apache.solr.common.cloud.DocCollection;
 import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.cloud.Slice;
 import org.apache.solr.common.cloud.SolrZkClient;
-import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.core.CoreDescriptor;
 import org.apache.solr.core.SolrResourceLoader;
@@ -77,7 +76,7 @@ public class CloudUtil {
         for (Replica replica : slice.getReplicas()) {
 
           String cnn = replica.getName();
-          String baseUrl = replica.getStr(ZkStateReader.BASE_URL_PROP);
+          String baseUrl = replica.getBaseUrl();
           log.debug("compare against coreNodeName={} baseUrl={}", cnn, baseUrl);
 
           if (thisCnn != null && thisCnn.equals(cnn)
diff --git a/solr/core/src/java/org/apache/solr/cloud/RecoveryStrategy.java b/solr/core/src/java/org/apache/solr/cloud/RecoveryStrategy.java
index d6d574d..f70276c 100644
--- a/solr/core/src/java/org/apache/solr/cloud/RecoveryStrategy.java
+++ b/solr/core/src/java/org/apache/solr/cloud/RecoveryStrategy.java
@@ -351,16 +351,11 @@ public class RecoveryStrategy implements Runnable, Closeable {
                                                                                             // though
       try {
         CloudDescriptor cloudDesc = this.coreDescriptor.getCloudDescriptor();
-        ZkNodeProps leaderprops = zkStateReader.getLeaderRetry(
-            cloudDesc.getCollectionName(), cloudDesc.getShardId());
-        final String leaderBaseUrl = leaderprops.getStr(ZkStateReader.BASE_URL_PROP);
-        final String leaderCoreName = leaderprops.getStr(ZkStateReader.CORE_NAME_PROP);
-
-        String leaderUrl = ZkCoreNodeProps.getCoreUrl(leaderBaseUrl, leaderCoreName);
-
-        String ourUrl = ZkCoreNodeProps.getCoreUrl(baseUrl, coreName);
+        ZkNodeProps leaderprops = zkStateReader.getLeaderRetry(cloudDesc.getCollectionName(), cloudDesc.getShardId());
+        final String leaderUrl = ZkCoreNodeProps.getCoreUrl(leaderprops);
+        final String ourUrl = ZkCoreNodeProps.getCoreUrl(baseUrl, coreName);
 
-        boolean isLeader = leaderUrl.equals(ourUrl); // TODO: We can probably delete most of this code if we say this
+        boolean isLeader = ourUrl.equals(leaderUrl); // TODO: We can probably delete most of this code if we say this
                                                      // strategy can only be used for pull replicas
         if (isLeader && !cloudDesc.isLeader()) {
           throw new SolrException(ErrorCode.SERVER_ERROR, "Cloud state still says we are leader.");
diff --git a/solr/core/src/java/org/apache/solr/cloud/ShardLeaderElectionContextBase.java b/solr/core/src/java/org/apache/solr/cloud/ShardLeaderElectionContextBase.java
index 500776f..b010de2 100644
--- a/solr/core/src/java/org/apache/solr/cloud/ShardLeaderElectionContextBase.java
+++ b/solr/core/src/java/org/apache/solr/cloud/ShardLeaderElectionContextBase.java
@@ -165,7 +165,7 @@ class ShardLeaderElectionContextBase extends ElectionContext {
         zkStateReader.getClusterState().getCollection(collection).getSlice(shardId).getReplicas().size() < 2) {
       Replica leader = zkStateReader.getLeader(collection, shardId);
       if (leader != null
-          && leader.getBaseUrl().equals(leaderProps.get(ZkStateReader.BASE_URL_PROP))
+          && leader.getNodeName().equals(leaderProps.get(ZkStateReader.NODE_NAME_PROP))
           && leader.getCoreName().equals(leaderProps.get(ZkStateReader.CORE_NAME_PROP))) {
         isAlreadyLeader = true;
       }
@@ -174,7 +174,7 @@ class ShardLeaderElectionContextBase extends ElectionContext {
       ZkNodeProps m = ZkNodeProps.fromKeyVals(Overseer.QUEUE_OPERATION, OverseerAction.LEADER.toLower(),
           ZkStateReader.SHARD_ID_PROP, shardId,
           ZkStateReader.COLLECTION_PROP, collection,
-          ZkStateReader.BASE_URL_PROP, leaderProps.get(ZkStateReader.BASE_URL_PROP),
+          ZkStateReader.NODE_NAME_PROP, leaderProps.get(ZkStateReader.NODE_NAME_PROP),
           ZkStateReader.CORE_NAME_PROP, leaderProps.get(ZkStateReader.CORE_NAME_PROP),
           ZkStateReader.STATE_PROP, Replica.State.ACTIVE.toString());
       assert zkController != null;
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 0ab5b25..d71adb1 100644
--- a/solr/core/src/java/org/apache/solr/cloud/ZkController.java
+++ b/solr/core/src/java/org/apache/solr/cloud/ZkController.java
@@ -103,7 +103,6 @@ import org.apache.zookeeper.data.Stat;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static org.apache.solr.common.cloud.ZkStateReader.BASE_URL_PROP;
 import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
 import static org.apache.solr.common.cloud.ZkStateReader.CORE_NAME_PROP;
 import static org.apache.solr.common.cloud.ZkStateReader.CORE_NODE_NAME_PROP;
@@ -890,6 +889,8 @@ public class ZkController implements Closeable {
     try {
       createClusterZkNodes(zkClient);
       zkStateReader.createClusterStateWatchersAndUpdate();
+
+      // this must happen after zkStateReader has initialized the cluster props
       this.baseURL = zkStateReader.getBaseUrlForNodeName(this.nodeName);
 
       checkForExistingEphemeralNode();
@@ -1092,6 +1093,7 @@ public class ZkController implements Closeable {
     if (zkRunOnly) {
       return;
     }
+
     String nodeName = getNodeName();
     String nodePath = ZkStateReader.LIVE_NODES_ZKNODE + "/" + nodeName;
     String nodeAddedPath = ZkStateReader.SOLR_AUTOSCALING_NODE_ADDED_PATH + "/" + nodeName;
@@ -1401,8 +1403,7 @@ public class ZkController implements Closeable {
         byte[] data = zkClient.getData(
             ZkStateReader.getShardLeadersPath(collection, slice), null, null,
             true);
-        ZkCoreNodeProps leaderProps = new ZkCoreNodeProps(
-            ZkNodeProps.load(data));
+        ZkCoreNodeProps leaderProps = new ZkCoreNodeProps(ZkNodeProps.load(data));
         return leaderProps;
       } catch (InterruptedException e) {
         throw e;
@@ -1442,7 +1443,6 @@ public class ZkController implements Closeable {
 
     Map<String, Object> props = new HashMap<>();
     // we only put a subset of props into the leader node
-    props.put(ZkStateReader.BASE_URL_PROP, getBaseUrl());
     props.put(ZkStateReader.CORE_NAME_PROP, cd.getName());
     props.put(ZkStateReader.NODE_NAME_PROP, getNodeName());
     props.put(ZkStateReader.CORE_NODE_NAME_PROP, coreNodeName);
@@ -1541,7 +1541,6 @@ public class ZkController implements Closeable {
       Map<String,Object> props = new HashMap<>();
       props.put(Overseer.QUEUE_OPERATION, "state");
       props.put(ZkStateReader.STATE_PROP, state.toString());
-      props.put(ZkStateReader.BASE_URL_PROP, getBaseUrl());
       props.put(ZkStateReader.CORE_NAME_PROP, cd.getName());
       props.put(ZkStateReader.ROLES_PROP, cd.getCloudDescriptor().getRoles());
       props.put(ZkStateReader.NODE_NAME_PROP, getNodeName());
@@ -1648,7 +1647,6 @@ public class ZkController implements Closeable {
           OverseerAction.DELETECORE.toLower(), ZkStateReader.CORE_NAME_PROP, coreName,
           ZkStateReader.NODE_NAME_PROP, getNodeName(),
           ZkStateReader.COLLECTION_PROP, cloudDescriptor.getCollectionName(),
-          ZkStateReader.BASE_URL_PROP, getBaseUrl(),
           ZkStateReader.CORE_NODE_NAME_PROP, coreNodeName);
       overseerJobQueue.offer(Utils.toJSON(m));
     }
@@ -2214,13 +2212,11 @@ public class ZkController implements Closeable {
 
   public void rejoinShardLeaderElection(SolrParams params) {
 
-
-      String collectionName = params.get(COLLECTION_PROP);
-      String shardId = params.get(SHARD_ID_PROP);
-      String coreNodeName = params.get(CORE_NODE_NAME_PROP);
-      String coreName = params.get(CORE_NAME_PROP);
-      String electionNode = params.get(ELECTION_NODE_PROP);
-      String baseUrl = params.get(BASE_URL_PROP);
+    String collectionName = params.get(COLLECTION_PROP);
+    String shardId = params.get(SHARD_ID_PROP);
+    String coreNodeName = params.get(CORE_NODE_NAME_PROP);
+    String coreName = params.get(CORE_NAME_PROP);
+    String electionNode = params.get(ELECTION_NODE_PROP);
 
     try {
       MDCLoggingContext.setCoreDescriptor(cc, cc.getCoreDescriptor(coreName));
@@ -2232,7 +2228,8 @@ public class ZkController implements Closeable {
       ElectionContext prevContext = electionContexts.get(contextKey);
       if (prevContext != null) prevContext.cancelElection();
 
-      ZkNodeProps zkProps = new ZkNodeProps(BASE_URL_PROP, baseUrl, CORE_NAME_PROP, coreName, NODE_NAME_PROP, getNodeName(), CORE_NODE_NAME_PROP, coreNodeName);
+      String ourUrl = ZkCoreNodeProps.getCoreUrl(UrlScheme.INSTANCE.getBaseUrlForNodeName(getNodeName()), coreName);
+      ZkNodeProps zkProps = new ZkNodeProps(CORE_NAME_PROP, coreName, NODE_NAME_PROP, getNodeName(), CORE_NODE_NAME_PROP, coreNodeName);
 
       LeaderElector elect = ((ShardLeaderElectionContextBase) prevContext).getLeaderElector();
       ShardLeaderElectionContext context = new ShardLeaderElectionContext(elect, shardId, collectionName,
@@ -2248,7 +2245,6 @@ public class ZkController implements Closeable {
         Replica.Type replicaType = core.getCoreDescriptor().getCloudDescriptor().getReplicaType();
         if (replicaType == Type.TLOG) {
           String leaderUrl = getLeader(core.getCoreDescriptor().getCloudDescriptor(), cloudConfig.getLeaderVoteWait());
-          String ourUrl = ZkCoreNodeProps.getCoreUrl(baseUrl, coreName);
           if (!leaderUrl.equals(ourUrl)) {
             // restart the replication thread to ensure the replication is running in each new replica
             // especially if previous role is "leader" (i.e., no replication thread)
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/AddReplicaCmd.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/AddReplicaCmd.java
index 3e0332e..ea1b277 100644
--- a/solr/core/src/java/org/apache/solr/cloud/api/collections/AddReplicaCmd.java
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/AddReplicaCmd.java
@@ -250,7 +250,6 @@ public class AddReplicaCmd implements OverseerCollectionMessageHandler.Cmd {
             ZkStateReader.SHARD_ID_PROP, createReplica.sliceName,
             ZkStateReader.CORE_NAME_PROP, createReplica.coreName,
             ZkStateReader.STATE_PROP, Replica.State.DOWN.toString(),
-            ZkStateReader.BASE_URL_PROP, zkStateReader.getBaseUrlForNodeName(createReplica.node),
             ZkStateReader.NODE_NAME_PROP, createReplica.node,
             ZkStateReader.REPLICA_TYPE, createReplica.replicaType.name());
         if (createReplica.coreNodeName != null) {
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/CreateCollectionCmd.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/CreateCollectionCmd.java
index 2d3e450..89f94a9 100644
--- a/solr/core/src/java/org/apache/solr/cloud/api/collections/CreateCollectionCmd.java
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/CreateCollectionCmd.java
@@ -247,7 +247,6 @@ public class CreateCollectionCmd implements OverseerCollectionMessageHandler.Cmd
               ZkStateReader.SHARD_ID_PROP, replicaPosition.shard,
               ZkStateReader.CORE_NAME_PROP, coreName,
               ZkStateReader.STATE_PROP, Replica.State.DOWN.toString(),
-              ZkStateReader.BASE_URL_PROP, baseUrl,
               ZkStateReader.NODE_NAME_PROP, nodeName,
               ZkStateReader.REPLICA_TYPE, replicaPosition.type.name(),
               CommonAdminParams.WAIT_FOR_FINAL_STATE, Boolean.toString(waitForFinalState));
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/OverseerCollectionMessageHandler.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/OverseerCollectionMessageHandler.java
index 94f1312..f4e349b 100644
--- a/solr/core/src/java/org/apache/solr/cloud/api/collections/OverseerCollectionMessageHandler.java
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/OverseerCollectionMessageHandler.java
@@ -63,6 +63,7 @@ import org.apache.solr.common.cloud.DocRouter;
 import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.cloud.Slice;
 import org.apache.solr.common.cloud.SolrZkClient;
+import org.apache.solr.common.cloud.UrlScheme;
 import org.apache.solr.common.cloud.ZkConfigManager;
 import org.apache.solr.common.cloud.ZkCoreNodeProps;
 import org.apache.solr.common.cloud.ZkNodeProps;
@@ -75,6 +76,7 @@ import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.util.ExecutorUtil;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
+import org.apache.solr.common.util.SolrNamedThreadFactory;
 import org.apache.solr.common.util.StrUtils;
 import org.apache.solr.common.util.SuppressForbidden;
 import org.apache.solr.common.util.TimeSource;
@@ -84,7 +86,6 @@ import org.apache.solr.handler.component.ShardHandler;
 import org.apache.solr.handler.component.ShardRequest;
 import org.apache.solr.handler.component.ShardResponse;
 import org.apache.solr.logging.MDCLoggingContext;
-import org.apache.solr.common.util.SolrNamedThreadFactory;
 import org.apache.solr.util.RTimer;
 import org.apache.solr.util.TimeOut;
 import org.apache.zookeeper.CreateMode;
@@ -94,11 +95,11 @@ import org.slf4j.LoggerFactory;
 
 import static org.apache.solr.client.solrj.cloud.autoscaling.Policy.POLICY;
 import static org.apache.solr.common.cloud.DocCollection.SNITCH;
-import static org.apache.solr.common.cloud.ZkStateReader.BASE_URL_PROP;
 import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
 import static org.apache.solr.common.cloud.ZkStateReader.CORE_NAME_PROP;
 import static org.apache.solr.common.cloud.ZkStateReader.CORE_NODE_NAME_PROP;
 import static org.apache.solr.common.cloud.ZkStateReader.ELECTION_NODE_PROP;
+import static org.apache.solr.common.cloud.ZkStateReader.NODE_NAME_PROP;
 import static org.apache.solr.common.cloud.ZkStateReader.PROPERTY_PROP;
 import static org.apache.solr.common.cloud.ZkStateReader.PROPERTY_VALUE_PROP;
 import static org.apache.solr.common.cloud.ZkStateReader.REJOIN_AT_HEAD_PROP;
@@ -318,7 +319,7 @@ public class OverseerCollectionMessageHandler implements OverseerMessageHandler,
   private void processRebalanceLeaders(ClusterState clusterState, ZkNodeProps message, @SuppressWarnings({"rawtypes"})NamedList results)
       throws Exception {
     checkRequired(message, COLLECTION_PROP, SHARD_ID_PROP, CORE_NAME_PROP, ELECTION_NODE_PROP,
-        CORE_NODE_NAME_PROP, BASE_URL_PROP, REJOIN_AT_HEAD_PROP);
+        CORE_NODE_NAME_PROP, NODE_NAME_PROP, REJOIN_AT_HEAD_PROP);
 
     ModifiableSolrParams params = new ModifiableSolrParams();
     params.set(COLLECTION_PROP, message.getStr(COLLECTION_PROP));
@@ -328,9 +329,9 @@ public class OverseerCollectionMessageHandler implements OverseerMessageHandler,
     params.set(CORE_NAME_PROP, message.getStr(CORE_NAME_PROP));
     params.set(CORE_NODE_NAME_PROP, message.getStr(CORE_NODE_NAME_PROP));
     params.set(ELECTION_NODE_PROP, message.getStr(ELECTION_NODE_PROP));
-    params.set(BASE_URL_PROP, message.getStr(BASE_URL_PROP));
+    params.set(NODE_NAME_PROP, message.getStr(NODE_NAME_PROP));
 
-    String baseUrl = message.getStr(BASE_URL_PROP);
+    String baseUrl = UrlScheme.INSTANCE.getBaseUrlForNodeName(message.getStr(NODE_NAME_PROP));
     ShardRequest sreq = new ShardRequest();
     sreq.nodeName = message.getStr(ZkStateReader.CORE_NAME_PROP);
     // yes, they must use same admin handler path everywhere...
@@ -440,10 +441,9 @@ public class OverseerCollectionMessageHandler implements OverseerMessageHandler,
     ZkNodeProps m = new ZkNodeProps(
         Overseer.QUEUE_OPERATION, OverseerAction.DELETECORE.toLower(),
         ZkStateReader.CORE_NAME_PROP, core,
-        ZkStateReader.NODE_NAME_PROP, replica.getStr(ZkStateReader.NODE_NAME_PROP),
+        ZkStateReader.NODE_NAME_PROP, replica.getNodeName(),
         ZkStateReader.COLLECTION_PROP, collectionName,
-        ZkStateReader.CORE_NODE_NAME_PROP, replicaName,
-        ZkStateReader.BASE_URL_PROP, replica.getStr(ZkStateReader.BASE_URL_PROP));
+        ZkStateReader.CORE_NODE_NAME_PROP, replicaName);
     overseer.offerStateUpdate(Utils.toJSON(m));
   }
 
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/SplitShardCmd.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/SplitShardCmd.java
index c616051..a29e7f6 100644
--- a/solr/core/src/java/org/apache/solr/cloud/api/collections/SplitShardCmd.java
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/SplitShardCmd.java
@@ -486,7 +486,6 @@ public class SplitShardCmd implements OverseerCollectionMessageHandler.Cmd {
             ZkStateReader.CORE_NAME_PROP, solrCoreName,
             ZkStateReader.REPLICA_TYPE, replicaPosition.type.name(),
             ZkStateReader.STATE_PROP, Replica.State.DOWN.toString(),
-            ZkStateReader.BASE_URL_PROP, zkStateReader.getBaseUrlForNodeName(subShardNodeName),
             ZkStateReader.NODE_NAME_PROP, subShardNodeName,
             CommonAdminParams.WAIT_FOR_FINAL_STATE, Boolean.toString(waitForFinalState));
         ocmh.overseer.offerStateUpdate(Utils.toJSON(props));
diff --git a/solr/core/src/java/org/apache/solr/cloud/overseer/SliceMutator.java b/solr/core/src/java/org/apache/solr/cloud/overseer/SliceMutator.java
index 800bef5..40ab1a3 100644
--- a/solr/core/src/java/org/apache/solr/cloud/overseer/SliceMutator.java
+++ b/solr/core/src/java/org/apache/solr/cloud/overseer/SliceMutator.java
@@ -77,7 +77,6 @@ public class SliceMutator {
     Replica replica = new Replica(coreNodeName,
         makeMap(
             ZkStateReader.CORE_NAME_PROP, message.getStr(ZkStateReader.CORE_NAME_PROP),
-            ZkStateReader.BASE_URL_PROP, message.getStr(ZkStateReader.BASE_URL_PROP),
             ZkStateReader.STATE_PROP, message.getStr(ZkStateReader.STATE_PROP),
             ZkStateReader.NODE_NAME_PROP, message.getStr(ZkStateReader.NODE_NAME_PROP), 
             ZkStateReader.REPLICA_TYPE, message.get(ZkStateReader.REPLICA_TYPE)), coll, slice);
@@ -87,7 +86,6 @@ public class SliceMutator {
   public ZkWriteCommand removeReplica(ClusterState clusterState, ZkNodeProps message) {
     final String cnn = message.getStr(ZkStateReader.CORE_NODE_NAME_PROP);
     final String collection = message.getStr(ZkStateReader.COLLECTION_PROP);
-    final String baseUrl = message.getStr(ZkStateReader.BASE_URL_PROP);
     if (!checkCollectionKeyExistence(message)) return ZkStateWriter.NO_OP;
 
     DocCollection coll = clusterState.getCollectionOrNull(collection);
@@ -97,10 +95,10 @@ public class SliceMutator {
     }
 
     Map<String, Slice> newSlices = new LinkedHashMap<>();
-
+    final String nodeName = message.getStr(ZkStateReader.NODE_NAME_PROP);
     for (Slice slice : coll.getSlices()) {
       Replica replica = slice.getReplica(cnn);
-      if (replica != null && (baseUrl == null || baseUrl.equals(replica.getBaseUrl()))) {
+      if (replica != null && (nodeName == null || nodeName.equals(replica.getNodeName()))) {
         Map<String, Replica> newReplicas = slice.getReplicasCopy();
         newReplicas.remove(cnn);
         slice = new Slice(slice.getName(), newReplicas, slice.getProperties(),collection);
@@ -112,15 +110,7 @@ public class SliceMutator {
   }
 
   public ZkWriteCommand setShardLeader(ClusterState clusterState, ZkNodeProps message) {
-    StringBuilder sb = new StringBuilder();
-    String baseUrl = message.getStr(ZkStateReader.BASE_URL_PROP);
-    String coreName = message.getStr(ZkStateReader.CORE_NAME_PROP);
-    sb.append(baseUrl);
-    if (baseUrl != null && !baseUrl.endsWith("/")) sb.append("/");
-    sb.append(coreName == null ? "" : coreName);
-    if (!(sb.substring(sb.length() - 1).equals("/"))) sb.append("/");
-    String leaderUrl = sb.length() > 0 ? sb.toString() : null;
-
+    String leaderUrl = ZkCoreNodeProps.getCoreUrl(message);
     String collectionName = message.getStr(ZkStateReader.COLLECTION_PROP);
     String sliceName = message.getStr(ZkStateReader.SHARD_ID_PROP);
     DocCollection coll = clusterState.getCollectionOrNull(collectionName);
@@ -137,7 +127,7 @@ public class SliceMutator {
     final Map<String, Replica> newReplicas = new LinkedHashMap<>();
     for (Replica replica : slice.getReplicas()) {
       // TODO: this should only be calculated once and cached somewhere?
-      String coreURL = ZkCoreNodeProps.getCoreUrl(replica.getStr(ZkStateReader.BASE_URL_PROP), replica.getStr(ZkStateReader.CORE_NAME_PROP));
+      String coreURL = ZkCoreNodeProps.getCoreUrl(replica.getBaseUrl(), replica.getStr(ZkStateReader.CORE_NAME_PROP));
 
       if (replica == oldLeader && !coreURL.equals(leaderUrl)) {
         replica = new ReplicaMutator(cloudManager).unsetLeader(replica);
diff --git a/solr/core/src/java/org/apache/solr/core/BlobRepository.java b/solr/core/src/java/org/apache/solr/core/BlobRepository.java
index 4b1f702..4ede217 100644
--- a/solr/core/src/java/org/apache/solr/core/BlobRepository.java
+++ b/solr/core/src/java/org/apache/solr/core/BlobRepository.java
@@ -54,7 +54,6 @@ import org.slf4j.LoggerFactory;
 
 import static org.apache.solr.common.SolrException.ErrorCode.SERVER_ERROR;
 import static org.apache.solr.common.SolrException.ErrorCode.SERVICE_UNAVAILABLE;
-import static org.apache.solr.common.cloud.ZkStateReader.BASE_URL_PROP;
 
 /**
  * The purpose of this class is to store the Jars loaded in memory and to keep only one copy of the Jar in a single node.
@@ -209,7 +208,7 @@ public class BlobRepository {
    */
   ByteBuffer fetchBlob(String key) {
     Replica replica = getSystemCollReplica();
-    String url = replica.getStr(BASE_URL_PROP) + "/" + CollectionAdminParams.SYSTEM_COLL + "/blob/" + key + "?wt=filestream";
+    String url = replica.getBaseUrl() + "/" + CollectionAdminParams.SYSTEM_COLL + "/blob/" + key + "?wt=filestream";
     return fetchFromUrl(key, url);
   }
 
diff --git a/solr/core/src/java/org/apache/solr/core/ZkContainer.java b/solr/core/src/java/org/apache/solr/core/ZkContainer.java
index 0a44fbc..8230948 100644
--- a/solr/core/src/java/org/apache/solr/core/ZkContainer.java
+++ b/solr/core/src/java/org/apache/solr/core/ZkContainer.java
@@ -28,21 +28,29 @@ import java.util.concurrent.TimeoutException;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
+import org.apache.commons.lang3.StringUtils;
 import org.apache.solr.cloud.CurrentCoreDescriptorProvider;
 import org.apache.solr.cloud.SolrZkServer;
 import org.apache.solr.cloud.ZkController;
 import org.apache.solr.common.AlreadyClosedException;
 import org.apache.solr.common.SolrException;
+import org.apache.solr.common.cloud.ClusterProperties;
 import org.apache.solr.common.cloud.Replica;
+import org.apache.solr.common.cloud.UrlScheme;
 import org.apache.solr.common.cloud.ZkConfigManager;
 import org.apache.solr.common.cloud.ZooKeeperException;
 import org.apache.solr.common.util.ExecutorUtil;
-import org.apache.solr.logging.MDCLoggingContext;
 import org.apache.solr.common.util.SolrNamedThreadFactory;
+import org.apache.solr.logging.MDCLoggingContext;
 import org.apache.zookeeper.KeeperException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.solr.common.cloud.UrlScheme.HTTP;
+import static org.apache.solr.common.cloud.UrlScheme.HTTPS;
+import static org.apache.solr.common.cloud.UrlScheme.HTTPS_PORT_PROP;
+import static org.apache.solr.common.cloud.ZkStateReader.URL_SCHEME;
+
 /**
  * Used by {@link CoreContainer} to hold ZooKeeper / SolrCloud info, especially {@link ZkController}.
  * Mainly it does some ZK initialization, and ensures a loading core registers in ZK.
@@ -131,10 +139,20 @@ public class ZkContainer {
             });
 
 
-        if (zkRun != null && zkServer.getServers().size() > 1 && confDir == null && boostrapConf == false) {
-          // we are part of an ensemble and we are not uploading the config - pause to give the config time
-          // to get up
-          Thread.sleep(10000);
+        if (zkRun != null) {
+          if (StringUtils.isNotEmpty(System.getProperty(HTTPS_PORT_PROP))) {
+            // Embedded ZK and probably running with SSL
+            new ClusterProperties(zkController.getZkClient()).setClusterProperty(URL_SCHEME, HTTPS);
+            UrlScheme.INSTANCE.setUrlScheme(HTTPS);
+          } else {
+            UrlScheme.INSTANCE.setUrlScheme(System.getProperty(URL_SCHEME, HTTP));
+          }
+
+          if (zkServer.getServers().size() > 1 && confDir == null && boostrapConf == false) {
+            // we are part of an ensemble and we are not uploading the config - pause to give the config time
+            // to get up
+            Thread.sleep(10000);
+          }
         }
 
         if(confDir != null) {
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 d502dec..e9a404a 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
@@ -35,6 +35,7 @@ import org.apache.solr.common.cloud.DocCollection;
 import org.apache.solr.common.cloud.DocRouter;
 import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.cloud.Slice;
+import org.apache.solr.common.cloud.UrlScheme;
 import org.apache.solr.common.cloud.ZkNodeProps;
 import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.params.ShardParams;
@@ -206,7 +207,7 @@ public class ClusterStatus {
       throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Collection: " + name + " not found");
     }
     if (requestedShards == null || requestedShards.isEmpty()) {
-      return collection;
+      return postProcessCollectionJSON(collection);
     } else {
       Map<String, Object> shards = (Map<String, Object>) collection.get("shards");
       Map<String, Object>  selected = new HashMap<>();
@@ -217,12 +218,10 @@ public class ClusterStatus {
         selected.put(selectedShard, shards.get(selectedShard));
         collection.put("shards", selected);
       }
-      return collection;
+      return postProcessCollectionJSON(collection);
     }
   }
 
-
-
   /**
    * Walks the tree of collection status to verify that any replicas not reporting a "down" status is
    * on a live node, if any replicas reporting their status as "active" but the node is not live is
@@ -256,5 +255,22 @@ public class ClusterStatus {
     }
   }
 
-
+  @SuppressWarnings("unchecked")
+  public static Map<String,Object> postProcessCollectionJSON(Map<String, Object> collection) {
+    final Map<String, Map<String,Object>> shards = collection != null
+        ? (Map<String, Map<String,Object>>)collection.getOrDefault("shards", Collections.emptyMap())
+        : Collections.emptyMap();
+    shards.values().forEach(s -> {
+      final Map<String, Map<String,Object>> replicas =
+          (Map<String, Map<String,Object>>)s.getOrDefault("replicas", Collections.emptyMap());
+      replicas.values().forEach(r -> {
+        String nodeName = (String)r.get(ZkStateReader.NODE_NAME_PROP);
+        if (nodeName != null) {
+          // UI needs the base_url set
+          r.put(ZkStateReader.BASE_URL_PROP, UrlScheme.INSTANCE.getBaseUrlForNodeName(nodeName));
+        }
+      });
+    });
+    return collection;
+  }
 }
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/MetricsHistoryHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/MetricsHistoryHandler.java
index 610071a..e0f1b19 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/MetricsHistoryHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/MetricsHistoryHandler.java
@@ -110,6 +110,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import static java.util.stream.Collectors.toMap;
+import static org.apache.solr.common.cloud.ZkStateReader.URL_SCHEME;
 import static org.apache.solr.common.params.CommonParams.ID;
 
 /**
@@ -191,7 +192,7 @@ public class MetricsHistoryHandler extends RequestHandlerBase implements Permiss
           .getOrDefault("history", Collections.emptyMap());
       args.putAll(props);
 
-      overseerUrlScheme = cloudManager.getClusterStateProvider().getClusterProperty("urlScheme", "http");
+      overseerUrlScheme = cloudManager.getClusterStateProvider().getClusterProperty(URL_SCHEME, "http");
     } else {
       overseerUrlScheme = "http";
     }
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/RebalanceLeaders.java b/solr/core/src/java/org/apache/solr/handler/admin/RebalanceLeaders.java
index 81900c3..8f3fdb2 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/RebalanceLeaders.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/RebalanceLeaders.java
@@ -409,7 +409,7 @@ class RebalanceLeaders {
     propMap.put(QUEUE_OPERATION, REBALANCELEADERS.toLower());
     propMap.put(CORE_NAME_PROP, core);
     propMap.put(CORE_NODE_NAME_PROP, replica.getName());
-    propMap.put(ZkStateReader.BASE_URL_PROP, replica.getProperties().get(ZkStateReader.BASE_URL_PROP));
+    propMap.put(ZkStateReader.NODE_NAME_PROP, replica.getNodeName());
     propMap.put(REJOIN_AT_HEAD_PROP, Boolean.toString(rejoinAtHead)); // Get ourselves to be first in line.
     propMap.put(ELECTION_NODE_PROP, electionNode);
     String asyncId = REBALANCELEADERS.toLower() + "_" + core + "_" + Math.abs(System.nanoTime());
diff --git a/solr/core/src/java/org/apache/solr/handler/admin/RequestSyncShardOp.java b/solr/core/src/java/org/apache/solr/handler/admin/RequestSyncShardOp.java
index 53ca274..8aae420 100644
--- a/solr/core/src/java/org/apache/solr/handler/admin/RequestSyncShardOp.java
+++ b/solr/core/src/java/org/apache/solr/handler/admin/RequestSyncShardOp.java
@@ -59,7 +59,6 @@ class RequestSyncShardOp implements CoreAdminHandler.CoreAdminOp {
         syncStrategy = new SyncStrategy(core.getCoreContainer());
 
         Map<String, Object> props = new HashMap<>();
-        props.put(ZkStateReader.BASE_URL_PROP, zkController.getBaseUrl());
         props.put(ZkStateReader.CORE_NAME_PROP, cname);
         props.put(ZkStateReader.NODE_NAME_PROP, zkController.getNodeName());
 
diff --git a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
index 43ab7e27..0751549 100644
--- a/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
+++ b/solr/core/src/java/org/apache/solr/servlet/HttpSolrCall.java
@@ -115,7 +115,6 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.MarkerFactory;
 
-import static org.apache.solr.common.cloud.ZkStateReader.BASE_URL_PROP;
 import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
 import static org.apache.solr.common.cloud.ZkStateReader.CORE_NAME_PROP;
 import static org.apache.solr.common.cloud.ZkStateReader.NODE_NAME_PROP;
@@ -1052,13 +1051,13 @@ public class HttpSolrCall {
             // if it's by core name, make sure they match
             continue;
           }
-          if (replica.getStr(BASE_URL_PROP).equals(cores.getZkController().getBaseUrl())) {
+          if (replica.getBaseUrl().equals(cores.getZkController().getBaseUrl())) {
             // don't count a local core
             continue;
           }
 
           if (origCorename != null) {
-            coreUrl = replica.getStr(BASE_URL_PROP) + "/" + origCorename;
+            coreUrl = replica.getBaseUrl() + "/" + origCorename;
           } else {
             coreUrl = replica.getCoreUrl();
             if (coreUrl.endsWith("/")) {
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 a76f5ad..d2680bb 100755
--- a/solr/core/src/java/org/apache/solr/util/SolrCLI.java
+++ b/solr/core/src/java/org/apache/solr/util/SolrCLI.java
@@ -121,6 +121,7 @@ import org.apache.solr.common.MapWriter;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.cloud.ClusterState;
 import org.apache.solr.common.cloud.DocCollection;
+import org.apache.solr.common.cloud.UrlScheme;
 import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.cloud.Slice;
 import org.apache.solr.common.cloud.SolrZkClient;
@@ -3119,6 +3120,7 @@ public class SolrCLI {
 
     protected void runImpl(CommandLine cli) throws Exception {
       this.urlScheme = cli.getOptionValue("urlScheme", "http");
+      UrlScheme.INSTANCE.setUrlScheme(this.urlScheme);
 
       serverDir = new File(cli.getOptionValue("serverDir"));
       if (!serverDir.isDirectory())
diff --git a/solr/core/src/test/org/apache/solr/TestRandomDVFaceting.java b/solr/core/src/test/org/apache/solr/TestRandomDVFaceting.java
index f8bb93e..fba9f4f 100644
--- a/solr/core/src/test/org/apache/solr/TestRandomDVFaceting.java
+++ b/solr/core/src/test/org/apache/solr/TestRandomDVFaceting.java
@@ -42,6 +42,7 @@ import org.slf4j.LoggerFactory;
  */
 @Slow
 @SolrTestCaseJ4.SuppressPointFields(bugUrl="Test explicitly compares Trie to Points, randomization defeats the point")
+@SolrTestCaseJ4.SuppressSSL
 public class TestRandomDVFaceting extends SolrTestCaseJ4 {
 
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
diff --git a/solr/core/src/test/org/apache/solr/cloud/ClusterStateMockUtilTest.java b/solr/core/src/test/org/apache/solr/cloud/ClusterStateMockUtilTest.java
index 89e9007..16a1d1e 100644
--- a/solr/core/src/test/org/apache/solr/cloud/ClusterStateMockUtilTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/ClusterStateMockUtilTest.java
@@ -29,6 +29,7 @@ import org.junit.Test;
 /**
  * Tests for {@link ClusterStateMockUtil}
  */
+@SolrTestCaseJ4.SuppressSSL // tests expect http scheme
 public class ClusterStateMockUtilTest extends SolrTestCaseJ4 {
 
   @Test
diff --git a/solr/core/src/test/org/apache/solr/cloud/DeleteReplicaTest.java b/solr/core/src/test/org/apache/solr/cloud/DeleteReplicaTest.java
index df36112..0b4339f 100644
--- a/solr/core/src/test/org/apache/solr/cloud/DeleteReplicaTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/DeleteReplicaTest.java
@@ -253,8 +253,7 @@ public class DeleteReplicaTest extends SolrCloudTestCase {
         ZkStateReader.CORE_NAME_PROP, replica.getCoreName(),
         ZkStateReader.NODE_NAME_PROP, replica.getNodeName(),
         ZkStateReader.COLLECTION_PROP, collectionName,
-        ZkStateReader.CORE_NODE_NAME_PROP, replica.getName(),
-        ZkStateReader.BASE_URL_PROP, replica.getBaseUrl());
+        ZkStateReader.CORE_NODE_NAME_PROP, replica.getName());
 
     cluster.getOpenOverseer().getStateUpdateQueue().offer(Utils.toJSON(m));
 
@@ -335,8 +334,7 @@ public class DeleteReplicaTest extends SolrCloudTestCase {
               ZkStateReader.CORE_NAME_PROP, replica1.getCoreName(),
               ZkStateReader.NODE_NAME_PROP, replica1.getNodeName(),
               ZkStateReader.COLLECTION_PROP, collectionName,
-              ZkStateReader.CORE_NODE_NAME_PROP, replica1.getName(),
-              ZkStateReader.BASE_URL_PROP, replica1.getBaseUrl());
+              ZkStateReader.CORE_NODE_NAME_PROP, replica1.getName());
           cluster.getOpenOverseer().getStateUpdateQueue().offer(Utils.toJSON(m));
 
           boolean replicaDeleted = false;
diff --git a/solr/core/src/test/org/apache/solr/cloud/LeaderElectionTest.java b/solr/core/src/test/org/apache/solr/cloud/LeaderElectionTest.java
index 50821fc..1e6b2ca 100644
--- a/solr/core/src/test/org/apache/solr/cloud/LeaderElectionTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/LeaderElectionTest.java
@@ -32,6 +32,7 @@ import org.apache.lucene.util.LuceneTestCase.Slow;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.common.cloud.OnReconnect;
 import org.apache.solr.common.cloud.SolrZkClient;
+import org.apache.solr.common.cloud.UrlScheme;
 import org.apache.solr.common.cloud.ZkCoreNodeProps;
 import org.apache.solr.common.cloud.ZkNodeProps;
 import org.apache.solr.common.cloud.ZkStateReader;
@@ -205,21 +206,22 @@ public class LeaderElectionTest extends SolrTestCaseJ4 {
   public void testBasic() throws Exception {
     LeaderElector elector = new LeaderElector(zkClient);
     ZkNodeProps props = new ZkNodeProps(ZkStateReader.BASE_URL_PROP,
-        "http://127.0.0.1/solr/", ZkStateReader.CORE_NAME_PROP, "");
+        UrlScheme.INSTANCE.applyUrlScheme("http://127.0.0.1/solr/"), ZkStateReader.CORE_NAME_PROP, "");
     ZkController zkController = MockSolrSource.makeSimpleMock(null, null, zkClient);
     ElectionContext context = new ShardLeaderElectionContextBase(elector,
         "shard2", "collection1", "dummynode1", props, zkController);
     elector.setup(context);
     elector.joinElection(context, false);
-    assertEquals("http://127.0.0.1/solr/",
+    assertEquals(UrlScheme.INSTANCE.getUrlScheme() + "://127.0.0.1/solr/",
         getLeaderUrl("collection1", "shard2"));
   }
 
   @Test
   public void testCancelElection() throws Exception {
+    UrlScheme u = UrlScheme.INSTANCE;
     LeaderElector first = new LeaderElector(zkClient);
     ZkNodeProps props = new ZkNodeProps(ZkStateReader.BASE_URL_PROP,
-        "http://127.0.0.1/solr/", ZkStateReader.CORE_NAME_PROP, "1");
+        u.applyUrlScheme("http://127.0.0.1/solr/"), ZkStateReader.CORE_NAME_PROP, "1");
     ZkController zkController = MockSolrSource.makeSimpleMock(null, null, zkClient);
     ElectionContext firstContext = new ShardLeaderElectionContextBase(first,
         "slice1", "collection2", "dummynode1", props, zkController);
@@ -227,21 +229,25 @@ public class LeaderElectionTest extends SolrTestCaseJ4 {
     first.joinElection(firstContext, false);
 
     Thread.sleep(1000);
-    assertEquals("original leader was not registered", "http://127.0.0.1/solr/1/", getLeaderUrl("collection2", "slice1"));
+
+    String url1 = u.applyUrlScheme("http://127.0.0.1/solr/1/");
+    String url2 = u.applyUrlScheme("http://127.0.0.1/solr/2/");
+
+    assertEquals("original leader was not registered", url1, getLeaderUrl("collection2", "slice1"));
 
     LeaderElector second = new LeaderElector(zkClient);
     props = new ZkNodeProps(ZkStateReader.BASE_URL_PROP,
-        "http://127.0.0.1/solr/", ZkStateReader.CORE_NAME_PROP, "2");
+        u.applyUrlScheme("http://127.0.0.1/solr/"), ZkStateReader.CORE_NAME_PROP, "2");
     zkController = MockSolrSource.makeSimpleMock(null, null, zkClient);
     ElectionContext context = new ShardLeaderElectionContextBase(second,
         "slice1", "collection2", "dummynode2", props, zkController);
     second.setup(context);
     second.joinElection(context, false);
     Thread.sleep(1000);
-    assertEquals("original leader should have stayed leader", "http://127.0.0.1/solr/1/", getLeaderUrl("collection2", "slice1"));
+    assertEquals("original leader should have stayed leader", url1, getLeaderUrl("collection2", "slice1"));
     firstContext.cancelElection();
     Thread.sleep(1000);
-    assertEquals("new leader was not registered", "http://127.0.0.1/solr/2/", getLeaderUrl("collection2", "slice1"));
+    assertEquals("new leader was not registered", url2, getLeaderUrl("collection2", "slice1"));
   }
 
   private String getLeaderUrl(final String collection, final String slice)
@@ -384,7 +390,12 @@ public class LeaderElectionTest extends SolrTestCaseJ4 {
       for (int i = 1; i <= numShards; i ++) {
         // if this test fails, getLeaderUrl will more likely throw an exception and fail the test,
         // but add an assertEquals as well for good measure
-        assertEquals("2/", getLeaderUrl("collection1", "parshard" + i));
+        String leaderUrl = getLeaderUrl("collection1", "parshard" + i);
+        int at = leaderUrl.indexOf("://");
+        if (at != -1) {
+          leaderUrl = leaderUrl.substring(at + 3);
+        }
+        assertEquals("2/", leaderUrl);
       }
     } finally {
       // cleanup any threads still running
@@ -414,6 +425,11 @@ public class LeaderElectionTest extends SolrTestCaseJ4 {
 
   private int getLeaderThread() throws KeeperException, InterruptedException {
     String leaderUrl = getLeaderUrl("collection1", "shard1");
+    // strip off the scheme
+    final int at = leaderUrl.indexOf("://");
+    if (at != -1) {
+      leaderUrl = leaderUrl.substring(at + 3);
+    }
     return Integer.parseInt(leaderUrl.replaceAll("/", ""));
   }
 
diff --git a/solr/core/src/test/org/apache/solr/cloud/NodeMutatorTest.java b/solr/core/src/test/org/apache/solr/cloud/NodeMutatorTest.java
index a446f29..70e100c 100644
--- a/solr/core/src/test/org/apache/solr/cloud/NodeMutatorTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/NodeMutatorTest.java
@@ -19,6 +19,7 @@ package org.apache.solr.cloud;
 import java.io.IOException;
 import java.util.List;
 
+import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.SolrTestCaseJ4Test;
 import org.apache.solr.cloud.overseer.NodeMutator;
 import org.apache.solr.cloud.overseer.ZkWriteCommand;
@@ -28,6 +29,7 @@ import org.apache.solr.common.cloud.ZkNodeProps;
 import org.apache.solr.common.cloud.ZkStateReader;
 import org.junit.Test;
 
+@SolrTestCaseJ4.SuppressSSL // tests compare for http:
 public class NodeMutatorTest extends SolrTestCaseJ4Test {
 
   private static final String NODE3 = "baseUrl3_";
diff --git a/solr/core/src/test/org/apache/solr/cloud/OverseerTest.java b/solr/core/src/test/org/apache/solr/cloud/OverseerTest.java
index 17e687b..9bbb4b0 100644
--- a/solr/core/src/test/org/apache/solr/cloud/OverseerTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/OverseerTest.java
@@ -108,6 +108,7 @@ import com.codahale.metrics.Snapshot;
 import com.codahale.metrics.Timer;
 
 @Slow
+@SolrTestCaseJ4.SuppressSSL
 public class OverseerTest extends SolrTestCaseJ4 {
 
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@@ -216,8 +217,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
             ZkStateReader.CORE_NODE_NAME_PROP, coreNodeName,
             ZkStateReader.COLLECTION_PROP, collection,
             ZkStateReader.SHARD_ID_PROP, shard,
-            ZkStateReader.NUM_SHARDS_PROP, Integer.toString(numShards),
-            ZkStateReader.BASE_URL_PROP, "http://" + nodeName + "/solr/");
+            ZkStateReader.NUM_SHARDS_PROP, Integer.toString(numShards));
         ZkDistributedQueue q = overseer.getStateUpdateQueue();
         q.offer(Utils.toJSON(m));
       }
@@ -236,15 +236,14 @@ public class OverseerTest extends SolrTestCaseJ4 {
             zkClient.makePath("/collections/" + collection + "/leader_elect/"
                 + shardId + "/election", true);
           } catch (NodeExistsException nee) {}
-          ZkNodeProps props = new ZkNodeProps(ZkStateReader.BASE_URL_PROP,
-              "http://" + nodeName + "/solr/", ZkStateReader.NODE_NAME_PROP,
-              nodeName, ZkStateReader.CORE_NAME_PROP, coreName,
+          ZkNodeProps props = new ZkNodeProps(ZkStateReader.NODE_NAME_PROP, nodeName,
+              ZkStateReader.CORE_NAME_PROP, coreName,
               ZkStateReader.SHARD_ID_PROP, shardId,
               ZkStateReader.COLLECTION_PROP, collection,
               ZkStateReader.CORE_NODE_NAME_PROP, coreNodeName);
           LeaderElector elector = new LeaderElector(zkClient);
           ShardLeaderElectionContextBase ctx = new ShardLeaderElectionContextBase(
-              elector, shardId, collection, nodeName + "_" + coreName, props,
+              elector, shardId, collection, nodeName + coreName, props,
               MockSolrSource.makeSimpleMock(overseer, zkStateReader, null));
           elector.setup(ctx);
           electionContext.put(coreName, ctx);
@@ -391,7 +390,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
       try (ZkStateReader reader = new ZkStateReader(zkClient)) {
         reader.createClusterStateWatchersAndUpdate();
 
-        mockController = new MockZKController(server.getZkAddress(), "127.0.0.1", overseers);
+        mockController = new MockZKController(server.getZkAddress(), "127.0.0.1_solr", overseers);
 
         final int numShards = 6;
 
@@ -441,7 +440,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
       try (ZkStateReader reader = new ZkStateReader(zkClient)) {
         reader.createClusterStateWatchersAndUpdate();
 
-        mockController = new MockZKController(server.getZkAddress(), "127.0.0.1", overseers);
+        mockController = new MockZKController(server.getZkAddress(), "127.0.0.1_solr", overseers);
 
         final int numShards = 3;
         mockController.createCollection(COLLECTION, 3);
@@ -508,7 +507,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
       try (ZkStateReader reader = new ZkStateReader(zkClient)) {
         reader.createClusterStateWatchersAndUpdate();
 
-        mockController = new MockZKController(server.getZkAddress(), "127.0.0.1", overseers);
+        mockController = new MockZKController(server.getZkAddress(), "127.0.0.1_solr", overseers);
 
         try (ZkController zkController = createMockZkController(server.getZkAddress(), zkClient, reader)) {
 
@@ -519,7 +518,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
           }
         }
         ZkNodeProps m = new ZkNodeProps(Overseer.QUEUE_OPERATION, OverseerAction.DOWNNODE.toLower(),
-            ZkStateReader.NODE_NAME_PROP, "127.0.0.1");
+            ZkStateReader.NODE_NAME_PROP, "127.0.0.1_solr");
         List<ZkWriteCommand> commands = new NodeMutator().downNode(reader.getClusterState(), m);
 
         ZkDistributedQueue q = overseers.get(0).getStateUpdateQueue();
@@ -588,8 +587,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
       q.offer(Utils.toJSON(m));
 
       m = new ZkNodeProps(Overseer.QUEUE_OPERATION, OverseerAction.STATE.toLower(),
-          ZkStateReader.BASE_URL_PROP, "http://127.0.0.1/solr",
-          ZkStateReader.NODE_NAME_PROP, "node1",
+          ZkStateReader.NODE_NAME_PROP, "node1_",
           ZkStateReader.COLLECTION_PROP, COLLECTION,
           ZkStateReader.SHARD_ID_PROP, "shard1",
           ZkStateReader.CORE_NAME_PROP, "core1",
@@ -604,8 +602,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
 
       //publish node state (active)
       m = new ZkNodeProps(Overseer.QUEUE_OPERATION, OverseerAction.STATE.toLower(),
-          ZkStateReader.BASE_URL_PROP, "http://127.0.0.1/solr",
-          ZkStateReader.NODE_NAME_PROP, "node1",
+          ZkStateReader.NODE_NAME_PROP, "node1_",
           ZkStateReader.COLLECTION_PROP, COLLECTION,
           ZkStateReader.SHARD_ID_PROP, "shard1",
           ZkStateReader.CORE_NAME_PROP, "core1",
@@ -661,7 +658,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
       reader = new ZkStateReader(zkClient);
       reader.createClusterStateWatchersAndUpdate();
 
-      mockController = new MockZKController(server.getZkAddress(), "node1", overseers);
+      mockController = new MockZKController(server.getZkAddress(), "127.0.0.1_solr", overseers);
 
       overseerClient = electNewOverseer(server.getZkAddress());
 
@@ -723,7 +720,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
       reader = new ZkStateReader(zkClient);
       reader.createClusterStateWatchersAndUpdate();
 
-      mockController = new MockZKController(server.getZkAddress(), "node1", overseers);
+      mockController = new MockZKController(server.getZkAddress(), "127.0.0.1_solr", overseers);
 
       LeaderElector overseerElector = new LeaderElector(zkClient);
       if (overseers.size() > 0) {
@@ -911,7 +908,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
       for (int i = 0; i < atLeast(4); i++) {
         killCounter.incrementAndGet(); // for each round allow 1 kill
 
-        mockController = new MockZKController(server.getZkAddress(), "node1", overseers);
+        mockController = new MockZKController(server.getZkAddress(), "node1_", overseers);
 
         TimeOut timeout = new TimeOut(10, TimeUnit.SECONDS, TimeSource.NANO_TIME);
         while (!timeout.hasTimedOut()) {
@@ -952,7 +949,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
           }
         }
 
-        mockController2 = new MockZKController(server.getZkAddress(), "node2", overseers);
+        mockController2 = new MockZKController(server.getZkAddress(), "node2_", overseers);
 
        timeout = new TimeOut(10, TimeUnit.SECONDS, TimeSource.NANO_TIME);
         while (!timeout.hasTimedOut()) {
@@ -1036,7 +1033,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
       reader = new ZkStateReader(zkClient);
       reader.createClusterStateWatchersAndUpdate();
 
-      mockController = new MockZKController(server.getZkAddress(), "node1", overseers);
+      mockController = new MockZKController(server.getZkAddress(), "127.0.0.1_solr", overseers);
 
       overseerClient = electNewOverseer(server.getZkAddress());
 
@@ -1052,7 +1049,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
 
       mockController.close();
 
-      mockController = new MockZKController(server.getZkAddress(), "node1", overseers);
+      mockController = new MockZKController(server.getZkAddress(), "127.0.0.1_solr", overseers);
 
       mockController.publishState(COLLECTION, "core1", "core_node1","shard1", Replica.State.RECOVERING, 1, true, overseers.get(0));
 
@@ -1093,7 +1090,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
       reader = new ZkStateReader(zkClient);
       reader.createClusterStateWatchersAndUpdate();
 
-      mockController = new MockZKController(server.getZkAddress(), "node1", overseers);
+      mockController = new MockZKController(server.getZkAddress(), "127.0.0.1_solr", overseers);
 
       final int MAX_COLLECTIONS = 10, MAX_CORES = 10, MAX_STATE_CHANGES = 20000, STATE_FORMAT = 2;
 
@@ -1117,9 +1114,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
             ZkStateReader.CORE_NAME_PROP, "core" + k,
             ZkStateReader.CORE_NODE_NAME_PROP, "node1",
             ZkStateReader.COLLECTION_PROP, "perf" + j,
-            ZkStateReader.NUM_SHARDS_PROP, "1",
-            ZkStateReader.BASE_URL_PROP, "http://" +  "node1"
-            + "/solr/");
+            ZkStateReader.NUM_SHARDS_PROP, "1");
         ZkDistributedQueue q = overseers.get(0).getStateUpdateQueue();
         q.offer(Utils.toJSON(m));
         if (j >= MAX_COLLECTIONS - 1) j = 0;
@@ -1227,8 +1222,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
           "createNodeSet", "");
       queue.offer(Utils.toJSON(m));
       m = new ZkNodeProps(Overseer.QUEUE_OPERATION, OverseerAction.STATE.toLower(),
-          ZkStateReader.BASE_URL_PROP, "http://127.0.0.1/solr",
-          ZkStateReader.NODE_NAME_PROP, "node1",
+          ZkStateReader.NODE_NAME_PROP, "127.0.0.1_solr",
           ZkStateReader.SHARD_ID_PROP, "shard1",
           ZkStateReader.COLLECTION_PROP, COLLECTION,
           ZkStateReader.CORE_NAME_PROP, "core1",
@@ -1236,8 +1230,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
           ZkStateReader.STATE_PROP, Replica.State.RECOVERING.toString());
       queue.offer(Utils.toJSON(m));
       m = new ZkNodeProps(Overseer.QUEUE_OPERATION, "state",
-          ZkStateReader.BASE_URL_PROP, "http://127.0.0.1/solr",
-          ZkStateReader.NODE_NAME_PROP, "node1",
+          ZkStateReader.NODE_NAME_PROP, "node1_",
           ZkStateReader.SHARD_ID_PROP, "shard1",
           ZkStateReader.COLLECTION_PROP, COLLECTION,
           ZkStateReader.CORE_NAME_PROP, "core2",
@@ -1250,8 +1243,7 @@ public class OverseerTest extends SolrTestCaseJ4 {
       //submit to proper queue
       queue = overseers.get(0).getStateUpdateQueue();
       m = new ZkNodeProps(Overseer.QUEUE_OPERATION, OverseerAction.STATE.toLower(),
-          ZkStateReader.BASE_URL_PROP, "http://127.0.0.1/solr",
-          ZkStateReader.NODE_NAME_PROP, "node1",
+          ZkStateReader.NODE_NAME_PROP, "127.0.0.1_solr",
           ZkStateReader.SHARD_ID_PROP, "shard1",
           ZkStateReader.COLLECTION_PROP, COLLECTION,
           ZkStateReader.CORE_NAME_PROP, "core3",
@@ -1299,9 +1291,8 @@ public class OverseerTest extends SolrTestCaseJ4 {
       q.offer(Utils.toJSON(m));
 
       m = new ZkNodeProps(Overseer.QUEUE_OPERATION, OverseerAction.STATE.toLower(),
-          ZkStateReader.BASE_URL_PROP, "http://127.0.0.1/solr",
           ZkStateReader.SHARD_ID_PROP, "shard1",
-          ZkStateReader.NODE_NAME_PROP, "node1",
+          ZkStateReader.NODE_NAME_PROP, "127.0.0.1_solr",
           ZkStateReader.COLLECTION_PROP, "c1",
           ZkStateReader.CORE_NAME_PROP, "core1",
           ZkStateReader.CORE_NODE_NAME_PROP, "core_node1",
@@ -1314,9 +1305,8 @@ public class OverseerTest extends SolrTestCaseJ4 {
       verifyReplicaStatus(reader, "c1", "shard1", "core_node1", Replica.State.DOWN);
 
       m = new ZkNodeProps(Overseer.QUEUE_OPERATION, OverseerAction.STATE.toLower(),
-          ZkStateReader.BASE_URL_PROP, "http://127.0.0.1/solr",
           ZkStateReader.SHARD_ID_PROP, "shard1",
-          ZkStateReader.NODE_NAME_PROP, "node1",
+          ZkStateReader.NODE_NAME_PROP, "127.0.0.1_solr",
           ZkStateReader.COLLECTION_PROP, "c1",
           ZkStateReader.CORE_NAME_PROP, "core1",
           ZkStateReader.ROLES_PROP, "",
@@ -1326,9 +1316,8 @@ public class OverseerTest extends SolrTestCaseJ4 {
 
 
       m = new ZkNodeProps(Overseer.QUEUE_OPERATION, OverseerAction.STATE.toLower(),
-          ZkStateReader.BASE_URL_PROP, "http://127.0.0.1/solr",
           ZkStateReader.SHARD_ID_PROP, "shard1",
-          ZkStateReader.NODE_NAME_PROP, "node1",
+          ZkStateReader.NODE_NAME_PROP, "127.0.0.1_solr",
           ZkStateReader.COLLECTION_PROP, "c1",
           ZkStateReader.CORE_NAME_PROP, "core1",
           ZkStateReader.ROLES_PROP, "",
@@ -1359,9 +1348,8 @@ public class OverseerTest extends SolrTestCaseJ4 {
       m = new ZkNodeProps(Overseer.QUEUE_OPERATION, CollectionParams.CollectionAction.ADDREPLICA.toLower(),
           "collection", "test",
           ZkStateReader.SHARD_ID_PROP, "x",
-          ZkStateReader.BASE_URL_PROP, "http://127.0.0.1/solr",
           ZkStateReader.CORE_NODE_NAME_PROP, "core_node1",
-          ZkStateReader.NODE_NAME_PROP, "node1",
+          ZkStateReader.NODE_NAME_PROP, "127.0.0.1_solr",
           ZkStateReader.CORE_NAME_PROP, "core1",
           ZkStateReader.STATE_PROP, Replica.State.DOWN.toString()
       );
@@ -1499,9 +1487,8 @@ public class OverseerTest extends SolrTestCaseJ4 {
         for (int ss = 1; ss <= numShards; ++ss) {
           final int N = (numReplicas-rr)*numShards + ss;
           ZkNodeProps m = new ZkNodeProps(Overseer.QUEUE_OPERATION, OverseerAction.STATE.toLower(),
-              ZkStateReader.BASE_URL_PROP, "http://127.0.0.1/solr",
               ZkStateReader.SHARD_ID_PROP, "shard"+ss,
-              ZkStateReader.NODE_NAME_PROP, "node"+N,
+              ZkStateReader.NODE_NAME_PROP, "127.0.0.1_solr",
               ZkStateReader.COLLECTION_PROP, COLLECTION,
               ZkStateReader.CORE_NAME_PROP, "core"+N,
               ZkStateReader.CORE_NODE_NAME_PROP, "core_node"+N,
@@ -1524,9 +1511,8 @@ public class OverseerTest extends SolrTestCaseJ4 {
         for (int ss = 1; ss <= numShards; ++ss) {
           final int N = (numReplicas-rr)*numShards + ss;
           ZkNodeProps m = new ZkNodeProps(Overseer.QUEUE_OPERATION, OverseerAction.STATE.toLower(),
-              ZkStateReader.BASE_URL_PROP, "http://127.0.0.1/solr",
               ZkStateReader.SHARD_ID_PROP, "shard"+ss,
-              ZkStateReader.NODE_NAME_PROP, "node"+N,
+              ZkStateReader.NODE_NAME_PROP, "127.0.0.1_solr",
               ZkStateReader.COLLECTION_PROP, COLLECTION,
               ZkStateReader.CORE_NAME_PROP, "core"+N,
               ZkStateReader.ROLES_PROP, "",
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestLeaderElectionWithEmptyReplica.java b/solr/core/src/test/org/apache/solr/cloud/TestLeaderElectionWithEmptyReplica.java
index f0bb15a..f8d7b5a 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestLeaderElectionWithEmptyReplica.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestLeaderElectionWithEmptyReplica.java
@@ -35,8 +35,6 @@ import org.apache.solr.common.cloud.Slice;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
-import static org.apache.solr.common.cloud.ZkStateReader.BASE_URL_PROP;
-
 /**
  * See SOLR-9504
  */
@@ -73,7 +71,7 @@ public class TestLeaderElectionWithEmptyReplica extends SolrCloudTestCase {
     List<JettySolrRunner> jettySolrRunners = cluster.getJettySolrRunners();
     for (JettySolrRunner jettySolrRunner : jettySolrRunners) {
       int port = jettySolrRunner.getBaseUrl().getPort();
-      if (replica.getStr(BASE_URL_PROP).contains(":" + port))  {
+      if (replica.getBaseUrl().contains(":" + port))  {
         replicaJetty = jettySolrRunner;
         break;
       }
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterSSL.java b/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterSSL.java
index 4c45537..ffe0f7b 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterSSL.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestMiniSolrCloudClusterSSL.java
@@ -45,6 +45,7 @@ import org.apache.solr.client.solrj.impl.HttpClientUtil;
 import org.apache.solr.client.solrj.impl.HttpSolrClient;
 import org.apache.solr.client.solrj.request.CollectionAdminRequest;
 import org.apache.solr.client.solrj.request.CoreAdminRequest;
+import org.apache.solr.common.cloud.UrlScheme;
 import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.params.CoreAdminParams.CoreAdminAction;
 import org.apache.solr.util.SSLTestConfig;
@@ -104,6 +105,7 @@ public class TestMiniSolrCloudClusterSSL extends SolrTestCaseJ4 {
     HttpClientUtil.setSocketFactoryRegistryProvider(sslConfig.buildClientSocketFactoryRegistryProvider());
     Http2SolrClient.setDefaultSSLConfig(sslConfig.buildClientSSLConfig());
     System.setProperty(ZkStateReader.URL_SCHEME, "http");
+    UrlScheme.INSTANCE.setUrlScheme(UrlScheme.HTTP);
     checkClusterWithNodeReplacement(sslConfig);
   }
   
@@ -115,6 +117,7 @@ public class TestMiniSolrCloudClusterSSL extends SolrTestCaseJ4 {
     HttpClientUtil.setSocketFactoryRegistryProvider(sslConfig.buildClientSocketFactoryRegistryProvider());
     Http2SolrClient.setDefaultSSLConfig(sslConfig.buildClientSSLConfig());
     System.setProperty(ZkStateReader.URL_SCHEME, "http");
+    UrlScheme.INSTANCE.setUrlScheme(UrlScheme.HTTP);
     checkClusterWithNodeReplacement(sslConfig);
   }
   
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 e14942c..d4054da 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestRandomRequestDistribution.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestRandomRequestDistribution.java
@@ -111,7 +111,7 @@ public class TestRandomRequestDistribution extends AbstractFullDistribZkTestBase
     DocCollection b1x1 = clusterState.getCollection("b1x1");
     Collection<Replica> replicas = b1x1.getSlice("shard1").getReplicas();
     assertEquals(1, replicas.size());
-    String baseUrl = replicas.iterator().next().getStr(ZkStateReader.BASE_URL_PROP);
+    String baseUrl = replicas.iterator().next().getBaseUrl();
     if (!baseUrl.endsWith("/")) baseUrl += "/";
     try (HttpSolrClient client = getHttpSolrClient(baseUrl + "a1x2", 2000, 5000)) {
 
@@ -170,7 +170,6 @@ public class TestRandomRequestDistribution extends AbstractFullDistribZkTestBase
 
     //Simulate a replica being in down state.
     ZkNodeProps m = new ZkNodeProps(Overseer.QUEUE_OPERATION, OverseerAction.STATE.toLower(),
-        ZkStateReader.BASE_URL_PROP, notLeader.getStr(ZkStateReader.BASE_URL_PROP),
         ZkStateReader.NODE_NAME_PROP, notLeader.getStr(ZkStateReader.NODE_NAME_PROP),
         ZkStateReader.COLLECTION_PROP, "football",
         ZkStateReader.SHARD_ID_PROP, "shard1",
@@ -188,7 +187,7 @@ public class TestRandomRequestDistribution extends AbstractFullDistribZkTestBase
 
     //Query against the node which hosts the down replica
 
-    String baseUrl = notLeader.getStr(ZkStateReader.BASE_URL_PROP);
+    String baseUrl = notLeader.getBaseUrl();
     if (!baseUrl.endsWith("/")) baseUrl += "/";
     String path = baseUrl + "football";
     log.info("Firing queries against path={}", path);
diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIDistributedZkTest.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIDistributedZkTest.java
index e32738b..eec0199 100644
--- a/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIDistributedZkTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIDistributedZkTest.java
@@ -626,8 +626,7 @@ public class CollectionsAPIDistributedZkTest extends SolrCloudTestCase {
     Replica newReplica = grabNewReplica(response, getCollectionState(collectionName));
 
     assertEquals("Replica should be created on the right node",
-        cluster.getSolrClient().getZkStateReader().getBaseUrlForNodeName(nodeList.get(0)),
-        newReplica.getStr(ZkStateReader.BASE_URL_PROP));
+        cluster.getSolrClient().getZkStateReader().getBaseUrlForNodeName(nodeList.get(0)), newReplica.getBaseUrl());
 
     Path instancePath = createTempDir();
     response = CollectionAdminRequest.addReplicaToShard(collectionName, "shard1")
@@ -636,7 +635,7 @@ public class CollectionsAPIDistributedZkTest extends SolrCloudTestCase {
     newReplica = grabNewReplica(response, getCollectionState(collectionName));
     assertNotNull(newReplica);
 
-    try (HttpSolrClient coreclient = getHttpSolrClient(newReplica.getStr(ZkStateReader.BASE_URL_PROP))) {
+    try (HttpSolrClient coreclient = getHttpSolrClient(newReplica.getBaseUrl())) {
       CoreAdminResponse status = CoreAdminRequest.getStatus(newReplica.getStr("core"), coreclient);
       NamedList<Object> coreStatus = status.getCoreStatus(newReplica.getStr("core"));
       String instanceDirStr = (String) coreStatus.get("instanceDir");
diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/ShardSplitTest.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/ShardSplitTest.java
index 41169a4..e3b2634 100644
--- a/solr/core/src/test/org/apache/solr/cloud/api/collections/ShardSplitTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/ShardSplitTest.java
@@ -73,7 +73,6 @@ import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static org.apache.solr.common.cloud.ZkStateReader.BASE_URL_PROP;
 import static org.apache.solr.common.cloud.ZkStateReader.MAX_SHARDS_PER_NODE;
 import static org.apache.solr.common.cloud.ZkStateReader.REPLICATION_FACTOR;
 
@@ -193,7 +192,7 @@ public class ShardSplitTest extends BasicDistributedZkTest {
           boolean restarted = false;
           for (JettySolrRunner jetty : jettys) {
             int port = jetty.getBaseUrl().getPort();
-            if (replica.getStr(BASE_URL_PROP).contains(":" + port))  {
+            if (replica.getBaseUrl().contains(":" + port))  {
               stoppedNodeName = jetty.getNodeName();
               jetty.stop();
               jetty.start();
@@ -212,7 +211,7 @@ public class ShardSplitTest extends BasicDistributedZkTest {
           CollectionAdminRequest.AddReplica addReplica = CollectionAdminRequest.addReplicaToShard(collectionName, SHARD1_0);
           // use control client because less chances of it being the node being restarted
           // this is to avoid flakiness of test because of NoHttpResponseExceptions
-          String control_collection = client.getZkStateReader().getClusterState().getCollection("control_collection").getReplicas().get(0).getStr(BASE_URL_PROP);
+          String control_collection = client.getZkStateReader().getClusterState().getCollection("control_collection").getReplicas().get(0).getBaseUrl();
           try (HttpSolrClient control = new HttpSolrClient.Builder(control_collection).withHttpClient(client.getLbClient().getHttpClient()).build())  {
             state = addReplica.processAndWait(control, 30);
           }
diff --git a/solr/core/src/test/org/apache/solr/core/snapshots/TestSolrCloudSnapshots.java b/solr/core/src/test/org/apache/solr/core/snapshots/TestSolrCloudSnapshots.java
index 4a3678b..7570051 100644
--- a/solr/core/src/test/org/apache/solr/core/snapshots/TestSolrCloudSnapshots.java
+++ b/solr/core/src/test/org/apache/solr/core/snapshots/TestSolrCloudSnapshots.java
@@ -16,8 +16,6 @@
  */
 package org.apache.solr.core.snapshots;
 
-import static org.apache.solr.common.cloud.ZkStateReader.BASE_URL_PROP;
-
 import java.lang.invoke.MethodHandles;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -27,8 +25,8 @@ import java.util.Optional;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
-import org.apache.lucene.util.TestUtil;
 import org.apache.lucene.util.LuceneTestCase.Slow;
+import org.apache.lucene.util.TestUtil;
 import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.impl.CloudSolrClient;
@@ -42,7 +40,6 @@ import org.apache.solr.common.cloud.DocCollection;
 import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.cloud.Replica.State;
 import org.apache.solr.common.cloud.Slice;
-import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.core.snapshots.CollectionSnapshotMetaData.CoreSnapshotMetaData;
 import org.apache.solr.core.snapshots.SolrSnapshotMetaDataManager.SnapshotMetaData;
@@ -146,8 +143,8 @@ public class TestSolrCloudSnapshots extends SolrCloudTestCase {
           continue; // We know that the snapshot is not created for this replica.
         }
 
-        String replicaBaseUrl = replica.getStr(BASE_URL_PROP);
-        String coreName = replica.getStr(ZkStateReader.CORE_NAME_PROP);
+        String replicaBaseUrl = replica.getBaseUrl();
+        String coreName = replica.getCoreName();
 
         assertTrue(snapshotByCoreName.containsKey(coreName));
         CoreSnapshotMetaData coreSnapshot = snapshotByCoreName.get(coreName);
@@ -256,8 +253,8 @@ public class TestSolrCloudSnapshots extends SolrCloudTestCase {
           continue; // We know that the snapshot was not created for this replica.
         }
 
-        String replicaBaseUrl = replica.getStr(BASE_URL_PROP);
-        String coreName = replica.getStr(ZkStateReader.CORE_NAME_PROP);
+        String replicaBaseUrl = replica.getBaseUrl();
+        String coreName = replica.getCoreName();
 
         try (SolrClient adminClient = getHttpSolrClient(replicaBaseUrl)) {
           Collection<SnapshotMetaData> snapshots = listCoreSnapshots(adminClient, coreName);
diff --git a/solr/core/src/test/org/apache/solr/core/snapshots/TestSolrCoreSnapshots.java b/solr/core/src/test/org/apache/solr/core/snapshots/TestSolrCoreSnapshots.java
index 2593c35..0caa9f4 100644
--- a/solr/core/src/test/org/apache/solr/core/snapshots/TestSolrCoreSnapshots.java
+++ b/solr/core/src/test/org/apache/solr/core/snapshots/TestSolrCoreSnapshots.java
@@ -55,8 +55,6 @@ import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static org.apache.solr.common.cloud.ZkStateReader.BASE_URL_PROP;
-
 @SolrTestCaseJ4.SuppressSSL // Currently unknown why SSL does not work with this test
 @Slow
 public class TestSolrCoreSnapshots extends SolrCloudTestCase {
@@ -96,8 +94,8 @@ public class TestSolrCoreSnapshots extends SolrCloudTestCase {
     assertEquals(1, shard.getReplicas().size());
     Replica replica = shard.getReplicas().iterator().next();
 
-    String replicaBaseUrl = replica.getStr(BASE_URL_PROP);
-    String coreName = replica.getStr(ZkStateReader.CORE_NAME_PROP);
+    String replicaBaseUrl = replica.getBaseUrl();
+    String coreName = replica.getCoreName();
     String backupName = TestUtil.randomSimpleString(random(), 1, 5);
     String commitName = TestUtil.randomSimpleString(random(), 1, 5);
     String duplicateName = commitName.concat("_duplicate");
diff --git a/solr/core/src/test/org/apache/solr/handler/TestBlobHandler.java b/solr/core/src/test/org/apache/solr/handler/TestBlobHandler.java
index c6c1dfe..8c4003d 100644
--- a/solr/core/src/test/org/apache/solr/handler/TestBlobHandler.java
+++ b/solr/core/src/test/org/apache/solr/handler/TestBlobHandler.java
@@ -39,7 +39,6 @@ import org.apache.solr.cloud.AbstractFullDistribZkTestBase;
 import org.apache.solr.common.MapWriter;
 import org.apache.solr.common.cloud.DocCollection;
 import org.apache.solr.common.cloud.Replica;
-import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.util.StrUtils;
 import org.apache.solr.util.RTimer;
 import org.apache.solr.util.SimplePostTool;
@@ -66,7 +65,7 @@ public class TestBlobHandler extends AbstractFullDistribZkTestBase {
       DocCollection sysColl = cloudClient.getZkStateReader().getClusterState().getCollection(".system");
       Replica replica = sysColl.getActiveSlicesMap().values().iterator().next().getLeader();
 
-      String baseUrl = replica.getStr(ZkStateReader.BASE_URL_PROP);
+      String baseUrl = replica.getBaseUrl();
       String url = baseUrl + "/.system/config/requestHandler";
       MapWriter map = TestSolrConfigHandlerConcurrent.getAsMap(url, cloudClient);
       assertNotNull(map);
diff --git a/solr/core/src/test/org/apache/solr/handler/TestConfigReload.java b/solr/core/src/test/org/apache/solr/handler/TestConfigReload.java
index 49ec80b..ff19501 100644
--- a/solr/core/src/test/org/apache/solr/handler/TestConfigReload.java
+++ b/solr/core/src/test/org/apache/solr/handler/TestConfigReload.java
@@ -96,7 +96,7 @@ public class TestConfigReload extends AbstractFullDistribZkTestBase {
     List<String> urls = new ArrayList<>();
     for (Slice slice : coll.getSlices()) {
       for (Replica replica : slice.getReplicas())
-        urls.add(""+replica.get(ZkStateReader.BASE_URL_PROP) + "/"+replica.get(ZkStateReader.CORE_NAME_PROP));
+        urls.add(""+replica.getBaseUrl() + "/" + replica.get(ZkStateReader.CORE_NAME_PROP));
     }
     HashSet<String> succeeded = new HashSet<>();
 
diff --git a/solr/core/src/test/org/apache/solr/handler/TestHdfsBackupRestoreCore.java b/solr/core/src/test/org/apache/solr/handler/TestHdfsBackupRestoreCore.java
index 3347c02..cf9d1c0 100644
--- a/solr/core/src/test/org/apache/solr/handler/TestHdfsBackupRestoreCore.java
+++ b/solr/core/src/test/org/apache/solr/handler/TestHdfsBackupRestoreCore.java
@@ -46,7 +46,6 @@ import org.apache.solr.common.SolrInputDocument;
 import org.apache.solr.common.cloud.DocCollection;
 import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.cloud.Slice;
-import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.params.CoreAdminParams;
 import org.apache.solr.common.params.CoreAdminParams.CoreAdminAction;
 import org.apache.solr.util.BadHdfsThreadsFilter;
@@ -56,8 +55,6 @@ import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static org.apache.solr.common.cloud.ZkStateReader.BASE_URL_PROP;
-
 @ThreadLeakFilters(defaultFilters = true, filters = {
     SolrIgnoredThreadsFilter.class,
     QuickPatchThreadsFilter.class,
@@ -179,8 +176,8 @@ public class TestHdfsBackupRestoreCore extends SolrCloudTestCase {
     assertEquals(1, shard.getReplicas().size());
     Replica replica = shard.getReplicas().iterator().next();
 
-    String replicaBaseUrl = replica.getStr(BASE_URL_PROP);
-    String coreName = replica.getStr(ZkStateReader.CORE_NAME_PROP);
+    String replicaBaseUrl = replica.getBaseUrl();
+    String coreName = replica.getCoreName();
     String backupName = TestUtil.randomSimpleString(random(), 1, 5);
 
     boolean testViaReplicationHandler = random().nextBoolean();
diff --git a/solr/core/src/test/org/apache/solr/handler/TestReqParamsAPI.java b/solr/core/src/test/org/apache/solr/handler/TestReqParamsAPI.java
index 5c52bf4..dea016b 100644
--- a/solr/core/src/test/org/apache/solr/handler/TestReqParamsAPI.java
+++ b/solr/core/src/test/org/apache/solr/handler/TestReqParamsAPI.java
@@ -85,7 +85,7 @@ public class TestReqParamsAPI extends SolrCloudTestCase {
     List<String> urls = new ArrayList<>();
     for (Slice slice : coll.getSlices()) {
       for (Replica replica : slice.getReplicas())
-        urls.add("" + replica.get(ZkStateReader.BASE_URL_PROP) + "/" + replica.get(ZkStateReader.CORE_NAME_PROP));
+        urls.add("" + replica.getBaseUrl() + "/" + replica.get(ZkStateReader.CORE_NAME_PROP));
     }
 
     RestTestHarness writeHarness = restTestHarnesses.get(random().nextInt(restTestHarnesses.size()));
diff --git a/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerCloud.java b/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerCloud.java
index 662354a..53072d0 100644
--- a/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerCloud.java
+++ b/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerCloud.java
@@ -85,7 +85,7 @@ public class TestSolrConfigHandlerCloud extends AbstractFullDistribZkTestBase {
     List<String> urls = new ArrayList<>();
     for (Slice slice : coll.getSlices()) {
       for (Replica replica : slice.getReplicas())
-        urls.add(""+replica.get(ZkStateReader.BASE_URL_PROP) + "/"+replica.get(ZkStateReader.CORE_NAME_PROP));
+        urls.add(""+replica.getBaseUrl() + "/" + replica.get(ZkStateReader.CORE_NAME_PROP));
     }
     return urls.get(random().nextInt(urls.size()));
   }
@@ -95,7 +95,7 @@ public class TestSolrConfigHandlerCloud extends AbstractFullDistribZkTestBase {
     List<String> urls = new ArrayList<>();
     for (Slice slice : coll.getSlices()) {
       for (Replica replica : slice.getReplicas())
-        urls.add(""+replica.get(ZkStateReader.BASE_URL_PROP) + "/"+replica.get(ZkStateReader.CORE_NAME_PROP));
+        urls.add(""+replica.getBaseUrl() + "/" + replica.get(ZkStateReader.CORE_NAME_PROP));
     }
 
     RestTestHarness writeHarness = randomRestTestHarness();
diff --git a/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerConcurrent.java b/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerConcurrent.java
index 1b43808..c7c3598 100644
--- a/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerConcurrent.java
+++ b/solr/core/src/test/org/apache/solr/handler/TestSolrConfigHandlerConcurrent.java
@@ -146,7 +146,7 @@ public class TestSolrConfigHandlerConcurrent extends AbstractFullDistribZkTestBa
       List<String> urls = new ArrayList<>();
       for (Slice slice : coll.getSlices()) {
         for (Replica replica : slice.getReplicas())
-          urls.add(""+replica.get(ZkStateReader.BASE_URL_PROP) + "/"+replica.get(ZkStateReader.CORE_NAME_PROP));
+          urls.add(""+replica.getBaseUrl() + "/" + replica.get(ZkStateReader.CORE_NAME_PROP));
       }
 
 
diff --git a/solr/core/src/test/org/apache/solr/handler/component/CloudReplicaSourceTest.java b/solr/core/src/test/org/apache/solr/handler/component/CloudReplicaSourceTest.java
index 186af33..aa8e887 100644
--- a/solr/core/src/test/org/apache/solr/handler/component/CloudReplicaSourceTest.java
+++ b/solr/core/src/test/org/apache/solr/handler/component/CloudReplicaSourceTest.java
@@ -31,6 +31,7 @@ import org.mockito.Mockito;
 /**
  * Tests for {@link CloudReplicaSource}
  */
+@SolrTestCaseJ4.SuppressSSL // lots of assumptions about http: in this test
 public class CloudReplicaSourceTest extends SolrTestCaseJ4 {
 
   @BeforeClass
diff --git a/solr/core/src/test/org/apache/solr/index/hdfs/CheckHdfsIndexTest.java b/solr/core/src/test/org/apache/solr/index/hdfs/CheckHdfsIndexTest.java
index 20bc306..7285d34 100644
--- a/solr/core/src/test/org/apache/solr/index/hdfs/CheckHdfsIndexTest.java
+++ b/solr/core/src/test/org/apache/solr/index/hdfs/CheckHdfsIndexTest.java
@@ -26,6 +26,7 @@ import org.apache.lucene.index.BaseTestCheckIndex;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.util.QuickPatchThreadsFilter;
 import org.apache.solr.SolrIgnoredThreadsFilter;
+import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.SolrQuery;
 import org.apache.solr.cloud.AbstractFullDistribZkTestBase;
@@ -47,6 +48,7 @@ import com.carrotsearch.randomizedtesting.annotations.ThreadLeakFilters;
     QuickPatchThreadsFilter.class,
     BadHdfsThreadsFilter.class // hdfs currently leaks thread(s)
 })
+@SolrTestCaseJ4.SuppressSSL
 // commented out on: 24-Dec-2018 @LuceneTestCase.BadApple(bugUrl="https://issues.apache.org/jira/browse/SOLR-12028") // 12-Jun-2018
 public class CheckHdfsIndexTest extends AbstractFullDistribZkTestBase {
   private static MiniDFSCluster dfsCluster;
diff --git a/solr/core/src/test/org/apache/solr/update/SolrCmdDistributorTest.java b/solr/core/src/test/org/apache/solr/update/SolrCmdDistributorTest.java
index 77f5a89..ce95592 100644
--- a/solr/core/src/test/org/apache/solr/update/SolrCmdDistributorTest.java
+++ b/solr/core/src/test/org/apache/solr/update/SolrCmdDistributorTest.java
@@ -375,11 +375,8 @@ public class SolrCmdDistributorTest extends BaseDistributedSearchTestCase {
       }
       ArrayList<Node> nodes = new ArrayList<>();
 
-      ZkNodeProps nodeProps = new ZkNodeProps(ZkStateReader.BASE_URL_PROP, solrclient.getBaseURL(),
-          ZkStateReader.CORE_NAME_PROP, "");
-
       final AtomicInteger retries = new AtomicInteger();
-      nodeProps = new ZkNodeProps(ZkStateReader.BASE_URL_PROP, solrclient.getBaseURL(), ZkStateReader.CORE_NAME_PROP, "");
+      ZkNodeProps nodeProps = new ZkNodeProps(ZkStateReader.BASE_URL_PROP, solrclient.getBaseURL(), ZkStateReader.CORE_NAME_PROP, "");
       Node retryNode = new StdNode(new ZkCoreNodeProps(nodeProps), "collection1", "shard1", 5) {
         @Override
         public boolean checkRetry(Error err) {
@@ -439,11 +436,8 @@ public class SolrCmdDistributorTest extends BaseDistributedSearchTestCase {
       streamingClients.setExp(Exp.CONNECT_EXCEPTION);
       ArrayList<Node> nodes = new ArrayList<>();
 
-      ZkNodeProps nodeProps = new ZkNodeProps(ZkStateReader.BASE_URL_PROP, solrclient.getBaseURL(),
-          ZkStateReader.CORE_NAME_PROP, "");
-
       final AtomicInteger retries = new AtomicInteger();
-      nodeProps = new ZkNodeProps(ZkStateReader.BASE_URL_PROP, solrclient.getBaseURL(), ZkStateReader.CORE_NAME_PROP, "");
+      ZkNodeProps nodeProps = new ZkNodeProps(ZkStateReader.BASE_URL_PROP, solrclient.getBaseURL(), ZkStateReader.CORE_NAME_PROP, "");
       if (nodeType == NodeType.FORWARD) {
         nodes.add(new ForwardNode(new ZkCoreNodeProps(nodeProps), null, "collection1", "shard1", 5) {
           @Override
@@ -594,11 +588,8 @@ public class SolrCmdDistributorTest extends BaseDistributedSearchTestCase {
       streamingClients.setExp(Exp.CONNECT_EXCEPTION);
       ArrayList<Node> nodes = new ArrayList<>();
 
-      ZkNodeProps nodeProps = new ZkNodeProps(ZkStateReader.BASE_URL_PROP, solrclient.getBaseURL(),
-          ZkStateReader.CORE_NAME_PROP, "");
-
       final AtomicInteger retries = new AtomicInteger();
-      nodeProps = new ZkNodeProps(ZkStateReader.BASE_URL_PROP, solrclient.getBaseURL(), ZkStateReader.CORE_NAME_PROP, "");
+      ZkNodeProps nodeProps = new ZkNodeProps(ZkStateReader.BASE_URL_PROP, solrclient.getBaseURL(), ZkStateReader.CORE_NAME_PROP, "");
       Node retryNode;
       if (nodeType == NodeType.FORWARD) {
         retryNode = new ForwardNode(new ZkCoreNodeProps(nodeProps), null, "collection1", "shard1", 5) {
@@ -711,11 +702,8 @@ public class SolrCmdDistributorTest extends BaseDistributedSearchTestCase {
       streamingClients.setExp(Exp.SOCKET_EXCEPTION);
       ArrayList<Node> nodes = new ArrayList<>();
 
-      ZkNodeProps nodeProps = new ZkNodeProps(ZkStateReader.BASE_URL_PROP, solrclient.getBaseURL(),
-          ZkStateReader.CORE_NAME_PROP, "");
-
       final AtomicInteger retries = new AtomicInteger();
-      nodeProps = new ZkNodeProps(ZkStateReader.BASE_URL_PROP, solrclient.getBaseURL(), ZkStateReader.CORE_NAME_PROP, "");
+      ZkNodeProps nodeProps = new ZkNodeProps(ZkStateReader.BASE_URL_PROP, solrclient.getBaseURL(), ZkStateReader.CORE_NAME_PROP, "");
       ForwardNode retryNode = new ForwardNode(new ZkCoreNodeProps(nodeProps), null, "collection1", "shard1", 5) {
         @Override
         public boolean checkRetry(Error err) {
@@ -758,11 +746,8 @@ public class SolrCmdDistributorTest extends BaseDistributedSearchTestCase {
       streamingClients.setExp(Exp.SOCKET_EXCEPTION);
       ArrayList<Node> nodes = new ArrayList<>();
 
-      ZkNodeProps nodeProps = new ZkNodeProps(ZkStateReader.BASE_URL_PROP, solrclient.getBaseURL(),
-          ZkStateReader.CORE_NAME_PROP, "");
-
       final AtomicInteger retries = new AtomicInteger();
-      nodeProps = new ZkNodeProps(ZkStateReader.BASE_URL_PROP, solrclient.getBaseURL(), ZkStateReader.CORE_NAME_PROP, "");
+      ZkNodeProps nodeProps = new ZkNodeProps(ZkStateReader.BASE_URL_PROP, solrclient.getBaseURL(), ZkStateReader.CORE_NAME_PROP, "");
       Node retryNode = new StdNode(new ZkCoreNodeProps(nodeProps), "collection1", "shard1", 5) {
         @Override
         public boolean checkRetry(Error err) {
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BaseCloudSolrClient.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BaseCloudSolrClient.java
index 0fbd114..60d5768 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BaseCloudSolrClient.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/BaseCloudSolrClient.java
@@ -71,6 +71,7 @@ import org.apache.solr.common.cloud.DocRouter;
 import org.apache.solr.common.cloud.ImplicitDocRouter;
 import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.cloud.Slice;
+import org.apache.solr.common.cloud.UrlScheme;
 import org.apache.solr.common.cloud.ZkCoreNodeProps;
 import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.params.ModifiableSolrParams;
@@ -83,7 +84,6 @@ import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
 import org.apache.solr.common.util.SolrNamedThreadFactory;
 import org.apache.solr.common.util.StrUtils;
-import org.apache.solr.common.util.Utils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.MDC;
@@ -1096,14 +1096,12 @@ public abstract class BaseCloudSolrClient extends SolrClient {
       if (!liveNodes.isEmpty()) {
         List<String> liveNodesList = new ArrayList<>(liveNodes);
         Collections.shuffle(liveNodesList, rand);
-        theUrlList.add(Utils.getBaseUrlForNodeName(liveNodesList.get(0),
-            getClusterStateProvider().getClusterProperty(ZkStateReader.URL_SCHEME,"http")));
+        theUrlList.add(UrlScheme.INSTANCE.getBaseUrlForNodeName(liveNodesList.get(0)));
       }
 
     } else if (ADMIN_PATHS.contains(request.getPath())) {
       for (String liveNode : liveNodes) {
-        theUrlList.add(Utils.getBaseUrlForNodeName(liveNode,
-            getClusterStateProvider().getClusterProperty(ZkStateReader.URL_SCHEME,"http")));
+        theUrlList.add(UrlScheme.INSTANCE.getBaseUrlForNodeName(liveNode));
       }
 
     } else { // Typical...
diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/ClusterStateUtil.java b/solr/solrj/src/java/org/apache/solr/common/cloud/ClusterStateUtil.java
index 5e61bc1..9ce8090 100644
--- a/solr/solrj/src/java/org/apache/solr/common/cloud/ClusterStateUtil.java
+++ b/solr/solrj/src/java/org/apache/solr/common/cloud/ClusterStateUtil.java
@@ -141,7 +141,7 @@ public class ClusterStateUtil {
               // on a live node?
               boolean live = clusterState.liveNodesContain(replica.getNodeName());
               String rcoreNodeName = replica.getName();
-              String rbaseUrl = replica.getStr(ZkStateReader.BASE_URL_PROP);
+              String rbaseUrl = replica.getBaseUrl();
               if (live && coreNodeName.equals(rcoreNodeName)
                   && baseUrl.equals(rbaseUrl)) {
                 // found it
diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/Replica.java b/solr/solrj/src/java/org/apache/solr/common/cloud/Replica.java
index a022ed2..eef3f89 100644
--- a/solr/solrj/src/java/org/apache/solr/common/cloud/Replica.java
+++ b/solr/solrj/src/java/org/apache/solr/common/cloud/Replica.java
@@ -22,6 +22,8 @@ import java.util.Objects;
 import java.util.Set;
 
 import org.apache.solr.common.util.Utils;
+import static org.apache.solr.common.cloud.ZkStateReader.BASE_URL_PROP;
+
 public class Replica extends ZkNodeProps {
   
   /**
@@ -133,6 +135,7 @@ public class Replica extends ZkNodeProps {
       this.state = State.ACTIVE;                         //Default to ACTIVE
       propMap.put(ZkStateReader.STATE_PROP, state.toString());
     }
+    propMap.put(BASE_URL_PROP, UrlScheme.INSTANCE.getBaseUrlForNodeName(this.nodeName));
   }
 
   public String getCollection(){
@@ -164,10 +167,11 @@ public class Replica extends ZkNodeProps {
   }
 
   public String getCoreUrl() {
-    return ZkCoreNodeProps.getCoreUrl(getStr(ZkStateReader.BASE_URL_PROP), core);
+    return ZkCoreNodeProps.getCoreUrl(getBaseUrl(), core);
   }
+
   public String getBaseUrl(){
-    return getStr(ZkStateReader.BASE_URL_PROP);
+    return getStr(BASE_URL_PROP);
   }
 
   /** SolrCore name. */
diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/UrlScheme.java b/solr/solrj/src/java/org/apache/solr/common/cloud/UrlScheme.java
new file mode 100644
index 0000000..b459199
--- /dev/null
+++ b/solr/solrj/src/java/org/apache/solr/common/cloud/UrlScheme.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.common.cloud;
+
+import java.util.Objects;
+
+import org.apache.solr.common.util.Utils;
+
+/**
+ * Singleton access to global urlScheme, which although is stored in ZK as a cluster property
+ * really should be treated like a static global that is set at initialization and not altered after.
+ *
+ * Client applications should not use this class directly; it is only included in SolrJ because Replica
+ * and ZkNodeProps depend on it.
+ */
+public enum UrlScheme {
+  INSTANCE;
+
+  public static final String HTTP = "http";
+  public static final String HTTPS = "https";
+  public static final String HTTPS_PORT_PROP = "solr.jetty.https.port";
+
+  private volatile String urlScheme = HTTP;
+
+  /**
+   * Set the global urlScheme variable; ideally this should be immutable once set, but some tests rely on changing
+   * the value on-the-fly.
+   * @param urlScheme The new URL scheme, either http or https.
+   */
+  public void setUrlScheme(final String urlScheme) {
+    if (HTTP.equals(urlScheme) || HTTPS.equals(urlScheme)) {
+      this.urlScheme = urlScheme;
+    } else {
+      throw new IllegalArgumentException("Invalid urlScheme: "+urlScheme);
+    }
+  }
+
+  public String getBaseUrlForNodeName(String nodeName) {
+    Objects.requireNonNull(nodeName,"node_name must not be null");
+    return Utils.getBaseUrlForNodeName(nodeName, urlScheme);
+  }
+
+  /**
+   * Given a URL string with or without a scheme, return a new URL with the correct scheme applied.
+   * @param url A URL to change the scheme (http|https)
+   * @return A new URL with the correct scheme
+   */
+  public String applyUrlScheme(final String url) {
+    Objects.requireNonNull(url, "URL must not be null!");
+
+    // heal an incorrect scheme if needed, otherwise return null indicating no change
+    final int at = url.indexOf("://");
+    return (at == -1) ? (urlScheme + "://" + url) : urlScheme + url.substring(at);
+  }
+
+  public String getUrlScheme() {
+    return urlScheme;
+  }
+}
diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/ZkCoreNodeProps.java b/solr/solrj/src/java/org/apache/solr/common/cloud/ZkCoreNodeProps.java
index 42bcd18..7ac0fbb 100644
--- a/solr/solrj/src/java/org/apache/solr/common/cloud/ZkCoreNodeProps.java
+++ b/solr/solrj/src/java/org/apache/solr/common/cloud/ZkCoreNodeProps.java
@@ -16,15 +16,17 @@
  */
 package org.apache.solr.common.cloud;
 
+import java.util.Objects;
+
 public class ZkCoreNodeProps {
-  private ZkNodeProps nodeProps;
+  private final ZkNodeProps nodeProps;
   
   public ZkCoreNodeProps(ZkNodeProps nodeProps) {
     this.nodeProps = nodeProps;
   }
   
   public String getCoreUrl() {
-    return getCoreUrl(nodeProps.getStr(ZkStateReader.BASE_URL_PROP), nodeProps.getStr(ZkStateReader.CORE_NAME_PROP));
+    return getCoreUrl(this.nodeProps);
   }
   
   public String getNodeName() {
@@ -36,22 +38,35 @@ public class ZkCoreNodeProps {
   }
 
   public String getBaseUrl() {
-    return nodeProps.getStr(ZkStateReader.BASE_URL_PROP);
+    return getBaseUrl(this.nodeProps);
   }
   
   public String getCoreName() {
     return nodeProps.getStr(ZkStateReader.CORE_NAME_PROP);
   }
+
+  private static String getBaseUrl(ZkNodeProps nodeProps) {
+    String baseUrl = null;
+    final String nodeName = nodeProps.getStr(ZkStateReader.NODE_NAME_PROP);
+    if (nodeName != null) {
+      baseUrl = UrlScheme.INSTANCE.getBaseUrlForNodeName(nodeName);
+    } else if (nodeProps.containsKey(ZkStateReader.BASE_URL_PROP)) {
+      baseUrl = UrlScheme.INSTANCE.applyUrlScheme(nodeProps.getStr(ZkStateReader.BASE_URL_PROP));
+    }
+    return baseUrl;
+  }
   
   public static String getCoreUrl(ZkNodeProps nodeProps) {
-    return getCoreUrl(nodeProps.getStr(ZkStateReader.BASE_URL_PROP), nodeProps.getStr(ZkStateReader.CORE_NAME_PROP));
+    String baseUrl = getBaseUrl(nodeProps);
+    return baseUrl != null ? getCoreUrl(baseUrl, nodeProps.getStr(ZkStateReader.CORE_NAME_PROP)) : null;
   }
   
   public static String getCoreUrl(String baseUrl, String coreName) {
+    Objects.requireNonNull(baseUrl,"baseUrl must not be null");
     StringBuilder sb = new StringBuilder();
     sb.append(baseUrl);
     if (!baseUrl.endsWith("/")) sb.append("/");
-    sb.append(coreName);
+    sb.append(coreName != null ? coreName : "");
     if (!(sb.substring(sb.length() - 1).equals("/"))) sb.append("/");
     return sb.toString();
   }
@@ -68,6 +83,4 @@ public class ZkCoreNodeProps {
   public boolean isLeader() {
     return nodeProps.containsKey(ZkStateReader.LEADER_PROP);
   }
-
-
 }
diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/ZkNodeProps.java b/solr/solrj/src/java/org/apache/solr/common/cloud/ZkNodeProps.java
index de3bea6..6f893c9 100644
--- a/solr/solrj/src/java/org/apache/solr/common/cloud/ZkNodeProps.java
+++ b/solr/solrj/src/java/org/apache/solr/common/cloud/ZkNodeProps.java
@@ -17,7 +17,12 @@
 package org.apache.solr.common.cloud;
 
 import java.io.IOException;
-import java.util.*;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
 
 import org.apache.solr.common.util.JavaBinCodec;
 import org.apache.solr.common.util.Utils;
@@ -37,6 +42,13 @@ public class ZkNodeProps implements JSONWriter.Writable {
    */
   public ZkNodeProps(Map<String,Object> propMap) {
     this.propMap = propMap;
+
+    // don't store base_url if we have a node_name to recompute from when we read back from ZK
+    // sub-classes that know they need a base_url (Replica) can eagerly compute in their ctor
+    if (this.propMap.containsKey(ZkStateReader.NODE_NAME_PROP)) {
+      this.propMap.remove(ZkStateReader.BASE_URL_PROP);
+    }
+
     // TODO: store an unmodifiable map, but in a way that guarantees not to wrap more than once.
     // Always wrapping introduces a memory leak.
   }
@@ -90,7 +102,7 @@ public class ZkNodeProps implements JSONWriter.Writable {
    */
   @SuppressWarnings({"unchecked"})
   public static ZkNodeProps load(byte[] bytes) {
-    Map<String, Object> props = null;
+    Map<String, Object> props;
     if (bytes[0] == 2) {
       try (JavaBinCodec jbc = new JavaBinCodec()) {
         props = (Map<String, Object>) jbc.unmarshal(bytes);
@@ -105,15 +117,26 @@ public class ZkNodeProps implements JSONWriter.Writable {
 
   @Override
   public void write(JSONWriter jsonWriter) {
-    jsonWriter.write(propMap);
+    // don't write out the base_url if we have a node_name
+    if (propMap.containsKey(ZkStateReader.BASE_URL_PROP) && propMap.containsKey(ZkStateReader.NODE_NAME_PROP)) {
+      final Map<String,Object> filtered = new HashMap<>();
+      // stream / collect is no good here as the Collector doesn't like null values
+      propMap.forEach((key, value) -> {
+        if (!ZkStateReader.BASE_URL_PROP.equals(key)) {
+          filtered.put(key, value);
+        }
+      });
+      jsonWriter.write(filtered);
+    } else {
+      jsonWriter.write(propMap);
+    }
   }
   
   /**
    * Get a string property value.
    */
   public String getStr(String key) {
-    Object o = propMap.get(key);
-    return o == null ? null : o.toString();
+    return getStr(key, null);
   }
 
   /**
@@ -127,8 +150,17 @@ public class ZkNodeProps implements JSONWriter.Writable {
   /**
    * Get a string property value.
    */
-  public String getStr(String key,String def) {
+  public String getStr(String key, String def) {
     Object o = propMap.get(key);
+
+    // TODO: This "hack" should not be needed but keeping it here b/c we removed the base_url from the map in the ctor
+    if (o == null && def == null && ZkStateReader.BASE_URL_PROP.equals(key)) {
+      final String nodeName = (String)propMap.get(ZkStateReader.NODE_NAME_PROP);
+      if (nodeName != null) {
+        o = UrlScheme.INSTANCE.getBaseUrlForNodeName(nodeName);
+      }
+    }
+
     return o == null ? def : o.toString();
   }
 
@@ -139,14 +171,6 @@ public class ZkNodeProps implements JSONWriter.Writable {
   @Override
   public String toString() {
     return toJSONString(this);
-    /***
-    StringBuilder sb = new StringBuilder();
-    Set<Entry<String,Object>> entries = propMap.entrySet();
-    for(Entry<String,Object> entry : entries) {
-      sb.append(entry.getKey() + "=" + entry.getValue() + "\n");
-    }
-    return sb.toString();
-    ***/
   }
 
   /**
@@ -155,7 +179,7 @@ public class ZkNodeProps implements JSONWriter.Writable {
   public boolean containsKey(String key) {
     return propMap.containsKey(key);
   }
-
+  
   public boolean getBool(String key, boolean b) {
     Object o = propMap.get(key);
     if (o == null) return b;
diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/ZkStateReader.java b/solr/solrj/src/java/org/apache/solr/common/cloud/ZkStateReader.java
index 637545b..fef21b6 100644
--- a/solr/solrj/src/java/org/apache/solr/common/cloud/ZkStateReader.java
+++ b/solr/solrj/src/java/org/apache/solr/common/cloud/ZkStateReader.java
@@ -55,7 +55,11 @@ import org.apache.solr.common.SolrException.ErrorCode;
 import org.apache.solr.common.params.AutoScalingParams;
 import org.apache.solr.common.params.CollectionAdminParams;
 import org.apache.solr.common.params.CoreAdminParams;
-import org.apache.solr.common.util.*;
+import org.apache.solr.common.util.ExecutorUtil;
+import org.apache.solr.common.util.ObjectReleaseTracker;
+import org.apache.solr.common.util.Pair;
+import org.apache.solr.common.util.SolrNamedThreadFactory;
+import org.apache.solr.common.util.Utils;
 import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.KeeperException.NoNodeException;
 import org.apache.zookeeper.WatchedEvent;
@@ -71,6 +75,7 @@ import static java.util.Collections.emptyMap;
 import static java.util.Collections.emptySet;
 import static java.util.Collections.emptySortedSet;
 import static java.util.Collections.unmodifiableSet;
+import static org.apache.solr.common.cloud.UrlScheme.HTTP;
 import static org.apache.solr.common.util.Utils.fromJSON;
 
 public class ZkStateReader implements SolrCloseable {
@@ -924,7 +929,11 @@ public class ZkStateReader implements SolrCloseable {
   }
 
   public String getLeaderUrl(String collection, String shard, int timeout) throws InterruptedException {
-    ZkCoreNodeProps props = new ZkCoreNodeProps(getLeaderRetry(collection, shard, timeout));
+    Replica replica = getLeaderRetry(collection, shard, timeout);
+    if (replica == null || replica.getBaseUrl() == null) {
+      return null;
+    }
+    ZkCoreNodeProps props = new ZkCoreNodeProps(replica);
     return props.getCoreUrl();
   }
 
@@ -1129,6 +1138,9 @@ public class ZkStateReader implements SolrCloseable {
           this.clusterProperties = ClusterProperties.convertCollectionDefaultsToNestedFormat((Map<String, Object>) Utils.fromJSON(data));
           log.debug("Loaded cluster properties: {}", this.clusterProperties);
 
+          // Make the urlScheme globally accessible
+          UrlScheme.INSTANCE.setUrlScheme(getClusterProperty(ZkStateReader.URL_SCHEME, HTTP));
+
           for (ClusterPropertiesListener listener : clusterPropertiesListeners) {
             listener.onChange(getClusterProperties());
           }
diff --git a/solr/solrj/src/test-files/solrj/solr/autoscaling/testAutoscalingPreferencesUsedWithNoPolicy.json b/solr/solrj/src/test-files/solrj/solr/autoscaling/testAutoscalingPreferencesUsedWithNoPolicy.json
index a4c39d4..d32e894 100644
--- a/solr/solrj/src/test-files/solrj/solr/autoscaling/testAutoscalingPreferencesUsedWithNoPolicy.json
+++ b/solr/solrj/src/test-files/solrj/solr/autoscaling/testAutoscalingPreferencesUsedWithNoPolicy.json
@@ -1,8 +1,8 @@
 {
-  "liveNodes":["node1:8983",
-    "node2:8984",
-    "node3:8985"],
-  "replicaInfo":{"node1:8983":{"c1":{
+  "liveNodes":["node1:8983_",
+    "node2:8984_",
+    "node3:8985_"],
+  "replicaInfo":{"node1:8983_":{"c1":{
     "s1":[{"r1":{
       "type":"NRT",
       "INDEX.sizeInGB":"1100"}},
@@ -12,17 +12,17 @@
       "INDEX.sizeInGB":"1100"}},
       {"r2":{"type":"NRT"}}]}}},
   "nodeValues":{
-    "node1:8983":{
+    "node1:8983_":{
       "cores":4,
       "freedisk":300,
       "totaldisk":4700,
       "port":8983},
-    "node2:8984":{
+    "node2:8984_":{
       "cores":0,
       "freedisk":1000,
       "totaldisk":1200,
       "port":8984},
-    "node3:8985":{
+    "node3:8985_":{
       "cores":0,
       "freedisk":1651,
       "totaldisk":1700,
@@ -34,20 +34,20 @@
     "s1":{"replicas":{
       "r1":{
         "type":"NRT",
-        "node_name":"node1:8983",
+        "node_name":"node1:8983_",
         "state":"active",
         "leader":"true"},
       "r2":{
         "type":"NRT",
-        "node_name":"node1:8983",
+        "node_name":"node1:8983_",
         "state":"active"}}},
     "s2":{"replicas":{
       "r1":{
         "type":"NRT",
-        "node_name":"node1:8983",
+        "node_name":"node1:8983_",
         "state":"active",
         "leader":"true"},
       "r2":{
         "type":"NRT",
-        "node_name":"node1:8983",
+        "node_name":"node1:8983_",
         "state":"active"}}}}}}}
diff --git a/solr/solrj/src/test-files/solrj/solr/autoscaling/testEqualOnNonNode.json b/solr/solrj/src/test-files/solrj/solr/autoscaling/testEqualOnNonNode.json
index c2dc13d..e1205ab 100644
--- a/solr/solrj/src/test-files/solrj/solr/autoscaling/testEqualOnNonNode.json
+++ b/solr/solrj/src/test-files/solrj/solr/autoscaling/testEqualOnNonNode.json
@@ -6,59 +6,53 @@
       "replicas":{
         "r1":{//east
           "core":"r1",
-          "base_url":"http://10.0.0.4:8983/solr",
-          "node_name":"node1",
+          "node_name":"node1_",
           "state":"active"},
         "r2":{//west
           "core":"r2",
-          "base_url":"http://10.0.0.4:7574/solr",
-          "node_name":"node2",
+          "node_name":"node2_",
           "state":"active"}}},
     "shard2":{
       "range":"0-7fffffff",
       "replicas":{
         "r3":{//east
           "core":"r3",
-          "base_url":"http://10.0.0.4:8983/solr",
-          "node_name":"node1",
+          "node_name":"node1_",
           "state":"active"},
         "r4":{//west
           "core":"r4",
-          "base_url":"http://10.0.0.4:8987/solr",
-          "node_name":"node4",
+          "node_name":"node4_",
           "state":"active"},
         "r6":{//east
           "core":"r6",
-          "base_url":"http://10.0.0.4:8989/solr",
-          "node_name":"node3",
+          "node_name":"node3_",
           "state":"active"},
         "r5":{//east
           "core":"r5",
-          "base_url":"http://10.0.0.4:8983/solr",
-          "node_name":"node1",
+          "node_name":"node1_",
           "state":"active"}}}}}},
   {"nodeValues":{
-    "node1":{
+    "node1_":{
       "cores":3,
       "freedisk":700,
       "totaldisk":1000,
       "sysprop.zone":"east"},
-    "node2":{
+    "node2_":{
       "cores":1,
       "freedisk":900,
       "totaldisk":1000,
       "sysprop.zone":"west"},
-    "node3":{
+    "node3_":{
       "cores":1,
       "freedisk":900,
       "totaldisk":1000,
       "sysprop.zone":"east"},
-    "node4":{
+    "node4_":{
       "cores":1,
       "freedisk":900,
       "totaldisk":1000,
       "sysprop.zone":"west"},
-    "node5":{
+    "node5_":{
       "cores":0,
       "freedisk":1000,
       "totaldisk":1000,
diff --git a/solr/solrj/src/test-files/solrj/solr/autoscaling/testFreeDiskDeviation.json b/solr/solrj/src/test-files/solrj/solr/autoscaling/testFreeDiskDeviation.json
index 10e3670..0a05b3e 100644
--- a/solr/solrj/src/test-files/solrj/solr/autoscaling/testFreeDiskDeviation.json
+++ b/solr/solrj/src/test-files/solrj/solr/autoscaling/testFreeDiskDeviation.json
@@ -1,32 +1,32 @@
 {
   "liveNodes": [
-    "node1",
-    "node2",
-    "node3"
+    "node1_",
+    "node2_",
+    "node3_"
   ],
   "replicaInfo": {
-    "node1": {
+    "node1_": {
       "mycoll1": {
         "shard3": [{"r3": {"type": "NRT", "INDEX.sizeInGB": 700}}],
         "shard4": [{"r4": {"type": "NRT", "INDEX.sizeInGB": 400}}]
       }
     },
-    "node2": {
+    "node2_": {
       "mycoll1": {
         "shard1": [{"r1": {"type": "NRT", "INDEX.sizeInGB": 450}}],
         "shard2": [{"r2": {"type": "NRT", "INDEX.sizeInGB": 750}}]
       }
     },
-    "node3": {
+    "node3_": {
       "mycoll2": {
         "shard1": [{"r1": {"type": "NRT", "INDEX.sizeInGB": 250}}]
       }
     }
   },
   "nodeValues": {
-    "node1": {"node": "node1", "cores": 2, "freedisk": 900},
-    "node2": {"node": "node2", "cores": 2, "freedisk": 800},
-    "node3": {"node": "node3", "cores": 1, "freedisk": 1200}
+    "node1_": {"node": "node1_", "cores": 2, "freedisk": 900},
+    "node2_": {"node": "node2_", "cores": 2, "freedisk": 800},
+    "node3_": {"node": "node3_", "cores": 1, "freedisk": 1200}
   },
   "config": {
     "cluster-policy": [{"replica":"<2", "shard":"#EACH", "node":"#ANY"},
diff --git a/solr/solrj/src/test-files/solrj/solr/autoscaling/testFreeDiskSuggestions.json b/solr/solrj/src/test-files/solrj/solr/autoscaling/testFreeDiskSuggestions.json
index 2b8897b..70c85b8 100644
--- a/solr/solrj/src/test-files/solrj/solr/autoscaling/testFreeDiskSuggestions.json
+++ b/solr/solrj/src/test-files/solrj/solr/autoscaling/testFreeDiskSuggestions.json
@@ -1,9 +1,9 @@
 {
-  "liveNodes":["node1",
-    "node2"],
+  "liveNodes":["node1_",
+    "node2_"],
   "replicaInfo":{
-    "node1":{},
-    "node2":{"mycoll1":{
+    "node1_":{},
+    "node2_":{"mycoll1":{
       "shard1":[{"r1":{
         "type":"NRT",
         "INDEX.sizeInGB":900}}],
@@ -17,11 +17,11 @@
         "type":"NRT",
         "INDEX.sizeInGB":100}}]}}},
   "nodeValues":{
-    "node1":{
-      "node":"node1",
+    "node1_":{
+      "node":"node1_",
       "cores":0,
       "freedisk":2000},
-    "node2":{
-      "node":"node2",
+    "node2_":{
+      "node":"node2_",
       "cores":4,
       "freedisk":500}}}
\ No newline at end of file
diff --git a/solr/solrj/src/test-files/solrj/solr/autoscaling/testMoveReplicasInMultipleCollections.json b/solr/solrj/src/test-files/solrj/solr/autoscaling/testMoveReplicasInMultipleCollections.json
index 16ba1a7..21c43d8 100644
--- a/solr/solrj/src/test-files/solrj/solr/autoscaling/testMoveReplicasInMultipleCollections.json
+++ b/solr/solrj/src/test-files/solrj/solr/autoscaling/testMoveReplicasInMultipleCollections.json
@@ -8,15 +8,13 @@
         "replicas":{
           "core_node1":{
             "core":"collection1_shard1_replica_n1",
-            "base_url":"http://127.0.0.1:51650/solr",
-            "node_name":"node1",
+            "node_name":"node1_",
             "state":"active",
             "type":"NRT",
             "leader":"true"},
           "core_node6":{
             "core":"collection1_shard1_replica_n3",
-            "base_url":"http://127.0.0.1:51651/solr",
-            "node_name":"node3",
+            "node_name":"node3_",
             "state":"active",
             "type":"NRT"}}},
       "shard2":{
@@ -25,15 +23,13 @@
         "replicas":{
           "core_node3":{
             "core":"collection1_shard2_replica_n1",
-            "base_url":"http://127.0.0.1:51650/solr",
-            "node_name":"node1",
+            "node_name":"node1_",
             "state":"active",
             "type":"NRT",
             "leader":"true"},
           "core_node5":{
             "core":"collection1_shard2_replica_n3",
-            "base_url":"http://127.0.0.1:51651/solr",
-            "node_name":"node3",
+            "node_name":"node3_",
             "state":"active",
             "type":"NRT"}}}},
     "router":{
@@ -52,14 +48,12 @@
         "replicas":{
           "core_node1":{
             "core":"collection2_shard1_replica_n1",
-            "base_url":"http://127.0.0.1:51649/solr",
-            "node_name":"node2",
+            "node_name":"node2_",
             "state":"active",
             "type":"NRT"},
           "core_node2":{
             "core":"collection2_shard1_replica_n2",
-            "base_url":"http://127.0.0.1:51651/solr",
-            "node_name":"node3",
+            "node_name":"node3_",
             "state":"active",
             "type":"NRT",
             "leader":"true"}}},
@@ -69,14 +63,12 @@
         "replicas":{
           "core_node3":{
             "core":"collection2_shard2_replica_n1",
-            "base_url":"http://127.0.0.1:51649/solr",
-            "node_name":"node2",
+            "node_name":"node2_",
             "state":"active",
             "type":"NRT"},
           "core_node4":{
             "core":"collection2_shard2_replica_n2",
-            "base_url":"http://127.0.0.1:51651/solr",
-            "node_name":"node3",
+            "node_name":"node3_",
             "state":"active",
             "type":"NRT",
             "leader":"true"}}}},
diff --git a/solr/solrj/src/test-files/solrj/solr/autoscaling/testPolicy.json b/solr/solrj/src/test-files/solrj/solr/autoscaling/testPolicy.json
index 373607e..e18cf20 100644
--- a/solr/solrj/src/test-files/solrj/solr/autoscaling/testPolicy.json
+++ b/solr/solrj/src/test-files/solrj/solr/autoscaling/testPolicy.json
@@ -6,36 +6,30 @@
       "replicas":{
         "r1":{
           "core":"r1",
-          "base_url":"http://10.0.0.4:8983/solr",
-          "node_name":"node1",
+          "node_name":"node1_",
           "state":"active",
           "leader":"true"},
         "r2":{
           "core":"r2",
-          "base_url":"http://10.0.0.4:7574/solr",
-          "node_name":"node2",
+          "node_name":"node2_",
           "state":"active"}}},
     "shard2":{
       "range":"0-7fffffff",
       "replicas":{
         "r3":{
           "core":"r3",
-          "base_url":"http://10.0.0.4:8983/solr",
-          "node_name":"node1",
+          "node_name":"node1_",
           "state":"active",
           "leader":"true"},
         "r4":{
           "core":"r4",
-          "base_url":"http://10.0.0.4:8987/solr",
-          "node_name":"node4",
+          "node_name":"node4_",
           "state":"active"},
         "r6":{
           "core":"r6",
-          "base_url":"http://10.0.0.4:8989/solr",
-          "node_name":"node3",
+          "node_name":"node3_",
           "state":"active"},
         "r5":{
           "core":"r5",
-          "base_url":"http://10.0.0.4:8983/solr",
-          "node_name":"node1",
+          "node_name":"node1_",
           "state":"active"}}}}}}
\ No newline at end of file
diff --git a/solr/solrj/src/test-files/solrj/solr/autoscaling/testWithCollection.json b/solr/solrj/src/test-files/solrj/solr/autoscaling/testWithCollection.json
index d171998..395bf8a 100644
--- a/solr/solrj/src/test-files/solrj/solr/autoscaling/testWithCollection.json
+++ b/solr/solrj/src/test-files/solrj/solr/autoscaling/testWithCollection.json
@@ -10,12 +10,10 @@
       "replicas":{
         "r1":{
           "core":"r1",
-          "base_url":"http://10.0.0.4:8983/solr",
-          "node_name":"node1",
+          "node_name":"node1_",
           "state":"active",
           "leader":"true"},
         "r2":{
           "core":"r2",
-          "base_url":"http://10.0.0.4:7574/solr",
-          "node_name":"node2",
+          "node_name":"node2_",
           "state":"active"}}}}}}
\ No newline at end of file
diff --git a/solr/solrj/src/test-files/solrj/solr/autoscaling/testWithCollectionMoveReplica.json b/solr/solrj/src/test-files/solrj/solr/autoscaling/testWithCollectionMoveReplica.json
index 469eef1..23d5d9a 100644
--- a/solr/solrj/src/test-files/solrj/solr/autoscaling/testWithCollectionMoveReplica.json
+++ b/solr/solrj/src/test-files/solrj/solr/autoscaling/testWithCollectionMoveReplica.json
@@ -5,8 +5,7 @@
       "range":"80000000-ffffffff",
       "replicas":{"r1":{
         "core":"r1",
-        "base_url":"http://10.0.0.4:8983/solr",
-        "node_name":"node1",
+        "node_name":"node1_",
         "state":"active",
         "leader":"true"}}}},
     "withCollection":"articles_coll"},
@@ -17,12 +16,10 @@
       "replicas":{
         "r1":{
           "core":"r1",
-          "base_url":"http://10.0.0.4:8983/solr",
-          "node_name":"node1",
+          "node_name":"node1_",
           "state":"active",
           "leader":"true"},
         "r2":{
           "core":"r2",
-          "base_url":"http://10.0.0.4:7574/solr",
-          "node_name":"node2",
+          "node_name":"node2_",
           "state":"active"}}}}}}
\ No newline at end of file
diff --git a/solr/solrj/src/test-files/solrj/solr/autoscaling/testWithCollectionMoveVsAddSuggestions.json b/solr/solrj/src/test-files/solrj/solr/autoscaling/testWithCollectionMoveVsAddSuggestions.json
index 0d99d4a..1fbe4f7 100644
--- a/solr/solrj/src/test-files/solrj/solr/autoscaling/testWithCollectionMoveVsAddSuggestions.json
+++ b/solr/solrj/src/test-files/solrj/solr/autoscaling/testWithCollectionMoveVsAddSuggestions.json
@@ -6,19 +6,16 @@
       "replicas":{
         "r1":{
           "core":"r1",
-          "base_url":"http://10.0.0.4:8983/solr",
-          "node_name":"node1",
+          "node_name":"node1_",
           "state":"active",
           "leader":"true"},
         "r2":{
           "core":"r2",
-          "base_url":"http://10.0.0.4:7574/solr",
-          "node_name":"node2",
+          "node_name":"node2_",
           "state":"active"},
         "r3":{
           "core":"r3",
-          "base_url":"http://10.0.0.4:7579/solr",
-          "node_name":"node6",
+          "node_name":"node6_",
           "state":"active"}}}}},
   "comments_coll":{
     "withCollection":"articles_coll",
@@ -28,22 +25,18 @@
       "replicas":{
         "r1":{
           "core":"r1",
-          "base_url":"http://10.0.0.4:7576/solr",
-          "node_name":"node3",
+          "node_name":"node3_",
           "state":"active",
           "leader":"true"},
         "r2":{
           "core":"r2",
-          "base_url":"http://10.0.0.4:7577/solr",
-          "node_name":"node4",
+          "node_name":"node4_",
           "state":"active"},
         "r3":{
           "core":"r3",
-          "base_url":"http://10.0.0.4:7578/solr",
-          "node_name":"node5",
+          "node_name":"node5_",
           "state":"active"},
         "r4":{
           "core":"r4",
-          "base_url":"http://10.0.0.4:7579/solr",
-          "node_name":"node6",
+          "node_name":"node6_",
           "state":"active"}}}}}}
\ No newline at end of file
diff --git a/solr/solrj/src/test-files/solrj/solr/autoscaling/testWithCollectionSuggestions.json b/solr/solrj/src/test-files/solrj/solr/autoscaling/testWithCollectionSuggestions.json
index c4a29db..f26d07b 100644
--- a/solr/solrj/src/test-files/solrj/solr/autoscaling/testWithCollectionSuggestions.json
+++ b/solr/solrj/src/test-files/solrj/solr/autoscaling/testWithCollectionSuggestions.json
@@ -10,12 +10,10 @@
       "replicas":{
         "r1":{
           "core":"r1",
-          "base_url":"http://10.0.0.4:8983/solr",
-          "node_name":"node1",
+          "node_name":"node1_",
           "state":"active",
           "leader":"true"},
         "r2":{
           "core":"r2",
-          "base_url":"http://10.0.0.4:7574/solr",
-          "node_name":"node2",
+          "node_name":"node2_",
           "state":"active"}}}}}}
\ No newline at end of file
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/cloud/autoscaling/TestPolicy.java b/solr/solrj/src/test/org/apache/solr/client/solrj/cloud/autoscaling/TestPolicy.java
index 2ef6abb..ce34641 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/cloud/autoscaling/TestPolicy.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/cloud/autoscaling/TestPolicy.java
@@ -148,7 +148,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
     @SuppressWarnings({"unchecked"})
     ClusterState clusterState = ClusterState.load(1,
         (Map) loadFromResource("testWithCollection.json"),
-        ImmutableSet.of("node1", "node2", "node3", "node4", "node5"), CLUSTER_STATE);
+        ImmutableSet.of("node1_", "node2_", "node3_", "node4_", "node5_"), CLUSTER_STATE);
     DelegatingClusterStateProvider clusterStateProvider = new DelegatingClusterStateProvider(null) {
       @Override
       public ClusterState getClusterState() throws IOException {
@@ -188,7 +188,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
       }
     };
     @SuppressWarnings({"rawtypes"})
-    Map m = solrClientNodeStateProvider.getNodeValues("node1", ImmutableSet.of("cores", "withCollection"));
+    Map m = solrClientNodeStateProvider.getNodeValues("node1_", ImmutableSet.of("cores", "withCollection"));
     assertNotNull(m.get("withCollection"));
 
     @SuppressWarnings({"rawtypes"})
@@ -230,8 +230,8 @@ public class TestPolicy extends SolrTestCaseJ4 {
     assertNotNull(op);
     nodes.add(op.getParams().get("node"));
     assertEquals(2, nodes.size());
-    assertTrue("node1 should have been selected by add replica", nodes.contains("node1"));
-    assertTrue("node2 should have been selected by add replica", nodes.contains("node2"));
+    assertTrue("node1_ should have been selected by add replica", nodes.contains("node1_"));
+    assertTrue("node2_ should have been selected by add replica", nodes.contains("node2_"));
 
     session = suggester.getSession();
     suggester = session.getSuggester(MOVEREPLICA);
@@ -245,7 +245,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
     ClusterState clusterState =
         ClusterState.load(1,
             (Map) loadFromResource("testWithCollectionSuggestions.json"),
-            ImmutableSet.of("node1", "node2", "node3", "node4", "node5"), CLUSTER_STATE);
+            ImmutableSet.of("node1_", "node2_", "node3_", "node4_", "node5_"), CLUSTER_STATE);
     DelegatingClusterStateProvider clusterStateProvider = new DelegatingClusterStateProvider(null) {
       @Override
       public ClusterState getClusterState() throws IOException {
@@ -285,7 +285,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
       }
     };
     @SuppressWarnings({"rawtypes"})
-    Map m = solrClientNodeStateProvider.getNodeValues("node1", ImmutableSet.of("cores", "withCollection"));
+    Map m = solrClientNodeStateProvider.getNodeValues("node1_", ImmutableSet.of("cores", "withCollection"));
     assertNotNull(m.get("withCollection"));
 
     @SuppressWarnings({"rawtypes"})
@@ -332,15 +332,15 @@ public class TestPolicy extends SolrTestCaseJ4 {
     nodes.add((String) l.get(1)._get("operation/command/add-replica/node", null));
 
     assertEquals(2, nodes.size());
-    assertTrue(nodes.contains("node1"));
-    assertTrue(nodes.contains("node2"));
+    assertTrue(nodes.contains("node1_"));
+    assertTrue(nodes.contains("node2_"));
   }
 
   public void testWithCollectionMoveVsAddSuggestions() throws IOException {
     @SuppressWarnings({"unchecked"})
     ClusterState clusterState = ClusterState.load(1,
         (Map) loadFromResource("testWithCollectionMoveVsAddSuggestions.json"),
-        ImmutableSet.of("node1", "node2", "node3", "node4", "node5", "node6"),
+        ImmutableSet.of("node1_", "node2_", "node3_", "node4_", "node5_", "node6_"),
         CLUSTER_STATE
     );
     DelegatingClusterStateProvider clusterStateProvider = new DelegatingClusterStateProvider(null) {
@@ -382,7 +382,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
       }
     };
     @SuppressWarnings({"rawtypes"})
-    Map m = solrClientNodeStateProvider.getNodeValues("node1", ImmutableSet.of("cores", "withCollection"));
+    Map m = solrClientNodeStateProvider.getNodeValues("node1_", ImmutableSet.of("cores", "withCollection"));
     assertNotNull(m.get("withCollection"));
 
     @SuppressWarnings({"rawtypes"})
@@ -443,16 +443,16 @@ public class TestPolicy extends SolrTestCaseJ4 {
     Set<String> allTargetNodes = new HashSet<>(targetNodes);
     allTargetNodes.addAll(addNodes);
     assertEquals(3, allTargetNodes.size());
-    assertTrue(allTargetNodes.contains("node3"));
-    assertTrue(allTargetNodes.contains("node4"));
-    assertTrue(allTargetNodes.contains("node5"));
+    assertTrue(allTargetNodes.contains("node3_"));
+    assertTrue(allTargetNodes.contains("node4_"));
+    assertTrue(allTargetNodes.contains("node5_"));
   }
 
   public void testWithCollectionMoveReplica() {
     @SuppressWarnings({"unchecked"})
     ClusterState clusterState = ClusterState.load(1,
         (Map) loadFromResource("testWithCollectionMoveReplica.json"),
-        ImmutableSet.of("node2", "node3", "node4", "node5"), CLUSTER_STATE);
+        ImmutableSet.of("node2_", "node3_", "node4_", "node5_"), CLUSTER_STATE);
     DelegatingClusterStateProvider clusterStateProvider = new DelegatingClusterStateProvider(null) {
       @Override
       public ClusterState getClusterState() throws IOException {
@@ -492,7 +492,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
       }
     };
     @SuppressWarnings({"rawtypes"})
-    Map m = solrClientNodeStateProvider.getNodeValues("node1", ImmutableSet.of("cores", "withCollection"));
+    Map m = solrClientNodeStateProvider.getNodeValues("node1_", ImmutableSet.of("cores", "withCollection"));
     assertNotNull(m.get("withCollection"));
 
     @SuppressWarnings({"rawtypes"})
@@ -522,17 +522,17 @@ public class TestPolicy extends SolrTestCaseJ4 {
     });
     Suggester suggester = session.getSuggester(CollectionAction.MOVEREPLICA);
     suggester.hint(Hint.COLL_SHARD, new Pair<>("comments_coll", "shard1"));
-    suggester.hint(Hint.SRC_NODE, "node1");
+    suggester.hint(Hint.SRC_NODE, "node1_");
     @SuppressWarnings({"rawtypes"})
     SolrRequest op = suggester.getSuggestion();
     assertNotNull(op);
-    assertEquals("node2 should have been selected by move replica", "node2",
+    assertEquals("node2_ should have been selected by move replica", "node2_",
         op.getParams().get("targetNode"));
 
     session = suggester.getSession();
     suggester = session.getSuggester(MOVEREPLICA);
     suggester.hint(Hint.COLL_SHARD, new Pair<>("comments_coll", "shard1"));
-    suggester.hint(Hint.SRC_NODE, "node1");
+    suggester.hint(Hint.SRC_NODE, "node1_");
     op = suggester.getSuggestion();
     assertNull(op);
   }
@@ -682,9 +682,9 @@ public class TestPolicy extends SolrTestCaseJ4 {
     clause = Clause.create("{cores: '#EQUAL' , node:'#ANY'}");
     assertEquals(ComputedType.EQUAL, clause.globalTag.computedType);
     expectThrows(IllegalArgumentException.class,
-        () -> Clause.create("{cores: '#EQUAL' , node:'node1'}"));
+        () -> Clause.create("{cores: '#EQUAL' , node:'node1_'}"));
 
-    clause = Clause.create("{cores: '#EQUAL' , node:[node1 , node2 , node3]}");
+    clause = Clause.create("{cores: '#EQUAL' , node:[node1_ , node2_ , node3_]}");
     assertEquals(Operand.IN, clause.getTag().op);
     assertEquals(ComputedType.EQUAL, clause.getGlobalTag().computedType);
 
@@ -705,14 +705,14 @@ public class TestPolicy extends SolrTestCaseJ4 {
     clause = Clause.create("{cores: '14%' , node:'#ANY'}");
     assertEquals(ComputedType.PERCENT, clause.getGlobalTag().computedType);
 
-    clause = Clause.create("{cores: '14%' , node:[node1, node2, node3]}");
+    clause = Clause.create("{cores: '14%' , node:[node1_, node2_, node3_]}");
     assertEquals(Operand.IN, clause.getTag().op);
 
     expectThrows(IllegalArgumentException.class,
         () -> Clause.create("{replica: '!14%' , node:'#ANY'}"));
 
     expectThrows(IllegalArgumentException.class,
-        () -> Clause.create("{cores: '!14%' , node:[node1, node2, node3]}"));
+        () -> Clause.create("{cores: '!14%' , node:[node1_, node2_, node3_]}"));
 
     expectThrows(IllegalArgumentException.class,
         () -> Clause.create("{cores: '!1.66' , node:'#ANY'}"));
@@ -725,7 +725,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
         () -> Clause.create("{cores: '>14%' , node:'#ANY'}"));
      clause  = Clause.create("{replica:1, nodeset : {sysprop.zone : east}}");
      assertEquals(Variable.Type.SYSPROP, clause.tag.varType);
-     clause  =Clause.create("{replica:1, nodeset : [node1, node2, node3]}");
+     clause  =Clause.create("{replica:1, nodeset : [node1_, node2_, node3_]}");
      assertEquals(Variable.Type.NODE, clause.tag.varType);
      assertEquals(Operand.IN, clause.tag.op);
 
@@ -783,14 +783,14 @@ public class TestPolicy extends SolrTestCaseJ4 {
         "          'r1': {" +
         "            'core': 'r1'," +
         "            'base_url': 'http://10.0.0.4:8983/solr'," +
-        "            'node_name': 'node1'," +
+        "            'node_name': 'node1_'," +
         "            'state': 'active'," +
         "            'leader': 'true'" +
         "          }," +
         "          'r2': {" +
         "            'core': 'r2'," +
         "            'base_url': 'http://10.0.0.4:7574/solr'," +
-        "            'node_name': 'node2'," +
+        "            'node_name': 'node2_'," +
         "            'state': 'active'" +
         "          }" +
         "        }" +
@@ -801,26 +801,26 @@ public class TestPolicy extends SolrTestCaseJ4 {
         "          'r3': {" +
         "            'core': 'r3'," +
         "            'base_url': 'http://10.0.0.4:8983/solr'," +
-        "            'node_name': 'node1'," +
+        "            'node_name': 'node1_'," +
         "            'state': 'active'," +
         "            'leader': 'true'" +
         "          }," +
         "          'r4': {" +
         "            'core': 'r4'," +
         "            'base_url': 'http://10.0.0.4:8987/solr'," +
-        "            'node_name': 'node4'," +
+        "            'node_name': 'node4_'," +
         "            'state': 'active'" +
         "          }," +
         "          'r6': {" +
         "            'core': 'r6'," +
         "            'base_url': 'http://10.0.0.4:8989/solr'," +
-        "            'node_name': 'node3'," +
+        "            'node_name': 'node3_'," +
         "            'state': 'active'" +
         "          }," +
         "          'r5': {" +
         "            'core': 'r5'," +
         "            'base_url': 'http://10.0.0.4:8983/solr'," +
-        "            'node_name': 'node1'," +
+        "            'node_name': 'node1_'," +
         "            'state': 'active'" +
         "          }" +
         "        }" +
@@ -831,7 +831,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
 
     @SuppressWarnings({"unchecked"})
     ClusterState clusterState = ClusterState.load(1, clusterStateStr.getBytes(UTF_8),
-        ImmutableSet.of("node1", "node2", "node3", "node4", "node5"));
+        ImmutableSet.of("node1_", "node2_", "node3_", "node4_", "node5_"));
     DelegatingClusterStateProvider clusterStateProvider = new DelegatingClusterStateProvider(null) {
       @Override
       public ClusterState getClusterState() throws IOException {
@@ -898,7 +898,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
     List<Violation> violations = session.getViolations();
     assertEquals(2, violations.size());
     for (Violation violation : violations) {
-      if (violation.node.equals("node1")) {
+      if (violation.node.equals("node1_")) {
         RangeVal val = (RangeVal) violation.getClause().replica.val;
         assertEquals(1.0d, val.min.doubleValue(), 0.01);
         assertEquals(2.0, val.max.doubleValue(), 0.01);
@@ -909,7 +909,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
         for (Violation.ReplicaInfoAndErr replicaInfoAndErr : violation.getViolatingReplicas()) {
           assertTrue(expected.contains(replicaInfoAndErr.replicaInfo.getCore()));
         }
-      } else if (violation.node.equals("node5")) {
+      } else if (violation.node.equals("node5_")) {
         assertEquals(-1, violation.replicaCountDelta.doubleValue(), 0.01);
 
       } else {
@@ -917,7 +917,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
       }
     }
 //    Violation violation = violations.get(0);
-//    assertEquals("node1", violation.node);
+//    assertEquals("node1_", violation.node);
 
 
   }
@@ -1020,15 +1020,15 @@ public class TestPolicy extends SolrTestCaseJ4 {
   @SuppressWarnings({"unchecked", "rawtypes"})
   public void testNodeLostMultipleReplica() {
     String nodeValues = " {" +
-        "    'node4':{" +
+        "    'node4_':{" +
         "      'node':'10.0.0.4:8987_solr'," +
         "      'cores':1," +
         "      'freedisk':884.7097854614258}," +
-        "    'node3':{" +
+        "    'node3_':{" +
         "      'node':'10.0.0.4:8989_solr'," +
         "      'cores':1," +
         "      'freedisk':884.7097854614258}," +
-        "    'node2':{" +
+        "    'node2_':{" +
         "      'node':'10.0.0.4:7574_solr'," +
         "      'cores':1," +
         "      'freedisk':884.7097854614258}," +
@@ -1062,27 +1062,27 @@ public class TestPolicy extends SolrTestCaseJ4 {
     Policy policy = config.getPolicy();
     Policy.Session session = policy.createSession(provider);
     Suggester suggester = session.getSuggester(MOVEREPLICA)
-        .hint(Hint.SRC_NODE, "node1");
+        .hint(Hint.SRC_NODE, "node1_");
 
     SolrRequest operation = suggester.getSuggestion();
     assertNotNull(operation);
-    assertEquals("node2", operation.getParams().get("targetNode"));
+    assertEquals("node2_", operation.getParams().get("targetNode"));
 
     session = suggester.getSession();
     suggester = session.getSuggester(MOVEREPLICA)
-        .hint(Hint.SRC_NODE, "node1");
+        .hint(Hint.SRC_NODE, "node1_");
     operation = suggester.getSuggestion();
     assertNotNull(operation);
-    assertEquals("node3", operation.getParams().get("targetNode"));
+    assertEquals("node3_", operation.getParams().get("targetNode"));
 
     session = suggester.getSession();
     suggester = session.getSuggester(MOVEREPLICA)
-        .hint(Hint.SRC_NODE, "node1");
+        .hint(Hint.SRC_NODE, "node1_");
     operation = suggester.getSuggestion();
     assertNull(operation);
 
-    // lets change the policy such that all replicas that were on node1
-    // can now fit on node2
+    // lets change the policy such that all replicas that were on node1_
+    // can now fit on node2_
     policies = (Map) Utils.fromJSONString("{" +
         "  'cluster-preferences': [" +
         "    { 'maximize': 'freedisk', 'precision': 50}," +
@@ -1116,13 +1116,13 @@ public class TestPolicy extends SolrTestCaseJ4 {
         session = suggester.getSession();
       }
       suggester = session.getSuggester(MOVEREPLICA)
-          .hint(Hint.SRC_NODE, "node1");
+          .hint(Hint.SRC_NODE, "node1_");
       operation = suggester.getSuggestion();
       if (expectedReplica == null) {
         assertNull(operation);
       } else {
         assertNotNull(operation);
-        assertEquals("node2", operation.getParams().get("targetNode"));
+        assertEquals("node2_", operation.getParams().get("targetNode"));
         assertEquals(expectedReplica, operation.getParams().get("replica"));
       }
     }
@@ -1158,7 +1158,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
 
     session = null;
     final String[] expectedReplica = new String[] { "r1", "r3", "r5" };
-    final String[] expectedTargetNode = new String[] { "node3", "node3", "node2" };
+    final String[] expectedTargetNode = new String[] { "node3_", "node3_", "node2_" };
     for (int ii = 0; ii < expectedReplica.length; ++ii) {
       if (session == null) {
         session = policy.createSession(provider);
@@ -1166,7 +1166,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
         session = suggester.getSession();
       }
       suggester = session.getSuggester(MOVEREPLICA)
-          .hint(Hint.SRC_NODE, "node1");
+          .hint(Hint.SRC_NODE, "node1_");
       operation = suggester.getSuggestion();
       assertNotNull(operation);
       assertEquals(expectedTargetNode[ii], operation.getParams().get("targetNode"));
@@ -1281,10 +1281,10 @@ public class TestPolicy extends SolrTestCaseJ4 {
 
     }
     Map<String, Map> nodeValues = (Map<String, Map>) Utils.fromJSONString("{" +
-        "node1:{cores:12, freedisk: 334, heapUsage:10480, rack: rack4, sysprop.fs: slowdisk}," +
-        "node2:{cores:4, freedisk: 749, heapUsage:6873, rack: rack3, sysprop.fs: unknown }," +
-        "node3:{cores:7, freedisk: 262, heapUsage:7834, rack: rack2, sysprop.fs : ssd}," +
-        "node4:{cores:8, freedisk: 375, heapUsage:16900, nodeRole:overseer, rack: rack1, sysprop.fs: unknown}" +
+        "node1_:{cores:12, freedisk: 334, heapUsage:10480, rack: rack4, sysprop.fs: slowdisk}," +
+        "node2_:{cores:4, freedisk: 749, heapUsage:6873, rack: rack3, sysprop.fs: unknown }," +
+        "node3_:{cores:7, freedisk: 262, heapUsage:7834, rack: rack2, sysprop.fs : ssd}," +
+        "node4_:{cores:8, freedisk: 375, heapUsage:16900, nodeRole:overseer, rack: rack1, sysprop.fs: unknown}" +
         "}");
     Policy policy = new Policy(policies);
     Suggester suggester = policy.createSession(getSolrCloudManager(nodeValues, clusterState))
@@ -1294,7 +1294,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
     SolrRequest op = suggester.getSuggestion();
     assertNotNull(op);
     assertEquals(Replica.Type.PULL.name(), op.getParams().get("type"));
-    assertEquals("PULL type node must be in 'slowdisk' node", "node1", op.getParams().get("node"));
+    assertEquals("PULL type node must be in 'slowdisk' node", "node1_", op.getParams().get("node"));
 
     suggester = suggester.getSession()
         .getSuggester(ADDREPLICA)
@@ -1303,7 +1303,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
     op = suggester.getSuggestion();
     assertNotNull(op);
     assertEquals(Replica.Type.PULL.name(), op.getParams().get("type"));
-    assertEquals("PULL type node must be in 'slowdisk' node", "node1", op.getParams().get("node"));
+    assertEquals("PULL type node must be in 'slowdisk' node", "node1_", op.getParams().get("node"));
 
     suggester = suggester.getSession()
         .getSuggester(ADDREPLICA)
@@ -1312,7 +1312,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
     op = suggester.getSuggestion();
     assertNotNull(op);
     assertEquals(Replica.Type.TLOG.name(), op.getParams().get("type"));
-    assertEquals("TLOG type node must be in 'ssd' node", "node3", op.getParams().get("node"));
+    assertEquals("TLOG type node must be in 'ssd' node", "node3_", op.getParams().get("node"));
 
     suggester = suggester.getSession()
         .getSuggester(ADDREPLICA)
@@ -1321,7 +1321,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
     op = suggester.getSuggestion();
     assertNotNull(op);
     assertEquals(Replica.Type.TLOG.name(), op.getParams().get("type"));
-    assertEquals("TLOG type node must be in 'ssd' node", "node3", op.getParams().get("node"));
+    assertEquals("TLOG type node must be in 'ssd' node", "node3_", op.getParams().get("node"));
 
     suggester = suggester.getSession()
         .getSuggester(ADDREPLICA)
@@ -1336,8 +1336,8 @@ public class TestPolicy extends SolrTestCaseJ4 {
   public void testMoveReplicasInMultipleCollections() throws IOException {
     @SuppressWarnings({"unchecked", "rawtypes"})
     Map<String, Map> nodeValues = (Map<String, Map>) Utils.fromJSONString("{" +
-        "node1:{cores:2}," +
-        "node3:{cores:4}" +
+        "node1_:{cores:2}," +
+        "node3_:{cores:4}" +
         "}");
     Policy policy = new Policy(new HashMap<>());
     @SuppressWarnings({"unchecked"})
@@ -1346,12 +1346,12 @@ public class TestPolicy extends SolrTestCaseJ4 {
         .getSuggester(MOVEREPLICA)
         .hint(Hint.COLL, "collection1")
         .hint(Hint.COLL, "collection2")
-        .hint(Suggester.Hint.SRC_NODE, "node2");
+        .hint(Suggester.Hint.SRC_NODE, "node2_");
     @SuppressWarnings({"rawtypes"})
     SolrRequest op = suggester.getSuggestion();
     assertNotNull(op);
     assertEquals("collection2", op.getParams().get("collection"));
-    assertEquals("node1", op.getParams().get("targetNode"));
+    assertEquals("node1_", op.getParams().get("targetNode"));
     String coreNodeName = op.getParams().get("replica");
     assertTrue(coreNodeName.equals("core_node3") || coreNodeName.equals("core_node1"));
 
@@ -1359,11 +1359,11 @@ public class TestPolicy extends SolrTestCaseJ4 {
         .getSuggester(MOVEREPLICA)
         .hint(Hint.COLL, "collection1")
         .hint(Hint.COLL, "collection2")
-        .hint(Suggester.Hint.SRC_NODE, "node2");
+        .hint(Suggester.Hint.SRC_NODE, "node2_");
     op = suggester.getSuggestion();
     assertNotNull(op);
     assertEquals("collection2", op.getParams().get("collection"));
-    assertEquals("node1", op.getParams().get("targetNode"));
+    assertEquals("node1_", op.getParams().get("targetNode"));
     coreNodeName = op.getParams().get("replica");
     assertTrue(coreNodeName.equals("core_node3") || coreNodeName.equals("core_node1"));
 
@@ -1371,7 +1371,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
         .getSuggester(MOVEREPLICA)
         .hint(Hint.COLL, "collection1")
         .hint(Hint.COLL, "collection2")
-        .hint(Suggester.Hint.SRC_NODE, "node2");
+        .hint(Suggester.Hint.SRC_NODE, "node2_");
     op = suggester.getSuggestion();
     assertNull(op);
   }
@@ -1412,10 +1412,10 @@ public class TestPolicy extends SolrTestCaseJ4 {
     }
     @SuppressWarnings({"unchecked", "rawtypes"})
     Map<String, Map> nodeValues = (Map<String, Map>) Utils.fromJSONString("{" +
-        "node1:{cores:12, freedisk: 334, heapUsage:10480, rack: rack4, sysprop.fs: slowdisk}," +
-        "node2:{cores:4, freedisk: 749, heapUsage:6873, rack: rack3, sysprop.fs: unknown}," +
-        "node3:{cores:7, freedisk: 262, heapUsage:7834, rack: rack2, sysprop.fs : ssd}," +
-        "node4:{cores:8, freedisk: 375, heapUsage:16900, nodeRole:overseer, rack: rack1, sysprop.fs: unknown}" +
+        "node1_:{cores:12, freedisk: 334, heapUsage:10480, rack: rack4, sysprop.fs: slowdisk}," +
+        "node2_:{cores:4, freedisk: 749, heapUsage:6873, rack: rack3, sysprop.fs: unknown}," +
+        "node3_:{cores:7, freedisk: 262, heapUsage:7834, rack: rack2, sysprop.fs : ssd}," +
+        "node4_:{cores:8, freedisk: 375, heapUsage:16900, nodeRole:overseer, rack: rack1, sysprop.fs: unknown}" +
         "}");
     @SuppressWarnings({"unchecked"})
     Policy policy = new Policy(policies);
@@ -1436,7 +1436,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
       assertTrue("Collection for replica is not as expected " + collection, collection.equals("newColl") || collection.equals("newColl2"));
       if (collection.equals("newColl")) countNewCollOp++;
       else countNewColl2Op++;
-      assertEquals("PULL type node must be in 'slowdisk' node, countOp : " + countOp, "node1", op.getParams().get("node"));
+      assertEquals("PULL type node must be in 'slowdisk' node, countOp : " + countOp, "node1_", op.getParams().get("node"));
       suggester = suggester.getSession().getSuggester(ADDREPLICA)
           .hint(Hint.REPLICATYPE, Replica.Type.PULL)
           .hint(Hint.COLL_SHARD, new Pair<>("newColl", "shard1"))
@@ -1461,7 +1461,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
       assertTrue("Collection for replica is not as expected " + collection, collection.equals("newColl") || collection.equals("newColl2"));
       if (collection.equals("newColl")) countNewCollOp++;
       else countNewColl2Op++;
-      assertEquals("TLOG type node must be in 'ssd' node", "node3", op.getParams().get("node"));
+      assertEquals("TLOG type node must be in 'ssd' node", "node3_", op.getParams().get("node"));
       suggester = suggester.getSession()
           .getSuggester(ADDREPLICA)
           .hint(Hint.COLL_SHARD, new Pair<>("newColl", "shard2"))
@@ -1575,7 +1575,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
     String rules = "{" +
         "    'cluster-policy':[" +
         "      { 'nodeRole':'overseer', replica: 0,  'strict':false}," +
-        "      { 'replica':'<1', 'node':'node3', 'shard':'#EACH'}," +
+        "      { 'replica':'<1', 'node':'node3_', 'shard':'#EACH'}," +
         "      { 'replica':'<2', 'node':'#ANY', 'shard':'#EACH'}," +
         "      { 'replica':1, 'sysprop.rack':'rack1'}]" +
         "  }";
@@ -1583,7 +1583,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
       rules = "{" +
           "    'cluster-policy':[" +
           "      { 'nodeRole':'overseer', replica: 0,  'strict':false}," +
-          "      { 'replica':'<1', 'node':'node3', 'shard':'#EACH'}," +
+          "      { 'replica':'<1', 'node':'node3_', 'shard':'#EACH'}," +
           "      { 'replica':'<2', 'node':'#ANY', 'shard':'#EACH'}," +
           "      { 'replica':1, nodeset: {'sysprop.rack':'rack1'}}]" +
           "  }";
@@ -1602,7 +1602,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
     String rules = "{" +
         "cluster-policy:[" +
         "{nodeRole:'overseer',replica : 0 , strict:false}," +
-        "{replica:'<1',node:node3}," +
+        "{replica:'<1',node:node3_}," +
         "{replica:'<2',node:'#ANY', shard:'#EACH'}]," +
         " cluster-preferences:[" +
         "{minimize:cores , precision:2}," +
@@ -1612,7 +1612,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
       rules = "{" +
           "cluster-policy:[" +
           "{nodeset:{nodeRole:'overseer'},replica : 0 , strict:false}," +
-          "{replica:'<1',node:node3}," +
+          "{replica:'<1',node:node3_}," +
           "{replica:'<2',node:'#ANY', shard:'#EACH'}]," +
           " cluster-preferences:[" +
           "{minimize:cores , precision:2}," +
@@ -1621,10 +1621,10 @@ public class TestPolicy extends SolrTestCaseJ4 {
     }
 
     Map<String, Map> nodeValues = (Map<String, Map>) Utils.fromJSONString("{" +
-        "node1:{cores:12, freedisk: 334, heapUsage:10480}," +
-        "node2:{cores:4, freedisk: 749, heapUsage:6873}," +
-        "node3:{cores:7, freedisk: 262, heapUsage:7834}," +
-        "node4:{cores:8, freedisk: 375, heapUsage:16900, nodeRole:overseer}" +
+        "node1_:{cores:12, freedisk: 334, heapUsage:10480}," +
+        "node2_:{cores:4, freedisk: 749, heapUsage:6873}," +
+        "node3_:{cores:7, freedisk: 262, heapUsage:7834}," +
+        "node4_:{cores:8, freedisk: 375, heapUsage:16900, nodeRole:overseer}" +
         "}");
 
     Policy policy = new Policy((Map<String, Object>) Utils.fromJSONString(rules));
@@ -1632,36 +1632,36 @@ public class TestPolicy extends SolrTestCaseJ4 {
     session = policy.createSession(getSolrCloudManager(nodeValues, clusterState));
 
     List<Row> l = session.getSortedNodes();
-    assertEquals("node1", l.get(0).node);
-    assertEquals("node3", l.get(1).node);
-    assertEquals("node4", l.get(2).node);
-    assertEquals("node2", l.get(3).node);
+    assertEquals("node1_", l.get(0).node);
+    assertEquals("node3_", l.get(1).node);
+    assertEquals("node4_", l.get(2).node);
+    assertEquals("node2_", l.get(3).node);
 
 
     List<Violation> violations = session.getViolations();
     assertEquals(3, violations.size());
-    assertTrue(violations.stream().anyMatch(violation -> "node3".equals(violation.getClause().tag.getValue())));
+    assertTrue(violations.stream().anyMatch(violation -> "node3_".equals(violation.getClause().tag.getValue())));
     assertTrue(violations.stream().anyMatch(violation -> "nodeRole".equals(violation.getClause().tag.getName())));
     assertTrue(violations.stream().anyMatch(violation -> (violation.getClause().replica.getOperand() == Operand.LESS_THAN && "node".equals(violation.getClause().tag.getName()))));
 
     Suggester suggester = session.getSuggester(ADDREPLICA)
         .hint(Hint.COLL_SHARD, new Pair<>("gettingstarted", "r1"));
     SolrParams operation = suggester.getSuggestion().getParams();
-    assertEquals("node2", operation.get("node"));
+    assertEquals("node2_", operation.get("node"));
 
     nodeValues = (Map<String, Map>) Utils.fromJSONString("{" +
-        "node1:{cores:12, freedisk: 334, heapUsage:10480}," +
-        "node2:{cores:4, freedisk: 749, heapUsage:6873}," +
-        "node3:{cores:7, freedisk: 262, heapUsage:7834}," +
-        "node5:{cores:0, freedisk: 895, heapUsage:17834}," +
-        "node4:{cores:8, freedisk: 375, heapUsage:16900, nodeRole:overseer}" +
+        "node1_:{cores:12, freedisk: 334, heapUsage:10480}," +
+        "node2_:{cores:4, freedisk: 749, heapUsage:6873}," +
+        "node3_:{cores:7, freedisk: 262, heapUsage:7834}," +
+        "node5_:{cores:0, freedisk: 895, heapUsage:17834}," +
+        "node4_:{cores:8, freedisk: 375, heapUsage:16900, nodeRole:overseer}" +
         "}");
     session = policy.createSession(getSolrCloudManager(nodeValues, clusterState));
     SolrRequest opReq = session.getSuggester(MOVEREPLICA)
-        .hint(Hint.TARGET_NODE, "node5")
+        .hint(Hint.TARGET_NODE, "node5_")
         .getSuggestion();
     assertNotNull(opReq);
-    assertEquals("node5", opReq.getParams().get("targetNode"));
+    assertEquals("node5_", opReq.getParams().get("targetNode"));
   }
 
   @Test
@@ -1676,15 +1676,15 @@ public class TestPolicy extends SolrTestCaseJ4 {
     Policy policy = new Policy((Map<String, Object>) Utils.fromJSONString(autoScalingjson));
 //    PolicyHelper.SESSION_REF.set(ref1);
     String nodeValues = " {" +
-        "    'node4':{" +
+        "    'node4_':{" +
         "      'node':'10.0.0.4:8987_solr'," +
         "      'cores':1," +
         "      'freedisk':884.7097854614258}," +
-        "    'node3':{" +
+        "    'node3_':{" +
         "      'node':'10.0.0.4:8989_solr'," +
         "      'cores':1," +
         "      'freedisk':884.7097854614258}," +
-        "    'node2':{" +
+        "    'node2_':{" +
         "      'node':'10.0.0.4:7574_solr'," +
         "      'cores':1," +
         "      'freedisk':884.7097854614258}," +
@@ -1764,9 +1764,9 @@ public class TestPolicy extends SolrTestCaseJ4 {
   public void testMultiSessionsCache() throws IOException, InterruptedException {
     @SuppressWarnings({"rawtypes", "unchecked"})
     Map<String, Map> nodeValues = (Map<String, Map>) Utils.fromJSONString(" {" +
-        "    'node1':{ 'node':'10.0.0.4:8987_solr', 'cores':1 }," +
-        "    'node2':{ 'node':'10.0.0.4:8989_solr', 'cores':1 }," +
-        "    'node3':{ 'node':'10.0.0.4:7574_solr', 'cores':1 }" +
+        "    'node1_':{ 'node':'10.0.0.4:8987_solr', 'cores':1 }," +
+        "    'node2_':{ 'node':'10.0.0.4:8989_solr', 'cores':1 }," +
+        "    'node3_':{ 'node':'10.0.0.4:7574_solr', 'cores':1 }" +
         "}");
 
     @SuppressWarnings({"rawtypes"})
@@ -1828,9 +1828,9 @@ public class TestPolicy extends SolrTestCaseJ4 {
   public void testMultiThreadedSessionsCache() throws IOException, InterruptedException {
     @SuppressWarnings({"rawtypes", "unchecked"})
     Map<String, Map> nodeValues = (Map<String, Map>) Utils.fromJSONString(" {" +
-        "    'node1':{ 'node':'10.0.0.4:8987_solr', 'cores':1 }," +
-        "    'node2':{ 'node':'10.0.0.4:8989_solr', 'cores':1 }," +
-        "    'node3':{ 'node':'10.0.0.4:7574_solr', 'cores':1 }" +
+        "    'node1_':{ 'node':'10.0.0.4:8987_solr', 'cores':1 }," +
+        "    'node2_':{ 'node':'10.0.0.4:8989_solr', 'cores':1 }," +
+        "    'node3_':{ 'node':'10.0.0.4:7574_solr', 'cores':1 }" +
         "}");
 
     @SuppressWarnings({"rawtypes"})
@@ -1909,10 +1909,10 @@ public class TestPolicy extends SolrTestCaseJ4 {
         "      {'maximize':'freedisk','precision':100}]}";
     @SuppressWarnings({"unchecked", "rawtypes"})
     Map<String, Map> nodeValues = (Map<String, Map>) Utils.fromJSONString("{" +
-        "node1:{cores:12, freedisk: 334, heapUsage:10480, rack: rack4, sysprop.fs: slowdisk}," +
-        "node2:{cores:4, freedisk: 749, heapUsage:6873, rack: rack3, sysprop.fs: slowdisk}," +
-        "node3:{cores:7, freedisk: 262, heapUsage:7834, rack: rack2, sysprop.fs : ssd}," +
-        "node4:{cores:8, freedisk: 375, heapUsage:16900, nodeRole:overseer, rack: rack1, sysprop.fs: slowdisk}" +
+        "node1_:{cores:12, freedisk: 334, heapUsage:10480, rack: rack4, sysprop.fs: slowdisk}," +
+        "node2_:{cores:4, freedisk: 749, heapUsage:6873, rack: rack3, sysprop.fs: slowdisk}," +
+        "node3_:{cores:7, freedisk: 262, heapUsage:7834, rack: rack2, sysprop.fs : ssd}," +
+        "node4_:{cores:8, freedisk: 375, heapUsage:16900, nodeRole:overseer, rack: rack1, sysprop.fs: slowdisk}" +
         "}");
     @SuppressWarnings({"unchecked"})
     Policy policy = new Policy((Map<String, Object>) Utils.fromJSONString(autoscaleJson));
@@ -1925,7 +1925,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
           .hint(Hint.COLL_SHARD, new Pair<>("newColl", "shard1"))
           .getSuggestion();
       assertNotNull(op);
-      assertEquals("node3", op.getParams().get("node"));
+      assertEquals("node3_", op.getParams().get("node"));
       session = suggester.getSession();
     }
 
@@ -1955,10 +1955,10 @@ public class TestPolicy extends SolrTestCaseJ4 {
     }
     @SuppressWarnings({"unchecked", "rawtypes"})
     Map<String, Map> nodeValues = (Map<String, Map>) Utils.fromJSONString("{" +
-        "node1:{cores:12, freedisk: 334, heapUsage:10480, rack: rack4}," +
-        "node2:{cores:4, freedisk: 749, heapUsage:6873, rack: rack3}," +
-        "node3:{cores:7, freedisk: 262, heapUsage:7834, rack: rack2, sysprop.fs : ssd}," +
-        "node4:{cores:8, freedisk: 375, heapUsage:16900, nodeRole:overseer, rack: rack1}" +
+        "node1_:{cores:12, freedisk: 334, heapUsage:10480, rack: rack4}," +
+        "node2_:{cores:4, freedisk: 749, heapUsage:6873, rack: rack3}," +
+        "node3_:{cores:7, freedisk: 262, heapUsage:7834, rack: rack2, sysprop.fs : ssd}," +
+        "node4_:{cores:8, freedisk: 375, heapUsage:16900, nodeRole:overseer, rack: rack1}" +
         "}");
 
     @SuppressWarnings({"unchecked"})
@@ -1971,14 +1971,14 @@ public class TestPolicy extends SolrTestCaseJ4 {
         .hint(Hint.COLL_SHARD, new Pair<>("newColl", "shard1"))
         .getSuggestion();
     assertNotNull(op);
-    assertEquals("node3", op.getParams().get("node"));
+    assertEquals("node3_", op.getParams().get("node"));
     suggester = suggester
         .getSession()
         .getSuggester(ADDREPLICA)
         .hint(Hint.COLL_SHARD, new Pair<>("newColl", "shard1"));
     op = suggester.getSuggestion();
     assertNotNull(op);
-    assertEquals("node3", op.getParams().get("node"));
+    assertEquals("node3_", op.getParams().get("node"));
 
     suggester = suggester
         .getSession()
@@ -1986,7 +1986,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
         .hint(Hint.COLL_SHARD, new Pair<>("newColl", "shard1"));
     op = suggester.getSuggestion();
     assertNotNull(op);
-    assertEquals("node2", op.getParams().get("node"));
+    assertEquals("node2_", op.getParams().get("node"));
   }
 
   @SuppressWarnings({"unchecked", "rawtypes"})
@@ -2077,13 +2077,13 @@ public class TestPolicy extends SolrTestCaseJ4 {
         "]," +
         "'cluster-policy':[" +
         "{replica:0, 'nodeRole':'overseer','strict':false}," +
-        "{'replica':'<1','node':'node3'}," +
+        "{'replica':'<1','node':'node3_'}," +
         "{'replica':'<2','node':'#ANY','shard':'#EACH'}" +
         "]," +
         "'policies':{" +
         "'p1':[" +
         "{replica:0, 'nodeRole':'overseer','strict':false}," +
-        "{'replica':'<1','node':'node3'}," +
+        "{'replica':'<1','node':'node3_'}," +
         "{'replica':'<2','node':'#ANY','shard':'#EACH'}," +
         "{'replica':'<3','shard':'#EACH','sysprop.rack':'#EACH'}" +
         "]" +
@@ -2099,13 +2099,13 @@ public class TestPolicy extends SolrTestCaseJ4 {
           "]," +
           "'cluster-policy':[" +
           "{replica:0, nodeset:{'nodeRole':'overseer'},'strict':false}," +
-          "{'replica':'<1','node':'node3'}," +
+          "{'replica':'<1','node':'node3_'}," +
           "{'replica':'<2','node':'#ANY','shard':'#EACH'}" +
           "]," +
           "'policies':{" +
           "'p1':[" +
           "{replica:0, nodeset:{'nodeRole':'overseer'},'strict':false}," +
-          "{'replica':'<1','node':'node3'}," +
+          "{'replica':'<1','node':'node3_'}," +
           "{'replica':'<2','node':'#ANY','shard':'#EACH'}," +
           "{'replica':'<3','shard':'#EACH', nodeset : { 'sysprop.rack':[rack1, rack2, rack3, rack4]}}" +
           "]" +
@@ -2117,10 +2117,10 @@ public class TestPolicy extends SolrTestCaseJ4 {
 
     @SuppressWarnings({"unchecked", "rawtypes"})
     Map<String, Map> nodeValues = (Map<String, Map>) Utils.fromJSONString("{" +
-        "node1:{cores:12, freedisk: 334, heapUsage:10480, rack: rack4}," +
-        "node2:{cores:4, freedisk: 749, heapUsage:6873, rack: rack3}," +
-        "node3:{cores:7, freedisk: 262, heapUsage:7834, rack: rack2}," +
-        "node4:{cores:8, freedisk: 375, heapUsage:16900, nodeRole:overseer, sysprop.rack: rack1}" +
+        "node1_:{cores:12, freedisk: 334, heapUsage:10480, rack: rack4}," +
+        "node2_:{cores:4, freedisk: 749, heapUsage:6873, rack: rack3}," +
+        "node3_:{cores:7, freedisk: 262, heapUsage:7834, rack: rack2}," +
+        "node4_:{cores:8, freedisk: 375, heapUsage:16900, nodeRole:overseer, sysprop.rack: rack1}" +
         "}");
     @SuppressWarnings({"unchecked"})
     Policy policy = new Policy((Map<String, Object>) Utils.fromJSONString(rules));
@@ -2164,7 +2164,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
         .getSuggester(ADDREPLICA)
         .hint(Hint.COLL_SHARD, new Pair<>("newColl", "s1")).getSuggestion();
     assertNotNull(op);
-    assertEquals("node2", op.getNode());
+    assertEquals("node2_", op.getNode());
   }
   @SuppressWarnings({"rawtypes"})
   static SolrCloudManager getSolrCloudManager(final Map<String, Map> nodeValues, String clusterS) {
@@ -2332,10 +2332,10 @@ public class TestPolicy extends SolrTestCaseJ4 {
 
     @SuppressWarnings({"unchecked", "rawtypes"})
     Map<String, Map> nodeValues = (Map<String, Map>) Utils.fromJSONString("{" +
-        "node1:{cores:12, freedisk: 334, heap:10480, sysprop.rack:rack3}," +
-        "node2:{cores:4, freedisk: 749, heap:6873, sysprop.fs : ssd, sysprop.rack:rack1}," +
-        "node3:{cores:7, freedisk: 262, heap:7834, sysprop.rack:rack4}," +
-        "node4:{cores:0, freedisk: 900, heap:16900, nodeRole:overseer, sysprop.rack:rack2}" +
+        "node1_:{cores:12, freedisk: 334, heap:10480, sysprop.rack:rack3}," +
+        "node2_:{cores:4, freedisk: 749, heap:6873, sysprop.fs : ssd, sysprop.rack:rack1}," +
+        "node3_:{cores:7, freedisk: 262, heap:7834, sysprop.rack:rack4}," +
+        "node4_:{cores:0, freedisk: 900, heap:16900, nodeRole:overseer, sysprop.rack:rack2}" +
         "}");
 
     SolrCloudManager cloudManager = new DelegatingCloudManager(null) {
@@ -2361,7 +2361,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
         return new DelegatingClusterStateProvider(null) {
           @Override
           public Set<String> getLiveNodes() {
-            return new HashSet<>(Arrays.asList("node1", "node2", "node3", "node4"));
+            return new HashSet<>(Arrays.asList("node1_", "node2_", "node3_", "node4_"));
           }
         };
       }
@@ -2370,7 +2370,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
     List<ReplicaPosition> locations = PolicyHelper.getReplicaLocations(
         "newColl", new AutoScalingConfig((Map<String, Object>) Utils.fromJSONString(autoScaleJson)),
         cloudManager, Collections.singletonMap("newColl", "policy1"), Arrays.asList("shard1", "shard2"), 3, 0, 0, null);
-    assertTrue(locations.stream().allMatch(it -> ImmutableList.of("node2", "node1", "node3").contains(it.node)));
+    assertTrue(locations.stream().allMatch(it -> ImmutableList.of("node2_", "node1_", "node3_").contains(it.node)));
   }
 
   public void testMoveReplicaSuggester() {
@@ -2574,7 +2574,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
         .getV2Request();
     assertEquals("/c/mycoll2/shards", v2Request._get("path",null));
     assertEquals("add-replica", v2Request._get("command[0]/key",null));
-    assertEquals("node1", v2Request._get("command/add-replica/node",null));
+    assertEquals("node1_", v2Request._get("command/add-replica/node",null));
 
 
     suggester = suggester.getSession()
@@ -2587,7 +2587,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
 
     assertEquals("/c/mycoll2/shards", v2Request._get("path",null));
     assertEquals("add-replica", v2Request._get("command[0]/key",null));
-    assertEquals("node2", v2Request._get("command/add-replica/node",null));
+    assertEquals("node2_", v2Request._get("command/add-replica/node",null));
 
 
   }
@@ -2618,13 +2618,13 @@ public class TestPolicy extends SolrTestCaseJ4 {
     List<Suggester.SuggestionInfo> l = PolicyHelper.getSuggestions(cfg, cloudManagerWithData((Map) loadFromResource("testFreeDiskSuggestions.json")));
     assertEquals(3, l.size());
     assertEquals("r4", l.get(0)._get("operation/command/move-replica/replica", null));
-    assertEquals("node1", l.get(0)._get("operation/command/move-replica/targetNode", null));
+    assertEquals("node1_", l.get(0)._get("operation/command/move-replica/targetNode", null));
 
     assertEquals("r3", l.get(1)._get("operation/command/move-replica/replica", null));
-    assertEquals("node1", l.get(1)._get("operation/command/move-replica/targetNode", null));
+    assertEquals("node1_", l.get(1)._get("operation/command/move-replica/targetNode", null));
 
     assertEquals("r2", l.get(2)._get("operation/command/move-replica/replica", null));
-    assertEquals("node1", l.get(2)._get("operation/command/move-replica/targetNode", null));
+    assertEquals("node1_", l.get(2)._get("operation/command/move-replica/targetNode", null));
 
 
     autoScalingjson = "  { cluster-policy:[" +
@@ -2647,13 +2647,13 @@ public class TestPolicy extends SolrTestCaseJ4 {
     l = PolicyHelper.getSuggestions(cfg, cloudManagerWithData((Map) loadFromResource("testFreeDiskSuggestions.json")));
     assertEquals(3, l.size());
     assertEquals("r4", l.get(0)._get("operation/command/move-replica/replica", null));
-    assertEquals("node1", l.get(0)._get("operation/command/move-replica/targetNode", null));
+    assertEquals("node1_", l.get(0)._get("operation/command/move-replica/targetNode", null));
 
     assertEquals("r3", l.get(1)._get("operation/command/move-replica/replica", null));
-    assertEquals("node1", l.get(1)._get("operation/command/move-replica/targetNode", null));
+    assertEquals("node1_", l.get(1)._get("operation/command/move-replica/targetNode", null));
 
     assertEquals("r2", l.get(2)._get("operation/command/move-replica/replica", null));
-    assertEquals("node1", l.get(2)._get("operation/command/move-replica/targetNode", null));
+    assertEquals("node1_", l.get(2)._get("operation/command/move-replica/targetNode", null));
 
 
   }
@@ -2785,10 +2785,10 @@ public class TestPolicy extends SolrTestCaseJ4 {
 
     @SuppressWarnings({"unchecked", "rawtypes"})
     Map<String, Map> nodeValues = (Map<String, Map>) Utils.fromJSONString("{" +
-        "node1:{cores:12, freedisk: 334, heap:10480, sysprop.rack:rack3}," +
-        "node2:{cores:4, freedisk: 262, heap:6873, sysprop.fs : ssd, sysprop.rack:rack1}," +
-        "node3:{cores:7, freedisk: 749, heap:7834, sysprop.rack:rack4}," +
-        "node4:{cores:0, freedisk: 900, heap:16900, nodeRole:overseer, sysprop.rack:rack2}" +
+        "node1_:{cores:12, freedisk: 334, heap:10480, sysprop.rack:rack3}," +
+        "node2_:{cores:4, freedisk: 262, heap:6873, sysprop.fs : ssd, sysprop.rack:rack1}," +
+        "node3_:{cores:7, freedisk: 749, heap:7834, sysprop.rack:rack4}," +
+        "node4_:{cores:0, freedisk: 900, heap:16900, nodeRole:overseer, sysprop.rack:rack2}" +
         "}");
 
     SolrCloudManager cloudManager = new DelegatingCloudManager(null) {
@@ -2805,16 +2805,16 @@ public class TestPolicy extends SolrTestCaseJ4 {
           @Override
           @SuppressWarnings({"unchecked", "rawtypes"})
           public Map<String, Map<String, List<ReplicaInfo>>> getReplicaInfo(String node, Collection<String> keys) {
-            if (node.equals("node1")) {
+            if (node.equals("node1_")) {
               Map m = Utils.makeMap("newColl",
                   Utils.makeMap("shard1", Collections.singletonList(new ReplicaInfo("r1", "shard1",
-                      new Replica("r1", Utils.makeMap(ZkStateReader.NODE_NAME_PROP, "node1", ZkStateReader.CORE_NAME_PROP, "core1"), "newColl", "shard1"),
+                      new Replica("r1", Utils.makeMap(ZkStateReader.NODE_NAME_PROP, "node1_", ZkStateReader.CORE_NAME_PROP, "core1"), "newColl", "shard1"),
                       Utils.makeMap(FREEDISK.perReplicaValue, 200)))));
               return m;
-            } else if (node.equals("node2")) {
+            } else if (node.equals("node2_")) {
               Map m = Utils.makeMap("newColl",
                   Utils.makeMap("shard2", Collections.singletonList(new ReplicaInfo("r1", "shard2",
-                      new Replica("r1", Utils.makeMap(ZkStateReader.NODE_NAME_PROP, "node2", ZkStateReader.CORE_NAME_PROP, "core2"),"newColl", "shard2"),
+                      new Replica("r1", Utils.makeMap(ZkStateReader.NODE_NAME_PROP, "node2_", ZkStateReader.CORE_NAME_PROP, "core2"),"newColl", "shard2"),
                       Utils.makeMap(FREEDISK.perReplicaValue, 200)))));
               return m;
             }
@@ -2828,7 +2828,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
         return new DelegatingClusterStateProvider(null) {
           @Override
           public Set<String> getLiveNodes() {
-            return new HashSet<>(Arrays.asList("node1", "node2", "node3", "node4"));
+            return new HashSet<>(Arrays.asList("node1_", "node2_", "node3_", "node4_"));
           }
 
           @Override
@@ -2837,9 +2837,9 @@ public class TestPolicy extends SolrTestCaseJ4 {
               @Override
               public Replica getLeader(String sliceName) {
                 if (sliceName.equals("shard1"))
-                  return new Replica("r1", Utils.makeMap(ZkStateReader.NODE_NAME_PROP, "node1", ZkStateReader.CORE_NAME_PROP, "core1"), name, "shard1");
+                  return new Replica("r1", Utils.makeMap(ZkStateReader.NODE_NAME_PROP, "node1_", ZkStateReader.CORE_NAME_PROP, "core1"), name, "shard1");
                 if (sliceName.equals("shard2"))
-                  return new Replica("r2", Utils.makeMap(ZkStateReader.NODE_NAME_PROP, "node2", ZkStateReader.CORE_NAME_PROP, "core2"),name, "shard2");
+                  return new Replica("r2", Utils.makeMap(ZkStateReader.NODE_NAME_PROP, "node2_", ZkStateReader.CORE_NAME_PROP, "core2"),name, "shard2");
                 return null;
               }
             };
@@ -2851,7 +2851,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
     List<ReplicaPosition> locations = PolicyHelper.getReplicaLocations(
         "newColl", new AutoScalingConfig((Map<String, Object>) Utils.fromJSONString(autoScaleJson)),
         cloudManager, null, Arrays.asList("shard1", "shard2"), 1, 0, 0, null);
-    assertTrue(locations.stream().allMatch(it -> "node3".equals(it.node)));
+    assertTrue(locations.stream().allMatch(it -> "node3_".equals(it.node)));
   }
 
   public void testMoveReplicaLeaderlast() {
@@ -2859,7 +2859,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
     List<Pair<ReplicaInfo, Row>> validReplicas = new ArrayList<>();
     Map<String, Object> propMap = Utils.makeMap(
         "leader", "true",
-        ZkStateReader.NODE_NAME_PROP, "node1",
+        ZkStateReader.NODE_NAME_PROP, "node1_",
         ZkStateReader.REPLICA_TYPE, Replica.Type.NRT.toString(),
         ZkStateReader.CORE_NAME_PROP, "core1");
     Replica replica = new Replica("r1", propMap, "c1", "s1");
@@ -3077,7 +3077,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
         replicas.forEach((coreNode, val3) -> {
           Map<String, Object> replica = (Map<String, Object>) val3;
           if (!replica.containsKey("node_name")) {
-            replica.put("node_name", "node1");
+            replica.put("node_name", "node1_");
           }
           if (!replica.containsKey("core")) {
             replica.put("core", "core_" + coreNode);
@@ -3097,7 +3097,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
             String coreNode = replica.keySet().iterator().next().toString();
             replica = (Map) replica.get(coreNode);
             if (!replica.containsKey("node_name")) {
-              replica.put("node_name", "node1");
+              replica.put("node_name", "node1_");
             }
             if (!replica.containsKey("core")) {
               replica.put("core", "core_" + coreNode);
@@ -3202,7 +3202,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
 
     assertEquals(1, replicaPositions.size());
     ReplicaPosition replicaPosition = replicaPositions.get(0);
-    assertEquals("node3:8985", replicaPosition.node); // only node3:8985 has enough space to handle the new replica
+    assertEquals("node3:8985_", replicaPosition.node); // only node3_:8985 has enough space to handle the new replica
     assertEquals("s1", replicaPosition.shard); // sanity check
   }
 
@@ -3215,7 +3215,7 @@ public class TestPolicy extends SolrTestCaseJ4 {
     Map replicaInfoMap = (Map) m.remove("replicaInfo");
 
     @SuppressWarnings({"unchecked"})
-    ClusterState clusterState = ClusterState.load(1, clusterStateMap, ImmutableSet.of("node1", "node2"), CLUSTER_STATE);
+    ClusterState clusterState = ClusterState.load(1, clusterStateMap, ImmutableSet.of("node1_", "node2_"), CLUSTER_STATE);
 
     List<String> shards = Arrays.asList("shard1", "shard2", "shard3");
 
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/cloud/autoscaling/TestPolicy2.java b/solr/solrj/src/test/org/apache/solr/client/solrj/cloud/autoscaling/TestPolicy2.java
index 357dbdd..a4264ec 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/cloud/autoscaling/TestPolicy2.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/cloud/autoscaling/TestPolicy2.java
@@ -109,10 +109,10 @@ public class TestPolicy2 extends SolrTestCaseJ4 {
     List<Suggester.SuggestionInfo> suggestions = null;
     assertEquals(2, violations.size());
     for (Violation violation : violations) {
-      if (violation.node.equals("node1")) {
+      if (violation.node.equals("node1_")) {
         assertEquals(1.0d, violation.replicaCountDelta, 0.001);
         assertEquals(3, violation.getViolatingReplicas().size());
-      } else if (violation.node.equals("node5")) {
+      } else if (violation.node.equals("node5_")) {
         assertEquals(-1.0d, violation.replicaCountDelta, 0.001);
         assertEquals(0, violation.getViolatingReplicas().size());
       } else {
@@ -126,7 +126,7 @@ public class TestPolicy2 extends SolrTestCaseJ4 {
     String repName = (String) suggestions.get(0)._get("operation/command/move-replica/replica", null);
 
     AtomicBoolean found = new AtomicBoolean(false);
-    session.getNode("node1").forEachReplica(replicaInfo -> {
+    session.getNode("node1_").forEachReplica(replicaInfo -> {
       if (replicaInfo.getName().equals(repName)) {
         found.set(true);
       }
@@ -142,10 +142,10 @@ public class TestPolicy2 extends SolrTestCaseJ4 {
     violations = session.getViolations();
     assertEquals(2, violations.size());
     for (Violation violation : violations) {
-      if(violation.node.equals("node1")) {
+      if(violation.node.equals("node1_")) {
         assertEquals(1.0d, violation.replicaCountDelta, 0.001);
         assertEquals(3, violation.getViolatingReplicas().size());
-      } else if(violation.node.equals("node5")){
+      } else if(violation.node.equals("node5_")){
         assertEquals(-1.0d, violation.replicaCountDelta, 0.001);
         assertEquals(0, violation.getViolatingReplicas().size());
       } else {
@@ -157,12 +157,12 @@ public class TestPolicy2 extends SolrTestCaseJ4 {
     suggestions = PolicyHelper.getSuggestions(new AutoScalingConfig((Map<String, Object>) Utils.fromJSONString(autoScalingjson)),
         createCloudManager(l.get(0), l.get(1)));
     assertEquals(1, suggestions.size());
-    assertEquals("node5", suggestions.get(0)._get("operation/command/move-replica/targetNode", null));
+    assertEquals("node5_", suggestions.get(0)._get("operation/command/move-replica/targetNode", null));
 
     String rName = (String) suggestions.get(0)._get("operation/command/move-replica/replica", null);
 
     found.set(false);
-    session.getNode("node1").forEachReplica(replicaInfo -> {
+    session.getNode("node1_").forEachReplica(replicaInfo -> {
       if (replicaInfo.getName().equals(rName)) {
         found.set(true);
       }
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudHttp2SolrClientTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudHttp2SolrClientTest.java
index 2db6dc7..0d5efd7 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudHttp2SolrClientTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudHttp2SolrClientTest.java
@@ -61,7 +61,6 @@ import org.apache.solr.common.cloud.DocCollection;
 import org.apache.solr.common.cloud.DocRouter;
 import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.cloud.Slice;
-import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.params.ShardParams;
@@ -80,7 +79,7 @@ import org.junit.rules.ExpectedException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static org.apache.solr.client.solrj.impl.BaseCloudSolrClient.*;
+import static org.apache.solr.client.solrj.impl.BaseCloudSolrClient.RouteResponse;
 
 
 /**
@@ -333,7 +332,7 @@ public class CloudHttp2SolrClientTest extends SolrCloudTestCase {
     Map<String, Long> requestCountsMap = Maps.newHashMap();
     for (Slice slice : col.getSlices()) {
       for (Replica replica : slice.getReplicas()) {
-        String baseURL = (String) replica.get(ZkStateReader.BASE_URL_PROP);
+        String baseURL = replica.getBaseUrl();
         requestCountsMap.put(baseURL, getNumRequests(baseURL, "routing_collection"));
       }
     }
@@ -344,7 +343,7 @@ public class CloudHttp2SolrClientTest extends SolrCloudTestCase {
     Set<String> expectedBaseURLs = Sets.newHashSet();
     for (Slice expectedSlice : expectedSlices) {
       for (Replica replica : expectedSlice.getReplicas()) {
-        String baseURL = (String) replica.get(ZkStateReader.BASE_URL_PROP);
+        String baseURL = replica.getBaseUrl();
         expectedBaseURLs.add(baseURL);
       }
     }
@@ -391,7 +390,7 @@ public class CloudHttp2SolrClientTest extends SolrCloudTestCase {
     Map<String, Long> numRequestsToUnexpectedUrls = Maps.newHashMap();
     for (Slice slice : col.getSlices()) {
       for (Replica replica : slice.getReplicas()) {
-        String baseURL = (String) replica.get(ZkStateReader.BASE_URL_PROP);
+        String baseURL = replica.getBaseUrl();
 
         Long prevNumRequests = requestCountsMap.get(baseURL);
         Long curNumRequests = getNumRequests(baseURL, "routing_collection");
@@ -710,7 +709,7 @@ public class CloudHttp2SolrClientTest extends SolrCloudTestCase {
     SolrQuery q = new SolrQuery().setQuery("*:*");
     HttpSolrClient.RemoteSolrException sse = null;
 
-    final String url = r.getStr(ZkStateReader.BASE_URL_PROP) + "/" + COLLECTION;
+    final String url = r.getBaseUrl() + "/" + COLLECTION;
     try (HttpSolrClient solrClient = getHttpSolrClient(url)) {
 
       if (log.isInfoEnabled()) {
@@ -737,7 +736,7 @@ public class CloudHttp2SolrClientTest extends SolrCloudTestCase {
     Set<String> allNodesOfColl = new HashSet<>();
     for (Slice slice : coll.getSlices()) {
       for (Replica replica : slice.getReplicas()) {
-        allNodesOfColl.add(replica.getStr(ZkStateReader.BASE_URL_PROP));
+        allNodesOfColl.add(replica.getBaseUrl());
       }
     }
     String theNode = null;
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudSolrClientTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudSolrClientTest.java
index 1820d90..9e38a12 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudSolrClientTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/CloudSolrClientTest.java
@@ -49,8 +49,8 @@ import org.apache.solr.client.solrj.request.QueryRequest;
 import org.apache.solr.client.solrj.request.UpdateRequest;
 import org.apache.solr.client.solrj.response.QueryResponse;
 import org.apache.solr.client.solrj.response.RequestStatusState;
-import org.apache.solr.client.solrj.response.UpdateResponse;
 import org.apache.solr.client.solrj.response.SolrPingResponse;
+import org.apache.solr.client.solrj.response.UpdateResponse;
 import org.apache.solr.cloud.AbstractDistribZkTestBase;
 import org.apache.solr.cloud.SolrCloudTestCase;
 import org.apache.solr.common.SolrDocument;
@@ -62,7 +62,6 @@ import org.apache.solr.common.cloud.DocCollection;
 import org.apache.solr.common.cloud.DocRouter;
 import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.cloud.Slice;
-import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.params.ShardParams;
@@ -319,7 +318,7 @@ public class CloudSolrClientTest extends SolrCloudTestCase {
     Map<String, Long> requestCountsMap = Maps.newHashMap();
     for (Slice slice : col.getSlices()) {
       for (Replica replica : slice.getReplicas()) {
-        String baseURL = (String) replica.get(ZkStateReader.BASE_URL_PROP);
+        String baseURL = replica.getBaseUrl();
         requestCountsMap.put(baseURL, getNumRequests(baseURL, "routing_collection"));
       }
     }
@@ -330,8 +329,7 @@ public class CloudSolrClientTest extends SolrCloudTestCase {
     Set<String> expectedBaseURLs = Sets.newHashSet();
     for (Slice expectedSlice : expectedSlices) {
       for (Replica replica : expectedSlice.getReplicas()) {
-        String baseURL = (String) replica.get(ZkStateReader.BASE_URL_PROP);
-        expectedBaseURLs.add(baseURL);
+        expectedBaseURLs.add(replica.getBaseUrl());
       }
     }
 
@@ -377,7 +375,7 @@ public class CloudSolrClientTest extends SolrCloudTestCase {
     Map<String, Long> numRequestsToUnexpectedUrls = Maps.newHashMap();
     for (Slice slice : col.getSlices()) {
       for (Replica replica : slice.getReplicas()) {
-        String baseURL = (String) replica.get(ZkStateReader.BASE_URL_PROP);
+        String baseURL = replica.getBaseUrl();
 
         Long prevNumRequests = requestCountsMap.get(baseURL);
         Long curNumRequests = getNumRequests(baseURL, "routing_collection");
@@ -694,7 +692,7 @@ public class CloudSolrClientTest extends SolrCloudTestCase {
     SolrQuery q = new SolrQuery().setQuery("*:*");
     HttpSolrClient.RemoteSolrException sse = null;
 
-    final String url = r.getStr(ZkStateReader.BASE_URL_PROP) + "/" + COLLECTION;
+    final String url = r.getBaseUrl() + "/" + COLLECTION;
     try (HttpSolrClient solrClient = getHttpSolrClient(url)) {
 
       if (log.isInfoEnabled()) {
@@ -721,7 +719,7 @@ public class CloudSolrClientTest extends SolrCloudTestCase {
     Set<String> allNodesOfColl = new HashSet<>();
     for (Slice slice : coll.getSlices()) {
       for (Replica replica : slice.getReplicas()) {
-        allNodesOfColl.add(replica.getStr(ZkStateReader.BASE_URL_PROP));
+        allNodesOfColl.add(replica.getBaseUrl());
       }
     }
     String theNode = null;
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/routing/NodePreferenceRulesComparatorTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/routing/NodePreferenceRulesComparatorTest.java
index 3998dd0..63c44db 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/routing/NodePreferenceRulesComparatorTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/routing/NodePreferenceRulesComparatorTest.java
@@ -21,11 +21,13 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.common.cloud.UrlScheme;
 import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.params.ShardParams;
 import org.junit.Test;
 
+@SolrTestCaseJ4.SuppressSSL // this test is all about http://
 public class NodePreferenceRulesComparatorTest extends SolrTestCaseJ4 {
 
   @Test
@@ -33,11 +35,11 @@ public class NodePreferenceRulesComparatorTest extends SolrTestCaseJ4 {
     List<Replica> replicas = getBasicReplicaList();
 
     // replicaLocation rule
-    List<PreferenceRule> rules = PreferenceRule.from(ShardParams.SHARDS_PREFERENCE_REPLICA_LOCATION + ":http://host2:8983");
+    List<PreferenceRule> rules = PreferenceRule.from(ShardParams.SHARDS_PREFERENCE_REPLICA_LOCATION + ":http://node2:8983");
     NodePreferenceRulesComparator comparator = new NodePreferenceRulesComparator(rules, null);
     replicas.sort(comparator);
-    assertEquals("node2", replicas.get(0).getNodeName());
-    assertEquals("node1", replicas.get(1).getNodeName());
+    assertEquals("node2", getHost(replicas.get(0).getNodeName()));
+    assertEquals("node1", getHost(replicas.get(1).getNodeName()));
 
   }
 
@@ -49,8 +51,8 @@ public class NodePreferenceRulesComparatorTest extends SolrTestCaseJ4 {
     NodePreferenceRulesComparator comparator = new NodePreferenceRulesComparator(rules, null);
 
     replicas.sort(comparator);
-    assertEquals("node1", replicas.get(0).getNodeName());
-    assertEquals("node2", replicas.get(1).getNodeName());
+    assertEquals("node1", getHost(replicas.get(0).getNodeName()));
+    assertEquals("node2", getHost(replicas.get(1).getNodeName()));
 
     // reversed rule
     rules = PreferenceRule.from(ShardParams.SHARDS_PREFERENCE_REPLICA_TYPE + ":TLOG," +
@@ -58,8 +60,8 @@ public class NodePreferenceRulesComparatorTest extends SolrTestCaseJ4 {
     comparator = new NodePreferenceRulesComparator(rules, null);
 
     replicas.sort(comparator);
-    assertEquals("node2", replicas.get(0).getNodeName());
-    assertEquals("node1", replicas.get(1).getNodeName());
+    assertEquals("node2", getHost(replicas.get(0).getNodeName()));
+    assertEquals("node1", getHost(replicas.get(1).getNodeName()));
   }
 
   @SuppressWarnings("unchecked")
@@ -71,8 +73,7 @@ public class NodePreferenceRulesComparatorTest extends SolrTestCaseJ4 {
         new Replica(
             "node4",
             map(
-                ZkStateReader.BASE_URL_PROP, "http://host2_2:8983/solr",
-                ZkStateReader.NODE_NAME_PROP, "node4",
+                ZkStateReader.NODE_NAME_PROP, "node4:8983_solr",
                 ZkStateReader.CORE_NAME_PROP, "collection1",
                 ZkStateReader.REPLICA_TYPE, "TLOG"
             ),"collection1","shard1"
@@ -82,14 +83,14 @@ public class NodePreferenceRulesComparatorTest extends SolrTestCaseJ4 {
     List<PreferenceRule> rules = PreferenceRule.from(
         ShardParams.SHARDS_PREFERENCE_REPLICA_TYPE + ":NRT," +
             ShardParams.SHARDS_PREFERENCE_REPLICA_TYPE + ":TLOG," +
-            ShardParams.SHARDS_PREFERENCE_REPLICA_LOCATION + ":http://host2_2");
+            ShardParams.SHARDS_PREFERENCE_REPLICA_LOCATION + ":http://node4");
     NodePreferenceRulesComparator comparator = new NodePreferenceRulesComparator(rules, null);
 
     replicas.sort(comparator);
-    assertEquals("node1", replicas.get(0).getNodeName());
-    assertEquals("node4", replicas.get(1).getNodeName());
-    assertEquals("node2", replicas.get(2).getNodeName());
-    assertEquals("node3", replicas.get(3).getNodeName());
+    assertEquals("node1", getHost(replicas.get(0).getNodeName()));
+    assertEquals("node4", getHost(replicas.get(1).getNodeName()));
+    assertEquals("node2", getHost(replicas.get(2).getNodeName()));
+    assertEquals("node3", getHost(replicas.get(3).getNodeName()));
   }
 
   @Test(expected = IllegalArgumentException.class)
@@ -116,13 +117,14 @@ public class NodePreferenceRulesComparatorTest extends SolrTestCaseJ4 {
 
   @SuppressWarnings("unchecked")
   private static List<Replica> getBasicReplicaList() {
+    UrlScheme.INSTANCE.setUrlScheme(UrlScheme.HTTP);
+
     List<Replica> replicas = new ArrayList<Replica>();
     replicas.add(
         new Replica(
             "node1",
             map(
-                ZkStateReader.BASE_URL_PROP, "http://host1:8983/solr",
-                ZkStateReader.NODE_NAME_PROP, "node1",
+                ZkStateReader.NODE_NAME_PROP, "node1:8983_solr",
                 ZkStateReader.CORE_NAME_PROP, "collection1",
                 ZkStateReader.REPLICA_TYPE, "NRT"
             ),"collection1","shard1"
@@ -132,8 +134,7 @@ public class NodePreferenceRulesComparatorTest extends SolrTestCaseJ4 {
         new Replica(
             "node2",
             map(
-                ZkStateReader.BASE_URL_PROP, "http://host2:8983/solr",
-                ZkStateReader.NODE_NAME_PROP, "node2",
+                ZkStateReader.NODE_NAME_PROP, "node2:8983_solr",
                 ZkStateReader.CORE_NAME_PROP, "collection1",
                 ZkStateReader.REPLICA_TYPE, "TLOG"
             ),"collection1","shard1"
@@ -143,8 +144,7 @@ public class NodePreferenceRulesComparatorTest extends SolrTestCaseJ4 {
         new Replica(
             "node3",
             map(
-                ZkStateReader.BASE_URL_PROP, "http://host2_2:8983/solr",
-                ZkStateReader.NODE_NAME_PROP, "node3",
+                ZkStateReader.NODE_NAME_PROP, "node3:8983_solr",
                 ZkStateReader.CORE_NAME_PROP, "collection1",
                 ZkStateReader.REPLICA_TYPE, "PULL"
             ),"collection1","shard1"
@@ -152,4 +152,9 @@ public class NodePreferenceRulesComparatorTest extends SolrTestCaseJ4 {
     );
     return replicas;
   }
+
+  private String getHost(final String nodeName) {
+    final int colonAt = nodeName.indexOf(':');
+    return colonAt != -1 ? nodeName.substring(0,colonAt) : nodeName.substring(0, nodeName.indexOf('_'));
+  }
 }
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/routing/RequestReplicaListTransformerGeneratorTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/routing/RequestReplicaListTransformerGeneratorTest.java
index c0ebad3..c09366d 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/routing/RequestReplicaListTransformerGeneratorTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/routing/RequestReplicaListTransformerGeneratorTest.java
@@ -42,30 +42,35 @@ public class RequestReplicaListTransformerGeneratorTest extends SolrTestCaseJ4 {
 
     ReplicaListTransformer rlt = generator.getReplicaListTransformer(params);
     rlt.transform(replicas);
-    assertEquals("node1", replicas.get(0).getNodeName());
-    assertEquals("node2", replicas.get(1).getNodeName());
-    assertEquals("node3", replicas.get(2).getNodeName());
+    assertEquals("node1", getHost(replicas.get(0).getNodeName()));
+    assertEquals("node2", getHost(replicas.get(1).getNodeName()));
+    assertEquals("node3", getHost(replicas.get(2).getNodeName()));
 
     params.set("routingPreference", "1");
     rlt = generator.getReplicaListTransformer(params);
     rlt.transform(replicas);
-    assertEquals("node2", replicas.get(0).getNodeName());
-    assertEquals("node3", replicas.get(1).getNodeName());
-    assertEquals("node1", replicas.get(2).getNodeName());
+    assertEquals("node2", getHost(replicas.get(0).getNodeName()));
+    assertEquals("node3", getHost(replicas.get(1).getNodeName()));
+    assertEquals("node1", getHost(replicas.get(2).getNodeName()));
 
     params.set("routingPreference", "2");
     rlt = generator.getReplicaListTransformer(params);
     rlt.transform(replicas);
-    assertEquals("node3", replicas.get(0).getNodeName());
-    assertEquals("node1", replicas.get(1).getNodeName());
-    assertEquals("node2", replicas.get(2).getNodeName());
+    assertEquals("node3", getHost(replicas.get(0).getNodeName()));
+    assertEquals("node1", getHost(replicas.get(1).getNodeName()));
+    assertEquals("node2", getHost(replicas.get(2).getNodeName()));
 
     params.set("routingPreference", "3");
     rlt = generator.getReplicaListTransformer(params);
     rlt.transform(replicas);
-    assertEquals("node1", replicas.get(0).getNodeName());
-    assertEquals("node2", replicas.get(1).getNodeName());
-    assertEquals("node3", replicas.get(2).getNodeName());
+    assertEquals("node1", getHost(replicas.get(0).getNodeName()));
+    assertEquals("node2", getHost(replicas.get(1).getNodeName()));
+    assertEquals("node3", getHost(replicas.get(2).getNodeName()));
+  }
+  
+  private String getHost(final String nodeName) {
+    final int colonAt = nodeName.indexOf(':');
+    return colonAt != -1 ? nodeName.substring(0,colonAt) : nodeName.substring(0, nodeName.indexOf('_'));
   }
 
   @SuppressWarnings("unchecked")
@@ -80,8 +85,7 @@ public class RequestReplicaListTransformerGeneratorTest extends SolrTestCaseJ4 {
         new Replica(
             "node4",
             map(
-                ZkStateReader.BASE_URL_PROP, "http://host2_2:8983/solr",
-                ZkStateReader.NODE_NAME_PROP, "node4",
+                ZkStateReader.NODE_NAME_PROP, "node4:8983_solr",
                 ZkStateReader.CORE_NAME_PROP, "collection1",
                 ZkStateReader.REPLICA_TYPE, "TLOG"
             ), "c1","s1"
@@ -93,8 +97,7 @@ public class RequestReplicaListTransformerGeneratorTest extends SolrTestCaseJ4 {
         new Replica(
             "node5",
             map(
-                ZkStateReader.BASE_URL_PROP, "http://host2_2:8983/solr",
-                ZkStateReader.NODE_NAME_PROP, "node5",
+                ZkStateReader.NODE_NAME_PROP, "node5:8983_solr",
                 ZkStateReader.CORE_NAME_PROP, "collection1",
                 ZkStateReader.REPLICA_TYPE, "PULL"
             ), "c1","s1"
@@ -110,20 +113,20 @@ public class RequestReplicaListTransformerGeneratorTest extends SolrTestCaseJ4 {
     params.add(ShardParams.SHARDS_PREFERENCE, rulesParam);
     ReplicaListTransformer rlt = generator.getReplicaListTransformer(params);
     rlt.transform(replicas);
-    assertEquals("node1", replicas.get(0).getNodeName());
-    assertEquals("node2", replicas.get(1).getNodeName());
-    assertEquals("node4", replicas.get(2).getNodeName());
-    assertEquals("node3", replicas.get(3).getNodeName());
-    assertEquals("node5", replicas.get(4).getNodeName());
+    assertEquals("node1", getHost(replicas.get(0).getNodeName()));
+    assertEquals("node2", getHost(replicas.get(1).getNodeName()));
+    assertEquals("node4", getHost(replicas.get(2).getNodeName()));
+    assertEquals("node3", getHost(replicas.get(3).getNodeName()));
+    assertEquals("node5", getHost(replicas.get(4).getNodeName()));
 
     params.set("routingPreference", "1");
     rlt = generator.getReplicaListTransformer(params);
     rlt.transform(replicas);
-    assertEquals("node1", replicas.get(0).getNodeName());
-    assertEquals("node4", replicas.get(1).getNodeName());
-    assertEquals("node2", replicas.get(2).getNodeName());
-    assertEquals("node5", replicas.get(3).getNodeName());
-    assertEquals("node3", replicas.get(4).getNodeName());
+    assertEquals("node1", getHost(replicas.get(0).getNodeName()));
+    assertEquals("node4", getHost(replicas.get(1).getNodeName()));
+    assertEquals("node2", getHost(replicas.get(2).getNodeName()));
+    assertEquals("node5", getHost(replicas.get(3).getNodeName()));
+    assertEquals("node3", getHost(replicas.get(4).getNodeName()));
   }
 
   @SuppressWarnings("unchecked")
@@ -133,8 +136,7 @@ public class RequestReplicaListTransformerGeneratorTest extends SolrTestCaseJ4 {
         new Replica(
             "node1",
             map(
-                ZkStateReader.BASE_URL_PROP, "http://host1:8983/solr",
-                ZkStateReader.NODE_NAME_PROP, "node1",
+                ZkStateReader.NODE_NAME_PROP, "node1:8983_solr",
                 ZkStateReader.CORE_NAME_PROP, "collection1",
                 ZkStateReader.REPLICA_TYPE, "NRT"
             ),"c1","s1"
@@ -144,8 +146,7 @@ public class RequestReplicaListTransformerGeneratorTest extends SolrTestCaseJ4 {
         new Replica(
             "node2",
             map(
-                ZkStateReader.BASE_URL_PROP, "http://host2:8983/solr",
-                ZkStateReader.NODE_NAME_PROP, "node2",
+                ZkStateReader.NODE_NAME_PROP, "node2:8983_solr",
                 ZkStateReader.CORE_NAME_PROP, "collection1",
                 ZkStateReader.REPLICA_TYPE, "TLOG"
             ),"c1","s1"
@@ -155,8 +156,7 @@ public class RequestReplicaListTransformerGeneratorTest extends SolrTestCaseJ4 {
         new Replica(
             "node3",
             map(
-                ZkStateReader.BASE_URL_PROP, "http://host2_2:8983/solr",
-                ZkStateReader.NODE_NAME_PROP, "node3",
+                ZkStateReader.NODE_NAME_PROP, "node3:8983_solr",
                 ZkStateReader.CORE_NAME_PROP, "collection1",
                 ZkStateReader.REPLICA_TYPE, "PULL"
             ),"c1","s1"
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/routing/ShufflingReplicaListTransformerTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/routing/ShufflingReplicaListTransformerTest.java
index 4350511..e9156c8 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/routing/ShufflingReplicaListTransformerTest.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/routing/ShufflingReplicaListTransformerTest.java
@@ -40,7 +40,7 @@ public class ShufflingReplicaListTransformerTest extends SolrTestCase {
       Map<String, Object> propMap = new HashMap<>();
       propMap.put("core", "core" + counter);
       propMap.put("type", "NRT");
-      propMap.put("node_name", "node" + counter);
+      propMap.put("node_name", "node" + counter + "_");
       counter++;
       replicas.add(new Replica(url, propMap, "c1", "s1"));
     }
@@ -76,7 +76,7 @@ public class ShufflingReplicaListTransformerTest extends SolrTestCase {
 
   private final void maybeAddUrl(final List<String> urls, final String url) {
     if (random().nextBoolean()) {
-      urls.add(url);
+      urls.add(url + "_");
     }
   }
 
diff --git a/solr/solrj/src/test/org/apache/solr/common/cloud/UrlSchemeTest.java b/solr/solrj/src/test/org/apache/solr/common/cloud/UrlSchemeTest.java
new file mode 100644
index 0000000..077f3ca
--- /dev/null
+++ b/solr/solrj/src/test/org/apache/solr/common/cloud/UrlSchemeTest.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.common.cloud;
+
+import org.apache.solr.SolrTestCase;
+import org.junit.Test;
+
+import static org.apache.solr.common.cloud.UrlScheme.HTTP;
+import static org.apache.solr.common.cloud.UrlScheme.HTTPS;
+
+public class UrlSchemeTest extends SolrTestCase {
+
+  @Test
+  public void testApplyUrlScheme() {
+
+    final UrlScheme t = UrlScheme.INSTANCE;
+    t.setUrlScheme(HTTPS);
+
+    //  mock a SolrZkClient with some live nodes and cluster props set.
+    String liveNode1 = "192.168.1.1:8983_solr";
+    String liveNode2 = "127.0.0.1:8983_solr";
+    String liveNode3 = "127.0.0.1_";
+    String liveNode4 = "127.0.0.1:61631_l_%2Fig";
+
+    assertEquals("https://192.168.1.1:8983/solr", t.getBaseUrlForNodeName(liveNode1));
+    assertEquals("https://127.0.0.1:8983/solr", t.getBaseUrlForNodeName(liveNode2));
+    assertEquals("https://127.0.0.1", t.getBaseUrlForNodeName(liveNode3));
+    assertEquals("https://127.0.0.1:61631/l_/ig", t.getBaseUrlForNodeName(liveNode4));
+    // heal wrong scheme too
+    assertEquals("https://127.0.0.1:8983/solr", t.applyUrlScheme("127.0.0.1:8983/solr"));
+    assertEquals("https://127.0.0.1:8983/solr", t.applyUrlScheme("http://127.0.0.1:8983/solr"));
+
+    t.setUrlScheme(HTTP);
+    assertEquals("http://192.168.1.1:8983/solr", t.getBaseUrlForNodeName(liveNode1));
+    assertEquals("http://127.0.0.1:8983/solr", t.getBaseUrlForNodeName(liveNode2));
+    assertEquals("http://127.0.0.1", t.getBaseUrlForNodeName(liveNode3));
+    assertEquals("http://127.0.0.1:61631/l_/ig", t.getBaseUrlForNodeName(liveNode4));
+    // heal wrong scheme too
+    assertEquals("http://127.0.0.1:8983/solr", t.applyUrlScheme("https://127.0.0.1:8983/solr"));
+  }
+}
diff --git a/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java b/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
index a0831bc..0ded194 100644
--- a/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
+++ b/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
@@ -102,6 +102,7 @@ import org.apache.solr.common.SolrDocumentList;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrInputDocument;
 import org.apache.solr.common.SolrInputField;
+import org.apache.solr.common.cloud.UrlScheme;
 import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.params.MultiMapSolrParams;
@@ -161,6 +162,7 @@ import org.xml.sax.SAXException;
 
 import static java.util.Objects.requireNonNull;
 import static org.apache.solr.cloud.SolrZkServer.ZK_WHITELIST_PROPERTY;
+import static org.apache.solr.common.cloud.ZkStateReader.URL_SCHEME;
 import static org.apache.solr.update.processor.DistributedUpdateProcessor.DistribPhase;
 import static org.apache.solr.update.processor.DistributingUpdateProcessorFactory.DISTRIB_UPDATE_PARAM;
 
@@ -298,7 +300,10 @@ public abstract class SolrTestCaseJ4 extends SolrTestCase {
     Http2SolrClient.setDefaultSSLConfig(sslConfig.buildClientSSLConfig());
     if(isSSLMode()) {
       // SolrCloud tests should usually clear this
-      System.setProperty("urlScheme", "https");
+      System.setProperty(URL_SCHEME, UrlScheme.HTTPS);
+      UrlScheme.INSTANCE.setUrlScheme(UrlScheme.HTTPS);
+    } else {
+      UrlScheme.INSTANCE.setUrlScheme(UrlScheme.HTTP);
     }
   }
 
@@ -338,7 +343,8 @@ public abstract class SolrTestCaseJ4 extends SolrTestCase {
       System.clearProperty("tests.shardhandler.randomSeed");
       System.clearProperty("enable.update.log");
       System.clearProperty("useCompoundFile");
-      System.clearProperty("urlScheme");
+      System.clearProperty(URL_SCHEME);
+      UrlScheme.INSTANCE.setUrlScheme(UrlScheme.HTTP);
       System.clearProperty("solr.cloud.wait-for-updates-with-stale-state-pause");
       System.clearProperty("solr.zkclienttmeout");
       System.clearProperty(ZK_WHITELIST_PROPERTY);
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 d242528..1fb1efb 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
@@ -16,6 +16,7 @@
  */
 package org.apache.solr.cloud;
 
+import static org.apache.solr.common.cloud.ZkStateReader.URL_SCHEME;
 import static org.apache.solr.common.util.Utils.makeMap;
 
 import java.io.File;
@@ -72,6 +73,7 @@ import org.apache.solr.common.cloud.ClusterState;
 import org.apache.solr.common.cloud.DocCollection;
 import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.cloud.Slice;
+import org.apache.solr.common.cloud.UrlScheme;
 import org.apache.solr.common.cloud.ZkCoreNodeProps;
 import org.apache.solr.common.cloud.ZkNodeProps;
 import org.apache.solr.common.cloud.ZkStateReader;
@@ -255,17 +257,17 @@ public abstract class AbstractFullDistribZkTestBase extends AbstractDistribZkTes
     }
 
     if (isSSLMode()) {
-      System.clearProperty("urlScheme");
+      System.clearProperty(URL_SCHEME);
       try (ZkStateReader zkStateReader = new ZkStateReader(zkServer.getZkAddress(),
           AbstractZkTestCase.TIMEOUT, AbstractZkTestCase.TIMEOUT)) {
         try {
           zkStateReader.getZkClient().create(ZkStateReader.CLUSTER_PROPS,
-              Utils.toJSON(Collections.singletonMap("urlScheme", "https")),
+              Utils.toJSON(Collections.singletonMap(URL_SCHEME, "https")),
               CreateMode.PERSISTENT, true);
         } catch (KeeperException.NodeExistsException e) {
           ZkNodeProps props = ZkNodeProps.load(zkStateReader.getZkClient().getData(ZkStateReader.CLUSTER_PROPS,
               null, null, true));
-          zkStateReader.getZkClient().setData(ZkStateReader.CLUSTER_PROPS, Utils.toJSON(props.plus("urlScheme", "https")), true);
+          zkStateReader.getZkClient().setData(ZkStateReader.CLUSTER_PROPS, Utils.toJSON(props.plus(URL_SCHEME, "https")), true);
         }
       }
     }
@@ -787,7 +789,7 @@ public abstract class AbstractFullDistribZkTestBase extends AbstractDistribZkTes
   }
 
   protected SocketProxy getProxyForReplica(Replica replica) throws Exception {
-    String replicaBaseUrl = replica.getStr(ZkStateReader.BASE_URL_PROP);
+    String replicaBaseUrl = replica.getBaseUrl();
     assertNotNull(replicaBaseUrl);
 
     List<JettySolrRunner> runners = new ArrayList<>(jettys);
@@ -849,7 +851,7 @@ public abstract class AbstractFullDistribZkTestBase extends AbstractDistribZkTes
           int port = new URI(((HttpSolrClient) client).getBaseURL())
               .getPort();
 
-          if (replica.getStr(ZkStateReader.BASE_URL_PROP).contains(":" + port)) {
+          if (replica.getBaseUrl().contains(":" + port)) {
             CloudSolrServerClient csc = new CloudSolrServerClient();
             csc.solrClient = client;
             csc.port = port;
@@ -875,7 +877,7 @@ public abstract class AbstractFullDistribZkTestBase extends AbstractDistribZkTes
         Set<Entry<String,Replica>> entries = slice.getReplicasMap().entrySet();
         for (Entry<String,Replica> entry : entries) {
           Replica replica = entry.getValue();
-          if (replica.getStr(ZkStateReader.BASE_URL_PROP).contains(":" + port)) {
+          if (replica.getBaseUrl().contains(":" + port)) {
             List<CloudJettyRunner> list = shardToJetty.get(slice.getName());
             if (list == null) {
               list = new ArrayList<>();
@@ -887,7 +889,8 @@ public abstract class AbstractFullDistribZkTestBase extends AbstractDistribZkTes
             cjr.info = replica;
             cjr.nodeName = replica.getStr(ZkStateReader.NODE_NAME_PROP);
             cjr.coreNodeName = entry.getKey();
-            cjr.url = replica.getStr(ZkStateReader.BASE_URL_PROP) + "/" + replica.getStr(ZkStateReader.CORE_NAME_PROP);
+            // TODO: no trailing slash on end desired, so replica.getCoreUrl is not applicable here
+            cjr.url = replica.getBaseUrl() + "/" + replica.getStr(ZkStateReader.CORE_NAME_PROP);
             cjr.client = findClientByPort(port, theClients);
             list.add(cjr);
             if (isLeader) {
@@ -2017,8 +2020,9 @@ public abstract class AbstractFullDistribZkTestBase extends AbstractDistribZkTes
       Set<Map.Entry<String,Replica>> shardEntries = shards.entrySet();
       for (Map.Entry<String,Replica> shardEntry : shardEntries) {
         final ZkNodeProps node = shardEntry.getValue();
-        if (clusterState.liveNodesContain(node.getStr(ZkStateReader.NODE_NAME_PROP))) {
-          return ZkCoreNodeProps.getCoreUrl(node.getStr(ZkStateReader.BASE_URL_PROP), collection); //new ZkCoreNodeProps(node).getCoreUrl();
+        final String nodeName = node.getStr(ZkStateReader.NODE_NAME_PROP);
+        if (clusterState.liveNodesContain(nodeName)) {
+          return ZkCoreNodeProps.getCoreUrl(UrlScheme.INSTANCE.getBaseUrlForNodeName(nodeName), collection);
         }
       }
     }