MAPREDUCE-3102. Changed NodeManager to fail fast when LinuxContainerExecutor has wrong configuration or permissions. Contributed by Hitesh Shah.
svn merge -c r1202117 --ignore-ancestry ../../trunk/ git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-0.23@1202118 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
7934940eb8
commit
0e3715e98f
|
@ -38,6 +38,9 @@ Release 0.23.1 - Unreleased
|
|||
MAPREDUCE-3331. Improvement to single node cluster setup documentation for
|
||||
0.23 (Anupam Seth via mahadev)
|
||||
|
||||
MAPREDUCE-3102. Changed NodeManager to fail fast when LinuxContainerExecutor
|
||||
has wrong configuration or permissions. (Hitesh Shah via vinodkv)
|
||||
|
||||
OPTIMIZATIONS
|
||||
|
||||
BUG FIXES
|
||||
|
|
|
@ -62,6 +62,13 @@ public abstract class ContainerExecutor implements Configurable {
|
|||
return conf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the executor initialization steps.
|
||||
* Verify that the necessary configs, permissions are in place.
|
||||
* @throws IOException
|
||||
*/
|
||||
public abstract void init() throws IOException;
|
||||
|
||||
/**
|
||||
* Prepare the environment for containers in this application to execute.
|
||||
* For $x in local.dirs
|
||||
|
|
|
@ -69,6 +69,11 @@ public class DefaultContainerExecutor extends ContainerExecutor {
|
|||
this.lfs = lfs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() throws IOException {
|
||||
// nothing to do or verify here
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startLocalizer(Path nmPrivateContainerTokensPath,
|
||||
InetSocketAddress nmAddr, String user, String appId, String locId,
|
||||
|
|
|
@ -100,6 +100,29 @@ public class LinuxContainerExecutor extends ContainerExecutor {
|
|||
: conf.get(YarnConfiguration.NM_LINUX_CONTAINER_EXECUTOR_PATH, defaultPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() throws IOException {
|
||||
// Send command to executor which will just start up,
|
||||
// verify configuration/permissions and exit
|
||||
List<String> command = new ArrayList<String>(
|
||||
Arrays.asList(containerExecutorExe,
|
||||
"--checksetup"));
|
||||
String[] commandArray = command.toArray(new String[command.size()]);
|
||||
ShellCommandExecutor shExec = new ShellCommandExecutor(commandArray);
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("checkLinuxExecutorSetup: " + Arrays.toString(commandArray));
|
||||
}
|
||||
try {
|
||||
shExec.execute();
|
||||
} catch (ExitCodeException e) {
|
||||
int exitCode = shExec.getExitCode();
|
||||
LOG.warn("Exit code from container is : " + exitCode);
|
||||
logOutput(shExec.getOutput());
|
||||
throw new IOException("Linux container executor not configured properly"
|
||||
+ " (error=" + exitCode + ")", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startLocalizer(Path nmPrivateContainerTokensPath,
|
||||
InetSocketAddress nmAddr, String user, String appId, String locId,
|
||||
|
|
|
@ -110,6 +110,11 @@ public class NodeManager extends CompositeService implements
|
|||
ContainerExecutor exec = ReflectionUtils.newInstance(
|
||||
conf.getClass(YarnConfiguration.NM_CONTAINER_EXECUTOR,
|
||||
DefaultContainerExecutor.class, ContainerExecutor.class), conf);
|
||||
try {
|
||||
exec.init();
|
||||
} catch (IOException e) {
|
||||
throw new YarnException("Failed to initialize container executor", e);
|
||||
}
|
||||
DeletionService del = new DeletionService(exec);
|
||||
addService(del);
|
||||
|
||||
|
|
|
@ -302,10 +302,12 @@ public class ContainerLaunch implements Callable<Integer> {
|
|||
// by this time, it will never be launched
|
||||
exec.deactivateContainer(containerId);
|
||||
|
||||
LOG.debug("Getting pid for container " + containerIdStr + " to kill"
|
||||
+ " from pid file "
|
||||
+ (pidFilePath != null ? pidFilePath.toString() : "null"));
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Getting pid for container " + containerIdStr + " to kill"
|
||||
+ " from pid file "
|
||||
+ (pidFilePath != null ? pidFilePath.toString() : "null"));
|
||||
}
|
||||
|
||||
// however the container process may have already started
|
||||
try {
|
||||
|
||||
|
|
|
@ -38,12 +38,15 @@
|
|||
#endif
|
||||
|
||||
void display_usage(FILE *stream) {
|
||||
fprintf(stream,
|
||||
"Usage: container-executor --checksetup\n");
|
||||
fprintf(stream,
|
||||
"Usage: container-executor user command command-args\n");
|
||||
fprintf(stream, "Commands:\n");
|
||||
fprintf(stream, " initialize container: %2d appid tokens cmd app...\n",
|
||||
INITIALIZE_CONTAINER);
|
||||
fprintf(stream, " launch container: %2d appid containerid workdir container-script tokens\n",
|
||||
fprintf(stream,
|
||||
" launch container: %2d appid containerid workdir container-script tokens pidfile\n",
|
||||
LAUNCH_CONTAINER);
|
||||
fprintf(stream, " signal container: %2d container-pid signal\n",
|
||||
SIGNAL_CONTAINER);
|
||||
|
@ -52,14 +55,31 @@ void display_usage(FILE *stream) {
|
|||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
//Minimum number of arguments required to run the container-executor
|
||||
int invalid_args = 0;
|
||||
int do_check_setup = 0;
|
||||
|
||||
LOGFILE = stdout;
|
||||
ERRORFILE = stderr;
|
||||
|
||||
// Minimum number of arguments required to run
|
||||
// the std. container-executor commands is 4
|
||||
// 4 args not needed for checksetup option
|
||||
if (argc < 4) {
|
||||
invalid_args = 1;
|
||||
if (argc == 2) {
|
||||
const char *arg1 = argv[1];
|
||||
if (strcmp("--checksetup", arg1) == 0) {
|
||||
invalid_args = 0;
|
||||
do_check_setup = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (invalid_args != 0) {
|
||||
display_usage(stdout);
|
||||
return INVALID_ARGUMENT_NUMBER;
|
||||
}
|
||||
|
||||
LOGFILE = stdout;
|
||||
ERRORFILE = stderr;
|
||||
int command;
|
||||
const char * app_id = NULL;
|
||||
const char * container_id = NULL;
|
||||
|
@ -111,11 +131,19 @@ int main(int argc, char **argv) {
|
|||
return INVALID_CONTAINER_EXEC_PERMISSIONS;
|
||||
}
|
||||
|
||||
if (do_check_setup != 0) {
|
||||
// basic setup checks done
|
||||
// verified configs available and valid
|
||||
// verified executor permissions
|
||||
return 0;
|
||||
}
|
||||
|
||||
//checks done for user name
|
||||
if (argv[optind] == NULL) {
|
||||
fprintf(ERRORFILE, "Invalid user name.\n");
|
||||
return INVALID_USER_NAME;
|
||||
}
|
||||
|
||||
int ret = set_user(argv[optind]);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
|
@ -143,7 +171,7 @@ int main(int argc, char **argv) {
|
|||
break;
|
||||
case LAUNCH_CONTAINER:
|
||||
if (argc < 9) {
|
||||
fprintf(ERRORFILE, "Too few arguments (%d vs 8) for launch container\n",
|
||||
fprintf(ERRORFILE, "Too few arguments (%d vs 9) for launch container\n",
|
||||
argc);
|
||||
fflush(ERRORFILE);
|
||||
return INVALID_ARGUMENT_NUMBER;
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* 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.yarn.server.nodemanager;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.hadoop.yarn.YarnException;
|
||||
import org.apache.hadoop.yarn.conf.YarnConfiguration;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestNodeManager {
|
||||
|
||||
public static final class InvalidContainerExecutor extends
|
||||
DefaultContainerExecutor {
|
||||
@Override
|
||||
public void init() throws IOException {
|
||||
throw new IOException("dummy executor init called");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContainerExecutorInitCall() {
|
||||
NodeManager nm = new NodeManager();
|
||||
YarnConfiguration conf = new YarnConfiguration();
|
||||
conf.setClass(YarnConfiguration.NM_CONTAINER_EXECUTOR,
|
||||
InvalidContainerExecutor.class,
|
||||
ContainerExecutor.class);
|
||||
try {
|
||||
nm.init(conf);
|
||||
fail("Init should fail");
|
||||
} catch (YarnException e) {
|
||||
//PASS
|
||||
assert(e.getCause().getMessage().contains("dummy executor init called"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue