Checking if a node.js app has started properly using bash - linux

I wrote a node.js application and have written a bash script to start it and verify if it's running. I have my script run npm start & first, then I have a check to see if the ports I want open are open using netstat. The check works fine when I run it after the script is run, but during the running of the script, the check fails because the server has not fully started before the check is run. My code is below:
echo "Starting the server..."
npm start & > /dev/null 2>&1
if [[ -z $(sudo netstat -tulpn | grep :$portNum | grep node) ]] ; then
echo -e "\tPort $portNum is not in use, something went wrong. Exiting."
else
echo -e "\tPort $portNum is in use!"
fi
Is there a good way to take the above script and change it so that the check doesn't occur until the server is fully started? I don't want to use sleep if I can help it.

You can use a wait call:
echo "Starting the server..."
npm start & > /dev/null 2>&1
wait
if [[ -z $(sudo netstat -tulpn | grep :$portNum | grep node) ]] ; then
echo -e "\tPort $portNum is not in use, something went wrong. Exiting."
else
echo -e "\tPort $portNum is in use!"
fi
The only limitation to this is that if npm daemonizes itself then it's no longer a child of the script so the wait command will have no effect (the reason for this is that a process daemonizes itself by terminating and spawning a new process that inherits its role).

Related

Bash - use 1 stop script for multiple similar services, and kill the correct process only

I have multiple processes running as services on a machine
Before moving from 1 process/service to multiple ones, I used the following script to stop my service
#!/bin/sh
SIGNAL=${SIGNAL:-TERM}
PIDS=$(ps ax | grep -i 'datastream' | grep java | grep -v grep | awk '{print $1}')
if [ -z "$PIDS" ]; then
echo "No Brooklin server to stop"
exit 1
else
kill -s $SIGNAL $PIDS
fi
The issue now is that this script kills all processes of this type if invoked as a service stop command
My services are called for example service-A, service-B, service-C. If I send a service service-C stop command, the current script will stop all 3 processes.
I would like to make the script use the provided service name to determine which process to stop (I can grep A/B/C from the process output to ps, but I haven't managed to tell it how to stop only the process given in the service stop command.
Does anyone have experience handling something similar?
You can try something like below while starting your application which can store your PID in a static file and then you can use the same file to kill the process.
Pasting below one of my start - stop script which I have used in past for churning up multiple processes.
Start Script :-
#!/bin/bash
export PORT=$1
. /application/setEnv.sh
/java/jdk1.8.0_152/bin/java -Xms512m -Xmx2G -XX:+DisableExplicitGC -jar /application/api-1.0-0-all.jar </dev/null >>$LOGDIR/service$PORT.log 2>&1 &
echo $! > /application/service$PORT.pid
disown $!
Stop Script :-
#!/bin/bash
PORT=$1
PID=`cat /application/service$PORT.pid`
if [ ! -z "$PID" ]; then
rm /application/service$PORT.pid
kill -9 $PID >/dev/null 2>&1
if [ $? -gt 0 ]; then
echo "PID file found but no matching process was found. Stop aborted."
exit 1
fi
else
echo "PID file is empty and has been ignored."
fi
mv /application/logs/service$PORT.log /application/logs/service$PORT.log`date +%d%m%Y%H%M%S`
Only change which I can think of is the replace my port utilisation logic viz. $PORT with your service names viz. A/B/C.

How to get the status of any service in a sh script on centos 7?

I am trying to get the service status (for a /bin/sh script) and start it if is not running.
I found some scripts, but does not work for centos 7.
There are, as usual, multiples ways to do this. Just one example, that check if postfix is running:
#!/bin/sh
PID=`cat /var/spool/postfix/pid/master.pid`
# echo $PID
PS=`/bin/ps axu | grep $PID | grep -v grep`
# echo $PS
if [ "$PS" = "" ]
then
/sbin/service postfix restart
fi
You could use "pid" file, or try to detect if process is running (parsing output of "ps axu |grep process_name"), or parse output of "service process status" command, etc, etc.

Bash: start remote python application through ssh and get its PID

I'm creating a little bash script to copy new files from a windows machine to a remote linux centos server (i run this script using the git-shell) then i want to restart the python application thats running in the server to use those new files.
The problem is that everytime i run this script i want to end the actual running process before i start it again, so i want to get the pid of the process i start and save it to a file in the remote host so i can read it from there the next time i run the program and kill it.
My code by now looks similar to this:
echo "Copying code files to server..."
# The destination folder has to exist in the server
scp -r ./python/ root#myserver:/root/
echo "Checking for running processes..."
if ssh root#myserver 'ls dmr.pid >/dev/null'; then
echo "PID file exists, reading file..."
PID=$(ssh root#myserver 'cat dmr.pid')
# Terminate the actual process
echo "Terminating the process with PID '$PID'..."
ssh root#myserver 'kill $PID'
else
echo "PID file doesn't exist, not known processes running"
fi
# Restart the server and get the PID
echo "Restarting the server..."
ssh root#myserver 'python /root/python/run_dev_server.py > /dev/null 2>&1 &'
SERV_PID=$(ssh root#myserver 'echo $!')
echo "Saving PID to file dmr.pid"
ssh root#myserver "echo '$SERV_PID' > \"dmr.pid\""
echo "Sucesfully finished!"
The important lines are:
ssh root#myserver 'python /root/python/run_dev_server.py > /dev/null 2>&1 &'
SERV_PID=$(ssh root#myserver 'echo $!')
the problem with this is that the script finishes but the file ends up empty as well as the $SERV_PID variable.
And if i dont redirect the outputs and just do something like this:
SERV_PID=$(ssh root#myserver 'python /root/python/run_dev_server.py & echo $!')
i get stuck after "Restarting the server" and never get the PID or the file that will contain it or even the end of the script.
But if i run this right in the console:
ssh root#myserver 'python /root/python/run_dev_server.py & echo $!'
i get a PID printed to the terminal.
Any advice on this would be really appreciated.
ssh root#myserver 'python /root/python/run_dev_server.py > /dev/null 2>&1 &'
SERV_PID=$(ssh root#myserver 'echo $!')
With the above code, you are running two ssh commands and the both create two different shells. The problem is echo $! gives the most recent background process' ID from the current shell which is none.
That is, when you ssh for the second time, it's new shell and there's no background process running in it and hence echo $! gives no output. This explains why your PID file is empty.
Instead what you can do is to lookup for all instances of your python script and kill them using killall command. Or similar idea using ps command.
Thanks to Kingslndian i solved it by making one single command that did the three steps i required, so with that avoided the problem of running in different shells:
ssh root#myserver 'python /root/python/run_dev_server.py > /dev/null 2>&1 & echo $! > "dmr.pid"'

How to set up an automatic (re)start of a background ssh tunnel

I am a beginner user of linux, and also quite newbie at ssh and tunnels.
Anyway, my goal is to maintain a ssh tunnel open in background.
In order to do that, I wrote the following batch that I then added into crontab (the batch is automatically processed every 5 minutes during workdays and from 8am to 9pm).
I read in some other thread in stackoverflow that one should use autossh that will ensure the ssh will always be ok through a recurrent check. So did I....
#!/bin/bash
LOGFILE="/root/Tunnel/logBatchRestart.log"
NOW="$(date +%d/%m/%Y' - '%H:%M)" # date & time of log
if ! ps ax | grep ssh | grep tunnelToto &> /dev/null
then
echo "[$NOW] ssh tunnel not running : restarting it" >> $LOGFILE
autossh -f -N -L pppp:tunnelToto:nnnnn nom-prenom#193.xxx.yyy.zzz -p qqqq
if ! ps ax | grep ssh | grep toto &> /dev/null
then
echo "[$NOW] failed starting tunnel" >> $LOGFILE
else
echo "[$NOW] restart successfull" >> $LOGFILE
fi
fi
My problem is that sometimes the tunnel stops working, although every thing looks ok (ps ax | grep ssh > the result shows the two expected tasks : autossh main task and the ssh tunnel itself). I actually know about the problem cause the tunnel is used by a third party software that triggers an error as soon as the tunnel is no more responding.
SO I am wondering how I should improve my batch in order It will be able to check the tunnel and restart it if it happens to be dead. I saw some ideas in there, but it was concluded by the "autossh" hint... which I already use. Thus, I am out of ideas... If any of you have, I'd gladly have a look at them!
Thanks for taking interest in my question, and for your (maybe) suggestions!
Instead of checking the ssh process with ps you can do the following trick
create script, that does the following and add it to your crontab via crontab -e
#!/bin/sh
REMOTEUSER=username
REMOTEHOST=remotehost
SSH_REMOTEPORT=22
SSH_LOCALPORT=10022
TUNNEL_REMOTEPORT=8080
TUNNEL_LOCALPORT=8080
createTunnel() {
/usr/bin/ssh -f -N -L$SSH_LOCALPORT:$REMOTEHOST:SSH_REMOTEPORT -L$TUNNEL_LOCALPORT:$REMOTEHOST:TUNNEL_REMOTEPORT $REMOTEUSER#$REMOTEHOST
if [[ $? -eq 0 ]]; then
echo Tunnel to $REMOTEHOST created successfully
else
echo An error occurred creating a tunnel to $REMOTEHOST RC was $?
fi
}
## Run the 'ls' command remotely. If it returns non-zero, then create a new connection
/usr/bin/ssh -p $SSH_LOCALPORT $REMOTEUSER#localhost ls >/dev/null 2>&1
if [[ $? -ne 0 ]]; then
echo Creating new tunnel connection
createTunnel
fi
In fact, this script will open two ports
port 22 which will be used to check if the tunnel is still alive
port 8080 which is the port you might want to use
Please check and send me further questions via comments
(I add this as an answer since there is not enough room for it un a comment)
Ok, I managed to make the batch run to launch the ssh tunnel (I had to specify my hostname instead of localhost in order it could be triggered) :
#!/bin/bash
LOGFILE="/root/Tunnel/logBatchRedemarrage.log"
NOW="$(date +%d/%m/%Y' - '%H:%M)" # date et heure du log
REMOTEUSER=username
REMOTEHOST=remoteHost
SSH_REMOTEPORT=22
SSH_LOCALPORT=10022
TUNNEL_REMOTEPORT=12081
TUNNEL_SPECIFIC_REMOTE_PORT=22223
TUNNEL_LOCALPORT=8082
createTunnel() {
/usr/bin/ssh -f -N -L$SSH_LOCALPORT:$REMOTEHOST:$SSH_REMOTEPORT -L$TUNNEL_LOCALPORT:$REMOTEHOST:$TUNNEL_REMOTEPORT $REMOTEUSER#193.abc.def.ghi -p $TUNNEL_SPECIFIC_REMOTE_PORT
if [[ $? -eq 0 ]]; then
echo [$NOW] Tunnel to $REMOTEHOST created successfully >> $LOGFILE
else
echo [$NOW] An error occurred creating a tunnel to $REMOTEHOST RC was $? >> $LOGFILE
fi
}
## Run the 'ls' command remotely. If it returns non-zero, then create a new connection
/usr/bin/ssh -p $SSH_LOCALPORT $REMOTEUSER#193.abc.def.ghi ls >/dev/null 2>&1
if [[ $? -ne 0 ]]; then
echo [$NOW] Creating new tunnel connection >> $LOGFILE
createTunnel
fi
However, I got some immediate message (below) when the tunnel is running and when cron tries to lauch the batch again... sounds like it cannot listen to it. Also since I need some time to get a proof , I can't say yet it will successfully restart if the tunnel is out.
Here's the response to the second start of the batch.
bind: Address already in use channel_setup_fwd_listener: cannot listen
to port: 10022 bind: Address already in use
channel_setup_fwd_listener: cannot listen to port: 8082 Could not
request local forwarding.

How to tell the status of a Linux Daemon

We have a Linux Daemon in c and a bash script to start it. The daemon sometimes fail to start because of some configuration file errors but the script reports the daemon was started successfully. A snippet of the script is shown as below, could someone tell me what's wrong with the script?
...
case "$1" in
start)
echo -n "Starting Demo Daemon: "
sudo -u demouser env DEMO_HOME=$DEMO_HOME /usr/local/demouser/bin/democtl startup > /dev/null 2> /dev/null
if [ "$?" = "0" ]; then
echo_success
else
echo_failure
fi
echo
;;
...
Thanks!
I feel there is nothing wrong with the script,it is the reponsibility of daemon to return non zero exit status if failed to start properly and based on those the script will display the message.(which i think it does)
You can add following line in your script to get running status of your Linux Daemon
status=`ps -aef |grep "\/usr\/local\/demouser\/bin\/democtl" |grep -v grep|wc -l`
if [ "$status" = "1" ]; then
echo_success
else
echo_failure
fi

Resources