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 @@ protected String callGet(String url, String credentials) throws Exception { 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 @@ protected int runAssert(CommandLine cli) throws Exception { 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 static int assertSolrRunning(String url, String credentials) throws Excep 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 static int assertSolrNotRunning(String url, String credentials) throws Ex 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 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 static int assertSolrNotRunning(String url, String credentials) throws Ex 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 @@ private static boolean isSolrRunningOn(String url, String credentials) throws Ex 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 @@ private static boolean isSolrRunningOn(String url, String credentials) throws Ex } 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 @@ private void handleKerberos(CommandLine cli) throws Exception { 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 @@ private void handleKerberos(CommandLine cli) throws Exception { // 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 @@ private void handleKerberos(CommandLine cli) throws Exception { 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 @@ private void handleBasicAuth(CommandLine cli) throws Exception { 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 @@ private void handleBasicAuth(CommandLine cli) throws Exception { } // 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 @@ private void handleBasicAuth(CommandLine cli) throws Exception { 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 @@ private void checkSecurityJsonExists(SolrZkClient zkClient) 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 @@ private void clearSecurityJson(CommandLine cli, boolean updateIncludeFileOnly) t 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 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 systemInfo = + solrClient.request( + new GenericSolrRequest(SolrRequest.METHOD.GET, CommonParams.SYSTEM_INFO_PATH)); + + // convert raw JSON into user-friendly output + StatusTool statusTool = new StatusTool(); + Map status = statusTool.reportStatus(systemInfo, solrClient); + @SuppressWarnings("unchecked") + Map cloud = (Map) 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. + * + *

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 existsCheckResult = solrClient.request(new CollectionAdminRequest.List()); + @SuppressWarnings("unchecked") + List collections = (List) 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 existsCheckResult = + CoreAdminRequest.getStatus(coreName, solrClient).getResponse(); + NamedList status = (NamedList) existsCheckResult.get("status"); + NamedList coreStatus = (NamedList) status.get(coreName); + Map failureStatus = + (Map) 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 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 void runImpl(CommandLine cli) throws Exception { 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 @@ private 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 String getUsage() { @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 String getUsage() { @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 void runImpl(CommandLine cli) throws Exception { 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 Options getOptions() { @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 void runImpl(CommandLine cli) throws Exception { echoIfVerbose(jsonBody); try (SolrClient solrClient = - SolrCLI.getSolrClient(solrUrl, cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION))) { + CLIUtils.getSolrClient(solrUrl, cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION))) { NamedList 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 Options getOptions() { @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 void runImpl(CommandLine cli) throws Exception { 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 @@ protected void createCore(CommandLine cli, SolrClient solrClient) throws Excepti // 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 @@ protected void createCollection(CommandLine cli) throws Exception { .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 @@ protected void createCollection(CloudSolrClient cloudSolrClient, CommandLine cli } // 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 @@ protected void createCollection(CloudSolrClient cloudSolrClient, CommandLine cli } // 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 @@ protected void createCollection(CloudSolrClient cloudSolrClient, CommandLine cli } 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 @@ private void printDefaultConfigsetWarningIfNecessary(CommandLine cli) { && (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 Options getOptions() { @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 @@ protected void deleteCollection(CommandLine cli) throws Exception { .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 void runImpl(CommandLine cli) throws Exception { 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 @@ class CoreHandler { 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 HealthcheckTool(PrintStream stdout) { @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 @@ protected void runCloudTool(CloudSolrClient cloudSolrClient, CommandLine cli) th 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 @@ protected void runCloudTool(CloudSolrClient cloudSolrClient, CommandLine cli) th 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 systemInfo = @@ -192,7 +192,7 @@ protected void runCloudTool(CloudSolrClient cloudSolrClient, CommandLine cli) th } 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 void runImpl(CommandLine cli) throws Exception { 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 String getName() { + "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 void runImpl(CommandLine cli) throws Exception { 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 Options getOptions() { 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 void runImpl(CommandLine cli) throws Exception { 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 void runImpl(CommandLine cli) throws Exception { } else { String url = - SolrCLI.getDefaultSolrUrl() + CLIUtils.getDefaultSolrUrl() + "/solr/" + cli.getOptionValue(COLLECTION_NAME_OPTION) + "/update"; @@ -765,7 +765,7 @@ public void commit() throws IOException, SolrServerException { 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 void optimize() throws IOException, SolrServerException { 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 @@ protected void runExample(CommandLine cli, String exampleName) throws Exception 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 @@ protected void runExample(CommandLine cli, String exampleName) throws Exception } } else { String coreName = collectionName; - if (SolrCLI.safeCheckCoreExists( + if (CLIUtils.safeCheckCoreExists( solrUrl, coreName, cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION))) { alreadyExists = true; echo( @@ -800,7 +800,7 @@ protected String createCloudExampleCollection( // 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 @@ protected String createCloudExampleCollection( } } 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 Options getOptions() { 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 Options getOptions() { 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 Options getOptions() { 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 void runImpl(CommandLine cli) throws Exception { Optional backupRepo = Optional.ofNullable(cli.getOptionValue(BACKUP_REPO_NAME_OPTION)); Optional 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 Options getOptions() { @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.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 @@ /** 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 static CommandLine parseCmdLine(Tool tool, String[] args) { 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 @@ private static Set findClasses(String path, String packageName) throws E 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 postJsonToSolr( @@ -540,204 +434,18 @@ private static void printHelp() { 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 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 systemInfo = - solrClient.request( - new GenericSolrRequest(SolrRequest.METHOD.GET, CommonParams.SYSTEM_INFO_PATH)); - - // convert raw JSON into user-friendly output - StatusTool statusTool = new StatusTool(); - Map status = statusTool.reportStatus(systemInfo, solrClient); - @SuppressWarnings("unchecked") - Map cloud = (Map) 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 existsCheckResult = solrClient.request(new CollectionAdminRequest.List()); - @SuppressWarnings("unchecked") - List collections = (List) 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 existsCheckResult = - CoreAdminRequest.getStatus(coreName, solrClient).getResponse(); - NamedList status = (NamedList) existsCheckResult.get("status"); - NamedList coreStatus = (NamedList) status.get(coreName); - Map failureStatus = - (Map) 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 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 @@ private void printProcessStatus(SolrProcess process, CommandLine cli) throws Exc 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 String statusFromRunningSolr(String solrUrl, CommandLine cli) throws Exce .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 Map waitToSeeSolrUp( try { return getStatus(solrUrl, credentials); } catch (Exception exc) { - if (SolrCLI.exceptionIsAuthRelated(exc)) { + if (CLIUtils.exceptionIsAuthRelated(exc)) { throw exc; } try { @@ -308,7 +296,7 @@ public Map waitToSeeSolrUp( } public Map 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 void runImpl(CommandLine cli) throws Exception { * 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 @@ private PushBackStream doLocalMode(CommandLine cli, String expr) throws Exceptio */ 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 Options getOptions() { @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 String getHeader() { @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 String getUsage() { @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 String getHeader() { @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 String getHeader() { @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 String getUsage() { @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 void runImpl(CommandLine cli) throws Exception { 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.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 @@ private boolean prompt(boolean noprompt) { boolean shouldExecute = true; if (!noprompt) { // show a prompt asking user to execute the setup command for the plugin PackageUtils.print( - 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 void deploy( 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.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 static String resolve( /** 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.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 void testInteractiveSolrCloudExample() throws Exception { // 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.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 @@ protected void doTestDeleteAction(String testCollectionName, String solrUrl) thr 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 } }