HDFS-5619. NameNode: record ACL modifications to edit log. Contributed by Haohui Mai.
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/HDFS-4685@1553224 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
25e9d2e895
commit
c3b56ed1c8
|
@ -18,6 +18,9 @@ HDFS-4685 (Unreleased)
|
||||||
|
|
||||||
HDFS-5618. NameNode: persist ACLs in fsimage. (Haohui Mai via cnauroth)
|
HDFS-5618. NameNode: persist ACLs in fsimage. (Haohui Mai via cnauroth)
|
||||||
|
|
||||||
|
HDFS-5619. NameNode: record ACL modifications to edit log.
|
||||||
|
(Haohui Mai via cnauroth)
|
||||||
|
|
||||||
OPTIMIZATIONS
|
OPTIMIZATIONS
|
||||||
|
|
||||||
BUG FIXES
|
BUG FIXES
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
package org.apache.hadoop.hdfs.server.namenode;
|
package org.apache.hadoop.hdfs.server.namenode;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
|
@ -28,6 +29,8 @@ import org.apache.hadoop.fs.permission.AclEntry;
|
||||||
*/
|
*/
|
||||||
@InterfaceAudience.Private
|
@InterfaceAudience.Private
|
||||||
public class AclFeature implements INode.Feature {
|
public class AclFeature implements INode.Feature {
|
||||||
|
public static final List<AclEntry> EMPTY_ENTRY_LIST = Collections.emptyList();
|
||||||
|
|
||||||
private List<AclEntry> entries;
|
private List<AclEntry> entries;
|
||||||
|
|
||||||
public List<AclEntry> getEntries() {
|
public List<AclEntry> getEntries() {
|
||||||
|
|
|
@ -77,7 +77,6 @@ import org.apache.hadoop.hdfs.util.ReadOnlyList;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
|
|
||||||
/*************************************************
|
/*************************************************
|
||||||
* FSDirectory stores the filesystem directory state.
|
* FSDirectory stores the filesystem directory state.
|
||||||
|
@ -2640,30 +2639,52 @@ public class FSDirectory implements Closeable {
|
||||||
void removeAcl(String src) throws IOException {
|
void removeAcl(String src) throws IOException {
|
||||||
writeLock();
|
writeLock();
|
||||||
try {
|
try {
|
||||||
final INodeWithAdditionalFields node = resolveINodeWithAdditionalField(src);
|
unprotectedRemoveAcl(src);
|
||||||
AclFeature f = node.getAclFeature();
|
fsImage.getEditLog().logSetAcl(src, AclFeature.EMPTY_ENTRY_LIST);
|
||||||
if (f != null)
|
|
||||||
node.removeAclFeature();
|
|
||||||
} finally {
|
} finally {
|
||||||
writeUnlock();
|
writeUnlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setAcl(String src, Iterable<AclEntry> aclSpec) throws IOException {
|
private void unprotectedRemoveAcl(String src) throws UnresolvedLinkException,
|
||||||
|
SnapshotAccessControlException, FileNotFoundException {
|
||||||
|
assert hasWriteLock();
|
||||||
|
final INodeWithAdditionalFields node = resolveINodeWithAdditionalField(src);
|
||||||
|
AclFeature f = node.getAclFeature();
|
||||||
|
if (f != null)
|
||||||
|
node.removeAclFeature();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setAcl(String src, List<AclEntry> aclSpec) throws IOException {
|
||||||
writeLock();
|
writeLock();
|
||||||
try {
|
try {
|
||||||
final INodeWithAdditionalFields node = resolveINodeWithAdditionalField(src);
|
unprotectedSetAcl(src, aclSpec);
|
||||||
AclFeature f = node.getAclFeature();
|
fsImage.getEditLog().logSetAcl(src, aclSpec);
|
||||||
if (f == null) {
|
|
||||||
f = new AclFeature();
|
|
||||||
node.addAclFeature(f);
|
|
||||||
}
|
|
||||||
f.setEntries(Lists.newArrayList(aclSpec));
|
|
||||||
} finally {
|
} finally {
|
||||||
writeUnlock();
|
writeUnlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void unprotectedSetAcl(String src, List<AclEntry> aclSpec)
|
||||||
|
throws UnresolvedLinkException, SnapshotAccessControlException,
|
||||||
|
FileNotFoundException {
|
||||||
|
assert hasWriteLock();
|
||||||
|
final INodeWithAdditionalFields node = resolveINodeWithAdditionalField(src);
|
||||||
|
AclFeature f = node.getAclFeature();
|
||||||
|
|
||||||
|
if (aclSpec.size() == 0) {
|
||||||
|
if (f != null)
|
||||||
|
node.removeAclFeature();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f == null) {
|
||||||
|
f = new AclFeature();
|
||||||
|
node.addAclFeature(f);
|
||||||
|
}
|
||||||
|
f.setEntries(aclSpec);
|
||||||
|
}
|
||||||
|
|
||||||
AclStatus getAclStatus(String src) throws IOException {
|
AclStatus getAclStatus(String src) throws IOException {
|
||||||
readLock();
|
readLock();
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.classification.InterfaceStability;
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.fs.Options;
|
import org.apache.hadoop.fs.Options;
|
||||||
|
import org.apache.hadoop.fs.permission.AclEntry;
|
||||||
import org.apache.hadoop.fs.permission.FsPermission;
|
import org.apache.hadoop.fs.permission.FsPermission;
|
||||||
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
||||||
import org.apache.hadoop.hdfs.protocol.CachePoolInfo;
|
import org.apache.hadoop.hdfs.protocol.CachePoolInfo;
|
||||||
|
@ -68,6 +69,7 @@ import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.RenameOldOp;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.RenameOp;
|
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.RenameOp;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.RenameSnapshotOp;
|
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.RenameSnapshotOp;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.RenewDelegationTokenOp;
|
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.RenewDelegationTokenOp;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.SetAclOp;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.SetGenstampV1Op;
|
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.SetGenstampV1Op;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.SetGenstampV2Op;
|
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.SetGenstampV2Op;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.SetOwnerOp;
|
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.SetOwnerOp;
|
||||||
|
@ -1000,6 +1002,13 @@ public class FSEditLog implements LogsPurgeable {
|
||||||
logEdit(op);
|
logEdit(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void logSetAcl(String src, List<AclEntry> entries) {
|
||||||
|
SetAclOp op = SetAclOp.getInstance();
|
||||||
|
op.src = src;
|
||||||
|
op.aclEntries = entries;
|
||||||
|
logEdit(op);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all the journals this edit log is currently operating on.
|
* Get all the journals this edit log is currently operating on.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -66,6 +66,7 @@ import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.RenameOldOp;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.RenameOp;
|
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.RenameOp;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.RenameSnapshotOp;
|
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.RenameSnapshotOp;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.RenewDelegationTokenOp;
|
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.RenewDelegationTokenOp;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.SetAclOp;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.SetGenstampV1Op;
|
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.SetGenstampV1Op;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.SetGenstampV2Op;
|
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.SetGenstampV2Op;
|
||||||
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.SetNSQuotaOp;
|
import org.apache.hadoop.hdfs.server.namenode.FSEditLogOp.SetNSQuotaOp;
|
||||||
|
@ -691,6 +692,11 @@ public class FSEditLogLoader {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case OP_SET_ACL: {
|
||||||
|
SetAclOp setAclOp = (SetAclOp) op;
|
||||||
|
fsDir.unprotectedSetAcl(setAclOp.src, setAclOp.aclEntries);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
throw new IOException("Invalid operation read " + op.opCode);
|
throw new IOException("Invalid operation read " + op.opCode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_RENAME;
|
||||||
import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_RENAME_OLD;
|
import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_RENAME_OLD;
|
||||||
import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_RENAME_SNAPSHOT;
|
import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_RENAME_SNAPSHOT;
|
||||||
import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_RENEW_DELEGATION_TOKEN;
|
import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_RENEW_DELEGATION_TOKEN;
|
||||||
|
import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_SET_ACL;
|
||||||
import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_SET_GENSTAMP_V1;
|
import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_SET_GENSTAMP_V1;
|
||||||
import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_SET_GENSTAMP_V2;
|
import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_SET_GENSTAMP_V2;
|
||||||
import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_SET_NS_QUOTA;
|
import static org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes.OP_SET_NS_QUOTA;
|
||||||
|
@ -75,6 +76,10 @@ import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.classification.InterfaceStability;
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
import org.apache.hadoop.fs.ChecksumException;
|
import org.apache.hadoop.fs.ChecksumException;
|
||||||
import org.apache.hadoop.fs.Options.Rename;
|
import org.apache.hadoop.fs.Options.Rename;
|
||||||
|
import org.apache.hadoop.fs.permission.AclEntry;
|
||||||
|
import org.apache.hadoop.fs.permission.AclEntryScope;
|
||||||
|
import org.apache.hadoop.fs.permission.AclEntryType;
|
||||||
|
import org.apache.hadoop.fs.permission.FsAction;
|
||||||
import org.apache.hadoop.fs.permission.FsPermission;
|
import org.apache.hadoop.fs.permission.FsPermission;
|
||||||
import org.apache.hadoop.fs.permission.PermissionStatus;
|
import org.apache.hadoop.fs.permission.PermissionStatus;
|
||||||
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
||||||
|
@ -86,6 +91,8 @@ import org.apache.hadoop.hdfs.protocol.ClientProtocol;
|
||||||
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
|
import org.apache.hadoop.hdfs.protocol.HdfsConstants;
|
||||||
import org.apache.hadoop.hdfs.protocol.LayoutVersion;
|
import org.apache.hadoop.hdfs.protocol.LayoutVersion;
|
||||||
import org.apache.hadoop.hdfs.protocol.LayoutVersion.Feature;
|
import org.apache.hadoop.hdfs.protocol.LayoutVersion.Feature;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.proto.AclProtos.AclEditLogProto;
|
||||||
|
import org.apache.hadoop.hdfs.protocolPB.PBHelper;
|
||||||
import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenIdentifier;
|
import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenIdentifier;
|
||||||
import org.apache.hadoop.hdfs.util.XMLUtils;
|
import org.apache.hadoop.hdfs.util.XMLUtils;
|
||||||
import org.apache.hadoop.hdfs.util.XMLUtils.InvalidXmlException;
|
import org.apache.hadoop.hdfs.util.XMLUtils.InvalidXmlException;
|
||||||
|
@ -108,6 +115,8 @@ import org.xml.sax.helpers.AttributesImpl;
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper classes for reading the ops from an InputStream.
|
* Helper classes for reading the ops from an InputStream.
|
||||||
|
@ -166,6 +175,7 @@ public abstract class FSEditLogOp {
|
||||||
inst.put(OP_ADD_CACHE_POOL, new AddCachePoolOp());
|
inst.put(OP_ADD_CACHE_POOL, new AddCachePoolOp());
|
||||||
inst.put(OP_MODIFY_CACHE_POOL, new ModifyCachePoolOp());
|
inst.put(OP_MODIFY_CACHE_POOL, new ModifyCachePoolOp());
|
||||||
inst.put(OP_REMOVE_CACHE_POOL, new RemoveCachePoolOp());
|
inst.put(OP_REMOVE_CACHE_POOL, new RemoveCachePoolOp());
|
||||||
|
inst.put(OP_SET_ACL, new SetAclOp());
|
||||||
}
|
}
|
||||||
|
|
||||||
public FSEditLogOp get(FSEditLogOpCodes opcode) {
|
public FSEditLogOp get(FSEditLogOpCodes opcode) {
|
||||||
|
@ -173,6 +183,16 @@ public abstract class FSEditLogOp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ImmutableMap<String, FsAction> fsActionMap() {
|
||||||
|
ImmutableMap.Builder<String, FsAction> b = ImmutableMap.builder();
|
||||||
|
for (FsAction v : FsAction.values())
|
||||||
|
b.put(v.SYMBOL, v);
|
||||||
|
return b.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final ImmutableMap<String, FsAction> FSACTION_SYMBOL_MAP
|
||||||
|
= fsActionMap();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for an EditLog Op. EditLog ops cannot be constructed
|
* Constructor for an EditLog Op. EditLog ops cannot be constructed
|
||||||
* directly, but only through Reader#readOp.
|
* directly, but only through Reader#readOp.
|
||||||
|
@ -3232,6 +3252,65 @@ public abstract class FSEditLogOp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class SetAclOp extends FSEditLogOp {
|
||||||
|
List<AclEntry> aclEntries = Lists.newArrayList();
|
||||||
|
String src;
|
||||||
|
|
||||||
|
private SetAclOp() {
|
||||||
|
super(OP_SET_ACL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SetAclOp getInstance() {
|
||||||
|
return new SetAclOp();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void readFields(DataInputStream in, int logVersion) throws IOException {
|
||||||
|
AclEditLogProto p = AclEditLogProto.parseDelimitedFrom((DataInputStream)in);
|
||||||
|
src = p.getSrc();
|
||||||
|
aclEntries = PBHelper.convertAclEntry(p.getEntriesList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeFields(DataOutputStream out) throws IOException {
|
||||||
|
AclEditLogProto.Builder b = AclEditLogProto.newBuilder();
|
||||||
|
if (src != null)
|
||||||
|
b.setSrc(src);
|
||||||
|
b.addAllEntries(PBHelper.convertAclEntryProto(aclEntries));
|
||||||
|
b.build().writeDelimitedTo(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void toXml(ContentHandler contentHandler) throws SAXException {
|
||||||
|
XMLUtils.addSaxString(contentHandler, "SRC", src);
|
||||||
|
for (AclEntry e : aclEntries) {
|
||||||
|
contentHandler.startElement("", "", "ENTRY", new AttributesImpl());
|
||||||
|
XMLUtils.addSaxString(contentHandler, "SCOPE", e.getScope().name());
|
||||||
|
XMLUtils.addSaxString(contentHandler, "TYPE", e.getType().name());
|
||||||
|
XMLUtils.addSaxString(contentHandler, "NAME", e.getName());
|
||||||
|
fsActionToXml(contentHandler, e.getPermission());
|
||||||
|
contentHandler.endElement("", "", "ENTRY");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void fromXml(Stanza st) throws InvalidXmlException {
|
||||||
|
src = st.getValue("SRC");
|
||||||
|
if (!st.hasChildren("ENTRY"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
List<Stanza> stanzas = st.getChildren("ENTRY");
|
||||||
|
for (Stanza s : stanzas) {
|
||||||
|
AclEntry e = new AclEntry.Builder()
|
||||||
|
.setScope(AclEntryScope.valueOf(s.getValue("SCOPE")))
|
||||||
|
.setType(AclEntryType.valueOf(s.getValue("TYPE")))
|
||||||
|
.setName(s.getValue("NAME"))
|
||||||
|
.setPermission(fsActionFromXml(s)).build();
|
||||||
|
aclEntries.add(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static private short readShort(DataInputStream in) throws IOException {
|
static private short readShort(DataInputStream in) throws IOException {
|
||||||
return Short.parseShort(FSImageSerialization.readString(in));
|
return Short.parseShort(FSImageSerialization.readString(in));
|
||||||
}
|
}
|
||||||
|
@ -3641,4 +3720,16 @@ public abstract class FSEditLogOp {
|
||||||
short mode = Short.valueOf(st.getValue("MODE"));
|
short mode = Short.valueOf(st.getValue("MODE"));
|
||||||
return new FsPermission(mode);
|
return new FsPermission(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void fsActionToXml(ContentHandler contentHandler, FsAction v)
|
||||||
|
throws SAXException {
|
||||||
|
XMLUtils.addSaxString(contentHandler, "PERM", v.SYMBOL);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FsAction fsActionFromXml(Stanza st) throws InvalidXmlException {
|
||||||
|
FsAction v = FSACTION_SYMBOL_MAP.get(st.getValue("PERM"));
|
||||||
|
if (v == null)
|
||||||
|
throw new InvalidXmlException("Invalid value for FsAction");
|
||||||
|
return v;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,12 +60,13 @@ public enum FSEditLogOpCodes {
|
||||||
OP_DISALLOW_SNAPSHOT ((byte) 30),
|
OP_DISALLOW_SNAPSHOT ((byte) 30),
|
||||||
OP_SET_GENSTAMP_V2 ((byte) 31),
|
OP_SET_GENSTAMP_V2 ((byte) 31),
|
||||||
OP_ALLOCATE_BLOCK_ID ((byte) 32),
|
OP_ALLOCATE_BLOCK_ID ((byte) 32),
|
||||||
OP_ADD_CACHE_DIRECTIVE ((byte) 33),
|
OP_ADD_CACHE_DIRECTIVE ((byte) 33),
|
||||||
OP_REMOVE_CACHE_DIRECTIVE ((byte) 34),
|
OP_REMOVE_CACHE_DIRECTIVE ((byte) 34),
|
||||||
OP_ADD_CACHE_POOL ((byte) 35),
|
OP_ADD_CACHE_POOL ((byte) 35),
|
||||||
OP_MODIFY_CACHE_POOL ((byte) 36),
|
OP_MODIFY_CACHE_POOL ((byte) 36),
|
||||||
OP_REMOVE_CACHE_POOL ((byte) 37),
|
OP_REMOVE_CACHE_POOL ((byte) 37),
|
||||||
OP_MODIFY_CACHE_DIRECTIVE ((byte) 38),
|
OP_MODIFY_CACHE_DIRECTIVE ((byte) 38),
|
||||||
|
OP_SET_ACL ((byte) 39),
|
||||||
|
|
||||||
// Note that fromByte(..) depends on OP_INVALID being at the last position.
|
// Note that fromByte(..) depends on OP_INVALID being at the last position.
|
||||||
OP_INVALID ((byte) -1);
|
OP_INVALID ((byte) -1);
|
||||||
|
|
|
@ -7327,7 +7327,7 @@ public class FSNamesystem implements Namesystem, FSClusterStats,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setAcl(String src, Iterable<AclEntry> aclSpec) throws IOException {
|
void setAcl(String src, List<AclEntry> aclSpec) throws IOException {
|
||||||
checkOperation(OperationCategory.WRITE);
|
checkOperation(OperationCategory.WRITE);
|
||||||
writeLock();
|
writeLock();
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -64,6 +64,11 @@ message AclFsImageProto {
|
||||||
repeated AclEntryProto entries = 1;
|
repeated AclEntryProto entries = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message AclEditLogProto {
|
||||||
|
required string src = 1;
|
||||||
|
repeated AclEntryProto entries = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message ModifyAclEntriesRequestProto {
|
message ModifyAclEntriesRequestProto {
|
||||||
required string src = 1;
|
required string src = 1;
|
||||||
repeated AclEntryProto aclSpec = 2;
|
repeated AclEntryProto aclSpec = 2;
|
||||||
|
|
|
@ -20,6 +20,8 @@ package org.apache.hadoop.hdfs;
|
||||||
|
|
||||||
import com.google.common.base.Charsets;
|
import com.google.common.base.Charsets;
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
@ -27,7 +29,7 @@ import org.apache.hadoop.fs.*;
|
||||||
import org.apache.hadoop.fs.FileSystem;
|
import org.apache.hadoop.fs.FileSystem;
|
||||||
import org.apache.hadoop.fs.FileSystem.Statistics;
|
import org.apache.hadoop.fs.FileSystem.Statistics;
|
||||||
import org.apache.hadoop.fs.Options.Rename;
|
import org.apache.hadoop.fs.Options.Rename;
|
||||||
import org.apache.hadoop.fs.Path;
|
import org.apache.hadoop.fs.permission.AclEntry;
|
||||||
import org.apache.hadoop.fs.permission.FsPermission;
|
import org.apache.hadoop.fs.permission.FsPermission;
|
||||||
import org.apache.hadoop.hdfs.MiniDFSCluster.NameNodeInfo;
|
import org.apache.hadoop.hdfs.MiniDFSCluster.NameNodeInfo;
|
||||||
import org.apache.hadoop.hdfs.client.HdfsDataInputStream;
|
import org.apache.hadoop.hdfs.client.HdfsDataInputStream;
|
||||||
|
@ -1061,6 +1063,8 @@ public class DFSTestUtil {
|
||||||
filesystem.removeCacheDirective(id);
|
filesystem.removeCacheDirective(id);
|
||||||
// OP_REMOVE_CACHE_POOL
|
// OP_REMOVE_CACHE_POOL
|
||||||
filesystem.removeCachePool("pool1");
|
filesystem.removeCachePool("pool1");
|
||||||
|
// OP_SET_ACL
|
||||||
|
filesystem.setAcl(pathConcatTarget, Lists.<AclEntry> newArrayList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void abortStream(DFSOutputStream out) throws IOException {
|
public static void abortStream(DFSOutputStream out) throws IOException {
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.apache.hadoop.hdfs.server.namenode;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.fs.Path;
|
||||||
|
import org.apache.hadoop.fs.permission.AclEntry;
|
||||||
|
import org.apache.hadoop.fs.permission.AclEntryScope;
|
||||||
|
import org.apache.hadoop.fs.permission.AclEntryType;
|
||||||
|
import org.apache.hadoop.fs.permission.AclStatus;
|
||||||
|
import org.apache.hadoop.fs.permission.FsAction;
|
||||||
|
import org.apache.hadoop.hdfs.DistributedFileSystem;
|
||||||
|
import org.apache.hadoop.hdfs.MiniDFSCluster;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.HdfsConstants.SafeModeAction;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
public class TestFSImageWithAcl {
|
||||||
|
private static Configuration conf;
|
||||||
|
private static MiniDFSCluster cluster;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUp() throws IOException {
|
||||||
|
conf = new Configuration();
|
||||||
|
cluster = new MiniDFSCluster.Builder(conf).numDataNodes(1).build();
|
||||||
|
cluster.waitActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void tearDown() {
|
||||||
|
cluster.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testAcl(boolean persistNamespace) throws IOException {
|
||||||
|
Path p = new Path("/p");
|
||||||
|
DistributedFileSystem fs = cluster.getFileSystem();
|
||||||
|
fs.create(p).close();
|
||||||
|
fs.mkdirs(new Path("/23"));
|
||||||
|
|
||||||
|
AclEntry e = new AclEntry.Builder().setName("foo")
|
||||||
|
.setPermission(FsAction.READ_EXECUTE).setScope(AclEntryScope.DEFAULT)
|
||||||
|
.setType(AclEntryType.OTHER).build();
|
||||||
|
fs.setAcl(p, Lists.newArrayList(e));
|
||||||
|
|
||||||
|
if (persistNamespace) {
|
||||||
|
fs.setSafeMode(SafeModeAction.SAFEMODE_ENTER);
|
||||||
|
fs.saveNamespace();
|
||||||
|
fs.setSafeMode(SafeModeAction.SAFEMODE_LEAVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
cluster.restartNameNode();
|
||||||
|
cluster.waitActive();
|
||||||
|
|
||||||
|
AclStatus s = cluster.getNamesystem().getAclStatus(p.toString());
|
||||||
|
AclEntry[] returned = Lists.newArrayList(s.getEntries()).toArray(
|
||||||
|
new AclEntry[0]);
|
||||||
|
Assert.assertArrayEquals(new AclEntry[] { e }, returned);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPersistAcl() throws IOException {
|
||||||
|
testAcl(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAclEditLog() throws IOException {
|
||||||
|
testAcl(false);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue