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
an encryption zone. (wang)
HDFS-6730. Create a .RAW extended attribute namespace. (clamb)
OPTIMIZATIONS
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
* traditional Operating Systems. Extended Attributes consist of one
* or more name/value pairs associated with a file or directory. Four
* namespaces are defined: user, trusted, security and system.
* or more name/value pairs associated with a file or directory. Five
* namespaces are defined: user, trusted, security, system and raw.
* 1) USER namespace attributes may be used by any user to store
* arbitrary information. Access permissions in this namespace are
* defined by a file directory's permission bits. For sticky directories,
@ -43,6 +43,12 @@ import org.apache.hadoop.classification.InterfaceAudience;
* <br>
* 4) SECURITY namespace attributes are used by the fs kernel for
* 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/>
* @see <a href="http://en.wikipedia.org/wiki/Extended_file_attributes">
* http://en.wikipedia.org/wiki/Extended_file_attributes</a>
@ -55,7 +61,8 @@ public class XAttr {
USER,
TRUSTED,
SECURITY,
SYSTEM;
SYSTEM,
RAW;
}
private final NameSpace ns;

View File

@ -49,9 +49,9 @@ public class XAttrHelper {
Preconditions.checkNotNull(name, "XAttr name cannot be null.");
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 " +
"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) {
throw new HadoopIllegalArgumentException("XAttr name cannot be empty.");
}
@ -66,9 +66,11 @@ public class XAttrHelper {
ns = NameSpace.SYSTEM;
} else if (prefix.equals(NameSpace.SECURITY.toString().toLowerCase())) {
ns = NameSpace.SECURITY;
} else if (prefix.equals(NameSpace.RAW.toString().toLowerCase())) {
ns = NameSpace.RAW;
} else {
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.
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">
* http://en.wikipedia.org/wiki/Extended_file_attributes</a>
* @param src file or directory
* @param xAttrs xAttrs to get
* @return List<XAttr> <code>XAttr</code> list
* @throws IOException
*/
@ -1345,12 +1344,15 @@ public interface ClientProtocol {
/**
* 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/>
* A regular user only can remove xattr of "user" namespace.
* A super user can remove xattr of "user" and "trusted" namespace.
* XAttr of "security" and "system" namespace is only used/exposed
* 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/>
* @see <a href="http://en.wikipedia.org/wiki/Extended_file_attributes">
* 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 String CRYPTO_XATTR_ENCRYPTION_ZONE =
"system.hdfs.crypto.encryption.zone";
"raw.hdfs.crypto.encryption.zone";
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);
HdfsFileStatus resultingStat = null;
FSPermissionChecker pc = getPermissionChecker();
XAttrPermissionFilter.checkPermissionForApi(pc, xAttr);
XAttrPermissionFilter.checkPermissionForApi(pc, xAttr,
FSDirectory.isReservedRawName(src));
checkOperation(OperationCategory.WRITE);
byte[][] pathComponents = FSDirectory.getPathComponentsForReservedPath(src);
writeLock();
@ -8640,10 +8641,11 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
String src = srcArg;
nnConf.checkXAttrsConfigFlag();
FSPermissionChecker pc = getPermissionChecker();
final boolean isRawPath = FSDirectory.isReservedRawName(src);
boolean getAll = xAttrs == null || xAttrs.isEmpty();
if (!getAll) {
try {
XAttrPermissionFilter.checkPermissionForApi(pc, xAttrs);
XAttrPermissionFilter.checkPermissionForApi(pc, xAttrs, isRawPath);
} catch (AccessControlException e) {
logAuditEvent(false, "getXAttrs", srcArg);
throw e;
@ -8660,7 +8662,7 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
}
List<XAttr> all = dir.getXAttrs(src);
List<XAttr> filteredAll = XAttrPermissionFilter.
filterXAttrsForApi(pc, all);
filterXAttrsForApi(pc, all, isRawPath);
if (getAll) {
return filteredAll;
} else {
@ -8696,6 +8698,7 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
List<XAttr> listXAttrs(String src) throws IOException {
nnConf.checkXAttrsConfigFlag();
final FSPermissionChecker pc = getPermissionChecker();
final boolean isRawPath = FSDirectory.isReservedRawName(src);
checkOperation(OperationCategory.READ);
byte[][] pathComponents = FSDirectory.getPathComponentsForReservedPath(src);
readLock();
@ -8708,7 +8711,7 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
}
final List<XAttr> all = dir.getXAttrs(src);
final List<XAttr> filteredAll = XAttrPermissionFilter.
filterXAttrsForApi(pc, all);
filterXAttrsForApi(pc, all, isRawPath);
return filteredAll;
} catch (AccessControlException e) {
logAuditEvent(false, "listXAttrs", src);
@ -8753,7 +8756,8 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
nnConf.checkXAttrsConfigFlag();
HdfsFileStatus resultingStat = null;
FSPermissionChecker pc = getPermissionChecker();
XAttrPermissionFilter.checkPermissionForApi(pc, xAttr);
XAttrPermissionFilter.checkPermissionForApi(pc, xAttr,
FSDirectory.isReservedRawName(src));
checkOperation(OperationCategory.WRITE);
byte[][] pathComponents = FSDirectory.getPathComponentsForReservedPath(src);
writeLock();

View File

@ -47,15 +47,27 @@ import com.google.common.base.Preconditions;
* <br>
* SYSTEM - extended system attributes: these are used by the HDFS
* 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
public class XAttrPermissionFilter {
static void checkPermissionForApi(FSPermissionChecker pc, XAttr xAttr)
static void checkPermissionForApi(FSPermissionChecker pc, XAttr xAttr,
boolean isRawPath)
throws AccessControlException {
final boolean isSuperUser = pc.isSuperUser();
if (xAttr.getNameSpace() == XAttr.NameSpace.USER ||
(xAttr.getNameSpace() == XAttr.NameSpace.TRUSTED &&
pc.isSuperUser())) {
(xAttr.getNameSpace() == XAttr.NameSpace.TRUSTED && isSuperUser)) {
return;
}
if (xAttr.getNameSpace() == XAttr.NameSpace.RAW &&
isRawPath && isSuperUser) {
return;
}
throw new AccessControlException("User doesn't have permission for xattr: "
@ -63,30 +75,34 @@ public class XAttrPermissionFilter {
}
static void checkPermissionForApi(FSPermissionChecker pc,
List<XAttr> xAttrs) throws AccessControlException {
List<XAttr> xAttrs, boolean isRawPath) throws AccessControlException {
Preconditions.checkArgument(xAttrs != null);
if (xAttrs.isEmpty()) {
return;
}
for (XAttr xAttr : xAttrs) {
checkPermissionForApi(pc, xAttr);
checkPermissionForApi(pc, xAttr, isRawPath);
}
}
static List<XAttr> filterXAttrsForApi(FSPermissionChecker pc,
List<XAttr> xAttrs) {
List<XAttr> xAttrs, boolean isRawPath) {
assert xAttrs != null : "xAttrs can not be null";
if (xAttrs == null || xAttrs.isEmpty()) {
return xAttrs;
}
List<XAttr> filteredXAttrs = Lists.newArrayListWithCapacity(xAttrs.size());
final boolean isSuperUser = pc.isSuperUser();
for (XAttr xAttr : xAttrs) {
if (xAttr.getNameSpace() == XAttr.NameSpace.USER) {
filteredXAttrs.add(xAttr);
} 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);
}
}

View File

@ -27,6 +27,7 @@ message XAttrProto {
TRUSTED = 1;
SECURITY = 2;
SYSTEM = 3;
RAW = 4;
}
required XAttrNamespaceProto namespace = 1;

View File

@ -30,7 +30,7 @@ Extended Attributes in HDFS
** {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.
@ -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 <<<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}
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.
*/
public class TestXAttr {
private static XAttr XATTR, XATTR1, XATTR2, XATTR3, XATTR4;
private static XAttr XATTR, XATTR1, XATTR2, XATTR3, XATTR4, XATTR5;
@BeforeClass
public static void setUp() throws Exception {
@ -58,6 +58,11 @@ public class TestXAttr {
.setName("name")
.setValue(value)
.build();
XATTR5 = new XAttr.Builder()
.setNameSpace(XAttr.NameSpace.RAW)
.setName("name")
.setValue(value)
.build();
}
@Test
@ -65,14 +70,17 @@ public class TestXAttr {
assertNotSame(XATTR1, XATTR2);
assertNotSame(XATTR2, XATTR3);
assertNotSame(XATTR3, XATTR4);
assertNotSame(XATTR4, XATTR5);
assertEquals(XATTR, XATTR1);
assertEquals(XATTR1, XATTR1);
assertEquals(XATTR2, XATTR2);
assertEquals(XATTR3, XATTR3);
assertEquals(XATTR4, XATTR4);
assertEquals(XATTR5, XATTR5);
assertFalse(XATTR1.equals(XATTR2));
assertFalse(XATTR2.equals(XATTR3));
assertFalse(XATTR3.equals(XATTR4));
assertFalse(XATTR4.equals(XATTR5));
}
@Test
@ -81,5 +89,6 @@ public class TestXAttr {
assertFalse(XATTR1.hashCode() == XATTR2.hashCode());
assertFalse(XATTR2.hashCode() == XATTR3.hashCode());
assertFalse(XATTR3.hashCode() == XATTR4.hashCode());
assertFalse(XATTR4.hashCode() == XATTR5.hashCode());
}
}

View File

@ -69,6 +69,7 @@ public class FSXAttrBaseTest {
protected static Configuration conf;
private static int pathCount = 0;
protected static Path path;
protected static Path rawPath;
// XAttrs
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 String name3 = "user.a3";
protected static final String name4 = "user.a4";
protected static final String raw1 = "raw.a1";
protected static final String raw2 = "raw.a2";
protected FileSystem fs;
@ -107,6 +110,7 @@ public class FSXAttrBaseTest {
public void setUp() throws Exception {
pathCount += 1;
path = new Path("/p" + pathCount);
rawPath = new Path("/.reserved/raw/p" + pathCount);
initFileSystem();
}
@ -395,7 +399,8 @@ public class FSXAttrBaseTest {
Assert.fail("expected IOException");
} catch (Exception e) {
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 '.'",
e);
}
@ -582,7 +587,7 @@ public class FSXAttrBaseTest {
/* Unknown namespace should throw an exception. */
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 {
fs.removeXAttr(path, "wackynamespace.foo");
Assert.fail("expected IOException");
@ -918,6 +923,176 @@ public class FSXAttrBaseTest {
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.
*

View File

@ -191,14 +191,19 @@ public class TestFSDirectory {
existingXAttrs.add(xAttr1);
existingXAttrs.add(xAttr2);
// Adding a system namespace xAttr, isn't affected by inode xAttrs limit.
XAttr newXAttr = (new XAttr.Builder()).setNameSpace(XAttr.NameSpace.SYSTEM).
// Adding system and raw namespace xAttrs aren't affected by inode
// 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();
List<XAttr> newXAttrs = Lists.newArrayListWithCapacity(1);
newXAttrs.add(newXAttr);
List<XAttr> newXAttrs = Lists.newArrayListWithCapacity(2);
newXAttrs.add(newSystemXAttr);
newXAttrs.add(newRawXAttr);
List<XAttr> xAttrs = fsdir.setINodeXAttrs(existingXAttrs, newXAttrs,
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.
XAttr newXAttr1 = (new XAttr.Builder()).setNameSpace(

View File

@ -64,7 +64,7 @@
<comparators>
<comparator>
<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>
</comparators>
</test>
@ -125,6 +125,42 @@
</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 /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>
<description>setfattr : Add an xattr, and encode is text</description>
<test-commands>
@ -257,6 +293,26 @@
</comparators>
</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>
<description>getfattr : Get an xattr</description>
<test-commands>