From 7c738fc1bd14fd3e2ca4e66569b496b3fd9d0288 Mon Sep 17 00:00:00 2001 From: Sravi K <49591501+ksravista@users.noreply.github.com> Date: Fri, 21 Jun 2024 06:54:42 -0400 Subject: [PATCH] HBASE-28632 Make -h arg respected by hbck2 and exit if unrecognized arguments are passed (#143) The -h argument in hbck is not respected and instead of displaying the argument usage guide, the command continued to execute. Any unrecognized arguments should cause an exception and exit. Co-authored-by: Sravi Kommineni Reviewed-by: Ray Mattingly Signed-off-by: Nick Dimiduk --- .../src/main/java/org/apache/hbase/HBCK2.java | 89 ++++++++++++++++++- .../hbase/TestHBCKCommandLineParsing.java | 9 ++ 2 files changed, 96 insertions(+), 2 deletions(-) diff --git a/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java b/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java index b9c7db3a3f..c569d2773e 100644 --- a/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java +++ b/hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java @@ -1152,6 +1152,11 @@ private int doCommandLine(CommandLine commandLine, Options options) throws IOExc // Now process command. String[] commands = commandLine.getArgs(); String command = commands[0]; + + if (commandHasHelpOption(commands)) { + return showUsagePerCommand(command, options); + } + switch (command) { // Case handlers all have same format. Check first that the server supports // the feature FIRST, then move to process the command. @@ -1345,6 +1350,69 @@ private int doCommandLine(CommandLine commandLine, Options options) throws IOExc return EXIT_SUCCESS; } + static int showUsagePerCommand(String command, Options options) throws IOException { + boolean invalidCommand = false; + try (StringWriter sw = new StringWriter(); PrintWriter writer = new PrintWriter(sw)) { + writer.println("Command:"); + switch (command) { + case ADD_MISSING_REGIONS_IN_META_FOR_TABLES: + usageAddFsRegionsMissingInMeta(writer); + break; + case ASSIGNS: + usageAssigns(writer); + break; + case BYPASS: + usageBypass(writer); + break; + case FILESYSTEM: + usageFilesystem(writer); + break; + case FIX_META: + usageFixMeta(writer); + break; + case GENERATE_TABLE_INFO: + usageGenerateMissingTableInfo(writer); + break; + case REPLICATION: + usageReplication(writer); + break; + case EXTRA_REGIONS_IN_META: + usageExtraRegionsInMeta(writer); + break; + case REPORT_MISSING_REGIONS_IN_META: + usageReportMissingRegionsInMeta(writer); + break; + case SET_REGION_STATE: + usageSetRegionState(writer); + break; + case SET_TABLE_STATE: + usageSetTableState(writer); + break; + case SCHEDULE_RECOVERIES: + usageScheduleRecoveries(writer); + break; + case RECOVER_UNKNOWN: + usageRecoverUnknown(writer); + break; + case UNASSIGNS: + usageUnassigns(writer); + break; + case REGIONINFO_MISMATCH: + usageRegioninfoMismatch(writer); + break; + default: + showErrorMessage("Invalid arg: " + command); + invalidCommand = true; + break; + } + if (!invalidCommand) { + HelpFormatter formatter = new HelpFormatter(); + formatter.printHelp("HBCK2 [OPTIONS] COMMAND ", "Options:", options, sw.toString()); + } + return invalidCommand ? EXIT_FAILURE : EXIT_SUCCESS; + } + } + private static String toString(List things) { return things.stream().map(Object::toString).collect(Collectors.joining(", ")); } @@ -1507,22 +1575,39 @@ private Pair> parseCommandWithFixAndInputOptions(Strin return Pair.newPair(commandLine, params); } + private boolean commandHasHelpOption(String[] args) { + args = purgeFirst(args); + Options options = new Options(); + Option helpOption = + Option.builder("h").longOpt("help").desc("help message for a command").build(); + + options.addOption(helpOption); + CommandLine test = getCommandLine(args, options, false); + return test != null && test.hasOption(helpOption.getOpt()); + } + /** * Get a commandLine object with options and a arg list */ - private CommandLine getCommandLine(String[] args, Options options) { + private CommandLine getCommandLine(String[] args, Options options, boolean showException) { // Parse command-line. CommandLineParser parser = new DefaultParser(); CommandLine commandLine; try { commandLine = parser.parse(options, args, false); } catch (ParseException e) { - showErrorMessage(e.getMessage()); + if (showException) { + showErrorMessage(e.getMessage()); + } return null; } return commandLine; } + private CommandLine getCommandLine(String[] args, Options options) { + return getCommandLine(args, options, true); + } + /** Returns Read arguments from args or a list of input files */ private List getFromArgsOrFiles(List args, boolean getFromFile) throws IOException { diff --git a/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCKCommandLineParsing.java b/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCKCommandLineParsing.java index 71bc97b9f6..ec56b94322 100644 --- a/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCKCommandLineParsing.java +++ b/hbase-hbck2/src/test/java/org/apache/hbase/TestHBCKCommandLineParsing.java @@ -72,6 +72,15 @@ public void testHelp() throws IOException { // Passing -h/--help does the same output = retrieveOptionOutput(new String[] { "-h" }); assertTrue(output, output.startsWith("usage: HBCK2")); + + // passing -h after the command, should print usage for that command + output = retrieveOptionOutput(new String[] { "addFsRegionsMissingInMeta", "-h" }); + assertFalse(output.contains("ERROR:")); + assertTrue(output.contains("Options:")); + + // invalid argument -h should print error + output = retrieveOptionOutput(new String[] { "invalidArg", "-h" }); + assertTrue(output.contains("ERROR:")); } @Test