svn merge -c 1391649 FIXES: YARN-106. Nodemanager needs to set permissions of local directories (jlowe via bobby)
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-2@1391651 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
587f499b88
commit
b2db4b2917
|
@ -97,6 +97,9 @@ Release 0.23.4 - UNRELEASED
|
||||||
YARN-88. DefaultContainerExecutor can fail to set proper permissions.
|
YARN-88. DefaultContainerExecutor can fail to set proper permissions.
|
||||||
(Jason Lowe via sseth)
|
(Jason Lowe via sseth)
|
||||||
|
|
||||||
|
YARN-106. Nodemanager needs to set permissions of local directories (jlowe
|
||||||
|
via bobby)
|
||||||
|
|
||||||
Release 0.23.3 - Unreleased
|
Release 0.23.3 - Unreleased
|
||||||
|
|
||||||
INCOMPATIBLE CHANGES
|
INCOMPATIBLE CHANGES
|
||||||
|
|
|
@ -19,12 +19,17 @@
|
||||||
package org.apache.hadoop.yarn.server.nodemanager;
|
package org.apache.hadoop.yarn.server.nodemanager;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
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.fs.FileContext;
|
||||||
|
import org.apache.hadoop.fs.Path;
|
||||||
|
import org.apache.hadoop.fs.permission.FsPermission;
|
||||||
import org.apache.hadoop.util.DiskChecker;
|
import org.apache.hadoop.util.DiskChecker;
|
||||||
import org.apache.hadoop.util.DiskChecker.DiskErrorException;
|
import org.apache.hadoop.util.DiskChecker.DiskErrorException;
|
||||||
|
|
||||||
|
@ -65,6 +70,31 @@ class DirectoryCollection {
|
||||||
return numFailures;
|
return numFailures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create any non-existent directories and parent directories, updating the
|
||||||
|
* list of valid directories if necessary.
|
||||||
|
* @param localFs local file system to use
|
||||||
|
* @param perm absolute permissions to use for any directories created
|
||||||
|
* @return true if there were no errors, false if at least one error occurred
|
||||||
|
*/
|
||||||
|
synchronized boolean createNonExistentDirs(FileContext localFs,
|
||||||
|
FsPermission perm) {
|
||||||
|
boolean failed = false;
|
||||||
|
for (final String dir : localDirs) {
|
||||||
|
try {
|
||||||
|
createDir(localFs, new Path(dir), perm);
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.warn("Unable to create directory " + dir + " error " +
|
||||||
|
e.getMessage() + ", removing from the list of valid directories.");
|
||||||
|
localDirs.remove(dir);
|
||||||
|
failedDirs.add(dir);
|
||||||
|
numFailures++;
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !failed;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check the health of current set of local directories, updating the list
|
* Check the health of current set of local directories, updating the list
|
||||||
* of valid directories if necessary.
|
* of valid directories if necessary.
|
||||||
|
@ -86,4 +116,20 @@ class DirectoryCollection {
|
||||||
}
|
}
|
||||||
return numFailures > oldNumFailures;
|
return numFailures > oldNumFailures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,9 +26,12 @@ import java.util.TimerTask;
|
||||||
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;
|
||||||
|
import org.apache.hadoop.fs.FileContext;
|
||||||
import org.apache.hadoop.fs.LocalDirAllocator;
|
import org.apache.hadoop.fs.LocalDirAllocator;
|
||||||
import org.apache.hadoop.fs.Path;
|
import org.apache.hadoop.fs.Path;
|
||||||
|
import org.apache.hadoop.fs.permission.FsPermission;
|
||||||
import org.apache.hadoop.util.StringUtils;
|
import org.apache.hadoop.util.StringUtils;
|
||||||
|
import org.apache.hadoop.yarn.YarnException;
|
||||||
import org.apache.hadoop.yarn.conf.YarnConfiguration;
|
import org.apache.hadoop.yarn.conf.YarnConfiguration;
|
||||||
import org.apache.hadoop.yarn.service.AbstractService;
|
import org.apache.hadoop.yarn.service.AbstractService;
|
||||||
|
|
||||||
|
@ -120,6 +123,19 @@ public class LocalDirsHandlerService extends AbstractService {
|
||||||
lastDisksCheckTime = System.currentTimeMillis();
|
lastDisksCheckTime = System.currentTimeMillis();
|
||||||
super.init(conf);
|
super.init(conf);
|
||||||
|
|
||||||
|
FileContext localFs;
|
||||||
|
try {
|
||||||
|
localFs = FileContext.getLocalFSFileContext(config);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new YarnException("Unable to get the local filesystem", e);
|
||||||
|
}
|
||||||
|
FsPermission perm = new FsPermission((short)0755);
|
||||||
|
boolean createSucceeded = localDirs.createNonExistentDirs(localFs, perm);
|
||||||
|
createSucceeded &= logDirs.createNonExistentDirs(localFs, perm);
|
||||||
|
if (!createSucceeded) {
|
||||||
|
updateDirsAfterFailure();
|
||||||
|
}
|
||||||
|
|
||||||
// Check the disk health immediately to weed out bad directories
|
// Check the disk health immediately to weed out bad directories
|
||||||
// before other init code attempts to use them.
|
// before other init code attempts to use them.
|
||||||
checkDirs();
|
checkDirs();
|
||||||
|
@ -229,7 +245,8 @@ public class LocalDirsHandlerService extends AbstractService {
|
||||||
* Set good local dirs and good log dirs in the configuration so that the
|
* Set good local dirs and good log dirs in the configuration so that the
|
||||||
* LocalDirAllocator objects will use this updated configuration only.
|
* LocalDirAllocator objects will use this updated configuration only.
|
||||||
*/
|
*/
|
||||||
private void updateDirsInConfiguration() {
|
private void updateDirsAfterFailure() {
|
||||||
|
LOG.info("Disk(s) failed. " + getDisksHealthReport());
|
||||||
Configuration conf = getConfig();
|
Configuration conf = getConfig();
|
||||||
List<String> localDirs = getLocalDirs();
|
List<String> localDirs = getLocalDirs();
|
||||||
conf.setStrings(YarnConfiguration.NM_LOCAL_DIRS,
|
conf.setStrings(YarnConfiguration.NM_LOCAL_DIRS,
|
||||||
|
@ -237,6 +254,10 @@ public class LocalDirsHandlerService extends AbstractService {
|
||||||
List<String> logDirs = getLogDirs();
|
List<String> logDirs = getLogDirs();
|
||||||
conf.setStrings(YarnConfiguration.NM_LOG_DIRS,
|
conf.setStrings(YarnConfiguration.NM_LOG_DIRS,
|
||||||
logDirs.toArray(new String[logDirs.size()]));
|
logDirs.toArray(new String[logDirs.size()]));
|
||||||
|
if (!areDisksHealthy()) {
|
||||||
|
// Just log.
|
||||||
|
LOG.error("Most of the disks failed. " + getDisksHealthReport());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkDirs() {
|
private void checkDirs() {
|
||||||
|
@ -249,12 +270,7 @@ public class LocalDirsHandlerService extends AbstractService {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newFailure) {
|
if (newFailure) {
|
||||||
LOG.info("Disk(s) failed. " + getDisksHealthReport());
|
updateDirsAfterFailure();
|
||||||
updateDirsInConfiguration();
|
|
||||||
if (!areDisksHealthy()) {
|
|
||||||
// Just log.
|
|
||||||
LOG.error("Most of the disks failed. " + getDisksHealthReport());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
lastDisksCheckTime = System.currentTimeMillis();
|
lastDisksCheckTime = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,13 @@ import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ListIterator;
|
import java.util.ListIterator;
|
||||||
|
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.fs.CommonConfigurationKeys;
|
||||||
|
import org.apache.hadoop.fs.FileContext;
|
||||||
|
import org.apache.hadoop.fs.FileStatus;
|
||||||
import org.apache.hadoop.fs.FileUtil;
|
import org.apache.hadoop.fs.FileUtil;
|
||||||
|
import org.apache.hadoop.fs.Path;
|
||||||
|
import org.apache.hadoop.fs.permission.FsPermission;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
@ -65,4 +71,37 @@ public class TestDirectoryCollection {
|
||||||
// Verify no ConcurrentModification is thrown
|
// Verify no ConcurrentModification is thrown
|
||||||
li.next();
|
li.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateDirectories() throws IOException {
|
||||||
|
Configuration conf = new Configuration();
|
||||||
|
conf.set(CommonConfigurationKeys.FS_PERMISSIONS_UMASK_KEY, "077");
|
||||||
|
FileContext localFs = FileContext.getLocalFSFileContext(conf);
|
||||||
|
|
||||||
|
String dirA = new File(testDir, "dirA").getPath();
|
||||||
|
String dirB = new File(dirA, "dirB").getPath();
|
||||||
|
String dirC = new File(testDir, "dirC").getPath();
|
||||||
|
Path pathC = new Path(dirC);
|
||||||
|
FsPermission permDirC = new FsPermission((short)0710);
|
||||||
|
|
||||||
|
localFs.mkdir(pathC, null, true);
|
||||||
|
localFs.setPermission(pathC, permDirC);
|
||||||
|
|
||||||
|
String[] dirs = { dirA, dirB, dirC };
|
||||||
|
DirectoryCollection dc = new DirectoryCollection(dirs);
|
||||||
|
FsPermission defaultPerm = FsPermission.getDefault()
|
||||||
|
.applyUMask(new FsPermission((short)FsPermission.DEFAULT_UMASK));
|
||||||
|
boolean createResult = dc.createNonExistentDirs(localFs, defaultPerm);
|
||||||
|
Assert.assertTrue(createResult);
|
||||||
|
|
||||||
|
FileStatus status = localFs.getFileStatus(new Path(dirA));
|
||||||
|
Assert.assertEquals("local dir parent not created with proper permissions",
|
||||||
|
defaultPerm, status.getPermission());
|
||||||
|
status = localFs.getFileStatus(new Path(dirB));
|
||||||
|
Assert.assertEquals("local dir not created with proper permissions",
|
||||||
|
defaultPerm, status.getPermission());
|
||||||
|
status = localFs.getFileStatus(pathC);
|
||||||
|
Assert.assertEquals("existing local directory permissions modified",
|
||||||
|
permDirC, status.getPermission());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,8 +43,9 @@ public class TestContainerLogsPage {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testContainerLogDirs() throws IOException {
|
public void testContainerLogDirs() throws IOException {
|
||||||
String logdirwithFile = "file:///target/"
|
String absLogDir = new File("target",
|
||||||
+ TestNMWebServer.class.getSimpleName() + "LogDir";
|
TestNMWebServer.class.getSimpleName() + "LogDir").getAbsolutePath();
|
||||||
|
String logdirwithFile = "file://" + absLogDir;
|
||||||
Configuration conf = new Configuration();
|
Configuration conf = new Configuration();
|
||||||
conf.set(YarnConfiguration.NM_LOG_DIRS, logdirwithFile);
|
conf.set(YarnConfiguration.NM_LOG_DIRS, logdirwithFile);
|
||||||
NodeHealthCheckerService healthChecker = new NodeHealthCheckerService();
|
NodeHealthCheckerService healthChecker = new NodeHealthCheckerService();
|
||||||
|
|
Loading…
Reference in New Issue