/**
* 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.hdfs;
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.Options;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
public class AvatarShellCommand {
private static String WRONG = " - wrong arguments: ";
private static String CMD = "Command: ";
private static List<String> safeModeActions = new ArrayList<String>();
static {
safeModeActions.add("enter");
safeModeActions.add("leave");
safeModeActions.add("get");
safeModeActions.add("initqueues");
safeModeActions.add("prepfailover");
safeModeActions.add("get");
}
// commands
static final String waitTxIdCommand = "waittxid";
static final String failoverCommand = "failover";
static final String prepfailoverCommand = "prepfailover";
static final String metasaveCommand = "metasave";
static final String safemodeCommand = "safemode";
static final String setAvatarCommand = "setAvatar";
static final String isInitializedCommand = "isInitialized";
static final String shutdownAvatarCommand = "shutdownAvatar";
static final String showAvatarCommand = "showAvatar";
static final String saveNamespaceCommand = "saveNamespace";
// helpers
static final String zeroCommand = "zero";
static final String oneCommand = "one";
static final String serviceCommand = "service";
static final String addressCommand = "address";
// commands
boolean isWaitTxIdCommand;
boolean isFailoverCommand;
boolean isPrepfailoverCommand;
boolean isMetasaveCommand;
String[] metasageArgs;
boolean isSafemodeCommand;
String[] safemodeArgs;
boolean isSetAvatarCommand;
String[] setAvatarArgs;
boolean isIsInitializedCommand;
boolean isShutdownAvatarCommand;
boolean isShowAvatarCommand;
boolean isSaveNamespaceCommand;
String[] saveNamespaceArgs;
// helpers
boolean isZeroCommand;
boolean isOneCommand;
boolean isServiceCommand;
String[] serviceArgs;
boolean isAddressCommand;
String[] addressArgs;
List<String> getSaveNamespaceArgs() {
List<String> args = new ArrayList<String>();
if (saveNamespaceArgs != null) {
for (String arg : saveNamespaceArgs) {
args.add(arg);
}
}
return args;
}
void throwException(String msg) {
System.err.println(msg);
throw new IllegalArgumentException(msg);
}
/**
* For commands that directly obtain information from zk
*/
void noZeroOrOneOrAddress(String command) {
if (isZeroCommand || isOneCommand) {
throwException(CMD + command + " (zero|one) should not be specified");
}
if (isAddressCommand) {
throwException(CMD + command + " address should not be specified");
}
}
/**
* Check if either -zero -one or -address are specified.
*/
void eitherZeroOrOneOrAddress(String command) {
if (!isAddressCommand && !(isZeroCommand ^ isOneCommand)) {
throwException(CMD + command + ": (zero|one) specified incorrectly");
}
if (isAddressCommand && (isZeroCommand || isOneCommand)) {
throwException(CMD + command + ": cannot specify address with (zero|one)");
}
}
private void assertArgsSize(String command, String[] args, int maxSize,
int requiredSize) {
if (args == null && requiredSize == 0) {
return;
}
if (args.length < requiredSize || args.length > maxSize) {
throwException(CMD + command + WRONG + Arrays.toString(args));
}
}
boolean validate(CommandLine cmd) {
int commands = 0;
commands += isWaitTxIdCommand ? 1 : 0;
commands += isFailoverCommand ? 1 : 0;
commands += isPrepfailoverCommand ? 1 : 0;
commands += isMetasaveCommand ? 1 : 0;
commands += isSafemodeCommand ? 1 : 0;
commands += isSetAvatarCommand ? 1 : 0;
commands += isIsInitializedCommand ? 1 : 0;
commands += isShutdownAvatarCommand ? 1 : 0;
commands += isShowAvatarCommand ? 1 : 0;
commands += isSaveNamespaceCommand ? 1 : 0;
if (commands > 1) {
throwException("More than one command specified");
}
if (isZeroCommand && isOneCommand) {
throwException("Both zero and one specified");
}
if ((isServiceCommand || isZeroCommand || isOneCommand) && isAddressCommand) {
throwException("Both service|zero|one and address specified");
}
// /////////////////////// complext commands
// -waittxid
if (isWaitTxIdCommand) {
noZeroOrOneOrAddress(waitTxIdCommand);
assertArgsSize(waitTxIdCommand, cmd.getOptionValues(waitTxIdCommand), 0,
0);
}
// -failover
if (isFailoverCommand) {
noZeroOrOneOrAddress(failoverCommand);
assertArgsSize(failoverCommand, cmd.getOptionValues(failoverCommand), 0,
0);
}
// -prepfalover
if (isPrepfailoverCommand) {
noZeroOrOneOrAddress(prepfailoverCommand);
assertArgsSize(prepfailoverCommand,
cmd.getOptionValues(prepfailoverCommand), 0, 0);
}
// /////////////// per-avatar node commands
// -showAvatar
if (isShowAvatarCommand) {
eitherZeroOrOneOrAddress(showAvatarCommand);
assertArgsSize(showAvatarCommand, cmd.getOptionValues(showAvatarCommand),
0, 0);
}
// -shutDownAvatar
if (isShutdownAvatarCommand) {
eitherZeroOrOneOrAddress(shutdownAvatarCommand);
assertArgsSize(shutdownAvatarCommand,
cmd.getOptionValues(shutdownAvatarCommand), 0, 0);
}
// -isInitialized
if (isIsInitializedCommand) {
eitherZeroOrOneOrAddress(isInitializedCommand);
assertArgsSize(isInitializedCommand,
cmd.getOptionValues(isInitializedCommand), 0, 0);
}
// -setAvatar
if (isSetAvatarCommand) {
eitherZeroOrOneOrAddress(setAvatarCommand);
setAvatarArgs = cmd.getOptionValues(setAvatarCommand);
assertArgsSize(setAvatarCommand, setAvatarArgs, 2, 1);
if (setAvatarArgs != null) {
boolean hasPrimary = false;
for (String arg : setAvatarArgs) {
if (!(arg.equals("primary") || arg.equals("force")))
throwException(CMD + setAvatarCommand + WRONG
+ Arrays.toString(setAvatarArgs));
if (arg.equals("primary"))
hasPrimary = true;
}
if (!hasPrimary) {
throwException(CMD + setAvatarCommand + WRONG
+ Arrays.toString(setAvatarArgs));
}
}
}
// -metasave
if (isMetasaveCommand) {
eitherZeroOrOneOrAddress(metasaveCommand);
metasageArgs = cmd.getOptionValues(metasaveCommand);
assertArgsSize(metasaveCommand, metasageArgs, 1, 1);
}
// -safemode
if (isSafemodeCommand) {
eitherZeroOrOneOrAddress(safemodeCommand);
safemodeArgs = cmd.getOptionValues(safemodeCommand);
assertArgsSize(safemodeCommand, safemodeArgs, 1, 1);
for (String arg : safemodeArgs) {
if (!safeModeActions.contains(arg))
throwException(CMD + safemodeCommand + " - safemode action: " + arg
+ " unknown");
}
}
// -saveNamespace
if (isSaveNamespaceCommand) {
eitherZeroOrOneOrAddress(saveNamespaceCommand);
saveNamespaceArgs = cmd.getOptionValues(saveNamespaceCommand);
assertArgsSize(saveNamespaceCommand, saveNamespaceArgs, 2, 0);
if (saveNamespaceArgs != null) {
for (String arg : saveNamespaceArgs) {
if (!(arg.equals("uncompressed") || arg.equals("force")))
throwException(CMD + saveNamespaceCommand + WRONG
+ Arrays.toString(saveNamespaceArgs));
}
}
}
// -service
if (isServiceCommand) {
serviceArgs = cmd.getOptionValues(serviceCommand);
assertArgsSize(serviceCommand, serviceArgs, 1, 1);
}
// -address
if (isAddressCommand) {
addressArgs = cmd.getOptionValues(addressCommand);
assertArgsSize(addressCommand, addressArgs, 1, 1);
int i = addressArgs[0].indexOf(":");
if (i < 1)
throwException(addressCommand + ": wrong host:port pair");
try {
Integer.valueOf(addressArgs[0].substring(i + 1));
} catch (Exception e) {
throwException(addressCommand + ": wrong host:port pair");
}
}
// -zero -one
assertArgsSize(zeroCommand, cmd.getOptionValues(zeroCommand), 0, 0);
assertArgsSize(oneCommand, cmd.getOptionValues(oneCommand), 0, 0);
return true;
}
static AvatarShellCommand parseCommand(String[] argv) {
CommandLine cmd = parseOptions(argv);
if (cmd == null)
return null;
AvatarShellCommand asc = new AvatarShellCommand();
asc.isWaitTxIdCommand = cmd.hasOption(waitTxIdCommand);
asc.isFailoverCommand = cmd.hasOption(failoverCommand);
asc.isPrepfailoverCommand = cmd.hasOption(prepfailoverCommand);
asc.isMetasaveCommand = cmd.hasOption(metasaveCommand);
asc.isSafemodeCommand = cmd.hasOption(safemodeCommand);
asc.isSetAvatarCommand = cmd.hasOption(setAvatarCommand);
asc.isIsInitializedCommand = cmd.hasOption(isInitializedCommand);
asc.isShutdownAvatarCommand = cmd.hasOption(shutdownAvatarCommand);
asc.isShowAvatarCommand = cmd.hasOption(showAvatarCommand);
asc.isSaveNamespaceCommand = cmd.hasOption(saveNamespaceCommand);
asc.isZeroCommand = cmd.hasOption(zeroCommand);
asc.isOneCommand = cmd.hasOption(oneCommand);
asc.isServiceCommand = cmd.hasOption(serviceCommand);
asc.isAddressCommand = cmd.hasOption(addressCommand);
try {
asc.validate(cmd);
} catch (Exception e) {
return null;
}
return asc;
}
private static CommandLine parseOptions(String[] argv) {
Options options = buildOptions();
CommandLineParser parser = new PosixParser();
try {
return parser.parse(options, argv);
} catch (ParseException e) {
System.out.println("Error parsing command-line options");
return null;
}
}
/**
* Build command-line options and descriptions
*/
@SuppressWarnings("static-access")
public static Options buildOptions() {
Options options = new Options();
// actual commands
options.addOption(OptionBuilder.hasOptionalArgs().create(waitTxIdCommand));
options.addOption(OptionBuilder.hasOptionalArgs().create(failoverCommand));
options.addOption(OptionBuilder.hasOptionalArgs().create(
prepfailoverCommand));
options.addOption(OptionBuilder.hasOptionalArgs().create(metasaveCommand));
options.addOption(OptionBuilder.hasOptionalArgs().create(safemodeCommand));
options.addOption(OptionBuilder.hasOptionalArgs().create(
saveNamespaceCommand));
options.addOption(OptionBuilder.hasOptionalArgs().create(setAvatarCommand));
options.addOption(OptionBuilder.hasOptionalArgs().create(
isInitializedCommand));
options.addOption(OptionBuilder.hasOptionalArgs().create(
shutdownAvatarCommand));
options
.addOption(OptionBuilder.hasOptionalArgs().create(showAvatarCommand));
// helper commands
options.addOption(OptionBuilder.hasOptionalArgs().create(zeroCommand));
options.addOption(OptionBuilder.hasOptionalArgs().create(oneCommand));
options.addOption(OptionBuilder.hasOptionalArgs().create(serviceCommand));
options.addOption(OptionBuilder.hasOptionalArgs().create(addressCommand));
return options;
}
}