blob: 42e41a1a0e43047cb2247f175b807b2573dd6367 [file] [log] [blame]
/*
* Copyright 2017 HugeGraph Authors
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package com.baidu.hugegraph.cmd;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import com.baidu.hugegraph.base.Printer;
import com.baidu.hugegraph.base.ToolClient;
import com.baidu.hugegraph.base.ToolClient.ConnectionInfo;
import com.baidu.hugegraph.base.ToolManager;
import com.baidu.hugegraph.constant.Constants;
import com.baidu.hugegraph.exception.ExitException;
import com.baidu.hugegraph.manager.AuthBackupRestoreManager;
import com.baidu.hugegraph.manager.BackupManager;
import com.baidu.hugegraph.manager.DumpGraphManager;
import com.baidu.hugegraph.manager.GraphsManager;
import com.baidu.hugegraph.manager.GremlinManager;
import com.baidu.hugegraph.manager.RestoreManager;
import com.baidu.hugegraph.manager.TasksManager;
import com.baidu.hugegraph.structure.Task;
import com.baidu.hugegraph.structure.constant.GraphMode;
import com.baidu.hugegraph.structure.gremlin.Result;
import com.baidu.hugegraph.structure.gremlin.ResultSet;
import com.baidu.hugegraph.util.E;
import com.baidu.hugegraph.util.ToolUtil;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.ParameterException;
import com.beust.jcommander.ParametersDelegate;
import com.google.common.collect.Lists;
import static com.baidu.hugegraph.manager.BackupManager.BACKUP_DEFAULT_TIMEOUT;
public class HugeGraphCommand {
private static final int DEFAULT_GRAPH_CLEAR_TIMEOUT = 300;
private static final int DEFAULT_GRAPH_CREATE_TIMEOUT = 300;
private SubCommands subCommands;
private List<ToolManager> taskManagers;
@ParametersDelegate
private SubCommands.Url url = new SubCommands.Url();
@ParametersDelegate
private SubCommands.Graph graph = new SubCommands.Graph();
@ParametersDelegate
private SubCommands.Username username = new SubCommands.Username();
@ParametersDelegate
private SubCommands.Password password = new SubCommands.Password();
@ParametersDelegate
private SubCommands.Timeout timeout = new SubCommands.Timeout();
@ParametersDelegate
private SubCommands.TrustStoreFile trustStoreFile =
new SubCommands.TrustStoreFile();
@ParametersDelegate
private SubCommands.TrustStorePassword trustStorePassword =
new SubCommands.TrustStorePassword();
@ParametersDelegate
private SubCommands.ThrowMode throwMode = new SubCommands.ThrowMode();
public HugeGraphCommand() {
this.subCommands = new SubCommands();
this.taskManagers = Lists.newArrayList();
}
public Map<String, Object> subCommands() {
return this.subCommands.commands();
}
@SuppressWarnings("unchecked")
public <T> T subCommand(String subCmd) {
return (T) this.subCommands.commands().get(subCmd);
}
public String url() {
return this.url.url;
}
private void url(String url) {
this.url.url = url;
}
public String graph() {
return this.graph.graph;
}
private void graph(String graph) {
this.graph.graph = graph;
}
public String username() {
return this.username.username;
}
public void username(String username) {
this.username.username = username;
}
public String password() {
return this.password.password;
}
public void password(String password) {
this.password.password = password;
}
public int timeout() {
return this.timeout.timeout;
}
public void timeout(int timeout) {
this.timeout.timeout = timeout;
}
public String trustStoreFile () {
return this.trustStoreFile.trustStoreFile;
}
public void trustStoreFile(String trustStoreFile) {
this.trustStoreFile.trustStoreFile = trustStoreFile;
}
public String trustStorePassword () {
return this.trustStorePassword.trustStorePassword;
}
public void trustStorePassword(String trustStorePassword) {
this.trustStorePassword.trustStorePassword = trustStorePassword;
}
public boolean throwMode() {
return this.throwMode.throwMode;
}
private void throwMode(boolean throwMode) {
this.throwMode.throwMode = throwMode;
}
public JCommander jCommander() {
JCommander.Builder builder = JCommander.newBuilder();
// Add main command firstly
builder.addObject(this);
// Add sub-commands
for (Map.Entry<String, Object> entry : this.subCommands().entrySet()) {
builder.addCommand(entry.getKey(), entry.getValue());
}
JCommander jCommander = builder.build();
jCommander.setProgramName("hugegraph");
jCommander.setCaseSensitiveOptions(true);
jCommander.setAllowAbbreviatedOptions(true);
return jCommander;
}
private void execute(String subCmd, JCommander jCommander) {
this.checkMainParams();
switch (subCmd) {
case "backup":
if (this.timeout() < BACKUP_DEFAULT_TIMEOUT) {
this.timeout(BACKUP_DEFAULT_TIMEOUT);
}
Printer.print("Graph '%s' start backup!", this.graph());
SubCommands.Backup backup = this.subCommand(subCmd);
BackupManager backupManager = manager(BackupManager.class);
backupManager.init(backup);
backupManager.backup(backup.types());
break;
case "restore":
GraphsManager graphsManager = manager(GraphsManager.class);
GraphMode mode = graphsManager.mode(this.graph());
E.checkState(mode.maintaining(),
"Invalid mode '%s' of graph '%s' for restore " +
"sub-command", mode, this.graph());
Printer.print("Graph '%s' start restore in mode '%s'!",
this.graph(), mode);
SubCommands.Restore restore = this.subCommand(subCmd);
RestoreManager restoreManager = manager(RestoreManager.class);
restoreManager.init(restore);
restoreManager.mode(mode);
restoreManager.restore(restore.types());
break;
case "migrate":
SubCommands.Migrate migrate = this.subCommand(subCmd);
Printer.print("Migrate graph '%s' from '%s' to '%s' as '%s'",
this.graph(), this.url(),
migrate.targetUrl(), migrate.targetGraph());
// Backup source graph
if (this.timeout() < BACKUP_DEFAULT_TIMEOUT) {
this.timeout(BACKUP_DEFAULT_TIMEOUT);
}
backup = convMigrate2Backup(migrate);
backupManager = manager(BackupManager.class);
backupManager.init(backup);
backupManager.backup(backup.types());
// Restore source graph to target graph
this.url(migrate.targetUrl());
this.graph(migrate.targetGraph());
this.username(migrate.targetUsername());
this.password(migrate.targetPassword());
this.timeout(migrate.targetTimeout());
this.trustStoreFile(migrate.targetTrustStoreFile());
this.trustStorePassword(migrate.targetTrustStorePassword());
graphsManager = manager(GraphsManager.class);
GraphMode origin = graphsManager.mode(migrate.targetGraph());
// Set target graph mode
mode = migrate.mode();
E.checkState(mode.maintaining(),
"Invalid mode '%s' of graph '%s' for restore",
mode, migrate.targetGraph());
graphsManager.mode(migrate.targetGraph(), mode);
// Restore
Printer.print("Graph '%s' start restore in mode '%s'!",
migrate.targetGraph(), migrate.mode());
String directory = backupManager.directory().directory();
restore = convMigrate2Restore(migrate, directory);
restoreManager = manager(RestoreManager.class);
restoreManager.init(restore);
restoreManager.mode(mode);
restoreManager.restore(restore.types());
// Restore target graph mode
graphsManager.mode(migrate.targetGraph(), origin);
break;
case "dump":
Printer.print("Graph '%s' start dump!", this.graph());
SubCommands.DumpGraph dump = this.subCommand(subCmd);
DumpGraphManager dumpManager = manager(DumpGraphManager.class);
dumpManager.init(dump);
dumpManager.dumpFormatter(dump.formatter());
dumpManager.dump();
break;
case "graph-create":
SubCommands.GraphCreate graphCreate = this.subCommand(subCmd);
if (timeout() < DEFAULT_GRAPH_CREATE_TIMEOUT) {
this.timeout(DEFAULT_GRAPH_CREATE_TIMEOUT);
}
graphsManager = manager(GraphsManager.class);
graphsManager.create(graphCreate.name(), graphCreate.config());
Printer.print("Graph '%s' is created", graphCreate.name());
break;
case "graph-clone":
SubCommands.GraphClone graphClone = this.subCommand(subCmd);
if (timeout() < DEFAULT_GRAPH_CREATE_TIMEOUT) {
this.timeout(DEFAULT_GRAPH_CREATE_TIMEOUT);
}
graphsManager = manager(GraphsManager.class);
graphsManager.clone(graphClone.name(),
graphClone.cloneGraphName());
Printer.print("Graph '%s' is created(cloned from '%s')",
graphClone.name(), graphClone.cloneGraphName());
break;
case "graph-list":
graphsManager = manager(GraphsManager.class);
Printer.printList("Graphs", graphsManager.list());
break;
case "graph-get":
graphsManager = manager(GraphsManager.class);
Printer.printMap("Graph info",
graphsManager.get(this.graph()));
break;
case "graph-clear":
SubCommands.GraphClear graphClear = this.subCommand(subCmd);
if (timeout() < DEFAULT_GRAPH_CLEAR_TIMEOUT) {
this.timeout(DEFAULT_GRAPH_CLEAR_TIMEOUT);
}
graphsManager = manager(GraphsManager.class);
graphsManager.clear(this.graph(), graphClear.confirmMessage());
Printer.print("Graph '%s' is cleared", this.graph());
break;
case "graph-drop":
SubCommands.GraphDrop graphDrop = this.subCommand(subCmd);
if (timeout() < DEFAULT_GRAPH_CLEAR_TIMEOUT) {
this.timeout(DEFAULT_GRAPH_CLEAR_TIMEOUT);
}
graphsManager = manager(GraphsManager.class);
graphsManager.drop(this.graph(), graphDrop.confirmMessage());
Printer.print("Graph '%s' is dropped", this.graph());
break;
case "graph-mode-set":
SubCommands.GraphModeSet graphModeSet = this.subCommand(subCmd);
graphsManager = manager(GraphsManager.class);
graphsManager.mode(this.graph(), graphModeSet.mode());
Printer.print("Set graph '%s' mode to '%s'",
this.graph(), graphModeSet.mode());
break;
case "graph-mode-get":
graphsManager = manager(GraphsManager.class);
Printer.printKV("Graph mode", graphsManager.mode(this.graph()));
break;
case "gremlin-execute":
SubCommands.Gremlin gremlin = this.subCommand(subCmd);
GremlinManager gremlinManager = manager(GremlinManager.class);
Printer.print("Run gremlin script");
ResultSet result = gremlinManager.execute(gremlin.script(),
gremlin.bindings(),
gremlin.language(),
gremlin.aliases());
Iterator<Result> iterator = result.iterator();
while (iterator.hasNext()) {
Printer.print(iterator.next().getString());
}
break;
case "gremlin-schedule":
SubCommands.GremlinJob job = this.subCommand(subCmd);
gremlinManager = manager(GremlinManager.class);
Printer.print("Run gremlin script as async job");
long taskId = gremlinManager.executeAsTask(job.script(),
job.bindings(),
job.language());
Printer.printKV("Task id", taskId);
break;
case "task-list":
SubCommands.TaskList taskList = this.subCommand(subCmd);
TasksManager tasksManager = manager(TasksManager.class);
List<Task> tasks = tasksManager.list(taskList.status(),
taskList.limit());
List<Object> results = tasks.stream().map(Task::asMap)
.collect(Collectors.toList());
Printer.printList("Tasks", results);
break;
case "task-get":
SubCommands.TaskGet taskGet = this.subCommand(subCmd);
tasksManager = manager(TasksManager.class);
Printer.printKV("Task info",
tasksManager.get(taskGet.taskId()).asMap());
break;
case "task-delete":
SubCommands.TaskDelete taskDelete = this.subCommand(subCmd);
tasksManager = manager(TasksManager.class);
tasksManager.delete(taskDelete.taskId());
Printer.print("Task '%s' is deleted", taskDelete.taskId());
break;
case "task-cancel":
SubCommands.TaskCancel taskCancel = this.subCommand(subCmd);
tasksManager = manager(TasksManager.class);
tasksManager.cancel(taskCancel.taskId());
Printer.print("Task '%s' is cancelled", taskCancel.taskId());
break;
case "task-clear":
SubCommands.TaskClear taskClear = this.subCommand(subCmd);
tasksManager = manager(TasksManager.class);
tasksManager.clear(taskClear.force());
Printer.print("Tasks are cleared[force=%s]",
taskClear.force());
break;
case "auth-backup":
Printer.print("Auth backup start...");
SubCommands.AuthBackup authBackup = this.subCommand(subCmd);
AuthBackupRestoreManager authBackupManager = manager(AuthBackupRestoreManager.class);
authBackupManager.init(authBackup);
authBackupManager.backup(authBackup.types());
break;
case "auth-restore":
Printer.print("Auth restore start...");
SubCommands.AuthRestore authRestore = this.subCommand(subCmd);
AuthBackupRestoreManager authRestoreManager = manager(AuthBackupRestoreManager.class);
authRestoreManager.init(authRestore);
authRestoreManager.restore(authRestore.types());
break;
default:
throw new ParameterException(String.format(
"Invalid sub-command: %s", subCmd));
}
}
private void execute(String[] args) {
JCommander jCommander = this.parseCommand(args);
this.execute(jCommander.getParsedCommand(), jCommander);
}
private void checkMainParams() {
E.checkArgument(this.url() != null, "Url can't be null");
E.checkArgument(this.username() == null && this.password() == null ||
this.username() != null && this.password() != null,
"Both user name and password must be null or " +
"not null at same time");
}
private <T extends ToolManager> T manager(Class<T> clz) {
try {
ConnectionInfo info = new ConnectionInfo(this.url(), this.graph(),
this.username(),
this.password(),
this.timeout(),
this.trustStoreFile(),
this.trustStorePassword());
T toolManager = clz.getConstructor(ToolClient.ConnectionInfo.class)
.newInstance(info);
this.taskManagers.add(toolManager);
return toolManager;
} catch (Exception e) {
throw new RuntimeException(String.format(
"Construct manager failed for class '%s', please make " +
"sure global arguments set correctly: " +
"--url=%s,--graph=%s,--user=%s,--password=%s," +
"--timeout=%s,--trust-store-file=%s," +
"--trust-store-password=%s", clz.getSimpleName(),
this.url(), this.graph(), this.username(),
this.password(), this.timeout(),
this.trustStoreFile(), this.trustStorePassword()), e);
}
}
private static SubCommands.Backup convMigrate2Backup(
SubCommands.Migrate migrate) {
SubCommands.Backup backup = new SubCommands.Backup();
backup.splitSize(migrate.splitSize());
backup.directory(migrate.directory());
backup.logDir(migrate.logDir());
backup.types(migrate.types());
backup.retry(migrate.retry());
backup.hdfsConf(migrate.hdfsConf());
return backup;
}
private static SubCommands.Restore convMigrate2Restore(
SubCommands.Migrate migrate,
String directory) {
SubCommands.Restore restore = new SubCommands.Restore();
restore.clean(!migrate.keepData());
restore.directory(directory);
restore.logDir(migrate.logDir());
restore.types(migrate.types());
restore.retry(migrate.retry());
restore.hdfsConf(migrate.hdfsConf());
return restore;
}
private GraphMode mode() {
GraphsManager graphsManager = manager(GraphsManager.class);
GraphMode mode = graphsManager.mode(this.graph());
E.checkState(mode.maintaining(),
"Invalid mode '%s' of graph '%s' for restore " +
"sub-command", mode, this.graph());
return mode;
}
public JCommander parseCommand(String[] args) {
JCommander jCommander = this.jCommander();
if (args.length == 0) {
throw ExitException.exception(ToolUtil.commandUsage(jCommander),
"No command found, please input" +
" command");
}
if (this.parseHelp(args, jCommander)) {
assert false;
} else {
jCommander.parse(args);
}
String subCommand = jCommander.getParsedCommand();
if (subCommand == null) {
throw ExitException.normal(ToolUtil.commandsCategory(
jCommander),
"No sub-command found");
}
return jCommander;
}
public boolean parseHelp(String[] args, JCommander jCommander) {
String subCommand = Strings.EMPTY;
List<String> list = Arrays.asList(args);
if (!list.contains(Constants.COMMAND_HELP)) {
return false;
}
// Parse the '--throw-mode' command
if (list.contains(Constants.COMMAND_THROW_MODE)) {
int index = list.indexOf(Constants.COMMAND_THROW_MODE) + 1;
jCommander.parse(Constants.COMMAND_THROW_MODE,
list.get(index));
}
int index = list.indexOf(Constants.COMMAND_HELP);
if (list.size() > index + 1) {
subCommand = list.get(index + 1);
}
if (StringUtils.isEmpty(subCommand)) {
throw ExitException.normal(ToolUtil.commandUsage(jCommander),
"Command : hugegragh help");
}
Map<String, JCommander> commands = jCommander.getCommands();
if (commands.containsKey(subCommand)) {
throw ExitException.normal(ToolUtil.commandUsage(
commands.get(subCommand)),
"Command : hugegragh help %s",
subCommand);
} else {
throw ExitException.exception(ToolUtil.commandsCategory(jCommander),
"Unexpected help sub-command " +
"%s", subCommand);
}
}
public void shutdown() {
if (CollectionUtils.isEmpty(this.taskManagers)) {
return;
}
for (ToolManager toolManager : this.taskManagers) {
toolManager.close();
}
}
public static void main(String[] args) {
HugeGraphCommand cmd = new HugeGraphCommand();
int exitCode = Constants.EXIT_CODE_NORMAL;
try {
cmd.execute(args);
} catch (ExitException e) {
exitCode = e.exitCode();
ToolUtil.exitOrThrow(e, cmd.throwMode());
} catch (Throwable e) {
exitCode = Constants.EXIT_CODE_ERROR;
ToolUtil.printOrThrow(e, cmd.throwMode());
} finally {
cmd.shutdown();
}
if (exitCode != Constants.EXIT_CODE_NORMAL) {
System.exit(exitCode);
}
}
}