SOLR-16921: use -solrUrl to derive the zk host connection for bin/solr zk subcommands (#2370)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index ed71e52..ef0782c 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -99,7 +99,7 @@
 
 Improvements
 ---------------------
-(No changes)
+* SOLR-16921: use -solrUrl to derive the zk host connection for bin/solr zk subcommands (Eric Pugh)
 
 Optimizations
 ---------------------
diff --git a/solr/bin/solr b/solr/bin/solr
index 65551a5..e9a4577 100755
--- a/solr/bin/solr
+++ b/solr/bin/solr
@@ -451,6 +451,8 @@
     echo "             -z zkHost          Optional Zookeeper connection string for all commands. If specified it"
     echo "                                  overrides the 'ZK_HOST=...'' defined in solr.in.sh."
     echo ""
+    echo "             -s solrUrl         Optional Solr URL to look up the correct zkHost connection string via."
+    echo ""
     echo "             -V/-verbose        Enable more verbose output for this script."
     echo ""
     echo "         upconfig uploads a configset from the local machine to Zookeeper."
@@ -583,12 +585,12 @@
     echo -e "\nERROR: $1\n"
   fi
 
-  echo "  Usage: solr zk upconfig|downconfig -d <confdir> -n <configName> [-z zkHost]"
-  echo "         solr zk cp [-r] <src> <dest> [-z zkHost]"
-  echo "         solr zk rm [-r] <path> [-z zkHost]"
-  echo "         solr zk mv <src> <dest> [-z zkHost]"
-  echo "         solr zk ls [-r] <path> [-z zkHost]"
-  echo "         solr zk mkroot <path> [-z zkHost]"
+  echo "  Usage: solr zk upconfig|downconfig -d <confdir> -n <configName> [-z zkHost] [-s solrUrl]"
+  echo "         solr zk cp [-r] <src> <dest> [-z zkHost] [-s solrUrl]"
+  echo "         solr zk rm [-r] <path> [-z zkHost] [-s solrUrl]"
+  echo "         solr zk mv <src> <dest> [-z zkHost] [-s solrUrl]"
+  echo "         solr zk ls [-r] <path> [-z zkHost] [-s solrUrl]"
+  echo "         solr zk mkroot <path> [-z zkHost] [-s solrUrl]"
   echo ""
 
   if [ "$1" == "" ]; then
@@ -886,6 +888,7 @@
 if [[ "$SCRIPT_CMD" == "zk" ]]; then
 
   VERBOSE=""
+  ZK_SOLR_URL=""
 
   if [ $# -gt 0 ]; then
     while true; do
@@ -901,6 +904,13 @@
             ZK_HOST="$2"
             shift 2
         ;;
+        -s|-solrUrl)
+            if [[ -z "$2" || "${2:0:1}" == "-" ]]; then
+              print_short_zk_usage "$SCRIPT_CMD" "Solr Url is required when using the $1 option!"
+            fi
+            ZK_SOLR_URL="$2"
+            shift 2
+        ;;        
         -n|-confname)
             if [[ -z "$2" || "${2:0:1}" == "-" ]]; then
               print_short_zk_usage "$SCRIPT_CMD" "Configuration name is required when using the $1 option!"
@@ -953,11 +963,7 @@
   if [ -z "$ZK_OP" ]; then
     print_short_zk_usage "Zookeeper operation (one of 'upconfig', 'downconfig', 'rm', 'mv', 'cp', 'ls', 'mkroot') is required!"
   fi
-
-  if [ -z "$ZK_HOST" ]; then
-    print_short_zk_usage "Zookeeper address (-z) argument is required or ZK_HOST must be specified in the solr.in.sh file."
-  fi
-
+  
   if [[ "$ZK_OP" == "upconfig" ||  "$ZK_OP" == "downconfig" ]]; then
     if [ -z "$CONFIGSET_CONFDIR" ]; then
       print_short_zk_usage "Local directory of the configset (-d) argument is required!"
@@ -983,37 +989,44 @@
     fi
   fi
 
+  CONNECTION_PARAMS=""
+  
+  if [[ -z "$ZK_HOST" ]]; then
+    CONNECTION_PARAMS="-solrUrl ${ZK_SOLR_URL}"
+  else
+    CONNECTION_PARAMS="-zkHost ${ZK_HOST}"
+  fi 
 
   case "$ZK_OP" in
     upconfig)
-      run_tool "$ZK_OP" -confname "$CONFIGSET_CONFNAME" -confdir "$CONFIGSET_CONFDIR" -zkHost "$ZK_HOST" -configsetsDir "$SOLR_TIP/server/solr/configsets" $VERBOSE
+      run_tool "$ZK_OP" -confname "$CONFIGSET_CONFNAME" -confdir "$CONFIGSET_CONFDIR" $CONNECTION_PARAMS -configsetsDir "$SOLR_TIP/server/solr/configsets" $VERBOSE
     ;;
     downconfig)
-      run_tool "$ZK_OP" -confname "$CONFIGSET_CONFNAME" -confdir "$CONFIGSET_CONFDIR" -zkHost "$ZK_HOST" $VERBOSE
+      run_tool "$ZK_OP" -confname "$CONFIGSET_CONFNAME" -confdir "$CONFIGSET_CONFDIR" $CONNECTION_PARAMS $VERBOSE
     ;;
     rm)
       if [ -z "$ZK_SRC" ]; then
         print_short_zk_usage "Zookeeper path to remove must be specified when using the 'rm' command"
       fi
-      run_tool "$ZK_OP" -path "$ZK_SRC" -zkHost "$ZK_HOST" -recurse "$ZK_RECURSE" $VERBOSE
+      run_tool "$ZK_OP" -path "$ZK_SRC" $CONNECTION_PARAMS -recurse "$ZK_RECURSE" $VERBOSE
     ;;
     mv)
-      run_tool "$ZK_OP" -src "$ZK_SRC" -dst "$ZK_DST" -zkHost "$ZK_HOST" $VERBOSE
+      run_tool "$ZK_OP" -src "$ZK_SRC" -dst "$ZK_DST" $CONNECTION_PARAMS $VERBOSE
     ;;
     cp)
-      run_tool "$ZK_OP" -src "$ZK_SRC" -dst "$ZK_DST" -zkHost "$ZK_HOST" -recurse "$ZK_RECURSE" $VERBOSE
+      run_tool "$ZK_OP" -src "$ZK_SRC" -dst "$ZK_DST" $CONNECTION_PARAMS -recurse "$ZK_RECURSE" $VERBOSE
     ;;
     ls)
       if [ -z "$ZK_SRC" ]; then
         print_short_zk_usage "Zookeeper path to list must be specified when using the 'ls' command"
       fi
-      run_tool "$ZK_OP" -path "$ZK_SRC" -recurse "$ZK_RECURSE" -zkHost "$ZK_HOST" $VERBOSE
+      run_tool "$ZK_OP" -path "$ZK_SRC" -recurse "$ZK_RECURSE" $CONNECTION_PARAMS $VERBOSE
     ;;
     mkroot)
       if [ -z "$ZK_SRC" ]; then
         print_short_zk_usage "Zookeeper path to list must be specified when using the 'mkroot' command"
       fi
-      run_tool "$ZK_OP" -path "$ZK_SRC" -zkHost "$ZK_HOST" $VERBOSE
+      run_tool "$ZK_OP" -path "$ZK_SRC" $CONNECTION_PARAMS $VERBOSE
     ;;
     *)
       print_short_zk_usage "Unrecognized Zookeeper operation $ZK_OP"
diff --git a/solr/bin/solr.cmd b/solr/bin/solr.cmd
index 222baf4..aee0892 100755
--- a/solr/bin/solr.cmd
+++ b/solr/bin/solr.cmd
@@ -393,6 +393,8 @@
 echo             -z zkHost       Optional Zookeeper connection string for all commands. If specified it
 echo                             overrides the 'ZK_HOST=...'' defined in solr.in.cmd.
 echo.
+echo             -s solrUrl      Optional Solr URL to look up the correct zkHost connection string via.
+echo.
 echo             -V              Enable more verbose output.
 echo.
 echo         upconfig uploads a configset from the local machine to Zookeeper.
@@ -470,12 +472,12 @@
   echo  ERROR: !ERROR_MSG!
   echo.
 )
-echo  Usage: solr zk upconfig^|downconfig -d ^<confdir^> -n ^<configName^> [-z zkHost]
-echo         solr zk cp [-r] ^<src^> ^<dest^> [-z zkHost]
-echo         solr zk rm [-r] ^<path^> [-z zkHost]
-echo         solr zk mv ^<src^> ^<dest^> [-z zkHost]
-echo         solr zk ls [-r] ^<path^> [-z zkHost]
-echo         solr zk mkroot ^<path^> [-z zkHost]
+echo  Usage: solr zk upconfig^|downconfig -d ^<confdir^> -n ^<configName^> [-z zkHost] [-s solrUrl]
+echo         solr zk cp [-r] ^<src^> ^<dest^> [-z zkHost] [-s solrUrl]
+echo         solr zk rm [-r] ^<path^> [-z zkHost] [-s solrUrl]
+echo         solr zk mv ^<src^> ^<dest^> [-z zkHost] [-s solrUrl]
+echo         solr zk ls [-r] ^<path^> [-z zkHost] [-s solrUrl]
+echo         solr zk mkroot ^<path^> [-z zkHost] [-s solrUrl]
 echo.
 IF "%ZK_FULL%"=="true" (
   goto zk_full_usage
@@ -552,6 +554,8 @@
 IF "%1"=="-z" goto set_zookeeper
 IF "%1"=="-zkhost" goto set_zookeeper
 IF "%1"=="-zkHost" goto set_zookeeper
+IF "%1"=="-s" goto set_solr_url
+IF "%1"=="-solrUrl" goto set_solr_url
 IF "%1"=="-a" goto set_addl_opts
 IF "%1"=="-addlopts" goto set_addl_opts
 IF "%1"=="-j" goto set_addl_jetty_config
@@ -773,6 +777,19 @@
 SHIFT
 goto parse_args
 
+:set_solr_url
+
+set "arg=%~2"
+IF "%arg%"=="" (
+  set SCRIPT_ERROR=Solr url string is required!
+  goto invalid_cmd_line
+)
+
+set "ZK_SOLR_URL=%~2"
+SHIFT
+SHIFT
+goto parse_args
+
 :set_addl_opts
 set "arg=%~2"
 set "SOLR_ADDL_ARGS=%~2"
@@ -1480,9 +1497,13 @@
   goto zk_short_usage
 )
 
-IF "!ZK_HOST!"=="" (
-  set "ERROR_MSG=Must specify -z zkHost"
-  goto zk_short_usage
+set CONNECTION_PARAMS=""
+
+IF "!ZK_OP!"=="" (
+  set CONNECTION_PARAMS="-solrUrl !ZK_SOLR_URL!"
+)
+ELSE (
+  set CONNECTION_PARAMS="-zkHost ZK_HOST!"
 )
 
 IF "!ZK_OP!"=="upconfig" (
@@ -1497,7 +1518,7 @@
   "%JAVA%" %SOLR_SSL_OPTS% %AUTHC_OPTS% %SOLR_ZK_CREDS_AND_ACLS% %SOLR_TOOL_OPTS% -Dsolr.install.dir="%SOLR_TIP%" ^
   -Dlog4j.configurationFile="file:///%DEFAULT_SERVER_DIR%\resources\log4j2-console.xml" ^
   -classpath "%DEFAULT_SERVER_DIR%\solr-webapp\webapp\WEB-INF\lib\*;%DEFAULT_SERVER_DIR%\lib\ext\*" ^
-  org.apache.solr.cli.SolrCLI !ZK_OP! -confname !CONFIGSET_NAME! -confdir !CONFIGSET_DIR! -zkHost !ZK_HOST! %ZK_VERBOSE%^
+  org.apache.solr.cli.SolrCLI !ZK_OP! -confname !CONFIGSET_NAME! -confdir !CONFIGSET_DIR! %CONNECTION_PARAMS% %ZK_VERBOSE%^
   -configsetsDir "%SOLR_TIP%/server/solr/configsets"
 ) ELSE IF "!ZK_OP!"=="downconfig" (
   IF "!CONFIGSET_NAME!"=="" (
diff --git a/solr/core/src/java/org/apache/solr/cli/ConfigSetDownloadTool.java b/solr/core/src/java/org/apache/solr/cli/ConfigSetDownloadTool.java
index c11e0e7..efe1ee2 100644
--- a/solr/core/src/java/org/apache/solr/cli/ConfigSetDownloadTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/ConfigSetDownloadTool.java
@@ -58,6 +58,7 @@
             .desc("Local directory with configs.")
             .build(),
         SolrCLI.OPTION_ZKHOST,
+        SolrCLI.OPTION_SOLRURL,
         SolrCLI.OPTION_VERBOSE);
   }
 
diff --git a/solr/core/src/java/org/apache/solr/cli/ConfigSetUploadTool.java b/solr/core/src/java/org/apache/solr/cli/ConfigSetUploadTool.java
index 6576742..0573df8 100644
--- a/solr/core/src/java/org/apache/solr/cli/ConfigSetUploadTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/ConfigSetUploadTool.java
@@ -65,6 +65,7 @@
             .desc("Parent directory of example configsets.")
             .build(),
         SolrCLI.OPTION_ZKHOST,
+        SolrCLI.OPTION_SOLRURL,
         SolrCLI.OPTION_VERBOSE);
   }
 
diff --git a/solr/core/src/java/org/apache/solr/cli/ZkCpTool.java b/solr/core/src/java/org/apache/solr/cli/ZkCpTool.java
index 02379d5..54f32b2 100644
--- a/solr/core/src/java/org/apache/solr/cli/ZkCpTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/ZkCpTool.java
@@ -57,6 +57,7 @@
             .build(),
         SolrCLI.OPTION_RECURSE,
         SolrCLI.OPTION_ZKHOST,
+        SolrCLI.OPTION_SOLRURL,
         SolrCLI.OPTION_VERBOSE);
   }
 
diff --git a/solr/core/src/java/org/apache/solr/cli/ZkLsTool.java b/solr/core/src/java/org/apache/solr/cli/ZkLsTool.java
index 24f1c80..8036806 100644
--- a/solr/core/src/java/org/apache/solr/cli/ZkLsTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/ZkLsTool.java
@@ -50,6 +50,7 @@
             .build(),
         SolrCLI.OPTION_RECURSE,
         SolrCLI.OPTION_ZKHOST,
+        SolrCLI.OPTION_SOLRURL,
         SolrCLI.OPTION_VERBOSE);
   }
 
diff --git a/solr/core/src/java/org/apache/solr/cli/ZkMkrootTool.java b/solr/core/src/java/org/apache/solr/cli/ZkMkrootTool.java
index e411878..67e65bc 100644
--- a/solr/core/src/java/org/apache/solr/cli/ZkMkrootTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/ZkMkrootTool.java
@@ -49,6 +49,7 @@
             .desc("Path to create.")
             .build(),
         SolrCLI.OPTION_ZKHOST,
+        SolrCLI.OPTION_SOLRURL,
         SolrCLI.OPTION_VERBOSE);
   }
 
diff --git a/solr/core/src/java/org/apache/solr/cli/ZkMvTool.java b/solr/core/src/java/org/apache/solr/cli/ZkMvTool.java
index 6506aa9..e9a8a3b 100644
--- a/solr/core/src/java/org/apache/solr/cli/ZkMvTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/ZkMvTool.java
@@ -57,6 +57,7 @@
             .desc("Destination Znode to move to.")
             .build(),
         SolrCLI.OPTION_ZKHOST,
+        SolrCLI.OPTION_SOLRURL,
         SolrCLI.OPTION_VERBOSE);
   }
 
diff --git a/solr/core/src/java/org/apache/solr/cli/ZkRmTool.java b/solr/core/src/java/org/apache/solr/cli/ZkRmTool.java
index dad5bdb..81aafbc 100644
--- a/solr/core/src/java/org/apache/solr/cli/ZkRmTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/ZkRmTool.java
@@ -52,6 +52,7 @@
             .build(),
         SolrCLI.OPTION_RECURSE,
         SolrCLI.OPTION_ZKHOST,
+        SolrCLI.OPTION_SOLRURL,
         SolrCLI.OPTION_VERBOSE);
   }
 
diff --git a/solr/packaging/test/test_zk.bats b/solr/packaging/test/test_zk.bats
index 65cb75a..723b8e5 100644
--- a/solr/packaging/test/test_zk.bats
+++ b/solr/packaging/test/test_zk.bats
@@ -47,6 +47,12 @@
   assert_output --partial "aliases.json"
 }
 
+@test "get zk host using solr url" {
+  sleep 1
+  run solr zk ls / -solrUrl http://localhost:${SOLR_PORT}
+  assert_output --partial "aliases.json"
+}
+
 @test "copying files around" {
   touch myfile.txt
 
diff --git a/solr/solr-ref-guide/modules/deployment-guide/pages/solr-control-script-reference.adoc b/solr/solr-ref-guide/modules/deployment-guide/pages/solr-control-script-reference.adoc
index ca1b8a6..4bcfc35 100644
--- a/solr/solr-ref-guide/modules/deployment-guide/pages/solr-control-script-reference.adoc
+++ b/solr/solr-ref-guide/modules/deployment-guide/pages/solr-control-script-reference.adoc
@@ -1152,12 +1152,12 @@
 [source,plain]
 ----
 $ bin/solr zk -h
-Usage: solr zk upconfig|downconfig -d <confdir> -n <configName> [-z zkHost]
-         solr zk cp [-r] <src> <dest> [-z zkHost]
-         solr zk rm [-r] <path> [-z zkHost]
-         solr zk mv <src> <dest> [-z zkHost]
-         solr zk ls [-r] <path> [-z zkHost]
-         solr zk mkroot <path> [-z zkHost]
+Usage: solr zk upconfig|downconfig -d <confdir> -n <configName> [-z zkHost] [-s solrUrl]
+         solr zk cp [-r] <src> <dest> [-z zkHost] [-s solrUrl]
+         solr zk rm [-r] <path> [-z zkHost] [-s solrUrl]
+         solr zk mv <src> <dest> [-z zkHost] [-s solrUrl]
+         solr zk ls [-r] <path> [-z zkHost] [-s solrUrl]
+         solr zk mkroot <path> [-z zkHost] [-s solrUrl]
 ----
 
 NOTE: Solr should have been started at least once before issuing these commands to initialize ZooKeeper with the znodes Solr expects.
@@ -1218,6 +1218,15 @@
 +
 *Example*: `-z 123.321.23.43:2181`
 
+`-solrUrl <url>`::
++
+[%autowidth,frame=none]
+|===
+|Optional |Default: `http://localhost:8983`
+|===
++
+Base Solr URL, which can be used in SolrCloud mode to determine the ZooKeeper connection string if that's not known.
+
 An example of this command with all of the parameters is:
 
 [source,bash]
@@ -1281,6 +1290,15 @@
 +
 *Example*: `-z 123.321.23.43:2181`
 
+`-solrUrl <url>`::
++
+[%autowidth,frame=none]
+|===
+|Optional |Default: `http://localhost:8983`
+|===
++
+Base Solr URL, which can be used in SolrCloud mode to determine the ZooKeeper connection string if that's not known.
+
 An example of this command with all parameters is:
 
 [source,bash]
@@ -1356,6 +1374,15 @@
 +
 *Example*: `-z 123.321.23.43:2181`
 
+`-solrUrl <url>`::
++
+[%autowidth,frame=none]
+|===
+|Optional |Default: `http://localhost:8983`
+|===
++
+Base Solr URL, which can be used in SolrCloud mode to determine the ZooKeeper connection string if that's not known.
+
 When `<src>` is a zk resource, `<dest>` may be '.'.
 If `<dest>` ends with '/', then `<dest>` will be a local folder or parent znode and the last element of the <src> path will be appended unless `<src>` also ends in a slash.
 `<dest>` may be `zk:`, which may be useful when using the `cp -r` form to backup/restore the entire zk state.
@@ -1430,6 +1457,15 @@
 +
 *Example*: `-z 123.321.23.43:2181`
 
+`-solrUrl <url>`::
++
+[%autowidth,frame=none]
+|===
+|Optional |Default: `http://localhost:8983`
+|===
++
+Base Solr URL, which can be used in SolrCloud mode to determine the ZooKeeper connection string if that's not known.
+
 Examples of this command with the parameters are:
 
 `bin/solr zk rm -r /configs`
@@ -1483,6 +1519,15 @@
 
 `bin/solr zk mv /configs/oldconfigset /configs/newconfigset`
 
+`-solrUrl <url>`::
++
+[%autowidth,frame=none]
+|===
+|Optional |Default: `http://localhost:8983`
+|===
++
+Base Solr URL, which can be used in SolrCloud mode to determine the ZooKeeper connection string if that's not known.
+
 
 === List a ZooKeeper znode's Children
 
@@ -1525,11 +1570,20 @@
 +
 *Example*: `-z 123.321.23.43:2181`
 
+`-solrUrl <url>`::
++
+[%autowidth,frame=none]
+|===
+|Optional |Default: `http://localhost:8983`
+|===
++
+Base Solr URL, which can be used in SolrCloud mode to determine the ZooKeeper connection string if that's not known.
+
 An example of this command with the parameters is:
 
 `bin/solr zk ls -r /collections/mycollection`
 
-`bin/solr zk ls /collections`
+`bin/solr zk ls /collections -s http://localhost:8983`
 
 
 === Create a znode (supports chroot)
@@ -1565,6 +1619,15 @@
 +
 *Example*: `-z 123.321.23.43:2181`
 
+`-solrUrl <url>`::
++
+[%autowidth,frame=none]
+|===
+|Optional |Default: `http://localhost:8983`
+|===
++
+Base Solr URL, which can be used in SolrCloud mode to determine the ZooKeeper connection string if that's not known.
+
 Examples of this command:
 
 `bin/solr zk mkroot /solr -z 123.321.23.43:2181`