ContainerLaunch implements Callable<Integer> { static void writeLaunchEnv(OutputStream out, Map<String,String> environment, Map<Path,List<String>> resources, List<String> command) throws IOException { ShellScriptBuilder sb = Shell.WINDOWS ? new WindowsShellScriptBuilder() : new UnixShellScriptBuilder(); if (environment != null) { for (Map.Entry<String,String> env : environment.entrySet()) { sb.env(env.getKey().toString(), env.getValue().toString()); } } if (resources != null) { for (Map.Entry<Path,List<String>> entry : resources.entrySet()) { for (String linkName : entry.getValue()) { sb.symlink(entry.getKey(), new Path(linkName)); } } } sb.command(command); PrintStream pout = null; try { pout = new PrintStream(out); sb.write(pout); } finally { if (out != null) { out.close(); } } } ContainerLaunch(Context context, Configuration configuration,
      Dispatcher dispatcher, ContainerExecutor exec, Application app,
      Container container, LocalDirsHandlerService dirsHandler,
      ContainerManagerImpl containerManager); @VisibleForTesting static String expandEnvironment(String var,
      Path containerLogDir); @Override @SuppressWarnings("unchecked") // dispatcher not typed Integer call(); @SuppressWarnings("unchecked") // dispatcher not typed void cleanupContainer(); static String getRelativeContainerLogDir(String appIdStr,
      String containerIdStr); void sanitizeEnv(Map<String, String> environment, Path pwd,
      List<Path> appDirs, List<String> containerLogDirs,
      Map<Path, List<String>> resources); static final String CONTAINER_SCRIPT; static final String FINAL_CONTAINER_TOKENS_FILE; }
@Test public void testSpecialCharSymlinks() throws IOException { File shellFile = null; File tempFile = null; String badSymlink = Shell.WINDOWS ? "foo@zz_#!-+bar.cmd" : "foo@zz%_#*&!-+= bar()"; File symLinkFile = null; try { shellFile = Shell.appendScriptExtension(tmpDir, "hello"); tempFile = Shell.appendScriptExtension(tmpDir, "temp"); String timeoutCommand = Shell.WINDOWS ? "@echo \"hello\"" : "echo \"hello\""; PrintWriter writer = new PrintWriter(new FileOutputStream(shellFile)); FileUtil.setExecutable(shellFile, true); writer.println(timeoutCommand); writer.close(); Map<Path, List<String>> resources = new HashMap<Path, List<String>>(); Path path = new Path(shellFile.getAbsolutePath()); resources.put(path, Arrays.asList(badSymlink)); FileOutputStream fos = new FileOutputStream(tempFile); Map<String, String> env = new HashMap<String, String>(); List<String> commands = new ArrayList<String>(); if (Shell.WINDOWS) { commands.add("cmd"); commands.add("/c"); commands.add("\"" + badSymlink + "\""); } else { commands.add("/bin/sh ./\\\"" + badSymlink + "\\\""); } ContainerLaunch.writeLaunchEnv(fos, env, resources, commands); fos.flush(); fos.close(); FileUtil.setExecutable(tempFile, true); Shell.ShellCommandExecutor shexc = new Shell.ShellCommandExecutor(new String[]{tempFile.getAbsolutePath()}, tmpDir); shexc.execute(); assertEquals(shexc.getExitCode(), 0); assert(shexc.getOutput().contains("hello")); symLinkFile = new File(tmpDir, badSymlink); } finally { if (shellFile != null && shellFile.exists()) { shellFile.delete(); } if (tempFile != null && tempFile.exists()) { tempFile.delete(); } if (symLinkFile != null && symLinkFile.exists()) { symLinkFile.delete(); } } }
@Test (timeout = 20000) public void testInvalidSymlinkDiagnostics() throws IOException { File shellFile = null; File tempFile = null; String symLink = Shell.WINDOWS ? "test.cmd" : "test"; File symLinkFile = null; try { shellFile = Shell.appendScriptExtension(tmpDir, "hello"); tempFile = Shell.appendScriptExtension(tmpDir, "temp"); String timeoutCommand = Shell.WINDOWS ? "@echo \"hello\"" : "echo \"hello\""; PrintWriter writer = new PrintWriter(new FileOutputStream(shellFile)); FileUtil.setExecutable(shellFile, true); writer.println(timeoutCommand); writer.close(); Map<Path, List<String>> resources = new HashMap<Path, List<String>>(); Path invalidPath = new Path(shellFile.getAbsolutePath()+"randomPath"); resources.put(invalidPath, Arrays.asList(symLink)); FileOutputStream fos = new FileOutputStream(tempFile); Map<String, String> env = new HashMap<String, String>(); List<String> commands = new ArrayList<String>(); if (Shell.WINDOWS) { commands.add("cmd"); commands.add("/c"); commands.add("\"" + symLink + "\""); } else { commands.add("/bin/sh ./\\\"" + symLink + "\\\""); } ContainerLaunch.writeLaunchEnv(fos, env, resources, commands); fos.flush(); fos.close(); FileUtil.setExecutable(tempFile, true); Shell.ShellCommandExecutor shexc = new Shell.ShellCommandExecutor(new String[]{tempFile.getAbsolutePath()}, tmpDir); String diagnostics = null; try { shexc.execute(); Assert.fail("Should catch exception"); } catch(ExitCodeException e){ diagnostics = e.getMessage(); } Assert.assertNotNull(diagnostics); Assert.assertTrue(shexc.getExitCode() != 0); symLinkFile = new File(tmpDir, symLink); } finally { if (shellFile != null && shellFile.exists()) { shellFile.delete(); } if (tempFile != null && tempFile.exists()) { tempFile.delete(); } if (symLinkFile != null && symLinkFile.exists()) { symLinkFile.delete(); } } }
@Test (timeout = 20000) public void testInvalidEnvSyntaxDiagnostics() throws IOException { File shellFile = null; try { shellFile = Shell.appendScriptExtension(tmpDir, "hello"); Map<Path, List<String>> resources = new HashMap<Path, List<String>>(); FileOutputStream fos = new FileOutputStream(shellFile); FileUtil.setExecutable(shellFile, true); Map<String, String> env = new HashMap<String, String>(); env.put( "APPLICATION_WORKFLOW_CONTEXT", "{\"workflowId\":\"609f91c5cd83\"," + "\"workflowName\":\"\n\ninsert table " + "\npartition (cd_education_status)\nselect cd_demo_sk, cd_gender, " ); List<String> commands = new ArrayList<String>(); ContainerLaunch.writeLaunchEnv(fos, env, resources, commands); fos.flush(); fos.close(); Map<String, String> cmdEnv = new HashMap<String, String>(); cmdEnv.put("LANG", "C"); Shell.ShellCommandExecutor shexc = new Shell.ShellCommandExecutor(new String[]{shellFile.getAbsolutePath()}, tmpDir, cmdEnv); String diagnostics = null; try { shexc.execute(); Assert.fail("Should catch exception"); } catch(ExitCodeException e){ diagnostics = e.getMessage(); } Assert.assertTrue(diagnostics.contains(Shell.WINDOWS ? "is not recognized as an internal or external command" : "command not found")); Assert.assertTrue(shexc.getExitCode() != 0); } finally { if (shellFile != null && shellFile.exists()) { shellFile.delete(); } } }
@Test (timeout = 20000) public void testContainerLaunchStdoutAndStderrDiagnostics() throws IOException { File shellFile = null; try { shellFile = Shell.appendScriptExtension(tmpDir, "hello"); String command = Shell.WINDOWS ? "@echo \"hello\" & @echo \"error\" 1>&2 & exit /b 2" : "echo \"hello\"; echo \"error\" 1>&2; exit 2;"; PrintWriter writer = new PrintWriter(new FileOutputStream(shellFile)); FileUtil.setExecutable(shellFile, true); writer.println(command); writer.close(); Map<Path, List<String>> resources = new HashMap<Path, List<String>>(); FileOutputStream fos = new FileOutputStream(shellFile, true); Map<String, String> env = new HashMap<String, String>(); List<String> commands = new ArrayList<String>(); commands.add(command); ContainerLaunch.writeLaunchEnv(fos, env, resources, commands); fos.flush(); fos.close(); Shell.ShellCommandExecutor shexc = new Shell.ShellCommandExecutor(new String[]{shellFile.getAbsolutePath()}, tmpDir); String diagnostics = null; try { shexc.execute(); Assert.fail("Should catch exception"); } catch(ExitCodeException e){ diagnostics = e.getMessage(); } Assert.assertTrue(diagnostics.contains("error")); Assert.assertTrue(shexc.getOutput().contains("hello")); Assert.assertTrue(shexc.getExitCode() == 2); } finally { if (shellFile != null && shellFile.exists()) { shellFile.delete(); } } }