
oracle.kv.impl.admin.client.PlanCommand Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of oracle-nosql-server Show documentation
Show all versions of oracle-nosql-server Show documentation
NoSQL Database Server - supplies build and runtime support for the server (store) side of the Oracle NoSQL Database.
The newest version!
/*-
* Copyright (C) 2011, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This file was distributed by Oracle as part of a version of Oracle NoSQL
* Database made available at:
*
* http://www.oracle.com/technetwork/database/database-technologies/nosqldb/downloads/index.html
*
* Please see the LICENSE file included in the top-level directory of the
* appropriate version of Oracle NoSQL Database for a copy of the license and
* additional information.
*/
package oracle.kv.impl.admin.client;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import oracle.kv.impl.admin.AdminFaultException;
import oracle.kv.impl.admin.AdminNotReadyException;
import oracle.kv.impl.admin.CommandResult;
import oracle.kv.impl.admin.CommandResult.CommandSucceeds;
import oracle.kv.impl.admin.CommandServiceAPI;
import oracle.kv.impl.admin.IllegalCommandException;
import oracle.kv.impl.admin.param.AdminParams;
import oracle.kv.impl.admin.param.ArbNodeParams;
import oracle.kv.impl.admin.param.Parameters;
import oracle.kv.impl.admin.param.RepNodeParams;
import oracle.kv.impl.admin.param.StorageNodeParams;
import oracle.kv.impl.admin.plan.Plan;
import oracle.kv.impl.admin.plan.Plan.State;
import oracle.kv.impl.admin.plan.StatusReport;
import oracle.kv.impl.api.table.TableBuilder;
import oracle.kv.impl.api.table.TableEvolver;
import oracle.kv.impl.api.table.TableLimits;
import oracle.kv.impl.monitor.views.ServiceChange;
import oracle.kv.impl.param.ParameterMap;
import oracle.kv.impl.param.ParameterState;
import oracle.kv.impl.security.util.PasswordReader;
import oracle.kv.impl.security.util.SecurityUtils;
import oracle.kv.impl.security.util.ShellPasswordReader;
import oracle.kv.impl.topo.AdminId;
import oracle.kv.impl.topo.ArbNodeId;
import oracle.kv.impl.topo.Datacenter;
import oracle.kv.impl.topo.DatacenterId;
import oracle.kv.impl.topo.DatacenterType;
import oracle.kv.impl.topo.RepGroupId;
import oracle.kv.impl.topo.RepNodeId;
import oracle.kv.impl.topo.ResourceId;
import oracle.kv.impl.topo.StorageNodeId;
import oracle.kv.impl.topo.Topology;
import oracle.kv.impl.util.CommandParser;
import oracle.kv.impl.util.HostPort;
import oracle.kv.impl.util.JsonUtils;
import oracle.kv.util.ErrorMessage;
import oracle.kv.util.shell.CommandWithSubs;
import oracle.kv.util.shell.Shell;
import oracle.kv.util.shell.ShellArgumentException;
import oracle.kv.util.shell.ShellCommandResult;
import oracle.kv.util.shell.ShellException;
import oracle.kv.util.shell.ShellUsageException;
import org.codehaus.jackson.node.ObjectNode;
/** Subcommands of plan */
class PlanCommand extends CommandWithSubs {
/*
* TODO need to add command for start/stop all arbiters
*/
private static final List extends SubCommand> subs = Arrays.asList(
new AddIndexSub(), /* add-index */
new AddTableSub(), /* add-table */
new CancelSub(), /* cancel */
/*
* TODO : Yet to implement support for change-admindir[size]
* and change-rnlogdir[size].
*/
new ChangeStorageDirSub(), /* change-storagedir */
new ChangeParamsSub(), /* change-parameters */
new ChangeUserSub(), /* change-user */
new CreateUserSub(), /* create-user */
new DeployAdminSub(), /* deploy-admin */
new DeployDCSub(), /* deploy-datacenter */
new DeploySNSub(), /* deploy-sn */
new DeployTopologySub(), /* deploy-topology */
new DeployZoneSub(), /* deploy-zone */
new DropUserSub(), /* drop-user */
new EnableRequestsSub(), /* enable-requests */
new EvolveTableSub(), /* evolve-table */
new ExecuteSub(), /* execute */
new FailoverSub(), /* failover */
new GrantSub(), /* grant */
new InterruptSub(), /* interrupt */
new MigrateSNSub(), /* migrate-sn */
new NetworkRestoreSub(), /* network-restore */
new PlanWaitSub(), /* wait */
new RemoveAdminSub(), /* remove-admin */
new RemoveDatacenterSub(), /* remove-datacenter */
new RemoveIndexSub(), /* remove-index */
new RemoveSNSub(), /* remove-sn */
new RemoveTableSub(), /* remove-table */
new RemoveZoneSub(), /* remove-zone */
new RepairTopologySub(), /* repair-topology */
new RevokeSub(), /* revoke */
new SetTableLimitsSub(), /* set-table-limits */
new StartServiceSub(), /* start-service */
new StopServiceSub(), /* stop-service */
new RegisterEsCluster(), /* register-es */
new DeregisterEsCluster(), /* deregister-es */
new VerifyDataSub() /* verify-data */
);
private static final String PLAN_COMMAND_NAME = "plan";
PlanCommand() {
super(subs,
PLAN_COMMAND_NAME,
4, /* prefix length */
0); /* min args -- let subs control it */
}
@Override
protected String getCommandOverview() {
return "Encapsulates operations, or jobs that modify store state." +
eol + "All subcommands with the exception of " +
"interrupt and wait change" + eol + "persistent state. Plans " +
"are asynchronous jobs so they return immediately" + eol +
"unless -wait is used. Plan status can be checked using " +
"\"show plans\"." + eol + "Optional arguments for all plans " +
"include:" +
eolt + "-wait -- wait for the plan to complete before returning" +
eolt + "-plan-name -- name for a plan. These are not unique" +
eolt + "-noexecute -- do not execute the plan. If specified " +
"the plan" + eolt + " " +
"can be run later using \"plan execute\"" +
eolt + "-force -- used to force plan execution and plan retry";
}
/*
* Base abstract class for PlanSubCommands. This class extracts
* the generic flags from the command line.
*/
abstract static class PlanSubCommand extends SubCommand {
protected boolean execute;
protected boolean wait;
protected boolean force;
protected String planName;
static final String genericFlags =
eolt + "[-plan-name ] [-wait] [-noexecute] [-force] " +
CommandParser.getJsonUsage();
static final String dcFlagsDeprecation =
"The -dc and -dcname flags, and the dc ID format, are" +
" deprecated" + eol +
"and have been replaced by -zn, -znname, and zn." +
eol + eol;
static final String lastPlanNotFound =
"Found no plans created by the current user.";
protected PlanSubCommand(String name, int prefixMatchLength) {
super(name, prefixMatchLength);
}
@Override
public String execute(String[] args, Shell shell)
throws ShellException {
wait = false;
execute = true;
force = false;
planName = null;
return exec(args, shell);
}
@Override
public ShellCommandResult executeJsonOutput(String[] args,
Shell shell)
throws ShellException {
wait = false;
execute = true;
force = false;
planName = null;
return execJsonOutput(args, shell);
}
protected int checkGenericArg(String arg, String[] args, int i)
throws ShellException {
int rval = 0;
if ("-plan-name".equals(arg)) {
planName = Shell.nextArg(args, i, this);
rval = 1;
} else if ("-wait".equals(arg)) {
wait = true;
} else if ("-noexecute".equals(arg)) {
execute = false;
} else if ("-force".equals(arg)) {
force = true;
} else {
throw new ShellUsageException("Invalid argument: " + arg,
this);
}
return rval;
}
public abstract String exec(String[] args, Shell shell)
throws ShellException;
/*
* Execute and return general POJO for sub commands. This method can
* be override to provide individual JSON output format in
* return value field.
*/
public ShellCommandResult execJsonOutput(String[] args,
Shell shell)
throws ShellException {
/* Bridge and filter V1 result */
final String result = exec(args, shell);
return filterJsonResult(result);
}
/**
* Return the most recently created plan's id. If users have no
* SYSVIEW privilege, the most recently plan created by them will be
* returned. If users do not have ownership of any plan, 0 will be
* returned.
*/
protected static int getLastPlanId(CommandServiceAPI cs)
throws RemoteException {
int range[] =
cs.getPlanIdRange(0L, (new Date()).getTime(), 1);
return range[0];
}
/*
* Encapsulate plan execution and optional waiting in a single place
*/
protected String executePlan(int planId, CommandServiceAPI cs,
Shell shell)
throws ShellException, RemoteException {
/*
* Implicitly approve plan. TODO: change server side to do this
*/
cs.approvePlan(planId);
if (execute) {
cs.executePlan(planId, force);
if (wait) {
shell.echo("Executed plan " + planId +
", waiting for completion..." + Shell.eol);
final Plan.State state =
awaitPlan(planId, 0, null, cs, shell);
if (state != Plan.State.SUCCEEDED) {
exitCode = Shell.EXIT_UNKNOWN;
}
if (!shell.getJson()) {
return state.getWaitMessage(planId);
}
long options = StatusReport.SHOW_FINISHED_BIT;
if (shell.getVerbose()) {
options |= StatusReport.VERBOSE_BIT;
}
return cs.getPlanStatus(
planId, options, shell.getJson());
}
}
if (shell.getJson()) {
ObjectNode returnValue = JsonUtils.createObjectNode();
returnValue.put("plan_id", planId);
CommandResult cmdResult = new CommandSucceeds(
returnValue.toString());
return Shell.toJsonReport(
PLAN_COMMAND_NAME + " " + getCommandName(), cmdResult);
}
if (execute) {
return "Started plan " + planId + ". Use show plan -id " +
planId + " to check status." + eolt +
"To wait for completion, use plan wait -id " + planId;
}
return "Created plan without execution: " + planId;
}
}
private static Plan.State awaitPlan(int planId,
int timeout,
TimeUnit timeUnit,
CommandServiceAPI cs,
Shell shell)
throws ShellException {
Exception cause;
final long endTime = (timeout == 0) ? Long.MAX_VALUE :
System.currentTimeMillis() + timeUnit.toMillis(timeout);
while (true) {
/*
* Await on the Admin. Retry on RemoteException or
* AdminNotReadyException, either indefinately (timeout == 0) or
* until the timeout expires.
*/
try {
return cs.awaitPlan(planId, timeout, timeUnit);
} catch (AdminFaultException afe) {
if (!afe.getFaultClassName().equals(
AdminNotReadyException.class.getName())) {
throw afe;
}
cause = afe;
} catch (RemoteException re) {
cause = re;
}
try {
if (System.currentTimeMillis() >= endTime) {
throw cause;
}
Thread.sleep(1000);
} catch (Exception e) {
throw new ShellException("Exception waiting for plan " + planId,
e);
}
/* Get a new connection to the Admin */
cs = ((CommandShell)shell).getAdmin(true);
}
}
@POST
static class ChangeStorageDirSub extends PlanSubCommand {
ChangeStorageDirSub() {
super("change-storagedir", 9);
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
StorageNodeId snId = null;
String storageDir = null;
String storageDirSize = null;
boolean add = true;
boolean addOrRemove = false;
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if ("-sn".equals(arg)) {
final String argString = Shell.nextArg(args, i++, this);
snId = parseSnid(argString);
} else if ("-storagedir".equals(arg)) {
storageDir = Shell.nextArg(args, i++, this);
} else if ("-path".equals(arg)) {
/*
* [#21880] use -storagedir as the flag name, but support
* -path until next R3 for backward compatibility.
*/
storageDir = Shell.nextArg(args, i++, this);
} else if ("-storagedirsize".equals(arg)) {
storageDirSize = Shell.nextArg(args, i++, this);
} else if ("-add".equals(arg)) {
add = true;
addOrRemove = true;
} else if ("-remove".equals(arg)) {
add = false;
addOrRemove = true;
} else {
i += checkGenericArg(arg, args, i);
}
}
if (snId == null || !addOrRemove) {
shell.requiredArg(null, this);
}
try {
final Parameters p = cs.getParameters();
final StorageNodeParams snp = p.get(snId);
if (snp == null) {
throw new ShellUsageException("Unknown storage node: " +
snId, this);
}
ParameterMap storageDirMap = null;
try {
storageDirMap = StorageNodeParams.
changeStorageDirMap(cs.getParameters(),
snp, add,
storageDir,
storageDirSize);
} catch (IllegalCommandException e) {
throw new ShellUsageException(e.getMessage(), this);
}
final int planId =
cs.createChangeParamsPlan(planName, snId, storageDirMap);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected boolean matches(String commandName) {
/* Allow deprecated name until R3 [#21880] */
return super.matches(commandName) ||
Shell.matches(commandName, "change-mountpoint",
prefixMatchLength);
}
@Override
protected String getCommandSyntax() {
return "plan change-storagedir -sn " + eolt +
"-storagedir " +
"-add|-remove " +
"[-storagedirsize ] " +
genericFlags;
}
@Override
protected String getCommandDescription() {
return
"Adds or removes a storage directory on a Storage Node for use" +
eolt +
"by a Replication Node. When -add is specified, the optional" +
eolt +
"-storagedirsize flag can be specified to set the size of the" +
eolt +
"directory. The size format is \"number [unit]\", where unit" +
eolt +
"can be KB, MG, GB, or TB. The unit is case insensitive and may" +
eolt +
"be separated from the number by a space, \"-\", or \"_\".";
}
}
@POST
static final class ChangeParamsSub extends PlanSubCommand {
final String incompatibleAllError =
"Invalid argument combination: Only one of the flags " +
"-all-rns, -all-sns, -all-admins, -all-ans, -global " +
"and -security may be used.";
final String serviceAllError =
"Invalid argument combination: -service flag cannot be used " +
"with -all-rns, -all-admins, -all-ans, -global or -security flags";
final String serviceDcError =
"Invalid argument combination: -service flag cannot be used " +
"with -zn, -znname, -dc, or -dcname flag";
final String commandSyntax =
"plan change-parameters -security | -global | -service | " +
eolt +
"-all-rns [-zn | -znname ] | " +
eolt +
"-all-ans [-zn | -znname ] | " +
eolt +
"-all-admins [-zn | -znname ] [-dry-run]" +
genericFlags + " -params [name=value]*";
final String commandDesc =
"Changes parameters for either the specified service, or for" +
eolt +
"all service instances of the same type that are deployed to" +
eolt +
"the specified zone or all zones. " +
eolt +
" -security changes store-wide security parameters and should" +
eolt +
" not be used with other flags. " +
eolt +
" -global changes store-wide non-security parameters and should" +
eolt +
" not be used with other flags. " +
eolt +
" -service affects a single component and should not be used " +
eolt +
" with either the -zn or -znname flag. " +
eolt +
eolt +
"One of the -all-* flags can be combined with -zn or -znname to " +
eolt +
"to change all instances of the service type deployed to the " +
eolt +
"specified zone, leaving unchanged any instances of the " +
eolt +
"specified type deployed to other zones. If one of the -all-* " +
eolt +
"flags is used without also specifying the zone, then the desired "+
eolt +
"parameter change will be applied to all instances of the " +
eolt +
"specified type within the store, regardless of zone. " +
eolt +
eolt +
"The parameters to change are specified via the -params flag" +
eolt +
"and consist of name/value pairs separated by spaces, where" +
eolt +
"any parameter values with embedded spaces must be quoted" +
eolt +
"(for example, name=\"value with spaces\"). Finally, if the" +
eolt +
"-dry-run flag is specified, the new parameters are returned" +
eolt +
"without applying the specified change." +
eol +
eolt +
"Use \"show parameters\" to see what parameters can be " +
"modified";
String serviceName;
StorageNodeId snid;
RepNodeId rnid;
AdminId aid;
ArbNodeId anid;
boolean allAdmin, allRN, allSN, security, allAN, global;
boolean dryRun;
ChangeParamsSub() {
super("change-parameters", 10);
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
return new ChangeParameterExecutor() {
@Override
public String
planExecutionResult(String serverText,
String deprecatedDcFlagPrefix)
throws ShellException {
if (shell.getJson()) {
return serverText;
}
return deprecatedDcFlagPrefix + serverText;
}
@Override
public String dryRunResult(ParameterMap map,
boolean showHidden)
throws ShellException {
return CommandUtils.formatParams(map,
showHidden, null);
}
}.commonExecute(args, shell);
}
@Override
public ShellCommandResult execJsonOutput(String[] args, Shell shell)
throws ShellException {
final ShellCommandResult scr =
ShellCommandResult.getDefault("plan change-parameter");
return new ChangeParameterExecutor() {
@Override
public ShellCommandResult
planExecutionResult(String serverText,
String deprecatedDcFlagPrefix)
throws ShellException {
return filterJsonResult(serverText);
}
@Override
public ShellCommandResult
dryRunResult(ParameterMap map,
boolean showHidden)
throws ShellException {
scr.setReturnValue(
CommandUtils.formatParamsJson(map, showHidden, null));
return scr;
}
}.commonExecute(args, shell);
}
@Override
protected String getCommandSyntax() {
return commandSyntax;
}
/* TODO: help differentiated by service type */
@Override
protected String getCommandDescription() {
return commandDesc;
}
private abstract class
ChangeParameterExecutor implements Executor {
@Override
public T commonExecute(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, ChangeParamsSub.this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
serviceName = null;
snid = null;
aid = null;
rnid = null;
anid = null;
allAdmin = allRN = allSN = dryRun = security = allAN =
global = false;
int i;
boolean foundParams = false;
DatacenterId dcid = null;
String dcName = null;
boolean getDcId = false;
boolean deprecatedDcFlag = false;
for (i = 1; i < args.length; i++) {
final String arg = args[i];
if ("-service".equals(arg)) {
serviceName = Shell.nextArg(
args, i++, ChangeParamsSub.this);
} else if ("-all-rns".equals(arg)) {
allRN = true;
} else if ("-all-admins".equals(arg)) {
allAdmin = true;
} else if ("-all-sns".equals(arg)) {
allSN = true;
} else if ("-all-ans".equals(arg)) {
allAN = true;
} else if (CommandUtils.isDatacenterIdFlag(arg)) {
dcid = DatacenterId.parse(
Shell.nextArg(args, i++, ChangeParamsSub.this));
if (CommandUtils.
isDeprecatedDatacenterId(arg, args[i])) {
deprecatedDcFlag = true;
}
} else if (CommandUtils.isDatacenterNameFlag(arg)) {
dcName = Shell.nextArg(
args, i++, ChangeParamsSub.this);
if (CommandUtils.isDeprecatedDatacenterName(arg)) {
deprecatedDcFlag = true;
}
} else if ("-global".equals(arg)) {
global = true;
} else if ("-security".equals(arg)) {
security = true;
} else if ("-dry-run".equals(arg)) {
dryRun = true;
} else if ("-params".equals(arg)) {
++i;
foundParams = true;
break;
} else {
i += checkGenericArg(arg, args, i);
}
}
/* Verify argument combinations */
if (serviceName == null) {
if (!(allAdmin || allRN || allSN || allAN ||
global || security)) {
shell.requiredArg(
null, ChangeParamsSub.this);
} else {
/*
* check whether multiple incompatible options are
* given.
*/
if (((allAdmin ? 1 : 0) +
(allRN ? 1 : 0) +
(allSN ? 1 : 0) +
(allAN ? 1 : 0) +
(global ? 1 : 0) +
(security ? 1 : 0)) > 1) {
throw new ShellUsageException(
incompatibleAllError, ChangeParamsSub.this);
}
if (dcName != null) {
getDcId = true;
}
}
} else {
if (allAdmin || allRN || allSN || security ||
allAN || global) {
throw new ShellUsageException(
serviceAllError, ChangeParamsSub.this);
}
if (dcid != null || dcName != null) {
throw new ShellUsageException(
serviceDcError, ChangeParamsSub.this);
}
}
if (!foundParams) {
shell.requiredArg("-params", ChangeParamsSub.this);
}
if (args.length <= i) {
throw new ShellArgumentException(
"No parameters were specified");
}
final String deprecatedDcFlagPrefix =
deprecatedDcFlag ? dcFlagsDeprecation : "";
try {
int planId = 0;
final ParameterMap map = createChangeMap(cs, args, i,
cmd.getHidden());
if (dryRun) {
return dryRunResult(map, cmd.getHidden());
}
if (getDcId) {
dcid = CommandUtils.getDatacenterId(
dcName, cs, ChangeParamsSub.this);
}
if (rnid != null) {
shell.verboseOutput("Changing parameters for " + rnid);
planId =
cs.createChangeParamsPlan(planName, rnid, map);
} else if (allRN) {
shell.verboseOutput(
"Changing parameters for all RepNodes" +
(dcName != null ?
" deployed to the " + dcName + " zone" :
(dcid != null ?
" deployed to the zone with id = " + dcid :
"")));
planId =
cs.createChangeAllParamsPlan(planName, dcid, map);
} else if (snid != null) {
shell.verboseOutput("Changing parameters for " + snid);
planId =
cs.createChangeParamsPlan(planName, snid, map);
} else if (anid != null) {
shell.verboseOutput("Changing parameters for " + anid);
planId =
cs.createChangeParamsPlan(planName, anid, map);
} else if (allAN) {
shell.verboseOutput(
"Changing parameters for all ArbNodes" +
(dcName != null ?
" deployed to the " + dcName + " zone" :
(dcid != null ?
" deployed to the zone with id = " + dcid :
"")));
planId =
cs.createChangeAllANParamsPlan(
planName, dcid, map);
} else if (allAdmin) {
shell.verboseOutput(
"Changing parameters for all Admins" +
(dcName != null ?
" deployed to the " + dcName + " zone" :
(dcid != null ?
" deployed to the zone with id = " + dcid :
"")));
planId =
cs.createChangeAllAdminsPlan(planName, dcid, map);
} else if (global) {
shell.verboseOutput(
"Changing global component parameters");
planId =
cs.createChangeGlobalComponentsParamsPlan(planName,
map);
} else if (security) {
shell.verboseOutput(
"Changing global security parameters");
planId =
cs.createChangeGlobalSecurityParamsPlan(
planName, map);
} else if (aid != null) {
shell.verboseOutput("Changing parameters for " + aid);
planId = cs.createChangeParamsPlan(planName, aid, map);
} else if (allSN) {
throw new ShellUsageException(
"Can't change all SN params at this time",
ChangeParamsSub.this);
}
if (shell.getVerbose()) {
shell.verboseOutput
("New parameters:" + eol +
CommandUtils.formatParams(map,
cmd.getHidden(),
null));
}
return planExecutionResult(
executePlan(planId, cs, shell),
deprecatedDcFlagPrefix);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return null;
}
public abstract T
planExecutionResult(String serverText,
String deprecatedDcFlagPrefix)
throws ShellException;
public abstract T dryRunResult(ParameterMap map,
boolean showHidden)
throws ShellException;
}
private ParameterMap getServiceMap(CommandServiceAPI cs)
throws ShellException, RemoteException {
ParameterMap map = null;
final Parameters p = cs.getParameters();
try {
rnid = RepNodeId.parse(serviceName);
final RepNodeParams rnp = p.get(rnid);
if (rnp != null) {
map = rnp.getMap();
} else {
throw new ShellUsageException
("No such service: " + serviceName, this);
}
} catch (IllegalArgumentException ignored) {
try {
snid = StorageNodeId.parse(serviceName);
final StorageNodeParams snp = p.get(snid);
if (snp != null) {
map = snp.getMap();
} else {
throw new ShellUsageException
("No such service: " + serviceName, this);
}
} catch (IllegalArgumentException ignored1) {
try {
aid = AdminId.parse(serviceName);
final AdminParams ap = p.get(aid);
if (ap != null) {
map = ap.getMap();
} else {
throw new ShellUsageException
("No such service: " + serviceName, this);
}
} catch (IllegalArgumentException ignored2) {
try {
anid = ArbNodeId.parse(serviceName);
final ArbNodeParams ap = p.get(anid);
if (ap != null) {
map = ap.getMap();
} else {
throw new ShellUsageException
("No such service: " + serviceName, this);
}
} catch (IllegalArgumentException ignored3) {
throw new ShellUsageException
("Invalid service name: " + serviceName, this);
}
}
}
}
return map;
}
private ParameterMap createChangeMap(CommandServiceAPI cs,
String[] args,
int i,
boolean showHidden)
throws ShellException, RemoteException {
ParameterMap map = null;
ParameterState.Info info = null;
ParameterState.Scope scope;
if (serviceName != null) {
map = getServiceMap(cs);
scope = null; /* allow any scope */
if (map.getType().equals(ParameterState.REPNODE_TYPE)) {
info = ParameterState.Info.REPNODE;
} else if (map.getType().equals(ParameterState.SNA_TYPE)) {
info = ParameterState.Info.SNA;
} else {
info = ParameterState.Info.ADMIN;
}
} else {
scope = ParameterState.Scope.STORE;
map = new ParameterMap();
if (allRN) {
map.setType(ParameterState.REPNODE_TYPE);
info = ParameterState.Info.REPNODE;
} else if (allSN) {
map.setType(ParameterState.SNA_TYPE);
info = ParameterState.Info.SNA;
} else if (global) {
map.setType(ParameterState.GLOBAL_TYPE);
info = ParameterState.Info.GLOBAL;
} else if (security) {
map.setType(ParameterState.GLOBAL_TYPE);
info = ParameterState.Info.GLOBAL;
} else {
map.setType(ParameterState.ADMIN_TYPE);
info = ParameterState.Info.ADMIN;
}
}
CommandUtils.parseParams(map, args, i, info, scope,
showHidden, this);
return map;
}
}
@POST
static final class ChangeUserSub extends PlanSubCommand {
static final String COMMAND_SYNTAX =
"plan change-user -name [-disable | -enable]" +
eolt + "[-set-password [-password ] " +
"[-retain-current-password]]" + eolt +
"[-clear-retained-password]" + genericFlags;
static final String COMMAND_DESC =
"Change a user with the specified name in the store. " +
"The" + eolt + "-retain-current-password argument option " +
"causes the current password to" + eolt + "be remembered " +
"during the -set-password operation as a valid alternate " +
eolt + "password for configured retention time or until" +
" cleared using -clear-retained-password." + eolt +
"If a retained password has already been set for the user," +
eolt + "setting retained password again will cause an " +
"error to be reported.";
static final String changeUserCommandDeprecation =
"The command:" + eol + eolt +
"plan change-user" + eol + eol +
"is deprecated and has been replaced by:" + eol + eolt +
"execute \'ALTER USER\'" + eol + eol;
static final String RETAIN_FLAG = "-retain-current-password";
static final String CLEAR_FLAG = "-clear-retained-password";
static final String DISABLE_FLAG = "-disable";
static final String ENABLE_FLAG = "-enable";
static final String SET_PASSWORD_FLAG = "-set-password";
static final String PASSWORD_FLAG = "-password";
static final String NAME_FLAG = "-name";
ChangeUserSub() {
super("change-user", 10);
}
/** This is a deprecated command. Return true. */
@Override
protected boolean isDeprecated() {
return true;
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
return new ChangeUserExecutor() {
@Override
public String nothingChange(String text)
throws ShellException {
return changeUserCommandDeprecation + text;
}
@Override
public String PlanResult(int planId,
CommandServiceAPI cs,
Shell commandShell)
throws ShellException, RemoteException {
return changeUserCommandDeprecation +
executePlan(planId, cs, commandShell);
}
}.commonExecute(args, shell);
}
private abstract class
ChangeUserExecutor implements Executor {
@Override
public T commonExecute(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, ChangeUserSub.this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
/* Flags for change options */
String userName = null;
String password = null;
boolean retainPassword = false;
boolean clearRetainedPassword = false;
boolean changePassword = false;
char[] newPlainPassword = null;
/* Use boxed boolean to help identify non-changed user state */
Boolean isEnabled = null;
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if (NAME_FLAG.equals(arg)) {
userName =
Shell.nextArg(args, i++, ChangeUserSub.this);
} else if (PASSWORD_FLAG.equals(arg)) {
password =
Shell.nextArg(args, i++, ChangeUserSub.this);
} else if (SET_PASSWORD_FLAG.equals(arg)) {
changePassword = true;
} else if (DISABLE_FLAG.equals(arg)) {
isEnabled = false;
} else if (ENABLE_FLAG.equals(arg)) {
isEnabled = true;
} else if (RETAIN_FLAG.equals(arg)) {
retainPassword = true;
} else if (CLEAR_FLAG.equals(arg)) {
clearRetainedPassword = true;
} else {
i += checkGenericArg(arg, args, i);
}
}
if (userName == null) {
shell.requiredArg(NAME_FLAG, ChangeUserSub.this);
}
if (password != null && !changePassword) {
throw new ShellArgumentException(
"Option -password is only valid in conjunction " +
"with -set-password.");
}
if (retainPassword && !changePassword) {
throw new ShellArgumentException(
"Option -retain-current-password is only valid in " +
"conjunction with -set-password.");
}
/* Nothing changes */
if (isEnabled == null &&
!changePassword && !clearRetainedPassword) {
return nothingChange(
"Nothing changed for user " + userName);
}
/* Get new password from user input */
if (changePassword) {
if (password != null) {
if (password.isEmpty()) {
throw new ShellArgumentException(
"Password may not be empty");
}
newPlainPassword = password.toCharArray();
} else {
/* No interactive mode in JSON mode */
if (shell.getJson() || shell.getJsonV1()) {
throw new ShellArgumentException(
"Password may not be empty");
}
final PasswordReader READER =
new ShellPasswordReader();
newPlainPassword =
CommandUtils.getPasswordFromInput(
READER, ChangeUserSub.this);
}
}
try {
final int planId =
cs.createChangeUserPlan(
planName, userName, isEnabled,
newPlainPassword, retainPassword,
clearRetainedPassword);
SecurityUtils.clearPassword(newPlainPassword);
return PlanResult(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return null;
}
public abstract T nothingChange(String text)
throws ShellException;
public abstract T
PlanResult(int planId,
CommandServiceAPI cs,
Shell commandShell)
throws ShellException, RemoteException;
}
@Override
public ShellCommandResult
execJsonOutput(String[] args, Shell shell)
throws ShellException {
final ShellCommandResult scr =
ShellCommandResult.getDefault("change user plan");
return new ChangeUserExecutor() {
@Override
public ShellCommandResult nothingChange(String text)
throws ShellException {
scr.setDescription(text);
return scr;
}
@Override
public ShellCommandResult PlanResult(int planId,
CommandServiceAPI cs,
Shell commandShell)
throws ShellException, RemoteException {
return filterJsonResult(
executePlan(planId, cs, commandShell));
}
}.commonExecute(args, shell);
}
@Override
protected String getCommandSyntax() {
return COMMAND_SYNTAX;
}
@Override
protected String getCommandDescription() {
return COMMAND_DESC + eol + eolt +
"This command is deprecated and has been replaced by:" +
eol + eolt + "execute \'ALTER USER\'";
}
}
@POST
static final class CreateUserSub extends PlanSubCommand {
static final String COMMAND_SYNTAX =
"plan create-user -name [-admin] [-disable]" +
eolt + "[-password ]" + genericFlags;
static final String COMMAND_DESC =
"Create a user with the specified name in the store." +
eolt + "The -admin argument indicates that the created " +
"user has full " + eolt + "administrative privileges.";
static final String createUserCommandDeprecation =
"The command:" + eol + eolt +
"plan create-user" + eol + eol +
"is deprecated and has been replaced by:" + eol + eolt +
"execute \'CREATE USER\'" + eol + eol;
static final String DISABLE_FLAG = "-disable";
static final String ADMIN_FLAG = "-admin";
static final String NAME_FLAG = "-name";
static final String PASSWORD_FLAG = "-password";
CreateUserSub() {
super("create-user", 10);
}
/** This is a deprecated command. Return true. */
@Override
protected boolean isDeprecated() {
return true;
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
if (shell.getJson()) {
return executeCommand(args, shell);
}
return createUserCommandDeprecation + executeCommand(args, shell);
}
private String executeCommand(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
String userName = null;
String password = null;
boolean isAdmin = false;
boolean isEnabled = true;
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if (NAME_FLAG.equals(arg)) {
userName = Shell.nextArg(args, i++, this);
} else if (PASSWORD_FLAG.equals(arg)) {
password = Shell.nextArg(args, i++, this);
} else if (ADMIN_FLAG.equals(arg)) {
isAdmin = true;
} else if (DISABLE_FLAG.equals(arg)) {
isEnabled = false;
} else {
i += checkGenericArg(arg, args, i);
}
}
if (userName == null ) {
shell.requiredArg(NAME_FLAG, this);
}
/* Get password from user input. */
char[] plainPasswd;
if (password != null) {
if (password.isEmpty()) {
throw new ShellArgumentException(
"Password may not be empty");
}
plainPasswd = password.toCharArray();
} else {
/* No interactive mode in JSON mode */
if (shell.getJson() || shell.getJsonV1()) {
throw new ShellArgumentException(
"Password may not be empty");
}
final PasswordReader READER = new ShellPasswordReader();
plainPasswd =
CommandUtils.getPasswordFromInput(READER, this);
}
try {
final int planId =
cs.createCreateUserPlan(planName, userName, isEnabled,
isAdmin, plainPasswd);
SecurityUtils.clearPassword(plainPasswd);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return COMMAND_SYNTAX;
}
@Override
protected String getCommandDescription() {
return COMMAND_DESC + eol + eolt +
"This command is deprecated and has been replaced by:" +
eol + eolt + "execute \'CREATE USER\'";
}
}
@POST
static final class DeployAdminSub extends PlanSubCommand {
static final String COMMAND_SYNTAX =
"plan deploy-admin -sn " +
eolt + genericFlags;
static final String COMMAND_DESC =
"Deploys an Admin to the specified storage node.";
DeployAdminSub() {
super("deploy-admin", 10);
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
StorageNodeId snid = null;
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if ("-port".equals(arg)) {
shell.echo("WARNING: the -port argument is obsolete " +
"and was benignly ignored." + Shell.eol);
/* Consume the obsolete arg that should follow -port*/
Shell.nextArg(args, i++, this);
} else if ("-sn".equals(arg)) {
final String argString = Shell.nextArg(args, i++, this);
snid = parseSnid(argString);
} else {
i += checkGenericArg(arg, args, i);
}
}
if (snid == null) {
shell.requiredArg(null, this);
}
try {
final int planId =
cs.createDeployAdminPlan(planName, snid,
null /* default to zone type */);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return COMMAND_SYNTAX;
}
@Override
protected String getCommandDescription() {
return COMMAND_DESC;
}
}
@POST
static final class DropUserSub extends PlanSubCommand {
static final String COMMAND_SYNTAX =
"plan drop-user -name " + genericFlags;
static final String COMMAND_DESC =
"Drop a user with the specified name in the store. A" +
eolt + "logged-in user may not drop itself.";
static final String dropUserCommandDeprecation =
"The command:" + eol + eolt +
"plan drop-user" + eol + eol +
"is deprecated and has been replaced by:" + eol + eolt +
"execute \'DROP USER\'" + eol + eol;
DropUserSub() {
super("drop-user", 7);
}
/** This is a deprecated command. Return true. */
@Override
protected boolean isDeprecated() {
return true;
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
if (shell.getJson()) {
return executeCommand(args, shell);
}
return dropUserCommandDeprecation + executeCommand(args, shell);
}
private String executeCommand(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
String userName = null;
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if ("-name".equals(arg)) {
userName = Shell.nextArg(args, i++, this);
} else {
i += checkGenericArg(arg, args, i);
}
}
if (userName == null) {
shell.requiredArg("-name", this);
}
try {
/*
* For failure recovery, execute the plan even though the user
* to drop does not exist.
*/
final int planId =
cs.createDropUserPlan(planName, userName);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return COMMAND_SYNTAX;
}
@Override
protected String getCommandDescription() {
return COMMAND_DESC + eol + eolt +
"This command is deprecated and has been replaced by:" +
eol + eolt + "execute \'DROP USER\'";
}
}
@POST
static final class RemoveAdminSub extends PlanSubCommand {
final String adminDcError =
"Invalid argument combination: -admin flag cannot be used " +
"with -zn, -znname, -dc, or -dcname flag";
final String dcIdNameError =
"Invalid argument combination: must use only one of the -zn," +
" -znname, -dc, or -dcname flags";
final String commandSyntax =
"plan remove-admin -admin | -zn | -znname " +
genericFlags;
/*
* TODO: Add hidden parameter support for -failed-sn in
* command syntax.
*/
final String commandDesc =
"Removes the desired Admin instances; either the single" +
eolt +
"specified instance, or all instances deployed to the specified" +
eolt +
"zone. If the -admin flag is used and there are 3 or " +
eolt +
"fewer Admins running in the store, or if the -zn or -znname" +
eolt +
"flag is used and the removal of all Admins from the specified" +
eolt +
"zone would result in only one or two Admins in the store," +
eolt +
"then the desired Admins will be removed only if the -force" +
eolt +
"flag is also specified. Additionally, if the -admin flag is" +
eolt +
"used and there is only one Admin in the store, or if the -zn or" +
eolt +
"-znname flag is used and the removal of all Admins from the" +
eolt +
"specified zone would result in the removal of all Admins" +
eolt +
"from the store, then the desired Admins will not be removed.";
/*
* TODO: Add hidden parameter support for -failed-sn in
* command description.
*/
final String noAdminError =
"There is no Admin in the store with the specified id ";
final String only1AdminError =
"Only one Admin in the store, so cannot remove the sole Admin ";
final String tooFewAdminError =
"Removing the specified Admin will result in fewer than 3" +
eolt +
"Admins in the store; which is strongly discouraged because" +
eolt +
"the loss of one of the remaining Admins will cause quorum" +
eolt +
"to be lost. If you still wish to remove the desired Admin," +
eolt +
"specify the -force flag. ";
final String noAdminDcError =
"There are no Admins in the specified zone ";
final String allAdminDcError =
"The specified zone contains all the Admins in the store," +
eolt +
"and so cannot be removed from the specified zone ";
final String tooFewAdminDcError =
"Removing all Admins from the specified zone will result" +
eolt +
"in fewer than 3 Admins in the store; which is strongly" +
eolt +
"discouraged because the loss of one of the remaining Admins " +
eolt +
"will cause quorum to be lost. If you still wish to remove" +
eolt +
"all of the Admins from the desired zone, specify the" +
eolt +
"-force flag. ";
RemoveAdminSub() {
super("remove-admin", 10);
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
AdminId aid = null;
DatacenterId dcid = null;
String dcName = null;
boolean getDcId = false;
boolean deprecatedDcFlag = false;
boolean failedSN = false;
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if ("-admin".equals(arg)) {
final String argString = Shell.nextArg(args, i++, this);
aid = parseAdminid(argString);
} else if (CommandUtils.isDatacenterIdFlag(arg)) {
dcid = DatacenterId.parse(Shell.nextArg(args, i++, this));
if (CommandUtils.isDeprecatedDatacenterId(arg, args[i])) {
deprecatedDcFlag = true;
}
} else if (CommandUtils.isDatacenterNameFlag(arg)) {
dcName = Shell.nextArg(args, i++, this);
if (CommandUtils.isDeprecatedDatacenterName(arg)) {
deprecatedDcFlag = true;
}
} else if ("-failed-sn".equals(arg)) {
failedSN = true;
} else {
i += checkGenericArg(arg, args, i);
}
}
/* Verify argument combinations */
if (aid == null) {
if (dcid == null) {
if (dcName == null) {
shell.requiredArg(null, this);
} else {
getDcId = true;
}
} else {
if (dcName != null) {
throw new ShellUsageException(dcIdNameError, this);
}
}
} else {
if (dcid != null || dcName != null) {
throw new ShellUsageException(adminDcError, this);
}
}
final String deprecatedDcFlagPrefix =
deprecatedDcFlag ? dcFlagsDeprecation : "";
/*
* If admin count is low, there are restrictions.
*/
Parameters parameters = null;
try {
parameters = cs.getParameters();
} catch (RemoteException re) {
cmd.noAdmin(re);
return "";
}
final int nAdmins = parameters.getAdminCount();
if (aid != null) {
if (parameters.get(aid) == null) {
throw new ShellArgumentException(
noAdminError + "[" + aid + "]");
}
if (nAdmins == 1) {
throw new ShellArgumentException(
only1AdminError + "[" + aid + "]");
}
if (nAdmins < 4 && !force) {
throw new ShellArgumentException(
tooFewAdminError + "There are only " + nAdmins +
" Admins in the store.");
}
} else {
final Set adminIdSet;
try {
if (getDcId) {
dcid = CommandUtils.getDatacenterId(dcName, cs, this);
}
adminIdSet =
parameters.getAdminIds(dcid, cs.getTopology());
} catch (RemoteException re) {
cmd.noAdmin(re);
return "";
}
String dcErrStr = "";
if (dcName != null) {
dcErrStr = dcName;
} else if (dcid != null) {
dcErrStr = dcid.toString();
}
if (adminIdSet.isEmpty()) {
throw new ShellArgumentException(
noAdminDcError + "[" + dcErrStr + "]");
}
if (adminIdSet.size() == nAdmins) {
throw new ShellArgumentException(
allAdminDcError + "[" + dcErrStr + "]");
}
if (nAdmins - adminIdSet.size() < 3 && !force) {
throw new ShellArgumentException(
tooFewAdminDcError + "There are " + nAdmins +
" Admins in the store and " + adminIdSet.size() +
" Admins in the specified zone " +
"[" + dcErrStr + "]");
}
}
try {
final int planId =
cs.createRemoveAdminPlan(planName, dcid, aid, failedSN);
if (shell.getJson()) {
return executePlan(planId, cs, shell);
}
return deprecatedDcFlagPrefix + executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return commandSyntax;
}
@Override
protected String getCommandDescription() {
return commandDesc;
}
}
@POST
static final class DeployDCSub extends DeployZoneSub {
static final String dcCommandDeprecation =
"The command:" + eol + eolt +
"plan deploy-datacenter" + eol + eol +
"is deprecated and has been replaced by:" + eol + eolt +
"plan deploy-zone" + eol + eol;
DeployDCSub() {
super("deploy-datacenter", 10);
}
/** This is a deprecated command. Return true. */
@Override
protected boolean isDeprecated() {
return true;
}
/** Add deprecation message. */
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
if (shell.getJson()) {
super.exec(args, shell);
}
return dcCommandDeprecation + super.exec(args, shell);
}
/** Add deprecation message. */
@Override
public String getCommandDescription() {
return super.getCommandDescription() + eol + eolt +
"This command is deprecated and has been replaced by:" +
eol + eolt +
"plan deploy-zone";
}
}
@POST
static class DeployZoneSub extends PlanSubCommand {
DeployZoneSub() {
super("deploy-zone", 10);
}
DeployZoneSub(final String name, final int prefixMatchLength) {
super(name, prefixMatchLength);
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
String dcName = null;
int rf = -1;
DatacenterType type = DatacenterType.PRIMARY;
boolean allowArbiters = false;
boolean masterAffinity = false;
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if ("-name".equals(arg)) {
dcName = Shell.nextArg(args, i++, this);
} else if ("-rf".equals(arg)) {
final String argString = Shell.nextArg(args, i++, this);
rf = parseUnsignedInt(argString);
} else if ("-type".equals(arg)) {
final String typeValue = Shell.nextArg(args, i++, this);
type = parseDatacenterType(typeValue);
} else if ("-arbiters".equals(arg)) {
allowArbiters = true;
} else if ("-no-arbiters".equals(arg)) {
allowArbiters = false;
} else if ("-master-affinity".equals(arg)) {
masterAffinity = true;
} else if ("-no-master-affinity".equals(arg)) {
masterAffinity = false;
} else {
i += checkGenericArg(arg, args, i);
}
}
if (rf == 0 && !allowArbiters) {
throw new ShellUsageException("Zone " + dcName +
" was specified with RF equal to zero and no-arbiters.",
this);
}
if (rf == -1) {
shell.requiredArg("rf", this);
}
if (dcName == null) {
shell.requiredArg("name", this);
}
try {
final int planId = cs.createDeployDatacenterPlan(
planName, dcName, rf, type, allowArbiters, masterAffinity);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return "plan " + name + " -name " +
eolt + "-rf " +
eolt + "[-type {primary | secondary}]" +
eolt + "[-arbiters | -no-arbiters]" +
eolt + "[-master-affinity | -no-master-affinity]" +
eolt + genericFlags;
}
@Override
protected String getCommandDescription() {
return
"Deploys the specified zone to the store," + eolt +
"creating a primary zone if -type is not specified.";
}
}
@POST
static final class DeploySNSub extends PlanSubCommand {
DeploySNSub() {
super("deploy-sn", 9);
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
DatacenterId dcid = null;
String host = null;
String dcName = null;
int port = 0;
boolean deprecatedDcFlag = false;
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if ("-host".equals(arg)) {
host = Shell.nextArg(args, i++, this);
} else if ("-port".equals(arg)) {
final String argString = Shell.nextArg(args, i++, this);
port = parseUnsignedInt(argString);
} else if (CommandUtils.isDatacenterIdFlag(arg)) {
dcid = DatacenterId.parse(Shell.nextArg(args, i++, this));
if (CommandUtils.isDeprecatedDatacenterId(arg, args[i])) {
deprecatedDcFlag = true;
}
} else if (CommandUtils.isDatacenterNameFlag(arg)) {
dcName = Shell.nextArg(args, i++, this);
if (CommandUtils.isDeprecatedDatacenterName(arg)) {
deprecatedDcFlag = true;
}
} else {
i += checkGenericArg(arg, args, i);
}
}
final String deprecatedDcFlagPrefix =
deprecatedDcFlag ? dcFlagsDeprecation : "";
if ((dcid == null && dcName == null) ||
host == null || port == 0) {
shell.requiredArg(null, this);
}
try {
if (dcid == null) {
dcid = CommandUtils.getDatacenterId(dcName, cs, this);
}
final int planId = cs.createDeploySNPlan(planName, dcid,
host, port, null);
String status = executePlan(planId, cs, shell);
if (shell.getJson()) {
return status;
}
return deprecatedDcFlagPrefix + status;
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return "plan deploy-sn -zn | -znname " +
"-host -port " +
eolt + genericFlags;
}
@Override
protected String getCommandDescription() {
return
"Deploys the storage node at the specified host and port " +
"into the" + eolt + "specified zone.";
}
}
@POST
static final class DeployTopologySub extends PlanSubCommand {
DeployTopologySub() {
super("deploy-topology", 10);
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
String topoName = null;
RepGroupId failedShard = null;
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if ("-name".equals(arg)) {
topoName = Shell.nextArg(args, i++, this);
} else if ("-failed-shard".equals(arg)) {
failedShard =
RepGroupId.parse(Shell.nextArg(args, i++,this));
} else {
i += checkGenericArg(arg, args, i);
}
}
if (topoName == null) {
shell.requiredArg("-name", this);
}
try {
if (failedShard != null) {
/* Ensure RNs of the failed shard are not running*/
Topology currentTopo = cs.getTopology();
Map statusMap =
cs.getStatusMap();
CommandUtils.ensureRNNotRunning(failedShard, currentTopo,
statusMap, this);
}
final int planId = cs.createDeployTopologyPlan(planName,
topoName,
failedShard);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return "plan deploy-topology -name " +
genericFlags;
/*
* TODO: Add hidden parameter support for -failed-shard
* in getCommandSyntax.
*/
}
@Override
protected String getCommandDescription() {
return
"Deploys the specified topology to the store. This " +
"operation can" + eolt + "take a while, depending on " +
"the size and state of the store.";
}
}
@POST
static final class RepairTopologySub extends PlanSubCommand {
RepairTopologySub() {
super("repair-topology", 4);
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
i += checkGenericArg(arg, args, i);
}
try {
final int planId = cs.createRepairPlan(planName);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return "plan repair-topology " + genericFlags;
}
@Override
protected String getCommandDescription() {
return
"Inspects the store's deployed, current topology for " +
"inconsistencies" + eolt +
"in location metadata that may have arisen from the " +
"interruption" + eolt +
"or cancellation of previous deploy-topology or migrate-sn " +
"plans. Where " + eolt +
"possible, inconsistencies are repaired. This operation can"
+ eolt + "take a while, depending on the size and state of " +
"the store.";
}
}
@POST
static final class ExecuteSub extends PlanSubCommand {
ExecuteSub() {
super("execute", 3);
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
int planId = 0;
try {
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if ("-id".equals(arg)) {
final String argString =
Shell.nextArg(args, i++, this);
planId = parseUnsignedInt(argString);
} else if ("-last".equals(arg)) {
planId = getLastPlanId(cs);
if (planId == 0) {
throw new ShellArgumentException(
lastPlanNotFound);
}
} else {
i += checkGenericArg(arg, args, i);
}
}
if (planId == 0) {
shell.requiredArg("-id|-last", this);
}
CommandUtils.ensurePlanExists(planId, cs, this);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return "plan execute -id | -last" + genericFlags;
}
@Override
protected String getCommandDescription() {
return
"Executes a created, but not yet executed plan. The plan " +
"must have" + eolt + "been previously created using the " +
"-noexecute flag. Use -last to" + eolt + "reference the " +
"most recently created plan.";
}
}
@POST
static class FailoverSub extends PlanSubCommand {
FailoverSub() {
/* For safety, no abbreviation. */
super("failover", 8);
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = getAdmin(cmd);
final Set primaryZones = new HashSet<>();
final Set offlineZones = new HashSet<>();
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
String zoneName = null;
DatacenterId dcId = null;
if ("-zn".equals(arg)) {
zoneName = Shell.nextArg(args, i++, this);
dcId = parseDatacenterId(zoneName);
} else if ("-znname".equals(arg)) {
zoneName = Shell.nextArg(args, i++, this);
dcId = getDatacenterId(cmd, cs, zoneName);
} else {
i += checkGenericArg(arg, args, i);
continue;
}
if (++i >= args.length) {
shell.requiredArg("-type", this);
}
final String typeFlag = args[i];
if ("-type".equals(typeFlag)) {
final String type = Shell.nextArg(args, i++, this);
if ("primary".equals(type)) {
primaryZones.add(dcId);
} else if ("offline-secondary".equals(type)) {
offlineZones.add(dcId);
} else {
invalidArgument(type);
}
if (primaryZones.contains(dcId) &&
offlineZones.contains(dcId)) {
throw new ShellUsageException(
"Zone " + zoneName +
" was specified with multiple types",
this);
}
} else {
shell.requiredArg("-type", this);
}
}
if (offlineZones.isEmpty()) {
throw new ShellUsageException(
"Must specify at least one offline-secondary zone", this);
}
return failover(cmd, cs, primaryZones, offlineZones);
}
/** Make getAdmin call through a method to simplify testing. */
CommandServiceAPI getAdmin(CommandShell cmd)
throws ShellException {
return cmd.getAdmin();
}
/**
* Make datacenter name conversion call through a method to simplify
* testing.
*/
DatacenterId getDatacenterId(CommandShell cmd,
CommandServiceAPI cs,
String dcName)
throws ShellException {
try {
return CommandUtils.getDatacenterId(dcName, cs, this);
} catch (RemoteException re) {
cmd.noAdmin(re);
throw new AssertionError("Not reached");
}
}
/** Make failover call through a method to simplify testing. */
String failover(CommandShell cmd, CommandServiceAPI cs,
Set primaryZones,
Set offlineZones)
throws ShellException {
try {
final int planId = cs.createFailoverPlan(
planName, primaryZones, offlineZones);
return executePlan(planId, cs, cmd);
} catch (RemoteException re) {
cmd.noAdmin(re);
throw new AssertionError("Not reached");
}
}
@Override
protected String getCommandSyntax() {
return "plan failover" + eolt +
"{ {-zn |-znname }" +
" -type {primary|offline-secondary} }..." +
genericFlags;
}
@Override
protected String getCommandDescription() {
return "Changes zone types to failover to a changed set of" +
" primary" + eolt + "zones following a failure of primary" +
" zones that has resulted in a loss of" + eolt + "quorum.";
}
}
@POST
static final class GrantSub extends PlanSubCommand {
static final String USER_FLAG = "-user";
static final String ROLE_FLAG = "-role";
static final String COMMAND_SYNTAX =
"plan grant -user [-role ]*" + genericFlags;
static final String COMMAND_DESC =
"Grant roles to a user with specified name. The -role option " +
"accepts" + eolt + "only predefined roles in KVStore currently.";
static final String grantCommandDeprecation =
"The command:" + eol + eolt +
"plan grant" + eol + eol +
"is deprecated and has been replaced by:" + eol + eolt +
"execute \'GRANT\'" + eol + eol;
GrantSub() {
super("grant", 3);
}
/** This is a deprecated command. Return true. */
@Override
protected boolean isDeprecated() {
return true;
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
if (shell.getJson()) {
return executeCommand(args, shell);
}
return grantCommandDeprecation + executeCommand(args, shell);
}
private String executeCommand(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
final Set roles = new HashSet<>();
String userName = null;
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if (USER_FLAG.equals(arg)) {
userName = Shell.nextArg(args, i++, this);
} else if (ROLE_FLAG.equals(arg)) {
final String role = Shell.nextArg(args, i++, this);
roles.add(role.toLowerCase());
} else {
i += checkGenericArg(arg, args, i);
}
}
if (userName == null) {
shell.requiredArg(USER_FLAG, this);
}
if (roles.isEmpty()) {
shell.requiredArg(ROLE_FLAG, this);
}
try {
final int planId =
cs.createGrantPlan(planName, userName, roles);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return COMMAND_SYNTAX;
}
@Override
protected String getCommandDescription() {
return COMMAND_DESC + eol + eolt +
"This command is deprecated and has been replaced by:" +
eol + eolt + "execute \'GRANT\'";
}
}
@POST
static final class InterruptSub extends InterruptCancelSub {
InterruptSub() {
super("interrupt", 3, true);
}
@Override
protected String getCommandSyntax() {
return "plan interrupt -id | -last " +
CommandParser.getJsonUsage();
}
@Override
protected String getCommandDescription() {
return
"Interrupts a running plan. An interrupted plan can " +
"only be re-executed" + eolt + "or canceled. Use -last " +
"to reference the most recently" + eolt + "created plan.";
}
}
@POST
static final class CancelSub extends InterruptCancelSub {
CancelSub() {
super("cancel", 3, false);
}
@Override
protected String getCommandSyntax() {
return "plan cancel -id | -last " +
CommandParser.getJsonUsage();
}
@Override
protected String getCommandDescription() {
return
"Cancels a plan that is not running. A running plan " +
"must be" + eolt + "interrupted before it can be canceled. " +
"Use -last to reference the most" + eolt + "recently " +
"created plan.";
}
}
/*
* Put interrupt/cancel into same code.
*/
abstract static class InterruptCancelSub extends PlanSubCommand {
private final boolean isInterrupt;
protected InterruptCancelSub(String name, int prefixMatchLength,
boolean isInterrupt) {
super(name, prefixMatchLength);
this.isInterrupt = isInterrupt;
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
return new InterruptCancelExecutor() {
@Override
public String successDescription(String text)
throws ShellException {
return text;
}
@Override
public String failureDescription(String text)
throws ShellException {
return text;
}
}.commonExecute(args, shell);
}
private abstract class
InterruptCancelExecutor implements Executor {
@Override
public T commonExecute(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, InterruptCancelSub.this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
int planId = 0;
try {
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if ("-id".equals(arg)) {
final String argString =
Shell.nextArg(
args, i++, InterruptCancelSub.this);
planId = parseUnsignedInt(argString);
} else if ("-last".equals(arg)) {
planId = getLastPlanId(cs);
if (planId == 0) {
return failureDescription(lastPlanNotFound);
}
} else {
shell.unknownArgument(
arg, InterruptCancelSub.this);
}
}
if (planId == 0) {
shell.requiredArg(
"-id|-last", InterruptCancelSub.this);
}
CommandUtils.ensurePlanExists(
planId, cs, InterruptCancelSub.this);
if (isInterrupt) {
cs.interruptPlan(planId);
return successDescription(
"Plan " + planId + " was interrupted");
}
cs.cancelPlan(planId);
return successDescription(
"Plan " + planId + " was canceled");
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return null;
}
public abstract T successDescription(String text)
throws ShellException;
public abstract T failureDescription(String text)
throws ShellException;
}
@Override
public ShellCommandResult execJsonOutput(String[] args,
Shell shell)
throws ShellException {
final ShellCommandResult scr =
ShellCommandResult.getDefault("plan cancel|interrupt");
return new InterruptCancelExecutor() {
@Override
public ShellCommandResult successDescription(String text)
throws ShellException {
scr.setDescription(text);
return scr;
}
@Override
public ShellCommandResult failureDescription(String text)
throws ShellException {
scr.setReturnCode(ErrorMessage.NOSQL_5100.getValue());
scr.setDescription(text);
return scr;
}
}.commonExecute(args, shell);
}
}
@POST
static final class MigrateSNSub extends PlanSubCommand {
MigrateSNSub() {
super("migrate-sn", 7);
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
StorageNodeId fromSnid = null;
StorageNodeId toSnid = null;
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if ("-from".equals(arg)) {
final String argString = Shell.nextArg(args, i++, this);
fromSnid = parseSnid(argString);
} else if ("-to".equals(arg)) {
final String argString = Shell.nextArg(args, i++, this);
toSnid = parseSnid(argString);
} else if ("-admin-port".equals(arg)) {
shell.echo(
"WARNING: the -admin-port argument is obsolete " +
"and was benignly ignored." + Shell.eol);
/* Consume the obsolete arg that should follow -admin-port*/
Shell.nextArg(args, i++, this);
} else {
i += checkGenericArg(arg, args, i);
}
}
if (fromSnid == null || toSnid == null) {
shell.requiredArg(null, this);
}
try {
/*
* If the old SN hosted an admin with an admin web service,
* the port arg is required
*/
CommandUtils.ensureStorageNodeExists(fromSnid, cs, this);
CommandUtils.ensureStorageNodeExists(toSnid, cs, this);
final int planId =
cs.createMigrateSNPlan(planName, fromSnid, toSnid);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return "plan migrate-sn -from -to " + genericFlags;
}
@Override
protected String getCommandDescription() {
return
"Migrates the services from one storage node to another. " +
"The old node" + eolt + "must not be running.";
}
}
@POST
static final class NetworkRestoreSub extends PlanSubCommand {
static String COMMAND_NAME = "network-restore";
static String SOURCE_ID_FLAG = "-from";
static String TARGET_ID_FLAG = "-to";
static String RETAIN_LOG_FLAG = "-retain-logs";
static String COMMAND_DESC = "Network restore a RepNode from " +
"another one in their replication group.";
static String COMMAND_SYNTAX =
"plan network-restore -from -to -retain-logs" +
genericFlags;
NetworkRestoreSub() {
super(COMMAND_NAME, 7);
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
RepNodeId sourceNode = null;
RepNodeId targetNode = null;
boolean retainOrigLog = false;
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if (SOURCE_ID_FLAG.equals(arg)) {
final String argString = Shell.nextArg(args, i++, this);
sourceNode = parseRnid(argString);
} else if (TARGET_ID_FLAG.equals(arg)) {
final String argString = Shell.nextArg(args, i++, this);
targetNode = parseRnid(argString);
} else if (RETAIN_LOG_FLAG.equals(arg)) {
retainOrigLog = true;
} else {
i += checkGenericArg(arg, args, i);
}
}
if (sourceNode == null) {
shell.requiredArg(SOURCE_ID_FLAG, this);
}
if (targetNode == null) {
shell.requiredArg(TARGET_ID_FLAG, this);
}
try {
CommandUtils.ensureRepNodeExists(sourceNode, cs, this);
CommandUtils.ensureRepNodeExists(targetNode, cs, this);
final int planId = cs.createNetworkRestorePlan(
planName, sourceNode, targetNode, retainOrigLog);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return COMMAND_SYNTAX;
}
@Override
protected String getCommandDescription() {
return COMMAND_DESC;
}
}
@POST
static final class RemoveSNSub extends PlanSubCommand {
RemoveSNSub() {
super("remove-sn", 9);
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
StorageNodeId snid = null;
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if ("-sn".equals(arg)) {
final String argString = Shell.nextArg(args, i++, this);
snid = parseSnid(argString);
} else {
i += checkGenericArg(arg, args, i);
}
}
if (snid == null) {
shell.requiredArg("-sn", this);
}
try {
CommandUtils.ensureStorageNodeExists(snid, cs, this);
final int planId = cs.createRemoveSNPlan(planName, snid);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return "plan remove-sn -sn " + genericFlags;
}
@Override
protected String getCommandDescription() {
return
"Removes the specified storage node from the topology.";
}
}
@POST
static final class StartServiceSub extends StartStopServiceSub {
StartServiceSub() {
super("start-service", 4, true);
}
@Override
protected String getCommandSyntax() {
return "plan start-service" +
" {-service | -all-rns [-zn | -znname ]" +
" | -all-ans [-zn | -znname ]" +
" | -zn | -znname }" + genericFlags;
}
@Override
protected String getCommandDescription() {
return "Starts the specified service(s).";
}
}
@POST
static final class StopServiceSub extends StartStopServiceSub {
StopServiceSub() {
super("stop-service", 4, false);
}
@Override
protected String getCommandSyntax() {
return "plan stop-service" +
" {-service | -all-rns [-zn | -znname ]" +
" | -all-ans [-zn | -znname ]" +
" | -zn | -znname }" + genericFlags;
}
@Override
protected String getCommandDescription() {
return "Stops the specified service(s).";
}
}
/*
* Start/stop specified services
*/
abstract static class StartStopServiceSub extends PlanSubCommand {
private final Set serviceIds= new HashSet<>();
private final boolean isStart;
protected StartStopServiceSub(String name, int prefixMatchLength,
boolean isStart) {
super(name, prefixMatchLength);
this.isStart = isStart;
}
/*
* Adds all the replicationNode IDs given the zoneId (datacenterId)
*/
private void getRepNodesByZoneId(Topology topology, String zoneId)
throws ShellException {
final DatacenterId dcId = parseDatacenterId(zoneId);
if (topology.get(dcId) == null) {
throw new IllegalArgumentException("The specified zone id " +
"does not exist");
}
for (RepNodeId rnId : topology.getRepNodeIds(dcId)) {
addService(rnId);
}
}
/*
* Adds all the replicationNode IDs given the zoneName (datacenterName)
*/
private void getRepNodesByZoneName(Topology topology,
String zoneName) {
final Datacenter zone = topology.getDatacenter(zoneName);
if (zone == null) {
throw new IllegalArgumentException("The specified zone name " +
"does not exist");
}
for (RepNodeId rnId : topology.getRepNodeIds(zone.getResourceId())){
addService(rnId);
}
}
/*
* Adds all the ArbNode IDs given the zoneId (datacenterId)
*/
private void getArbNodesByZoneId(Topology topology, String zoneId)
throws ShellException {
final DatacenterId dcId = parseDatacenterId(zoneId);
if (topology.get(dcId) == null) {
throw new IllegalArgumentException("The specified zone id " +
"does not exist");
}
for (ArbNodeId anId : topology.getArbNodeIds(dcId)) {
addService(anId);
}
}
/*
* Adds all the ArbNode IDs given the zoneName (datacenterName)
*/
private void getArbNodesByZoneName(Topology topology,
String zoneName) {
final Datacenter zone = topology.getDatacenter(zoneName);
if (zone == null) {
throw new IllegalArgumentException("The specified zone name " +
"does not exist");
}
for (ArbNodeId rnId : topology.getArbNodeIds(zone.getResourceId())){
addService(rnId);
}
}
/*
* Adds all the ArbNode IDs
*/
private void getAllArbNodes(Topology topology) {
for (ArbNodeId anId : topology.getArbNodeIds(null)) {
addService(anId);
}
}
/*
* Adds all the Admin IDs given the zoneId (datacenterId)
*/
private void getAdminsByZoneId(CommandServiceAPI cs,
DatacenterId zoneId)
throws RemoteException {
final Topology topology = cs.getTopology();
if (topology.get(zoneId) == null) {
throw new IllegalArgumentException("The specified zone id " +
"does not exist");
}
final Parameters p = cs.getParameters();
for (final AdminId aid : p.getAdminIds(zoneId, topology)) {
addService(aid);
}
}
/*
* Adds all the Admin IDs given the zoneName (datacenterName)
*/
private void getAdminsByZoneName(CommandServiceAPI cs, String zoneName)
throws RemoteException {
final Topology topology = cs.getTopology();
final Datacenter zone = topology.getDatacenter(zoneName);
if (zone == null) {
throw new IllegalArgumentException("The specified zone name " +
"does not exist");
}
getAdminsByZoneId(cs, zone.getResourceId());
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
serviceIds.clear();
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
String zoneId = null;
String zoneName = null;
boolean allRNs = false;
boolean allANs = false;
try {
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if ("-service".equals(arg)) {
final String serviceName =
Shell.nextArg(args, i++, this);
addService(serviceName, cs);
} else if ("-all-rns".equals(arg)) {
allRNs = true;
} else if ("-all-ans".equals(arg)) {
allANs = true;
} else if ("-zn".equals(arg)) {
zoneId = Shell.nextArg(args, i++, this);
/* Parse -zname because it was released by accident */
} else if ("-zname".equals(arg) || "-znname".equals(arg)) {
zoneName = Shell.nextArg(args, i++, this);
} else {
i += checkGenericArg(arg, args, i);
}
}
if (!serviceIds.isEmpty()) {
/*
* Since the -service flag was used, make sure no others
* were
*/
if (allRNs) {
throw new ShellUsageException(
"Cannot use -service and -all-rns flags together",
this);
}
if (allANs) {
throw new ShellUsageException(
"Cannot use -service and -all-ans flags together",
this);
}
if ((zoneId != null) || (zoneName != null)) {
throw new ShellUsageException(
"Cannot use -zn or -znname flags with the" +
" -service flag", this);
}
} else if ((zoneId != null) && (zoneName != null)) {
throw new ShellUsageException(
"Cannot use both the -zn and -znname flags", this);
} else if (allRNs) {
/* All RNs (and only RNs) in a zone or the store */
if (zoneId != null) {
getRepNodesByZoneId(cs.getTopology(), zoneId);
} else if (zoneName != null) {
getRepNodesByZoneName(cs.getTopology(), zoneName);
} else {
/* Special case all RNs and only RNs of the store */
final int planId = isStart ?
cs.createStartAllRepNodesPlan(planName) :
cs.createStopAllRepNodesPlan(planName);
return executePlan(planId, cs, shell);
}
} else if (allANs) {
/* All ANs (and only ANs) in a zone or the store */
if (zoneId != null) {
getArbNodesByZoneId(cs.getTopology(), zoneId);
} else if (zoneName != null) {
getArbNodesByZoneName(cs.getTopology(), zoneName);
} else {
/* All ANs and only ANs of the store */
getAllArbNodes(cs.getTopology());
}
} else if (zoneId != null) {
/* All services in the zone */
getRepNodesByZoneId(cs.getTopology(), zoneId);
getAdminsByZoneId(cs, DatacenterId.parse(zoneId));
getArbNodesByZoneId(cs.getTopology(), zoneId);
} else if (zoneName != null) {
/* All services in the zone */
getRepNodesByZoneName(cs.getTopology(), zoneName);
getAdminsByZoneName(cs, zoneName);
getArbNodesByZoneName(cs.getTopology(), zoneName);
} else {
/* Nothing was specified! */
shell.requiredArg("-service|-all-rns|-all-ans|-zn|-znname",
this);
}
/*
* No point in issuing a plan if there are no services.
*/
if (serviceIds.isEmpty()) {
throw new ShellArgumentException(
"No services were found in the specified zone");
}
final int planId = isStart ?
cs.createStartServicesPlan(planName, serviceIds) :
cs.createStopServicesPlan(planName, serviceIds);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
throw new AssertionError("Not reached");
}
}
/*
* Parses the service name and adds the ID to the services. Throws
* ShellException if the name is not a valid service ID or the
* service type is not supported.
*/
private void addService(String serviceName, CommandServiceAPI cs)
throws ShellException, RemoteException {
try {
final RepNodeId rnId = parseRnid(serviceName);
CommandUtils.ensureRepNodeExists(rnId, cs, this);
addService(rnId);
return;
} catch (ShellException ignore) { }
try {
final ArbNodeId anId = parseAnid(serviceName);
CommandUtils.ensureArbNodeExists(anId, cs, this);
addService(anId);
return;
} catch (ShellException ignore) { }
try {
final AdminId adminId = parseAdminid(serviceName);
final Parameters p = cs.getParameters();
if (p.get(adminId) == null) {
throw new ShellUsageException("Admin does not exist: " +
adminId, this);
}
addService(adminId);
return;
} catch (ShellException ignore) { }
throw new ShellException("Unknown or unsupported service: " +
serviceName);
}
private void addService(ResourceId resId) {
serviceIds.add(resId);
}
}
@POST
static final class PlanWaitSub extends PlanSubCommand {
PlanWaitSub() {
super("wait", 3);
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
return new PlanWaitExecutor() {
@Override
public String stateResult(State state, int planId)
throws ShellException {
return state.getWaitMessage(planId);
}
}.commonExecute(args, shell);
}
private abstract class
PlanWaitExecutor implements Executor {
@Override
public T commonExecute(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, PlanWaitSub.this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
int planId = 0;
int timeoutSecs = 0;
try {
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if ("-id".equals(arg)) {
final String argString =
Shell.nextArg(args, i++, PlanWaitSub.this);
planId = parseUnsignedInt(argString);
} else if ("-seconds".equals(arg)) {
final String argString =
Shell.nextArg(args, i++, PlanWaitSub.this);
timeoutSecs = parseUnsignedInt(argString);
} else if ("-last".equals(arg)) {
planId = getLastPlanId(cs);
if (planId == 0) {
throw new ShellArgumentException(
lastPlanNotFound);
}
} else {
shell.unknownArgument(arg, PlanWaitSub.this);
}
}
if (planId == 0) {
shell.requiredArg("-id", PlanWaitSub.this);
}
CommandUtils.ensurePlanExists(
planId, cs, PlanWaitSub.this);
final Plan.State state =
awaitPlan(planId, timeoutSecs,
TimeUnit.SECONDS, cs, shell);
return stateResult(state, planId);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return null;
}
public abstract T stateResult(Plan.State state, int planId)
throws ShellException;
}
@Override
public ShellCommandResult execJsonOutput(String[] args, Shell shell)
throws ShellException {
final ShellCommandResult scr =
ShellCommandResult.getDefault("plan wait");
return new PlanWaitExecutor() {
@Override
public ShellCommandResult
stateResult(State state, int planId)
throws ShellException {
final ObjectNode on = JsonUtils.createObjectNode();
on.put("planId", planId);
on.put("state", state.toString());
scr.setReturnValue(on);
return scr;
}
}.commonExecute(args, shell);
}
@Override
protected String getCommandSyntax() {
return
"plan wait -id | -last [-seconds ] " +
CommandParser.getJsonUsage();
}
@Override
protected String getCommandDescription() {
return
"Waits for the specified plan to complete. If the " +
"optional timeout" + eolt + "is specified, wait that long, " +
"otherwise wait indefinitely. Use -last" + eolt +
"to reference the most recently created plan.";
}
}
@POST
static final class RemoveDatacenterSub extends RemoveZoneSub {
static final String dcCommandDeprecation =
"The command:" + eol + eolt +
"plan remove-datacenter" + eol + eol +
"is deprecated and has been replaced by:" + eol + eolt +
"plan remove-zone" + eol + eol;
RemoveDatacenterSub() {
super("remove-datacenter", 9);
}
/** This is a deprecated command. Return true. */
@Override
protected boolean isDeprecated() {
return true;
}
/** Add deprecation message. */
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
if (shell.getJson()) {
return super.exec(args, shell);
}
return dcCommandDeprecation + super.exec(args, shell);
}
/** Add deprecation message. */
@Override
public String getCommandDescription() {
return super.getCommandDescription() + eol + eolt +
"This command is deprecated and has been replaced by:" +
eol + eolt +
"plan remove-zone";
}
}
@POST
static class RemoveZoneSub extends PlanSubCommand {
static final String ID_FLAG = "-zn";
static final String NAME_FLAG = "-znname";
RemoveZoneSub() {
super("remove-zone", 9);
}
RemoveZoneSub(final String name, final int prefixMatchLength) {
super(name, prefixMatchLength);
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
DatacenterId id = null;
String nameFlag = null;
boolean deprecatedDcFlag = false;
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if (CommandUtils.isDatacenterIdFlag(arg)) {
final String argVal = Shell.nextArg(args, i++, this);
id = parseDatacenterId(argVal);
if (CommandUtils.isDeprecatedDatacenterId(arg, argVal)) {
deprecatedDcFlag = true;
}
} else if (CommandUtils.isDatacenterNameFlag(arg)) {
nameFlag = Shell.nextArg(args, i++, this);
if (CommandUtils.isDeprecatedDatacenterName(arg)) {
deprecatedDcFlag = true;
}
} else {
i += checkGenericArg(arg, args, i);
}
}
if (id == null && nameFlag == null) {
shell.requiredArg(ID_FLAG + " | " + NAME_FLAG, this);
}
final String deprecatedDcFlagPrefix =
deprecatedDcFlag ? dcFlagsDeprecation : "";
try {
if (id != null) {
CommandUtils.ensureDatacenterExists(id, cs, this);
} else {
id = CommandUtils.getDatacenterId(nameFlag, cs, this);
}
final int planId = cs.createRemoveDatacenterPlan(planName, id);
if (shell.getJson()) {
return executePlan(planId, cs, shell);
}
return deprecatedDcFlagPrefix + executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
public String getCommandSyntax() {
return "plan " + name + " " + ID_FLAG + " | " +
NAME_FLAG + " " + genericFlags;
}
@Override
public String getCommandDescription() {
return "Removes the specified zone from the store.";
}
}
static final class AddTableSub extends PlanSubCommand {
static final String TABLE_NAME_FLAG = "-name";
static final String NAMESPACE_FLAG = "-namespace";
AddTableSub() {
super("add-table", 5);
}
@Override
protected boolean isDeprecated() {
return true;
}
@Override
@SuppressWarnings("null")
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
CommandShell cmd = (CommandShell)shell;
CommandServiceAPI cs = cmd.getAdmin();
String tableName = null;
String namespace = null;
for (int i = 1; i < args.length; i++) {
String arg = args[i];
if (TABLE_NAME_FLAG.equals(arg)) {
tableName = Shell.nextArg(args, i++, this);
} else if (NAMESPACE_FLAG.equals(arg)) {
namespace = Shell.nextArg(args, i++, this);
} else {
i += checkGenericArg(arg, args, i);
}
}
if (tableName == null) {
shell.requiredArg(TABLE_NAME_FLAG, this);
}
Object obj = shell.getVariable(tableName);
if (obj == null || !(obj instanceof TableBuilder)) {
invalidArgument("table " + tableName +
" is not yet built, please run the \'table create\' " +
"command to build it first.");
}
try {
TableBuilder tb = (TableBuilder)obj;
if (namespace == null) {
namespace = (tb.getNamespace() != null) ?
tb.getNamespace() : cmd.getNamespace();
}
final int planId =
cs.createAddTablePlan(planName,
namespace,
tb.getName(),
((tb.getParent()!=null)?
tb.getParent().getFullName():null),
tb.getFieldMap(),
tb.getPrimaryKey(),
tb.getPrimaryKeySizes(),
tb.getShardKey(),
tb.getDefaultTTL(),
tb.isR2compatible(),
tb.getSchemaId(),
tb.getDescription());
shell.removeVariable(tableName);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return "plan add-table " + TABLE_NAME_FLAG + " " +
genericFlags;
}
@Override
protected String getCommandDescription() {
return "Add a new table to the store. " + "The table name is an " +
"optionally namespace" + eolt + "qualified dot-separated " +
"name with the format" + eolt +
"[ns:]tableName[.childTableName]*. Use the " +
"table create command to" + eolt + "create the named table." +
" Use \"table list -create\" to see the list of " +
eolt + "tables that can be added.";
}
}
@POST
static final class EnableRequestsSub extends PlanSubCommand {
static final String COMMAND_NAME = "enable-requests";
static final String REQUEST_TYPE = "-request-type";
static final String TARGET_SHARDS_FLAG = "-shards";
static final String SHARDS_DELIMITER = ",";
static final String STORE_FLAG = "-store";
static final String COMMAND_SYNTAX =
"plan " + COMMAND_NAME + " " + REQUEST_TYPE +
" {all|readonly|none} {"+ TARGET_SHARDS_FLAG +
" | " + STORE_FLAG + "}";
static final String COMMAND_DESC =
"Change the type of user requests supported by a set of shards" +
" or the entire store";
static final String CONFLICT_FLAGS_ERROR =
"Cannot use " + TARGET_SHARDS_FLAG + " and " +
STORE_FLAG + " flags together";
protected EnableRequestsSub() {
super(COMMAND_NAME, 3);
}
private void addShards(CommandServiceAPI cs,
String shardsString,
Set shards)
throws RemoteException, ShellException {
if (shardsString == null) {
return;
}
final String[] shardsArray = shardsString.split(SHARDS_DELIMITER);
for (String shard : shardsArray) {
final RepGroupId shardId = parseShardId(shard.trim());
CommandUtils.ensureShardExists(shardId, cs, this);
shards.add(shardId);
}
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
String requestType = null;
String shardString = null;
boolean entireStore = false;
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if (REQUEST_TYPE.equals(arg)) {
requestType = Shell.nextArg(args, i++, this);
} else if (TARGET_SHARDS_FLAG.equals(arg)) {
shardString = Shell.nextArg(args, i++, this);
} else if (STORE_FLAG.equals(arg)) {
entireStore = true;
} else {
i += checkGenericArg(arg, args, i);
}
}
if (shardString != null && entireStore) {
throw new ShellUsageException(CONFLICT_FLAGS_ERROR, this);
}
if (!entireStore && shardString == null) {
shell.requiredArg(null, this);
}
if (requestType == null) {
shell.requiredArg(REQUEST_TYPE, this);
}
try {
final Set shards = new HashSet();
if (TARGET_SHARDS_FLAG != null) {
addShards(cs, shardString, shards);
}
final int planId = cs.createEnableRequestsPlan(
planName, requestType, shards, entireStore);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return COMMAND_SYNTAX + genericFlags;
}
@Override
protected String getCommandDescription() {
return COMMAND_DESC;
}
}
static final class EvolveTableSub extends PlanSubCommand {
static final String TABLE_NAME_FLAG = "-name";
EvolveTableSub() {
super("evolve-table", 8);
}
@Override
protected boolean isDeprecated() {
return true;
}
@Override
@SuppressWarnings("null")
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
CommandShell cmd = (CommandShell)shell;
CommandServiceAPI cs = cmd.getAdmin();
String tableName = null;
for (int i = 1; i < args.length; i++) {
String arg = args[i];
if (TABLE_NAME_FLAG.equals(arg)) {
tableName = Shell.nextArg(args, i++, this);
} else {
i += checkGenericArg(arg, args, i);
}
}
if (tableName == null) {
shell.requiredArg(TABLE_NAME_FLAG, this);
}
Object obj = shell.getVariable(tableName);
if (obj == null ||
!(obj instanceof TableEvolver)) {
invalidArgument("table " + tableName +
" is not yet built, please run command \'table evolve\'" +
" to build it first.");
}
TableEvolver te = (TableEvolver)obj;
try {
final int planId =
cs.createEvolveTablePlan(planName,
te.getTable().getInternalNamespace(),
te.getTable().getFullName(),
te.getTableVersion(),
te.getFieldMap(),
te.getDefaultTTL());
shell.removeVariable(tableName);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return "plan evolve-table " + TABLE_NAME_FLAG + " " +
genericFlags;
}
@Override
protected String getCommandDescription() {
return "Evolve a table in the store. The table name is an " +
"optionally namespace" + eolt + "qualified " +
"dot-separated name with the format " + eolt +
"[ns:]tableName[.childTableName]*. The named table must " +
"have been" + eolt + "evolved using the \"table evolve\" " +
"command. Use \"table list -evolve\" " +
"to " + eolt + "see the list of tables that can be evolved.";
}
}
static final class RemoveTableSub extends PlanSubCommand {
static final String TABLE_NAME_FLAG = "-name";
static final String TABLE_NS_FLAG = "-namespace";
/* No longer supported */
private static final String KEEP_DATA_FLAG = "-keep-data";
RemoveTableSub() {
super("remove-table", 8);
}
@Override
protected boolean isDeprecated() {
return true;
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
CommandShell cmd = (CommandShell)shell;
CommandServiceAPI cs = cmd.getAdmin();
String tableName = null;
String namespace = null;
for (int i = 1; i < args.length; i++) {
String arg = args[i];
if (TABLE_NAME_FLAG.equals(arg)) {
tableName = Shell.nextArg(args, i++, this);
} else if (TABLE_NS_FLAG.equals(arg)) {
namespace = Shell.nextArg(args, i++, this);
} else if (KEEP_DATA_FLAG.equals(arg)) {
invalidArgument(KEEP_DATA_FLAG + " is no longer supported");
} else {
i += checkGenericArg(arg, args, i);
}
}
if (tableName == null) {
shell.requiredArg(TABLE_NAME_FLAG, this);
}
if (namespace == null) {
namespace = cmd.getNamespace();
}
try {
final int planId =
cs.createRemoveTablePlan(planName, namespace, tableName);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return "plan remove-table " + TABLE_NAME_FLAG + " " +
genericFlags;
}
@Override
protected String getCommandDescription() {
return "Remove a table from the store. The table name is an " +
"optionally" + eolt + "namespace qualified dot-separated " +
"name with the format" + eolt +
"[ns:]tableName[.childTableName]*. The named table must exist " +
"and must" + eolt + "not have " +
"any child tables. Indexes on the table are automatically " +
eolt + "removed. Data stored in this table is also " +
"removed. Depending on " + eolt + "the indexes and amount of " +
"data stored in the table this may be a " + eolt +
"long-running plan.";
}
}
@POST
static final class RevokeSub extends PlanSubCommand {
static final String USER_FLAG = "-user";
static final String ROLE_FLAG = "-role";
static final String COMMAND_SYNTAX =
"plan revoke -user [-role ]*" + genericFlags;
static final String COMMAND_DESC =
"Revoke roles from a user with specified name. The -role option " +
"accepts" + eolt + "only predefined roles in KVStore currently.";
static final String revokeCommandDeprecation =
"The command:" + eol + eolt +
"plan revoke" + eol + eol +
"is deprecated and has been replaced by:" + eol + eolt +
"execute \'REVOKE\'" + eol + eol;
RevokeSub() {
super("revoke", 3);
}
/** This is a deprecated command. Return true. */
@Override
protected boolean isDeprecated() {
return true;
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
if (shell.getJson()) {
return executeCommand(args, shell);
}
return revokeCommandDeprecation + executeCommand(args, shell);
}
private String executeCommand(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
final Set roles = new HashSet();
String userName = null;
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if (USER_FLAG.equals(arg)) {
userName = Shell.nextArg(args, i++, this);
} else if (ROLE_FLAG.equals(arg)) {
final String role = Shell.nextArg(args, i++, this);
roles.add(role.toLowerCase());
} else {
i += checkGenericArg(arg, args, i);
}
}
if (userName == null) {
shell.requiredArg(USER_FLAG, this);
}
if (roles.isEmpty()) {
shell.requiredArg(ROLE_FLAG, this);
}
try {
final int planId =
cs.createRevokePlan(planName, userName, roles);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return COMMAND_SYNTAX;
}
@Override
protected String getCommandDescription() {
return COMMAND_DESC + eol + eolt +
"This command is deprecated and has been replaced by:" +
eol + eolt + "execute \'REVOKE\'";
}
}
static final class AddIndexSub extends PlanSubCommand {
static final String INDEX_NAME_FLAG = "-name";
static final String TABLE_FLAG = "-table";
static final String TABLE_NS_FLAG = "-namespace";
static final String FIELD_FLAG = "-field";
static final String DESC_FLAG = "-desc";
AddIndexSub() {
super("add-index", 5);
}
@Override
protected boolean isDeprecated() {
return true;
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
CommandShell cmd = (CommandShell)shell;
CommandServiceAPI cs = cmd.getAdmin();
String indexName = null;
String tableName = null;
String namespace = null;
String desc = null;
List fields = new ArrayList<>();
for (int i = 1; i < args.length; i++) {
String arg = args[i];
if (INDEX_NAME_FLAG.equals(arg)) {
indexName = Shell.nextArg(args, i++, this);
} else if (TABLE_FLAG.equals(arg)) {
tableName = Shell.nextArg(args, i++, this);
} else if (TABLE_NS_FLAG.equals(arg)) {
namespace = Shell.nextArg(args, i++, this);
} else if (FIELD_FLAG.equals(arg)) {
fields.add(Shell.nextArg(args, i++, this));
} else if (DESC_FLAG.equals(arg)) {
desc = Shell.nextArg(args, i++, this);
} else {
i += checkGenericArg(arg, args, i);
}
}
if (indexName == null) {
shell.requiredArg(INDEX_NAME_FLAG, this);
}
if (tableName == null) {
shell.requiredArg(TABLE_FLAG, this);
}
if (fields.isEmpty()) {
shell.requiredArg(FIELD_FLAG, this);
}
if (namespace == null) {
namespace = cmd.getNamespace();
}
try {
final int planId =
cs.createAddIndexPlan(planName,
namespace,
indexName,
tableName,
fields.toArray(new String[0]),
null,
desc);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return "plan add-index " + INDEX_NAME_FLAG + " " +
TABLE_FLAG + " " +
"[" + FIELD_FLAG + " ]* " + eolt +
"[" + DESC_FLAG + " ]" +
genericFlags;
}
@Override
protected String getCommandDescription() {
return "Add an index to a table in the store. " +
"The table name is an optionally" + eolt + "namespace " +
"qualified dot-separated name with the format" + eolt +
"[ns:]tableName[.childTableName]*.";
}
}
static final class RemoveIndexSub extends PlanSubCommand {
static final String INDEX_NAME_FLAG = "-name";
static final String TABLE_FLAG = "-table";
static final String TABLE_NS_FLAG = "-namespace";
RemoveIndexSub() {
super("remove-index", 8);
}
@Override
protected boolean isDeprecated() {
return true;
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
CommandShell cmd = (CommandShell)shell;
CommandServiceAPI cs = cmd.getAdmin();
String indexName = null;
String tableName = null;
String namespace = null;
for (int i = 1; i < args.length; i++) {
String arg = args[i];
if (INDEX_NAME_FLAG.equals(arg)) {
indexName = Shell.nextArg(args, i++, this);
} else if (TABLE_FLAG.equals(arg)) {
tableName = Shell.nextArg(args, i++, this);
} else if (TABLE_NS_FLAG.equals(arg)) {
namespace = Shell.nextArg(args, i++, this);
} else {
i += checkGenericArg(arg, args, i);
}
}
if (indexName == null) {
shell.requiredArg(INDEX_NAME_FLAG, this);
}
if (tableName == null) {
shell.requiredArg(TABLE_FLAG, this);
}
if (namespace == null) {
namespace = cmd.getNamespace();
}
try {
final int planId =
cs.createRemoveIndexPlan(planName, namespace,
indexName, tableName);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return "plan remove-index " + INDEX_NAME_FLAG + " " +
TABLE_FLAG + " " +
genericFlags;
}
@Override
protected String getCommandDescription() {
return "Remove an index from a table. The table name is an " +
"optionally namespace" + eolt + "qualified " +
"dot-separated name with the format " + eolt +
"[ns:]tableName[.childTableName]*.";
}
}
@POST
static final class RegisterEsCluster extends PlanSubCommand {
static final String COMMAND_SYNTAX=
"plan register-es -clustername " + eol +
"-host -port " +
" -secure " + eol +
CommandParser.getJsonUsage();
static final String COMMAND_DESC =
"Registers an Elasticsearch cluster with the store." + eol +
"It is only necessary to register one node of the cluster, " + eol +
"as the other nodes in the cluster will be found automatically.";
RegisterEsCluster() {
super("register-es", 5);
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
String clusterName = null;
String hostName = null;
int port = 0;
String secureVal = null;
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
if ("-clustername".equals(arg)) {
clusterName = Shell.nextArg(args, i++, this);
} else if ("-host".equals(arg)) {
hostName = Shell.nextArg(args, i++, this);
} else if ("-port".equals(arg)) {
final String argString = Shell.nextArg(args, i++, this);
port = parseUnsignedInt(argString);
} else if ("-secure".equals(arg)) {
secureVal = Shell.nextArg(args, i++, this);
}else {
i += checkGenericArg(arg, args, i);
}
}
if (clusterName == null) {
shell.requiredArg("-clustername", this);
}
if (hostName == null) {
shell.requiredArg("-hostName", this);
}
if (port == 0) {
shell.requiredArg("-port", this);
}
/*
* FTS Default is secure FTS.
* Secure FTS is only available in EE version.
* For CE and BE version, secure flag need to be explicitly
* set to false.
*/
if (secureVal == null) {
secureVal = "true";
}
final HostPort hp = new HostPort(hostName, port);
try {
final int planId =
cs.createRegisterESClusterPlan(planName,
clusterName,
hp.toString(),
Boolean.parseBoolean(secureVal),
force);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return COMMAND_SYNTAX;
}
@Override
protected String getCommandDescription() {
return COMMAND_DESC;
}
}
@POST
static final class DeregisterEsCluster extends PlanSubCommand {
static final String COMMAND_SYNTAX=
"plan deregister-es " +
CommandParser.getJsonUsage();
static final String COMMAND_DESC =
"Deregisters an Elasticsearch cluster from the store." + eol +
"This can be done only if all full text indexes are first removed.";
DeregisterEsCluster() {
super("deregister-es", 5);
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
for (int i = 1; i < args.length; i++) {
i += checkGenericArg(args[i], args, i);
}
try {
final int planId =
cs.createDeregisterESClusterPlan(planName);
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
@Override
protected String getCommandSyntax() {
return COMMAND_SYNTAX;
}
@Override
protected String getCommandDescription() {
return COMMAND_DESC;
}
}
@POST
static final class VerifyDataSub extends PlanSubCommand {
final String COMMAND_SYNTAX = "plan verify-data " +
"[-verify-log [-log-read-delay ]] " +
eolt +
"[-verify-btree " +
"[-btree-batch-delay ] " +
eolt +
"[-index ] [-datarecord ]] " +
eolt
+ "-service | -all-services [-zn | -znname ] " +
eolt +
"| -all-rns [-zn | -znname ] | " +
eolt +
"-all-admins [-zn | -znname ] " + genericFlags;
final String COMMAND_DESC =
"-verify-log verifies the checksum of each data record " +
eolt +
"in the log file of JE. It is enabled by default. " +
eolt +
"-log-read-delay configures the the delay time" +
eolt +
" between file reads and the default value is 100 millisecond." +
eolt +
eolt +
"-verify-btree verifies that the b-tree of " +
eolt +
"database in memory contains the valid reference " +
eolt +
"to each data record in disk. It is enabled by default. " +
eolt +
"-btree-batch-delay configures the delay time, in " +
eolt +
"milliseconds, between batches (1000 records) and the " +
eolt +
"default value is 10 milliseconds. -verify-btree can be " +
eolt +
"combined with -datarecord and -index." +
eolt +
eolt +
"\t -datarecord is disabled by default. If it is enabled, " +
eolt +
"\t the plan will read and verify data records on disk which " +
eolt +
"\t are not in the cache. This will take longer and " +
eolt +
"\t cause more read IO." +
eolt +
eolt +
"\t -index is enabled by default. It runs verification " +
eolt +
"\t on indexes. -datarecord needs to be enabled to do " +
eolt +
"\t a full verification. If -datarecord is disabled, the " +
eolt +
"\t command will only verify the reference from index to " +
eolt +
"\t primary table, but not the reference from primary table to " +
eolt +
"\t index." +
eolt +
eolt +
"Users can run the verification on either the specified " +
eolt +
"service using -service, or all service instances of " +
eolt +
"the specified type or all types that are deployed to " +
eolt +
"the specified zone or all zones using one of the -all-* flags. " +
eolt +
"A -all-* flag can be combined with -zn or -znname to verify " +
eolt +
"data on all instances of the service type deployed to the " +
eolt +
"specified zone. If one of the -all-* flags is used without " +
eolt +
"also specifying the zone, then the verification will be run on " +
eolt +
"all instances of the specified type or all types within the " +
eolt +
"store, regardless of zone.";
final String logOrBtreeError =
"Invalid argument: -verify-log, -verify-btree or both must " +
"be enabled.";
final String btreeComboError =
"Invalid argument combination: -btree-batch-delay, -index and " +
"-datarecord flags cannot be used if -verify-btree is disabled.";
final String logComboError =
"invalid argument combination: -log-read-delay flag cannot be " +
"used if -verify-log is disabled.";
final String serviceAllError =
"Invalid argument combination: -service flag cannot be used " +
"with -all-admins, -all-rns, or -all-services flag.";
final String serviceDcError =
"Invalid argument combination: -service flag cannot be used " +
"with -zn or -znname flag.";
final String negativeDelayError =
"-btree-batch-delay and -log-read-delay cannot be less than zero.";
final String incompatibleAllError =
"Invalid argument combination: Only one of the flags " +
"-all-rns, -all-admins, and -all-services may be used.";
boolean verifyLog;
boolean verifyBtree;
long btreeDelay;
long logDelay;
String serviceName;
boolean allAdmin, allRN, allService;
boolean index;
boolean dataRecord;
RepNodeId rnid;
AdminId aid;
VerifyDataSub() {
super("verify-data", 10);
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
verifyLog = true;
verifyBtree = true;
allAdmin = allRN = allService = dataRecord = false;
index = true;
btreeDelay = -1;
logDelay = -1;
serviceName = null;
rnid = null;
aid = null;
DatacenterId dcid = null;
String dcName = null;
boolean deprecatedDcFlag = false;
boolean getDcId = false;
for (int i = 1; i < args.length; i++) {
String arg = args[i];
if ("-verify-log".equals(arg)) {
verifyLog = enabled(Shell.nextArg(args, i++, this),
"-verify-log");
} else if ("-verify-btree".equals(arg)) {
verifyBtree = enabled(Shell.nextArg(args, i++, this),
"-verify-btree");
if (!verifyBtree) {
index = false;
}
} else if ("-btree-batch-delay".equals(arg)) {
btreeDelay =
Integer.parseInt(Shell.nextArg(args, i++, this));
if (btreeDelay < 0) {
throw new ShellUsageException(negativeDelayError, this);
}
} else if ("-log-read-delay".equals(arg)) {
logDelay = Integer.parseInt(Shell.nextArg(args, i++, this));
if (logDelay < 0) {
throw new ShellUsageException(negativeDelayError, this);
}
} else if ("-service".equals(arg)) {
serviceName = Shell.nextArg(args, i++, this);
} else if ("-all-admins".equals(arg)) {
allAdmin = true;
} else if ("-all-rns".equals(arg)) {
allRN = true;
} else if ("-all-services".equals(arg)) {
allService = true;
} else if (CommandUtils.isDatacenterIdFlag(arg)) {
dcid = DatacenterId.parse(Shell.nextArg(args, i++, this));
if (CommandUtils.isDeprecatedDatacenterId(arg, args[i])) {
deprecatedDcFlag = true;
}
} else if (CommandUtils.isDatacenterNameFlag(arg)) {
dcName = Shell.nextArg(args, i++, this);
if (CommandUtils.isDeprecatedDatacenterName(arg)) {
deprecatedDcFlag = true;
}
} else if ("-index".equals(arg)) {
index = enabled(Shell.nextArg(args, i++, this), "-index");
} else if ("-datarecord".equals(arg)) {
dataRecord = enabled(Shell.nextArg(args, i++, this),
"-datarecord");
} else {
i += checkGenericArg(arg, args, i);
}
}
if (!(verifyLog || verifyBtree)) {
throw new ShellUsageException(logOrBtreeError, this);
}
if ((!verifyBtree) && (index || dataRecord || (btreeDelay > -1))) {
throw new ShellUsageException(btreeComboError, this);
}
if ((!verifyLog) && (logDelay > -1)) {
throw new ShellUsageException(logComboError, this);
}
if (serviceName == null) {
if (!(allAdmin || allRN || allService)) {
shell.requiredArg(null, this);
} else {
if ((allAdmin ? 1 : 0) + (allRN ? 1 : 0) +
(allService ? 1 : 0) > 1) {
throw new ShellUsageException(incompatibleAllError,
this);
}
if (dcName != null) {
getDcId = true;
}
}
} else {
if (allAdmin || allRN || allService) {
throw new ShellUsageException(serviceAllError, this);
}
if (dcid != null || dcName != null) {
throw new ShellUsageException(serviceDcError, this);
}
}
String deprecatedDcFlagPrefix =
deprecatedDcFlag ? dcFlagsDeprecation : "";
try {
int planId = 0;
if (getDcId) {
dcid = CommandUtils.getDatacenterId(dcName, cs, this);
}
if (serviceName != null) {
getServiceId(cs);
if (aid != null) {
shell.verboseOutput("Verifying the database for " +
aid);
planId = cs.createVerifyServicePlan(planName, aid,
verifyBtree,
verifyLog, index,
dataRecord,
btreeDelay,
logDelay);
} else {
shell.verboseOutput("Verifying the database for " +
rnid);
planId = cs.createVerifyServicePlan(planName, rnid,
verifyBtree,
verifyLog,
index, dataRecord,
btreeDelay,
logDelay);
}
} else {
String suffixMessage = "";
if (dcName != null) {
suffixMessage = " deployed to the " + dcName +
" zone";
} else if (dcid != null) {
suffixMessage = " deployed to the zone with id" +
" = " + dcid;
}
if (allAdmin) {
shell.verboseOutput(
"Verifying the databases for all Admins" +
suffixMessage);
planId = cs.createVerifyAllAdminsPlan(planName, dcid,
verifyBtree,
verifyLog,
index, dataRecord,
btreeDelay,
logDelay);
} else if (allRN) {
shell.verboseOutput(
"Verifying the databases for all RepNodes" +
suffixMessage);
planId = cs.createVerifyAllRepNodesPlan(planName, dcid,
verifyBtree,
verifyLog,
index,
dataRecord,
btreeDelay,
logDelay);
} else {
shell.verboseOutput(
"Verifying the databases for all services" +
suffixMessage);
planId = cs.createVerifyAllServicesPlan(planName, dcid,
verifyBtree,
verifyLog,
index,
dataRecord,
btreeDelay,
logDelay);
}
}
if (shell.getJson()) {
return executePlan(planId, cs, shell);
}
return deprecatedDcFlagPrefix + executePlan(planId, cs, shell);
} catch (RemoteException e) {
cmd.noAdmin(e);
return "";
}
}
@Override
protected String getCommandSyntax() {
return COMMAND_SYNTAX;
}
@Override
protected String getCommandDescription() {
return COMMAND_DESC;
}
private void getServiceId(CommandServiceAPI cs)
throws ShellException, RemoteException {
Parameters param = cs.getParameters();
try {
rnid = RepNodeId.parse(serviceName);
if (param.get(rnid) == null) {
throw new ShellUsageException("No such service" +
serviceName, this);
}
} catch (IllegalArgumentException e) {
try {
aid = AdminId.parse(serviceName);
if (param.get(aid) == null) {
throw new ShellUsageException("No such service" +
serviceName, this);
}
} catch (IllegalArgumentException e2) {
throw new ShellUsageException("Invalid service name: " +
serviceName, this);
}
}
}
private boolean enabled(String input, String option)
throws ShellException {
if (input.equals("enable")) {
return true;
} else if (input.equals("disable")) {
return false;
} else {
throw new ShellUsageException(option +
" must be followed by enable or disable",
this);
}
}
}
@POST
static private final class SetTableLimitsSub extends PlanSubCommand {
static final String TABLE_NAME_FLAG = "-name";
static final String TABLE_NS_FLAG = "-namespace";
static final String READ_LIMIT_FLAG = "-read-limit";
static final String WRITE_LIMIT_FLAG = "-write-limit";
static final String SIZE_LIMIT_FLAG = "-size-limit";
static final String INDEX_LIMIT_FLAG = "-index-limit";
static final String CHILD_TABLE_LIMIT_FLAG = "-child-table-limit";
static final String INDEX_KEY_SIZE_LIMIT_FLAG = "-index-key-size-limit";
static final String COMMAND_DESC =
"Sets table limits. At least one limit must be specified." + eol +
"Limits which are omitted are not changed";
SetTableLimitsSub() {
super("set-table-limits", 6);
}
@Override
protected boolean isHidden() {
return true;
}
@Override
public String exec(String[] args, Shell shell)
throws ShellException {
Shell.checkHelp(args, this);
final CommandShell cmd = (CommandShell) shell;
final CommandServiceAPI cs = cmd.getAdmin();
String tableName = null;
String namespace = null;
/* NO_CHANGE indicates that the limit was not specified */
int readLimit = TableLimits.NO_CHANGE;
int writeLimit = TableLimits.NO_CHANGE;
int sizeLimit = TableLimits.NO_CHANGE;
int indexLimit = TableLimits.NO_CHANGE;
int childTableLimit = TableLimits.NO_CHANGE;
int indexKeySizeLimit = TableLimits.NO_CHANGE;
boolean limitSpecified = false;
for (int i = 1; i < args.length; i++) {
final String arg = args[i];
switch (arg) {
case TABLE_NAME_FLAG:
tableName = Shell.nextArg(args, i++, this);
break;
case TABLE_NS_FLAG:
namespace = Shell.nextArg(args, i++, this);
break;
case READ_LIMIT_FLAG:
readLimit = parseLimit(Shell.nextArg(args, i++, this));
limitSpecified = true;
break;
case WRITE_LIMIT_FLAG:
writeLimit = parseLimit(Shell.nextArg(args, i++, this));
limitSpecified = true;
break;
case SIZE_LIMIT_FLAG:
sizeLimit = parseLimit(Shell.nextArg(args, i++, this));
limitSpecified = true;
break;
case INDEX_LIMIT_FLAG:
sizeLimit = parseLimit(Shell.nextArg(args, i++, this));
limitSpecified = true;
break;
case CHILD_TABLE_LIMIT_FLAG:
childTableLimit =
parseLimit(Shell.nextArg(args, i++, this));
limitSpecified = true;
break;
case INDEX_KEY_SIZE_LIMIT_FLAG:
indexKeySizeLimit =
parseLimit(Shell.nextArg(args, i++, this));
limitSpecified = true;
break;
default:
i += checkGenericArg(arg, args, i);
break;
}
}
if (tableName == null) {
shell.requiredArg(TABLE_NAME_FLAG, this);
}
if (!limitSpecified) {
shell.requiredArg("at least one limit must be specified", this);
}
try {
final int planId =
cs.createTableLimitPlan(planName, namespace, tableName,
new TableLimits(readLimit,
writeLimit,
sizeLimit,
indexLimit,
childTableLimit,
indexKeySizeLimit));
return executePlan(planId, cs, shell);
} catch (RemoteException re) {
cmd.noAdmin(re);
}
return "";
}
private int parseLimit(String arg) throws ShellException {
return arg.equalsIgnoreCase("none") ? TableLimits.NO_LIMIT :
parseUnsignedInt(arg);
}
@Override
protected String getCommandSyntax() {
return "plan set-table-limit " + TABLE_NAME_FLAG + " " +
"[" + TABLE_NS_FLAG + " ] " + eolt +
"[" + READ_LIMIT_FLAG + " |none] " + eolt +
"[" + WRITE_LIMIT_FLAG + " |none] " + eolt +
"[" + SIZE_LIMIT_FLAG + " |none]" + eolt +
"[" + INDEX_LIMIT_FLAG + " <# indexes>|none]" + eolt +
"[" + CHILD_TABLE_LIMIT_FLAG + "<# tables>|none]" + eolt +
"[" + INDEX_KEY_SIZE_LIMIT_FLAG + " |none]" +
genericFlags;
}
@Override
protected String getCommandDescription() {
return COMMAND_DESC;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy