Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RestoreCommand as CliCommand #29

Draft
wants to merge 1 commit into
base: li-dev/release-3.6.2-1-backup
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<String, CliCommand> entry : commandMapCli.entrySet()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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",
"<restore point (zxid)> "
+ "<backup storage type:storage config type:backup path:namespace> "
+ "<snapshot destination path> "
+ "<log destination path> "
+ "<-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();
}
}
Original file line number Diff line number Diff line change
@@ -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<BackupFileInfo> logs;
List<BackupFileInfo> snaps;
List<BackupFileInfo> filesToCopy;

int mostRecentLogNeededIndex;
int snapNeededIndex;
int oldestLogNeededIndex;

public static void usage() {
System.out.println("Usage: RestoreFromBackupTool restore <restore_point> <backup_store> <data_destination> <log_destination>");
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:<config_path>:<backup_path>:<namespace>");
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) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From a cli perspective, it is not a good idea to fix the number of arguments. Also order of arguments should not matter. The better way could be scanning the input arguments to find whether there is a matching option.

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");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: you may output the numStr as well.

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);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use reflection to make this flexible too?


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;
}
}