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

dlmarion pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/accumulo.git


The following commit(s) were added to refs/heads/main by this push:
     new be10fb3aba Always include legacy client options in error output (#6502)
be10fb3aba is described below

commit be10fb3aba96b48c00609f770b74311f62ca9659
Author: Laura Schanno <[email protected]>
AuthorDate: Mon Aug 31 09:51:18 2026 -0400

    Always include legacy client options in error output (#6502)
    
    The ClientOpts class does not always include the names of legacy options
    in its error output when a user provides legacy options to the Accumulo
    client.
    
    Made the following changes:
    - Break the legacy options in ClientOpts into individual properties that
      can be set by JCommander.
    - Add `ClientOpts.getPopulatedLegacyOptions()` which will return a set
      of all user-provided legacy options.
    - Update `ClientOpts.validateArgs()` to check for the presence of any
      legacy options, and include them in the error message.
    
    Fixes #6501
---
 .../org/apache/accumulo/core/cli/ClientOpts.java   | 132 ++++++++++++++++-----
 .../apache/accumulo/core/cli/TestClientOpts.java   |  95 +++++++++++++--
 2 files changed, 186 insertions(+), 41 deletions(-)

diff --git a/core/src/main/java/org/apache/accumulo/core/cli/ClientOpts.java 
b/core/src/main/java/org/apache/accumulo/core/cli/ClientOpts.java
index 1fa02a0bd2..0019fbabab 100644
--- a/core/src/main/java/org/apache/accumulo/core/cli/ClientOpts.java
+++ b/core/src/main/java/org/apache/accumulo/core/cli/ClientOpts.java
@@ -25,10 +25,12 @@ import java.net.URL;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Scanner;
+import java.util.Set;
 
 import org.apache.accumulo.core.client.security.tokens.AuthenticationToken;
 import org.apache.accumulo.core.clientImpl.ClientInfoImpl;
@@ -132,19 +134,51 @@ public class ClientOpts extends Help {
     }
   }
 
-  /**
-   * A catch all for older legacy options that have been dropped. Most of them 
were replaced with
-   * accumulo-client.properties in 2.0. Others have been dropped completely.
-   */
-  private String[] legacyClientOpts = {"-p", "-tc", "--tokenClass", "-i", 
"--instance",
-      "--site-file", "--keytab", "--debug", "-fake", "--mock", "--ssl", 
"--sasl"};
+  public static final String OPT_CONFIG_FILE_SHORT = "-c";
+  public static final String OPT_CONFIG_FILE_LONG = "--config-file";
+
+  public static final String LEGACY_OPT_PASSWORD = "-p";
+  public static final String LEGACY_OPT_TOKEN_CLASS_SHORT = "-tc";
+  public static final String LEGACY_OPT_TOKEN_CLASS_LONG = "--tokenClass";
+  public static final String LEGACY_OPT_INSTANCE_SHORT = "-i";
+  public static final String LEGACY_OPT_INSTANCE_LONG = "--instance";
+  public static final String LEGACY_OPT_SITE_FILE = "--site-file";
+  public static final String LEGACY_OPT_KEYTAB = "--keytab";
+  public static final String LEGACY_OPT_DEBUG = "--debug";
+  public static final String LEGACY_OPT_FAKE = "--fake";
+  public static final String LEGACY_OPT_MOCK = "--mock";
+  public static final String LEGACY_OPT_SSL = "--ssl";
+  public static final String LEGACY_OPT_SASL = "--sasl";
+
+  @Parameter(names = LEGACY_OPT_PASSWORD, hidden = true)
+  private String legacyPassword;
+
+  @Parameter(names = {LEGACY_OPT_TOKEN_CLASS_SHORT, 
LEGACY_OPT_TOKEN_CLASS_LONG}, hidden = true)
+  private String legacyTokenClass;
+
+  @Parameter(names = {LEGACY_OPT_INSTANCE_SHORT, LEGACY_OPT_INSTANCE_LONG}, 
hidden = true)
+  private String legacyInstance;
+
+  @Parameter(names = LEGACY_OPT_SITE_FILE, hidden = true)
+  private String legacySiteFile;
+
+  @Parameter(names = LEGACY_OPT_KEYTAB, hidden = true)
+  private String legacyKeytab;
 
-  @Parameter(names = {"-p", "-tc", "--tokenClass", "-i", "--instance", 
"--site-file", "--keytab"},
-      hidden = true)
-  private String legacyOpts = null;
+  @Parameter(names = LEGACY_OPT_DEBUG, hidden = true)
+  private boolean legacyDebug;
 
-  @Parameter(names = {"--debug", "-fake", "--mock", "--ssl", "--sasl"}, hidden 
= true)
-  private boolean legacyOptsBoolean = false;
+  @Parameter(names = LEGACY_OPT_FAKE, hidden = true)
+  private boolean legacyFake;
+
+  @Parameter(names = LEGACY_OPT_MOCK, hidden = true)
+  private boolean legacyMock;
+
+  @Parameter(names = LEGACY_OPT_SSL, hidden = true)
+  private boolean legacySsl;
+
+  @Parameter(names = LEGACY_OPT_SASL, hidden = true)
+  private boolean legacySasl;
 
   @Parameter(names = {"-u", "--user"}, description = "Connection user")
   public String principal = null;
@@ -164,8 +198,9 @@ public class ClientOpts extends Help {
       description = "the authorizations to use when reading or writing")
   public Authorizations auths = Authorizations.EMPTY;
 
-  @Parameter(names = {"-c", "--config-file"}, description = "Read the given 
client config file. "
-      + "If omitted, the classpath will be searched for file named 
accumulo-client.properties")
+  @Parameter(names = {OPT_CONFIG_FILE_SHORT, OPT_CONFIG_FILE_LONG},
+      description = "Read the given client config file. "
+          + "If omitted, the classpath will be searched for file named 
accumulo-client.properties")
   private String clientConfigFile = null;
 
   @Parameter(names = "-o", splitter = NullSplitter.class, description = 
"Overrides property in "
@@ -178,28 +213,60 @@ public class ClientOpts extends Help {
 
   @Override
   public void validateArgs() {
-    if (legacyOpts != null || legacyOptsBoolean) {
-      if (legacyOpts != null) {
-        // grab the bad options
-        StringBuilder badOptions = new StringBuilder();
-        for (String badArg : legacyClientOpts) {
-          if (legacyOpts.contains(badArg)) {
-            badOptions.append(badArg).append(" ");
-          }
-        }
-        throw new IllegalArgumentException("The Client options: " + badOptions
-            + "have been dropped. Use accumulo-client.properties for any 
connection or token "
-            + "options. See '-c, --config-file' option.");
-      }
-      if (legacyOptsBoolean) {
-        throw new IllegalArgumentException(
-            "The Client options: --debug, -fake, --mock, --ssl, --sasl"
-                + "have been dropped. Use accumulo-client.properties for any 
connection or token "
-                + "options. See '-c, --config-file' option.");
-      }
+    Set<String> options = getPopulatedLegacyOptions();
+    if (!options.isEmpty()) {
+      String optionsStr = String.join(" ", options);
+      throw new IllegalArgumentException("The Client options " + optionsStr
+          + " have been dropped. Use accumulo-client.properties for any 
connection or"
+          + " token options. See '" + ClientOpts.OPT_CONFIG_FILE_SHORT + ", "
+          + ClientOpts.OPT_CONFIG_FILE_LONG + "' option.");
     }
   }
 
+  /**
+   * Get the list of legacy options provided to the Accumulo client.
+   *
+   * @return the legacy options
+   */
+  private Set<String> getPopulatedLegacyOptions() {
+    Set<String> options = new LinkedHashSet<>();
+    if (legacyPassword != null) {
+      options.add(LEGACY_OPT_PASSWORD);
+    }
+    if (legacyTokenClass != null) {
+      // Add both the short and long form.
+      options.add(LEGACY_OPT_TOKEN_CLASS_SHORT);
+      options.add(LEGACY_OPT_TOKEN_CLASS_LONG);
+    }
+    if (legacyInstance != null) {
+      // Add both the short and long form.
+      options.add(LEGACY_OPT_INSTANCE_SHORT);
+      options.add(LEGACY_OPT_INSTANCE_LONG);
+    }
+    if (legacySiteFile != null) {
+      options.add(LEGACY_OPT_SITE_FILE);
+    }
+    if (legacyKeytab != null) {
+      options.add(LEGACY_OPT_KEYTAB);
+    }
+    if (legacyDebug) {
+      options.add(LEGACY_OPT_DEBUG);
+    }
+    if (legacyFake) {
+      options.add(LEGACY_OPT_FAKE);
+    }
+    if (legacyMock) {
+      options.add(LEGACY_OPT_MOCK);
+    }
+    if (legacySsl) {
+      options.add(LEGACY_OPT_SSL);
+    }
+    if (legacySasl) {
+      options.add(LEGACY_OPT_SASL);
+    }
+    return options;
+  }
+
   private Properties cachedProps = null;
 
   public String getClientConfigFile() {
@@ -230,4 +297,5 @@ public class ClientOpts extends Help {
     }
     return cachedProps;
   }
+
 }
diff --git 
a/core/src/test/java/org/apache/accumulo/core/cli/TestClientOpts.java 
b/core/src/test/java/org/apache/accumulo/core/cli/TestClientOpts.java
index 3ff4f2e921..71fa400bc8 100644
--- a/core/src/test/java/org/apache/accumulo/core/cli/TestClientOpts.java
+++ b/core/src/test/java/org/apache/accumulo/core/cli/TestClientOpts.java
@@ -18,18 +18,104 @@
  */
 package org.apache.accumulo.core.cli;
 
+import static org.apache.accumulo.core.cli.ClientOpts.LEGACY_OPT_DEBUG;
+import static org.apache.accumulo.core.cli.ClientOpts.LEGACY_OPT_FAKE;
+import static org.apache.accumulo.core.cli.ClientOpts.LEGACY_OPT_INSTANCE_LONG;
+import static 
org.apache.accumulo.core.cli.ClientOpts.LEGACY_OPT_INSTANCE_SHORT;
+import static org.apache.accumulo.core.cli.ClientOpts.LEGACY_OPT_KEYTAB;
+import static org.apache.accumulo.core.cli.ClientOpts.LEGACY_OPT_MOCK;
+import static org.apache.accumulo.core.cli.ClientOpts.LEGACY_OPT_PASSWORD;
+import static org.apache.accumulo.core.cli.ClientOpts.LEGACY_OPT_SASL;
+import static org.apache.accumulo.core.cli.ClientOpts.LEGACY_OPT_SITE_FILE;
+import static org.apache.accumulo.core.cli.ClientOpts.LEGACY_OPT_SSL;
+import static 
org.apache.accumulo.core.cli.ClientOpts.LEGACY_OPT_TOKEN_CLASS_LONG;
+import static 
org.apache.accumulo.core.cli.ClientOpts.LEGACY_OPT_TOKEN_CLASS_SHORT;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.params.provider.Arguments.arguments;
 
 import java.util.Properties;
+import java.util.stream.Stream;
 
 import org.apache.accumulo.core.client.security.tokens.PasswordToken;
 import org.apache.accumulo.core.conf.ClientProperty;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
 
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
 public class TestClientOpts {
 
+  /**
+   * Provide a stream of arguments with the following parameters:
+   * <ol>
+   * <li>The option</li>
+   * <li>Whether the option is a boolean flag</li>
+   * <li>What is expected to be present in the error message</li>
+   * </ol>
+   *
+   * @return the arguments
+   */
+  private static Stream<Arguments> provideLegacyOptions() {
+    // @formatter:off
+    return Stream.of(
+                    arguments(LEGACY_OPT_PASSWORD, false, LEGACY_OPT_PASSWORD),
+                    arguments(LEGACY_OPT_TOKEN_CLASS_SHORT, false, 
LEGACY_OPT_TOKEN_CLASS_SHORT + " " + LEGACY_OPT_TOKEN_CLASS_LONG),
+                    arguments(LEGACY_OPT_TOKEN_CLASS_LONG, false, 
LEGACY_OPT_TOKEN_CLASS_SHORT + " " + LEGACY_OPT_TOKEN_CLASS_LONG),
+                    arguments(LEGACY_OPT_INSTANCE_SHORT, false, 
LEGACY_OPT_INSTANCE_SHORT + " " + LEGACY_OPT_INSTANCE_LONG),
+                    arguments(LEGACY_OPT_INSTANCE_LONG, false, 
LEGACY_OPT_INSTANCE_SHORT + " " + LEGACY_OPT_INSTANCE_LONG),
+                    arguments(LEGACY_OPT_SITE_FILE, false, 
LEGACY_OPT_SITE_FILE),
+                    arguments(LEGACY_OPT_KEYTAB, false, LEGACY_OPT_KEYTAB),
+                    arguments(LEGACY_OPT_DEBUG, true, LEGACY_OPT_DEBUG),
+                    arguments(LEGACY_OPT_FAKE, true, LEGACY_OPT_FAKE),
+                    arguments(LEGACY_OPT_MOCK, true, LEGACY_OPT_MOCK),
+                    arguments(LEGACY_OPT_SSL, true, LEGACY_OPT_SSL),
+                    arguments(LEGACY_OPT_SASL, true, LEGACY_OPT_SASL)
+    );
+    // @formatter:on
+  }
+
+  /**
+   * Verify that if the given legacy option is provided to the Accumulo 
client, an error is thrown.
+   *
+   * @param option the option name
+   * @param isFlag whether the option is a flag
+   * @param formattedOption what we expect to see in the error message
+   */
+  @DisplayName("Verify legacy options result in exception")
+  @ParameterizedTest(name = "Option: {0}, Flag: {1}, Expected in message: 
''{2}''")
+  @Order(1)
+  @MethodSource("provideLegacyOptions")
+  void testLegacyOptions(String option, boolean isFlag, String 
formattedOption) {
+    String[] args = isFlag ? new String[] {option} : new String[] {option, 
"value"};
+    ClientOpts opts = new ClientOpts();
+    IllegalArgumentException exception =
+        assertThrows(IllegalArgumentException.class, () -> 
opts.parseArgs("test", args));
+    assertTrue(exception.getMessage()
+        .contains("The Client options " + formattedOption + " have been 
dropped."));
+  }
+
+  /**
+   * Verify that if multiple legacy options are provided to the Accumulo 
client, they are all
+   * included in the error message.
+   */
+  @Test
+  void testMultipleLegacyOptionsAreAllListedInException() {
+    String[] args =
+        {LEGACY_OPT_PASSWORD, "1234", LEGACY_OPT_INSTANCE_SHORT, "myInstance", 
LEGACY_OPT_DEBUG};
+    ClientOpts opts = new ClientOpts();
+    IllegalArgumentException exception =
+        assertThrows(IllegalArgumentException.class, () -> 
opts.parseArgs("test", args));
+    assertTrue(exception.getMessage()
+        .contains("The Client options -p -i --instance --debug have been 
dropped."));
+  }
+
   @Test
   public void testBasic() {
     ClientOpts opts = new ClientOpts();
@@ -66,13 +152,4 @@ public class TestClientOpts {
     assertEquals("myinst", props.getProperty("instance.name"));
   }
 
-  @Test
-  public void testSasl() throws Exception {
-    ClientOpts opts = new ClientOpts();
-    String[] args =
-        new String[] {"--password", "mypass", "-u", "userabc", "-o", 
"instance.name=myinst", "-o",
-            "instance.zookeepers=zoo1,zoo2", "-o", "auth.principal=user123", 
"--sasl"};
-    assertThrows(IllegalArgumentException.class, () -> opts.parseArgs("test", 
args));
-  }
-
 }

Reply via email to