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:
Charles Lamb 2014-07-30 01:35:04 +00:00
parent 415223548d
commit 9ca2f34c8f
13 changed files with 313 additions and 32 deletions

View File

@ -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

View File

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

View File

@ -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();

View File

@ -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>

View File

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

View File

@ -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();

View File

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

View File

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

View File

@ -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.

View File

@ -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());
} }
} }

View File

@ -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.
* *

View File

@ -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(

View File

@ -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>