You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@helix.apache.org by zz...@apache.org on 2013/11/01 00:48:34 UTC
git commit: [HELIX-285] add integration test util's, rb=15160
Updated Branches:
refs/heads/helix-0.6.2-release 711561b8a -> f2c245f79
[HELIX-285] add integration test util's, rb=15160
Project: http://git-wip-us.apache.org/repos/asf/incubator-helix/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-helix/commit/f2c245f7
Tree: http://git-wip-us.apache.org/repos/asf/incubator-helix/tree/f2c245f7
Diff: http://git-wip-us.apache.org/repos/asf/incubator-helix/diff/f2c245f7
Branch: refs/heads/helix-0.6.2-release
Commit: f2c245f79d9abdcff6366153a7ed6246a219f872
Parents: 711561b
Author: zzhang <zz...@apache.org>
Authored: Thu Oct 31 16:48:16 2013 -0700
Committer: zzhang <zz...@apache.org>
Committed: Thu Oct 31 16:48:16 2013 -0700
----------------------------------------------------------------------
helix-core/pom.xml | 4 +
.../helix/controller/HelixControllerMain.java | 4 +
.../apache/helix/examples/ExampleProcess.java | 13 +-
.../manager/zk/HelixManagerShutdownHook.java | 26 +++
.../tools/ClusterExternalViewVerifier.java | 151 +++++++++++++++
.../helix/tools/ClusterLiveNodesVerifier.java | 26 +++
.../org/apache/helix/tools/ClusterVerifier.java | 128 +++++++++++++
.../apache/helix/tools/IntegrationTestUtil.java | 185 +++++++++++++++++++
8 files changed, 535 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/f2c245f7/helix-core/pom.xml
----------------------------------------------------------------------
diff --git a/helix-core/pom.xml b/helix-core/pom.xml
index 0c42af8..c6d2fca 100644
--- a/helix-core/pom.xml
+++ b/helix-core/pom.xml
@@ -226,6 +226,10 @@ under the License.
<mainClass>org.apache.helix.tools.YAMLClusterSetup</mainClass>
<name>yaml-cluster-setup</name>
</program>
+ <program>
+ <mainClass>org.apache.helix.tools.IntegrationTestUtil</mainClass>
+ <name>test-util</name>
+ </program>
</programs>
</configuration>
</plugin>
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/f2c245f7/helix-core/src/main/java/org/apache/helix/controller/HelixControllerMain.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/controller/HelixControllerMain.java b/helix-core/src/main/java/org/apache/helix/controller/HelixControllerMain.java
index 4aae39b..62f3b23 100644
--- a/helix-core/src/main/java/org/apache/helix/controller/HelixControllerMain.java
+++ b/helix-core/src/main/java/org/apache/helix/controller/HelixControllerMain.java
@@ -48,6 +48,7 @@ import org.apache.helix.HelixManager;
import org.apache.helix.HelixManagerFactory;
import org.apache.helix.InstanceType;
import org.apache.helix.controller.restlet.ZKPropertyTransferServer;
+import org.apache.helix.manager.zk.HelixManagerShutdownHook;
import org.apache.helix.participant.DistClusterControllerStateModelFactory;
import org.apache.helix.participant.StateMachineEngine;
import org.apache.log4j.Logger;
@@ -233,6 +234,9 @@ public class HelixControllerMain {
HelixManager manager =
startHelixController(zkConnectString, clusterName, controllerName, controllerMode);
+
+ Runtime.getRuntime().addShutdownHook(new HelixManagerShutdownHook(manager));
+
try {
Thread.currentThread().join();
} catch (InterruptedException e) {
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/f2c245f7/helix-core/src/main/java/org/apache/helix/examples/ExampleProcess.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/examples/ExampleProcess.java b/helix-core/src/main/java/org/apache/helix/examples/ExampleProcess.java
index 34a13e5..e023cf9 100644
--- a/helix-core/src/main/java/org/apache/helix/examples/ExampleProcess.java
+++ b/helix-core/src/main/java/org/apache/helix/examples/ExampleProcess.java
@@ -33,13 +33,16 @@ import org.apache.commons.cli.ParseException;
import org.apache.helix.HelixManager;
import org.apache.helix.HelixManagerFactory;
import org.apache.helix.InstanceType;
+import org.apache.helix.manager.zk.HelixManagerShutdownHook;
import org.apache.helix.model.Message.MessageType;
import org.apache.helix.participant.StateMachineEngine;
import org.apache.helix.participant.statemachine.StateModel;
import org.apache.helix.participant.statemachine.StateModelFactory;
import org.apache.helix.tools.ClusterStateVerifier;
+import org.apache.log4j.Logger;
public class ExampleProcess {
+ private static final Logger LOG = Logger.getLogger(ExampleProcess.class);
public static final String zkServer = "zkSvr";
public static final String cluster = "cluster";
@@ -57,8 +60,6 @@ public class ExampleProcess {
private final String stateModelType;
private HelixManager manager;
- // private StateMachineEngine genericStateMachineHandler;
-
private StateModelFactory<StateModel> stateModelFactory;
private final int delay;
@@ -98,6 +99,10 @@ public class ExampleProcess {
manager.disconnect();
}
+ public HelixManager getManager() {
+ return manager;
+ }
+
@SuppressWarnings("static-access")
private static Options constructCommandLineOptions() {
Option helpOption =
@@ -168,6 +173,7 @@ public class ExampleProcess {
public static void printUsage(Options cliOptions) {
HelpFormatter helpFormatter = new HelpFormatter();
+ helpFormatter.setWidth(1000);
helpFormatter.printHelp("java " + ExampleProcess.class.getName(), cliOptions);
}
@@ -232,6 +238,9 @@ public class ExampleProcess {
new ExampleProcess(zkConnectString, clusterName, instanceName, file, stateModelValue, delay);
process.start();
+
+ Runtime.getRuntime().addShutdownHook(new HelixManagerShutdownHook(process.getManager()));
+
Thread.currentThread().join();
}
}
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/f2c245f7/helix-core/src/main/java/org/apache/helix/manager/zk/HelixManagerShutdownHook.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/manager/zk/HelixManagerShutdownHook.java b/helix-core/src/main/java/org/apache/helix/manager/zk/HelixManagerShutdownHook.java
new file mode 100644
index 0000000..f91bf71
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/manager/zk/HelixManagerShutdownHook.java
@@ -0,0 +1,26 @@
+package org.apache.helix.manager.zk;
+
+import org.apache.helix.HelixManager;
+import org.apache.log4j.Logger;
+
+/**
+ * Shutdown hook for helix manager
+ * Working for kill -2/-15
+ * NOT working for kill -9
+ */
+public class HelixManagerShutdownHook extends Thread {
+ private static Logger LOG = Logger.getLogger(HelixManagerShutdownHook.class);
+
+ final HelixManager _manager;
+
+ public HelixManagerShutdownHook(HelixManager manager) {
+ _manager = manager;
+ }
+
+ @Override
+ public void run() {
+ LOG.info("HelixControllerMainShutdownHook invoked on manager: " + _manager.getClusterName()
+ + ", " + _manager.getInstanceName());
+ _manager.disconnect();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/f2c245f7/helix-core/src/main/java/org/apache/helix/tools/ClusterExternalViewVerifier.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/tools/ClusterExternalViewVerifier.java b/helix-core/src/main/java/org/apache/helix/tools/ClusterExternalViewVerifier.java
new file mode 100644
index 0000000..b72170f
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/tools/ClusterExternalViewVerifier.java
@@ -0,0 +1,151 @@
+package org.apache.helix.tools;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.helix.controller.pipeline.Stage;
+import org.apache.helix.controller.pipeline.StageContext;
+import org.apache.helix.controller.stages.AttributeName;
+import org.apache.helix.controller.stages.BestPossibleStateCalcStage;
+import org.apache.helix.controller.stages.BestPossibleStateOutput;
+import org.apache.helix.controller.stages.ClusterDataCache;
+import org.apache.helix.controller.stages.ClusterEvent;
+import org.apache.helix.controller.stages.CurrentStateComputationStage;
+import org.apache.helix.controller.stages.ResourceComputationStage;
+import org.apache.helix.manager.zk.ZkClient;
+import org.apache.helix.model.ExternalView;
+import org.apache.helix.model.Partition;
+import org.apache.log4j.Logger;
+
+/**
+ * given zk, cluster, and a list of expected live-instances
+ * check whether cluster's external-view reaches best-possible states
+ */
+public class ClusterExternalViewVerifier extends ClusterVerifier {
+ private static Logger LOG = Logger.getLogger(ClusterExternalViewVerifier.class);
+
+ final List<String> _expectSortedLiveNodes; // always sorted
+
+ public ClusterExternalViewVerifier(ZkClient zkclient, String clusterName,
+ List<String> expectLiveNodes) {
+ super(zkclient, clusterName);
+ _expectSortedLiveNodes = expectLiveNodes;
+ Collections.sort(_expectSortedLiveNodes);
+ }
+
+ boolean verifyLiveNodes(List<String> actualLiveNodes) {
+ Collections.sort(actualLiveNodes);
+ return _expectSortedLiveNodes.equals(actualLiveNodes);
+ }
+
+ /**
+ * @param externalView
+ * @param bestPossibleState map of partition to map of instance to state
+ * @return
+ */
+ boolean verifyExternalView(ExternalView externalView,
+ Map<Partition, Map<String, String>> bestPossibleState) {
+ Map<String, Map<String, String>> bestPossibleStateMap =
+ convertBestPossibleState(bestPossibleState);
+ // trimBestPossibleState(bestPossibleStateMap);
+
+ Map<String, Map<String, String>> externalViewMap = externalView.getRecord().getMapFields();
+ return externalViewMap.equals(bestPossibleStateMap);
+ }
+
+ static void runStage(ClusterEvent event, Stage stage) throws Exception {
+ StageContext context = new StageContext();
+ stage.init(context);
+ stage.preProcess();
+ stage.process(event);
+ stage.postProcess();
+ }
+
+ BestPossibleStateOutput calculateBestPossibleState(ClusterDataCache cache) throws Exception {
+ ClusterEvent event = new ClusterEvent("event");
+ event.addAttribute("ClusterDataCache", cache);
+
+ List<Stage> stages = new ArrayList<Stage>();
+ stages.add(new ResourceComputationStage());
+ stages.add(new CurrentStateComputationStage());
+ stages.add(new BestPossibleStateCalcStage());
+
+ for (Stage stage : stages) {
+ runStage(event, stage);
+ }
+
+ return event.getAttribute(AttributeName.BEST_POSSIBLE_STATE.toString());
+ }
+
+ /**
+ * remove empty map and DROPPED state from best possible state
+ * @param bestPossibleState
+ */
+ // static void trimBestPossibleState(Map<String, Map<String, String>> bestPossibleState) {
+ // Iterator<Entry<String, Map<String, String>>> iter = bestPossibleState.entrySet().iterator();
+ // while (iter.hasNext()) {
+ // Map.Entry<String, Map<String, String>> entry = iter.next();
+ // Map<String, String> instanceStateMap = entry.getValue();
+ // if (instanceStateMap.isEmpty()) {
+ // iter.remove();
+ // } else {
+ // // remove instances with DROPPED state
+ // Iterator<Map.Entry<String, String>> insIter = instanceStateMap.entrySet().iterator();
+ // while (insIter.hasNext()) {
+ // Map.Entry<String, String> insEntry = insIter.next();
+ // String state = insEntry.getValue();
+ // if (state.equalsIgnoreCase(HelixDefinedState.DROPPED.toString())) {
+ // insIter.remove();
+ // }
+ // }
+ // }
+ // }
+ // }
+
+ static Map<String, Map<String, String>> convertBestPossibleState(
+ Map<Partition, Map<String, String>> bestPossibleState) {
+ Map<String, Map<String, String>> result = new HashMap<String, Map<String, String>>();
+ for (Partition partition : bestPossibleState.keySet()) {
+ result.put(partition.getPartitionName(), bestPossibleState.get(partition));
+ }
+ return result;
+ }
+
+ @Override
+ public boolean verify() throws Exception {
+ ClusterDataCache cache = new ClusterDataCache();
+ cache.refresh(_accessor);
+
+ List<String> liveInstances = new ArrayList<String>();
+ liveInstances.addAll(cache.getLiveInstances().keySet());
+ boolean success = verifyLiveNodes(liveInstances);
+ if (!success) {
+ LOG.info("liveNodes not match, expect: " + _expectSortedLiveNodes + ", actual: "
+ + liveInstances);
+ return false;
+ }
+
+ BestPossibleStateOutput bestPossbileStates = calculateBestPossibleState(cache);
+ Map<String, ExternalView> externalViews =
+ _accessor.getChildValuesMap(_keyBuilder.externalViews());
+
+ // TODO all ideal-states should be included in external-views
+
+ for (String resourceName : externalViews.keySet()) {
+ ExternalView externalView = externalViews.get(resourceName);
+ Map<Partition, Map<String, String>> bestPossbileState =
+ bestPossbileStates.getResourceMap(resourceName);
+ success = verifyExternalView(externalView, bestPossbileState);
+ if (!success) {
+ LOG.info("external-view for resource: " + resourceName + " not match");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/f2c245f7/helix-core/src/main/java/org/apache/helix/tools/ClusterLiveNodesVerifier.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/tools/ClusterLiveNodesVerifier.java b/helix-core/src/main/java/org/apache/helix/tools/ClusterLiveNodesVerifier.java
new file mode 100644
index 0000000..2912247
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/tools/ClusterLiveNodesVerifier.java
@@ -0,0 +1,26 @@
+package org.apache.helix.tools;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.helix.manager.zk.ZkClient;
+
+public class ClusterLiveNodesVerifier extends ClusterVerifier {
+
+ final List<String> _expectSortedLiveNodes; // always sorted
+
+ public ClusterLiveNodesVerifier(ZkClient zkclient, String clusterName,
+ List<String> expectLiveNodes) {
+ super(zkclient, clusterName);
+ _expectSortedLiveNodes = expectLiveNodes;
+ Collections.sort(_expectSortedLiveNodes);
+ }
+
+ @Override
+ public boolean verify() throws Exception {
+ List<String> actualLiveNodes = _accessor.getChildNames(_keyBuilder.liveInstances());
+ Collections.sort(actualLiveNodes);
+ return _expectSortedLiveNodes.equals(actualLiveNodes);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/f2c245f7/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifier.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifier.java b/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifier.java
new file mode 100644
index 0000000..ca8eea7
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifier.java
@@ -0,0 +1,128 @@
+package org.apache.helix.tools;
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.I0Itec.zkclient.IZkChildListener;
+import org.I0Itec.zkclient.IZkDataListener;
+import org.apache.helix.HelixDataAccessor;
+import org.apache.helix.PropertyKey;
+import org.apache.helix.ZNRecord;
+import org.apache.helix.manager.zk.ZKHelixDataAccessor;
+import org.apache.helix.manager.zk.ZkBaseDataAccessor;
+import org.apache.helix.manager.zk.ZkClient;
+import org.apache.log4j.Logger;
+
+public abstract class ClusterVerifier implements IZkChildListener, IZkDataListener {
+ private static Logger LOG = Logger.getLogger(ClusterVerifier.class);
+
+ protected final ZkClient _zkclient;
+ protected final String _clusterName;
+ protected final HelixDataAccessor _accessor;
+ protected final PropertyKey.Builder _keyBuilder;
+ private CountDownLatch _countdown;
+
+ static class ClusterVerifyTrigger {
+ final PropertyKey _triggerKey;
+ final boolean _triggerOnChildDataChange;
+
+ public ClusterVerifyTrigger(PropertyKey triggerKey, boolean triggerOnChildDataChange) {
+ _triggerKey = triggerKey;
+ _triggerOnChildDataChange = triggerOnChildDataChange;
+ }
+ }
+
+ public ClusterVerifier(ZkClient zkclient, String clusterName) {
+ _zkclient = zkclient;
+ _clusterName = clusterName;
+ _accessor = new ZKHelixDataAccessor(clusterName, new ZkBaseDataAccessor<ZNRecord>(zkclient));
+ _keyBuilder = _accessor.keyBuilder();
+ }
+
+ public boolean verifyByCallback(long timeout, List<ClusterVerifyTrigger> triggers) {
+ _countdown = new CountDownLatch(1);
+
+ for (ClusterVerifyTrigger trigger : triggers) {
+ String path = trigger._triggerKey.getPath();
+ _zkclient.subscribeChildChanges(path, this);
+ if (trigger._triggerOnChildDataChange) {
+ List<String> childs = _zkclient.getChildren(path);
+ for (String child : childs) {
+ String childPath = String.format("%s/%s", path, child);
+ _zkclient.subscribeDataChanges(childPath, this);
+ }
+ }
+ }
+
+ boolean success = false;
+ try {
+ success = verify();
+ if (!success) {
+
+ success = _countdown.await(timeout, TimeUnit.MILLISECONDS);
+ if (!success) {
+ // make a final try if timeout
+ success = verify();
+ }
+ }
+ } catch (Exception e) {
+ LOG.error("Exception in verifier", e);
+ }
+
+ // clean up
+ _zkclient.unsubscribeAll();
+
+ return success;
+ }
+
+ @Override
+ public void handleDataChange(String dataPath, Object data) throws Exception {
+ boolean success = verify();
+ if (success) {
+ _countdown.countDown();
+ }
+ }
+
+ @Override
+ public void handleDataDeleted(String dataPath) throws Exception {
+ _zkclient.unsubscribeDataChanges(dataPath, this);
+ }
+
+ @Override
+ public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception {
+ for (String child : currentChilds) {
+ String childPath = String.format("%s/%s", parentPath, child);
+ _zkclient.subscribeDataChanges(childPath, this);
+ }
+
+ boolean success = verify();
+ if (success) {
+ _countdown.countDown();
+ }
+ }
+
+ public boolean verifyByPolling(long timeout) {
+ try {
+ long start = System.currentTimeMillis();
+ boolean success;
+ do {
+ success = verify();
+ if (success) {
+ return true;
+ }
+ TimeUnit.MILLISECONDS.sleep(500);
+ } while ((System.currentTimeMillis() - start) <= timeout);
+ } catch (Exception e) {
+ LOG.error("Exception in verifier", e);
+ }
+ return false;
+ }
+
+ /**
+ * verify
+ * @return
+ * @throws Exception
+ */
+ public abstract boolean verify() throws Exception;
+}
http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/f2c245f7/helix-core/src/main/java/org/apache/helix/tools/IntegrationTestUtil.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/tools/IntegrationTestUtil.java b/helix-core/src/main/java/org/apache/helix/tools/IntegrationTestUtil.java
new file mode 100644
index 0000000..8c70bbc
--- /dev/null
+++ b/helix-core/src/main/java/org/apache/helix/tools/IntegrationTestUtil.java
@@ -0,0 +1,185 @@
+package org.apache.helix.tools;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.GnuParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.OptionBuilder;
+import org.apache.commons.cli.OptionGroup;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.helix.PropertyKey;
+import org.apache.helix.ZNRecord;
+import org.apache.helix.manager.zk.ZNRecordSerializer;
+import org.apache.helix.manager.zk.ZkClient;
+import org.apache.log4j.Logger;
+
+/**
+ * collection of test utilities for integration tests
+ */
+public class IntegrationTestUtil {
+ private static Logger LOG = Logger.getLogger(IntegrationTestUtil.class);
+
+ public static final long defaultTimeout = 30 * 1000; // in milliseconds
+ public static final String help = "help";
+ public static final String zkSvr = "zkSvr";
+
+ public static final String verifyExternalView = "verifyExternalView";
+ public static final String verifyLiveNodes = "verifyLiveNodes";
+ public static final String readZNode = "readZNode";
+ public static final String readLeader = "readLeader";
+
+ final ZkClient _zkclient;
+ final ZNRecordSerializer _serializer;
+
+ public IntegrationTestUtil(ZkClient zkclient) {
+ _zkclient = zkclient;
+ _serializer = new ZNRecordSerializer();
+ }
+
+ public void verifyExternalView(String[] args) {
+ if (args == null || args.length == 0) {
+ System.err.println("Illegal arguments for " + verifyExternalView);
+ return;
+ }
+
+ long timeoutValue = defaultTimeout;
+
+ String clusterName = args[0];
+ List<String> liveNodes = new ArrayList<String>();
+ for (int i = 1; i < args.length; i++) {
+ liveNodes.add(args[i]);
+ }
+
+ ClusterExternalViewVerifier verifier =
+ new ClusterExternalViewVerifier(_zkclient, clusterName, liveNodes);
+ boolean success = verifier.verifyByPolling(timeoutValue);
+ System.out.println(success ? "Successful" : "Failed");
+
+ }
+
+ public void verifyLiveNodes(String[] args) {
+ if (args == null || args.length == 0) {
+ System.err.println("Illegal arguments for " + verifyLiveNodes);
+ return;
+ }
+
+ long timeoutValue = defaultTimeout;
+
+ String clusterName = args[0];
+ List<String> liveNodes = new ArrayList<String>();
+ for (int i = 1; i < args.length; i++) {
+ liveNodes.add(args[i]);
+ }
+
+ ClusterLiveNodesVerifier verifier =
+ new ClusterLiveNodesVerifier(_zkclient, clusterName, liveNodes);
+ boolean success = verifier.verifyByPolling(timeoutValue);
+ System.out.println(success ? "Successful" : "Failed");
+ }
+
+ public void readZNode(String path) {
+ ZNRecord record = _zkclient.readData(path, true);
+ if (record == null) {
+ System.out.println("null");
+ } else {
+ System.out.println(new String(_serializer.serialize(record)));
+ }
+ }
+
+ @SuppressWarnings("static-access")
+ static Options constructCommandLineOptions() {
+ Option helpOption =
+ OptionBuilder.withLongOpt(help).withDescription("Prints command-line options information")
+ .create();
+
+ Option zkSvrOption =
+ OptionBuilder.hasArgs(1).isRequired(true).withArgName("zookeeperAddress")
+ .withLongOpt(zkSvr).withDescription("Provide zookeeper-address").create();
+
+ Option verifyExternalViewOption =
+ OptionBuilder.hasArgs().isRequired(false).withArgName("clusterName node1 node2..")
+ .withLongOpt(verifyExternalView).withDescription("Verify external-view").create();
+
+ Option verifyLiveNodesOption =
+ OptionBuilder.hasArg().isRequired(false).withArgName("clusterName node1, node2..")
+ .withLongOpt(verifyLiveNodes).withDescription("Verify live-nodes").create();
+
+ Option readZNodeOption =
+ OptionBuilder.hasArgs(1).isRequired(false).withArgName("zkPath").withLongOpt(readZNode)
+ .withDescription("Read znode").create();
+
+ Option readLeaderOption =
+ OptionBuilder.hasArgs(1).isRequired(false).withArgName("clusterName")
+ .withLongOpt(readLeader).withDescription("Read cluster controller").create();
+
+ OptionGroup optGroup = new OptionGroup();
+ optGroup.setRequired(true);
+ optGroup.addOption(verifyExternalViewOption);
+ optGroup.addOption(verifyLiveNodesOption);
+ optGroup.addOption(readZNodeOption);
+ optGroup.addOption(readLeaderOption);
+
+ Options options = new Options();
+ options.addOption(helpOption);
+ options.addOption(zkSvrOption);
+ options.addOptionGroup(optGroup);
+
+ return options;
+ }
+
+ static void printUsage(Options cliOptions) {
+ HelpFormatter helpFormatter = new HelpFormatter();
+ helpFormatter.setWidth(1000);
+ helpFormatter.printHelp("java " + ClusterExternalViewVerifier.class.getName(), cliOptions);
+ }
+
+ static void processCommandLineArgs(String[] cliArgs) {
+ CommandLineParser cliParser = new GnuParser();
+ Options cliOptions = constructCommandLineOptions();
+ CommandLine cmd = null;
+ try {
+ cmd = cliParser.parse(cliOptions, cliArgs);
+ } catch (ParseException pe) {
+ System.err.println("failed to parse command-line args: " + Arrays.asList(cliArgs)
+ + ", exception: " + pe.toString());
+ printUsage(cliOptions);
+ System.exit(1);
+ }
+
+ String zkServer = cmd.getOptionValue(zkSvr);
+
+ ZkClient zkclient =
+ new ZkClient(zkServer, ZkClient.DEFAULT_SESSION_TIMEOUT,
+ ZkClient.DEFAULT_CONNECTION_TIMEOUT, new ZNRecordSerializer());
+ IntegrationTestUtil util = new IntegrationTestUtil(zkclient);
+
+ if (cmd != null) {
+ if (cmd.hasOption(verifyExternalView)) {
+ String[] args = cmd.getOptionValues(verifyExternalView);
+ util.verifyExternalView(args);
+ } else if (cmd.hasOption(verifyLiveNodes)) {
+ String[] args = cmd.getOptionValues(verifyLiveNodes);
+ util.verifyLiveNodes(args);
+ } else if (cmd.hasOption(readZNode)) {
+ String path = cmd.getOptionValue(readZNode);
+ util.readZNode(path);
+ } else if (cmd.hasOption(readLeader)) {
+ String clusterName = cmd.getOptionValue(readLeader);
+ PropertyKey.Builder keyBuilder = new PropertyKey.Builder(clusterName);
+ util.readZNode(keyBuilder.controllerLeader().getPath());
+ } else {
+ printUsage(cliOptions);
+ }
+ }
+ }
+
+ public static void main(String[] args) {
+ processCommandLineArgs(args);
+ }
+}