-
Notifications
You must be signed in to change notification settings - Fork 9.2k
HADOOP-18122. ViewFileSystem fails on determining owning group when primary group doesn't exist for user #3987
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -77,6 +77,9 @@ | |
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| import static org.apache.hadoop.fs.viewfs.Constants.CONFIG_VIEWFS_MOUNT_LINKS_USER_NAME; | ||
| import static org.apache.hadoop.fs.viewfs.Constants.CONFIG_VIEWFS_MOUNT_LINKS_GROUP_NAME; | ||
|
|
||
| /** | ||
| * ViewFs (extends the AbstractFileSystem interface) implements a client-side | ||
| * mount table. The viewFs file system is implemented completely in memory on | ||
|
|
@@ -271,7 +274,7 @@ public AbstractFileSystem run() throws IOException { | |
|
|
||
| @Override | ||
| protected AbstractFileSystem getTargetFileSystem( | ||
| final INodeDir<AbstractFileSystem> dir) throws URISyntaxException { | ||
| final INodeDir<AbstractFileSystem> dir) throws URISyntaxException, IOException { | ||
| return new InternalDirOfViewFs(dir, creationTime, ugi, getUri(), this, | ||
| config); | ||
| } | ||
|
|
@@ -973,18 +976,27 @@ static class InternalDirOfViewFs extends AbstractFileSystem { | |
| final URI myUri; // the URI of the outer ViewFs | ||
| private InodeTree<AbstractFileSystem> fsState; | ||
| private Configuration conf; | ||
| private String mountLinkUserName; | ||
| private String mountLinkGroupName; | ||
|
|
||
| public InternalDirOfViewFs(final InodeTree.INodeDir<AbstractFileSystem> dir, | ||
| final long cTime, final UserGroupInformation ugi, final URI uri, | ||
| InodeTree fsState, Configuration conf) | ||
| throws URISyntaxException { | ||
| InodeTree fsState, Configuration conf) throws URISyntaxException, IOException { | ||
| super(FsConstants.VIEWFS_URI, FsConstants.VIEWFS_SCHEME, false, -1); | ||
| theInternalDir = dir; | ||
| creationTime = cTime; | ||
| this.ugi = ugi; | ||
| myUri = uri; | ||
| this.fsState = fsState; | ||
| this.conf = conf; | ||
| mountLinkUserName = conf.get(CONFIG_VIEWFS_MOUNT_LINKS_USER_NAME); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. may be write this as conf.get(CONFIG_VIEWFS_MOUNT_LINKS_USER_NAME) == null ? ugi.getShortUserName() : conf.get(CONFIG_VIEWFS_MOUNT_LINKS_USER_NAME) and explain why you are not using conf.get(CONFIG_VIEWFS_MOUNT_LINKS_USER_NAME, ugi.getShortUserName()) in a comment? Otherwise, it's unclear why you aren't using that method directly. Same for the other places where you are using this template |
||
| mountLinkGroupName = conf.get(CONFIG_VIEWFS_MOUNT_LINKS_GROUP_NAME); | ||
| if (mountLinkUserName == null) { | ||
| mountLinkUserName = ugi.getShortUserName(); | ||
| } | ||
| if (mountLinkGroupName == null) { | ||
| mountLinkGroupName = ugi.getPrimaryGroupName(); | ||
| } | ||
| } | ||
|
|
||
| static private void checkPathIsSlash(final Path f) throws IOException { | ||
|
|
@@ -1081,7 +1093,8 @@ public FileChecksum getFileChecksum(final Path f) | |
| public FileStatus getFileStatus(final Path f) throws IOException { | ||
| checkPathIsSlash(f); | ||
| return new FileStatus(0, true, 0, 0, creationTime, creationTime, | ||
| PERMISSION_555, ugi.getShortUserName(), ugi.getPrimaryGroupName(), | ||
| getMountLinkDefaultPermissions(), mountLinkUserName, | ||
| mountLinkGroupName, | ||
| new Path(theInternalDir.fullPath).makeQualified( | ||
| myUri, null)); | ||
| } | ||
|
|
@@ -1114,16 +1127,18 @@ public FileStatus getFileLinkStatus(final Path f) | |
| myUri, null)); | ||
| } catch (FileNotFoundException ex) { | ||
| result = new FileStatus(0, false, 0, 0, creationTime, creationTime, | ||
| PERMISSION_555, ugi.getShortUserName(), ugi.getPrimaryGroupName(), | ||
| inodelink.getTargetLink(), | ||
| new Path(inode.fullPath).makeQualified( | ||
| myUri, null)); | ||
| getMountLinkDefaultPermissions(), mountLinkUserName, | ||
| mountLinkGroupName, | ||
| inodelink.getTargetLink(), | ||
| new Path(inode.fullPath).makeQualified( | ||
| myUri, null)); | ||
| } | ||
| } else { | ||
| result = new FileStatus(0, true, 0, 0, creationTime, creationTime, | ||
| PERMISSION_555, ugi.getShortUserName(), ugi.getPrimaryGroupName(), | ||
| new Path(inode.fullPath).makeQualified( | ||
| myUri, null)); | ||
| getMountLinkDefaultPermissions(), mountLinkUserName, | ||
| mountLinkGroupName, | ||
| new Path(inode.fullPath).makeQualified( | ||
| myUri, null)); | ||
| } | ||
| return result; | ||
| } | ||
|
|
@@ -1178,8 +1193,8 @@ public FileStatus[] listStatus(final Path f) throws IOException { | |
| // symlink and rest other properties are belongs to mount link only. | ||
| linkStatuses.add( | ||
| new FileStatus(0, false, 0, 0, creationTime, creationTime, | ||
| PERMISSION_555, ugi.getShortUserName(), | ||
| ugi.getPrimaryGroupName(), link.getTargetLink(), path)); | ||
| getMountLinkDefaultPermissions(), mountLinkUserName, | ||
| mountLinkGroupName, link.getTargetLink(), path)); | ||
| continue; | ||
| } | ||
|
|
||
|
|
@@ -1210,8 +1225,8 @@ public FileStatus[] listStatus(final Path f) throws IOException { | |
| } else { | ||
| internalDirStatuses.add( | ||
| new FileStatus(0, true, 0, 0, creationTime, creationTime, | ||
| PERMISSION_555, ugi.getShortUserName(), | ||
| ugi.getPrimaryGroupName(), path)); | ||
| getMountLinkDefaultPermissions(), mountLinkUserName, | ||
| mountLinkGroupName, path)); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -1408,9 +1423,9 @@ public void setAcl(Path path, List<AclEntry> aclSpec) throws IOException { | |
| @Override | ||
| public AclStatus getAclStatus(Path path) throws IOException { | ||
| checkPathIsSlash(path); | ||
| return new AclStatus.Builder().owner(ugi.getShortUserName()) | ||
| .group(ugi.getPrimaryGroupName()) | ||
| .addEntries(AclUtil.getMinimalAcl(PERMISSION_555)) | ||
| return new AclStatus.Builder().owner(mountLinkUserName) | ||
| .group(mountLinkGroupName) | ||
| .addEntries(AclUtil.getMinimalAcl(getMountLinkDefaultPermissions())) | ||
| .stickyBit(false).build(); | ||
| } | ||
|
|
||
|
|
@@ -1479,5 +1494,9 @@ public void setStoragePolicy(Path path, String policyName) | |
| throws IOException { | ||
| throw readOnlyMountTable("setStoragePolicy", path); | ||
| } | ||
|
|
||
| private FsPermission getMountLinkDefaultPermissions() { | ||
| return PERMISSION_555; | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -70,7 +70,12 @@ | |
| import static org.apache.hadoop.fs.viewfs.Constants.CONFIG_VIEWFS_ENABLE_INNER_CACHE; | ||
| import static org.apache.hadoop.fs.viewfs.Constants.PERMISSION_555; | ||
| import static org.apache.hadoop.fs.viewfs.Constants.CONFIG_VIEWFS_TRASH_FORCE_INSIDE_MOUNT_POINT; | ||
| import static org.apache.hadoop.fs.viewfs.Constants.CONFIG_VIEWFS_MOUNT_LINKS_USER_NAME; | ||
| import static org.apache.hadoop.fs.viewfs.Constants.CONFIG_VIEWFS_MOUNT_LINKS_GROUP_NAME; | ||
| import static org.apache.hadoop.fs.FileSystem.TRASH_PREFIX; | ||
| import static org.apache.hadoop.test.LambdaTestUtils.intercept; | ||
| import static org.mockito.Mockito.when; | ||
| import static org.mockito.Mockito.spy; | ||
|
|
||
| import org.junit.After; | ||
| import org.junit.Assert; | ||
|
|
@@ -1705,4 +1710,59 @@ public void testInvalidMountPoints() throws Exception { | |
| ex.getMessage().startsWith("URISyntax exception")); | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| public void testInternalDirectoryOwnership() throws Exception { | ||
| Configuration localConf = new Configuration(conf); | ||
| FileSystem fs = FileSystem.get(FsConstants.VIEWFS_URI, localConf); | ||
|
|
||
| // Check default owner/group. | ||
| final UserGroupInformation currentUser = | ||
| UserGroupInformation.getCurrentUser(); | ||
| FileStatus status = fs.getFileStatus(new Path("/internalDir")); | ||
| assertEquals(currentUser.getUserName(), status.getOwner()); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. currentUser.getShortUserName()? |
||
| assertEquals(currentUser.getGroupNames()[0], status.getGroup()); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. currentUser.getPrimaryGroupName()? |
||
| assertEquals(PERMISSION_555, status.getPermission()); | ||
|
|
||
| UserGroupInformation currUgi = UserGroupInformation.getCurrentUser(); | ||
| try { | ||
| // Force exception when currUgi.getPrimaryGroupName() is called. This will | ||
| // not be triggered when viewfs mount link configs are defined. | ||
| UserGroupInformation spyUgi = spy(currUgi); | ||
| String failureMessage = "Fail on group check"; | ||
| when(spyUgi.getPrimaryGroupName()).thenThrow( | ||
| new IOException(failureMessage)); | ||
| UserGroupInformation.setLoginUser(spyUgi); | ||
|
|
||
| fs = FileSystem.get(FsConstants.VIEWFS_URI, localConf); | ||
| final FileSystem finalFs = fs; | ||
| intercept(IOException.class, () -> { | ||
| finalFs.getFileStatus(new Path("/internalDir")); | ||
| }); | ||
|
|
||
| // Set owner and group configs for internal directories. | ||
| String fakeUser = "abc"; | ||
| String fakeGroup = "def"; | ||
| localConf.set(CONFIG_VIEWFS_MOUNT_LINKS_USER_NAME, fakeUser); | ||
| localConf.set(CONFIG_VIEWFS_MOUNT_LINKS_GROUP_NAME, fakeGroup); | ||
|
|
||
| // Check that internal directory owner/group relects what's set. | ||
| fs = FileSystem.get(FsConstants.VIEWFS_URI, localConf); | ||
| status = fs.getFileStatus(new Path("/internalDir")); | ||
| assertEquals(fakeUser, status.getOwner()); | ||
| assertEquals(fakeGroup, status.getGroup()); | ||
| assertEquals(PERMISSION_555, status.getPermission()); | ||
|
|
||
| // Check that ACL status reflects what's set as well. | ||
| AclStatus aclStatus = fs.getAclStatus(new Path("/internalDir")); | ||
| assertEquals(fakeUser, aclStatus.getOwner()); | ||
| assertEquals(fakeGroup, aclStatus.getGroup()); | ||
| assertEquals(AclUtil.getMinimalAcl(PERMISSION_555), | ||
| aclStatus.getEntries()); | ||
| assertEquals(PERMISSION_555, aclStatus.getPermission()); | ||
| } finally { | ||
| // Set user back to the original currUgi object. | ||
| UserGroupInformation.setLoginUser(currUgi); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,6 +24,8 @@ | |
| import static org.apache.hadoop.fs.FileContextTestHelper.isDir; | ||
| import static org.apache.hadoop.fs.FileContextTestHelper.isFile; | ||
| import static org.apache.hadoop.fs.viewfs.Constants.PERMISSION_555; | ||
| import static org.apache.hadoop.fs.viewfs.Constants.CONFIG_VIEWFS_MOUNT_LINKS_USER_NAME; | ||
| import static org.apache.hadoop.fs.viewfs.Constants.CONFIG_VIEWFS_MOUNT_LINKS_GROUP_NAME; | ||
| import static org.junit.Assert.assertEquals; | ||
| import static org.junit.Assert.assertFalse; | ||
| import static org.mockito.ArgumentMatchers.any; | ||
|
|
@@ -1022,4 +1024,38 @@ public Object run() throws Exception { | |
| }); | ||
| } | ||
|
|
||
| public void testInternalDirectoryOwnership() throws IOException { | ||
| Configuration localConf = new Configuration(conf); | ||
| FileContext fc = FileContext.getFileContext( | ||
| FsConstants.VIEWFS_URI, localConf); | ||
|
|
||
| // check default owner/group | ||
| final UserGroupInformation currentUser = | ||
| UserGroupInformation.getCurrentUser(); | ||
| FileStatus status = fc.getFileStatus(new Path("/internalDir")); | ||
| assertEquals(currentUser.getUserName(), status.getOwner()); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. currentUser.getShortUserName()? |
||
| assertEquals(currentUser.getGroupNames()[0], status.getGroup()); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. currentUser.getPrimaryGroupName()? |
||
| assertEquals(PERMISSION_555, status.getPermission()); | ||
|
|
||
| // set owner and group configs for internal directories. | ||
| String fakeUser = "abc"; | ||
| String fakeGroup = "def"; | ||
| localConf.set(CONFIG_VIEWFS_MOUNT_LINKS_USER_NAME, fakeUser); | ||
| localConf.set(CONFIG_VIEWFS_MOUNT_LINKS_GROUP_NAME, fakeGroup); | ||
|
|
||
| // check that internal directory owner/group relects what's set. | ||
| fc = FileContext.getFileContext( | ||
| FsConstants.VIEWFS_URI, localConf); | ||
| status = fc.getFileStatus(new Path("/internalDir")); | ||
| assertEquals(fakeUser, status.getOwner()); | ||
| assertEquals(fakeGroup, status.getGroup()); | ||
| assertEquals(PERMISSION_555, status.getPermission()); | ||
|
|
||
| // check that ACL status reflects what's set as well. | ||
| AclStatus aclStatus = fc.getAclStatus(new Path("/internalDir")); | ||
| assertEquals(fakeUser, aclStatus.getOwner()); | ||
| assertEquals(fakeGroup, aclStatus.getGroup()); | ||
| assertEquals(aclStatus.getEntries(), | ||
| AclUtil.getMinimalAcl(PERMISSION_555)); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you want to make this configurable as well?