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

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"'

Related

Getting exit code from SSH command running in background in Linux (Ksh script)

I trying to run few commands to be executed in parallel in couple of remote servers using SSH and i need to get the correct exit code from those commands but with no success.
I am using the command below
(ssh -o LogLevel=Error "remote_server1" -n " . ~/.profile 1>&- 2>&-;echo "success" 2>&1 > /dev/null" ) & echo $? > /tmp/test1.txt
(ssh -o LogLevel=Error "remote_server2" -n " . ~/.profile 1>&- 2>&-;caname 2>&1 > /dev/null" ) & echo $? > /tmp/test2.txt
The result is always "0" (echo $?) even i forced to failed like the second example above. Any idea?

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

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).

Shell Scripting ssh execution of commands

I have no idea, how to execute this specific combined shell script command via ssh on a remote device.
#!/bin/bash
cmd=""
command="restart"
case "$command" in
restart)
cmd+="pkill -f fileA.py;"
cmd+="python3 -u fileA.py >> fileA.log &"
;;
*)
echo "Unknown command"
esac
cmd=$(ssh root#foobar $cmd)
The error that occurs is:
pkill -f fileA.py;python3 -u fileA.py >> fileA.log &
pkill: invalid user name: fileA.py
I know that the whole string is interpreted as one command, but that's not what I want to achive.
I appreciate any help.
Are you sure you pasted the right code? That pkill error messages comes from using the -u or
-U options. Please check that first.
Next, your lack of quotes is causing you problems. After the shell substitutes the variables, you have this:
cmd=$(ssh root#foobar pkill -f fileA.py;python3 -u fileA.py >> fileA.log &)
So you're killing the process on the remote system, and launching it on the local system.
I think you really need this:
case "$command" in
restart)
cmd="pkill -f fileA.py; nohup python3 -u fileA.py >> fileA.log & disown"
;;
*)
echo "Unknown command"
esac
cmd=$(ssh root#foobar bash -c "$cmd")
nohup and disown allow the backgrounded process to keep running after the shell exits.

Bash script to re-launch program in case of failure error

In linux (I use a Ubuntu), I run a (ruby) program that continually runs all day long. My job is to monitor to see if the program fails and if so, re-launch the program. This consists up simply hitting 'Up' for last command and 'Enter'. Simple enough.
There has to be a way to write a bash script to monitor my program if its stops working and to re-launch it automatically.
How would I go about doing this?
A bonus is to be able to save the output of the program when it errors.
What you could do:
#!/bin/bash
LOGFILE="some_file.log"
LAUNCH="your_program"
while :
do
echo "New launch at `date`" >> "${LOGFILE}"
${LAUNCH} >> "${LOGFILE}" 2>&1 &
wait
done
Another way is to periodicaly check the PID:
#!/bin/bash
LOGFILE="some_file.log"
LAUNCH="your_program"
PID=""
CHECK=""
while :
do
if [ -n "${PID}" ]; then
CHECK=`ps -o pid:1= -p "${PID}"`
fi
# If PID does not exist anymore, launch again
if [ -z "${CHECK}" ]; then
echo "New launch at `date`" >> "${LOGFILE}"
# Launch command and keep track of the PID
${LAUNCH} >> "${LOGFILE}" 2>&1 &
PID=$!
fi
sleep 2
done
Infinite loop:
while true; do
your_program >> /path/to/error.log 2>&1
done

Obtaining PID of Last Command Run on Other Machine

I am using the following code to launch a command on another machine:
#!/bin/bash
/usr/bin/rsh -n $Host_Name "cat asdf.txt &"
And I am trying to obtain the PID of the cat command by using the following:
/usr/bin/rsh -n $Host_Name pid="$!"
But when I echo $pid, it is just blank. What am I doing incorrectly? Is there an easier way of obtaining the PID of the last command that was executed on a different machine?
Thanks
You can only get the $! of the backgrounded command in the shell in which you started the command. If your command doesn't output anything to stderr, this could work:
/usr/bin/rsh -n $Host_Name "cat asdf.txt & echo $! >&2" 2> pidfile
The pid of the started command will then be stored locally in 'pidfile'.
Just a side-note: I would never use rsh. It is inherently insecure. I'd use ssh instead ;)

Resources