This is an automated email from the ASF dual-hosted git repository.
malliaridis pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/main by this push:
new e1f56b30c33 SOLR-17501: Move out CLI utils from SolrCLI (#2744)
e1f56b30c33 is described below
commit e1f56b30c33d9adfcb2c7aac1c01ef5393400c1e
Author: Christos Malliaridis <[email protected]>
AuthorDate: Tue Nov 19 22:06:44 2024 +0200
SOLR-17501: Move out CLI utils from SolrCLI (#2744)
---
.../core/src/java/org/apache/solr/cli/ApiTool.java | 2 +-
.../src/java/org/apache/solr/cli/AssertTool.java | 18 +-
.../src/java/org/apache/solr/cli/AuthTool.java | 16 +-
.../src/java/org/apache/solr/cli/CLIUtils.java | 351 +++++++++++++++++++++
.../src/java/org/apache/solr/cli/ClusterTool.java | 2 +-
.../java/org/apache/solr/cli/CommonCLIOptions.java | 2 +-
.../org/apache/solr/cli/ConfigSetDownloadTool.java | 4 +-
.../org/apache/solr/cli/ConfigSetUploadTool.java | 6 +-
.../src/java/org/apache/solr/cli/ConfigTool.java | 4 +-
.../src/java/org/apache/solr/cli/CreateTool.java | 20 +-
.../src/java/org/apache/solr/cli/DeleteTool.java | 8 +-
.../src/java/org/apache/solr/cli/ExportTool.java | 4 +-
.../java/org/apache/solr/cli/HealthcheckTool.java | 12 +-
.../java/org/apache/solr/cli/LinkConfigTool.java | 2 +-
.../src/java/org/apache/solr/cli/PackageTool.java | 6 +-
.../src/java/org/apache/solr/cli/PostLogsTool.java | 2 +-
.../src/java/org/apache/solr/cli/PostTool.java | 8 +-
.../java/org/apache/solr/cli/RunExampleTool.java | 8 +-
.../org/apache/solr/cli/SnapshotCreateTool.java | 2 +-
.../org/apache/solr/cli/SnapshotDeleteTool.java | 2 +-
.../org/apache/solr/cli/SnapshotDescribeTool.java | 2 +-
.../org/apache/solr/cli/SnapshotExportTool.java | 2 +-
.../java/org/apache/solr/cli/SnapshotListTool.java | 2 +-
.../core/src/java/org/apache/solr/cli/SolrCLI.java | 296 +----------------
.../src/java/org/apache/solr/cli/StatusTool.java | 32 +-
.../src/java/org/apache/solr/cli/StreamTool.java | 4 +-
.../java/org/apache/solr/cli/UpdateACLTool.java | 2 +-
.../src/java/org/apache/solr/cli/ZkCpTool.java | 2 +-
.../src/java/org/apache/solr/cli/ZkLsTool.java | 4 +-
.../src/java/org/apache/solr/cli/ZkMkrootTool.java | 4 +-
.../src/java/org/apache/solr/cli/ZkMvTool.java | 4 +-
.../src/java/org/apache/solr/cli/ZkRmTool.java | 4 +-
.../apache/solr/packagemanager/PackageManager.java | 5 +-
.../apache/solr/packagemanager/PackageUtils.java | 4 +-
.../src/test/org/apache/solr/cli/CLIUtilsTest.java | 144 +++++++++
.../src/test/org/apache/solr/cli/SolrCLITest.java | 9 -
.../org/apache/solr/cli/TestSolrCLIRunExample.java | 2 +-
.../apache/solr/cloud/SolrCloudExampleTest.java | 3 +-
38 files changed, 594 insertions(+), 410 deletions(-)
diff --git a/solr/core/src/java/org/apache/solr/cli/ApiTool.java
b/solr/core/src/java/org/apache/solr/cli/ApiTool.java
index 02f893b3753..ede4de68971 100644
--- a/solr/core/src/java/org/apache/solr/cli/ApiTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/ApiTool.java
@@ -79,7 +79,7 @@ public class ApiTool extends ToolBase {
URI uri = new URI(url.replace("+", "%20"));
String solrUrl = getSolrUrlFromUri(uri);
String path = uri.getPath();
- try (var solrClient = SolrCLI.getSolrClient(solrUrl, credentials)) {
+ try (var solrClient = CLIUtils.getSolrClient(solrUrl, credentials)) {
// For path parameter we need the path without the root so from the
second / char
// (because root can be configured)
// E.g URL is http://localhost:8983/solr/admin/info/system path is
diff --git a/solr/core/src/java/org/apache/solr/cli/AssertTool.java
b/solr/core/src/java/org/apache/solr/cli/AssertTool.java
index b710d0934b2..b111ef7b481 100644
--- a/solr/core/src/java/org/apache/solr/cli/AssertTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/AssertTool.java
@@ -250,13 +250,13 @@ public class AssertTool extends ToolBase {
if (cli.hasOption(IS_CLOUD_OPTION)) {
ret +=
assertSolrRunningInCloudMode(
- SolrCLI.normalizeSolrUrl(cli.getOptionValue(IS_CLOUD_OPTION)),
+ CLIUtils.normalizeSolrUrl(cli.getOptionValue(IS_CLOUD_OPTION)),
cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION));
}
if (cli.hasOption(IS_NOT_CLOUD_OPTION)) {
ret +=
assertSolrNotRunningInCloudMode(
-
SolrCLI.normalizeSolrUrl(cli.getOptionValue(IS_NOT_CLOUD_OPTION)),
+
CLIUtils.normalizeSolrUrl(cli.getOptionValue(IS_NOT_CLOUD_OPTION)),
cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION));
}
return ret;
@@ -267,7 +267,7 @@ public class AssertTool extends ToolBase {
try {
status.waitToSeeSolrUp(url, credentials, timeoutMs,
TimeUnit.MILLISECONDS);
} catch (Exception se) {
- if (SolrCLI.exceptionIsAuthRelated(se)) {
+ if (CLIUtils.exceptionIsAuthRelated(se)) {
throw se;
}
return exitOrException(
@@ -284,10 +284,10 @@ public class AssertTool extends ToolBase {
StatusTool status = new StatusTool();
long timeout =
System.nanoTime() + TimeUnit.NANOSECONDS.convert(timeoutMs,
TimeUnit.MILLISECONDS);
- try (SolrClient solrClient = SolrCLI.getSolrClient(url, credentials)) {
+ try (SolrClient solrClient = CLIUtils.getSolrClient(url, credentials)) {
NamedList<Object> response = solrClient.request(new
HealthCheckRequest());
Integer statusCode = (Integer) response.findRecursive("responseHeader",
"status");
- SolrCLI.checkCodeForAuthError(statusCode);
+ CLIUtils.checkCodeForAuthError(statusCode);
} catch (IOException | SolrServerException e) {
log.debug("Opening connection to {} failed, Solr does not seem to be
running", url, e);
return 0;
@@ -302,7 +302,7 @@ public class AssertTool extends ToolBase {
timeout = 0; // stop looping
}
} catch (Exception se) {
- if (SolrCLI.exceptionIsAuthRelated(se)) {
+ if (CLIUtils.exceptionIsAuthRelated(se)) {
throw se;
}
return exitOrException(se.getMessage());
@@ -417,7 +417,7 @@ public class AssertTool extends ToolBase {
status.waitToSeeSolrUp(url, credentials, timeoutMs,
TimeUnit.MILLISECONDS);
return true;
} catch (Exception se) {
- if (SolrCLI.exceptionIsAuthRelated(se)) {
+ if (CLIUtils.exceptionIsAuthRelated(se)) {
throw se;
}
return false;
@@ -425,8 +425,8 @@ public class AssertTool extends ToolBase {
}
private static boolean runningSolrIsCloud(String url, String credentials)
throws Exception {
- try (final SolrClient client = SolrCLI.getSolrClient(url, credentials)) {
- return SolrCLI.isCloudMode(client);
+ try (final SolrClient client = CLIUtils.getSolrClient(url, credentials)) {
+ return CLIUtils.isCloudMode(client);
}
}
diff --git a/solr/core/src/java/org/apache/solr/cli/AuthTool.java
b/solr/core/src/java/org/apache/solr/cli/AuthTool.java
index 817b0093748..45b609a2943 100644
--- a/solr/core/src/java/org/apache/solr/cli/AuthTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/AuthTool.java
@@ -194,7 +194,7 @@ public class AuthTool extends ToolBase {
if (!updateIncludeFileOnly) {
try {
- zkHost = SolrCLI.getZkHost(cli);
+ zkHost = CLIUtils.getZkHost(cli);
} catch (Exception ex) {
CLIO.out(
"Unable to access ZooKeeper. Please add the following
security.json to ZooKeeper (in case of SolrCloud):\n"
@@ -214,7 +214,7 @@ public class AuthTool extends ToolBase {
// check if security is already enabled or not
if (!zkInaccessible) {
- try (SolrZkClient zkClient = SolrCLI.getSolrZkClient(cli, zkHost))
{
+ try (SolrZkClient zkClient = CLIUtils.getSolrZkClient(cli,
zkHost)) {
checkSecurityJsonExists(zkClient);
} catch (Exception ex) {
CLIO.out(
@@ -229,7 +229,7 @@ public class AuthTool extends ToolBase {
if (!updateIncludeFileOnly) {
if (!zkInaccessible) {
echoIfVerbose("Uploading following security.json: " +
securityJson);
- try (SolrZkClient zkClient = SolrCLI.getSolrZkClient(cli, zkHost))
{
+ try (SolrZkClient zkClient = CLIUtils.getSolrZkClient(cli,
zkHost)) {
zkClient.setData(
"/security.json",
securityJson.getBytes(StandardCharsets.UTF_8), true);
} catch (Exception ex) {
@@ -309,7 +309,7 @@ public class AuthTool extends ToolBase {
if (!updateIncludeFileOnly) {
try {
- zkHost = SolrCLI.getZkHost(cli);
+ zkHost = CLIUtils.getZkHost(cli);
} catch (Exception ex) {
if (cli.hasOption(CommonCLIOptions.ZK_HOST_OPTION)) {
CLIO.out(
@@ -332,7 +332,7 @@ public class AuthTool extends ToolBase {
}
// check if security is already enabled or not
- try (SolrZkClient zkClient = SolrCLI.getSolrZkClient(cli, zkHost)) {
+ try (SolrZkClient zkClient = CLIUtils.getSolrZkClient(cli, zkHost)) {
checkSecurityJsonExists(zkClient);
}
}
@@ -381,7 +381,7 @@ public class AuthTool extends ToolBase {
if (!updateIncludeFileOnly) {
echoIfVerbose("Uploading following security.json: " + securityJson);
- try (SolrZkClient zkClient = SolrCLI.getSolrZkClient(cli, zkHost)) {
+ try (SolrZkClient zkClient = CLIUtils.getSolrZkClient(cli, zkHost)) {
zkClient.setData("/security.json",
securityJson.getBytes(StandardCharsets.UTF_8), true);
}
}
@@ -460,7 +460,7 @@ public class AuthTool extends ToolBase {
private void clearSecurityJson(CommandLine cli, boolean
updateIncludeFileOnly) throws Exception {
String zkHost;
if (!updateIncludeFileOnly) {
- zkHost = SolrCLI.getZkHost(cli);
+ zkHost = CLIUtils.getZkHost(cli);
if (zkHost == null) {
stdout.print("ZK Host not found. Solr should be running in cloud
mode.");
SolrCLI.exit(1);
@@ -468,7 +468,7 @@ public class AuthTool extends ToolBase {
echoIfVerbose("Uploading following security.json: {}");
- try (SolrZkClient zkClient = SolrCLI.getSolrZkClient(cli, zkHost)) {
+ try (SolrZkClient zkClient = CLIUtils.getSolrZkClient(cli, zkHost)) {
zkClient.setData("/security.json",
"{}".getBytes(StandardCharsets.UTF_8), true);
}
}
diff --git a/solr/core/src/java/org/apache/solr/cli/CLIUtils.java
b/solr/core/src/java/org/apache/solr/cli/CLIUtils.java
new file mode 100644
index 00000000000..7f4c0dc648b
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cli/CLIUtils.java
@@ -0,0 +1,351 @@
+/*
+ * 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.cli;
+
+import static org.apache.solr.common.SolrException.ErrorCode.FORBIDDEN;
+import static org.apache.solr.common.SolrException.ErrorCode.UNAUTHORIZED;
+import static org.apache.solr.common.params.CommonParams.NAME;
+import static org.apache.solr.common.params.CommonParams.SYSTEM_INFO_PATH;
+
+import java.io.IOException;
+import java.net.SocketException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import org.apache.commons.cli.CommandLine;
+import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.impl.CloudHttp2SolrClient;
+import org.apache.solr.client.solrj.impl.CloudSolrClient;
+import org.apache.solr.client.solrj.impl.Http2SolrClient;
+import org.apache.solr.client.solrj.impl.SolrZkClientTimeout;
+import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.client.solrj.request.CoreAdminRequest;
+import org.apache.solr.client.solrj.request.GenericSolrRequest;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.cloud.SolrZkClient;
+import org.apache.solr.common.cloud.ZkStateReader;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.util.EnvUtils;
+import org.apache.solr.common.util.NamedList;
+
+/** Utility class that holds various helper methods for the CLI. */
+public final class CLIUtils {
+
+ private CLIUtils() {}
+
+ public static String RED = "\u001B[31m";
+
+ public static String GREEN = "\u001B[32m";
+
+ public static String YELLOW = "\u001B[33m";
+
+ private static final long MAX_WAIT_FOR_CORE_LOAD_NANOS =
+ TimeUnit.NANOSECONDS.convert(1, TimeUnit.MINUTES);
+
+ public static String getDefaultSolrUrl() {
+ // note that ENV_VAR syntax (and the env vars too) are mapped to env.var
sys props
+ String scheme = EnvUtils.getProperty("solr.url.scheme", "http");
+ String host = EnvUtils.getProperty("solr.tool.host", "localhost");
+ String port = EnvUtils.getProperty("jetty.port", "8983"); // from
SOLR_PORT env
+ return String.format(Locale.ROOT, "%s://%s:%s",
scheme.toLowerCase(Locale.ROOT), host, port);
+ }
+
+ /**
+ * Determine if a request to Solr failed due to a communication error, which
is generally
+ * retry-able.
+ */
+ public static boolean checkCommunicationError(Exception exc) {
+ Throwable rootCause = SolrException.getRootCause(exc);
+ return (rootCause instanceof SolrServerException || rootCause instanceof
SocketException);
+ }
+
+ public static void checkCodeForAuthError(int code) {
+ if (code == UNAUTHORIZED.code || code == FORBIDDEN.code) {
+ throw new SolrException(
+ SolrException.ErrorCode.getErrorCode(code),
+ "Solr requires authentication for request. Please supply valid
credentials. HTTP code="
+ + code);
+ }
+ }
+
+ public static boolean exceptionIsAuthRelated(Exception exc) {
+ return (exc instanceof SolrException
+ && Arrays.asList(UNAUTHORIZED.code,
FORBIDDEN.code).contains(((SolrException) exc).code()));
+ }
+
+ public static SolrClient getSolrClient(String solrUrl, String credentials,
boolean barePath) {
+ // today we require all urls to end in /solr, however in the future we
will need to support the
+ // /api url end point instead. Eventually we want to have this method
always
+ // return a bare url, and then individual calls decide if they are /solr
or /api
+ // The /solr/ check is because sometimes a full url is passed in, like
+ // http://localhost:8983/solr/films_shard1_replica_n1/.
+ if (!barePath && !solrUrl.endsWith("/solr") &&
!solrUrl.contains("/solr/")) {
+ solrUrl = solrUrl + "/solr";
+ }
+ Http2SolrClient.Builder builder =
+ new Http2SolrClient.Builder(solrUrl)
+ .withMaxConnectionsPerHost(32)
+ .withKeyStoreReloadInterval(-1, TimeUnit.SECONDS)
+ .withOptionalBasicAuthCredentials(credentials);
+
+ return builder.build();
+ }
+
+ /**
+ * Helper method for all the places where we assume a /solr on the url.
+ *
+ * @param solrUrl The solr url that you want the client for
+ * @param credentials The username:password for basic auth.
+ * @return The SolrClient
+ */
+ public static SolrClient getSolrClient(String solrUrl, String credentials) {
+ return getSolrClient(solrUrl, credentials, false);
+ }
+
+ public static SolrClient getSolrClient(CommandLine cli, boolean barePath)
throws Exception {
+ String solrUrl = normalizeSolrUrl(cli);
+ String credentials =
cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION);
+ return getSolrClient(solrUrl, credentials, barePath);
+ }
+
+ public static SolrClient getSolrClient(CommandLine cli) throws Exception {
+ String solrUrl = normalizeSolrUrl(cli);
+ String credentials =
cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION);
+ return getSolrClient(solrUrl, credentials, false);
+ }
+
+ /**
+ * Strips off the end of solrUrl any /solr when a legacy solrUrl like
http://localhost:8983/solr
+ * is used, and warns those users. In the future we'll have urls ending with
/api as well.
+ *
+ * @param solrUrl The user supplied url to Solr.
+ * @return the solrUrl in the format that Solr expects to see internally.
+ */
+ public static String normalizeSolrUrl(String solrUrl) {
+ return normalizeSolrUrl(solrUrl, true);
+ }
+
+ /**
+ * Strips off the end of solrUrl any /solr when a legacy solrUrl like
http://localhost:8983/solr
+ * is used, and optionally logs a warning. In the future we'll have urls
ending with /api as well.
+ *
+ * @param solrUrl The user supplied url to Solr.
+ * @param logUrlFormatWarning If a warning message should be logged about
the url format
+ * @return the solrUrl in the format that Solr expects to see internally.
+ */
+ public static String normalizeSolrUrl(String solrUrl, boolean
logUrlFormatWarning) {
+ if (solrUrl != null) {
+ URI uri = URI.create(solrUrl);
+ String urlPath = uri.getRawPath();
+ if (urlPath != null && urlPath.contains("/solr")) {
+ String newSolrUrl =
+ uri.resolve(urlPath.substring(0, urlPath.lastIndexOf("/solr") +
1)).toString();
+ if (logUrlFormatWarning) {
+ CLIO.err(
+ "WARNING: URLs provided to this tool needn't include Solr's
context-root (e.g. \"/solr\"). Such URLs are deprecated and support for them
will be removed in a future release. Correcting from ["
+ + solrUrl
+ + "] to ["
+ + newSolrUrl
+ + "].");
+ }
+ solrUrl = newSolrUrl;
+ }
+ if (solrUrl.endsWith("/")) {
+ solrUrl = solrUrl.substring(0, solrUrl.length() - 1);
+ }
+ }
+ return solrUrl;
+ }
+
+ /**
+ * Get the base URL of a live Solr instance from either the --solr-url
command-line option or from
+ * ZooKeeper.
+ */
+ public static String normalizeSolrUrl(CommandLine cli) throws Exception {
+ String solrUrl = cli.getOptionValue(CommonCLIOptions.SOLR_URL_OPTION);
+
+ if (solrUrl == null) {
+ String zkHost = cli.getOptionValue(CommonCLIOptions.ZK_HOST_OPTION);
+ if (zkHost == null) {
+ solrUrl = getDefaultSolrUrl();
+ CLIO.err(
+ "Neither --zk-host or --solr-url parameters provided so assuming
solr url is "
+ + solrUrl
+ + ".");
+ } else {
+ try (CloudSolrClient cloudSolrClient =
getCloudHttp2SolrClient(zkHost)) {
+ cloudSolrClient.connect();
+ Set<String> liveNodes =
cloudSolrClient.getClusterState().getLiveNodes();
+ if (liveNodes.isEmpty())
+ throw new IllegalStateException(
+ "No live nodes found! Cannot determine 'solrUrl' from
ZooKeeper: " + zkHost);
+
+ String firstLiveNode = liveNodes.iterator().next();
+ solrUrl =
ZkStateReader.from(cloudSolrClient).getBaseUrlForNodeName(firstLiveNode);
+ solrUrl = normalizeSolrUrl(solrUrl, false);
+ }
+ }
+ }
+ solrUrl = normalizeSolrUrl(solrUrl);
+ return solrUrl;
+ }
+
+ /**
+ * Get the ZooKeeper connection string from either the zk-host command-line
option or by looking
+ * it up from a running Solr instance based on the solr-url option.
+ */
+ public static String getZkHost(CommandLine cli) throws Exception {
+
+ String zkHost = cli.getOptionValue(CommonCLIOptions.ZK_HOST_OPTION);
+ if (zkHost != null && !zkHost.isBlank()) {
+ return zkHost;
+ }
+
+ try (SolrClient solrClient = getSolrClient(cli)) {
+ // hit Solr to get system info
+ NamedList<Object> systemInfo =
+ solrClient.request(
+ new GenericSolrRequest(SolrRequest.METHOD.GET,
CommonParams.SYSTEM_INFO_PATH));
+
+ // convert raw JSON into user-friendly output
+ StatusTool statusTool = new StatusTool();
+ Map<String, Object> status = statusTool.reportStatus(systemInfo,
solrClient);
+ @SuppressWarnings("unchecked")
+ Map<String, Object> cloud = (Map<String, Object>) status.get("cloud");
+ if (cloud != null) {
+ String zookeeper = (String) cloud.get("ZooKeeper");
+ if (zookeeper.endsWith("(embedded)")) {
+ zookeeper = zookeeper.substring(0, zookeeper.length() -
"(embedded)".length());
+ }
+ zkHost = zookeeper;
+ }
+ }
+
+ return zkHost;
+ }
+
+ public static SolrZkClient getSolrZkClient(CommandLine cli, String zkHost)
throws Exception {
+ if (zkHost == null) {
+ throw new IllegalStateException(
+ "Solr at "
+ + cli.getOptionValue(CommonCLIOptions.SOLR_URL_OPTION)
+ + " is running in standalone server mode, this command can only
be used when running in SolrCloud mode.\n");
+ }
+ return new SolrZkClient.Builder()
+ .withUrl(zkHost)
+ .withTimeout(SolrZkClientTimeout.DEFAULT_ZK_CLIENT_TIMEOUT,
TimeUnit.MILLISECONDS)
+ .build();
+ }
+
+ public static CloudHttp2SolrClient getCloudHttp2SolrClient(String zkHost) {
+ return getCloudHttp2SolrClient(zkHost, null);
+ }
+
+ public static CloudHttp2SolrClient getCloudHttp2SolrClient(
+ String zkHost, Http2SolrClient.Builder builder) {
+ return new CloudHttp2SolrClient.Builder(Collections.singletonList(zkHost),
Optional.empty())
+ .withInternalClientBuilder(builder)
+ .build();
+ }
+
+ /**
+ * Extracts the port from the provided {@code solrUrl}. If a URL is provided
with https scheme and
+ * not explicitly defines the port, the default port for HTTPS (443) is used.
+ *
+ * <p>If URL does not contain a port nor https as scheme, it falls back to
port 80.
+ *
+ * @param solrUrl the URL to extract the port from
+ * @return The port that was found.
+ * @throws NullPointerException If solrUrl is null
+ * @throws URISyntaxException If the given string violates RFC 2396, as
augmented by the above
+ * deviations
+ */
+ public static int portFromUrl(String solrUrl) throws URISyntaxException {
+ URI uri = new URI(solrUrl);
+ int port = uri.getPort();
+ if (port == -1) {
+ return uri.getScheme().equals("https") ? 443 : 80;
+ } else {
+ return port;
+ }
+ }
+
+ public static boolean safeCheckCollectionExists(
+ String solrUrl, String collection, String credentials) {
+ boolean exists = false;
+ try (var solrClient = getSolrClient(solrUrl, credentials)) {
+ NamedList<Object> existsCheckResult = solrClient.request(new
CollectionAdminRequest.List());
+ @SuppressWarnings("unchecked")
+ List<String> collections = (List<String>)
existsCheckResult.get("collections");
+ exists = collections != null && collections.contains(collection);
+ } catch (Exception exc) {
+ // just ignore it since we're only interested in a positive result here
+ }
+ return exists;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static boolean safeCheckCoreExists(String solrUrl, String coreName,
String credentials) {
+ boolean exists = false;
+ try (var solrClient = getSolrClient(solrUrl, credentials)) {
+ boolean wait = false;
+ final long startWaitAt = System.nanoTime();
+ do {
+ if (wait) {
+ final int clamPeriodForStatusPollMs = 1000;
+ Thread.sleep(clamPeriodForStatusPollMs);
+ }
+ NamedList<Object> existsCheckResult =
+ CoreAdminRequest.getStatus(coreName, solrClient).getResponse();
+ NamedList<Object> status = (NamedList<Object>)
existsCheckResult.get("status");
+ NamedList<Object> coreStatus = (NamedList<Object>)
status.get(coreName);
+ Map<String, Object> failureStatus =
+ (Map<String, Object>) existsCheckResult.get("initFailures");
+ String errorMsg = (String) failureStatus.get(coreName);
+ final boolean hasName = coreStatus != null &&
coreStatus.asMap().containsKey(NAME);
+ exists = hasName || errorMsg != null;
+ wait = hasName && errorMsg == null &&
"true".equals(coreStatus.get("isLoading"));
+ } while (wait && System.nanoTime() - startWaitAt <
MAX_WAIT_FOR_CORE_LOAD_NANOS);
+ } catch (Exception exc) {
+ // just ignore it since we're only interested in a positive result here
+ }
+ return exists;
+ }
+
+ public static boolean isCloudMode(SolrClient solrClient) throws
SolrServerException, IOException {
+ NamedList<Object> systemInfo =
+ solrClient.request(new GenericSolrRequest(SolrRequest.METHOD.GET,
SYSTEM_INFO_PATH));
+ return "solrcloud".equals(systemInfo.get("mode"));
+ }
+
+ public static Path getConfigSetsDir(Path solrInstallDir) {
+ Path configSetsPath = Paths.get("server/solr/configsets/");
+ return solrInstallDir.resolve(configSetsPath);
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/cli/ClusterTool.java
b/solr/core/src/java/org/apache/solr/cli/ClusterTool.java
index 1c71b7b8fee..714654829cc 100644
--- a/solr/core/src/java/org/apache/solr/cli/ClusterTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/ClusterTool.java
@@ -79,7 +79,7 @@ public class ClusterTool extends ToolBase {
String propertyName = cli.getOptionValue(PROPERTY_OPTION);
String propertyValue = cli.getOptionValue(VALUE_OPTION);
- String zkHost = SolrCLI.getZkHost(cli);
+ String zkHost = CLIUtils.getZkHost(cli);
if (!ZkController.checkChrootPath(zkHost, true)) {
throw new IllegalStateException(
diff --git a/solr/core/src/java/org/apache/solr/cli/CommonCLIOptions.java
b/solr/core/src/java/org/apache/solr/cli/CommonCLIOptions.java
index 93f02c3e359..e6425abe1f3 100644
--- a/solr/core/src/java/org/apache/solr/cli/CommonCLIOptions.java
+++ b/solr/core/src/java/org/apache/solr/cli/CommonCLIOptions.java
@@ -47,7 +47,7 @@ public final class CommonCLIOptions {
.argName("HOST")
.desc(
"Base Solr URL, which can be used to determine the zk-host if
that's not known; defaults to: "
- + SolrCLI.getDefaultSolrUrl()
+ + CLIUtils.getDefaultSolrUrl()
+ '.')
.build();
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 b55b939117b..264023640f7 100644
--- a/solr/core/src/java/org/apache/solr/cli/ConfigSetDownloadTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/ConfigSetDownloadTool.java
@@ -79,13 +79,13 @@ public class ConfigSetDownloadTool extends ToolBase {
@Override
public void runImpl(CommandLine cli) throws Exception {
- String zkHost = SolrCLI.getZkHost(cli);
+ String zkHost = CLIUtils.getZkHost(cli);
String confName = cli.getOptionValue(CONF_NAME_OPTION);
String confDir = cli.getOptionValue(CONF_DIR_OPTION);
echoIfVerbose("\nConnecting to ZooKeeper at " + zkHost + " ...");
- try (SolrZkClient zkClient = SolrCLI.getSolrZkClient(cli, zkHost)) {
+ try (SolrZkClient zkClient = CLIUtils.getSolrZkClient(cli, zkHost)) {
Path configSetPath = Paths.get(confDir);
// we try to be nice about having the "conf" in the directory, and we
create it if it's not
// there.
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 b959245af2e..a9fc0631e11 100644
--- a/solr/core/src/java/org/apache/solr/cli/ConfigSetUploadTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/ConfigSetUploadTool.java
@@ -81,7 +81,7 @@ public class ConfigSetUploadTool extends ToolBase {
@Override
public void runImpl(CommandLine cli) throws Exception {
- String zkHost = SolrCLI.getZkHost(cli);
+ String zkHost = CLIUtils.getZkHost(cli);
final String solrInstallDir = System.getProperty("solr.install.dir");
Path solrInstallDirPath = Paths.get(solrInstallDir);
@@ -90,8 +90,8 @@ public class ConfigSetUploadTool extends ToolBase {
String confDir = cli.getOptionValue(CONF_DIR_OPTION);
echoIfVerbose("\nConnecting to ZooKeeper at " + zkHost + " ...");
- try (SolrZkClient zkClient = SolrCLI.getSolrZkClient(cli, zkHost)) {
- final Path configsetsDirPath =
SolrCLI.getConfigSetsDir(solrInstallDirPath);
+ try (SolrZkClient zkClient = CLIUtils.getSolrZkClient(cli, zkHost)) {
+ final Path configsetsDirPath =
CLIUtils.getConfigSetsDir(solrInstallDirPath);
Path confPath = ConfigSetService.getConfigsetPath(confDir,
configsetsDirPath.toString());
echo(
diff --git a/solr/core/src/java/org/apache/solr/cli/ConfigTool.java
b/solr/core/src/java/org/apache/solr/cli/ConfigTool.java
index fdd18f24d4b..e5e7c96791c 100644
--- a/solr/core/src/java/org/apache/solr/cli/ConfigTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/ConfigTool.java
@@ -98,7 +98,7 @@ public class ConfigTool extends ToolBase {
@Override
public void runImpl(CommandLine cli) throws Exception {
- String solrUrl = SolrCLI.normalizeSolrUrl(cli);
+ String solrUrl = CLIUtils.normalizeSolrUrl(cli);
String action = cli.getOptionValue(ACTION_OPTION, "set-property");
String collection = cli.getOptionValue(COLLECTION_NAME_OPTION);
String property = cli.getOptionValue(PROPERTY_OPTION);
@@ -127,7 +127,7 @@ public class ConfigTool extends ToolBase {
echoIfVerbose(jsonBody);
try (SolrClient solrClient =
- SolrCLI.getSolrClient(solrUrl,
cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION))) {
+ CLIUtils.getSolrClient(solrUrl,
cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION))) {
NamedList<Object> result = SolrCLI.postJsonToSolr(solrClient,
updatePath, jsonBody);
Integer statusCode = (Integer) result.findRecursive("responseHeader",
"status");
if (statusCode == 0) {
diff --git a/solr/core/src/java/org/apache/solr/cli/CreateTool.java
b/solr/core/src/java/org/apache/solr/cli/CreateTool.java
index 5fc57501d93..b1607af071b 100644
--- a/solr/core/src/java/org/apache/solr/cli/CreateTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/CreateTool.java
@@ -138,8 +138,8 @@ public class CreateTool extends ToolBase {
@Override
public void runImpl(CommandLine cli) throws Exception {
- try (var solrClient = SolrCLI.getSolrClient(cli)) {
- if (SolrCLI.isCloudMode(solrClient)) {
+ try (var solrClient = CLIUtils.getSolrClient(cli)) {
+ if (CLIUtils.isCloudMode(solrClient)) {
createCollection(cli);
} else {
createCore(cli, solrClient);
@@ -150,7 +150,7 @@ public class CreateTool extends ToolBase {
protected void createCore(CommandLine cli, SolrClient solrClient) throws
Exception {
String coreName = cli.getOptionValue(COLLECTION_NAME_OPTION);
String solrUrl =
- cli.getOptionValue(CommonCLIOptions.SOLR_URL_OPTION,
SolrCLI.getDefaultSolrUrl());
+ cli.getOptionValue(CommonCLIOptions.SOLR_URL_OPTION,
CLIUtils.getDefaultSolrUrl());
final String solrInstallDir = System.getProperty("solr.install.dir");
final String confDirName =
@@ -175,7 +175,7 @@ public class CreateTool extends ToolBase {
// convert raw JSON into user-friendly output
coreRootDirectory = (String) systemInfo.get("core_root");
- if (SolrCLI.safeCheckCoreExists(
+ if (CLIUtils.safeCheckCoreExists(
solrUrl, coreName,
cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION))) {
throw new IllegalArgumentException(
"\nCore '"
@@ -224,9 +224,9 @@ public class CreateTool extends ToolBase {
.withKeyStoreReloadInterval(-1, TimeUnit.SECONDS)
.withOptionalBasicAuthCredentials(
cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION));
- String zkHost = SolrCLI.getZkHost(cli);
+ String zkHost = CLIUtils.getZkHost(cli);
echoIfVerbose("Connecting to ZooKeeper at " + zkHost);
- try (CloudSolrClient cloudSolrClient =
SolrCLI.getCloudHttp2SolrClient(zkHost, builder)) {
+ try (CloudSolrClient cloudSolrClient =
CLIUtils.getCloudHttp2SolrClient(zkHost, builder)) {
cloudSolrClient.connect();
createCollection(cloudSolrClient, cli);
}
@@ -277,7 +277,7 @@ public class CreateTool extends ToolBase {
}
// TODO: This should be done using the configSet API
- final Path configsetsDirPath =
SolrCLI.getConfigSetsDir(solrInstallDirPath);
+ final Path configsetsDirPath =
CLIUtils.getConfigSetsDir(solrInstallDirPath);
ConfigSetService configSetService =
new
ZkConfigSetService(ZkStateReader.from(cloudSolrClient).getZkClient());
Path confPath = ConfigSetService.getConfigsetPath(confDir,
configsetsDirPath.toString());
@@ -294,7 +294,7 @@ public class CreateTool extends ToolBase {
}
// since creating a collection is a heavy-weight operation, check for
existence first
- if (SolrCLI.safeCheckCollectionExists(
+ if (CLIUtils.safeCheckCollectionExists(
solrUrl, collectionName,
cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION))) {
throw new IllegalStateException(
"\nCollection '"
@@ -339,7 +339,7 @@ public class CreateTool extends ToolBase {
}
private Path getFullConfDir(Path solrInstallDir, Path confDirName) {
- return SolrCLI.getConfigSetsDir(solrInstallDir).resolve(confDirName);
+ return CLIUtils.getConfigSetsDir(solrInstallDir).resolve(confDirName);
}
private void ensureConfDirExists(Path solrInstallDir, Path confDirName) {
@@ -362,7 +362,7 @@ public class CreateTool extends ToolBase {
&& (confName.equals("") || confName.equals("_default"))) {
final String collectionName = cli.getOptionValue(COLLECTION_NAME_OPTION);
final String solrUrl =
- cli.getOptionValue(CommonCLIOptions.SOLR_URL_OPTION,
SolrCLI.getDefaultSolrUrl());
+ cli.getOptionValue(CommonCLIOptions.SOLR_URL_OPTION,
CLIUtils.getDefaultSolrUrl());
final String curlCommand =
String.format(
Locale.ROOT,
diff --git a/solr/core/src/java/org/apache/solr/cli/DeleteTool.java
b/solr/core/src/java/org/apache/solr/cli/DeleteTool.java
index 2c42f8dc030..7fc94cb85d3 100644
--- a/solr/core/src/java/org/apache/solr/cli/DeleteTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/DeleteTool.java
@@ -101,8 +101,8 @@ public class DeleteTool extends ToolBase {
@Override
public void runImpl(CommandLine cli) throws Exception {
- try (var solrClient = SolrCLI.getSolrClient(cli)) {
- if (SolrCLI.isCloudMode(solrClient)) {
+ try (var solrClient = CLIUtils.getSolrClient(cli)) {
+ if (CLIUtils.isCloudMode(solrClient)) {
deleteCollection(cli);
} else {
deleteCore(cli, solrClient);
@@ -119,8 +119,8 @@ public class DeleteTool extends ToolBase {
.withOptionalBasicAuthCredentials(
cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION));
- String zkHost = SolrCLI.getZkHost(cli);
- try (CloudSolrClient cloudSolrClient =
SolrCLI.getCloudHttp2SolrClient(zkHost, builder)) {
+ String zkHost = CLIUtils.getZkHost(cli);
+ try (CloudSolrClient cloudSolrClient =
CLIUtils.getCloudHttp2SolrClient(zkHost, builder)) {
echoIfVerbose("Connecting to ZooKeeper at " + zkHost);
cloudSolrClient.connect();
deleteCollection(cloudSolrClient, cli);
diff --git a/solr/core/src/java/org/apache/solr/cli/ExportTool.java
b/solr/core/src/java/org/apache/solr/cli/ExportTool.java
index 5018855e597..ee8e5a42c78 100644
--- a/solr/core/src/java/org/apache/solr/cli/ExportTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/ExportTool.java
@@ -284,7 +284,7 @@ public class ExportTool extends ToolBase {
throw new IllegalArgumentException(
"Must specify -c / --name parameter with --solr-url to post
documents.");
}
- url = SolrCLI.normalizeSolrUrl(cli) + "/solr/" +
cli.getOptionValue(COLLECTION_NAME_OPTION);
+ url = CLIUtils.normalizeSolrUrl(cli) + "/solr/" +
cli.getOptionValue(COLLECTION_NAME_OPTION);
} else {
// think about support --zk-host someday.
@@ -664,7 +664,7 @@ public class ExportTool extends ToolBase {
boolean exportDocsFromCore() throws IOException, SolrServerException {
- try (SolrClient client = SolrCLI.getSolrClient(baseurl, credentials)) {
+ try (SolrClient client = CLIUtils.getSolrClient(baseurl, credentials))
{
expectedDocs = getDocCount(replica.getCoreName(), client, query);
QueryRequest request;
ModifiableSolrParams params = new ModifiableSolrParams();
diff --git a/solr/core/src/java/org/apache/solr/cli/HealthcheckTool.java
b/solr/core/src/java/org/apache/solr/cli/HealthcheckTool.java
index 6ec08f77d6c..8a6b293e17a 100644
--- a/solr/core/src/java/org/apache/solr/cli/HealthcheckTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/HealthcheckTool.java
@@ -89,12 +89,12 @@ public class HealthcheckTool extends ToolBase {
@Override
public void runImpl(CommandLine cli) throws Exception {
- String zkHost = SolrCLI.getZkHost(cli);
+ String zkHost = CLIUtils.getZkHost(cli);
if (zkHost == null) {
CLIO.err("Healthcheck tool only works in Solr Cloud mode.");
System.exit(1);
}
- try (CloudHttp2SolrClient cloudSolrClient =
SolrCLI.getCloudHttp2SolrClient(zkHost)) {
+ try (CloudHttp2SolrClient cloudSolrClient =
CLIUtils.getCloudHttp2SolrClient(zkHost)) {
echoIfVerbose("\nConnecting to ZooKeeper at " + zkHost + " ...");
cloudSolrClient.connect();
runCloudTool(cloudSolrClient, cli);
@@ -125,7 +125,7 @@ public class HealthcheckTool extends ToolBase {
SolrQuery q = new SolrQuery("*:*");
q.setRows(0);
QueryResponse qr = cloudSolrClient.query(collection, q);
- SolrCLI.checkCodeForAuthError(qr.getStatus());
+ CLIUtils.checkCodeForAuthError(qr.getStatus());
String collErr = null;
long docCount = -1;
try {
@@ -169,12 +169,12 @@ public class HealthcheckTool extends ToolBase {
q.setRows(0);
q.set(DISTRIB, "false");
try (var solrClientForCollection =
- SolrCLI.getSolrClient(
+ CLIUtils.getSolrClient(
coreUrl,
cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION))) {
qr = solrClientForCollection.query(q);
numDocs = qr.getResults().getNumFound();
try (var solrClient =
- SolrCLI.getSolrClient(
+ CLIUtils.getSolrClient(
replicaCoreProps.getBaseUrl(),
cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION))) {
NamedList<Object> systemInfo =
@@ -192,7 +192,7 @@ public class HealthcheckTool extends ToolBase {
} catch (Exception exc) {
log.error("ERROR: {} when trying to reach: {}", exc, coreUrl);
- if (SolrCLI.checkCommunicationError(exc)) {
+ if (CLIUtils.checkCommunicationError(exc)) {
replicaStatus = Replica.State.DOWN.toString();
} else {
replicaStatus = "error: " + exc;
diff --git a/solr/core/src/java/org/apache/solr/cli/LinkConfigTool.java
b/solr/core/src/java/org/apache/solr/cli/LinkConfigTool.java
index 2261b96474d..619e1d82e5c 100644
--- a/solr/core/src/java/org/apache/solr/cli/LinkConfigTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/LinkConfigTool.java
@@ -78,7 +78,7 @@ public class LinkConfigTool extends ToolBase {
String collection = cli.getOptionValue(COLLECTION_NAME_OPTION);
String confName = cli.getOptionValue(CONF_NAME_OPTION);
- String zkHost = SolrCLI.getZkHost(cli);
+ String zkHost = CLIUtils.getZkHost(cli);
try (SolrZkClient zkClient =
new SolrZkClient.Builder()
diff --git a/solr/core/src/java/org/apache/solr/cli/PackageTool.java
b/solr/core/src/java/org/apache/solr/cli/PackageTool.java
index cb8bc6493ad..b71c86896cb 100644
--- a/solr/core/src/java/org/apache/solr/cli/PackageTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/PackageTool.java
@@ -115,8 +115,8 @@ public class PackageTool extends ToolBase {
+ "don't print stack traces, hence special treatment is needed
here.")
public void runImpl(CommandLine cli) throws Exception {
try {
- String solrUrl = SolrCLI.normalizeSolrUrl(cli);
- String zkHost = SolrCLI.getZkHost(cli);
+ String solrUrl = CLIUtils.normalizeSolrUrl(cli);
+ String zkHost = CLIUtils.getZkHost(cli);
if (zkHost == null) {
throw new SolrException(ErrorCode.INVALID_STATE, "Package manager runs
only in SolrCloud");
}
@@ -125,7 +125,7 @@ public class PackageTool extends ToolBase {
String cmd = cli.getArgs()[0];
- try (SolrClient solrClient = SolrCLI.getSolrClient(cli, true)) {
+ try (SolrClient solrClient = CLIUtils.getSolrClient(cli, true)) {
packageManager = new PackageManager(solrClient, solrUrl, zkHost);
try {
repositoryManager = new RepositoryManager(solrClient,
packageManager);
diff --git a/solr/core/src/java/org/apache/solr/cli/PostLogsTool.java
b/solr/core/src/java/org/apache/solr/cli/PostLogsTool.java
index e1efeb0b920..c14d9c216db 100644
--- a/solr/core/src/java/org/apache/solr/cli/PostLogsTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/PostLogsTool.java
@@ -93,7 +93,7 @@ public class PostLogsTool extends ToolBase {
public void runImpl(CommandLine cli) throws Exception {
String url = null;
if (cli.hasOption(CommonCLIOptions.SOLR_URL_OPTION)) {
- url = SolrCLI.normalizeSolrUrl(cli) + "/solr/" +
cli.getOptionValue(COLLECTION_NAME_OPTION);
+ url = CLIUtils.normalizeSolrUrl(cli) + "/solr/" +
cli.getOptionValue(COLLECTION_NAME_OPTION);
} else {
// Could be required arg, but maybe we want to support --zk-host option
too?
diff --git a/solr/core/src/java/org/apache/solr/cli/PostTool.java
b/solr/core/src/java/org/apache/solr/cli/PostTool.java
index 0e50e619043..f6bc4b811f0 100644
--- a/solr/core/src/java/org/apache/solr/cli/PostTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/PostTool.java
@@ -279,7 +279,7 @@ public class PostTool extends ToolBase {
solrUpdateUrl = null;
if (cli.hasOption(CommonCLIOptions.SOLR_URL_OPTION)) {
String url =
- SolrCLI.normalizeSolrUrl(cli)
+ CLIUtils.normalizeSolrUrl(cli)
+ "/solr/"
+ cli.getOptionValue(COLLECTION_NAME_OPTION)
+ "/update";
@@ -287,7 +287,7 @@ public class PostTool extends ToolBase {
} else {
String url =
- SolrCLI.getDefaultSolrUrl()
+ CLIUtils.getDefaultSolrUrl()
+ "/solr/"
+ cli.getOptionValue(COLLECTION_NAME_OPTION)
+ "/update";
@@ -765,7 +765,7 @@ public class PostTool extends ToolBase {
info("COMMITting Solr index changes to " + solrUpdateUrl + "...");
String url = solrUpdateUrl.toString();
url = url.substring(0, url.lastIndexOf("/update"));
- try (final SolrClient client = SolrCLI.getSolrClient(url, credentials)) {
+ try (final SolrClient client = CLIUtils.getSolrClient(url, credentials)) {
client.commit();
}
}
@@ -775,7 +775,7 @@ public class PostTool extends ToolBase {
info("Performing an OPTIMIZE to " + solrUpdateUrl + "...");
String url = solrUpdateUrl.toString();
url = url.substring(0, url.lastIndexOf("/update"));
- try (final SolrClient client = SolrCLI.getSolrClient(url, credentials)) {
+ try (final SolrClient client = CLIUtils.getSolrClient(url, credentials)) {
client.optimize();
}
}
diff --git a/solr/core/src/java/org/apache/solr/cli/RunExampleTool.java
b/solr/core/src/java/org/apache/solr/cli/RunExampleTool.java
index 99307cf74f0..fff3c04f5c5 100644
--- a/solr/core/src/java/org/apache/solr/cli/RunExampleTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/RunExampleTool.java
@@ -286,7 +286,7 @@ public class RunExampleTool extends ToolBase {
boolean alreadyExists = false;
boolean cloudMode = nodeStatus.get("cloud") != null;
if (cloudMode) {
- if (SolrCLI.safeCheckCollectionExists(
+ if (CLIUtils.safeCheckCollectionExists(
solrUrl, collectionName,
cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION))) {
alreadyExists = true;
echo(
@@ -296,7 +296,7 @@ public class RunExampleTool extends ToolBase {
}
} else {
String coreName = collectionName;
- if (SolrCLI.safeCheckCoreExists(
+ if (CLIUtils.safeCheckCoreExists(
solrUrl, coreName,
cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION))) {
alreadyExists = true;
echo(
@@ -800,7 +800,7 @@ public class RunExampleTool extends ToolBase {
// Test for existence and then prompt to either create another
collection or skip the
// creation step
- if (SolrCLI.safeCheckCollectionExists(solrUrl, credentials,
collectionName)) {
+ if (CLIUtils.safeCheckCollectionExists(solrUrl, credentials,
collectionName)) {
echo("\nCollection '" + collectionName + "' already exists!");
int oneOrTwo =
promptForInt(
@@ -856,7 +856,7 @@ public class RunExampleTool extends ToolBase {
}
} else {
// must verify if default collection exists
- if (SolrCLI.safeCheckCollectionExists(solrUrl, collectionName,
credentials)) {
+ if (CLIUtils.safeCheckCollectionExists(solrUrl, collectionName,
credentials)) {
echo(
"\nCollection '"
+ collectionName
diff --git a/solr/core/src/java/org/apache/solr/cli/SnapshotCreateTool.java
b/solr/core/src/java/org/apache/solr/cli/SnapshotCreateTool.java
index 236a7416832..49cce02a15c 100644
--- a/solr/core/src/java/org/apache/solr/cli/SnapshotCreateTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/SnapshotCreateTool.java
@@ -71,7 +71,7 @@ public class SnapshotCreateTool extends ToolBase {
public void runImpl(CommandLine cli) throws Exception {
String snapshotName = cli.getOptionValue(SNAPSHOT_NAME_OPTION);
String collectionName = cli.getOptionValue(COLLECTION_NAME_OPTION);
- try (var solrClient = SolrCLI.getSolrClient(cli)) {
+ try (var solrClient = CLIUtils.getSolrClient(cli)) {
createSnapshot(solrClient, collectionName, snapshotName);
}
}
diff --git a/solr/core/src/java/org/apache/solr/cli/SnapshotDeleteTool.java
b/solr/core/src/java/org/apache/solr/cli/SnapshotDeleteTool.java
index 53fa8ad002a..c9dc90abab7 100644
--- a/solr/core/src/java/org/apache/solr/cli/SnapshotDeleteTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/SnapshotDeleteTool.java
@@ -71,7 +71,7 @@ public class SnapshotDeleteTool extends ToolBase {
public void runImpl(CommandLine cli) throws Exception {
String snapshotName = cli.getOptionValue(SNAPSHOT_NAME_OPTION);
String collectionName = cli.getOptionValue(COLLECTION_NAME_OPTION);
- try (var solrClient = SolrCLI.getSolrClient(cli)) {
+ try (var solrClient = CLIUtils.getSolrClient(cli)) {
deleteSnapshot(solrClient, collectionName, snapshotName);
}
}
diff --git a/solr/core/src/java/org/apache/solr/cli/SnapshotDescribeTool.java
b/solr/core/src/java/org/apache/solr/cli/SnapshotDescribeTool.java
index b76f36a7420..dcae8619f3e 100644
--- a/solr/core/src/java/org/apache/solr/cli/SnapshotDescribeTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/SnapshotDescribeTool.java
@@ -84,7 +84,7 @@ public class SnapshotDescribeTool extends ToolBase {
public void runImpl(CommandLine cli) throws Exception {
String snapshotName = cli.getOptionValue(SNAPSHOT_NAME_OPTION);
String collectionName = cli.getOptionValue(COLLECTION_NAME_OPTION);
- try (var solrClient = SolrCLI.getSolrClient(cli)) {
+ try (var solrClient = CLIUtils.getSolrClient(cli)) {
describeSnapshot(solrClient, collectionName, snapshotName);
}
}
diff --git a/solr/core/src/java/org/apache/solr/cli/SnapshotExportTool.java
b/solr/core/src/java/org/apache/solr/cli/SnapshotExportTool.java
index a51e91badb3..6b8cf3a45d0 100644
--- a/solr/core/src/java/org/apache/solr/cli/SnapshotExportTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/SnapshotExportTool.java
@@ -106,7 +106,7 @@ public class SnapshotExportTool extends ToolBase {
Optional<String> backupRepo =
Optional.ofNullable(cli.getOptionValue(BACKUP_REPO_NAME_OPTION));
Optional<String> asyncReqId =
Optional.ofNullable(cli.getOptionValue(ASYNC_ID_OPTION));
- try (var solrClient = SolrCLI.getSolrClient(cli)) {
+ try (var solrClient = CLIUtils.getSolrClient(cli)) {
exportSnapshot(solrClient, collectionName, snapshotName, destDir,
backupRepo, asyncReqId);
}
}
diff --git a/solr/core/src/java/org/apache/solr/cli/SnapshotListTool.java
b/solr/core/src/java/org/apache/solr/cli/SnapshotListTool.java
index 87219ce6021..4b952199e1b 100644
--- a/solr/core/src/java/org/apache/solr/cli/SnapshotListTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/SnapshotListTool.java
@@ -62,7 +62,7 @@ public class SnapshotListTool extends ToolBase {
@Override
public void runImpl(CommandLine cli) throws Exception {
String collectionName = cli.getOptionValue(COLLECTION_NAME_OPTION);
- try (var solrClient = SolrCLI.getSolrClient(cli)) {
+ try (var solrClient = CLIUtils.getSolrClient(cli)) {
listSnapshots(solrClient, collectionName);
}
}
diff --git a/solr/core/src/java/org/apache/solr/cli/SolrCLI.java
b/solr/core/src/java/org/apache/solr/cli/SolrCLI.java
index 4714c43c99c..32483720d17 100755
--- a/solr/core/src/java/org/apache/solr/cli/SolrCLI.java
+++ b/solr/core/src/java/org/apache/solr/cli/SolrCLI.java
@@ -16,32 +16,19 @@
*/
package org.apache.solr.cli;
-import static org.apache.solr.common.SolrException.ErrorCode.FORBIDDEN;
-import static org.apache.solr.common.SolrException.ErrorCode.UNAUTHORIZED;
-import static org.apache.solr.common.params.CommonParams.NAME;
-import static org.apache.solr.common.params.CommonParams.SYSTEM_INFO_PATH;
-
import com.google.common.annotations.VisibleForTesting;
import java.io.File;
-import java.io.IOException;
import java.lang.invoke.MethodHandles;
-import java.net.SocketException;
import java.net.URI;
import java.net.URL;
-import java.nio.file.Path;
-import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
-import java.util.Map;
import java.util.Objects;
-import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
-import java.util.concurrent.TimeUnit;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.apache.commons.cli.CommandLine;
@@ -51,22 +38,8 @@ import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.solr.client.solrj.SolrClient;
-import org.apache.solr.client.solrj.SolrRequest;
-import org.apache.solr.client.solrj.SolrServerException;
-import org.apache.solr.client.solrj.impl.CloudHttp2SolrClient;
-import org.apache.solr.client.solrj.impl.CloudSolrClient;
-import org.apache.solr.client.solrj.impl.Http2SolrClient;
-import org.apache.solr.client.solrj.impl.SolrZkClientTimeout;
-import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
-import org.apache.solr.client.solrj.request.CoreAdminRequest;
-import org.apache.solr.client.solrj.request.GenericSolrRequest;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.cloud.SolrZkClient;
-import org.apache.solr.common.cloud.ZkStateReader;
-import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.ContentStreamBase;
-import org.apache.solr.common.util.EnvUtils;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.util.configuration.SSLConfigurationsFactory;
import org.slf4j.Logger;
@@ -75,13 +48,6 @@ import org.slf4j.LoggerFactory;
/** Command-line utility for working with Solr. */
public class SolrCLI implements CLIO {
- public static String RED = "\u001B[31m";
- public static String GREEN = "\u001B[32m";
- public static String YELLOW = "\u001B[33m";
-
- private static final long MAX_WAIT_FOR_CORE_LOAD_NANOS =
- TimeUnit.NANOSECONDS.convert(1, TimeUnit.MINUTES);
-
private static final Logger log =
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
public static void exit(int exitStatus) {
@@ -188,14 +154,6 @@ public class SolrCLI implements CLIO {
return cli;
}
- public static String getDefaultSolrUrl() {
- // note that ENV_VAR syntax (and the env vars too) are mapped to env.var
sys props
- String scheme = EnvUtils.getProperty("solr.url.scheme", "http");
- String host = EnvUtils.getProperty("solr.tool.host", "localhost");
- String port = EnvUtils.getProperty("jetty.port", "8983"); // from
SOLR_PORT env
- return String.format(Locale.ROOT, "%s://%s:%s",
scheme.toLowerCase(Locale.ROOT), host, port);
- }
-
protected static void checkSslStoreSysProp(String solrInstallDir, String
key) {
String sysProp = "javax.net.ssl." + key;
String keyStore = System.getProperty(sysProp);
@@ -408,70 +366,6 @@ public class SolrCLI implements CLIO {
return classes;
}
- /**
- * Determine if a request to Solr failed due to a communication error, which
is generally
- * retry-able.
- */
- public static boolean checkCommunicationError(Exception exc) {
- Throwable rootCause = SolrException.getRootCause(exc);
- return (rootCause instanceof SolrServerException || rootCause instanceof
SocketException);
- }
-
- public static void checkCodeForAuthError(int code) {
- if (code == UNAUTHORIZED.code || code == FORBIDDEN.code) {
- throw new SolrException(
- SolrException.ErrorCode.getErrorCode(code),
- "Solr requires authentication for request. Please supply valid
credentials. HTTP code="
- + code);
- }
- }
-
- public static boolean exceptionIsAuthRelated(Exception exc) {
- return (exc instanceof SolrException
- && Arrays.asList(UNAUTHORIZED.code,
FORBIDDEN.code).contains(((SolrException) exc).code()));
- }
-
- public static SolrClient getSolrClient(String solrUrl, String credentials,
boolean barePath) {
- // today we require all urls to end in /solr, however in the future we
will need to support the
- // /api url end point instead. Eventually we want to have this method
always
- // return a bare url, and then individual calls decide if they are /solr
or /api
- // The /solr/ check is because sometimes a full url is passed in, like
- // http://localhost:8983/solr/films_shard1_replica_n1/.
- if (!barePath && !solrUrl.endsWith("/solr") &&
!solrUrl.contains("/solr/")) {
- solrUrl = solrUrl + "/solr";
- }
- Http2SolrClient.Builder builder =
- new Http2SolrClient.Builder(solrUrl)
- .withMaxConnectionsPerHost(32)
- .withKeyStoreReloadInterval(-1, TimeUnit.SECONDS)
- .withOptionalBasicAuthCredentials(credentials);
-
- return builder.build();
- }
-
- /**
- * Helper method for all the places where we assume a /solr on the url.
- *
- * @param solrUrl The solr url that you want the client for
- * @param credentials The username:password for basic auth.
- * @return The SolrClient
- */
- public static SolrClient getSolrClient(String solrUrl, String credentials) {
- return getSolrClient(solrUrl, credentials, false);
- }
-
- public static SolrClient getSolrClient(CommandLine cli, boolean barePath)
throws Exception {
- String solrUrl = SolrCLI.normalizeSolrUrl(cli);
- String credentials =
cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION);
- return getSolrClient(solrUrl, credentials, barePath);
- }
-
- public static SolrClient getSolrClient(CommandLine cli) throws Exception {
- String solrUrl = SolrCLI.normalizeSolrUrl(cli);
- String credentials =
cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION);
- return getSolrClient(solrUrl, credentials, false);
- }
-
private static final String JSON_CONTENT_TYPE = "application/json";
public static NamedList<Object> postJsonToSolr(
@@ -540,204 +434,18 @@ public class SolrCLI implements CLIO {
print("For more help on how to use Solr, head to
https://solr.apache.org/");
}
- /**
- * Strips off the end of solrUrl any /solr when a legacy solrUrl like
http://localhost:8983/solr
- * is used, and warns those users. In the future we'll have urls ending with
/api as well.
- *
- * @param solrUrl The user supplied url to Solr.
- * @return the solrUrl in the format that Solr expects to see internally.
- */
- public static String normalizeSolrUrl(String solrUrl) {
- return normalizeSolrUrl(solrUrl, true);
- }
-
- /**
- * Strips off the end of solrUrl any /solr when a legacy solrUrl like
http://localhost:8983/solr
- * is used, and optionally logs a warning. In the future we'll have urls
ending with /api as well.
- *
- * @param solrUrl The user supplied url to Solr.
- * @param logUrlFormatWarning If a warning message should be logged about
the url format
- * @return the solrUrl in the format that Solr expects to see internally.
- */
- public static String normalizeSolrUrl(String solrUrl, boolean
logUrlFormatWarning) {
- if (solrUrl != null) {
- URI uri = URI.create(solrUrl);
- String urlPath = uri.getRawPath();
- if (urlPath != null && urlPath.contains("/solr")) {
- String newSolrUrl =
- uri.resolve(urlPath.substring(0, urlPath.lastIndexOf("/solr") +
1)).toString();
- if (logUrlFormatWarning) {
- CLIO.err(
- "WARNING: URLs provided to this tool needn't include Solr's
context-root (e.g. \"/solr\"). Such URLs are deprecated and support for them
will be removed in a future release. Correcting from ["
- + solrUrl
- + "] to ["
- + newSolrUrl
- + "].");
- }
- solrUrl = newSolrUrl;
- }
- if (solrUrl.endsWith("/")) {
- solrUrl = solrUrl.substring(0, solrUrl.length() - 1);
- }
- }
- return solrUrl;
- }
-
- /**
- * Get the base URL of a live Solr instance from either the --solr-url
command-line option or from
- * ZooKeeper.
- */
- public static String normalizeSolrUrl(CommandLine cli) throws Exception {
- String solrUrl = cli.getOptionValue(CommonCLIOptions.SOLR_URL_OPTION);
- if (solrUrl == null) {
- String zkHost = cli.getOptionValue(CommonCLIOptions.ZK_HOST_OPTION);
- if (zkHost == null) {
- solrUrl = SolrCLI.getDefaultSolrUrl();
- CLIO.err(
- "Neither --zk-host or --solr-url parameters provided so assuming
solr url is "
- + solrUrl
- + ".");
- } else {
- try (CloudSolrClient cloudSolrClient =
getCloudHttp2SolrClient(zkHost)) {
- cloudSolrClient.connect();
- Set<String> liveNodes =
cloudSolrClient.getClusterState().getLiveNodes();
- if (liveNodes.isEmpty())
- throw new IllegalStateException(
- "No live nodes found! Cannot determine 'solrUrl' from
ZooKeeper: " + zkHost);
-
- String firstLiveNode = liveNodes.iterator().next();
- solrUrl =
ZkStateReader.from(cloudSolrClient).getBaseUrlForNodeName(firstLiveNode);
- solrUrl = normalizeSolrUrl(solrUrl, false);
- }
- }
- }
- solrUrl = normalizeSolrUrl(solrUrl);
- return solrUrl;
- }
-
- /**
- * Get the ZooKeeper connection string from either the zk-host command-line
option or by looking
- * it up from a running Solr instance based on the solr-url option.
- */
- public static String getZkHost(CommandLine cli) throws Exception {
-
- String zkHost = cli.getOptionValue(CommonCLIOptions.ZK_HOST_OPTION);
- if (zkHost != null && !zkHost.isBlank()) {
- return zkHost;
- }
-
- try (SolrClient solrClient = getSolrClient(cli)) {
- // hit Solr to get system info
- NamedList<Object> systemInfo =
- solrClient.request(
- new GenericSolrRequest(SolrRequest.METHOD.GET,
CommonParams.SYSTEM_INFO_PATH));
-
- // convert raw JSON into user-friendly output
- StatusTool statusTool = new StatusTool();
- Map<String, Object> status = statusTool.reportStatus(systemInfo,
solrClient);
- @SuppressWarnings("unchecked")
- Map<String, Object> cloud = (Map<String, Object>) status.get("cloud");
- if (cloud != null) {
- String zookeeper = (String) cloud.get("ZooKeeper");
- if (zookeeper.endsWith("(embedded)")) {
- zookeeper = zookeeper.substring(0, zookeeper.length() -
"(embedded)".length());
- }
- zkHost = zookeeper;
- }
- }
-
- return zkHost;
- }
-
- public static SolrZkClient getSolrZkClient(CommandLine cli, String zkHost)
throws Exception {
- if (zkHost == null) {
- throw new IllegalStateException(
- "Solr at "
- + cli.getOptionValue(CommonCLIOptions.SOLR_URL_OPTION)
- + " is running in standalone server mode, this command can only
be used when running in SolrCloud mode.\n");
- }
- return new SolrZkClient.Builder()
- .withUrl(zkHost)
- .withTimeout(SolrZkClientTimeout.DEFAULT_ZK_CLIENT_TIMEOUT,
TimeUnit.MILLISECONDS)
- .build();
- }
-
- public static CloudHttp2SolrClient getCloudHttp2SolrClient(String zkHost) {
- return getCloudHttp2SolrClient(zkHost, null);
- }
-
- public static CloudHttp2SolrClient getCloudHttp2SolrClient(
- String zkHost, Http2SolrClient.Builder builder) {
- return new CloudHttp2SolrClient.Builder(Collections.singletonList(zkHost),
Optional.empty())
- .withInternalClientBuilder(builder)
- .build();
- }
-
- public static boolean safeCheckCollectionExists(
- String solrUrl, String collection, String credentials) {
- boolean exists = false;
- try (var solrClient = getSolrClient(solrUrl, credentials)) {
- NamedList<Object> existsCheckResult = solrClient.request(new
CollectionAdminRequest.List());
- @SuppressWarnings("unchecked")
- List<String> collections = (List<String>)
existsCheckResult.get("collections");
- exists = collections != null && collections.contains(collection);
- } catch (Exception exc) {
- // just ignore it since we're only interested in a positive result here
- }
- return exists;
- }
-
- @SuppressWarnings("unchecked")
- public static boolean safeCheckCoreExists(String solrUrl, String coreName,
String credentials) {
- boolean exists = false;
- try (var solrClient = getSolrClient(solrUrl, credentials)) {
- boolean wait = false;
- final long startWaitAt = System.nanoTime();
- do {
- if (wait) {
- final int clamPeriodForStatusPollMs = 1000;
- Thread.sleep(clamPeriodForStatusPollMs);
- }
- NamedList<Object> existsCheckResult =
- CoreAdminRequest.getStatus(coreName, solrClient).getResponse();
- NamedList<Object> status = (NamedList<Object>)
existsCheckResult.get("status");
- NamedList<Object> coreStatus = (NamedList<Object>)
status.get(coreName);
- Map<String, Object> failureStatus =
- (Map<String, Object>) existsCheckResult.get("initFailures");
- String errorMsg = (String) failureStatus.get(coreName);
- final boolean hasName = coreStatus != null &&
coreStatus.asMap().containsKey(NAME);
- exists = hasName || errorMsg != null;
- wait = hasName && errorMsg == null &&
"true".equals(coreStatus.get("isLoading"));
- } while (wait && System.nanoTime() - startWaitAt <
MAX_WAIT_FOR_CORE_LOAD_NANOS);
- } catch (Exception exc) {
- // just ignore it since we're only interested in a positive result here
- }
- return exists;
- }
-
- public static boolean isCloudMode(SolrClient solrClient) throws
SolrServerException, IOException {
- NamedList<Object> systemInfo =
- solrClient.request(new GenericSolrRequest(SolrRequest.METHOD.GET,
SYSTEM_INFO_PATH));
- return "solrcloud".equals(systemInfo.get("mode"));
- }
-
- public static Path getConfigSetsDir(Path solrInstallDir) {
- Path configSetsPath = Paths.get("server/solr/configsets/");
- return solrInstallDir.resolve(configSetsPath);
- }
-
public static void print(Object message) {
print(null, message);
}
/** Console print using green color */
public static void printGreen(Object message) {
- print(GREEN, message);
+ print(CLIUtils.GREEN, message);
}
/** Console print using red color */
public static void printRed(Object message) {
- print(RED, message);
+ print(CLIUtils.RED, message);
}
public static void print(String color, Object message) {
diff --git a/solr/core/src/java/org/apache/solr/cli/StatusTool.java
b/solr/core/src/java/org/apache/solr/cli/StatusTool.java
index dcf0200e511..45713fbc085 100644
--- a/solr/core/src/java/org/apache/solr/cli/StatusTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/StatusTool.java
@@ -18,8 +18,6 @@
package org.apache.solr.cli;
import java.io.PrintStream;
-import java.net.URI;
-import java.net.URISyntaxException;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
@@ -188,25 +186,15 @@ public class StatusTool extends ToolBase {
CLIO.out("");
}
- private Integer portFromUrl(String solrUrl) {
+ public void waitForSolrUpAndPrintStatus(String solrUrl, CommandLine cli, int
maxWaitSecs)
+ throws Exception {
+ int solrPort = -1;
try {
- URI uri = new URI(solrUrl);
- int port = uri.getPort();
- if (port == -1) {
- return uri.getScheme().equals("https") ? 443 : 80;
- } else {
- return port;
- }
- } catch (URISyntaxException e) {
+ solrPort = CLIUtils.portFromUrl(solrUrl);
+ } catch (Exception e) {
CLIO.err("Invalid URL provided, does not contain port");
- System.exit(1);
- return null;
+ SolrCLI.exit(1);
}
- }
-
- public void waitForSolrUpAndPrintStatus(String solrUrl, CommandLine cli, int
maxWaitSecs)
- throws Exception {
- int solrPort = portFromUrl(solrUrl);
echo("Waiting up to " + maxWaitSecs + " seconds to see Solr running on
port " + solrPort);
boolean solrUp = waitForSolrUp(solrUrl, cli, maxWaitSecs);
if (solrUp) {
@@ -268,10 +256,10 @@ public class StatusTool extends ToolBase {
.write(getStatus(solrUrl,
cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION)));
return arr.toString();
} catch (Exception exc) {
- if (SolrCLI.exceptionIsAuthRelated(exc)) {
+ if (CLIUtils.exceptionIsAuthRelated(exc)) {
throw exc;
}
- if (SolrCLI.checkCommunicationError(exc)) {
+ if (CLIUtils.checkCommunicationError(exc)) {
// this is not actually an error from the tool as it's ok if Solr is
not online.
return null;
} else {
@@ -289,7 +277,7 @@ public class StatusTool extends ToolBase {
try {
return getStatus(solrUrl, credentials);
} catch (Exception exc) {
- if (SolrCLI.exceptionIsAuthRelated(exc)) {
+ if (CLIUtils.exceptionIsAuthRelated(exc)) {
throw exc;
}
try {
@@ -308,7 +296,7 @@ public class StatusTool extends ToolBase {
}
public Map<String, Object> getStatus(String solrUrl, String credentials)
throws Exception {
- try (var solrClient = SolrCLI.getSolrClient(solrUrl, credentials)) {
+ try (var solrClient = CLIUtils.getSolrClient(solrUrl, credentials)) {
return getStatus(solrClient);
}
}
diff --git a/solr/core/src/java/org/apache/solr/cli/StreamTool.java
b/solr/core/src/java/org/apache/solr/cli/StreamTool.java
index 9c0392ec71b..512b678da0f 100644
--- a/solr/core/src/java/org/apache/solr/cli/StreamTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/StreamTool.java
@@ -253,7 +253,7 @@ public class StreamTool extends ToolBase {
* locally.
*/
private PushBackStream doLocalMode(CommandLine cli, String expr) throws
Exception {
- String zkHost = SolrCLI.getZkHost(cli);
+ String zkHost = CLIUtils.getZkHost(cli);
echoIfVerbose("Connecting to ZooKeeper at " + zkHost);
solrClientCache.getCloudSolrClient(zkHost);
@@ -306,7 +306,7 @@ public class StreamTool extends ToolBase {
*/
private PushBackStream doRemoteMode(CommandLine cli, String expr) throws
Exception {
- String solrUrl = SolrCLI.normalizeSolrUrl(cli);
+ String solrUrl = CLIUtils.normalizeSolrUrl(cli);
if (!cli.hasOption("name")) {
throw new IllegalStateException(
"You must provide --name COLLECTION with --worker solr parameter.");
diff --git a/solr/core/src/java/org/apache/solr/cli/UpdateACLTool.java
b/solr/core/src/java/org/apache/solr/cli/UpdateACLTool.java
index 996ada0a213..bf54152d2ac 100644
--- a/solr/core/src/java/org/apache/solr/cli/UpdateACLTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/UpdateACLTool.java
@@ -59,7 +59,7 @@ public class UpdateACLTool extends ToolBase {
@Override
public void runImpl(CommandLine cli) throws Exception {
- String zkHost = SolrCLI.getZkHost(cli);
+ String zkHost = CLIUtils.getZkHost(cli);
String path = cli.getArgs()[0];
if (!ZkController.checkChrootPath(zkHost, true)) {
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 b2045ef3541..7f901e67cf2 100644
--- a/solr/core/src/java/org/apache/solr/cli/ZkCpTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/ZkCpTool.java
@@ -124,7 +124,7 @@ public class ZkCpTool extends ToolBase {
@Override
public void runImpl(CommandLine cli) throws Exception {
- String zkHost = SolrCLI.getZkHost(cli);
+ String zkHost = CLIUtils.getZkHost(cli);
echoIfVerbose("\nConnecting to ZooKeeper at " + zkHost + " ...");
String src = cli.getArgs()[0];
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 c8f1f55b266..57bb45d4e40 100644
--- a/solr/core/src/java/org/apache/solr/cli/ZkLsTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/ZkLsTool.java
@@ -57,10 +57,10 @@ public class ZkLsTool extends ToolBase {
@Override
public void runImpl(CommandLine cli) throws Exception {
- String zkHost = SolrCLI.getZkHost(cli);
+ String zkHost = CLIUtils.getZkHost(cli);
String znode = cli.getArgs()[0];
- try (SolrZkClient zkClient = SolrCLI.getSolrZkClient(cli, zkHost)) {
+ try (SolrZkClient zkClient = CLIUtils.getSolrZkClient(cli, zkHost)) {
echoIfVerbose("\nConnecting to ZooKeeper at " + zkHost + " ...");
boolean recursive = cli.hasOption(CommonCLIOptions.RECURSIVE_OPTION);
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 f2dc3703835..ace32ad5ce7 100644
--- a/solr/core/src/java/org/apache/solr/cli/ZkMkrootTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/ZkMkrootTool.java
@@ -76,11 +76,11 @@ public class ZkMkrootTool extends ToolBase {
@Override
public void runImpl(CommandLine cli) throws Exception {
- String zkHost = SolrCLI.getZkHost(cli);
+ String zkHost = CLIUtils.getZkHost(cli);
String znode = cli.getArgs()[0];
boolean failOnExists = cli.hasOption(FAIL_ON_EXISTS_OPTION);
- try (SolrZkClient zkClient = SolrCLI.getSolrZkClient(cli, zkHost)) {
+ try (SolrZkClient zkClient = CLIUtils.getSolrZkClient(cli, zkHost)) {
echoIfVerbose("\nConnecting to ZooKeeper at " + zkHost + " ...");
echo("Creating ZooKeeper path " + znode + " on ZooKeeper at " + zkHost);
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 41ca7d78822..dba47d5b824 100644
--- a/solr/core/src/java/org/apache/solr/cli/ZkMvTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/ZkMvTool.java
@@ -74,9 +74,9 @@ public class ZkMvTool extends ToolBase {
@Override
public void runImpl(CommandLine cli) throws Exception {
- String zkHost = SolrCLI.getZkHost(cli);
+ String zkHost = CLIUtils.getZkHost(cli);
- try (SolrZkClient zkClient = SolrCLI.getSolrZkClient(cli, zkHost)) {
+ try (SolrZkClient zkClient = CLIUtils.getSolrZkClient(cli, zkHost)) {
echoIfVerbose("\nConnecting to ZooKeeper at " + zkHost + " ...");
String src = cli.getArgs()[0];
String dst = cli.getArgs()[1];
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 cdb2e600334..777ad6035a5 100644
--- a/solr/core/src/java/org/apache/solr/cli/ZkRmTool.java
+++ b/solr/core/src/java/org/apache/solr/cli/ZkRmTool.java
@@ -58,7 +58,7 @@ public class ZkRmTool extends ToolBase {
@Override
public void runImpl(CommandLine cli) throws Exception {
- String zkHost = SolrCLI.getZkHost(cli);
+ String zkHost = CLIUtils.getZkHost(cli);
String target = cli.getArgs()[0];
boolean recursive = cli.hasOption(CommonCLIOptions.RECURSIVE_OPTION);
@@ -71,7 +71,7 @@ public class ZkRmTool extends ToolBase {
throw new SolrServerException("You may not remove the root ZK node
('/')!");
}
echoIfVerbose("\nConnecting to ZooKeeper at " + zkHost + " ...");
- try (SolrZkClient zkClient = SolrCLI.getSolrZkClient(cli, zkHost)) {
+ try (SolrZkClient zkClient = CLIUtils.getSolrZkClient(cli, zkHost)) {
if (!recursive && zkClient.getChildren(znode, null, true).size() != 0) {
throw new SolrServerException(
"ZooKeeper node " + znode + " has children and recursive has NOT
been specified.");
diff --git
a/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java
b/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java
index a751d20472f..1d69a9c429d 100644
--- a/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java
+++ b/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java
@@ -40,6 +40,7 @@ import java.util.Scanner;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
+import org.apache.solr.cli.CLIUtils;
import org.apache.solr.cli.SolrCLI;
import org.apache.solr.client.api.util.SolrVersion;
import org.apache.solr.client.solrj.SolrClient;
@@ -680,7 +681,7 @@ public class PackageManager implements Closeable {
boolean shouldExecute = true;
if (!noprompt) { // show a prompt asking user to execute the setup command
for the plugin
PackageUtils.print(
- SolrCLI.YELLOW,
+ CLIUtils.YELLOW,
"Execute this command. (If you choose no, you can manually
deploy/undeploy this plugin later) (y/n): ");
try (Scanner scanner = new Scanner(System.in, StandardCharsets.UTF_8)) {
String userInput = scanner.next();
@@ -954,7 +955,7 @@ public class PackageManager implements Closeable {
shouldInstallClusterPlugins,
parameters);
PackageUtils.print(
- res ? SolrCLI.GREEN : SolrCLI.RED, res ? "Deployment successful" :
"Deployment failed");
+ res ? CLIUtils.GREEN : CLIUtils.RED, res ? "Deployment successful" :
"Deployment failed");
}
/** Undeploys a package from given collections. */
diff --git
a/solr/core/src/java/org/apache/solr/packagemanager/PackageUtils.java
b/solr/core/src/java/org/apache/solr/packagemanager/PackageUtils.java
index 26b294b4906..1d1270a2b84 100644
--- a/solr/core/src/java/org/apache/solr/packagemanager/PackageUtils.java
+++ b/solr/core/src/java/org/apache/solr/packagemanager/PackageUtils.java
@@ -33,7 +33,7 @@ import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.lucene.util.SuppressForbidden;
-import org.apache.solr.cli.SolrCLI;
+import org.apache.solr.cli.CLIUtils;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
@@ -236,7 +236,7 @@ public class PackageUtils {
/** Console print using green color */
public static void formatGreen(StringBuilder sb, Object message) {
- format(sb, SolrCLI.GREEN, message);
+ format(sb, CLIUtils.GREEN, message);
}
public static void format(StringBuilder sb, Object message) {
diff --git a/solr/core/src/test/org/apache/solr/cli/CLIUtilsTest.java
b/solr/core/src/test/org/apache/solr/cli/CLIUtilsTest.java
new file mode 100644
index 00000000000..928266de7c0
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/cli/CLIUtilsTest.java
@@ -0,0 +1,144 @@
+/*
+ * 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.cli;
+
+import java.net.SocketException;
+import java.net.URISyntaxException;
+import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.cloud.SolrCloudTestCase;
+import org.apache.solr.common.SolrException;
+import org.junit.Test;
+
+public class CLIUtilsTest extends SolrCloudTestCase {
+
+ @Test
+ public void testDefaultSolrUrlWithNoProperties() {
+ System.clearProperty("solr.url.scheme");
+ System.clearProperty("solr.tool.host");
+ System.clearProperty("jetty.port");
+ assertEquals(
+ "Default Solr URL should match with no properties set.",
+ "http://localhost:8983",
+ CLIUtils.getDefaultSolrUrl());
+ }
+
+ @Test
+ public void testDefaultSolrUrlWithProperties() {
+ System.setProperty("solr.url.scheme", "https");
+ System.setProperty("solr.tool.host", "other.local");
+ System.setProperty("jetty.port", "1234");
+ assertEquals(
+ "Default Solr URL should match with custom properties set.",
+ "https://other.local:1234",
+ CLIUtils.getDefaultSolrUrl());
+ }
+
+ @Test
+ public void testCommunicationErrors() {
+ // communication errors
+ Exception serverException = new Exception(new SolrServerException(""));
+ assertTrue(
+ "SolrServerException should be communication error",
+ CLIUtils.checkCommunicationError(serverException));
+
+ Exception socketException = new RuntimeException(new Exception(new
SocketException()));
+ assertTrue(
+ "SocketException should be communication error",
+ CLIUtils.checkCommunicationError(socketException));
+
+ // TODO See if this should be a communication error or not
+ // Exception parentException = new SolrServerException(new Exception());
+ // assertTrue(
+ // "SolrServerException with different root cause should be
communication error",
+ // CLIUtils.checkCommunicationError(parentException));
+
+ Exception rootException = new SolrServerException("");
+ assertTrue(
+ "SolrServerException with no cause should be communication error",
+ CLIUtils.checkCommunicationError(rootException));
+
+ // non-communication errors
+ Exception exception1 = new NullPointerException();
+ assertFalse(
+ "NullPointerException should not be communication error",
+ CLIUtils.checkCommunicationError(exception1));
+
+ Exception exception2 = new RuntimeException(new Exception());
+ assertFalse(
+ "Exception should not be communication error",
+ CLIUtils.checkCommunicationError(exception2));
+ }
+
+ @Test
+ public void testCodeForAuthError() throws SolrException {
+ // auth errors
+ assertThrows(
+ "Forbidden (403) should throw SolrException",
+ SolrException.class,
+ () ->
CLIUtils.checkCodeForAuthError(SolrException.ErrorCode.FORBIDDEN.code));
+ assertThrows(
+ "Unauthorized (401) should throw SolrException",
+ SolrException.class,
+ () ->
CLIUtils.checkCodeForAuthError(SolrException.ErrorCode.UNAUTHORIZED.code));
+
+ // non auth errors
+ CLIUtils.checkCodeForAuthError(SolrException.ErrorCode.BAD_REQUEST.code);
+ CLIUtils.checkCodeForAuthError(SolrException.ErrorCode.CONFLICT.code);
+ CLIUtils.checkCodeForAuthError(SolrException.ErrorCode.SERVER_ERROR.code);
+ CLIUtils.checkCodeForAuthError(0); // Unknown
+ CLIUtils.checkCodeForAuthError(200); // HTTP OK
+ }
+
+ @Test
+ public void testResolveSolrUrl() {
+ assertEquals(CLIUtils.normalizeSolrUrl("http://localhost:8983/solr"),
"http://localhost:8983");
+ assertEquals(CLIUtils.normalizeSolrUrl("http://localhost:8983/solr/"),
"http://localhost:8983");
+ assertEquals(CLIUtils.normalizeSolrUrl("http://localhost:8983/"),
"http://localhost:8983");
+ assertEquals(CLIUtils.normalizeSolrUrl("http://localhost:8983"),
"http://localhost:8983");
+ assertEquals(
+ CLIUtils.normalizeSolrUrl("http://localhost:8983/solr/", false),
"http://localhost:8983");
+ }
+
+ @Test
+ public void testPortExtraction() throws URISyntaxException {
+ assertEquals(
+ "Should extract explicit port from valid URL",
+ 8983,
+ CLIUtils.portFromUrl("http://localhost:8983"));
+
+ assertEquals(
+ "Should extract explicit port from valid URL with trailing slash",
+ 1234,
+ CLIUtils.portFromUrl("http://localhost:1234/"));
+
+ assertEquals(
+ "Should extract implicit HTTP port (80)", 80,
CLIUtils.portFromUrl("http://localhost"));
+
+ assertEquals(
+ "Should extract implicit HTTPS port (443)", 443,
CLIUtils.portFromUrl("https://localhost"));
+
+ // TODO See if we could be more lenient and fallback to defaults instead.
+ assertThrows(
+ "Should throw NullpointerException if no scheme provided",
+ NullPointerException.class,
+ () -> CLIUtils.portFromUrl("localhost"));
+
+ // Note that a bunch of invalid URIs like "http::example.com",
"http:/example.com" and
+ // "//example.com" are not throwing URISyntaxException. This however is an
issue of
+ // java.lang.URI, which is very lenient.
+ }
+}
diff --git a/solr/core/src/test/org/apache/solr/cli/SolrCLITest.java
b/solr/core/src/test/org/apache/solr/cli/SolrCLITest.java
index 4b5290a1ff7..d045ae35501 100644
--- a/solr/core/src/test/org/apache/solr/cli/SolrCLITest.java
+++ b/solr/core/src/test/org/apache/solr/cli/SolrCLITest.java
@@ -20,15 +20,6 @@ import org.apache.solr.SolrTestCase;
import org.junit.Test;
public class SolrCLITest extends SolrTestCase {
- @Test
- public void testResolveSolrUrl() {
- assertEquals(SolrCLI.normalizeSolrUrl("http://localhost:8983/solr"),
"http://localhost:8983");
- assertEquals(SolrCLI.normalizeSolrUrl("http://localhost:8983/solr/"),
"http://localhost:8983");
- assertEquals(SolrCLI.normalizeSolrUrl("http://localhost:8983/"),
"http://localhost:8983");
- assertEquals(SolrCLI.normalizeSolrUrl("http://localhost:8983"),
"http://localhost:8983");
- assertEquals(
- SolrCLI.normalizeSolrUrl("http://localhost:8983/solr/", false),
"http://localhost:8983");
- }
@Test
public void testUptime() {
diff --git a/solr/core/src/test/org/apache/solr/cli/TestSolrCLIRunExample.java
b/solr/core/src/test/org/apache/solr/cli/TestSolrCLIRunExample.java
index 6c0522fd937..da279a12301 100644
--- a/solr/core/src/test/org/apache/solr/cli/TestSolrCLIRunExample.java
+++ b/solr/core/src/test/org/apache/solr/cli/TestSolrCLIRunExample.java
@@ -506,7 +506,7 @@ public class TestSolrCLIRunExample extends SolrTestCaseJ4 {
// verify Solr is running on the expected port and verify the collection
exists
String solrUrl = "http://localhost:" + bindPort + "/solr";
- if (!SolrCLI.safeCheckCollectionExists(solrUrl, collectionName, null)) {
+ if (!CLIUtils.safeCheckCollectionExists(solrUrl, collectionName, null)) {
fail(
"After running Solr cloud example, test collection '"
+ collectionName
diff --git a/solr/core/src/test/org/apache/solr/cloud/SolrCloudExampleTest.java
b/solr/core/src/test/org/apache/solr/cloud/SolrCloudExampleTest.java
index 1716d09a45f..8e2e728944f 100644
--- a/solr/core/src/test/org/apache/solr/cloud/SolrCloudExampleTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/SolrCloudExampleTest.java
@@ -24,6 +24,7 @@ import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.commons.cli.CommandLine;
import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.cli.CLIUtils;
import org.apache.solr.cli.CreateTool;
import org.apache.solr.cli.DeleteTool;
import org.apache.solr.cli.HealthcheckTool;
@@ -174,7 +175,7 @@ public class SolrCloudExampleTest extends
AbstractFullDistribZkTestBase {
CommandLine cli = SolrCLI.processCommandLineArgs(tool, args);
assertEquals("Delete action failed!", 0, tool.runTool(cli));
assertFalse(
- SolrCLI.safeCheckCollectionExists(
+ CLIUtils.safeCheckCollectionExists(
solrUrl, testCollectionName, null)); // it should not exist anymore
}
}