diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/zookeeper/ZooKeeperMainServer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/zookeeper/ZooKeeperMainServer.java index 08003356345..4b850e7e8ec 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/zookeeper/ZooKeeperMainServer.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/zookeeper/ZooKeeperMainServer.java @@ -19,6 +19,7 @@ package org.apache.hadoop.hbase.zookeeper; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map.Entry; @@ -26,6 +27,7 @@ import java.util.Properties; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; +import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.ZooKeeperMain; /** @@ -33,6 +35,8 @@ import org.apache.zookeeper.ZooKeeperMain; * from HBase XML configuration. */ public class ZooKeeperMainServer { + private static final String SERVER_ARG = "-server"; + public String parse(final Configuration c) { // Note that we do not simply grab the property // HConstants.ZOOKEEPER_QUORUM from the HBaseConfiguration because the @@ -61,20 +65,72 @@ public class ZooKeeperMainServer { return host.toString(); } + /** + * ZooKeeper 3.4.6 broke being able to pass commands on command line. + * See ZOOKEEPER-1897. This class is a hack to restore this faclity. + */ + private static class HACK_UNTIL_ZOOKEEPER_1897_ZooKeeperMain extends ZooKeeperMain { + public HACK_UNTIL_ZOOKEEPER_1897_ZooKeeperMain(String[] args) + throws IOException, InterruptedException { + super(args); + } + + /** + * Run the command-line args passed. Calls System.exit when done. + * @throws KeeperException + * @throws IOException + * @throws InterruptedException + */ + void runCmdLine() throws KeeperException, IOException, InterruptedException { + processCmd(this.cl); + System.exit(0); + } + } + + /** + * @param args + * @return True if argument strings have a '-server' in them. + */ + private static boolean hasServer(final String args[]) { + return args.length > 0 && args[0].equals(SERVER_ARG); + } + + /** + * @param args + * @return True if command-line arguments were passed. + */ + private static boolean hasCommandLineArguments(final String args[]) { + if (hasServer(args)) { + if (args.length < 2) throw new IllegalStateException("-server param but no value"); + return args.length > 2; + } + return args.length > 0; + } + /** * Run the tool. * @param args Command line arguments. First arg is path to zookeepers file. */ public static void main(String args[]) throws Exception { - Configuration conf = HBaseConfiguration.create(); - String hostport = new ZooKeeperMainServer().parse(conf); - String[] newArgs = args; - if (hostport != null && hostport.length() > 0) { - newArgs = new String[args.length + 2]; - System.arraycopy(args, 0, newArgs, 2, args.length); - newArgs[0] = "-server"; - newArgs[1] = hostport; + String [] newArgs = args; + if (!hasServer(args)) { + // Add the zk ensemble from configuration if none passed on command-line. + Configuration conf = HBaseConfiguration.create(); + String hostport = new ZooKeeperMainServer().parse(conf); + if (hostport != null && hostport.length() > 0) { + newArgs = new String[args.length + 2]; + System.arraycopy(args, 0, newArgs, 2, args.length); + newArgs[0] = "-server"; + newArgs[1] = hostport; + } + } + // If command-line arguments, run our hack so they are executed. + if (hasCommandLineArguments(args)) { + HACK_UNTIL_ZOOKEEPER_1897_ZooKeeperMain zkm = + new HACK_UNTIL_ZOOKEEPER_1897_ZooKeeperMain(newArgs); + zkm.runCmdLine(); + } else { + ZooKeeperMain.main(newArgs); } - ZooKeeperMain.main(newArgs); } } \ No newline at end of file diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZooKeeperMainServer.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZooKeeperMainServer.java index cf0294a9baf..88fedd02eb3 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZooKeeperMainServer.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZooKeeperMainServer.java @@ -21,6 +21,8 @@ package org.apache.hadoop.hbase.zookeeper; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import java.security.Permission; + import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.*; import org.junit.Test; @@ -28,9 +30,69 @@ import org.junit.experimental.categories.Category; @Category(SmallTests.class) public class TestZooKeeperMainServer { - private final ZooKeeperMainServer parser = new ZooKeeperMainServer(); + // ZKMS calls System.exit. Catch the call and prevent exit using trick described up in + // http://stackoverflow.com/questions/309396/java-how-to-test-methods-that-call-system-exit + protected static class ExitException extends SecurityException { + private static final long serialVersionUID = 1L; + public final int status; + public ExitException(int status) { + super("There is no escape!"); + this.status = status; + } + } - @Test public void test() { + private static class NoExitSecurityManager extends SecurityManager { + @Override + public void checkPermission(Permission perm) { + // allow anything. + } + + @Override + public void checkPermission(Permission perm, Object context) { + // allow anything. + } + + @Override + public void checkExit(int status) { + super.checkExit(status); + throw new ExitException(status); + } + } + + /** + * We need delete of a znode to work at least. + * @throws Exception + */ + @Test + public void testCommandLineWorks() throws Exception { + System.setSecurityManager(new NoExitSecurityManager()); + HBaseTestingUtility htu = new HBaseTestingUtility(); + htu.getConfiguration().setInt(HConstants.ZK_SESSION_TIMEOUT, 1000); + htu.startMiniZKCluster(); + try { + ZooKeeperWatcher zkw = htu.getZooKeeperWatcher(); + String znode = "/testCommandLineWorks"; + ZKUtil.createWithParents(zkw, znode, HConstants.EMPTY_BYTE_ARRAY); + ZKUtil.checkExists(zkw, znode); + boolean exception = false; + try { + ZooKeeperMainServer.main(new String [] {"-server", + "localhost:" + htu.getZkCluster().getClientPort(), "delete", znode}); + } catch (ExitException ee) { + // ZKMS calls System.exit which should trigger this exception. + exception = true; + } + assertTrue(exception); + assertEquals(-1, ZKUtil.checkExists(zkw, znode)); + } finally { + htu.shutdownMiniZKCluster(); + System.setSecurityManager(null); // or save and restore original + } + } + + @Test + public void testHostPortParse() { + ZooKeeperMainServer parser = new ZooKeeperMainServer(); Configuration c = HBaseConfiguration.create(); assertEquals("localhost:" + c.get(HConstants.ZOOKEEPER_CLIENT_PORT), parser.parse(c)); final String port = "1234";