HDFS-6730. Create a .RAW extended attribute namespace. (clamb)
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/fs-encryption@1614535 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
415223548d
commit
9ca2f34c8f
|
@ -68,6 +68,8 @@ fs-encryption (Unreleased)
|
||||||
HDFS-6771. Require specification of an encryption key when creating
|
HDFS-6771. Require specification of an encryption key when creating
|
||||||
an encryption zone. (wang)
|
an encryption zone. (wang)
|
||||||
|
|
||||||
|
HDFS-6730. Create a .RAW extended attribute namespace. (clamb)
|
||||||
|
|
||||||
OPTIMIZATIONS
|
OPTIMIZATIONS
|
||||||
|
|
||||||
BUG FIXES
|
BUG FIXES
|
||||||
|
|
|
@ -26,8 +26,8 @@ import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
/**
|
/**
|
||||||
* XAttr is the POSIX Extended Attribute model similar to that found in
|
* XAttr is the POSIX Extended Attribute model similar to that found in
|
||||||
* traditional Operating Systems. Extended Attributes consist of one
|
* traditional Operating Systems. Extended Attributes consist of one
|
||||||
* or more name/value pairs associated with a file or directory. Four
|
* or more name/value pairs associated with a file or directory. Five
|
||||||
* namespaces are defined: user, trusted, security and system.
|
* namespaces are defined: user, trusted, security, system and raw.
|
||||||
* 1) USER namespace attributes may be used by any user to store
|
* 1) USER namespace attributes may be used by any user to store
|
||||||
* arbitrary information. Access permissions in this namespace are
|
* arbitrary information. Access permissions in this namespace are
|
||||||
* defined by a file directory's permission bits. For sticky directories,
|
* defined by a file directory's permission bits. For sticky directories,
|
||||||
|
@ -43,6 +43,12 @@ import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
* <br>
|
* <br>
|
||||||
* 4) SECURITY namespace attributes are used by the fs kernel for
|
* 4) SECURITY namespace attributes are used by the fs kernel for
|
||||||
* security features. It is not visible to users.
|
* security features. It is not visible to users.
|
||||||
|
* <br>
|
||||||
|
* 5) RAW namespace attributes are used for internal system attributes that
|
||||||
|
* sometimes need to be exposed. Like SYSTEM namespace attributes they are
|
||||||
|
* not visible to the user except when getXAttr/getXAttrs is called on a file
|
||||||
|
* or directory in the /.reserved/raw HDFS directory hierarchy. These
|
||||||
|
* attributes can only be accessed by the superuser.
|
||||||
* <p/>
|
* <p/>
|
||||||
* @see <a href="http://en.wikipedia.org/wiki/Extended_file_attributes">
|
* @see <a href="http://en.wikipedia.org/wiki/Extended_file_attributes">
|
||||||
* http://en.wikipedia.org/wiki/Extended_file_attributes</a>
|
* http://en.wikipedia.org/wiki/Extended_file_attributes</a>
|
||||||
|
@ -55,7 +61,8 @@ public class XAttr {
|
||||||
USER,
|
USER,
|
||||||
TRUSTED,
|
TRUSTED,
|
||||||
SECURITY,
|
SECURITY,
|
||||||
SYSTEM;
|
SYSTEM,
|
||||||
|
RAW;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final NameSpace ns;
|
private final NameSpace ns;
|
||||||
|
|
|
@ -49,9 +49,9 @@ public class XAttrHelper {
|
||||||
Preconditions.checkNotNull(name, "XAttr name cannot be null.");
|
Preconditions.checkNotNull(name, "XAttr name cannot be null.");
|
||||||
|
|
||||||
final int prefixIndex = name.indexOf(".");
|
final int prefixIndex = name.indexOf(".");
|
||||||
if (prefixIndex < 4) {// Prefix length is at least 4.
|
if (prefixIndex < 3) {// Prefix length is at least 3.
|
||||||
throw new HadoopIllegalArgumentException("An XAttr name must be " +
|
throw new HadoopIllegalArgumentException("An XAttr name must be " +
|
||||||
"prefixed with user/trusted/security/system, followed by a '.'");
|
"prefixed with user/trusted/security/system/raw, followed by a '.'");
|
||||||
} else if (prefixIndex == name.length() - 1) {
|
} else if (prefixIndex == name.length() - 1) {
|
||||||
throw new HadoopIllegalArgumentException("XAttr name cannot be empty.");
|
throw new HadoopIllegalArgumentException("XAttr name cannot be empty.");
|
||||||
}
|
}
|
||||||
|
@ -66,9 +66,11 @@ public class XAttrHelper {
|
||||||
ns = NameSpace.SYSTEM;
|
ns = NameSpace.SYSTEM;
|
||||||
} else if (prefix.equals(NameSpace.SECURITY.toString().toLowerCase())) {
|
} else if (prefix.equals(NameSpace.SECURITY.toString().toLowerCase())) {
|
||||||
ns = NameSpace.SECURITY;
|
ns = NameSpace.SECURITY;
|
||||||
|
} else if (prefix.equals(NameSpace.RAW.toString().toLowerCase())) {
|
||||||
|
ns = NameSpace.RAW;
|
||||||
} else {
|
} else {
|
||||||
throw new HadoopIllegalArgumentException("An XAttr name must be " +
|
throw new HadoopIllegalArgumentException("An XAttr name must be " +
|
||||||
"prefixed with user/trusted/security/system, followed by a '.'");
|
"prefixed with user/trusted/security/system/raw, followed by a '.'");
|
||||||
}
|
}
|
||||||
XAttr xAttr = (new XAttr.Builder()).setNameSpace(ns).setName(name.
|
XAttr xAttr = (new XAttr.Builder()).setNameSpace(ns).setName(name.
|
||||||
substring(prefixIndex + 1)).setValue(value).build();
|
substring(prefixIndex + 1)).setValue(value).build();
|
||||||
|
|
|
@ -1335,7 +1335,6 @@ public interface ClientProtocol {
|
||||||
* @see <a href="http://en.wikipedia.org/wiki/Extended_file_attributes">
|
* @see <a href="http://en.wikipedia.org/wiki/Extended_file_attributes">
|
||||||
* http://en.wikipedia.org/wiki/Extended_file_attributes</a>
|
* http://en.wikipedia.org/wiki/Extended_file_attributes</a>
|
||||||
* @param src file or directory
|
* @param src file or directory
|
||||||
* @param xAttrs xAttrs to get
|
|
||||||
* @return List<XAttr> <code>XAttr</code> list
|
* @return List<XAttr> <code>XAttr</code> list
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
|
@ -1345,12 +1344,15 @@ public interface ClientProtocol {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove xattr of a file or directory.Value in xAttr parameter is ignored.
|
* Remove xattr of a file or directory.Value in xAttr parameter is ignored.
|
||||||
* Name must be prefixed with user/trusted/security/system.
|
* Name must be prefixed with user/trusted/security/system/raw.
|
||||||
* <p/>
|
* <p/>
|
||||||
* A regular user only can remove xattr of "user" namespace.
|
* A regular user only can remove xattr of "user" namespace.
|
||||||
* A super user can remove xattr of "user" and "trusted" namespace.
|
* A super user can remove xattr of "user" and "trusted" namespace.
|
||||||
* XAttr of "security" and "system" namespace is only used/exposed
|
* XAttr of "security" and "system" namespace is only used/exposed
|
||||||
* internally to the FS impl.
|
* internally to the FS impl.
|
||||||
|
* The xattrs of the "raw" namespace are only used/exposed when accessed in
|
||||||
|
* the /.reserved/raw HDFS directory hierarchy. These attributes can only be
|
||||||
|
* accessed by the superuser.
|
||||||
* <p/>
|
* <p/>
|
||||||
* @see <a href="http://en.wikipedia.org/wiki/Extended_file_attributes">
|
* @see <a href="http://en.wikipedia.org/wiki/Extended_file_attributes">
|
||||||
* http://en.wikipedia.org/wiki/Extended_file_attributes</a>
|
* http://en.wikipedia.org/wiki/Extended_file_attributes</a>
|
||||||
|
|
|
@ -296,8 +296,8 @@ public final class HdfsServerConstants {
|
||||||
public static final long NAMENODE_LEASE_RECHECK_INTERVAL = 2000;
|
public static final long NAMENODE_LEASE_RECHECK_INTERVAL = 2000;
|
||||||
|
|
||||||
public static final String CRYPTO_XATTR_ENCRYPTION_ZONE =
|
public static final String CRYPTO_XATTR_ENCRYPTION_ZONE =
|
||||||
"system.hdfs.crypto.encryption.zone";
|
"raw.hdfs.crypto.encryption.zone";
|
||||||
public static final String CRYPTO_XATTR_FILE_ENCRYPTION_INFO =
|
public static final String CRYPTO_XATTR_FILE_ENCRYPTION_INFO =
|
||||||
"system.hdfs.crypto.file.encryption.info";
|
"raw.hdfs.crypto.file.encryption.info";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8594,7 +8594,8 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
|
||||||
checkXAttrSize(xAttr);
|
checkXAttrSize(xAttr);
|
||||||
HdfsFileStatus resultingStat = null;
|
HdfsFileStatus resultingStat = null;
|
||||||
FSPermissionChecker pc = getPermissionChecker();
|
FSPermissionChecker pc = getPermissionChecker();
|
||||||
XAttrPermissionFilter.checkPermissionForApi(pc, xAttr);
|
XAttrPermissionFilter.checkPermissionForApi(pc, xAttr,
|
||||||
|
FSDirectory.isReservedRawName(src));
|
||||||
checkOperation(OperationCategory.WRITE);
|
checkOperation(OperationCategory.WRITE);
|
||||||
byte[][] pathComponents = FSDirectory.getPathComponentsForReservedPath(src);
|
byte[][] pathComponents = FSDirectory.getPathComponentsForReservedPath(src);
|
||||||
writeLock();
|
writeLock();
|
||||||
|
@ -8640,10 +8641,11 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
|
||||||
String src = srcArg;
|
String src = srcArg;
|
||||||
nnConf.checkXAttrsConfigFlag();
|
nnConf.checkXAttrsConfigFlag();
|
||||||
FSPermissionChecker pc = getPermissionChecker();
|
FSPermissionChecker pc = getPermissionChecker();
|
||||||
|
final boolean isRawPath = FSDirectory.isReservedRawName(src);
|
||||||
boolean getAll = xAttrs == null || xAttrs.isEmpty();
|
boolean getAll = xAttrs == null || xAttrs.isEmpty();
|
||||||
if (!getAll) {
|
if (!getAll) {
|
||||||
try {
|
try {
|
||||||
XAttrPermissionFilter.checkPermissionForApi(pc, xAttrs);
|
XAttrPermissionFilter.checkPermissionForApi(pc, xAttrs, isRawPath);
|
||||||
} catch (AccessControlException e) {
|
} catch (AccessControlException e) {
|
||||||
logAuditEvent(false, "getXAttrs", srcArg);
|
logAuditEvent(false, "getXAttrs", srcArg);
|
||||||
throw e;
|
throw e;
|
||||||
|
@ -8660,7 +8662,7 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
|
||||||
}
|
}
|
||||||
List<XAttr> all = dir.getXAttrs(src);
|
List<XAttr> all = dir.getXAttrs(src);
|
||||||
List<XAttr> filteredAll = XAttrPermissionFilter.
|
List<XAttr> filteredAll = XAttrPermissionFilter.
|
||||||
filterXAttrsForApi(pc, all);
|
filterXAttrsForApi(pc, all, isRawPath);
|
||||||
if (getAll) {
|
if (getAll) {
|
||||||
return filteredAll;
|
return filteredAll;
|
||||||
} else {
|
} else {
|
||||||
|
@ -8696,6 +8698,7 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
|
||||||
List<XAttr> listXAttrs(String src) throws IOException {
|
List<XAttr> listXAttrs(String src) throws IOException {
|
||||||
nnConf.checkXAttrsConfigFlag();
|
nnConf.checkXAttrsConfigFlag();
|
||||||
final FSPermissionChecker pc = getPermissionChecker();
|
final FSPermissionChecker pc = getPermissionChecker();
|
||||||
|
final boolean isRawPath = FSDirectory.isReservedRawName(src);
|
||||||
checkOperation(OperationCategory.READ);
|
checkOperation(OperationCategory.READ);
|
||||||
byte[][] pathComponents = FSDirectory.getPathComponentsForReservedPath(src);
|
byte[][] pathComponents = FSDirectory.getPathComponentsForReservedPath(src);
|
||||||
readLock();
|
readLock();
|
||||||
|
@ -8708,7 +8711,7 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
|
||||||
}
|
}
|
||||||
final List<XAttr> all = dir.getXAttrs(src);
|
final List<XAttr> all = dir.getXAttrs(src);
|
||||||
final List<XAttr> filteredAll = XAttrPermissionFilter.
|
final List<XAttr> filteredAll = XAttrPermissionFilter.
|
||||||
filterXAttrsForApi(pc, all);
|
filterXAttrsForApi(pc, all, isRawPath);
|
||||||
return filteredAll;
|
return filteredAll;
|
||||||
} catch (AccessControlException e) {
|
} catch (AccessControlException e) {
|
||||||
logAuditEvent(false, "listXAttrs", src);
|
logAuditEvent(false, "listXAttrs", src);
|
||||||
|
@ -8753,7 +8756,8 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
|
||||||
nnConf.checkXAttrsConfigFlag();
|
nnConf.checkXAttrsConfigFlag();
|
||||||
HdfsFileStatus resultingStat = null;
|
HdfsFileStatus resultingStat = null;
|
||||||
FSPermissionChecker pc = getPermissionChecker();
|
FSPermissionChecker pc = getPermissionChecker();
|
||||||
XAttrPermissionFilter.checkPermissionForApi(pc, xAttr);
|
XAttrPermissionFilter.checkPermissionForApi(pc, xAttr,
|
||||||
|
FSDirectory.isReservedRawName(src));
|
||||||
checkOperation(OperationCategory.WRITE);
|
checkOperation(OperationCategory.WRITE);
|
||||||
byte[][] pathComponents = FSDirectory.getPathComponentsForReservedPath(src);
|
byte[][] pathComponents = FSDirectory.getPathComponentsForReservedPath(src);
|
||||||
writeLock();
|
writeLock();
|
||||||
|
|
|
@ -47,15 +47,27 @@ import com.google.common.base.Preconditions;
|
||||||
* <br>
|
* <br>
|
||||||
* SYSTEM - extended system attributes: these are used by the HDFS
|
* SYSTEM - extended system attributes: these are used by the HDFS
|
||||||
* core and are not available through admin/user API.
|
* core and are not available through admin/user API.
|
||||||
|
* <br>
|
||||||
|
* RAW - extended system attributes: these are used for internal system
|
||||||
|
* attributes that sometimes need to be exposed. Like SYSTEM namespace
|
||||||
|
* attributes they are not visible to the user except when getXAttr/getXAttrs
|
||||||
|
* is called on a file or directory in the /.reserved/raw HDFS directory
|
||||||
|
* hierarchy. These attributes can only be accessed by the superuser.
|
||||||
|
* </br>
|
||||||
*/
|
*/
|
||||||
@InterfaceAudience.Private
|
@InterfaceAudience.Private
|
||||||
public class XAttrPermissionFilter {
|
public class XAttrPermissionFilter {
|
||||||
|
|
||||||
static void checkPermissionForApi(FSPermissionChecker pc, XAttr xAttr)
|
static void checkPermissionForApi(FSPermissionChecker pc, XAttr xAttr,
|
||||||
|
boolean isRawPath)
|
||||||
throws AccessControlException {
|
throws AccessControlException {
|
||||||
|
final boolean isSuperUser = pc.isSuperUser();
|
||||||
if (xAttr.getNameSpace() == XAttr.NameSpace.USER ||
|
if (xAttr.getNameSpace() == XAttr.NameSpace.USER ||
|
||||||
(xAttr.getNameSpace() == XAttr.NameSpace.TRUSTED &&
|
(xAttr.getNameSpace() == XAttr.NameSpace.TRUSTED && isSuperUser)) {
|
||||||
pc.isSuperUser())) {
|
return;
|
||||||
|
}
|
||||||
|
if (xAttr.getNameSpace() == XAttr.NameSpace.RAW &&
|
||||||
|
isRawPath && isSuperUser) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw new AccessControlException("User doesn't have permission for xattr: "
|
throw new AccessControlException("User doesn't have permission for xattr: "
|
||||||
|
@ -63,30 +75,34 @@ public class XAttrPermissionFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void checkPermissionForApi(FSPermissionChecker pc,
|
static void checkPermissionForApi(FSPermissionChecker pc,
|
||||||
List<XAttr> xAttrs) throws AccessControlException {
|
List<XAttr> xAttrs, boolean isRawPath) throws AccessControlException {
|
||||||
Preconditions.checkArgument(xAttrs != null);
|
Preconditions.checkArgument(xAttrs != null);
|
||||||
if (xAttrs.isEmpty()) {
|
if (xAttrs.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (XAttr xAttr : xAttrs) {
|
for (XAttr xAttr : xAttrs) {
|
||||||
checkPermissionForApi(pc, xAttr);
|
checkPermissionForApi(pc, xAttr, isRawPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<XAttr> filterXAttrsForApi(FSPermissionChecker pc,
|
static List<XAttr> filterXAttrsForApi(FSPermissionChecker pc,
|
||||||
List<XAttr> xAttrs) {
|
List<XAttr> xAttrs, boolean isRawPath) {
|
||||||
assert xAttrs != null : "xAttrs can not be null";
|
assert xAttrs != null : "xAttrs can not be null";
|
||||||
if (xAttrs == null || xAttrs.isEmpty()) {
|
if (xAttrs == null || xAttrs.isEmpty()) {
|
||||||
return xAttrs;
|
return xAttrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<XAttr> filteredXAttrs = Lists.newArrayListWithCapacity(xAttrs.size());
|
List<XAttr> filteredXAttrs = Lists.newArrayListWithCapacity(xAttrs.size());
|
||||||
|
final boolean isSuperUser = pc.isSuperUser();
|
||||||
for (XAttr xAttr : xAttrs) {
|
for (XAttr xAttr : xAttrs) {
|
||||||
if (xAttr.getNameSpace() == XAttr.NameSpace.USER) {
|
if (xAttr.getNameSpace() == XAttr.NameSpace.USER) {
|
||||||
filteredXAttrs.add(xAttr);
|
filteredXAttrs.add(xAttr);
|
||||||
} else if (xAttr.getNameSpace() == XAttr.NameSpace.TRUSTED &&
|
} else if (xAttr.getNameSpace() == XAttr.NameSpace.TRUSTED &&
|
||||||
pc.isSuperUser()) {
|
isSuperUser) {
|
||||||
|
filteredXAttrs.add(xAttr);
|
||||||
|
} else if (xAttr.getNameSpace() == XAttr.NameSpace.RAW &&
|
||||||
|
isSuperUser && isRawPath) {
|
||||||
filteredXAttrs.add(xAttr);
|
filteredXAttrs.add(xAttr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ message XAttrProto {
|
||||||
TRUSTED = 1;
|
TRUSTED = 1;
|
||||||
SECURITY = 2;
|
SECURITY = 2;
|
||||||
SYSTEM = 3;
|
SYSTEM = 3;
|
||||||
|
RAW = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
required XAttrNamespaceProto namespace = 1;
|
required XAttrNamespaceProto namespace = 1;
|
||||||
|
|
|
@ -30,7 +30,7 @@ Extended Attributes in HDFS
|
||||||
|
|
||||||
** {Namespaces and Permissions}
|
** {Namespaces and Permissions}
|
||||||
|
|
||||||
In HDFS, as in Linux, there are four valid namespaces: <<<user>>>, <<<trusted>>>, <<<system>>>, and <<<security>>>. Each of these namespaces have different access restrictions.
|
In HDFS, there are five valid namespaces: <<<user>>>, <<<trusted>>>, <<<system>>>, <<<security>>>, and <<<raw>>>. Each of these namespaces have different access restrictions.
|
||||||
|
|
||||||
The <<<user>>> namespace is the namespace that will commonly be used by client applications. Access to extended attributes in the user namespace is controlled by the corresponding file permissions.
|
The <<<user>>> namespace is the namespace that will commonly be used by client applications. Access to extended attributes in the user namespace is controlled by the corresponding file permissions.
|
||||||
|
|
||||||
|
@ -40,6 +40,8 @@ Extended Attributes in HDFS
|
||||||
|
|
||||||
The <<<security>>> namespace is reserved for internal HDFS use. This namespace is not accessible through userspace methods. It is currently unused.
|
The <<<security>>> namespace is reserved for internal HDFS use. This namespace is not accessible through userspace methods. It is currently unused.
|
||||||
|
|
||||||
|
The <<<raw>>> namespace is reserved for internal system attributes that sometimes need to be exposed. Like <<<system>>> namespace attributes they are not visible to the user except when <<<getXAttr>>>/<<<getXAttrs>>> is called on a file or directory in the <<</.reserved/raw>>> HDFS directory hierarchy. These attributes can only be accessed by the superuser. An example of where <<<raw>>> namespace extended attributes are used is the <<<distcp>>> utility. Encryption zone meta data is stored in <<<raw.*>>> extended attributes, so as long as the administrator uses <<</.reserved/raw>>> pathnames in source and target, the encrypted files in the encryption zones are transparently copied.
|
||||||
|
|
||||||
* {Interacting with extended attributes}
|
* {Interacting with extended attributes}
|
||||||
|
|
||||||
The Hadoop shell has support for interacting with extended attributes via <<<hadoop fs -getfattr>>> and <<<hadoop fs -setfattr>>>. These commands are styled after the Linux {{{http://www.bestbits.at/acl/man/man1/getfattr.txt}getfattr(1)}} and {{{http://www.bestbits.at/acl/man/man1/setfattr.txt}setfattr(1)}} commands.
|
The Hadoop shell has support for interacting with extended attributes via <<<hadoop fs -getfattr>>> and <<<hadoop fs -setfattr>>>. These commands are styled after the Linux {{{http://www.bestbits.at/acl/man/man1/getfattr.txt}getfattr(1)}} and {{{http://www.bestbits.at/acl/man/man1/setfattr.txt}setfattr(1)}} commands.
|
||||||
|
|
|
@ -29,7 +29,7 @@ import org.junit.Test;
|
||||||
* Tests for <code>XAttr</code> objects.
|
* Tests for <code>XAttr</code> objects.
|
||||||
*/
|
*/
|
||||||
public class TestXAttr {
|
public class TestXAttr {
|
||||||
private static XAttr XATTR, XATTR1, XATTR2, XATTR3, XATTR4;
|
private static XAttr XATTR, XATTR1, XATTR2, XATTR3, XATTR4, XATTR5;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void setUp() throws Exception {
|
public static void setUp() throws Exception {
|
||||||
|
@ -58,6 +58,11 @@ public class TestXAttr {
|
||||||
.setName("name")
|
.setName("name")
|
||||||
.setValue(value)
|
.setValue(value)
|
||||||
.build();
|
.build();
|
||||||
|
XATTR5 = new XAttr.Builder()
|
||||||
|
.setNameSpace(XAttr.NameSpace.RAW)
|
||||||
|
.setName("name")
|
||||||
|
.setValue(value)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -65,14 +70,17 @@ public class TestXAttr {
|
||||||
assertNotSame(XATTR1, XATTR2);
|
assertNotSame(XATTR1, XATTR2);
|
||||||
assertNotSame(XATTR2, XATTR3);
|
assertNotSame(XATTR2, XATTR3);
|
||||||
assertNotSame(XATTR3, XATTR4);
|
assertNotSame(XATTR3, XATTR4);
|
||||||
|
assertNotSame(XATTR4, XATTR5);
|
||||||
assertEquals(XATTR, XATTR1);
|
assertEquals(XATTR, XATTR1);
|
||||||
assertEquals(XATTR1, XATTR1);
|
assertEquals(XATTR1, XATTR1);
|
||||||
assertEquals(XATTR2, XATTR2);
|
assertEquals(XATTR2, XATTR2);
|
||||||
assertEquals(XATTR3, XATTR3);
|
assertEquals(XATTR3, XATTR3);
|
||||||
assertEquals(XATTR4, XATTR4);
|
assertEquals(XATTR4, XATTR4);
|
||||||
|
assertEquals(XATTR5, XATTR5);
|
||||||
assertFalse(XATTR1.equals(XATTR2));
|
assertFalse(XATTR1.equals(XATTR2));
|
||||||
assertFalse(XATTR2.equals(XATTR3));
|
assertFalse(XATTR2.equals(XATTR3));
|
||||||
assertFalse(XATTR3.equals(XATTR4));
|
assertFalse(XATTR3.equals(XATTR4));
|
||||||
|
assertFalse(XATTR4.equals(XATTR5));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -81,5 +89,6 @@ public class TestXAttr {
|
||||||
assertFalse(XATTR1.hashCode() == XATTR2.hashCode());
|
assertFalse(XATTR1.hashCode() == XATTR2.hashCode());
|
||||||
assertFalse(XATTR2.hashCode() == XATTR3.hashCode());
|
assertFalse(XATTR2.hashCode() == XATTR3.hashCode());
|
||||||
assertFalse(XATTR3.hashCode() == XATTR4.hashCode());
|
assertFalse(XATTR3.hashCode() == XATTR4.hashCode());
|
||||||
|
assertFalse(XATTR4.hashCode() == XATTR5.hashCode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,7 @@ public class FSXAttrBaseTest {
|
||||||
protected static Configuration conf;
|
protected static Configuration conf;
|
||||||
private static int pathCount = 0;
|
private static int pathCount = 0;
|
||||||
protected static Path path;
|
protected static Path path;
|
||||||
|
protected static Path rawPath;
|
||||||
|
|
||||||
// XAttrs
|
// XAttrs
|
||||||
protected static final String name1 = "user.a1";
|
protected static final String name1 = "user.a1";
|
||||||
|
@ -78,6 +79,8 @@ public class FSXAttrBaseTest {
|
||||||
protected static final byte[] value2 = {0x37, 0x38, 0x39};
|
protected static final byte[] value2 = {0x37, 0x38, 0x39};
|
||||||
protected static final String name3 = "user.a3";
|
protected static final String name3 = "user.a3";
|
||||||
protected static final String name4 = "user.a4";
|
protected static final String name4 = "user.a4";
|
||||||
|
protected static final String raw1 = "raw.a1";
|
||||||
|
protected static final String raw2 = "raw.a2";
|
||||||
|
|
||||||
protected FileSystem fs;
|
protected FileSystem fs;
|
||||||
|
|
||||||
|
@ -107,6 +110,7 @@ public class FSXAttrBaseTest {
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
pathCount += 1;
|
pathCount += 1;
|
||||||
path = new Path("/p" + pathCount);
|
path = new Path("/p" + pathCount);
|
||||||
|
rawPath = new Path("/.reserved/raw/p" + pathCount);
|
||||||
initFileSystem();
|
initFileSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,7 +399,8 @@ public class FSXAttrBaseTest {
|
||||||
Assert.fail("expected IOException");
|
Assert.fail("expected IOException");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
GenericTestUtils.assertExceptionContains
|
GenericTestUtils.assertExceptionContains
|
||||||
("An XAttr name must be prefixed with user/trusted/security/system, " +
|
("An XAttr name must be prefixed with " +
|
||||||
|
"user/trusted/security/system/raw, " +
|
||||||
"followed by a '.'",
|
"followed by a '.'",
|
||||||
e);
|
e);
|
||||||
}
|
}
|
||||||
|
@ -582,7 +587,7 @@ public class FSXAttrBaseTest {
|
||||||
|
|
||||||
/* Unknown namespace should throw an exception. */
|
/* Unknown namespace should throw an exception. */
|
||||||
final String expectedExceptionString = "An XAttr name must be prefixed " +
|
final String expectedExceptionString = "An XAttr name must be prefixed " +
|
||||||
"with user/trusted/security/system, followed by a '.'";
|
"with user/trusted/security/system/raw, followed by a '.'";
|
||||||
try {
|
try {
|
||||||
fs.removeXAttr(path, "wackynamespace.foo");
|
fs.removeXAttr(path, "wackynamespace.foo");
|
||||||
Assert.fail("expected IOException");
|
Assert.fail("expected IOException");
|
||||||
|
@ -918,6 +923,176 @@ public class FSXAttrBaseTest {
|
||||||
fsAsDiana.removeXAttr(path, name2);
|
fsAsDiana.removeXAttr(path, name2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 120000)
|
||||||
|
public void testRawXAttrs() throws Exception {
|
||||||
|
final UserGroupInformation user = UserGroupInformation.
|
||||||
|
createUserForTesting("user", new String[] {"mygroup"});
|
||||||
|
|
||||||
|
FileSystem.mkdirs(fs, path, FsPermission.createImmutable((short) 0750));
|
||||||
|
fs.setXAttr(rawPath, raw1, value1, EnumSet.of(XAttrSetFlag.CREATE,
|
||||||
|
XAttrSetFlag.REPLACE));
|
||||||
|
|
||||||
|
{
|
||||||
|
// getXAttr
|
||||||
|
final byte[] value = fs.getXAttr(rawPath, raw1);
|
||||||
|
Assert.assertArrayEquals(value, value1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// getXAttrs
|
||||||
|
final Map<String, byte[]> xattrs = fs.getXAttrs(rawPath);
|
||||||
|
Assert.assertEquals(xattrs.size(), 1);
|
||||||
|
Assert.assertArrayEquals(value1, xattrs.get(raw1));
|
||||||
|
fs.removeXAttr(rawPath, raw1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// replace and re-get
|
||||||
|
fs.setXAttr(rawPath, raw1, value1, EnumSet.of(XAttrSetFlag.CREATE));
|
||||||
|
fs.setXAttr(rawPath, raw1, newValue1, EnumSet.of(XAttrSetFlag.CREATE,
|
||||||
|
XAttrSetFlag.REPLACE));
|
||||||
|
|
||||||
|
final Map<String,byte[]> xattrs = fs.getXAttrs(rawPath);
|
||||||
|
Assert.assertEquals(xattrs.size(), 1);
|
||||||
|
Assert.assertArrayEquals(newValue1, xattrs.get(raw1));
|
||||||
|
|
||||||
|
fs.removeXAttr(rawPath, raw1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// listXAttrs on rawPath ensuring raw.* xattrs are returned
|
||||||
|
fs.setXAttr(rawPath, raw1, value1, EnumSet.of(XAttrSetFlag.CREATE));
|
||||||
|
fs.setXAttr(rawPath, raw2, value2, EnumSet.of(XAttrSetFlag.CREATE));
|
||||||
|
|
||||||
|
final List<String> xattrNames = fs.listXAttrs(rawPath);
|
||||||
|
assertTrue(xattrNames.contains(raw1));
|
||||||
|
assertTrue(xattrNames.contains(raw2));
|
||||||
|
assertTrue(xattrNames.size() == 2);
|
||||||
|
fs.removeXAttr(rawPath, raw1);
|
||||||
|
fs.removeXAttr(rawPath, raw2);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// listXAttrs on non-rawPath ensuring no raw.* xattrs returned
|
||||||
|
fs.setXAttr(rawPath, raw1, value1, EnumSet.of(XAttrSetFlag.CREATE));
|
||||||
|
fs.setXAttr(rawPath, raw2, value2, EnumSet.of(XAttrSetFlag.CREATE));
|
||||||
|
|
||||||
|
final List<String> xattrNames = fs.listXAttrs(path);
|
||||||
|
assertTrue(xattrNames.size() == 0);
|
||||||
|
fs.removeXAttr(rawPath, raw1);
|
||||||
|
fs.removeXAttr(rawPath, raw2);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Test non-root user operations in the "raw.*" namespace.
|
||||||
|
*/
|
||||||
|
user.doAs(new PrivilegedExceptionAction<Object>() {
|
||||||
|
@Override
|
||||||
|
public Object run() throws Exception {
|
||||||
|
final FileSystem userFs = dfsCluster.getFileSystem();
|
||||||
|
// Test that non-root can not set xattrs in the "raw.*" namespace
|
||||||
|
try {
|
||||||
|
// non-raw path
|
||||||
|
userFs.setXAttr(path, raw1, value1);
|
||||||
|
fail("setXAttr should have thrown");
|
||||||
|
} catch (AccessControlException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// raw path
|
||||||
|
userFs.setXAttr(rawPath, raw1, value1);
|
||||||
|
fail("setXAttr should have thrown");
|
||||||
|
} catch (AccessControlException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that non-root can not do getXAttrs in the "raw.*" namespace
|
||||||
|
try {
|
||||||
|
// non-raw path
|
||||||
|
userFs.getXAttrs(rawPath);
|
||||||
|
fail("getXAttrs should have thrown");
|
||||||
|
} catch (AccessControlException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// raw path
|
||||||
|
userFs.getXAttrs(path);
|
||||||
|
fail("getXAttrs should have thrown");
|
||||||
|
} catch (AccessControlException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that non-root can not do getXAttr in the "raw.*" namespace
|
||||||
|
try {
|
||||||
|
// non-raw path
|
||||||
|
userFs.getXAttr(rawPath, raw1);
|
||||||
|
fail("getXAttr should have thrown");
|
||||||
|
} catch (AccessControlException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// raw path
|
||||||
|
userFs.getXAttr(path, raw1);
|
||||||
|
fail("getXAttr should have thrown");
|
||||||
|
} catch (AccessControlException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Test that non-root can not do getXAttr in the "raw.*" namespace
|
||||||
|
*/
|
||||||
|
fs.setXAttr(rawPath, raw1, value1);
|
||||||
|
user.doAs(new PrivilegedExceptionAction<Object>() {
|
||||||
|
@Override
|
||||||
|
public Object run() throws Exception {
|
||||||
|
final FileSystem userFs = dfsCluster.getFileSystem();
|
||||||
|
try {
|
||||||
|
// non-raw path
|
||||||
|
userFs.getXAttr(rawPath, raw1);
|
||||||
|
fail("getXAttr should have thrown");
|
||||||
|
} catch (AccessControlException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// raw path
|
||||||
|
userFs.getXAttr(path, raw1);
|
||||||
|
fail("getXAttr should have thrown");
|
||||||
|
} catch (AccessControlException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test that only root can see raw.* xattrs returned from listXAttr
|
||||||
|
* and non-root can't do listXAttrs on /.reserved/raw.
|
||||||
|
*/
|
||||||
|
// non-raw path
|
||||||
|
final List<String> xattrNames = userFs.listXAttrs(path);
|
||||||
|
assertTrue(xattrNames.size() == 0);
|
||||||
|
try {
|
||||||
|
// raw path
|
||||||
|
userFs.listXAttrs(rawPath);
|
||||||
|
fail("listXAttrs on raw path should have thrown");
|
||||||
|
} catch (AccessControlException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
fs.removeXAttr(rawPath, raw1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a FileSystem for the super-user.
|
* Creates a FileSystem for the super-user.
|
||||||
*
|
*
|
||||||
|
|
|
@ -191,14 +191,19 @@ public class TestFSDirectory {
|
||||||
existingXAttrs.add(xAttr1);
|
existingXAttrs.add(xAttr1);
|
||||||
existingXAttrs.add(xAttr2);
|
existingXAttrs.add(xAttr2);
|
||||||
|
|
||||||
// Adding a system namespace xAttr, isn't affected by inode xAttrs limit.
|
// Adding system and raw namespace xAttrs aren't affected by inode
|
||||||
XAttr newXAttr = (new XAttr.Builder()).setNameSpace(XAttr.NameSpace.SYSTEM).
|
// xAttrs limit.
|
||||||
|
XAttr newSystemXAttr = (new XAttr.Builder()).
|
||||||
|
setNameSpace(XAttr.NameSpace.SYSTEM).setName("a3").
|
||||||
|
setValue(new byte[]{0x33, 0x33, 0x33}).build();
|
||||||
|
XAttr newRawXAttr = (new XAttr.Builder()).setNameSpace(XAttr.NameSpace.RAW).
|
||||||
setName("a3").setValue(new byte[]{0x33, 0x33, 0x33}).build();
|
setName("a3").setValue(new byte[]{0x33, 0x33, 0x33}).build();
|
||||||
List<XAttr> newXAttrs = Lists.newArrayListWithCapacity(1);
|
List<XAttr> newXAttrs = Lists.newArrayListWithCapacity(2);
|
||||||
newXAttrs.add(newXAttr);
|
newXAttrs.add(newSystemXAttr);
|
||||||
|
newXAttrs.add(newRawXAttr);
|
||||||
List<XAttr> xAttrs = fsdir.setINodeXAttrs(existingXAttrs, newXAttrs,
|
List<XAttr> xAttrs = fsdir.setINodeXAttrs(existingXAttrs, newXAttrs,
|
||||||
EnumSet.of(XAttrSetFlag.CREATE, XAttrSetFlag.REPLACE));
|
EnumSet.of(XAttrSetFlag.CREATE, XAttrSetFlag.REPLACE));
|
||||||
assertEquals(xAttrs.size(), 3);
|
assertEquals(xAttrs.size(), 4);
|
||||||
|
|
||||||
// Adding a trusted namespace xAttr, is affected by inode xAttrs limit.
|
// Adding a trusted namespace xAttr, is affected by inode xAttrs limit.
|
||||||
XAttr newXAttr1 = (new XAttr.Builder()).setNameSpace(
|
XAttr newXAttr1 = (new XAttr.Builder()).setNameSpace(
|
||||||
|
|
|
@ -64,7 +64,7 @@
|
||||||
<comparators>
|
<comparators>
|
||||||
<comparator>
|
<comparator>
|
||||||
<type>SubstringComparator</type>
|
<type>SubstringComparator</type>
|
||||||
<expected-output>name must be prefixed with user/trusted/security/system, followed by a '.'</expected-output>
|
<expected-output>name must be prefixed with user/trusted/security/system/raw, followed by a '.'</expected-output>
|
||||||
</comparator>
|
</comparator>
|
||||||
</comparators>
|
</comparators>
|
||||||
</test>
|
</test>
|
||||||
|
@ -125,6 +125,42 @@
|
||||||
</comparators>
|
</comparators>
|
||||||
</test>
|
</test>
|
||||||
|
|
||||||
|
<test>
|
||||||
|
<description>setfattr : Add an xattr of raw namespace</description>
|
||||||
|
<test-commands>
|
||||||
|
<command>-fs NAMENODE -touchz /file1</command>
|
||||||
|
<command>-fs NAMENODE -setfattr -n raw.a1 -v 123456 /file1</command>
|
||||||
|
</test-commands>
|
||||||
|
<cleanup-commands>
|
||||||
|
<command>-fs NAMENODE -rm /file1</command>
|
||||||
|
</cleanup-commands>
|
||||||
|
<comparators>
|
||||||
|
<comparator>
|
||||||
|
<type>SubstringComparator</type>
|
||||||
|
<expected-output>setfattr: User doesn't have permission for xattr: raw.a1</expected-output>
|
||||||
|
</comparator>
|
||||||
|
</comparators>
|
||||||
|
|
||||||
|
</test>
|
||||||
|
|
||||||
|
<test>
|
||||||
|
<description>setfattr : Add an xattr of raw namespace</description>
|
||||||
|
<test-commands>
|
||||||
|
<command>-fs NAMENODE -touchz /file1</command>
|
||||||
|
<command>-fs NAMENODE -setfattr -n raw.a1 -v 123456 /.reserved/raw/file1</command>
|
||||||
|
<command>-fs NAMENODE -getfattr -n raw.a1 /.reserved/raw/file1</command>
|
||||||
|
</test-commands>
|
||||||
|
<cleanup-commands>
|
||||||
|
<command>-fs NAMENODE -rm /file1</command>
|
||||||
|
</cleanup-commands>
|
||||||
|
<comparators>
|
||||||
|
<comparator>
|
||||||
|
<type>SubstringComparator</type>
|
||||||
|
<expected-output>raw.a1="123456"</expected-output>
|
||||||
|
</comparator>
|
||||||
|
</comparators>
|
||||||
|
</test>
|
||||||
|
|
||||||
<test>
|
<test>
|
||||||
<description>setfattr : Add an xattr, and encode is text</description>
|
<description>setfattr : Add an xattr, and encode is text</description>
|
||||||
<test-commands>
|
<test-commands>
|
||||||
|
@ -256,6 +292,26 @@
|
||||||
</comparator>
|
</comparator>
|
||||||
</comparators>
|
</comparators>
|
||||||
</test>
|
</test>
|
||||||
|
|
||||||
|
<test>
|
||||||
|
<description>setfattr : Remove an xattr of raw namespace</description>
|
||||||
|
<test-commands>
|
||||||
|
<command>-fs NAMENODE -touchz /file1</command>
|
||||||
|
<command>-fs NAMENODE -setfattr -n raw.a1 -v 123456 /.reserved/raw/file1</command>
|
||||||
|
<command>-fs NAMENODE -setfattr -n raw.a2 -v 123456 /.reserved/raw/file1</command>
|
||||||
|
<command>-fs NAMENODE -setfattr -x raw.a2 /.reserved/raw/file1</command>
|
||||||
|
<command>-fs NAMENODE -getfattr -d /.reserved/raw/file1</command>
|
||||||
|
</test-commands>
|
||||||
|
<cleanup-commands>
|
||||||
|
<command>-fs NAMENODE -rm /file1</command>
|
||||||
|
</cleanup-commands>
|
||||||
|
<comparators>
|
||||||
|
<comparator>
|
||||||
|
<type>SubstringComparator</type>
|
||||||
|
<expected-output># file: /.reserved/raw/file1#LF#raw.a1="123456"#LF#</expected-output>
|
||||||
|
</comparator>
|
||||||
|
</comparators>
|
||||||
|
</test>
|
||||||
|
|
||||||
<test>
|
<test>
|
||||||
<description>getfattr : Get an xattr</description>
|
<description>getfattr : Get an xattr</description>
|
||||||
|
|
Loading…
Reference in New Issue