YARN-8805. Automatically convert the launch command to the exec form when using entrypoint support

This commit is contained in:
Eric Badger 2019-03-11 12:43:14 -05:00
parent b4aa24d3c5
commit fa7a0b269a
4 changed files with 55 additions and 4 deletions

View File

@ -47,9 +47,12 @@ import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static org.apache.hadoop.yarn.service.api.ServiceApiConstants.COMPONENT_ID; import static org.apache.hadoop.yarn.service.api.ServiceApiConstants.COMPONENT_ID;
@ -149,6 +152,20 @@ public class ProviderUtils implements YarnServiceConstants {
return content; return content;
} }
public static String replaceSpacesWithDelimiter(String content,
String delimiter) {
List<String> parts = new ArrayList<String>();
Matcher m = Pattern.compile("([^\"]\\S*|\".+?\")\\s*").matcher(content);
while (m.find()) {
String part = m.group(1);
if(part.startsWith("\"") && part.endsWith("\"")) {
part = part.replaceAll("^\"|\"$", "");
}
parts.add(part);
}
return String.join(delimiter, parts);
}
// configs will be substituted by corresponding env in tokenMap // configs will be substituted by corresponding env in tokenMap
public static void substituteMapWithTokens(Map<String, String> configs, public static void substituteMapWithTokens(Map<String, String> configs,
Map<String, String> tokenMap) { Map<String, String> tokenMap) {

View File

@ -25,6 +25,7 @@ import org.apache.hadoop.yarn.service.provider.ProviderUtils;
import org.apache.hadoop.yarn.api.records.Container; import org.apache.hadoop.yarn.api.records.Container;
import org.apache.hadoop.yarn.service.api.records.Service; import org.apache.hadoop.yarn.service.api.records.Service;
import org.apache.hadoop.yarn.service.utils.SliderFileSystem; import org.apache.hadoop.yarn.service.utils.SliderFileSystem;
import org.apache.hadoop.yarn.service.containerlaunch.AbstractLauncher; import org.apache.hadoop.yarn.service.containerlaunch.AbstractLauncher;
import org.apache.hadoop.yarn.service.containerlaunch.CommandLineBuilder; import org.apache.hadoop.yarn.service.containerlaunch.CommandLineBuilder;
import org.apache.hadoop.yarn.service.containerlaunch.ContainerLaunchService; import org.apache.hadoop.yarn.service.containerlaunch.ContainerLaunchService;
@ -84,6 +85,11 @@ public class DockerProviderService extends AbstractProviderService
if (useEntryPoint) { if (useEntryPoint) {
String launchCommand = compLaunchContext.getLaunchCommand(); String launchCommand = compLaunchContext.getLaunchCommand();
if (!StringUtils.isEmpty(launchCommand)) { if (!StringUtils.isEmpty(launchCommand)) {
if(launchCommand.contains(" ")) {
// convert space delimiter command to exec format
launchCommand = ProviderUtils
.replaceSpacesWithDelimiter(launchCommand, ",");
}
launcher.addCommand(launchCommand); launcher.addCommand(launchCommand);
} }
} else { } else {

View File

@ -82,7 +82,7 @@ public class TestAbstractProviderService {
Component component = serviceContext.scheduler.getAllComponents().entrySet() Component component = serviceContext.scheduler.getAllComponents().entrySet()
.iterator().next().getValue(); .iterator().next().getValue();
ContainerLaunchService.ComponentLaunchContext clc = ContainerLaunchService.ComponentLaunchContext clc =
createEntryPointCLCFor(testService, component); createEntryPointCLCFor(testService, component, "sleep,9000");
ComponentInstance instance = component.getAllComponentInstances().iterator() ComponentInstance instance = component.getAllComponentInstances().iterator()
.next(); .next();
@ -95,13 +95,32 @@ public class TestAbstractProviderService {
launcher.getCommands()); launcher.getCommands());
} }
@Test
public void testBuildContainerLaunchCommandWithSpace() throws Exception {
AbstractProviderService providerService = new DockerProviderService();
Component component = serviceContext.scheduler.getAllComponents().entrySet()
.iterator().next().getValue();
ContainerLaunchService.ComponentLaunchContext clc =
createEntryPointCLCFor(testService, component, "ls -l \" space\"");
ComponentInstance instance = component.getAllComponentInstances().iterator()
.next();
Container container = mock(Container.class);
providerService.buildContainerLaunchCommand(launcher, testService, instance,
rule.getFs(), serviceContext.scheduler.getConfig(), container, clc,
null);
Assert.assertEquals("commands don't match.",
Lists.newArrayList("ls,-l, space"), launcher.getCommands());
}
@Test @Test
public void testBuildContainerLaunchContext() throws Exception { public void testBuildContainerLaunchContext() throws Exception {
AbstractProviderService providerService = new DockerProviderService(); AbstractProviderService providerService = new DockerProviderService();
Component component = serviceContext.scheduler.getAllComponents().entrySet() Component component = serviceContext.scheduler.getAllComponents().entrySet()
.iterator().next().getValue(); .iterator().next().getValue();
ContainerLaunchService.ComponentLaunchContext clc = ContainerLaunchService.ComponentLaunchContext clc =
createEntryPointCLCFor(testService, component); createEntryPointCLCFor(testService, component, "sleep,9000");
ComponentInstance instance = component.getAllComponentInstances().iterator() ComponentInstance instance = component.getAllComponentInstances().iterator()
.next(); .next();
@ -118,8 +137,8 @@ public class TestAbstractProviderService {
} }
private static ContainerLaunchService.ComponentLaunchContext private static ContainerLaunchService.ComponentLaunchContext
createEntryPointCLCFor(Service service, Component component) { createEntryPointCLCFor(Service service, Component component,
String launchCmd = "sleep,9000"; String launchCmd) {
Artifact artifact = new Artifact(); Artifact artifact = new Artifact();
artifact.setType(Artifact.TypeEnum.DOCKER); artifact.setType(Artifact.TypeEnum.DOCKER);
artifact.setId("example"); artifact.setId("example");

View File

@ -168,4 +168,13 @@ public class TestProviderUtils {
Assert.assertEquals(resolved.getResolvedRsrcPaths().get("destFile1"), Assert.assertEquals(resolved.getResolvedRsrcPaths().get("destFile1"),
"destFile1"); "destFile1");
} }
@Test
public void testReplaceSpacesWithDelimiter() {
String command = "ls -l \" space\"";
String expected = "ls,-l, space";
String actual = ProviderUtils.replaceSpacesWithDelimiter(command, ",");
Assert.assertEquals("replaceSpaceWithDelimiter produces unexpected result.",
expected, actual);
}
} }