How to run a Jar in Amazon EC2? - java

I am fairly new to Amazon. I have a Java file which reads GBs of crawled data and I am running this using AWS ToolKit for Eclipse. The disadvantage here is, I have to keep my machine running for weeks if I need to read the entire crawled data and that is not possible. Apart from that, I can't download GBs of data in to my local PC (Because it is reading data).
Is there any way that I can upload the Jar to Amazon, and Amazon run it without engaging with my computer? I have heard about web crawlers running in Amazon for weeks without downloading data into the developers machine, and without letting the developer to turn on his machine without shutting down for months.
The feature I am asking is just like "job flows" in Amazon Elastic Map-Reduce. You upload the code, it runs it inside. It doesn't matter whether you keep "your" machine turned on or not.

You can run with the nohup command for *nix
nohup java -jar myjar.jar 2>&1 >> logfile.log &
This will run your jar file, directing the output [stderr and stdout] to logfile.log. The & is needed so that it runs in the background, freeing up the command line / shell/
!! EDIT !!
It's worth noting that the easiest way I've found for stopping the job once it's started is:
ps -ef | grep java
Returns ec2-user 19082 19056 98 18:12 pts/0 00:00:11 java -jar myjar.jar
Then kill 19082.
Note, you can tail -f logfile.log or other such derivatives [less, cat, head] to view the output from the jar.
Answer to question/comment
Hi. You can use System.out.println(), yes, and that'll end up in logfile.log. The command that indicates that is the 2&>1 which means "redirect stream 2 into stream 1". In unix speak that means redirect/pipe stderr into stdout. We then specify >> logfile.log which means "append output to logfile.log". As System.out.println() writes to stdout it'll end up in logfile.log.
However, if you're app is set up to use Log4j/commons-logging then using LOG.info("statement"); will end up in the configured 'log4j.properties' log file. With this configuration the only statements that will end up in logfile.log will be those that are either System generated (errors, linux internal system messages) or anything that's written explicitly to the stdout (ie System.out.println()) statements;

Related

Can't run exe file using ProcessBuilder depending of computer

I have come across a problem while working with Process and ProcessBuilder in Java.
I have a line of code looking like this :
Process process = new ProcessBuilder("des.exe", String... params);
It works fine on my personal computer, but not on my testing server and I can't figure out why.
The ErrorStream give me this:
des.exe: MZ����#���: not found
des.exe: Syntax error: "(" unexpected
Both computers are on Ubuntu 16.04.4 LTS with java 1.8.
Any idea where it might come from?
The most likely reason for the difference is that the file format of windows executables is not registered with the binfmt_misc handler in the kernel, which allows the kernel to execute various programs through helpers transparently. The error Syntax error: "(" unexpected typically means that the file got handed off to /bin/sh, instead of to wine.
So, check if the binfmt_misc file system is mounted (most modern linuxes do this automatically):
grep binfmt_misc /proc/self/mountinfo
should return some entries (might be autofs, might be binfmt_misc depends on the distro).
if it isn't then mount it:
sudo mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc
you can tell what's registered by looking at the content of this directory. To register for running dos executables with wine you need to register it:
echo ':DOSWin:M::MZ::/usr/bin/wine:' | sudo tee /proc/sys/fs/binfmt_misc/register
Once registered, executing the binary should happen transparently, and it should succeed through the ProcessBuilder.
Configuring this for the server at boot time is left as an exercise to the user.
If you want to skip this entire mess, then you can change the execution from des.exe to wine with the first argument of des.exe.

Copy Linux liveUSB causes errors with init.d scripts

The Overall Problem
When I install a simple Java application that I wrote to run on boot in the background through /etc/init.d/, it works on the liveUSB that I explicitly install it on. When I make a copy of that stick, it never boot successfully. When booting the liveUSB copy the Java application will always hang when the liveUSB boot process reaches my script. My script, which does do exactly what it is supposed to do, even every 5 minutes and will continue running forever until you power down the machine.
My script is blocking everything else
Nothing loads beyond my script
You cannot cancel my script
There is no GUI
The only text you can see is the command line output from my script
Setup & Test - Everything goes well :)
I have a Linux liveUSB with 3 partitions. Simple standard Xubuntu image is loaded.
sda1 > 2gb stoage
sda2 > 2gb system
sda3 > remaining gb for casper
I have created a simple Java application that runs in the background on start up. To get this far, I followed these steps:
Compiled java application into classes
Placed class files in /home/user/folder/
Copied my startup.sh script into /etc/init.d/
While inside /etc/init.d/
Typed "update-rc.d startup.sh start 20 2 5 . stop 20 0 1 6 ."
This updated run levels successfully
Now I can restart / reboot / shutdown whatever operation and everything runs perfectly!
The Copy - Here's where it gets tricky!
When creating a copy of this stick, I follow these steps:
Mount sda2
copy everything from that folder to /home/user/Desktop/tmp-system/
Mount sda3
copy everything from that folder to /home/user/Desktop/tmp-casper/
Go into /home/user/Desktop/tmp-system/
Type "tar -cvf system.tar ."
Go into /home/user/Desktop/tmp-casper/
Type "tar -cvf casper.tar ."
Umount
sda2
sda3
Plug in empty USB (sdb for example)
Set up partitions (Same as the stick you are copying from)
Untar into partitions
tar -xvf system.tar ... into sdb2
tar -xvf casper.tar ... into sdb3
Testing - Here's where everything goes wrong!
Plug in newly created liveUSB into a computer
Boot from USB
Everything starts to boot fine
Java application that I wrote gets triggered
Boot process hangs forever
No cmd prompt available
NO GUI available
It is as if the thread is running (and it is! The output can be viewed every 5 minutes - which is exactly the way it should be)
Solution Attempts & Gotchas
1
I can mount the copied liveUSB edit the startup.sh to not start my Java application and it will still not boot (just as I suspected?).
2
If I use "dd if=sda of=sdb" the copy of the liveUSB will work perfectly fine. However this is not an acceptable solution. If I were to copy a 16gb stick with dd to a 64gb stick, that would turn the 64gb stick into a 16gb.
3
Tested many variations of startup.sh and the Java application itself. All of which produce the same error.
4
The method I am using to copy works for every other form of application, file or anything else.
5
I would also like to try and avoid using any additional libraries or programs to help run the Java application.
What you might better do is to use a method to quickly create a liveUSB Linux stick, then add the Java program settings and directories.
Here is some help - Bootable pendrive as live cd
I definitely like point number 1 that you mention. Copy liveUSB even without the Java program does not work. You have spent quite some time to debug that program. I have the feeling that you are interested in making many liveUSB with the Java program installed. Since dd is not an option, my guess is that it's more meaningful to somehow use a Kickstart procedure for quick LiveUSB installations and then copy the Java things.
Thanks.

How to get rid of /tmp/.java_pid<number> files in Linux?

I noticed a lot of file /tmp/.java_pid<...> in my Linux machine. The file command says they are sockets. Assuming they are created by Java I wonder why Java does not clean them up. How to make Java clean them up or just not create them?
These files are created by the JVM to support debugging. It's part of the attach api.
If you don't want java to create them then start java apps without debugging enabled.
You can safely delete them if there isn't a jvm with the corresponding pid... a task that is eminently suitable for a cron job.
A little bit of bash:
for file in /tmp/.java-[0-9]*; do
[ -d /proc/${file#*.java-} ] || rm -f $file
done
pid files are generally the location where applications store their process id, so the user can kill the process easily afterwards. These applications should be deleting these files when they close down.
I wouldn't worry about these files too much, unless you are seeing more and more of them and they dont get deleted, then it might be a tell tale sign that you have an application that is not shutting down correctly,

Execute shell command in Tomcat

So I have the following problem: I have a web service running inside a Tomcat7 server on Linux. The web service however has to execute some commands (mostly file operations such as copy and mount). Copy I've replaced with java.nio, but I don't think that there is a replacement for mount.
So I'm trying to execute shell commands out of my Tomcat Java process. Unfortunately it doesn't execute my commands. I've implemented the execution of shell commands in Java before. So my code should be correct:
Process pr = Runtime.getRuntime().exec("mount -o loop -t iso9660 <myimage> <mymountpoint>");
pr.waitFor();
<myimage> and <mymountpoint> are absolute paths, so no issues there either.
I've debugged my commands and they are working when executed on the console.
I've tried sending other commands. Simple commands such as id and pwd are working!
I've tried using /bin/bash -c "<command>", which didn't work.
I've tried executing a shell script, which executes the command, which didn't work.
I've tried escaping the spaces in my command, which didn't work.
So I've digged even deeper and now I'm suspecting some Tomcat security policy (Sandbox?), which prevents me from executing the command. Since security is no issue for me (it's an internal system, completely isolated from the outside world), I've tried a hack, which became quite popular just recently:
System.setSecurityManager(null);
This didn't work either. I'm using Java7 and Tomcat7 on RHEL6. Tomcat7 is just extracted! I don't have any files in /etc/.. or any other folder than /opt/tomcat/, where I've extracted the zip from the Tomcat home page. I've searched the /opt/tomcat/conf folder for security settings, but all I could find was the file catalina.policy, where it didn't seem like I could set some security level for shell commands.
Any ideas?
A few things:
System.setSecurityManager(null);
you have just killed the security of your application.
Yes, Tomcat is running as root. If I execute id I'm root as well.
Fix this immediately!
Now on to the question. You shouldnt have Tomcat executing anything, you need to defer this to a separate process whether that be a shell script or another Java program. This should also remove what (I hope) was a dependency on root running Tomcat. It should be possible to perform this command as a non-privileged user that cannot log into the system normally. You would do this by configuring /etc/fstab and supplying that same user the permissions to do this. From a pure security POV the process that mounts should not be owned by the tomcat user. Nor should the tomcat user ever be root. So to recap:
1) Stop running Tomcat as root
2) Create a separate process outside of the context of Tomcat to run this mount
3) Create a tomcat user, this user should not be able to log into the system nor should it be a privileged user (admin,super user, etc)
4) Create a process user, this user should be configured exactly as the tomcat user
5) Edit /etc/fstab giving the process user the necessary permissions to mount correctly.
It's generally a bad idea to use the single-string form of Runtime.exec. A better option is to use ProcessBuilder, and split up the arguments yourself rather than relying on Java to split them for you (which it does very naïvely).
ProcessBuilder pb = new ProcessBuilder("/bin/mount", "-o", "loop", /*...*/);
pb.redirectErrorStream(true); // equivalent of 2>&1
Process p = pb.start();
You say you're on RHEL so do you have selinux active? Check your logs and see if this is what's blocking you (I think it's audit.log you're looking for, it's been a few years since I've used selinux). If this does turn out to be the problem then you should probably ask on superuser or serverfault rather than SO...
I'm not sure if that's the problem you are having, but I've seen issues when Runtime.exec() is used without reading the associated output buffers. You can find a detailed explanation and potential solutions here. Reading the output and error streams can also help you figure out what's going on at the OS level when you run the command.
I've recently had to do something like this from a Swing app.
You'll probably be able to pull it off with ProcessBuilder, as in Ian's answer, but I found that once things start to get complex, it's easier to write a shell script that does what you want, enabling you to pass as few parameters as possible. Then use ProcessBuilder to invoke the shell script.
If you're invoking anything that has more than really minimal output, you'll also have to read the output and error streams to keep the process from blocking when the output buffers fill, as it seems you are already doing.
I use sudo -S before command and for the tomcat7 user: tomcat7 ALL=(ALL) NOPASSWD:ALL

Thread dump not getting generated on JBoss

I used to generate thread dumps by running kill -quit and I would get them in a log file where my server logs were there. When the file grew too large I removed it using rm and created a new file of the same name.
Now when I use kill -quit to take the thread dumps, nothing gets copied in the log file - its empty.
Can anyone help?
The default JBoss startup scripts on Unix usually look something like:
nohup $JBOSS_HOME/bin/run.sh $JBOSS_OPTS >/dev/null 2>&1 &
This is unfortunate because it's sends stderr to /dev/null. Usually this is not a problem, because once log4j initializes, then most application output will go to boot.log or server.log. However, for thread dumps, and other low level errors they get lost.
Your best bet is to change the startup script to redirect stdout and stderr to a file. Additionally, one thing that's overlooked in the default setup is redirect stdin. For daemon processes it's a best practice to redirect stdin to /dev/null. For example:
nohup $JBOSS_HOME/bin/run.sh $JBOSS_OPTS >> console-$(date +%Y%m%d).out 2>&1 < /dev/null &
Lastly, if you have a running process, you can use jstack, which is included with the JRE, to get a thread dump. This will output to the console from which it's invoked. I prefer the output from kill -3, but jstack also allows you to view native stack frames.
If this is on *nix, when you delete a file, everyone who has that file still open will continue to write to the old (now missing) file. The file will only be really deleted when all file handles to it are closed.
You would have to cause the JVM to close and re-open the log file. Not sure if this can be done without a restart.
If you go into jmx and find jboss.system:service=Logging,type=Log4jService you can then invoke the reconfigure method which should cause log4j to reopen any of its log files. Then the kill -quit should work.

Categories