diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperMain.java b/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperMain.java index 243aca33c39..8d864b609e4 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperMain.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeperMain.java @@ -57,6 +57,7 @@ import org.apache.zookeeper.cli.MalformedCommandException; import org.apache.zookeeper.cli.ReconfigCommand; import org.apache.zookeeper.cli.RemoveWatchesCommand; +import org.apache.zookeeper.cli.RestoreCommand; import org.apache.zookeeper.cli.SetAclCommand; import org.apache.zookeeper.cli.SetCommand; import org.apache.zookeeper.cli.SetQuotaCommand; @@ -123,6 +124,7 @@ public boolean getPrintWatches() { new GetAllChildrenNumberCommand().addToMap(commandMapCli); new VersionCommand().addToMap(commandMapCli); new AddWatchCommand().addToMap(commandMapCli); + new RestoreCommand().addToMap(commandMapCli); // add all to commandMap for (Entry entry : commandMapCli.entrySet()) { diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/cli/RestoreCommand.java b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/RestoreCommand.java new file mode 100644 index 00000000000..7f3b9ea2b2b --- /dev/null +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/cli/RestoreCommand.java @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.zookeeper.cli; + +import org.apache.zookeeper.common.ConfigException; +import org.apache.zookeeper.server.backup.RestoreFromBackupTool; + +/** + * Restore command for ZkCli. + */ +public class RestoreCommand extends CliCommand { + + private static final int RESTORE_NUM_ARGS_REQUIRED = 4; + + private RestoreFromBackupTool tool; + + + public RestoreCommand() { + super("restore", + " " + + " " + + " " + + " " + + "<-n:dry run>"); + tool = new RestoreFromBackupTool(); + } + + @Override + public CliCommand parse(String[] cmdArgs) throws CliParseException { + try { + tool.parseArgs(cmdArgs); + } catch (ConfigException e) { + throw new CliParseException(e.getMessage()); + } + return this; + } + + @Override + public boolean exec() throws CliException { + return tool.runWithRetries(); + } +} diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/backup/RestoreFromBackupTool.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/backup/RestoreFromBackupTool.java new file mode 100644 index 00000000000..d17d4ec13cf --- /dev/null +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/backup/RestoreFromBackupTool.java @@ -0,0 +1,120 @@ +package org.apache.zookeeper.server.backup; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import org.apache.zookeeper.common.ConfigException; +import org.apache.zookeeper.server.backup.storage.BackupStorageProvider; +import org.apache.zookeeper.server.backup.storage.impl.FileSystemBackupStorage; +import org.apache.zookeeper.server.persistence.FileTxnSnapLog; + +/** + * TODO: This is not a complete implementation. + * RestoreFromBackupTool skeleton. + */ +public class RestoreFromBackupTool { + private static final int MAX_RETRIES = 10; + + BackupStorageProvider storage; + + FileTxnSnapLog snapLog; + long zxidToRestore; + boolean dryRun = false; + + List logs; + List snaps; + List filesToCopy; + + int mostRecentLogNeededIndex; + int snapNeededIndex; + int oldestLogNeededIndex; + + public static void usage() { + System.out.println("Usage: RestoreFromBackupTool restore "); + System.out.println(" restore_point: the point to restore to, either the string 'latest' or a zxid in hex format."); + System.out.println(" backup_store: the connection information for the backup store"); + System.out.println(" For GPFS the format is: gpfs:::"); + System.out.println(" config_path: the path to the hdfs configuration"); + System.out.println(" backup_path: the path within hdfs where the backups are stored"); + System.out.println(" data_destination: local destination path for restored snapshots"); + System.out.println(" log_destination: local destination path for restored txlogs"); + } + + /** + * Parse and validate arguments to the tool + * @param args the set of arguments + * @return true if the arguments parse correctly; false in all other cases. + * @throws IOException if the backup provider cannot be instantiated correctly. + */ + public void parseArgs(String[] args) throws ConfigException { + // Check the num of args + if (args.length != 4 && args.length != 5) { + System.err.println("Invalid number of arguments for restore command"); + usage(); + System.exit(3); + } + + // Read the restore point + if (args[0].equals("latest")) { + zxidToRestore = Long.MAX_VALUE; + } else { + int base = 10; + String numStr = args[0]; + + if (args[0].startsWith("0x")) { + numStr = args[0].substring(2); + base = 16; + } + + try { + zxidToRestore = Long.parseLong(numStr, base); + } catch (NumberFormatException nfe) { + System.err.println("Invalid number specified for restore point"); + usage(); + System.exit(4); + } + } + + // Read the storage provider args + String[] providerParts = args[2].split(":"); + + if (providerParts.length != 4 || !providerParts[0].equals("gpfs")) { + // TODO: Support other storage implementations when making this OSS-compatible + System.err.println("GPFS is the only backup provider supported or the specification is incorrect."); + usage(); + System.exit(5); + } + + // Check if this is a dry-run + if (args.length == 5) { + if (!args[4].equals("-n")) { + System.err.println("Invalid argument: " + args[4]); + usage(); + System.exit(6); + } + + dryRun = true; + } + + // TODO: Construct a BackupConfig + BackupConfig backupConfig = new BackupConfig.Builder().build().get(); + + storage = new FileSystemBackupStorage(backupConfig); + + try { + File snapDir = new File(args[3]); + File logDir = new File(args[4]); + snapLog = new FileTxnSnapLog(logDir, snapDir); + } catch (IOException ioe) { + System.err.println("Could not setup transaction log utility." + ioe); + System.exit(8); + } + + System.out.println("parseArgs successful."); + } + + public boolean runWithRetries() { + return true; + } +}