|
@@ -24,6 +24,7 @@ import com.google.common.annotations.VisibleForTesting;
|
|
|
import org.apache.hadoop.classification.InterfaceAudience;
|
|
|
import org.apache.hadoop.classification.InterfaceStability;
|
|
|
import org.apache.hadoop.conf.Configuration;
|
|
|
+import org.apache.hadoop.util.ReflectionUtils;
|
|
|
import org.apache.hadoop.yarn.conf.YarnConfiguration;
|
|
|
import org.apache.hadoop.yarn.server.nodemanager.Context;
|
|
|
import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container;
|
|
@@ -34,28 +35,32 @@ import org.apache.hadoop.yarn.server.nodemanager.containermanager.runtime.Contai
|
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
|
-import java.util.EnumSet;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.HashSet;
|
|
|
+import java.util.List;
|
|
|
import java.util.Map;
|
|
|
+import java.util.Set;
|
|
|
|
|
|
/**
|
|
|
* This class is a {@link ContainerRuntime} implementation that delegates all
|
|
|
* operations to a {@link DefaultLinuxContainerRuntime} instance, a
|
|
|
- * {@link DockerLinuxContainerRuntime} instance, or a
|
|
|
- * {@link JavaSandboxLinuxContainerRuntime} instance depending on whether
|
|
|
- * each instance believes the operation to be within its scope.
|
|
|
+ * {@link DockerLinuxContainerRuntime} instance, a
|
|
|
+ * {@link JavaSandboxLinuxContainerRuntime} instance, or a custom instance
|
|
|
+ * depending on whether each instance believes the operation to be within its
|
|
|
+ * scope.
|
|
|
*
|
|
|
- * @see DockerLinuxContainerRuntime#isDockerContainerRequested
|
|
|
+ * @see LinuxContainerRuntime#isRuntimeRequested
|
|
|
*/
|
|
|
@InterfaceAudience.Private
|
|
|
@InterfaceStability.Unstable
|
|
|
public class DelegatingLinuxContainerRuntime implements LinuxContainerRuntime {
|
|
|
private static final Logger LOG =
|
|
|
- LoggerFactory.getLogger(DelegatingLinuxContainerRuntime.class);
|
|
|
+ LoggerFactory.getLogger(DelegatingLinuxContainerRuntime.class);
|
|
|
private DefaultLinuxContainerRuntime defaultLinuxContainerRuntime;
|
|
|
private DockerLinuxContainerRuntime dockerLinuxContainerRuntime;
|
|
|
private JavaSandboxLinuxContainerRuntime javaSandboxLinuxContainerRuntime;
|
|
|
- private EnumSet<LinuxContainerRuntimeConstants.RuntimeType> allowedRuntimes =
|
|
|
- EnumSet.noneOf(LinuxContainerRuntimeConstants.RuntimeType.class);
|
|
|
+ private Set<String> allowedRuntimes = new HashSet<>();
|
|
|
+ private List<LinuxContainerRuntime> pluggableRuntimes = new ArrayList<>();
|
|
|
|
|
|
@Override
|
|
|
public void initialize(Configuration conf, Context nmContext)
|
|
@@ -64,52 +69,62 @@ public class DelegatingLinuxContainerRuntime implements LinuxContainerRuntime {
|
|
|
YarnConfiguration.LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES,
|
|
|
YarnConfiguration.DEFAULT_LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES);
|
|
|
for (String configuredRuntime : configuredRuntimes) {
|
|
|
- try {
|
|
|
- allowedRuntimes.add(
|
|
|
- LinuxContainerRuntimeConstants.RuntimeType.valueOf(
|
|
|
- configuredRuntime.toUpperCase()));
|
|
|
- } catch (IllegalArgumentException e) {
|
|
|
- throw new ContainerExecutionException("Invalid runtime set in "
|
|
|
- + YarnConfiguration.LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES + " : "
|
|
|
- + configuredRuntime);
|
|
|
+ String normRuntime = configuredRuntime.toUpperCase();
|
|
|
+ allowedRuntimes.add(normRuntime);
|
|
|
+ if (isPluggableRuntime(normRuntime)) {
|
|
|
+ LinuxContainerRuntime runtime = createPluggableRuntime(conf,
|
|
|
+ configuredRuntime);
|
|
|
+ runtime.initialize(conf, nmContext);
|
|
|
+ pluggableRuntimes.add(runtime);
|
|
|
}
|
|
|
}
|
|
|
if (isRuntimeAllowed(
|
|
|
- LinuxContainerRuntimeConstants.RuntimeType.JAVASANDBOX)) {
|
|
|
+ LinuxContainerRuntimeConstants.RuntimeType.JAVASANDBOX.name())) {
|
|
|
javaSandboxLinuxContainerRuntime = new JavaSandboxLinuxContainerRuntime(
|
|
|
PrivilegedOperationExecutor.getInstance(conf));
|
|
|
javaSandboxLinuxContainerRuntime.initialize(conf, nmContext);
|
|
|
}
|
|
|
if (isRuntimeAllowed(
|
|
|
- LinuxContainerRuntimeConstants.RuntimeType.DOCKER)) {
|
|
|
+ LinuxContainerRuntimeConstants.RuntimeType.DOCKER.name())) {
|
|
|
dockerLinuxContainerRuntime = new DockerLinuxContainerRuntime(
|
|
|
PrivilegedOperationExecutor.getInstance(conf));
|
|
|
dockerLinuxContainerRuntime.initialize(conf, nmContext);
|
|
|
}
|
|
|
if (isRuntimeAllowed(
|
|
|
- LinuxContainerRuntimeConstants.RuntimeType.DEFAULT)) {
|
|
|
+ LinuxContainerRuntimeConstants.RuntimeType.DEFAULT.name())) {
|
|
|
defaultLinuxContainerRuntime = new DefaultLinuxContainerRuntime(
|
|
|
PrivilegedOperationExecutor.getInstance(conf));
|
|
|
defaultLinuxContainerRuntime.initialize(conf, nmContext);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public boolean isRuntimeRequested(Map<String, String> env) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
@VisibleForTesting
|
|
|
LinuxContainerRuntime pickContainerRuntime(
|
|
|
Map<String, String> environment) throws ContainerExecutionException {
|
|
|
LinuxContainerRuntime runtime;
|
|
|
//Sandbox checked first to ensure DockerRuntime doesn't circumvent controls
|
|
|
if (javaSandboxLinuxContainerRuntime != null &&
|
|
|
- javaSandboxLinuxContainerRuntime.isSandboxContainerRequested()){
|
|
|
+ javaSandboxLinuxContainerRuntime.isRuntimeRequested(environment)){
|
|
|
runtime = javaSandboxLinuxContainerRuntime;
|
|
|
} else if (dockerLinuxContainerRuntime != null &&
|
|
|
- DockerLinuxContainerRuntime.isDockerContainerRequested(environment)){
|
|
|
+ dockerLinuxContainerRuntime.isRuntimeRequested(environment)) {
|
|
|
runtime = dockerLinuxContainerRuntime;
|
|
|
- } else if (defaultLinuxContainerRuntime != null &&
|
|
|
- !DockerLinuxContainerRuntime.isDockerContainerRequested(environment)) {
|
|
|
- runtime = defaultLinuxContainerRuntime;
|
|
|
} else {
|
|
|
- throw new ContainerExecutionException("Requested runtime not allowed.");
|
|
|
+ LinuxContainerRuntime pluggableRuntime = pickPluggableRuntime(
|
|
|
+ environment);
|
|
|
+ if (pluggableRuntime != null) {
|
|
|
+ runtime = pluggableRuntime;
|
|
|
+ } else if (defaultLinuxContainerRuntime != null &&
|
|
|
+ defaultLinuxContainerRuntime.isRuntimeRequested(environment)) {
|
|
|
+ runtime = defaultLinuxContainerRuntime;
|
|
|
+ } else {
|
|
|
+ throw new ContainerExecutionException("Requested runtime not allowed.");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (LOG.isDebugEnabled()) {
|
|
@@ -120,6 +135,16 @@ public class DelegatingLinuxContainerRuntime implements LinuxContainerRuntime {
|
|
|
return runtime;
|
|
|
}
|
|
|
|
|
|
+ private LinuxContainerRuntime pickPluggableRuntime(
|
|
|
+ Map<String, String> environment) {
|
|
|
+ for (LinuxContainerRuntime runtime : pluggableRuntimes) {
|
|
|
+ if (runtime.isRuntimeRequested(environment)) {
|
|
|
+ return runtime;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
private LinuxContainerRuntime pickContainerRuntime(Container container)
|
|
|
throws ContainerExecutionException {
|
|
|
return pickContainerRuntime(container.getLaunchContext().getEnvironment());
|
|
@@ -175,9 +200,33 @@ public class DelegatingLinuxContainerRuntime implements LinuxContainerRuntime {
|
|
|
return runtime.getIpAndHost(container);
|
|
|
}
|
|
|
|
|
|
+ private boolean isPluggableRuntime(String runtimeType) {
|
|
|
+ for (LinuxContainerRuntimeConstants.RuntimeType type :
|
|
|
+ LinuxContainerRuntimeConstants.RuntimeType.values()) {
|
|
|
+ if (type.name().equalsIgnoreCase(runtimeType)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private LinuxContainerRuntime createPluggableRuntime(Configuration conf,
|
|
|
+ String runtimeType) throws ContainerExecutionException {
|
|
|
+ String confKey = String.format(
|
|
|
+ YarnConfiguration.LINUX_CONTAINER_RUNTIME_CLASS_FMT, runtimeType);
|
|
|
+ Class<? extends LinuxContainerRuntime> clazz = conf.getClass(
|
|
|
+ confKey, null, LinuxContainerRuntime.class);
|
|
|
+ if (clazz == null) {
|
|
|
+ throw new ContainerExecutionException("Invalid runtime set in "
|
|
|
+ + YarnConfiguration.LINUX_CONTAINER_RUNTIME_ALLOWED_RUNTIMES + " : "
|
|
|
+ + runtimeType + " : Missing configuration " + confKey);
|
|
|
+ }
|
|
|
+ return ReflectionUtils.newInstance(clazz, conf);
|
|
|
+ }
|
|
|
+
|
|
|
@VisibleForTesting
|
|
|
- boolean isRuntimeAllowed(
|
|
|
- LinuxContainerRuntimeConstants.RuntimeType runtimeType) {
|
|
|
- return allowedRuntimes.contains(runtimeType);
|
|
|
+ boolean isRuntimeAllowed(String runtimeType) {
|
|
|
+ return runtimeType != null && allowedRuntimes.contains(
|
|
|
+ runtimeType.toUpperCase());
|
|
|
}
|
|
|
}
|