/**
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 java.util.Arrays;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import jline.TerminalFactory;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
public class LlapStatusOptionsProcessor {
private static final String LLAPSTATUS_CONSTANT = "llapstatus";
private static final long FIND_YARN_APP_TIMEOUT_MS = 20 * 1000l; // 20seconds to wait for app to be visible
private static final long DEFAULT_STATUS_REFRESH_INTERVAL_MS = 1 * 1000l; // 1 seconds wait until subsequent status
private static final long DEFAULT_WATCH_MODE_TIMEOUT_MS = 5 * 60 * 1000l; // 5 minutes timeout for watch mode
private static final float DEFAULT_RUNNING_NODES_THRESHOLD = 1.0f;
enum OptionConstants {
NAME("name", 'n', "LLAP cluster name", true),
FIND_APP_TIMEOUT("findAppTimeout", 'f',
"Amount of time(s) that the tool will sleep to wait for the YARN application to start. negative values=wait forever, 0=Do not wait. default=" +
TimeUnit.SECONDS.convert(FIND_YARN_APP_TIMEOUT_MS, TimeUnit.MILLISECONDS) + "s", true),
OUTPUT_FILE("outputFile", 'o', "File to which output should be written (Default stdout)", true),
WATCH_MODE("watch", 'w', "Watch mode waits until all LLAP daemons are running or subset of the nodes are " +
"running (threshold can be specified via -r option) (Default wait until all nodes are running)", false),
RUNNING_NODES_THRESHOLD("runningNodesThreshold", 'r', "When watch mode is enabled (-w), wait until the " +
"specified threshold of nodes are running (Default 1.0 which means 100% nodes are running)", true),
STATUS_REFRESH_INTERVAL("refreshInterval", 'i', "Amount of time in seconds to wait until subsequent status checks" +
" in watch mode. Valid only for watch mode. (Default " +
TimeUnit.SECONDS.convert(DEFAULT_STATUS_REFRESH_INTERVAL_MS, TimeUnit.MILLISECONDS) + "s)", true),
WATCH_MODE_TIMEOUT("watchTimeout", 't', "Exit watch mode if the desired state is not attained until the specified" +
" timeout. (Default " + TimeUnit.SECONDS.convert(DEFAULT_WATCH_MODE_TIMEOUT_MS, TimeUnit.MILLISECONDS) +"s)", true),
HIVECONF("hiveconf", null, "Use value for given property. Overridden by explicit parameters", "property=value", 2),
HELP("help", 'H', "Print help information", false);
private final String longOpt;
private final Character shortOpt;
private final String description;
private final String argName;
private final int numArgs;
OptionConstants(String longOpt, char shortOpt, String description, boolean hasArgs) {
this(longOpt, shortOpt, description, longOpt, hasArgs ? 1 : 0);
}
OptionConstants(String longOpt, Character shortOpt, String description, String argName, int numArgs) {
this.longOpt = longOpt;
this.shortOpt = shortOpt;
this.description = description;
this.argName = argName;
this.numArgs = numArgs;
}
public String getLongOpt() {
return longOpt;
}
public Character getShortOpt() {
return shortOpt;
}
public String getDescription() {
return description;
}
public String getArgName() {
return argName;
}
public int getNumArgs() {
return numArgs;
}
}
public static class LlapStatusOptions {
private final String name;
private final Properties conf;
private final long findAppTimeoutMs;
private final String outputFile;
private final long refreshIntervalMs;
private final boolean watchMode;
private final long watchTimeout;
private final float runningNodesThreshold;
public LlapStatusOptions(final String name) {
this(name, new Properties(), FIND_YARN_APP_TIMEOUT_MS, null, DEFAULT_STATUS_REFRESH_INTERVAL_MS, false,
DEFAULT_WATCH_MODE_TIMEOUT_MS, DEFAULT_RUNNING_NODES_THRESHOLD);
}
public LlapStatusOptions(String name, Properties hiveProperties, long findAppTimeoutMs,
String outputFile, long refreshIntervalMs,
final boolean watchMode, final long watchTimeoutMs,
final float runningNodesThreshold) {
this.name = name;
this.conf = hiveProperties;
this.findAppTimeoutMs = findAppTimeoutMs;
this.outputFile = outputFile;
this.refreshIntervalMs = refreshIntervalMs;
this.watchMode = watchMode;
this.watchTimeout = watchTimeoutMs;
this.runningNodesThreshold = runningNodesThreshold;
}
public String getName() {
return name;
}
public Properties getConf() {
return conf;
}
public long getFindAppTimeoutMs() {
return findAppTimeoutMs;
}
public String getOutputFile() {
return outputFile;
}
public long getRefreshIntervalMs() {
return refreshIntervalMs;
}
public boolean isWatchMode() {
return watchMode;
}
public long getWatchTimeoutMs() {
return watchTimeout;
}
public float getRunningNodesThreshold() {
return runningNodesThreshold;
}
}
private final Options options = new Options();
private org.apache.commons.cli.CommandLine commandLine;
public LlapStatusOptionsProcessor() {
for (OptionConstants optionConstant : OptionConstants.values()) {
OptionBuilder optionBuilder = OptionBuilder.hasArgs(optionConstant.getNumArgs())
.withArgName(optionConstant.getArgName()).withLongOpt(optionConstant.getLongOpt())
.withDescription(optionConstant.getDescription());
if (optionConstant.getShortOpt() == null) {
options.addOption(optionBuilder.create());
} else {
options.addOption(optionBuilder.create(optionConstant.getShortOpt()));
}
}
}
public LlapStatusOptions processOptions(String[] args) throws ParseException {
commandLine = new GnuParser().parse(options, args);
if (commandLine.hasOption(OptionConstants.HELP.getShortOpt())) {
printUsage();
return null;
}
String name = commandLine.getOptionValue(OptionConstants.NAME.getLongOpt());
long findAppTimeoutMs = FIND_YARN_APP_TIMEOUT_MS;
if (commandLine.hasOption(OptionConstants.FIND_APP_TIMEOUT.getLongOpt())) {
findAppTimeoutMs = TimeUnit.MILLISECONDS.convert(Long.parseLong(
commandLine.getOptionValue(OptionConstants.FIND_APP_TIMEOUT.getLongOpt())),
TimeUnit.SECONDS);
}
Properties hiveConf;
if (commandLine.hasOption(OptionConstants.HIVECONF.getLongOpt())) {
hiveConf = commandLine.getOptionProperties(OptionConstants.HIVECONF.getLongOpt());
} else {
hiveConf = new Properties();
}
String outputFile = null;
if (commandLine.hasOption(OptionConstants.OUTPUT_FILE.getLongOpt())) {
outputFile = commandLine.getOptionValue(OptionConstants.OUTPUT_FILE.getLongOpt());
}
long refreshIntervalMs = DEFAULT_STATUS_REFRESH_INTERVAL_MS;
if (commandLine.hasOption(OptionConstants.STATUS_REFRESH_INTERVAL.getLongOpt())) {
long refreshIntervalSec = Long.parseLong(commandLine.getOptionValue(OptionConstants.STATUS_REFRESH_INTERVAL
.getLongOpt()));
if (refreshIntervalSec <= 0) {
throw new IllegalArgumentException("Refresh interval should be >0");
}
refreshIntervalMs = TimeUnit.MILLISECONDS.convert(refreshIntervalSec, TimeUnit.SECONDS);
}
boolean watchMode = commandLine.hasOption(OptionConstants.WATCH_MODE.getLongOpt()) ? true : false;
long watchTimeoutMs = DEFAULT_WATCH_MODE_TIMEOUT_MS;
if (commandLine.hasOption(OptionConstants.WATCH_MODE_TIMEOUT.getLongOpt())) {
long watchTimeoutSec = Long.parseLong(commandLine.getOptionValue(OptionConstants.WATCH_MODE_TIMEOUT.getLongOpt()));
if (watchTimeoutSec <= 0) {
throw new IllegalArgumentException("Watch timeout should be >0");
}
watchTimeoutMs = TimeUnit.MILLISECONDS.convert(watchTimeoutSec, TimeUnit.SECONDS);
}
float runningNodesThreshold = DEFAULT_RUNNING_NODES_THRESHOLD;
if (commandLine.hasOption(OptionConstants.RUNNING_NODES_THRESHOLD.getLongOpt())) {
runningNodesThreshold = Float.parseFloat(commandLine.getOptionValue(OptionConstants.RUNNING_NODES_THRESHOLD
.getLongOpt()));
if (runningNodesThreshold < 0.0f || runningNodesThreshold > 1.0f) {
throw new IllegalArgumentException("Running nodes threshold value should be between 0.0 and 1.0 (inclusive)");
}
}
return new LlapStatusOptions(name, hiveConf, findAppTimeoutMs, outputFile, refreshIntervalMs, watchMode,
watchTimeoutMs, runningNodesThreshold);
}
public static 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
}
LlapStatusOptionsProcessor optionsProcessor = new LlapStatusOptionsProcessor();
hf.printHelp(LLAPSTATUS_CONSTANT, optionsProcessor.options);
}
}