HBASE-21317 [hbck2] Add version, version handling, and
authorMichael Stack <stack@apache.org>
Mon, 15 Oct 2018 14:35:50 +0000 (09:35 -0500)
committerMichael Stack <stack@apache.org>
Mon, 15 Oct 2018 15:25:01 +0000 (10:25 -0500)
misc override to assigns/unassigns

M hbase-hbck2/pom.xml
 Add handling of a hbck.properties file that gets bundle
 up in the jar. During build, interpolation adds version
 and git info via git-commit-id-plugin and filtering.

M hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java
 Add version emission. Add fail when we go against an hbase
 that does not support hbck2.

 Add assigns/unassigns override. Change 'force' on bypass
 to match. Add a recursive to bypass so if passed a parent
 it will find children and bypass them.

hbase-hbck2/pom.xml
hbase-hbck2/src/main/java/org/apache/hbase/HBCK2.java
hbase-hbck2/src/main/resources/log4j2.xml
hbase-hbck2/src/test/java/org/apache/hbase/TestHBCK2.java
hbase-hbck2/src/test/java/org/apache/hbase/TestHBCKCommandLineParsing.java

index 91d147c..d6f2b7d 100644 (file)
   <artifactId>hbase-hbck2</artifactId>
   <name>Apache HBase - HBCK2</name>
   <description>HBCK for HBase 2+</description>
+  <properties>
+    <log4j2.version>2.11.1</log4j2.version>
+  </properties>
 
   <build>
-    <resources />
+    <resources>
+      <resource>
+          <directory>src/main/resources</directory>
+          <filtering>true</filtering>
+          <includes>
+              <include>**/hbck2.properties</include>
+              <include>**/log4j2.xml</include>
+          </includes>
+      </resource>
+    </resources>
     <testResources>
       <testResource>
         <directory>src/test/resources/META-INF/</directory>
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <groupId>pl.project13.maven</groupId>
+        <artifactId>git-commit-id-plugin</artifactId>
+        <version>2.2.5</version>
+        <executions>
+          <execution>
+            <id>get-the-git-infos</id>
+            <goals>
+              <goal>revision</goal>
+            </goals>
+            <!-- *NOTE*: The default phase of revision is initialize, but in case you want to change it, you can do so by adding the phase here -->
+            <phase>initialize</phase>
+          </execution>
+          <execution>
+            <id>validate-the-git-infos</id>
+            <goals>
+              <goal>validateRevision</goal>
+            </goals>
+            <!-- *NOTE*: The default phase of validateRevision is verify, but in case you want to change it, you can do so by adding the phase here -->
+            <phase>package</phase>
+          </execution>
+        </executions>
+        <configuration>
+          <dotGitDirectory>${project.basedir}/.git</dotGitDirectory>
+          <commitIdGenerationMode>flat</commitIdGenerationMode>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
   <dependencies>
     <dependency>
       <groupId>org.apache.logging.log4j</groupId>
       <artifactId>log4j-api</artifactId>
-      <version>2.11.1</version>
+      <version>${log4j2.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+      <version>${log4j2.version}</version>
     </dependency>
+    <!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-1.2-api -->
     <dependency>
-        <groupId>org.apache.logging.log4j</groupId>
-        <artifactId>log4j-core</artifactId>
-        <version>2.11.1</version>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-1.2-api</artifactId>
+      <version>${log4j2.version}</version>
     </dependency>
+
     <!--We want to use the shaded client but for testing, we need to rely on hbase-server.
         HBASE-15666 is about how shaded-client and hbase-server won't work together.
         TODO: Fix.-->
-      <dependency>
-        <groupId>org.apache.hbase</groupId>
-        <artifactId>hbase-server</artifactId>
-        <version>${hbase.version}</version>
-        <scope>provided</scope>
-      </dependency>
-      <dependency>
-        <groupId>org.apache.hbase</groupId>
-        <artifactId>hbase-testing-util</artifactId>
-        <version>${hbase.version}</version>
-        <scope>test</scope>
-      </dependency>
+    <dependency>
+      <groupId>org.apache.hbase</groupId>
+      <artifactId>hbase-server</artifactId>
+      <version>${hbase.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hbase</groupId>
+      <artifactId>hbase-testing-util</artifactId>
+      <version>${hbase.version}</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <profiles>
index a22fb82..64882aa 100644 (file)
@@ -26,13 +26,17 @@ import org.apache.commons.cli.Options;
 import org.apache.commons.cli.ParseException;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.conf.Configured;
+import org.apache.hadoop.hbase.ClusterMetrics;
 import org.apache.hadoop.hbase.HBaseConfiguration;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.Admin;
 import org.apache.hadoop.hbase.client.ClusterConnection;
+import org.apache.hadoop.hbase.client.Connection;
 import org.apache.hadoop.hbase.client.ConnectionFactory;
 import org.apache.hadoop.hbase.client.Hbck;
 import org.apache.hadoop.hbase.client.TableState;
+import org.apache.hadoop.hbase.util.VersionInfo;
 import org.apache.hadoop.util.Tool;
 import org.apache.hadoop.util.ToolRunner;
 import org.apache.logging.log4j.Level;
@@ -40,10 +44,14 @@ import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.config.Configurator;
 
+import java.io.BufferedReader;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.Arrays;
+import java.util.EnumSet;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -52,12 +60,13 @@ import java.util.stream.Collectors;
  * Supercedes hbck1.
  */
 // TODO:
-// + Add bulk assign/unassigns. If 60k OPENING regions, doing it via shell takes 10-60 seconds each.
 // + On assign, can we look to see if existing assign and if so fail until cancelled?
 // + Add test of Master version to ensure it supports hbck functionality.
+// ++ Hard. Server doesn't volunteer its version. Need to read the status? HBASE-20225
 // + Doc how we just take pointer to zk ensemble... If want to do more exotic config. on client,
 // then add a hbase-site.xml onto CLASSPATH for this tool to pick up.
-// + Kerberized cluster
+// + Add --version
+// + Add emitting what is supported against remote server?
 public class HBCK2 extends Configured implements Tool {
   private static final Logger LOG = LogManager.getLogger(HBCK2.class);
   public static final int EXIT_SUCCESS = 0;
@@ -67,34 +76,82 @@ public class HBCK2 extends Configured implements Tool {
   private static final String ASSIGNS = "assigns";
   private static final String UNASSIGNS = "unassigns";
   private static final String BYPASS = "bypass";
+  private static final String VERSION = "version";
   private Configuration conf;
+  private static final String TWO_POINT_ONE = "2.1.0";
+  private static final String MININUM_VERSION = "2.0.3";
 
-  TableState setTableState(TableName tableName, TableState.State state)
-      throws IOException {
-    try (ClusterConnection conn =
+  /**
+   * Check for HBCK support.
+   */
+  void checkHBCKSupport() throws IOException {
+    try (ClusterConnection connection =
              (ClusterConnection)ConnectionFactory.createConnection(getConf())) {
+      try (Admin admin = connection.getAdmin()) {
+        checkVersion(admin.getClusterMetrics(EnumSet.of(ClusterMetrics.Option.HBASE_VERSION)).
+            getHBaseVersion());
+      }
+    }
+  }
+
+  static void checkVersion(final String versionStr) {
+    if (versionStr.startsWith(TWO_POINT_ONE)) {
+      throw new UnsupportedOperationException(TWO_POINT_ONE + " has no support for hbck2");
+    }
+    if (VersionInfo.compareVersion(MININUM_VERSION, versionStr) > 0) {
+      throw new UnsupportedOperationException("Requires " + MININUM_VERSION + " at least.");
+    }
+  }
+
+  TableState setTableState(TableName tableName, TableState.State state) throws IOException {
+    try (ClusterConnection conn =
+             (ClusterConnection) ConnectionFactory.createConnection(getConf())) {
       try (Hbck hbck = conn.getHbck()) {
         return hbck.setTableStateInMeta(new TableState(tableName, state));
       }
     }
   }
 
-  List<Long> assigns(List<String> encodedRegionNames)
-  throws IOException {
+  List<Long> assigns(String [] args) throws IOException {
+    Options options = new Options();
+    Option override = Option.builder("o").longOpt("override").build();
+    options.addOption(override);
+    // Parse command-line.
+    CommandLineParser parser = new DefaultParser();
+    CommandLine commandLine = null;
+    try {
+      commandLine = parser.parse(options, args, false);
+    } catch (ParseException e) {
+      usage(options, e.getMessage());
+      return null;
+    }
+    boolean overrideFlag = commandLine.hasOption(override.getOpt());
     try (ClusterConnection conn =
-             (ClusterConnection)ConnectionFactory.createConnection(getConf())) {
+             (ClusterConnection) ConnectionFactory.createConnection(getConf())) {
       try (Hbck hbck = conn.getHbck()) {
-        return hbck.assigns(encodedRegionNames);
+        return hbck.assigns(commandLine.getArgList(), overrideFlag);
       }
     }
   }
 
-  List<Long> unassigns(List<String> encodedRegionNames)
-  throws IOException {
+  List<Long> unassigns(String [] args) throws IOException {
+    Options options = new Options();
+    Option override = Option.builder("o").longOpt("override").build();
+    options.addOption(override);
+    // Parse command-line.
+    CommandLineParser parser = new DefaultParser();
+    CommandLine commandLine = null;
+    try {
+      commandLine = parser.parse(options, args, false);
+    } catch (ParseException e) {
+      usage(options, e.getMessage());
+      return null;
+    }
+    boolean overrideFlag = commandLine.hasOption(override.getOpt());
     try (ClusterConnection conn =
-             (ClusterConnection)ConnectionFactory.createConnection(getConf())) {
+             (ClusterConnection) ConnectionFactory.createConnection(getConf())) {
       try (Hbck hbck = conn.getHbck()) {
-        return hbck.unassigns(encodedRegionNames);
+        return hbck.unassigns(commandLine.getArgList(), overrideFlag);
       }
     }
   }
@@ -102,75 +159,97 @@ public class HBCK2 extends Configured implements Tool {
   /**
    * @return List of results OR null if failed to run.
    */
-  List<Boolean> bypass(List<String> args)
+  List<Boolean> bypass(String [] args)
       throws IOException {
     // Bypass has two options....
-    Options options =  new Options();
-    Option force = Option.builder("f").longOpt("force").
-        desc("'force' the procedure finish").build();
-    options.addOption(force);
-    Option wait = Option.builder("w").longOpt("waitTime").hasArg().
-        desc("time to wait on entity lock before giving up").type(Integer.class).build();
+    Options options = new Options();
+    // See usage for 'help' on these options.
+    Option override = Option.builder("o").longOpt("override").build();
+    options.addOption(override);
+    Option recursive = Option.builder("r").longOpt("recursive").build();
+    options.addOption(recursive);
+    Option wait = Option.builder("w").longOpt("waitTime").hasArg().type(Integer.class).build();
     options.addOption(wait);
     // Parse command-line.
     CommandLineParser parser = new DefaultParser();
     CommandLine commandLine = null;
     try {
-      commandLine = parser.parse(options, args.toArray(new String [] {}), false);
+      commandLine = parser.parse(options, args, false);
     } catch (ParseException e) {
       usage(options, e.getMessage());
       return null;
     }
-    boolean b = commandLine.hasOption(force.getOpt());
     long waitTime = 0;
     if (commandLine.hasOption(wait.getOpt())) {
       waitTime = Integer.valueOf(commandLine.getOptionValue(wait.getOpt()));
       waitTime *= 1000; // Because time is in seconds.
     }
-    String [] pidStrs = commandLine.getArgs();
+    String[] pidStrs = commandLine.getArgs();
     if (pidStrs == null || pidStrs.length <= 0) {
       usage(options, "No pids supplied.");
       return null;
     }
+    boolean overrideFlag = commandLine.hasOption(override.getOpt());
+    boolean recursiveFlag = commandLine.hasOption(override.getOpt());
     List<Long> pids = Arrays.stream(pidStrs).map(i -> Long.valueOf(i)).collect(Collectors.toList());
-    try (ClusterConnection c = (ClusterConnection)ConnectionFactory.createConnection(getConf())) {
+    try (ClusterConnection c = (ClusterConnection) ConnectionFactory.createConnection(getConf())) {
       try (Hbck hbck = c.getHbck()) {
-        return hbck.bypassProcedure(pids, waitTime, b);
+        return hbck.bypassProcedure(pids, waitTime, overrideFlag, recursiveFlag);
       }
     }
   }
 
+  private String readHBCK2BuildProperties() throws IOException {
+    ClassLoader classLoader = getClass().getClassLoader();
+    InputStream inputStream = classLoader.getResourceAsStream("hbck2.properties");
+    StringBuilder resultStringBuilder = new StringBuilder();
+    BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
+    String line;
+    while ((line = br.readLine()) != null) {
+      resultStringBuilder.append(line).append("\n");
+    }
+    return resultStringBuilder.toString();
+  }
+
   private static final String getCommandUsage() {
     // NOTE: List commands belonw alphabetically!
     StringWriter sw = new StringWriter();
     PrintWriter writer = new PrintWriter(sw);
     writer.println();
     writer.println("Commands:");
-    writer.println(" " + ASSIGNS + " <ENCODED_REGIONNAME>...");
+    writer.println(" " + ASSIGNS + " [OPTIONS] <ENCODED_REGIONNAME>...");
+    writer.println("   Options:");
+    writer.println("    -o,--override  override ownership by another procedure");
     writer.println("   A 'raw' assign that can be used even during Master initialization.");
-    writer.println("   Skirts Coprocessors. Pass one or more encoded RegionNames:");
-    writer.println("   e.g. 1588230740 is hard-coded encoding for hbase:meta region and");
-    writer.println("   de00010733901a05f5a2a3a382e27dd4 is an example of what a random");
-    writer.println("   user-space encoded Region name looks like. For example:");
+    writer.println("   Skirts Coprocessors. Pass one or more encoded RegionNames.");
+    writer.println("   1588230740 is the hard-coded name for the hbase:meta region and");
+    writer.println("   de00010733901a05f5a2a3a382e27dd4 is an example of what a user-space");
+    writer.println("   encoded Region name looks like. For example:");
     writer.println("     $ HBCK2 assign 1588230740 de00010733901a05f5a2a3a382e27dd4");
-    writer.println("   Returns the pid of the created AssignProcedure or -1 if none.");
+    writer.println("   Returns the pid(s) of the created AssignProcedure(s) or -1 if none.");
     writer.println();
     writer.println(" " + BYPASS + " [OPTIONS] <PID>...");
-    writer.println("   Pass one (or more) procedure 'pid's to skip to the procedure finish.");
-    writer.println("   Parent of this procedures will also skip to its finish. Entities will");
-    writer.println("   be left in an inconsistent state and will require manual fixup.");
-    writer.println("   Pass --force to break any outstanding locks.");
-    writer.println("   Pass --waitTime=<seconds> to wait on entity lock before giving up.");
-    writer.println("   Default: force=false and waitTime=0. Returns true if succeeded.");
+    writer.println("   Options:");
+    writer.println("    -o,--override   interrupt if procedure is running");
+    writer.println("    -r,--recursive  bypass parent and its children. SLOW! EXPENSIVE!");
+    writer.println("    -w,--waitTime   seconds to wait on lock before giving up; default=0");
+    writer.println("   Pass one (or more) procedure 'pid's to skip to procedure finish.");
+    writer.println("   Parent of bypassed procedure will also be skipped to the finish.");
+    writer.println("   Entities will be left in an inconsistent state and will require");
+    writer.println("   manual fixup. Bypass fails if procedure has children. Add 'recursive'");
+    writer.println("   if all you have is a parent pid to finish parent and children. This");
+    writer.println("   is SLOW, and dangerous so use selectively. Does not always work.");
     writer.println();
     writer.println(" " + UNASSIGNS + " <ENCODED_REGIONNAME>...");
+    writer.println("   Options:");
+    writer.println("    -o,--override  override ownership by another procedure");
     writer.println("   A 'raw' unassign that can be used even during Master initialization.");
     writer.println("   Skirts Coprocessors. Pass one or more encoded RegionNames:");
-    writer.println("   Skirts Coprocessors. Pass one or more encoded RegionNames:");
-    writer.println("   de00010733901a05f5a2a3a382e27dd4 is an example of what a random");
-    writer.println("   user-space encoded Region name looks like. For example:");
+    writer.println("   1588230740 is the hard-coded name for the hbase:meta region and");
+    writer.println("   de00010733901a05f5a2a3a382e27dd4 is an example of what a user-space");
+    writer.println("   encoded Region name looks like. For example:");
     writer.println("     $ HBCK2 unassign 1588230740 de00010733901a05f5a2a3a382e27dd4");
-    writer.println("   Returns the pid of the created UnassignProcedure or -1 if none.");
+    writer.println("   Returns the pid(s) of the created UnassignProcedure(s) or -1 if none.");
     writer.println();
     writer.println(" " + SET_TABLE_STATE + " <TABLENAME> <STATE>");
     writer.println("   Possible table states: " + Arrays.stream(TableState.State.values()).
@@ -196,7 +275,7 @@ public class HBCK2 extends Configured implements Tool {
       System.out.println("ERROR: " + error);
     }
     HelpFormatter formatter = new HelpFormatter();
-    formatter.printHelp( "HBCK2 [OPTIONS] COMMAND <ARGS>",
+    formatter.printHelp("HBCK2 [OPTIONS] COMMAND <ARGS>",
         "\nOptions:", options, getCommandUsage());
   }
 
@@ -211,7 +290,7 @@ public class HBCK2 extends Configured implements Tool {
   }
 
   @Override
-  public int run(String [] args) throws IOException {
+  public int run(String[] args) throws IOException {
     // Configure Options. The below article was more helpful than the commons-cli doc:
     // https://dzone.com/articles/java-command-line-interfaces-part-1-apache-commons
     Options options = new Options();
@@ -226,8 +305,10 @@ public class HBCK2 extends Configured implements Tool {
         desc("parent znode of target hbase").build();
     options.addOption(parent);
     Option peerPort = Option.builder("p").longOpt(HConstants.ZOOKEEPER_CLIENT_PORT).
-        desc("peerport of target hbase ensemble").type(Integer.class).build();
+        desc("port of target hbase ensemble").type(Integer.class).build();
     options.addOption(peerPort);
+    Option version = Option.builder("v").longOpt(VERSION).desc("this hbck2 version").build();
+    options.addOption(version);
 
     // Parse command-line.
     CommandLineParser parser = new DefaultParser();
@@ -240,6 +321,10 @@ public class HBCK2 extends Configured implements Tool {
     }
 
     // Process general options.
+    if (commandLine.hasOption(version.getOpt())) {
+      System.out.println(readHBCK2BuildProperties());
+      return EXIT_SUCCESS;
+    }
     if (commandLine.hasOption(help.getOpt()) || commandLine.getArgList().isEmpty()) {
       usage(options);
       return EXIT_SUCCESS;
@@ -259,9 +344,11 @@ public class HBCK2 extends Configured implements Tool {
     if (commandLine.hasOption(parent.getOpt())) {
       getConf().set(HConstants.ZOOKEEPER_ZNODE_PARENT, commandLine.getOptionValue(parent.getOpt()));
     }
+    // Check we can run hbck at all.
+    checkHBCKSupport();
 
     // Now process commands.
-    String [] commands = commandLine.getArgs();
+    String[] commands = commandLine.getArgs();
     String command = commands[0];
     switch (command) {
       case SET_TABLE_STATE:
@@ -278,8 +365,7 @@ public class HBCK2 extends Configured implements Tool {
           usage(options, command + " takes one or more encoded region names");
           return EXIT_FAILURE;
         }
-        System.out.println(
-            toString(assigns(Arrays.stream(commands).skip(1).collect(Collectors.toList()))));
+        System.out.println(assigns(purgeFirst(commands)));
         break;
 
       case BYPASS:
@@ -287,7 +373,7 @@ public class HBCK2 extends Configured implements Tool {
           usage(options, command + " takes one or more pids");
           return EXIT_FAILURE;
         }
-        List<Boolean> bs = bypass(Arrays.stream(commands).skip(1).collect(Collectors.toList()));
+        List<Boolean> bs = bypass(purgeFirst(commands));
         if (bs == null) {
           // Something went wrong w/ the parse and command didn't run.
           return EXIT_FAILURE;
@@ -300,8 +386,7 @@ public class HBCK2 extends Configured implements Tool {
           usage(options, command + " takes one or more encoded region names");
           return EXIT_FAILURE;
         }
-        System.out.println(toString(
-            unassigns(Arrays.stream(commands).skip(1).collect(Collectors.toList()))));
+        System.out.println(toString(unassigns(purgeFirst(commands))));
         break;
 
       default:
@@ -315,6 +400,20 @@ public class HBCK2 extends Configured implements Tool {
     return things.stream().map(i -> i.toString()).collect(Collectors.joining(", "));
   }
 
+  /**
+   * @return A new array with first element dropped.
+   */
+  private static String[] purgeFirst(String[] args) {
+    int size = args.length;
+    if (size <= 1) {
+      return new String [] {};
+    }
+    size--;
+    String [] result = new String [size];
+    System.arraycopy(args, 1, result, 0, size);
+    return result;
+  }
+
   HBCK2(Configuration conf) {
     super(conf);
   }
index 9a62a18..fd44001 100644 (file)
@@ -6,7 +6,10 @@
     </Console>
   </Appenders>
   <Loggers>
-    <Root level="error">
+    <Logger name="org.apache.zookeeper" level="warn" additivity="false">
+      <AppenderRef ref="Console"/>
+    </Logger>
+    <Root level="info">
       <AppenderRef ref="Console"/>
     </Root>
   </Loggers>
index 6bc4b3c..1b54687 100644 (file)
@@ -18,7 +18,6 @@
 package org.apache.hbase;
 
 import junit.framework.TestCase;
-import org.apache.commons.cli.ParseException;
 import org.apache.hadoop.hbase.HBaseTestingUtility;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.client.Admin;
@@ -33,15 +32,12 @@ import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
 
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.PrintStream;
 import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Collectors;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
 
 /**
  * Tests commands. For command-line parsing, see adjacent test.
@@ -63,6 +59,26 @@ public class TestHBCK2 {
     TEST_UTIL.shutdownMiniCluster();
   }
 
+  @Test (expected = UnsupportedOperationException.class)
+  public void testCheckVersion202() {
+    HBCK2.checkVersion("2.0.2");
+  }
+
+  @Test (expected = UnsupportedOperationException.class)
+  public void testCheckVersion210() {
+    HBCK2.checkVersion("2.1.0");
+  }
+
+  @Test
+  public void testCheckVersion203() {
+    HBCK2.checkVersion("2.0.3");
+  }
+
+  @Test
+  public void testCheckVersion211() {
+    HBCK2.checkVersion("2.1.1");
+  }
+
   @Test
   public void testSetTableStateInMeta() throws IOException {
     HBCK2 hbck = new HBCK2(TEST_UTIL.getConfiguration());
@@ -83,8 +99,10 @@ public class TestHBCK2 {
         LOG.info("RS: {}", rs.toString());
       }
       HBCK2 hbck = new HBCK2(TEST_UTIL.getConfiguration());
-      List<Long> pids = hbck.unassigns(
-          regions.stream().map(r -> r.getEncodedName()).collect(Collectors.toList()));
+      List<String> regionStrs =
+          regions.stream().map(r -> r.getEncodedName()).collect(Collectors.toList());
+      String [] regionStrsArray = regionStrs.toArray(new String[] {});
+      List<Long> pids = hbck.unassigns(regionStrsArray);
       waitOnPids(pids);
       for (RegionInfo ri: regions) {
         RegionState rs = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager().
@@ -92,8 +110,7 @@ public class TestHBCK2 {
         LOG.info("RS: {}", rs.toString());
         TestCase.assertTrue(rs.toString(), rs.isClosed());
       }
-      pids = hbck.assigns(
-          regions.stream().map(r -> r.getEncodedName()).collect(Collectors.toList()));
+      pids = hbck.assigns(regionStrsArray);
       waitOnPids(pids);
       for (RegionInfo ri: regions) {
         RegionState rs = TEST_UTIL.getHBaseCluster().getMaster().getAssignmentManager().
@@ -102,8 +119,8 @@ public class TestHBCK2 {
         TestCase.assertTrue(rs.toString(), rs.isOpened());
       }
       // What happens if crappy region list passed?
-      pids = hbck.assigns(
-          Arrays.stream(new String [] {"a", "some rubbish name"}).collect(Collectors.toList()));
+      pids = hbck.assigns(Arrays.stream(new String [] {"a", "some rubbish name"}).
+          collect(Collectors.toList()).toArray(new String [] {}));
       for (long pid: pids) {
         assertEquals(org.apache.hadoop.hbase.procedure2.Procedure.NO_PROC_ID, pid);
       }
index c61f62f..d061767 100644 (file)
@@ -64,13 +64,14 @@ public class TestHBCKCommandLineParsing {
     System.setOut(oldOut);
     String output = os.toString();
     assertTrue(output, output.startsWith("usage: HBCK2"));
+    System.out.println(output);
   }
 
   @Test (expected=NumberFormatException.class)
   public void testCommandWithOptions() throws IOException {
     HBCK2 hbck = new HBCK2(TEST_UTIL.getConfiguration());
     // The 'x' below should cause the NumberFormatException. The Options should all be good.
-    hbck.run(new String[]{"bypass", "--waitTime=3", "--force", "x"});
+    hbck.run(new String[]{"bypass", "--waitTime=3", "--override", "--recursive", "x"});
   }
 }