/** * 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 org.apache.hadoop.hive.llap.cli; import com.google.common.base.Preconditions; import jline.TerminalFactory; import java.io.IOException; import java.util.Properties; import javax.annotation.Nonnull; 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.Options; import org.apache.commons.cli.ParseException; import org.apache.hadoop.hive.conf.HiveConf; import org.apache.hadoop.hive.llap.log.LogHelpers; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.hadoop.util.StringUtils; public class LlapOptionsProcessor { public static final String OPTION_INSTANCES = "instances"; //forward as arg public static final String OPTION_NAME = "name"; // forward as arg public static final String OPTION_DIRECTORY = "directory"; // work-dir public static final String OPTION_EXECUTORS = "executors"; // llap-daemon-site public static final String OPTION_CACHE = "cache"; // llap-daemon-site public static final String OPTION_SIZE = "size"; // forward via config.json public static final String OPTION_XMX = "xmx"; // forward as arg public static final String OPTION_AUXJARS = "auxjars"; // used to localize jars public static final String OPTION_AUXHIVE = "auxhive"; // used to localize jars public static final String OPTION_AUXHBASE = "auxhbase"; // used to localize jars public static final String OPTION_JAVA_HOME = "javaHome"; // forward via config.json public static final String OPTION_HIVECONF = "hiveconf"; // llap-daemon-site if relevant parameter public static final String OPTION_SLIDER_AM_CONTAINER_MB = "slider-am-container-mb"; // forward as arg public static final String OPTION_SLIDER_APPCONFIG_GLOBAL = "slider-appconfig-global"; // forward as arg public static final String OPTION_LLAP_QUEUE = "queue"; // forward via config.json public static final String OPTION_IO_THREADS = "iothreads"; // llap-daemon-site // Options for the python script that are here because our option parser cannot ignore the unknown ones public static final String OPTION_ARGS = "args"; // forward as arg public static final String OPTION_LOGLEVEL = "loglevel"; // forward as arg public static final String OPTION_LOGGER = "logger"; // forward as arg public static final String OPTION_CHAOS_MONKEY = "chaosmonkey"; // forward as arg public static final String OPTION_SLIDER_KEYTAB_DIR = "slider-keytab-dir"; public static final String OPTION_SLIDER_KEYTAB = "slider-keytab"; public static final String OPTION_SLIDER_PRINCIPAL = "slider-principal"; public static final String OPTION_SLIDER_PLACEMENT = "slider-placement"; public static final String OPTION_SLIDER_DEFAULT_KEYTAB = "slider-default-keytab"; public static final String OPTION_OUTPUT_DIR = "output"; public static final String OPTION_START = "startImmediately"; public static class LlapOptions { private final int instances; private final String directory; private final String name; private final int executors; private final int ioThreads; private final long cache; private final long size; private final long xmx; private final String jars; private final boolean isHbase; private final Properties conf; private final String javaPath; private final String llapQueueName; private final String logger; private final boolean isStarting; private final String output; private final boolean isHiveAux; public LlapOptions(String name, int instances, String directory, int executors, int ioThreads, long cache, long size, long xmx, String jars, boolean isHbase, @Nonnull Properties hiveconf, String javaPath, String llapQueueName, String logger, boolean isStarting, String output, boolean isHiveAux) throws ParseException { if (instances <= 0) { throw new ParseException("Invalid configuration: " + instances + " (should be greater than 0)"); } this.instances = instances; this.directory = directory; this.name = name; this.executors = executors; this.ioThreads = ioThreads; this.cache = cache; this.size = size; this.xmx = xmx; this.jars = jars; this.isHbase = isHbase; this.isHiveAux = isHiveAux; this.conf = hiveconf; this.javaPath = javaPath; this.llapQueueName = llapQueueName; this.logger = logger; this.isStarting = isStarting; this.output = output; } public String getOutput() { return output; } public String getName() { return name; } public int getInstances() { return instances; } public String getDirectory() { return directory; } public int getExecutors() { return executors; } public int getIoThreads() { return ioThreads; } public long getCache() { return cache; } public long getSize() { return size; } public long getXmx() { return xmx; } public String getAuxJars() { return jars; } public boolean getIsHBase() { return isHbase; } public boolean getIsHiveAux() { return isHiveAux; } public Properties getConfig() { return conf; } public String getJavaPath() { return javaPath; } public String getLlapQueueName() { return llapQueueName; } public String getLogger() { return logger; } public boolean isStarting() { return isStarting; } } protected static final Logger l4j = LoggerFactory.getLogger(LlapOptionsProcessor.class.getName()); private final Options options = new Options(); private org.apache.commons.cli.CommandLine commandLine; @SuppressWarnings("static-access") public LlapOptionsProcessor() { // set the number of instances on which llap should run options.addOption(OptionBuilder.hasArg().withArgName(OPTION_INSTANCES).withLongOpt(OPTION_INSTANCES) .withDescription("Specify the number of instances to run this on").create('i')); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_NAME).withLongOpt(OPTION_NAME) .withDescription("Cluster name for YARN registry").create('n')); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_DIRECTORY).withLongOpt(OPTION_DIRECTORY) .withDescription("Temp directory for jars etc.").create('d')); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_ARGS).withLongOpt(OPTION_ARGS) .withDescription("java arguments to the llap instance").create('a')); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_LOGLEVEL).withLongOpt(OPTION_LOGLEVEL) .withDescription("log levels for the llap instance").create('l')); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_LOGGER).withLongOpt(OPTION_LOGGER) .withDescription( "logger for llap instance ([" + LogHelpers.LLAP_LOGGER_NAME_RFA + "], " + LogHelpers.LLAP_LOGGER_NAME_QUERY_ROUTING + ", " + LogHelpers.LLAP_LOGGER_NAME_CONSOLE) .create()); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_CHAOS_MONKEY).withLongOpt(OPTION_CHAOS_MONKEY) .withDescription("chaosmonkey interval").create('m')); options.addOption(OptionBuilder.hasArg(false).withArgName(OPTION_SLIDER_DEFAULT_KEYTAB).withLongOpt(OPTION_SLIDER_DEFAULT_KEYTAB) .withDescription("try to set default settings for Slider AM keytab; mostly for dev testing").create()); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_SLIDER_KEYTAB_DIR).withLongOpt(OPTION_SLIDER_KEYTAB_DIR) .withDescription("Slider AM keytab directory on HDFS (where the headless user keytab is stored by Slider keytab installation, e.g. .slider/keytabs/llap)").create()); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_SLIDER_KEYTAB).withLongOpt(OPTION_SLIDER_KEYTAB) .withDescription("Slider AM keytab file name inside " + OPTION_SLIDER_KEYTAB_DIR).create()); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_SLIDER_PRINCIPAL).withLongOpt(OPTION_SLIDER_PRINCIPAL) .withDescription("Slider AM principal; should be the user running the cluster, e.g. hive@EXAMPLE.COM").create()); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_SLIDER_PLACEMENT).withLongOpt(OPTION_SLIDER_PLACEMENT) .withDescription("Slider placement policy; see slider documentation at https://slider.incubator.apache.org/docs/placement.html." + " 4 means anti-affinity (the default; unnecessary if LLAP is going to take more than half of the YARN capacity of a node), 0 is normal.").create()); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_EXECUTORS).withLongOpt(OPTION_EXECUTORS) .withDescription("executor per instance").create('e')); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_CACHE).withLongOpt(OPTION_CACHE) .withDescription("cache size per instance").create('c')); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_SIZE).withLongOpt(OPTION_SIZE) .withDescription("container size per instance").create('s')); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_XMX).withLongOpt(OPTION_XMX) .withDescription("working memory size").create('w')); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_LLAP_QUEUE) .withLongOpt(OPTION_LLAP_QUEUE) .withDescription("The queue within which LLAP will be started").create('q')); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_OUTPUT_DIR) .withLongOpt(OPTION_OUTPUT_DIR) .withDescription("Output directory for the generated scripts").create()); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_AUXJARS).withLongOpt(OPTION_AUXJARS) .withDescription("additional jars to package (by default, JSON SerDe jar is packaged" + " if available)").create('j')); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_AUXHBASE).withLongOpt(OPTION_AUXHBASE) .withDescription("whether to package the HBase jars (true by default)").create('h')); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_AUXHIVE).withLongOpt(OPTION_AUXHIVE) .withDescription("whether to package the Hive aux jars (true by default)").create(OPTION_AUXHIVE)); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_JAVA_HOME).withLongOpt(OPTION_JAVA_HOME) .withDescription( "Path to the JRE/JDK. This should be installed at the same location on all cluster nodes ($JAVA_HOME, java.home by default)") .create()); // -hiveconf x=y options.addOption(OptionBuilder.withValueSeparator().hasArgs(2).withArgName("property=value") .withLongOpt(OPTION_HIVECONF) .withDescription("Use value for given property. Overridden by explicit parameters") .create()); options.addOption(OptionBuilder.hasArg().withArgName("b") .withLongOpt(OPTION_SLIDER_AM_CONTAINER_MB) .withDescription("The size of the slider AppMaster container in MB").create('b')); options.addOption(OptionBuilder.withValueSeparator().hasArgs(2).withArgName("property=value") .withLongOpt(OPTION_SLIDER_APPCONFIG_GLOBAL) .withDescription("Property (key=value) to be set in the global section of the Slider appConfig") .create()); options.addOption(OptionBuilder.hasArg().withArgName(OPTION_IO_THREADS) .withLongOpt(OPTION_IO_THREADS).withDescription("executor per instance").create('t')); options.addOption(OptionBuilder.hasArg(false).withArgName(OPTION_START) .withLongOpt(OPTION_START).withDescription("immediately start the cluster") .create('z')); // [-H|--help] options.addOption(new Option("H", "help", false, "Print help information")); } private static long parseSuffixed(String value) { return StringUtils.TraditionalBinaryPrefix.string2long(value); } public LlapOptions processOptions(String argv[]) throws ParseException, IOException { commandLine = new GnuParser().parse(options, argv); if (commandLine.hasOption('H') || false == commandLine.hasOption("instances")) { // needs at least --instances printUsage(); return null; } int instances = Integer.parseInt(commandLine.getOptionValue(OPTION_INSTANCES)); String directory = commandLine.getOptionValue(OPTION_DIRECTORY); String jars = commandLine.getOptionValue(OPTION_AUXJARS); String name = commandLine.getOptionValue(OPTION_NAME, null); final int executors = Integer.parseInt(commandLine.getOptionValue(OPTION_EXECUTORS, "-1")); final int ioThreads = Integer.parseInt( commandLine.getOptionValue(OPTION_IO_THREADS, Integer.toString(executors))); final long cache = parseSuffixed(commandLine.getOptionValue(OPTION_CACHE, "-1")); final long size = parseSuffixed(commandLine.getOptionValue(OPTION_SIZE, "-1")); final long xmx = parseSuffixed(commandLine.getOptionValue(OPTION_XMX, "-1")); final boolean isHbase = Boolean.parseBoolean( commandLine.getOptionValue(OPTION_AUXHBASE, "true")); final boolean isHiveAux = Boolean.parseBoolean( commandLine.getOptionValue(OPTION_AUXHIVE, "true")); final boolean doStart = commandLine.hasOption(OPTION_START); final String output = commandLine.getOptionValue(OPTION_OUTPUT_DIR, null); final String queueName = commandLine.getOptionValue(OPTION_LLAP_QUEUE, HiveConf.ConfVars.LLAP_DAEMON_QUEUE_NAME.getDefaultValue()); final Properties hiveconf; if (commandLine.hasOption(OPTION_HIVECONF)) { hiveconf = commandLine.getOptionProperties(OPTION_HIVECONF); } else { hiveconf = new Properties(); } String javaHome = null; if (commandLine.hasOption(OPTION_JAVA_HOME)) { javaHome = commandLine.getOptionValue(OPTION_JAVA_HOME); } String logger = null; if (commandLine.hasOption(OPTION_LOGGER)) { logger = commandLine.getOptionValue(OPTION_LOGGER); Preconditions.checkArgument( logger.equalsIgnoreCase(LogHelpers.LLAP_LOGGER_NAME_QUERY_ROUTING) || logger.equalsIgnoreCase(LogHelpers.LLAP_LOGGER_NAME_CONSOLE) || logger.equalsIgnoreCase(LogHelpers.LLAP_LOGGER_NAME_RFA)); } // loglevel, chaosmonkey & args are parsed by the python processor return new LlapOptions(name, instances, directory, executors, ioThreads, cache, size, xmx, jars, isHbase, hiveconf, javaHome, queueName, logger, doStart, output, isHiveAux); } private void printUsage() { HelpFormatter hf = new HelpFormatter(); try { int width = hf.getWidth(); int jlineWidth = TerminalFactory.get().getWidth(); width = Math.min(160, Math.max(jlineWidth, width)); // Ignore potentially incorrect values hf.setWidth(width); } catch (Throwable t) { // Ignore } hf.printHelp("llap", options); } }