blob: 903a1e2ef9ff3f67e3d266069dbbf0566193682b [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with this
* work for additional information regarding copyright ownership. The ASF
* licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.apache.hadoop.hdfs.tools;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.RemoteIterator;
import org.apache.hadoop.hdfs.DistributedFileSystem;
import org.apache.hadoop.hdfs.protocol.AddErasureCodingPolicyResponse;
import org.apache.hadoop.hdfs.protocol.ErasureCodingPolicy;
import org.apache.hadoop.hdfs.protocol.ErasureCodingPolicyInfo;
import org.apache.hadoop.hdfs.protocol.NoECPolicySetException;
import org.apache.hadoop.hdfs.util.ECPolicyLoader;
import org.apache.hadoop.io.erasurecode.ErasureCodeConstants;
import org.apache.hadoop.tools.TableListing;
import org.apache.hadoop.util.StringUtils;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* CLI for the erasure code encoding operations.
*/
@InterfaceAudience.Private
public class ECAdmin extends Configured implements Tool {
public static final String NAME = "ec";
public static void main(String[] args) throws Exception {
final ECAdmin admin = new ECAdmin(new Configuration());
int res = ToolRunner.run(admin, args);
System.exit(res);
}
public ECAdmin(Configuration conf) {
super(conf);
}
@Override
public int run(String[] args) throws Exception {
if (args.length == 0) {
AdminHelper.printUsage(false, NAME, COMMANDS);
ToolRunner.printGenericCommandUsage(System.err);
return 1;
}
final AdminHelper.Command command = AdminHelper.determineCommand(args[0],
COMMANDS);
if (command == null) {
System.err.println("Can't understand command '" + args[0] + "'");
if (!args[0].startsWith("-")) {
System.err.println("Command names must start with dashes.");
}
AdminHelper.printUsage(false, NAME, COMMANDS);
ToolRunner.printGenericCommandUsage(System.err);
return 1;
}
final List<String> argsList = new LinkedList<>();
argsList.addAll(Arrays.asList(args).subList(1, args.length));
try {
return command.run(getConf(), argsList);
} catch (IllegalArgumentException e) {
System.err.println(AdminHelper.prettifyException(e));
return -1;
}
}
/** Command to list the set of enabled erasure coding policies. */
private static class ListECPoliciesCommand
implements AdminHelper.Command {
@Override
public String getName() {
return "-listPolicies";
}
@Override
public String getShortUsage() {
return "[" + getName() + "]\n";
}
@Override
public String getLongUsage() {
return getShortUsage() + "\n" +
"Get the list of all erasure coding policies.\n";
}
@Override
public int run(Configuration conf, List<String> args) throws IOException {
if (args.size() > 0) {
System.err.println(getName() + ": Too many arguments");
return 1;
}
final DistributedFileSystem dfs = AdminHelper.getDFS(conf);
try {
final Collection<ErasureCodingPolicyInfo> policies =
dfs.getAllErasureCodingPolicies();
if (policies.isEmpty()) {
System.out.println("There is no erasure coding policies in the " +
"cluster.");
} else {
System.out.println("Erasure Coding Policies:");
for (ErasureCodingPolicyInfo policy : policies) {
if (policy != null) {
System.out.println(policy);
}
}
}
} catch (IOException e) {
System.err.println(AdminHelper.prettifyException(e));
return 2;
}
return 0;
}
}
/** Command to add a set of erasure coding policies. */
private static class AddECPoliciesCommand
implements AdminHelper.Command {
@Override
public String getName() {
return "-addPolicies";
}
@Override
public String getShortUsage() {
return "[" + getName() + " -policyFile <file>]\n";
}
@Override
public String getLongUsage() {
final TableListing listing = AdminHelper.getOptionDescriptionListing();
listing.addRow("<file>",
"The path of the xml file which defines the EC policies to add");
return getShortUsage() + "\n" +
"Add a list of user defined erasure coding policies.\n" +
listing.toString();
}
@Override
public int run(Configuration conf, List<String> args) throws IOException {
final String filePath =
StringUtils.popOptionWithArgument("-policyFile", args);
if (filePath == null) {
System.err.println("Please specify the path with -policyFile.\nUsage: "
+ getLongUsage());
return 1;
}
if (args.size() > 0) {
System.err.println(getName() + ": Too many arguments");
return 1;
}
final DistributedFileSystem dfs = AdminHelper.getDFS(conf);
try {
List<ErasureCodingPolicy> policies =
new ECPolicyLoader().loadPolicy(filePath);
if (policies.size() > 0) {
AddErasureCodingPolicyResponse[] responses =
dfs.addErasureCodingPolicies(
policies.toArray(new ErasureCodingPolicy[policies.size()]));
for (AddErasureCodingPolicyResponse response : responses) {
System.out.println(response);
}
} else {
System.out.println("No EC policy parsed out from " + filePath);
}
} catch (IOException e) {
System.err.println(AdminHelper.prettifyException(e));
return 2;
}
return 0;
}
}
/** Command to get the erasure coding policy for a file or directory. */
private static class GetECPolicyCommand implements AdminHelper.Command {
@Override
public String getName() {
return "-getPolicy";
}
@Override
public String getShortUsage() {
return "[" + getName() + " -path <path>]\n";
}
@Override
public String getLongUsage() {
final TableListing listing = AdminHelper.getOptionDescriptionListing();
listing.addRow("<path>",
"The path of the file/directory for getting the erasure coding " +
"policy");
return getShortUsage() + "\n" +
"Get the erasure coding policy of a file/directory.\n\n" +
listing.toString();
}
@Override
public int run(Configuration conf, List<String> args) throws IOException {
final String path = StringUtils.popOptionWithArgument("-path", args);
if (path == null) {
System.err.println("Please specify the path with -path.\nUsage: " +
getLongUsage());
return 1;
}
if (args.size() > 0) {
System.err.println(getName() + ": Too many arguments");
return 1;
}
final Path p = new Path(path);
final DistributedFileSystem dfs = AdminHelper.getDFS(p.toUri(), conf);
try {
ErasureCodingPolicy ecPolicy = dfs.getErasureCodingPolicy(p);
if (ecPolicy != null) {
System.out.println(ecPolicy.getName());
} else {
System.out.println("The erasure coding policy of " + path + " is " +
"unspecified");
}
} catch (Exception e) {
System.err.println(AdminHelper.prettifyException(e));
return 2;
}
return 0;
}
}
/** Command to remove an erasure coding policy. */
private static class RemoveECPolicyCommand implements AdminHelper.Command {
@Override
public String getName() {
return "-removePolicy";
}
@Override
public String getShortUsage() {
return "[" + getName() + " -policy <policy>]\n";
}
@Override
public String getLongUsage() {
TableListing listing = AdminHelper.getOptionDescriptionListing();
listing.addRow("<policy>", "The name of the erasure coding policy");
return getShortUsage() + "\n" +
"Remove an user defined erasure coding policy.\n" +
listing.toString();
}
@Override
public int run(Configuration conf, List<String> args) throws IOException {
final String ecPolicyName = StringUtils.popOptionWithArgument(
"-policy", args);
if (ecPolicyName == null) {
System.err.println("Please specify the policy name.\nUsage: " +
getLongUsage());
return 1;
}
if (args.size() > 0) {
System.err.println(getName() + ": Too many arguments");
return 1;
}
final DistributedFileSystem dfs = AdminHelper.getDFS(conf);
try {
dfs.removeErasureCodingPolicy(ecPolicyName);
System.out.println("Erasure coding policy " + ecPolicyName +
"is removed");
} catch (IOException e) {
System.err.println(AdminHelper.prettifyException(e));
return 2;
}
return 0;
}
}
/** Command to set the erasure coding policy to a file/directory. */
private static class SetECPolicyCommand implements AdminHelper.Command {
@Override
public String getName() {
return "-setPolicy";
}
@Override
public String getShortUsage() {
return "[" + getName() +
" -path <path> [-policy <policy>] [-replicate]]\n";
}
@Override
public String getLongUsage() {
TableListing listing = AdminHelper.getOptionDescriptionListing();
listing.addRow("<path>", "The path of the file/directory to set " +
"the erasure coding policy");
listing.addRow("<policy>", "The name of the erasure coding policy");
listing.addRow("-replicate",
"force 3x replication scheme on the directory");
return getShortUsage() + "\n" +
"Set the erasure coding policy for a file/directory.\n\n" +
listing.toString() + "\n" +
"-replicate and -policy are optional arguments. They cannot been " +
"used at the same time";
}
@Override
public int run(Configuration conf, List<String> args) throws IOException {
final String path = StringUtils.popOptionWithArgument("-path", args);
if (path == null) {
System.err.println("Please specify the path for setting the EC " +
"policy.\nUsage: " + getLongUsage());
return 1;
}
String ecPolicyName = StringUtils.popOptionWithArgument("-policy",
args);
final boolean replicate = StringUtils.popOption("-replicate", args);
if (args.size() > 0) {
System.err.println(getName() + ": Too many arguments");
return 1;
}
if (replicate) {
if (ecPolicyName != null) {
System.err.println(getName() +
": -replicate and -policy cannot been used at the same time");
return 2;
}
ecPolicyName = ErasureCodeConstants.REPLICATION_POLICY_NAME;
}
final Path p = new Path(path);
final DistributedFileSystem dfs = AdminHelper.getDFS(p.toUri(), conf);
try {
dfs.setErasureCodingPolicy(p, ecPolicyName);
String actualECPolicyName = dfs.getErasureCodingPolicy(p).getName();
System.out.println("Set " + actualECPolicyName +
" erasure coding policy on "+ path);
RemoteIterator<FileStatus> dirIt = dfs.listStatusIterator(p);
if (dirIt.hasNext()) {
System.out.println("Warning: setting erasure coding policy on a " +
"non-empty directory will not automatically convert existing " +
"files to " + actualECPolicyName + " erasure coding policy");
}
} catch (Exception e) {
System.err.println(AdminHelper.prettifyException(e));
return 3;
}
return 0;
}
}
/** Command to unset the erasure coding policy set for a file/directory. */
private static class UnsetECPolicyCommand
implements AdminHelper.Command {
@Override
public String getName() {
return "-unsetPolicy";
}
@Override
public String getShortUsage() {
return "[" + getName() + " -path <path>]\n";
}
@Override
public String getLongUsage() {
TableListing listing = AdminHelper.getOptionDescriptionListing();
listing.addRow("<path>", "The path of the directory "
+ "from which the erasure coding policy will be unset.");
return getShortUsage() + "\n"
+ "Unset the erasure coding policy for a directory.\n\n"
+ listing.toString();
}
@Override
public int run(Configuration conf, List<String> args) throws IOException {
final String path = StringUtils.popOptionWithArgument("-path", args);
if (path == null) {
System.err.println("Please specify a path.\nUsage: " + getLongUsage());
return 1;
}
if (args.size() > 0) {
System.err.println(getName() + ": Too many arguments");
return 1;
}
final Path p = new Path(path);
final DistributedFileSystem dfs = AdminHelper.getDFS(p.toUri(), conf);
try {
dfs.unsetErasureCodingPolicy(p);
System.out.println("Unset erasure coding policy from " + path);
RemoteIterator<FileStatus> dirIt = dfs.listStatusIterator(p);
if (dirIt.hasNext()) {
System.out.println("Warning: unsetting erasure coding policy on a " +
"non-empty directory will not automatically convert existing" +
" files to replicated data.");
}
} catch (NoECPolicySetException e) {
System.err.println(AdminHelper.prettifyException(e));
System.err.println("Use '-setPolicy -path <PATH> -replicate' to enforce"
+ " default replication policy irrespective of EC policy"
+ " defined on parent.");
return 2;
} catch (Exception e) {
System.err.println(AdminHelper.prettifyException(e));
return 2;
}
return 0;
}
}
/** Command to list the set of supported erasure coding codecs and coders. */
private static class ListECCodecsCommand
implements AdminHelper.Command {
@Override
public String getName() {
return "-listCodecs";
}
@Override
public String getShortUsage() {
return "[" + getName() + "]\n";
}
@Override
public String getLongUsage() {
return getShortUsage() + "\n" +
"Get the list of supported erasure coding codecs and coders.\n" +
"A coder is an implementation of a codec. A codec can have " +
"different implementations, thus different coders.\n" +
"The coders for a codec are listed in a fall back order.\n";
}
@Override
public int run(Configuration conf, List<String> args) throws IOException {
if (args.size() > 0) {
System.err.println(getName() + ": Too many arguments");
return 1;
}
final DistributedFileSystem dfs = AdminHelper.getDFS(conf);
try {
Map<String, String> codecs =
dfs.getAllErasureCodingCodecs();
if (codecs.isEmpty()) {
System.out.println("No erasure coding codecs are supported on the " +
"cluster.");
} else {
System.out.println("Erasure Coding Codecs: Codec [Coder List]");
for (Map.Entry<String, String> codec : codecs.entrySet()) {
if (codec != null) {
System.out.println("\t" + codec.getKey().toUpperCase() + " ["
+ codec.getValue().toUpperCase() +"]");
}
}
}
} catch (IOException e) {
System.err.println(AdminHelper.prettifyException(e));
return 2;
}
return 0;
}
}
/** Command to enable an existing erasure coding policy. */
private static class EnableECPolicyCommand implements AdminHelper.Command {
@Override
public String getName() {
return "-enablePolicy";
}
@Override
public String getShortUsage() {
return "[" + getName() + " -policy <policy>]\n";
}
@Override
public String getLongUsage() {
TableListing listing = AdminHelper.getOptionDescriptionListing();
listing.addRow("<policy>", "The name of the erasure coding policy");
return getShortUsage() + "\n" +
"Enable the erasure coding policy.\n\n" +
listing.toString();
}
@Override
public int run(Configuration conf, List<String> args) throws IOException {
final String ecPolicyName = StringUtils.popOptionWithArgument("-policy",
args);
if (ecPolicyName == null) {
System.err.println("Please specify the policy name.\nUsage: " +
getLongUsage());
return 1;
}
if (args.size() > 0) {
System.err.println(getName() + ": Too many arguments");
return 1;
}
final DistributedFileSystem dfs = AdminHelper.getDFS(conf);
try {
dfs.enableErasureCodingPolicy(ecPolicyName);
System.out.println("Erasure coding policy " + ecPolicyName +
" is enabled");
} catch (IOException e) {
System.err.println(AdminHelper.prettifyException(e));
return 2;
}
return 0;
}
}
/** Command to disable an existing erasure coding policy. */
private static class DisableECPolicyCommand implements AdminHelper.Command {
@Override
public String getName() {
return "-disablePolicy";
}
@Override
public String getShortUsage() {
return "[" + getName() + " -policy <policy>]\n";
}
@Override
public String getLongUsage() {
TableListing listing = AdminHelper.getOptionDescriptionListing();
listing.addRow("<policy>", "The name of the erasure coding policy");
return getShortUsage() + "\n" +
"Disable the erasure coding policy.\n\n" +
listing.toString();
}
@Override
public int run(Configuration conf, List<String> args) throws IOException {
final String ecPolicyName = StringUtils.popOptionWithArgument("-policy",
args);
if (ecPolicyName == null) {
System.err.println("Please specify the policy name.\nUsage: " +
getLongUsage());
return 1;
}
if (args.size() > 0) {
System.err.println(getName() + ": Too many arguments");
return 1;
}
final DistributedFileSystem dfs = AdminHelper.getDFS(conf);
try {
dfs.disableErasureCodingPolicy(ecPolicyName);
System.out.println("Erasure coding policy " + ecPolicyName +
" is disabled");
} catch (IOException e) {
System.err.println(AdminHelper.prettifyException(e));
return 2;
}
return 0;
}
}
private static final AdminHelper.Command[] COMMANDS = {
new ListECPoliciesCommand(),
new AddECPoliciesCommand(),
new GetECPolicyCommand(),
new RemoveECPolicyCommand(),
new SetECPolicyCommand(),
new UnsetECPolicyCommand(),
new ListECCodecsCommand(),
new EnableECPolicyCommand(),
new DisableECPolicyCommand()
};
}