YARN-1908. Fixed DistributedShell to not fail in secure clusters. Contributed by Vinod Kumar Vavilapalli and Jian He.

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1585849 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Vinod Kumar Vavilapalli 2014-04-08 22:11:52 +00:00
parent 7915b36225
commit 6c2a0ce30b
2 changed files with 53 additions and 18 deletions

View File

@ -85,6 +85,9 @@ Release 2.4.1 - UNRELEASED
YARN-1905. TestProcfsBasedProcessTree must only run on Linux. (cnauroth)
YARN-1908. Fixed DistributedShell to not fail in secure clusters. (Vinod
Kumar Vavilapalli and Jian He via vinodkv)
Release 2.4.0 - 2014-04-07
INCOMPATIBLE CHANGES

View File

@ -27,6 +27,7 @@ import java.io.StringReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@ -91,7 +92,6 @@ import org.apache.hadoop.yarn.client.api.async.NMClientAsync;
import org.apache.hadoop.yarn.client.api.async.impl.NMClientAsyncImpl;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.exceptions.YarnException;
import org.apache.hadoop.yarn.exceptions.YarnRuntimeException;
import org.apache.hadoop.yarn.security.AMRMTokenIdentifier;
import org.apache.hadoop.yarn.util.ConverterUtils;
import org.apache.hadoop.yarn.util.Records;
@ -185,6 +185,9 @@ public class ApplicationMaster {
@SuppressWarnings("rawtypes")
private AMRMClientAsync amRMClient;
// In both secure and non-secure modes, this points to the job-submitter.
private UserGroupInformation appSubmitterUgi;
// Handle to communicate with the Node Manager
private NMClientAsync nmClientAsync;
// Listen to process the response from the Node Manager
@ -236,7 +239,7 @@ public class ApplicationMaster {
// Location of shell script ( obtained from info set in env )
// Shell script path in fs
private String shellScriptPath = "";
private String scriptPath = "";
// Timestamp needed for creating a local resource
private long shellScriptPathTimestamp = 0;
// File length needed for local resource
@ -451,7 +454,7 @@ public class ApplicationMaster {
}
if (envs.containsKey(DSConstants.DISTRIBUTEDSHELLSCRIPTLOCATION)) {
shellScriptPath = envs.get(DSConstants.DISTRIBUTEDSHELLSCRIPTLOCATION);
scriptPath = envs.get(DSConstants.DISTRIBUTEDSHELLSCRIPTLOCATION);
if (envs.containsKey(DSConstants.DISTRIBUTEDSHELLSCRIPTTIMESTAMP)) {
shellScriptPathTimestamp = Long.valueOf(envs
@ -462,10 +465,10 @@ public class ApplicationMaster {
.get(DSConstants.DISTRIBUTEDSHELLSCRIPTLEN));
}
if (!shellScriptPath.isEmpty()
if (!scriptPath.isEmpty()
&& (shellScriptPathTimestamp <= 0 || shellScriptPathLen <= 0)) {
LOG.error("Illegal values in env for shell script path" + ", path="
+ shellScriptPath + ", len=" + shellScriptPathLen + ", timestamp="
+ scriptPath + ", len=" + shellScriptPathLen + ", timestamp="
+ shellScriptPathTimestamp);
throw new IllegalArgumentException(
"Illegal values in env for shell script path");
@ -525,14 +528,23 @@ public class ApplicationMaster {
credentials.writeTokenStorageToStream(dob);
// Now remove the AM->RM token so that containers cannot access it.
Iterator<Token<?>> iter = credentials.getAllTokens().iterator();
LOG.info("Executing with tokens:");
while (iter.hasNext()) {
Token<?> token = iter.next();
LOG.info(token);
if (token.getKind().equals(AMRMTokenIdentifier.KIND_NAME)) {
iter.remove();
}
}
allTokens = ByteBuffer.wrap(dob.getData(), 0, dob.getLength());
// Create appSubmitterUgi and add original tokens to it
String appSubmitterUserName =
System.getenv(ApplicationConstants.Environment.USER.name());
appSubmitterUgi =
UserGroupInformation.createRemoteUser(appSubmitterUserName);
appSubmitterUgi.addCredentials(credentials);
AMRMClientAsync.CallbackHandler allocListener = new RMCallbackHandler();
amRMClient = AMRMClientAsync.createAMRMClientAsync(1000, allocListener);
amRMClient.init(conf);
@ -901,19 +913,26 @@ public class ApplicationMaster {
// resources too.
// In this scenario, if a shell script is specified, we need to have it
// copied and made available to the container.
if (!shellScriptPath.isEmpty()) {
Path renamedSchellScriptPath = null;
if (!scriptPath.isEmpty()) {
Path renamedScriptPath = null;
if (Shell.WINDOWS) {
renamedSchellScriptPath = new Path(shellScriptPath + ".bat");
renamedScriptPath = new Path(scriptPath + ".bat");
} else {
renamedSchellScriptPath = new Path(shellScriptPath + ".sh");
renamedScriptPath = new Path(scriptPath + ".sh");
}
try {
FileSystem fs = renamedSchellScriptPath.getFileSystem(conf);
fs.rename(new Path(shellScriptPath), renamedSchellScriptPath);
} catch (IOException e) {
LOG.warn("Not able to add suffix (.bat/.sh) to the shell script filename");
throw new YarnRuntimeException(e);
// rename the script file based on the underlying OS syntax.
renameScriptFile(renamedScriptPath);
} catch (Exception e) {
LOG.error(
"Not able to add suffix (.bat/.sh) to the shell script filename",
e);
// We know we cannot continue launching the container
// so we should release it.
numCompletedContainers.incrementAndGet();
numFailedContainers.incrementAndGet();
return;
}
LocalResource shellRsrc = Records.newRecord(LocalResource.class);
@ -921,11 +940,10 @@ public class ApplicationMaster {
shellRsrc.setVisibility(LocalResourceVisibility.APPLICATION);
try {
shellRsrc.setResource(ConverterUtils.getYarnUrlFromURI(new URI(
renamedSchellScriptPath.toString())));
renamedScriptPath.toString())));
} catch (URISyntaxException e) {
LOG.error("Error when trying to use shell script path specified"
+ " in env, path=" + renamedSchellScriptPath);
e.printStackTrace();
+ " in env, path=" + renamedScriptPath, e);
// A failure scenario on bad input such as invalid shell script path
// We know we cannot continue launching the container
@ -949,7 +967,7 @@ public class ApplicationMaster {
// Set executable command
vargs.add(shellCommand);
// Set shell script path
if (!shellScriptPath.isEmpty()) {
if (!scriptPath.isEmpty()) {
vargs.add(Shell.WINDOWS ? ExecBatScripStringtPath
: ExecShellStringPath);
}
@ -983,6 +1001,20 @@ public class ApplicationMaster {
}
}
private void renameScriptFile(final Path renamedScriptPath)
throws IOException, InterruptedException {
appSubmitterUgi.doAs(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws IOException {
FileSystem fs = renamedScriptPath.getFileSystem(conf);
fs.rename(new Path(scriptPath), renamedScriptPath);
return null;
}
});
LOG.info("User " + appSubmitterUgi.getUserName()
+ " added suffix(.sh/.bat) to script file as " + renamedScriptPath);
}
/**
* Setup the request that will be sent to the RM for the container ask.
*