HDFS-10918. Add a tool to get FileEncryptionInfo from CLI. Contributed by Xiao Chen.

This commit is contained in:
Xiao Chen 2016-10-03 16:01:54 -07:00
parent 736d33cddd
commit 853d65a157
6 changed files with 221 additions and 1 deletions

View File

@ -121,4 +121,25 @@ public class FileEncryptionInfo {
builder.append("}"); builder.append("}");
return builder.toString(); return builder.toString();
} }
/**
* A frozen version of {@link #toString()} to be backward compatible.
* When backward compatibility is not needed, use {@link #toString()}, which
* provides more info and is supposed to evolve.
* Don't change this method except for major revisions.
*
* NOTE:
* Currently this method is used by CLI for backward compatibility.
*/
public String toStringStable() {
StringBuilder builder = new StringBuilder("{");
builder.append("cipherSuite: " + cipherSuite);
builder.append(", cryptoProtocolVersion: " + version);
builder.append(", edek: " + Hex.encodeHexString(edek));
builder.append(", iv: " + Hex.encodeHexString(iv));
builder.append(", keyName: " + keyName);
builder.append(", ezKeyVersionName: " + ezKeyVersionName);
builder.append("}");
return builder.toString();
}
} }

View File

@ -41,6 +41,7 @@ import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FSLinkResolver; import org.apache.hadoop.fs.FSLinkResolver;
import org.apache.hadoop.fs.FileChecksum; import org.apache.hadoop.fs.FileChecksum;
import org.apache.hadoop.fs.FileEncryptionInfo;
import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FileSystemLinkResolver; import org.apache.hadoop.fs.FileSystemLinkResolver;
@ -2204,6 +2205,35 @@ public class DistributedFileSystem extends FileSystem {
return dfs.listEncryptionZones(); return dfs.listEncryptionZones();
} }
/* HDFS only */
public FileEncryptionInfo getFileEncryptionInfo(final Path path)
throws IOException {
Path absF = fixRelativePart(path);
return new FileSystemLinkResolver<FileEncryptionInfo>() {
@Override
public FileEncryptionInfo doCall(final Path p) throws IOException {
final HdfsFileStatus fi = dfs.getFileInfo(getPathName(p));
if (fi == null) {
throw new FileNotFoundException("File does not exist: " + p);
}
return fi.getFileEncryptionInfo();
}
@Override
public FileEncryptionInfo next(final FileSystem fs, final Path p)
throws IOException {
if (fs instanceof DistributedFileSystem) {
DistributedFileSystem myDfs = (DistributedFileSystem)fs;
return myDfs.getFileEncryptionInfo(p);
}
throw new UnsupportedOperationException(
"Cannot call getFileEncryptionInfo"
+ " on a symlink to a non-DistributedFileSystem: " + path
+ " -> " + p);
}
}.resolve(this, absF);
}
@Override @Override
public void setXAttr(Path path, final String name, final byte[] value, public void setXAttr(Path path, final String name, final byte[] value,
final EnumSet<XAttrSetFlag> flag) throws IOException { final EnumSet<XAttrSetFlag> flag) throws IOException {

View File

@ -29,6 +29,7 @@ import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.BlockStoragePolicySpi; import org.apache.hadoop.fs.BlockStoragePolicySpi;
import org.apache.hadoop.fs.CacheFlag; import org.apache.hadoop.fs.CacheFlag;
import org.apache.hadoop.fs.FileEncryptionInfo;
import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.Path;
@ -353,6 +354,19 @@ public class HdfsAdmin {
return dfs.listEncryptionZones(); return dfs.listEncryptionZones();
} }
/**
* Returns the FileEncryptionInfo on the HdfsFileStatus for the given path.
* The return value can be null if the path points to a directory, or a file
* that is not in an encryption zone.
*
* @throws FileNotFoundException if the path does not exist.
* @throws AccessControlException if no execute permission on parent path.
*/
public FileEncryptionInfo getFileEncryptionInfo(final Path path)
throws IOException {
return dfs.getFileEncryptionInfo(path);
}
/** /**
* Exposes a stream of namesystem events. Only events occurring after the * Exposes a stream of namesystem events. Only events occurring after the
* stream is created are available. * stream is created are available.

View File

@ -25,6 +25,7 @@ import java.util.List;
import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured; import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.FileEncryptionInfo;
import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.RemoteIterator; import org.apache.hadoop.fs.RemoteIterator;
@ -193,6 +194,53 @@ public class CryptoAdmin extends Configured implements Tool {
} }
} }
private static class GetFileEncryptionInfoCommand
implements AdminHelper.Command {
@Override
public String getName() {
return "-getFileEncryptionInfo";
}
@Override
public String getShortUsage() {
return "[" + getName() + " -path <path>]\n";
}
@Override
public String getLongUsage() {
final TableListing listing = AdminHelper.getOptionDescriptionListing();
listing.addRow("<path>", "The path to the file to show encryption info.");
return getShortUsage() + "\n" + "Get encryption info of a file.\n\n" +
listing.toString();
}
@Override
public int run(Configuration conf, List<String> args) throws IOException {
final String path = StringUtils.popOptionWithArgument("-path", args);
if (!args.isEmpty()) {
System.err.println("Can't understand argument: " + args.get(0));
return 1;
}
final HdfsAdmin admin =
new HdfsAdmin(FileSystem.getDefaultUri(conf), conf);
try {
final FileEncryptionInfo fei =
admin.getFileEncryptionInfo(new Path(path));
if (fei == null) {
System.out.println("No FileEncryptionInfo found for path " + path);
return 2;
}
System.out.println(fei.toStringStable());
} catch (IOException e) {
System.err.println(prettifyException(e));
return 3;
}
return 0;
}
}
private static class ProvisionTrashCommand implements AdminHelper.Command { private static class ProvisionTrashCommand implements AdminHelper.Command {
@Override @Override
public String getName() { public String getName() {
@ -237,6 +285,7 @@ public class CryptoAdmin extends Configured implements Tool {
private static final AdminHelper.Command[] COMMANDS = { private static final AdminHelper.Command[] COMMANDS = {
new CreateZoneCommand(), new CreateZoneCommand(),
new ListZonesCommand(), new ListZonesCommand(),
new ProvisionTrashCommand() new ProvisionTrashCommand(),
new GetFileEncryptionInfoCommand()
}; };
} }

View File

@ -29,6 +29,8 @@ Transparent Encryption in HDFS
* [crypto command-line interface](#crypto_command-line_interface) * [crypto command-line interface](#crypto_command-line_interface)
* [createZone](#createZone) * [createZone](#createZone)
* [listZones](#listZones) * [listZones](#listZones)
* [provisionTrash](#provisionTrash)
* [getFileEncryptionInfo](#getFileEncryptionInfo)
* [Example usage](#Example_usage) * [Example usage](#Example_usage)
* [Distcp considerations](#Distcp_considerations) * [Distcp considerations](#Distcp_considerations)
* [Running as the superuser](#Running_as_the_superuser) * [Running as the superuser](#Running_as_the_superuser)
@ -189,6 +191,16 @@ Provision a trash directory for an encryption zone.
|:---- |:---- | |:---- |:---- |
| *path* | The path to the root of the encryption zone. | | *path* | The path to the root of the encryption zone. |
### <a name="getFileEncryptionInfo"></a>getFileEncryptionInfo
Usage: `[-getFileEncryptionInfo -path <path>]`
Get encryption information from a file. This can be used to find out whether a file is being encrypted, and the key name / key version used to encrypt it.
| | |
|:---- |:---- |
| *path* | The path of the file to get encryption information. |
<a name="Example_usage"></a>Example usage <a name="Example_usage"></a>Example usage
------------- -------------
@ -208,6 +220,10 @@ These instructions assume that you are running as the normal user or HDFS superu
hadoop fs -put helloWorld /zone hadoop fs -put helloWorld /zone
hadoop fs -cat /zone/helloWorld hadoop fs -cat /zone/helloWorld
# As the normal user, get encryption information from the file
hdfs crypto -getFileEncryptionInfo -path /zone/helloWorld
# console output: {cipherSuite: {name: AES/CTR/NoPadding, algorithmBlockSize: 16}, cryptoProtocolVersion: CryptoProtocolVersion{description='Encryption zones', version=1, unknownValue=null}, edek: 2010d301afbd43b58f10737ce4e93b39, iv: ade2293db2bab1a2e337f91361304cb3, keyName: mykey, ezKeyVersionName: mykey@0}
<a name="Distcp_considerations"></a>Distcp considerations <a name="Distcp_considerations"></a>Distcp considerations
--------------------- ---------------------

View File

@ -388,5 +388,95 @@
</comparator> </comparator>
</comparators> </comparators>
</test> </test>
<test>
<description>Test success of getFileEncryptionInfo on a EZ file</description>
<test-commands>
<command>-fs NAMENODE -mkdir /src</command>
<crypto-admin-command>-createZone -path /src -keyName myKey</crypto-admin-command>
<command>-fs NAMENODE -touchz /src/file</command>
<crypto-admin-command>-getFileEncryptionInfo -path /src/file</crypto-admin-command>
</test-commands>
<cleanup-commands>
<command>-fs NAMENODE -rm -r /src</command>
</cleanup-commands>
<comparators>
<comparator>
<type>SubstringComparator</type>
<expected-output>keyName: myKey, ezKeyVersionName: myKey@0</expected-output>
</comparator>
</comparators>
</test>
<test>
<description>Test failure of getFileEncryptionInfo on a non-EZ file</description>
<test-commands>
<command>-fs NAMENODE -mkdir /src</command>
<command>-fs NAMENODE -touchz /src/cleartext</command>
<crypto-admin-command>-getFileEncryptionInfo -path /src/cleartext</crypto-admin-command>
</test-commands>
<cleanup-commands>
<command>-fs NAMENODE -rm -r /src</command>
</cleanup-commands>
<comparators>
<comparator>
<type>SubstringComparator</type>
<expected-output>No FileEncryptionInfo found for path</expected-output>
</comparator>
</comparators>
</test>
<test>
<description>Test failure of getFileEncryptionInfo on a non-exist file</description>
<test-commands>
<crypto-admin-command>-getFileEncryptionInfo -path /src/file</crypto-admin-command>
</test-commands>
<cleanup-commands>
<command>-fs NAMENODE -rm -r /src</command>
</cleanup-commands>
<comparators>
<comparator>
<type>SubstringComparator</type>
<expected-output>FileNotFoundException:</expected-output>
</comparator>
</comparators>
</test>
<test>
<description>Test failure of getFileEncryptionInfo on a EZ dir</description>
<test-commands>
<command>-fs NAMENODE -mkdir /src</command>
<crypto-admin-command>-createZone -path /src -keyName myKey</crypto-admin-command>
<crypto-admin-command>-getFileEncryptionInfo -path /src</crypto-admin-command>
</test-commands>
<cleanup-commands>
<command>-fs NAMENODE -rm -r /src</command>
</cleanup-commands>
<comparators>
<comparator>
<type>SubstringComparator</type>
<expected-output>No FileEncryptionInfo found for path </expected-output>
</comparator>
</comparators>
</test>
<test>
<description>Test failure of getFileEncryptionInfo on a EZ subdir</description>
<test-commands>
<command>-fs NAMENODE -mkdir /src</command>
<crypto-admin-command>-createZone -path /src -keyName myKey</crypto-admin-command>
<command>-fs NAMENODE -mkdir /src/dir</command>
<crypto-admin-command>-getFileEncryptionInfo -path /src/dir</crypto-admin-command>
</test-commands>
<cleanup-commands>
<command>-fs NAMENODE -rm -r /src</command>
</cleanup-commands>
<comparators>
<comparator>
<type>SubstringComparator</type>
<expected-output>No FileEncryptionInfo found for path </expected-output>
</comparator>
</comparators>
</test>
</tests> </tests>
</configuration> </configuration>