I need to launch a Java application on Centos (5.9) startup.
I am trying to start a simple script (named "lanzar.sh") on Centos at boot time:
#!/bin/sh
cd /home/someuser/Desktop/Dist
java -jar SomeApp.jar
I append the line "/bin/sh /home/someuser/Desktop/Dist/lanzar.sh" to /etc/rc.d/rc.local. But the java application does not start. I have:
Granted 755 rights to the /etc/rc.d/rc.local file
Write the content of the "lanzar.sh" into /etc/rc.d/rc.local. Separated with semicolon, and in different lines.
Changing "lanzar.sh" of location.
Other things, taken from other threads that did not work for me.
My rc.loca looks like:
#!/bin/sh
#
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don't
# want to do the full Sys V style init stuff.
#
#Some comment
#Some comment
#Some comment
touch /var/lock/subsys/local
/bin/sh /home/fernando/Desktop/Dist/lanzar.sh
Note: I know similar questions have been asked before, but after testing many of the answers that I have found by googling with no success, I had to ask this myself.
I highly recommend that you explore the /etc/init.d directory of your server and the /etc/rc3.d directory. See how the names of the files in /etc/rc3.d are symbolically linked to the names in the /etc/init.d directory. Notice how the files in /etc/rc3.d all start with Sxx or Kxxwherexx is a number between 00 to 99.
What I am about to tell you is officially all wrong. These startup scripts are way more complicated today that what I describe, but it's a basic outline of what's going on.
In standard Unix and Linux, startup scripts were normally stored in /etc/init.d and then linked to the /etc/rcX.d directory where X stood for what was called the Init States of the server. (Yes, I'm linking to an SCO Unix page, but they were all pretty similar).
Note that Init State 3 is running in multi-user mode and that all the daemons are started. This is why I am telling you to look in /etc/rc3.d.
When the server enters that init state, it runs all of the script starting with S in alphabetical order. It runs each script with the parameter start after it. So, S01xxxx starts before S03xxx which starts before S99xxxxx.
When the server exits that init state, it runs all of the scripts that start with K in alphabetical order, and passes the stop parameter to them.
Now, Centos, Redhat, and Fedora setup handles a lot of this for you. You specify which service you depend upon, and it figures out startup and shutdown order. However, nothing is preventing you from munging a startup script and creating your own links.
By the way, speaking about Java programs that startup and shutdown... Jenkins is a Java program that's started in a very similar way as your program. Here's the /etc/init.d script I got off of Jenkins website:
#!/bin/bash
#
# Startup script for Jenkins
#
# chkconfig: - 84 16
# description: Jenkins CI server
# Source function library.
. /etc/rc.d/init.d/functions
[ -z "$JAVA_HOME" -a -x /etc/profile.d/java.sh ] && . /etc/profile.d/java.sh
JENKINS_HOME=/var/jenkins
WAR="$JENKINS_HOME/jenkins.war"
LOG="/var/log/jenkins.log"
LOCK="/var/lock/subsys/jenkins"
export JENKINS_HOME
RETVAL=0
pid_of_jenkins() {
pgrep -f "java.*jenkins"
}
start() {
[ -e "$LOG" ] && cnt=`wc -l "$LOG" | awk '{ print $1 }'` || cnt=1
echo -n $"Starting jenkins: "
cd "$JENKINS_HOME"
nohup java -jar "$WAR" --httpPort=-1 --ajp13Port=8010 --prefix=/jenkins >> "$LOG" 2>&1 &
while { pid_of_jenkins > /dev/null ; } &&
! { tail +$cnt "$LOG" | grep -q 'Winstone Servlet Engine .* running' ; } ; do
sleep 1
done
pid_of_jenkins > /dev/null
RETVAL=$?
[ $RETVAL = 0 ] && success $"$STRING" || failure $"$STRING"
echo
[ $RETVAL = 0 ] && touch "$LOCK"
}
stop() {
echo -n "Stopping jenkins: "
pid=`pid_of_jenkins`
[ -n "$pid" ] && kill $pid
RETVAL=$?
cnt=10
while [ $RETVAL = 0 -a $cnt -gt 0 ] &&
{ pid_of_jenkins > /dev/null ; } ; do
sleep 1
((cnt--))
done
[ $RETVAL = 0 ] && rm -f "$LOCK"
[ $RETVAL = 0 ] && success $"$STRING" || failure $"$STRING"
echo
}
status() {
pid=`pid_of_jenkins`
if [ -n "$pid" ]; then
echo "jenkins (pid $pid) is running..."
return 0
fi
if [ -f "$LOCK" ]; then
echo $"${base} dead but subsys locked"
return 2
fi
echo "jenkins is stopped"
return 3
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
stop
start
;;
*)
echo $"Usage: $0 {start|stop|restart|status}"
exit 1
esac
exit $RETVAL
It'll give you something to work with.
Related
Advice on converting SysVinit file to Systemd services will be helpful.
Currently, I am using a systemv init script which will be executed after every boot on my STM32MP1 based Avenger96 board. Now I have to switch to Systemd from SysVinit. But I am not sure how to convert the init file to relevant systemd files. I am using Yocto with Ubuntu20.04 as build system. If someone help me to get started would be really great. Below is the init script and image recipe which establishes symlink to the init script.
custom-script.sh which is installed in etc/init.d/ directory of the rootfs.
#!/bin/sh
DAEMON="swupdate"
PIDFILE="/var/run/$DAEMON.pid"
PART_STATUS=$(sgdisk -A 4:get:2 /dev/mmcblk0)
if test "${PART_STATUS}" = "4:2:1" ; then
ROOTFS=rootfs-2
else
ROOTFS=rootfs-1
fi
if test -f /update-ok ; then
SURICATTA_ARGS="-c 2"
rm -f /update-ok
fi
start() {
printf 'Starting %s: ' "$DAEMON"
# shellcheck disable=SC2086 # we need the word splitting
start-stop-daemon -b -q -m -S -p "$PIDFILE" -x "/usr/bin/$DAEMON" \
-- -f /etc/swupdate/swupdate.cfg -L -e rootfs,${ROOTFS} -u "${SURICATTA_ARGS}"
status=$?
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
stop() {
printf 'Stopping %s: ' "$DAEMON"
start-stop-daemon -K -q -p "$PIDFILE"
status=$?
if [ "$status" -eq 0 ]; then
rm -f "$PIDFILE"
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
restart() {
stop
sleep 1
start
}
case "$1" in
start|stop|restart)
"$1";;
reload)
# Restart, since there is no true "reload" feature.
restart;;
*)
echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac
Image recipe which creates init.d dir and installs above script and also establishes symlink to rc4.d dir.
custom-image.bb
.
.
inherit update-rc.d
SRC_URI = "file://custom-script.sh \
"
S = "${WORKDIR}"
INITSCRIPT_PACKAGES = "${PN}"
INITSCRIPT_NAME = "custom-script.sh"
INITSCRIPT_PARAMS = "start 99 2 3 4 5 . "
do_install_append() {
install -d ${D}${sysconfdir}/rc4.d
install -d 644 ${D}${sysconfdir}/init.d
install -m 0755 ${WORKDIR}/custom-script.sh ${D}${sysconfdir}/init.d
ln -sf ../init.d/custom-script.sh ${D}${sysconfdir}/rc4.d/S99custom-script.sh
ln -sf ../init.d/custom-script.sh ${D}${sysconfdir}/rc4.d/K99custom-script.sh
}
FILES_${PN} += "${sysconfdir}/init.d"
Now I am trying to do the same functionality of custom-script.sh with systemd. Is it possible to make use of systemd-sysv-generator in this case?
Also, will the dir init.d completely removed once we switch to "systemd"? What will happen to other files which are present in etc/init.d?
Can anyone please help me get started?
Your help will be much appreciated.
Thanks in advance.
P.S: Please let me know if any info is missing here.
/etc/init.d will not get deleted by using systemd
Have you checked /etc/systemd and /usr/lib/systemd on your Ubuntu machine for examples of systemd scripts. Along the manual pages of systemd, you should have enough examples to convert your sysv init script to systemd.
I am using gcloud commands to deploy simple VMs. I am using startup script to configure all the required packages on the machine. Our packages are fetched from nexus. Sometimes our changes or nexus network issues result in failure of startup script. I configured a block of code to validate startup script return code. I run gcloud create command and provide startup script, the code block to validate startup script output looks like this..
echo "Step 2: sleep till startup script finishes"
## block to check return code of the VM startup script
MAX_WAIT_TIME=1200
WAIT_TIME=0
RC_CODE=""
echo "[INFO] waiting for startup-script return code"
while [ -z $RC_CODE ] && [ $WAIT_TIME -le $MAX_WAIT_TIME ]
do
RC_CODE=$(gcloud compute instances get-serial-port-output gce-$GCP_ZONE-d-$APP-dev \
--project=$GCP_PROJECT_ID \
--zone=$GCP_ZONE | awk '/^[0-9]{4}/ && /google_metadata_script_runner/ && /startup-script-url exit status/ {sub("\r", "", $NF); print $NF}')
if [[ -z $RC_CODE ]] ; then
echo -n "."
WAIT_TIME=$((WAIT_TIME+10))
sleep 10
else
if [[ $RC_CODE -eq 0 ]] ; then
echo -e "\n[INFO] startup script completed with return code $RC_CODE."
break
else
echo -e "\n[INFO] Startup script completed with return code $RC_CODE."
exit $RC_CODE
fi
fi
done
# to check timeout scenario
if [[ -z $RC_CODE ]]
then
echo "[INFO] Startup script timed out after $((MAX_WAIT_TIME/60))."
echo "[INFO] Startup script completed with return code 1."
exit 1
fi
My output looks like this,
+ ./sh/create-dev-vm-app.sh
Deleted [https://www.googleapis.com/compute/v1/projects/project-name/zones/europe-west1-c/instances/gce-europe-west1-c-d-myapp-dev].
Created [https://www.googleapis.com/compute/v1/projects/project-name/zones/europe-west1-c/instances/gce-europe-west1-c-d-myapp-dev].
waiting for startup-script return code
Specify --start=2473 in the next get-serial-port-output invocation to get only the new output starting from here.
.
Specify --start=32157 in the next get-serial-port-output invocation to get only the new output starting from here.
.
Specify --start=37602 in the next get-serial-port-output invocation to get only the new output starting from here.```
.
Startup script completed with return code 0.
How can I suppress the these 'Specify' lines from appearing on o/p screen? AND/OR print all startup-script messages received from get-serial-port-output output after I receive the return code.
Swallow standard error to avoid the extraneous output:
gcloud ... 2>/dev/null | awk ...
I have a bash script to deploy my spring-boot app (using bamboo).
script gets hung on this as the spring-boot app launches and is running
java -jar myApp.jar
I tried running it in the background with
java -jar myApp.jar &
as well as
java -jar myApp.jar &
disown
just "&" seems to do nothing while the "&" followed by "disown" made the script fail.
How do I let the script finish while the spring-boot app keeps running?
There is multiple options, one as mentioned is 'nohup' command. Another way to run is using 'screen' virtual terminal. But I would suggest you take a considerably better approach and run it as any other background service on *nix machines (like apache, mysql, etc.)
Here my very simple code that I have inside of /etc/init.d/great-spring-boot-app script, you can edit few lines to suite your conventions and save this file with
any name inside of /etc/init.d/ directory, for example /etc/init.d/my-cool-spring-boot-app
Then make it executable:
chmod +x /etc/init.d/my-cool-spring-boot-app
Afterwards can simply start process by doing something like
sudo service my-cool-spring-boot-app start
Other options are:
stop|restart|status
#!/bin/bash -
#=-= START OF CUSTOM SERVICE CONFIGURATION =-#
# Where micro service war/jar file sits?
MS_HOME=/opt/MY_MICRO_SERVICE_ROOT_DIRECTORY # <--- EDIT THIS LINE
# Actual file name of Micro Service (jar or war),
# ms-service.war or something-0.0.1-SNAPSHOT.jar, etc.
MS_JAR=MY_SPRING_BOOT_APPLICATION-0.0.1-SNAPSHOT.war # <--- EDIT THIS LINE
# ^^^ that should relative to MS_HOME directory.
# Which username we should run as.
RUNASUSER=USER_TO_RUN_AS; # <-- EDIT THIS LINE,
# if port number for spring boot is < 1024 it needs root perm.
JAVA_HOME=/usr/local/jdk1.8.0_60; # <-- EDIT THIS, Where is your JDK/JRE?
PATH=${JAVA_HOME}/bin:${PATH};
SHUTDOWN_WAIT=20; # before issuing kill -9 on process.
export PATH JAVA_HOME
# These options are used when micro service is starting
# Add whatever you want/need here... overrides application*.yml.
OPTIONS="
-Dserver.port=8080
-Dspring.profiles.active=dev
";
#=-= END OF CUSTOM CONFIGURATION =-=#
# Try to get PID of spring jar/war
MS_PID=`ps fax|grep java|grep "${MS_JAR}"|awk '{print $1}'`
export MS_PID;
# Function: run_as
run_as() {
local iam iwant;
iam=$(id -nu);
iwant="$1";
shift;
if [ "${iam}" = "${iwant}" ]; then {
eval $*;
}
else {
/bin/su -p -s /bin/sh ${iwant} $*;
} fi;
}
# Function: start
start() {
pid=${MS_PID}
if [ -n "${pid}" ]; then {
echo "Micro service is already running (pid: ${pid})";
}
else {
# Start screener ms
echo "Starting micro service";
cd $MS_HOME
run_as ${RUNASUSER} java -jar ${OPTIONS} ./${MS_JAR};
# java -jar ${OPTIONS} ./${MS_JAR}
} fi;
# return 0;
}
# Function: stop
stop() {
pid=${MS_PID}
if [ -n "${pid}" ]; then {
run_as ${RUNASUSER} kill -TERM $pid
echo -ne "Stopping micro service module";
kwait=${SHUTDOWN_WAIT};
count=0;
while kill -0 ${pid} 2>/dev/null && [ ${count} -le ${kwait} ]; do {
printf ".";
sleep 1;
(( count++ ));
} done;
echo;
if [ ${count} -gt ${kwait} ]; then {
printf "process is still running after %d seconds, killing process" \
${SHUTDOWN_WAIT};
kill ${pid};
sleep 3;
# if it's still running use kill -9
#
if kill -0 ${pid} 2>/dev/null; then {
echo "process is still running, using kill -9";
kill -9 ${pid}
sleep 3;
} fi;
} fi;
if kill -0 ${pid} 2>/dev/null; then {
echo "process is still running, I give up";
}
else {
# success, delete PID file, if you have used it with spring boot
# rm -f ${SPRING_BOOT_APP_PID};
} fi;
}
else {
echo "Micro service is not running";
} fi;
#return 0;
}
# Main Code
case $1 in
start)
start;
;;
stop)
stop;
;;
restart)
stop;
sleep 1;
start;
;;
status)
pid=$MS_PID
if [ "${pid}" ]; then {
echo "Micro service module is running with pid: ${pid}";
}
else {
echo "Micro service module is not running";
} fi;
;;
esac
exit 0;
This is the appropriate way to start background service(s) on Linux.
nohup java -jar myApp.jar &
nohup will intercept the HUP (hangup) signal when the TTY closes. This prevents the process from being terminated when the user logs out / your remote session ends. The ampersand is for starting the process in the background.
Easy stop / start spring boot application uber jar
https://github.com/tyrion9/spring-boot-startup-script
Copy uber jar file in the same folder
./bootstrap.sh start
./bootstrap.sh stop
./bootstrap.sh restart
Using start and shutdown scripts
I have answered similar question here.
You could use a set of scripts to achieve this. For example a startup.sh may look like this. It will start the application and write the process id to /path/to/app/pid.file .And the nohup disowns the process so the process doesn't hold on to current TTY session.
#!/bin/bash
nohup java -jar /path/to/app/hello-world.jar > /path/to/log.txt 2>&1 &
echo $! > /path/to/app/pid.file
And a shutdown.sh may look like this.
#!/bin/bash
kill $(cat /path/to/app/pid.file)
You can find more detail in my post. https://springhow.com/start-stop-scripts-for-spring-boot-applications/
#!/bin/bash
#!/bin/sh
# Need help
__help() { echo "$0 [ stop|start ]" 1>&2; exit 1; }
# Not enough args to run properly
[ $# -ne 1 ] && __help
# See what we're called with
case "$1" in
start) # Start sniffer as root, under a different argv[0] and make it drop rights
s=$(/usr/local/sbin/tcpdump -n -nn -f -q -i lo | awk 'END {print NR}')
echo "$s" > eppps_$(/bin/date +'%Y%m%d%H%M')
;;
stop) # End run, first "friendly", then strict:
/usr/bin/pkill -15 -f /usr/local/sbin/tcpdump >/dev/null 2>&1|| { sleep 3s; /usr/bin/pkill -9 -f /usr/local/sbin/tc$
;;
*) # Superfluous but show we only accept these args
__help
;;
esac
exit 0
This code runs perfectly on manual testing. But when i couple it with cron it just doesn't do anything. No output file is created.
My cron entries for the script looks like
http://postimage.org/image/1pztgd6xw/
It looks like you are not setting the working directory, so you may need to give an absolute path for the output file
I have a Cygwin bash script that I need to watch and terminate under certain conditions - specifically, after a certain file has been created. I'm having difficulty figuring out how exactly to terminate the script with the same level of completeness that Ctrl+C does, however.
Here's a simple script (called test1) that does little more than wait around to be terminated.
#!/bin/bash
test -f kill_me && rm kill_me
touch kill_me
tail -f kill_me
If this script is run in the foreground, Ctrl+C will terminate both the tail and the script itself. If the script is run in the background, a kill %1 (assuming it is job 1) will also terminate both tail and the script.
However, when I try to do the same thing from a script, I'm finding that only the bash process running the script is terminated, while tail hangs around disconnected from its parent. Here's one way I tried (test2):
#!/bin/bash
test -f kill_me && rm kill_me
(
touch kill_me
tail -f kill_me
) &
while true; do
sleep 1
test -f kill_me && {
kill %1
exit
}
done
If this is run, the bash subshell running in the background is terminated OK, but tail still hangs around.
If I use an explicitly separate script, like this, it still doesn't work (test3):
#!/bin/bash
test -f kill_me && rm kill_me
# assuming test1 above is included in the same directory
./test1 &
while true; do
sleep 1
test -f kill_me && {
kill %1
exit
}
done
tail is still hanging around after this script is run.
In my actual case, the process creating files is not particularly instrumentable, so I can't get it to terminate of its own accord; by finding out when it has created a particular file, however, I can at that point know that it's OK to terminate it. Unfortunately, I can't use a simple killall or equivalent, as there may be multiple instances running, and I only want to kill the specific instance.
/bin/kill (the program, not the bash builtin) interprets a negative PID as “kill the process group” which will get all the children too.
Changing
kill %1
to
/bin/kill -- -$$
works for me.
Adam's link put me in a direction that will solve the problem, albeit not without some minor caveats.
The script doesn't work unmodified under Cygwin, so I rewrote it, and with a couple more options. Here's my version:
#!/bin/bash
function usage
{
echo "usage: $(basename $0) [-c] [-<sigspec>] <pid>..."
echo "Recursively kill the process tree(s) rooted by <pid>."
echo "Options:"
echo " -c Only kill children; don't kill root"
echo " <sigspec> Arbitrary argument to pass to kill, expected to be signal specification"
exit 1
}
kill_parent=1
sig_spec=-9
function do_kill # <pid>...
{
kill "$sig_spec" "$#"
}
function kill_children # pid
{
local target=$1
local pid=
local ppid=
local i
# Returns alternating ids: first is pid, second is parent
for i in $(ps -f | tail +2 | cut -b 10-24); do
if [ ! -n "$pid" ]; then
# first in pair
pid=$i
else
# second in pair
ppid=$i
(( ppid == target && pid != $$ )) && {
kill_children $pid
do_kill $pid
}
# reset pid for next pair
pid=
fi
done
}
test -n "$1" || usage
while [ -n "$1" ]; do
case "$1" in
-c)
kill_parent=0
;;
-*)
sig_spec="$1"
;;
*)
kill_children $1
(( kill_parent )) && do_kill $1
;;
esac
shift
done
The only real downside is the somewhat ugly message that bash prints out when it receives a fatal signal, namely "Terminated", "Killed" or "Interrupted" (depending on what you send). However, I can live with that in batch scripts.
This script looks like it'll do the job:
#!/bin/bash
# Author: Sunil Alankar
##
# recursive kill. kills the process tree down from the specified pid
#
# foreach child of pid, recursive call dokill
dokill() {
local pid=$1
local itsparent=""
local aprocess=""
local x=""
# next line is a single line
for x in `/bin/ps -f | sed -e '/UID/d;s/[a-zA-Z0-9_-]\{1,\}
\{1,\}\([0-9]\{1,\}\) \{1,\}\([0-9]\{1,\}\) .*/\1 \2/g'`
do
if [ "$aprocess" = "" ]; then
aprocess=$x
itsparent=""
continue
else
itsparent=$x
if [ "$itsparent" = "$pid" ]; then
dokill $aprocess
fi
aprocess=""
fi
done
echo "killing $1"
kill -9 $1 > /dev/null 2>&1
}
case $# in
1) PID=$1
;;
*) echo "usage: rekill <top pid to kill>";
exit 1;
;;
esac
dokill $PID