/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF 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 gobblin.cli; import java.util.Arrays; import java.util.Collection; import java.util.Map; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import com.google.common.collect.ImmutableMap; /** * A command line interface for interacting with Gobblin. * From this tool, you should be able to: * * Check the status of Gobblin jobs * * View ... * * @author ahollenbach@nerdwallet.com */ public class Cli { private static final Map<String, Command> commandList = ImmutableMap.of( "jobs", (Command)new JobCommand() ); static class GlobalOptions { private final String adminServerHost; private final int adminServerPort; public GlobalOptions(String adminServerHost, int adminServerPort) { this.adminServerHost = adminServerHost; this.adminServerPort = adminServerPort; } public String getAdminServerHost() { return adminServerHost; } public int getAdminServerPort() { return adminServerPort; } } /** * Get the list of valid command names * @return List of command names */ public static Collection<String> getCommandNames() { return commandList.keySet(); } // Option long codes private static final String HOST_OPT = "host"; private static final String PORT_OPT = "port"; private static final String DEFAULT_REST_SERVER_HOST = "localhost"; private static final int DEFAULT_REST_SERVER_PORT = 8080; private String[] args; private Options options; public static void main(String[] args) { Cli cli = new Cli(args); cli.parseAndExecuteCommand(); } /** * Create a new Cli object. * @param args Command line arguments */ public Cli(String[] args) { this.args = args; this.options = new Options(); this.options.addOption("H", HOST_OPT, true, "Specify host (default:" + DEFAULT_REST_SERVER_HOST + ")"); this.options.addOption("P", PORT_OPT, true, "Specify port (default:" + DEFAULT_REST_SERVER_PORT + ")"); } /** * Parse and execute the appropriate command based on the args. * The general flow looks like this: * * 1. Parse a set of global options (eg host/port for the admin server) * 2. Parse out the command name * 3. Pass the global options and any left over parameters to a command handler */ public void parseAndExecuteCommand() { CommandLineParser parser = new DefaultParser(); try { CommandLine parsedOpts = parser.parse(this.options, this.args, true); GlobalOptions globalOptions = createGlobalOptions(parsedOpts); // Fetch the command and fail if there is ambiguity String[] remainingArgs = parsedOpts.getArgs(); if (remainingArgs.length == 0) { printHelpAndExit("Command not specified!"); } String commandName = remainingArgs[0].toLowerCase(); remainingArgs = remainingArgs.length > 1 ? Arrays.copyOfRange(remainingArgs, 1, remainingArgs.length) : new String[]{}; Command command = commandList.get(commandName); if (command == null) { System.out.println("Command " + commandName + " not known."); printHelpAndExit(); } else { command.execute(globalOptions, remainingArgs); } } catch (ParseException e) { printHelpAndExit("Ran into an error parsing args."); } } /** * Build the GlobalOptions information from the raw parsed options * @param parsedOpts Options parsed from the cmd line * @return */ private GlobalOptions createGlobalOptions(CommandLine parsedOpts) { String host = parsedOpts.hasOption(HOST_OPT) ? parsedOpts.getOptionValue(HOST_OPT) : DEFAULT_REST_SERVER_HOST; int port = DEFAULT_REST_SERVER_PORT; try { if (parsedOpts.hasOption(PORT_OPT)) { port = Integer.parseInt(parsedOpts.getOptionValue(PORT_OPT)); } } catch (NumberFormatException e) { printHelpAndExit("The port must be a valid integer."); } return new GlobalOptions(host, port); } /** * Print help and exit with a success code (0). */ private void printHelpAndExit() { System.out.println("Common usages:"); System.out.println(" gobblin-admin.sh jobs --list"); System.out.println(" gobblin-admin.sh jobs --list --name JobName"); System.out.println(" gobblin-admin.sh jobs --details --id job_id"); System.out.println(" gobblin-admin.sh jobs --properties --<id|name> <job_id|JobName>"); System.out.println(); printHelpAndExit(0); } /** * Prints an error message, then prints the help and exits with an error code. */ private void printHelpAndExit(String errorMessage) { System.err.println(errorMessage); printHelpAndExit(1); } /** * Print help and exit with the specified code. * @param exitCode The code to exit with */ private void printHelpAndExit(int exitCode) { HelpFormatter hf = new HelpFormatter(); hf.printHelp("gobblin-admin.sh <command> [options]", this.options); System.out.println("Valid commands:"); for (String command : getCommandNames()) { System.out.println(command); } System.exit(exitCode); } }