Repository: incubator-slider Updated Branches: refs/heads/feature/SLIDER-622-windows [created] c52493f94
SLIDER-622 test for FS permissions on minicluster Project: http://git-wip-us.apache.org/repos/asf/incubator-slider/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-slider/commit/c52493f9 Tree: http://git-wip-us.apache.org/repos/asf/incubator-slider/tree/c52493f9 Diff: http://git-wip-us.apache.org/repos/asf/incubator-slider/diff/c52493f9 Branch: refs/heads/feature/SLIDER-622-windows Commit: c52493f94dcaeea9d8f382e2bee5bebf93744351 Parents: 7974ffd Author: Steve Loughran <[email protected]> Authored: Mon Nov 10 12:53:57 2014 +0000 Committer: Steve Loughran <[email protected]> Committed: Mon Nov 10 12:53:57 2014 +0000 ---------------------------------------------------------------------- .../other/TestFilesystemPermissions.groovy | 256 +++++++++++++++++++ 1 file changed, 256 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/c52493f9/slider-core/src/test/groovy/org/apache/slider/other/TestFilesystemPermissions.groovy ---------------------------------------------------------------------- diff --git a/slider-core/src/test/groovy/org/apache/slider/other/TestFilesystemPermissions.groovy b/slider-core/src/test/groovy/org/apache/slider/other/TestFilesystemPermissions.groovy new file mode 100644 index 0000000..7da51c1 --- /dev/null +++ b/slider-core/src/test/groovy/org/apache/slider/other/TestFilesystemPermissions.groovy @@ -0,0 +1,256 @@ +/* + * 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.slider.other + +import groovy.io.FileType +import groovy.transform.CompileStatic +import groovy.util.logging.Slf4j +import org.apache.hadoop.conf.Configuration +import org.apache.hadoop.fs.AbstractFileSystem +import org.apache.hadoop.fs.FileContext +import org.apache.hadoop.fs.FileStatus +import org.apache.hadoop.fs.FileUtil +import org.apache.hadoop.fs.LocalFileSystem +import org.apache.hadoop.fs.Path +import org.apache.hadoop.fs.local.LocalFs +import org.apache.hadoop.fs.permission.FsPermission +import org.apache.hadoop.util.DiskChecker +import org.apache.hadoop.yarn.exceptions.YarnRuntimeException +import org.apache.hadoop.yarn.server.nodemanager.containermanager.localizer.ContainerLocalizer +import org.apache.hadoop.yarn.server.nodemanager.containermanager.localizer.ResourceLocalizationService +import org.apache.slider.test.YarnMiniClusterTestBase +import org.junit.After +import org.junit.Test +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +/** + * This test class exists to look at permissions of the filesystem, especially + * that created by Mini YARN clusters. On some windows jenkins machines, + * YARN actions were failing as the directories had the wrong permissions + * (i.e. too lax) + */ +@CompileStatic +@Slf4j +class TestFilesystemPermissions extends YarnMiniClusterTestBase { + + static final Logger LOG = LoggerFactory.getLogger(TestFilesystemPermissions); + + List<File> filesToDelete = [] + + @After + public void deleteFiles() { + filesToDelete.each { File f -> + FileUtil.fullyDelete(f, true) + } + } + + @Test + public void testJavaFSOperations() throws Throwable { + assertNativeLibrariesPresent(); + File subdir = testDir() + subdir.mkdir() + assert subdir.isDirectory() + assert FileUtil.canRead(subdir) + assert FileUtil.canWrite(subdir) + assert FileUtil.canExecute(subdir) + } + + @Test + public void testDiskCheckerOperations() throws Throwable { + assertNativeLibrariesPresent(); + File subdir = testDir() + subdir.mkdir() + DiskChecker checker = new DiskChecker() + checker.checkDir(subdir) + } + + @Test + public void testDiskCheckerMkdir() throws Throwable { + assertNativeLibrariesPresent(); + File subdir = testDir() + subdir.mkdirs() + DiskChecker checker = new DiskChecker() + checker.checkDir(subdir) + } + + /** + * Get a test dir for this method; one that will be deleted on teardown + * @return a filename unique to this test method + */ + File testDir() { + File parent = new File("target/testfspermissions") + parent.mkdir() + File testdir = new File(parent, methodName.methodName) + filesToDelete << testdir + return testdir; + } + + + @Test + public void testPermsMap() throws Throwable { + def dir = testDir() + def diruri = dir.toURI().toString() + def lfs = createLocalFS(dir, configuration) + getLocalDirsPathPermissionsMap(lfs, diruri) + } + + @Test + public void testInitLocaldir() throws Throwable { + def dir = testDir() + def diruri = dir.toURI().toString() + def lfs = createLocalFS(dir, configuration) + initializeLocalDir(lfs, diruri) + def localDirs = getInitializedLocalDirs(lfs, [diruri]) + assert localDirs.size() ==1 + } + + + @Test + public void testValidateMiniclusterPerms() throws Throwable { + def numLocal = 1 + def cluster = createMiniCluster("", configuration, 1, numLocal, 1, false) + def workDir = miniCluster.getTestWorkDir() + List<File> localdirs = []; + workDir.eachDir { File file -> + if (file.absolutePath.contains("-local")) { + // local dir + localdirs << file + } + } + assert localdirs.size() == numLocal + def lfs = createLocalFS(workDir, configuration) + localdirs.each { File file -> + checkLocalDir(lfs, file.toURI().toString()) + } + } + + FileContext createLocalFS(File dir, Configuration conf) { + return FileContext.getFileContext(dir.toURI(), conf) + } + + /** + * extracted from ResourceLocalizationService + * @param lfs + * @param localDir + * @return perms map + * @see ResourceLocalizationService + */ + private Map<Path, FsPermission> getLocalDirsPathPermissionsMap( + FileContext lfs, + String localDir) { + Map<Path, FsPermission> localDirPathFsPermissionsMap = new HashMap<Path, FsPermission>(); + + FsPermission defaultPermission = + FsPermission.getDirDefault().applyUMask(lfs.getUMask()); + FsPermission nmPrivatePermission = + ResourceLocalizationService.NM_PRIVATE_PERM.applyUMask(lfs.getUMask()); + + Path userDir = new Path(localDir, ContainerLocalizer.USERCACHE); + Path fileDir = new Path(localDir, ContainerLocalizer.FILECACHE); + Path sysDir = new Path( + localDir, + ResourceLocalizationService.NM_PRIVATE_DIR); + + localDirPathFsPermissionsMap.put(userDir, defaultPermission); + localDirPathFsPermissionsMap.put(fileDir, defaultPermission); + localDirPathFsPermissionsMap.put(sysDir, nmPrivatePermission); + return localDirPathFsPermissionsMap; + } + + private boolean checkLocalDir(FileContext lfs, String localDir) { + + Map<Path, FsPermission> pathPermissionMap = + getLocalDirsPathPermissionsMap(lfs, localDir); + + for (Map.Entry<Path, FsPermission> entry : pathPermissionMap.entrySet()) { + FileStatus status; + status = lfs.getFileStatus(entry.getKey()); + + if (!status.getPermission().equals(entry.getValue())) { + String msg = + "Permissions incorrectly set for dir " + entry.getKey() + + ", should be " + entry.getValue() + ", actual value = " + + status.getPermission(); + throw new YarnRuntimeException(msg); + } + } + return true; + } + + + private void initializeLocalDir(FileContext lfs, String localDir) { + + Map<Path, FsPermission> pathPermissionMap = + getLocalDirsPathPermissionsMap(lfs, localDir); + for (Map.Entry<Path, FsPermission> entry : pathPermissionMap.entrySet()) { + FileStatus status; + try { + status = lfs.getFileStatus(entry.getKey()); + } + catch (FileNotFoundException fs) { + status = null; + } + + if (status == null) { + lfs.mkdir(entry.getKey(), entry.getValue(), true); + status = lfs.getFileStatus(entry.getKey()); + } + FsPermission perms = status.getPermission(); + if (!perms.equals(entry.getValue())) { + lfs.setPermission(entry.getKey(), entry.getValue()); + } + } + } + + synchronized private List<String> getInitializedLocalDirs(FileContext lfs, + List<String> dirs) { + List<String> checkFailedDirs = new ArrayList<String>(); + for (String dir : dirs) { + try { + checkLocalDir(lfs, dir); + } catch (YarnRuntimeException e) { + checkFailedDirs.add(dir); + } + } + for (String dir : checkFailedDirs) { + LOG.info("Attempting to initialize " + dir); + initializeLocalDir(lfs, dir); + checkLocalDir(lfs, dir); + } + return dirs; + } + + + private void createDir(FileContext localFs, Path dir, FsPermission perm) + throws IOException { + if (dir == null) { + return; + } + try { + localFs.getFileStatus(dir); + } catch (FileNotFoundException e) { + createDir(localFs, dir.getParent(), perm); + localFs.mkdir(dir, perm, false); + if (!perm.equals(perm.applyUMask(localFs.getUMask()))) { + localFs.setPermission(dir, perm); + } + } + } +}
