/** * Licensed to Cloudera, Inc. under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. Cloudera, Inc. licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.cloudera.flume.util; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.Map.Entry; import jline.Completor; import jline.ConsoleReader; import org.antlr.runtime.RecognitionException; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; import org.apache.thrift.TException; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.protocol.TProtocol; import org.apache.thrift.transport.TSocket; import org.apache.thrift.transport.TTransport; import org.apache.thrift.transport.TTransportException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.cloudera.flume.VersionInfo; import com.cloudera.flume.conf.FlumeConfigData; import com.cloudera.flume.conf.FlumeConfiguration; import com.cloudera.flume.master.Command; import com.cloudera.flume.master.CommandStatus; import com.cloudera.flume.master.StatusManager; import com.cloudera.flume.reporter.server.thrift.ThriftFlumeReport; import com.cloudera.flume.reporter.server.thrift.ThriftFlumeReportServer; import com.cloudera.flume.shell.CommandBuilder; import com.cloudera.util.CheckJavaVersion; /** * The FlumeShell is a command-line-interface for a Flume master. * * TODO (jon) move to com.cloudera.flume.shell */ public class FlumeShell { private static final Logger LOG = LoggerFactory.getLogger(FlumeShell.class); // Sort on command name protected static final Map<String, CommandDescription> commandMap = new TreeMap<String, CommandDescription>(); protected boolean printPrompt = true; protected boolean done = false; protected long lastCmdId = 0; static final int POLL_DELAY_MS = 500; /** * Controls whether command prompt is shown */ public FlumeShell(boolean printPrompt) { this.printPrompt = printPrompt; } /** * Default constructor - command prompt on */ public FlumeShell() { this(true); } /** * Super simple class to aggregate some command metadata. */ static class CommandDescription { final String usage; final boolean needsCnxn; final int arity; CommandDescription(String usage, boolean needsCnxn, int minArity) { this.usage = usage; this.needsCnxn = needsCnxn; this.arity = minArity; } } static { commandMap.put("connect", new CommandDescription("host[:adminport=" + FlumeConfiguration.get().getConfigAdminPort() + "[:reportport=" + FlumeConfiguration.get().getConfigReportPort() + "]]", false, 1)); commandMap.put("getnodestatus", new CommandDescription("", true, 0)); commandMap.put("quit", new CommandDescription("", false, 0)); commandMap.put("getconfigs", new CommandDescription("", true, 0)); commandMap.put("getmappings", new CommandDescription("[physical node]", true, 0)); commandMap.put("source", new CommandDescription( "load a file and execute flume shell commands in it", false, 1)); commandMap.put("help", new CommandDescription("", false, 0)); // TODO (jon) hide this or format it better in help commandMap.put("exec", new CommandDescription( " (requires a command and arguments)", true, 1)); commandMap.put("submit", new CommandDescription( " (requires a command and arguments)", true, 1)); commandMap.put("wait", new CommandDescription( " [maxmillis (0==infinite) [, cmdid]]", true, 0)); commandMap.put("waitForNodesDone", new CommandDescription( " [maxmillis (0==infinite) [, node[, ...]]]", true, 2)); commandMap.put("waitForNodesActive", new CommandDescription( " [maxmillis (0==infinite) [, node[, ...]]]", true, 2)); // These actually work well and autocomplete the way we want! commandMap.put("exec config", new CommandDescription( "node 'source' 'sink'", true, 1)); commandMap.put("exec multiconfig", new CommandDescription("'spec'", true, 1)); commandMap.put("exec refresh", new CommandDescription("'spec'", true, 1)); commandMap.put("exec refreshAll", new CommandDescription("", true, 1)); commandMap.put("exec noop", new CommandDescription( "[delaymillis (no arg means no wait)]", true, 1)); commandMap.put("exec spawn", new CommandDescription( "physicalnode logicalnode (synonym for exec map. deprecated.)", true, 3)); commandMap.put("exec map", new CommandDescription( "physicalnode logicalnode", true, 3)); commandMap.put("exec decommission", new CommandDescription("logicalnode", true, 2)); commandMap.put("exec unmap", new CommandDescription( "physicalnode logicalnode", true, 3)); commandMap.put("exec unmapAll", new CommandDescription("", true, 1)); // TODO(Vibhor): Change this when we give the user ability to change the // physicalNode throttling limit. commandMap.put("exec setChokeLimit", new CommandDescription( "physicalnode chokeid limit", true, 3)); // These actually work well and autocomplete the way we want! commandMap.put("submit config", new CommandDescription( "node 'source' 'sink'", true, 1)); commandMap.put("submit multiconfig", new CommandDescription("'spec'", true, 1)); commandMap.put("submit refresh", new CommandDescription("'spec'", true, 1)); commandMap.put("submit refreshAll", new CommandDescription("", true, 1)); commandMap.put("submit noop", new CommandDescription("", true, 1)); commandMap.put("submit spawn", new CommandDescription( "physicalnode logicalnode (synonym for submit map. deprecated.)", true, 3)); commandMap.put("submit map", new CommandDescription( "physicalnode logicalnode", true, 3)); commandMap.put("submit decommission", new CommandDescription("logicalnode", true, 2)); commandMap.put("submit unmap", new CommandDescription( "physicalnode logicalnode", true, 3)); commandMap.put("submit unmapAll", new CommandDescription("", true, 1)); commandMap.put("getreports", new CommandDescription("", true, 0)); } protected AdminRPC client = null; protected ThriftFlumeReportServer.Client reportClient = null; public static final long CMD_WAIT_TIME_MS = 10 * 1000; protected static class FlumeCompletor implements Completor { @SuppressWarnings("unchecked") // :( @Override public int complete(String buffer, int cursor, List candidates) { for (String s : commandMap.keySet()) { if (s.startsWith(buffer)) { candidates.add(s); } } return 0; } } protected static class ShellCommand { protected String command; final protected List<String> args; public String getCommand() { return command; } public List<String> getArgs() { return Collections.unmodifiableList(args); } public ShellCommand(Command c) { this.command = c.getCommand(); this.args = Arrays.asList(c.getArgs()); } public ShellCommand(String line) throws RecognitionException { this(CommandBuilder.parseLine(line)); } } protected boolean connected = false; protected String curhost = ""; protected int curAPort = 0; protected int curRPort = 0; protected void disconnect() { System.out.println("Disconnected!"); connected = false; } protected void printHello() { System.out.println("=================================================="); System.out.println("FlumeShell v" + VersionInfo.getVersion()); System.out.println("Copyright (c) Cloudera 2010, All Rights Reserved"); System.out.println("=================================================="); System.out.println("Type a command to execute (hint: many commands"); System.out.println("only work when you are connected to a master node)"); System.out.println(""); System.out.println("You may connect to a master node by typing: "); System.out.println(" connect host[:adminport=" + FlumeConfiguration.get().getConfigAdminPort() + "[:reportport=" + FlumeConfiguration.get().getConfigReportPort() + "]]"); System.out.println(""); } protected void printHelp() { System.out.println("I know about these commands:"); System.out.println(""); for (Entry<String, CommandDescription> e : commandMap.entrySet()) { System.out.println(" " + e.getKey() + " " + e.getValue().usage); } } /** * This waits for a command cmdid for at most maxmillis to reach SUCCESS or * FAIL state. Returns -1 if timed out, returns 0 on sucess. */ protected long pollWait(long cmdid, long maxmillis) throws IOException, InterruptedException { if (!client.hasCmdId(cmdid)) { System.out.println("Command id " + cmdid + " does not exist"); return -1; } long start = System.currentTimeMillis(); while (System.currentTimeMillis() - start < maxmillis) { if (client.isFailure(cmdid)) { System.err.println("Command failed"); CommandStatus stat = client.getCommandStatus(cmdid); System.err.println(stat.getMessage()); return -1; } if (client.isSuccess(cmdid)) { System.out.println("Command succeeded"); // TODO (jon) get the commands history message and display it. return 0; } Thread.sleep(POLL_DELAY_MS); } System.err.println("Command timed out"); return -1; } boolean isDone(StatusManager.NodeStatus status) { StatusManager.NodeState state = status.state; switch (state) { case IDLE: case ERROR: case LOST: case DECOMMISSIONED: // if at version 0, do not return true for isDone. (nothing has happened!) return status.version != 0; case ACTIVE: case CONFIGURING: case HELLO: default: return false; } } /** * This waits for at most maxmillis for all nodes to reach IDLE or ERROR state */ protected long pollNodesDone(List<String> nodes, long maxmillis) throws InterruptedException { long start = System.currentTimeMillis(); while (System.currentTimeMillis() - start < maxmillis) { Map<String, StatusManager.NodeStatus> nodemap; try { nodemap = client.getNodeStatuses(); } catch (IOException e) { LOG.debug("Disconnected!", e); disconnect(); return -1; } boolean busy = false; for (String n : nodes) { StatusManager.NodeStatus stat = nodemap.get(n); if (stat == null) { busy = true; break; } if (!isDone(nodemap.get(n))) { busy = true; break; } } if (!busy) { System.out.println("Nodes are done (in IDLE or in ERROR state)"); return 0; } // busy Thread.sleep(500); } System.out.println("Command timed out"); disconnect(); return -1; } boolean isActive(StatusManager.NodeStatus status) { StatusManager.NodeState state = status.state; switch (state) { case ACTIVE: case CONFIGURING: return status.version != 0; case IDLE: case ERROR: case HELLO: case LOST: default: return false; } } /** * This checks to see if all the nodes in the specified list are in ACTIVE or * CONFIGURING state. This is fragile and temporary and should not be publicly * user exposed. * * Really what I want is a mechanism to track state transitions. */ protected long pollNodesActive(List<String> nodes, long maxmillis) throws InterruptedException { long start = System.currentTimeMillis(); while (System.currentTimeMillis() - start < maxmillis) { Map<String, StatusManager.NodeStatus> nodemap; try { nodemap = client.getNodeStatuses(); } catch (IOException e) { LOG.debug("Disconnected! " + e.getMessage(), e); System.out.println("Disconnected! " + e.getMessage()); disconnect(); return -1; } // this isn't completely reliable yet -- it should be used with care. boolean ready = true; for (String n : nodes) { StatusManager.NodeStatus stat = nodemap.get(n); if (stat == null) { ready = false; break; } if (!isActive(stat)) { ready = false; break; } } if (ready) { System.out.println("Nodes are active (in ACTIVE or CONFIGURING state)"); return 0; } // busy Thread.sleep(500); } System.out.println("Command timed out"); disconnect(); return -1; } /** * Exec the specified filename. This command is called "source" like in bash/c * shells */ long execFile(String filename) { FileReader f = null; try { f = new FileReader(filename); } catch (IOException e) { System.out.println("unable to source file " + filename + ": " + e.getMessage()); return -1; } BufferedReader in = new BufferedReader(f); String str; long lastret = 0; long lineno = 0; try { while ((str = in.readLine()) != null) { lineno++; lastret = executeLine(str); } return lastret; } catch (IOException ioe) { System.out.println("Problem reading line " + filename + ":" + lineno + " : " + ioe.getMessage()); return -1; } finally { try { in.close(); f.close(); } catch (IOException e) { LOG.error("Unable to close " + f); } } } private static int parsePort(String inp, int defaultPort) { int port = -1; try { port = Integer.parseInt(inp); } catch (NumberFormatException nfe) { System.out.println("Cannot parse port number '" + inp + "', defaulting to " + defaultPort); return defaultPort; } if (port < 0 || port > (0xffff)) { System.out.println("Port number out of range: " + port + ", defaulting to " + defaultPort); return defaultPort; } return port; } private static int parseAdminPort(String arg) { // determine the admin port int aPortDefault = FlumeConfiguration.get().getConfigAdminPort(); int aPort; if (arg != null) { aPort = parsePort(arg, aPortDefault); } else { aPort = aPortDefault; System.out.println("Using default admin port: " + aPort); } return aPort; } private static int parseReportPort(String arg) { // determine the report server port int rPortDefault = FlumeConfiguration.get().getConfigReportPort(); int rPort; if (arg != null) { rPort = parsePort(arg, rPortDefault); } else { rPort = rPortDefault; System.out.println("Using default report port: " + rPort); } return rPort; } /** * This either returns 0 for success, a value <0 for failure, and any return * >0 is a command id received from the master. * * Unexpected failures that go over the network should disconnect before * returning. (This is useful to "nullify" other commands if an error has * occurred) */ protected long execCommand(ShellCommand cmd) { if (!commandMap.containsKey(cmd.getCommand())) { System.out.println("Unknown command"); return -1; } CommandDescription cd = commandMap.get(cmd.getCommand()); // Run a few guard checks to see if we can execute command if (cmd.getArgs().size() < cd.arity) { System.out.println("Must supply at least " + cd.arity + " arguments"); return -1; } if (cd.needsCnxn && !connected) { System.out.println("Not connected"); return -1; } // Exhaustive exit the shell. if (cmd.getCommand().equals("quit")) { disconnect(); done = true; return 0; } // 'source' or exec the lines from a specified file. if (cmd.getCommand().equals("source")) { return execFile(cmd.getArgs().get(0)); } if (cmd.getCommand().equals("getnodestatus")) { Map<String, StatusManager.NodeStatus> nodemap; try { nodemap = client.getNodeStatuses(); } catch (IOException e) { LOG.debug("Disconnected!", e); disconnect(); return -1; } System.out.println("Master knows about " + nodemap.size() + " nodes"); for (Entry<String, StatusManager.NodeStatus> e : nodemap.entrySet()) { System.out.println("\t" + e.getKey() + " --> " + e.getValue().state.toString()); } return 0; } if (cmd.getCommand().equals("getreports")) { Map<String, ThriftFlumeReport> reports; try { reports = reportClient.getAllReports(); } catch (TException e) { LOG.debug("Disconnected!", e); disconnect(); return -1; } System.out.println("Master knows about " + reports.size() + " reports"); for (Entry<String, ThriftFlumeReport> e : reports.entrySet()) { System.out.println("\t" + e.getKey() + " --> " + e.getValue().toString()); } return 0; } if (cmd.getCommand().equals("getmappings")) { Map<String, List<String>> mappings; String physicalNode = null; String forPhysicalMessage = ""; if (cmd.args.size() > 0) { physicalNode = cmd.args.get(0); forPhysicalMessage = " for physical node " + physicalNode; } try { mappings = client.getMappings(physicalNode); } catch (IOException e) { LOG.debug("Disconnected!", e); disconnect(); return -1; } String header = String.format("%s\n\n%-30s --> %s\n", "Master has the following mappings" + forPhysicalMessage, "Physical Node", "Logical Node(s)"); if (mappings.size() > 0) { System.out.println(header); for (Entry<String, List<String>> entry : mappings.entrySet()) { System.out.println(String.format("%-30s --> %s", entry.getKey(), entry.getValue())); } } else { System.out.println("No physical / logic node mappings" + forPhysicalMessage + ". Use spawn to map a logical node to a physical node."); } return 0; } // Waits until the list of specified nodes are either in IDLE or in ERROR // state if (cmd.getCommand().equals("waitForNodesDone")) { Long maxmillis = Long.parseLong(cmd.getArgs().get(0)); List<String> nodes = cmd.getArgs().subList(1, cmd.getArgs().size()); try { maxmillis = (maxmillis <= 0) ? Long.MAX_VALUE : maxmillis; System.out.println("Waiting for " + maxmillis + " ms for nodes " + nodes + " to be IDLE/ERROR/LOST"); pollNodesDone(nodes, maxmillis); } catch (InterruptedException e) { System.out.println("Interrupted during command processing"); LOG.debug("Interrupted!", e); return -1; } } // Waits until the list of specified nodes are either in ACTIVE or // CONFIGURING state if (cmd.getCommand().equals("waitForNodesActive")) { Long maxmillis = Long.parseLong(cmd.getArgs().get(0)); List<String> nodes = cmd.getArgs().subList(1, cmd.getArgs().size()); try { maxmillis = (maxmillis <= 0) ? Long.MAX_VALUE : maxmillis; System.out.println("Waiting for " + maxmillis + " ms for nodes " + nodes + " to be ACTIVE"); pollNodesActive(nodes, maxmillis); } catch (InterruptedException e) { System.out.println("Interrupted during command processing"); LOG.debug("Interrupted!", e); return -1; } } if (cmd.getCommand().equals("connect")) { List<String> servers = new ArrayList<String>(Arrays.asList(cmd.getArgs() .get(0).split(","))); for (String s : servers) { String[] parts = s.split(":"); try { // determine the admin port int aPort = parseAdminPort(parts.length >= 2 ? parts[1] : null); // determine the report server port int rPort = parseReportPort(parts.length >= 3 ? parts[2] : null); try { connect(parts[0], aPort, rPort); } catch (IOException e) { System.out.println("Connection to " + s + " failed"); LOG.debug("Connection to " + s + " failed", e); } return 0; } catch (TTransportException t) { System.out.println("Connection to " + s + " failed"); LOG.debug("Connection to " + s + " failed", t); } return -1; } return 0; } /* * Submit sends a command to the master and returns its cmdid. This allows * for asynchronous issuing of commands. */ if (cmd.getCommand().equals("submit")) { try { List<String> args = new ArrayList<String>(); if (cmd.getArgs().size() > 1) { args = cmd.getArgs().subList(1, cmd.getArgs().size()); } long cmdid = client.submit(new Command(cmd.getArgs().get(0), (String[]) args.toArray(new String[args.size()]))); lastCmdId = cmdid; // Do not change this, other programs will likely depend on this. System.out.println("[id: " + cmdid + "] Submitted command : " + cmd.getArgs().get(0)); return cmdid; } catch (IOException e) { disconnect(); LOG.debug("config failed due to transport error", e); return -1; } } /* * Wait waits for the specified cmdid to be done (success or error), for a * specified amount of time. If no cmdid is specified, it is assumed to be * the last command issued by the shell, or the last command in the master's * command queue. * * 0 wait time means forever. */ if (cmd.getCommand().equals("wait")) { long millis = CMD_WAIT_TIME_MS; long cmdid = lastCmdId; // args are time, and then cmdid. List<String> args = cmd.getArgs(); if (args.size() >= 1) { long ms = Long.parseLong(args.get(0)); if (ms < 0) { System.out.println("Wait time <0 is illegal"); return -1; } // if 0, effectively wait forever. millis = (ms == 0) ? Long.MAX_VALUE : ms; } if (args.size() >= 2) { cmdid = Long.parseLong(args.get(1)); } try { return pollWait(cmdid, millis); } catch (IOException e) { disconnect(); LOG.debug("config failed due to transport error", e); return -1; } catch (InterruptedException e) { System.out.println("Interrupted during command processing"); LOG.debug("Interrupted!", e); return -1; } } /* * Exec sends a command to the master and polls for a response. These are * the commands which cause the master to do some processing. We wait * synchronously for success or failure. * * There is no schema checking for these commands - so it is possible to * send ill-formed commands and receive a failure notification with no idea * of what went wrong. */ if (cmd.getCommand().equals("exec")) { try { List<String> args = new ArrayList<String>(); if (cmd.getArgs().size() > 1) { args = cmd.getArgs().subList(1, cmd.getArgs().size()); } long cmdid = client.submit(new Command(cmd.getArgs().get(0), (String[]) args.toArray(new String[args.size()]))); System.out.println("[id: " + cmdid + "] Execing command : " + cmd.getArgs().get(0)); lastCmdId = cmdid; return pollWait(cmdid, CMD_WAIT_TIME_MS); } catch (IOException e) { disconnect(); LOG.debug("config failed due to transport error", e); return -1; } catch (InterruptedException e) { System.out.println("Interrupted during command processing"); LOG.debug("Interrupted!", e); return -1; } } if (cmd.getCommand().equals("getconfigs")) { try { Map<String, FlumeConfigData> configs = client.getConfigs(); if (configs.size() == 0) { System.out.println("Master has no logical node configurations."); return 0; } int maxnode = 0, maxsink = 0, maxsource = 0, maxflow = 0; for (Entry<String, FlumeConfigData> e : configs.entrySet()) { maxnode = java.lang.Math.max(maxnode, e.getKey().length()); maxsink = java.lang.Math.max(maxsink, e.getValue().sinkConfig .length()); maxsource = java.lang.Math.max(maxsource, e.getValue().sourceConfig .length()); maxflow = java.lang.Math.max(maxflow, e.getValue().getFlowID() .length()); } String title = String.format("%-" + maxnode + "s\t%-" + maxflow + "s\t%-" + maxsource + "s\t%-" + maxsink + "s", "NODE", "FLOW", "SOURCE", "SINK"); System.out.println(title); for (Entry<String, FlumeConfigData> e : configs.entrySet()) { String line = String.format("%-" + maxnode + "s\t%-" + maxflow + "s\t%-" + maxsource + "s\t%-" + maxsink + "s", e.getKey(), e .getValue().getFlowID(), e.getValue().sourceConfig, e.getValue().sinkConfig); System.out.println(line); } } catch (IOException e) { disconnect(); LOG.error("getconfigs failed due to transport error"); return -1; } return 0; } if (cmd.getCommand().equals("help")) { printHelp(); return 0; } return -1; } /** * Executes a command specified by a string * * Made public to be testable. */ public long executeLine(String line) { // do nothing if no line, empty line or comment if (line == null) { return 0; } // trim white space and and then check line = line.trim(); if (line.equals("") || line.startsWith("#")) { return 0; } try { ShellCommand cmd = new ShellCommand(line); return execCommand(cmd); } catch (Exception e) { System.out.println("Failed to run command '" + line + "' due to " + e.getMessage()); LOG.error("Failed to run command '" + line + "'"); return -1; } } protected String getPrompt() { if (!printPrompt) { return ""; } return "[flume " + (connected ? (curhost + ":" + curAPort + ":" + curRPort) : "(disconnected)") + "] "; } private ThriftFlumeReportServer.Client connectReportClient(String host, int port) throws TTransportException { TTransport masterTransport = new TSocket(host, port); TProtocol protocol = new TBinaryProtocol(masterTransport); masterTransport.open(); return new ThriftFlumeReportServer.Client(protocol); } protected void connect(String host, int aPort, int rPort) throws IOException, TTransportException { connected = false; System.out.println("Connecting to Flume master " + host + ":" + aPort + ":" + rPort + "..."); String rpcType = FlumeConfiguration.get().getMasterHeartbeatRPC(); if (FlumeConfiguration.RPC_TYPE_AVRO.equals(rpcType)) { client = new AdminRPCAvro(host, aPort); } else if (FlumeConfiguration.RPC_TYPE_THRIFT.equals(rpcType)) { client = new AdminRPCThrift(host, aPort); } else { throw new IOException("No valid RPC framework specified in config"); } // use default for now reportClient = connectReportClient(host, rPort); curhost = host; curAPort = aPort; curRPort = rPort; connected = true; } public void run() throws IOException, TTransportException { ConsoleReader cReader = new ConsoleReader(); cReader.addCompletor(new FlumeCompletor()); String line; while (!done && (line = cReader.readLine(getPrompt())) != null) { try { executeLine(line); } catch (RuntimeException r) { System.out.println("RuntimeException caught: " + r.getMessage()); } } } /** * Args are optional - the first arg is the host:port for the master to * connect to */ public static void main(String[] args) throws IOException, TTransportException { // Make sure the Java version is not older than 1.6 if (!CheckJavaVersion.isVersionOk()) { LOG .error("Exiting because of an old Java version or Java version in bad format"); System.exit(-1); } CommandLine cmd = null; Options options = new Options(); options.addOption("?", false, "Command line usage"); options.addOption("c", true, "Connect to master:adminport:reportport"); options.addOption("e", true, "Run a single command"); options.addOption("s", true, "Run a FlumeShell script"); options.addOption("q", false, "Run in quiet mode - only print command results"); try { CommandLineParser parser = new PosixParser(); cmd = parser.parse(options, args); } catch (ParseException e) { HelpFormatter fmt = new HelpFormatter(); fmt.printHelp("FlumeShell", options, true); System.exit(-1); } if (cmd.hasOption('?')) { HelpFormatter fmt = new HelpFormatter(); fmt.printHelp("FlumeShell", options, true); System.exit(0); } boolean print = true; if (cmd.hasOption('q')) { print = false; } FlumeShell shell = new FlumeShell(print); if (cmd.hasOption("c")) { String[] addr = cmd.getOptionValue("c").split(":"); // determine the admin port int aPort = parseAdminPort(addr.length >= 2 ? addr[1] : null); // determine the report server port int rPort = parseReportPort(addr.length >= 3 ? addr[2] : null); shell.connect(addr[0], aPort, rPort); } if (cmd.hasOption("e")) { long ret = shell.executeLine(cmd.getOptionValue("e")); // return error code if negative, otherwise return 0. System.exit(ret < 0 ? (int) ret : 0); } if (cmd.hasOption("s")) { FileReader f = null; try { f = new FileReader(cmd.getOptionValue('s')); } catch (IOException e) { System.err.println("Failed to open script: " + cmd.getOptionValue('s')); System.err.println("Exception was: " + e.getMessage()); System.exit(1); } BufferedReader in = new BufferedReader(f); String str; while ((str = in.readLine()) != null) { shell.executeLine(str); } System.exit(0); } if (!cmd.hasOption('q')) { shell.printHello(); } shell.run(); } }