Expand my Community achievements bar.

Don’t miss the AEM Skill Exchange in SF on Nov 14—hear from industry leaders, learn best practices, and enhance your AEM strategy with practical tips.
SOLVED

How to execute a shell script using ProcessBuilder from Sling Servlet

Avatar

Level 3

We are trying to execute a shell script from a Servlet but not able to. User makes a request [ http://localhost:4502/services/myservice ] , the get() in SlingServlet calls the below:

ProcessBuilder processBuilder = new ProcessBuilder("vltexport.sh", "myArg1", "myArg2");

We get an "IOException.. Cannot run the program.. File not found”.

I tried all the below options.. but none worked:

1. Added the script to PATH

2. processBuilder = new ProcessBuilder("/bin/bash -c vltexport.sh","/apps/swa","/Users/konathala/temp/“);

3. processBuilder = new ProcessBuilder("/bin/bash" "vltexport.sh","/apps/swa","/Users/konathala/temp/“);

4. processBuilder = new ProcessBuilder("/home/southwest/vltexport.sh”);

5. processBuilder = new ProcessBuilder("./vltexport.sh”);

Appreciate any thoughts on this.

1 Accepted Solution

Avatar

Correct answer by
Level 3

I found two solutions for the problem:

1. Run the java code to print the result of the processBuilder.environment(). This shows the properties, paths etc where AEM is using to execute. the output looks like this

{PATH=/usr/java/latest/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/crx/.local/bin:/home/crx/bin, HISTCONTROL=ignoredups, LESSOPEN=||/usr/bin/lesspipe.sh %s, SHELL=/bin/bash, HISTSIZE=1000, OLDPWD=/home/crx, XFILESEARCHPATH=/usr/dt/app-defaults/%L/Dt, USER=crx, LANG=en_US.UTF-8, XDG_SESSION_ID=c1, MAIL=/var/spool/mail/crx, HOSTNAME=southwest-stage-20161004A-author1uswest1, TMOUT=600, NLSPATH=/usr/dt/lib/nls/msg/%L/%N.cat, LOGNAME=crx, XDG_RUNTIME_DIR=/run/user/1005, PWD=/mnt/crx/author, LS_COLORS=, HISTTIMEFORMAT=%F %T , HOME=/home/crx, SHLVL=1, _=/bin/setsid}

If you observe closely PWD=/mnt/crx/author is the path where AEM internal process is looking at, USR=crx is the User that AEM is using internally to run the code.

So i copied my "shell script" to "/mnt/crx/author" and also gave execute permission to user "crx". 

2. Other alternative is to add your shell script to the global PATH so it is available. For example you can put it under "/usr/local/bin".

Servlet Code snippet:

public class AssetsServlet extends SlingAllMethodsServlet { protected void doGet(SlingHttpServletRequest request,SlingHttpServletResponse response) throws ServletException,IOException { log.info("\n.....AssetsServlet doGet"); try { ScriptHelper.executeScript(""); .... ....

 ScriptHelper Code Snippet

public class ScriptHelper { public static void executeScript(String scriptPath) { log.info("...ScriptHelper.executeScript()"); try { /** Commands for server * "vltexport.sh" - Name of shellscript * "/apps/swa" - Source folder. I'm using these to be copied over' * "/mnt/crx/author/vltdata" - Destination folder */ String[] sendCommand = {"vltexport.sh", "/apps/swa", "/mnt/crx/author/vltdata"}; ProcessBuilder processBuilder = new ProcessBuilder(); processBuilder.directory(new File("/mnt/crx/author/vltdata")); log.info("Command options="+Arrays.asList(sendCommand)); processBuilder.command(sendCommand); log.info("Command="+processBuilder.command()); processBuilder.redirectErrorStream(true); //new log.info("Environment:::\n"+processBuilder.environment()); log.info("... starting to execute vltexport command"); final Process process = processBuilder.inheritIO().start(); // old final int errCode = process.waitFor(); log.info("... Complete with Code(0:Success,127:Fail) = "+errCode); log.info("Echo Output:\n" + output(process.getInputStream())); } catch(InterruptedException ie) { log.info("Thrown InterruptedException. Msg="+ie.getMessage()); } catch (Exception e) { log.info( e.getClass().getName() + " -- Error:"+e.getMessage()); //e.printStackTrace(); } }

Sample script - vltexport.sh

#!/bin/bash export PATH=$PATH:/mnt/crx/author/vault-cli-3.1.16/bin vlt --credentials admin:admin export -v http://localhost:4502/crx $1 $2

View solution in original post

4 Replies

Avatar

Employee Advisor

Hi,

can the AEM instance user (the user which runs the AEM process) execute this script? Permissions? Executable bit? Selinux enabled?

Jörg

Avatar

Level 3

Jörg Hoh wrote...

Hi,

can the AEM instance user (the user which runs the AEM process) execute this script? Permissions? Executable bit? Selinux enabled?

Jörg

 

I'm trying to create the same user (user on linux server) on AEM. The user on server has the permissions to execute the script, but how do i map the user on AEM to have execute permissions of the script? 

Avatar

Correct answer by
Level 3

I found two solutions for the problem:

1. Run the java code to print the result of the processBuilder.environment(). This shows the properties, paths etc where AEM is using to execute. the output looks like this

{PATH=/usr/java/latest/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/crx/.local/bin:/home/crx/bin, HISTCONTROL=ignoredups, LESSOPEN=||/usr/bin/lesspipe.sh %s, SHELL=/bin/bash, HISTSIZE=1000, OLDPWD=/home/crx, XFILESEARCHPATH=/usr/dt/app-defaults/%L/Dt, USER=crx, LANG=en_US.UTF-8, XDG_SESSION_ID=c1, MAIL=/var/spool/mail/crx, HOSTNAME=southwest-stage-20161004A-author1uswest1, TMOUT=600, NLSPATH=/usr/dt/lib/nls/msg/%L/%N.cat, LOGNAME=crx, XDG_RUNTIME_DIR=/run/user/1005, PWD=/mnt/crx/author, LS_COLORS=, HISTTIMEFORMAT=%F %T , HOME=/home/crx, SHLVL=1, _=/bin/setsid}

If you observe closely PWD=/mnt/crx/author is the path where AEM internal process is looking at, USR=crx is the User that AEM is using internally to run the code.

So i copied my "shell script" to "/mnt/crx/author" and also gave execute permission to user "crx". 

2. Other alternative is to add your shell script to the global PATH so it is available. For example you can put it under "/usr/local/bin".

Servlet Code snippet:

public class AssetsServlet extends SlingAllMethodsServlet { protected void doGet(SlingHttpServletRequest request,SlingHttpServletResponse response) throws ServletException,IOException { log.info("\n.....AssetsServlet doGet"); try { ScriptHelper.executeScript(""); .... ....

 ScriptHelper Code Snippet

public class ScriptHelper { public static void executeScript(String scriptPath) { log.info("...ScriptHelper.executeScript()"); try { /** Commands for server * "vltexport.sh" - Name of shellscript * "/apps/swa" - Source folder. I'm using these to be copied over' * "/mnt/crx/author/vltdata" - Destination folder */ String[] sendCommand = {"vltexport.sh", "/apps/swa", "/mnt/crx/author/vltdata"}; ProcessBuilder processBuilder = new ProcessBuilder(); processBuilder.directory(new File("/mnt/crx/author/vltdata")); log.info("Command options="+Arrays.asList(sendCommand)); processBuilder.command(sendCommand); log.info("Command="+processBuilder.command()); processBuilder.redirectErrorStream(true); //new log.info("Environment:::\n"+processBuilder.environment()); log.info("... starting to execute vltexport command"); final Process process = processBuilder.inheritIO().start(); // old final int errCode = process.waitFor(); log.info("... Complete with Code(0:Success,127:Fail) = "+errCode); log.info("Echo Output:\n" + output(process.getInputStream())); } catch(InterruptedException ie) { log.info("Thrown InterruptedException. Msg="+ie.getMessage()); } catch (Exception e) { log.info( e.getClass().getName() + " -- Error:"+e.getMessage()); //e.printStackTrace(); } }

Sample script - vltexport.sh

#!/bin/bash export PATH=$PATH:/mnt/crx/author/vault-cli-3.1.16/bin vlt --credentials admin:admin export -v http://localhost:4502/crx $1 $2

Avatar

Employee Advisor

Good that you found the root of the problem. And even better, that you reported the full solution (even 2 of them!) back to the forum!
Thanks a lot!

Jörg