kill and restart the application from shell script - linux

I am trying to invoke the script from the c code, wherein the script file kills the application and restarts
/* testApp.c */
int main()
{
int data;
printf("Enter the data\n");
scanf("%d",&data);
/* Invoke the script file */
system("script.sh");
}
and below is the script file
#!/bin/sh
pkill testApp
start-stop-daemon --start --user root --name testApp --startas testApp -- --daemon
pidof testApp
if [ $? == 0 ]
then
echo "Restart of testApp success!!"
else
echo "Restart of testApp failed!!"
exit 1
fi
exit 0
when the application is executed, it terminates the running process and restarts the application, but it is not waiting at scanf for user input, just continues to execute
why isn't the application waiting for user input, if invoked from script file

Related

openrc can't start service that crashed, leaves started symlink behind

This init script is for a node service that sometimes crashes. When it does the started file /var/run/openrc/started/mStream is left behind and this prevents openrc from starting the app because it thinks it's already running.
The first start works fine, but then the symlink needs to be manually removed if the program crashes.
The name of the init script for the service is mStream
#!/sbin/openrc-run
pidfile=/var/run/node.pid
procname=/usr/bin/node
command_background=true
start() {
cd /home/alpine/setup/mStream
ebegin "Starting ${SVCNAME}"
start-stop-daemon --start --pidfile ${pidfile} --exec node --background cli-boot-wrapper.js
eend $?
}
stop() {
ebegin "Stopping ${SVCNAME}"
killall node
eend $?
}
restart() {
stop
wait;
start
}
status() {
netstat -naptu | grep -q ":80.*LISTEN.*node" && {
echo "Running"
} || {
echo "Stopped"
exit 1
}
}

PowerShell script to SSH to Multiple Linux devices and restart/reboot them

I am comfortable with writing single queries. I am new to writing bash scripts trying to automate the daily stuff. I need help on creating a PowerShell or bash script where I can SSH to multiple Linux devices with same SSH key and then reboot the devices.
I access linux devices manually with the following command in PowerShell
ssh -i C:\<path-to-the-private-key\test.ppk test#XX.X.X.XXX (X - IP Address)
Then I enter the following command
sudo reboot
It asks me to type the password and then restarts the device.
I have 100+ devices that I need to restart.
I can get a list of all IP address in a text file. How can we search for all the IP address in a text file, authenticate with the SSH private key and run the sudo command to restart the device?
Would it also be possible to throw a message if it was not able to restart a device?
Any help would be appreciated.
This is the script that I have.
testreboot.sh
#!/bin/bash
pw="test123"
hosts='IP.txt'
while read -r line; do {
/usr/bin/expect << EOF do
ssh test#"$hosts" 'sudo reboot'
expect "*?assword*"
send "%pw\r"
EOF
}
done < $hosts
IP.txt
XXX.XX.XX.XX
XXX.XX.XX.XX
XXX.XX.XX.XX
XXX.XX.XX.XX
I have Ubuntu 20.04 installed from Windows App Store. I am trying to run the testreboot.sh from PowerShell using the following command and get the following error message.
bash testreboot.sh
testreboot.sh: line 2: $'\r': command not found
testreboot.sh: line 3: $'\r': command not found
testreboot.sh: line 5: $'\r': command not found
testreboot.sh: line 16: syntax error near unexpected token `done'
testreboot.sh: line 16: `done < $hosts'
A better solution to this problem is to use something like Ansible, Chef, or Puppet to solve these multi-server coordination needs.
Here is an example in a shell script using expect to ssh to another server and login:
NOTE: When you use expect in this manner, you need to escape " and $ and
other items. If password has $, it must be escaped.
This is where after logging in and expect see a command prompt
For example:
44 [localhost.localdomain]/home/map%
This is where you would need to add sudo reboot command
-re \"$reg_ex_prompt\" {
}
Test Script:
#!/bin/sh
#
debug=0
exit_val=0
spawn_item="ssh"
destination="user_name#<IP of server to shh>"
reg_ex_prompt='\[%|>|\$|#\] $'
#
# Change -D 0 to -D 1 to debug interactivly
#
expect -D $debug -c "
spawn $spawn_item $destination
set ret 1
set timeout 20
expect {
timeout {
send_user \"Timeout reached!\"
exit \$ret
}
eof {
puts \"End of test connection reached!\"
if { \$ret == 0 } {
puts \"Connection test Successful!\"
puts \"Exiting $destination ...\"
} else {
puts \"Connection Failure!\"
}
exit \$ret
}
\"Connection refused\" {
puts \"ERROR: Trouble connecting to $device_type_parm destination $destination\"
puts \"Aborting...\"
exit \$ret
}
\"Permission denied\" {
puts \"ERROR: User name or password is incorrect for $destination\"
puts \"Aborting...\"
exit \$ret
}
\"Connection reset by peer\" {
puts \"ERROR: Trouble connecting to $destination\"
puts \"Aborting...\"
exit \$ret
}
\"you sure you want to continue connecting\" {
send \"yes\r\"
exp_continue
}
\"assword:\" {
puts \"\r\nSending password\"
send \"password\\\$\r\"
exp_continue
}
\"Choice? \" {
send \"1\r\"
exp_continue
}
\"Q. Quit\" {
send \"q\r\"
exp_continue
}
-re \"$reg_ex_prompt\" {
send \"sudo reboot\r\"
sleep 2
set ret 0
exit \$ret
}
interact
} "
# get the exit value from expect statment above
exit_val=$?

How can a runit' service restart return instantly?

I have a runit service I use to run a rails app using unicorn.
Its restart command uses a signal (USR2) to handle a zero-downtime restart. Basically, it waits until the new process is ready before the old ones die.
This causes a very long (40 seconds) restart time, in which service myservice restart doesn't return until the end.
While I can give runit a longer timeout (which I already do), I want to make this restart a fire-and-forget kind of action so it'll return instantly (or after the USR2 signal was fired, but without waiting for it to complete.
The entire logic is taken from multiple blog posts about zero-downtime rails deployments with unicorn restarts:
https://gist.github.com/czarneckid/4639793
https://gist.github.com/JeanMertz/8996796
https://nulogy.com/who-we-are/company-blog/articles/zero-downtime-deployments-with-chef-nginx-and-unicorn/
This is the runit script (generated by chef):
#!/bin/bash
#
# This file is managed by Chef, using the <%= node.name %> cookbook.
# Editing this file by hand is highly discouraged!
#
exec 2>&1
#
# Since unicorn creates a new pid on restart/reload, it needs a little extra
# love to manage with runit. Instead of managing unicorn directly, we simply
# trap signal calls to the service and redirect them to unicorn directly.
#
RUNIT_PID=$$
APPLICATION_NAME=<%= #options[:application_name] %>
APPLICATION_PATH=<%= File.join(#options[:path], 'current') %>
BUNDLE_CMD="<%= #options[:bundle_command] ? "#{#options[:bundle_command]} exec" : '' %>"
UNICORN_CMD=<%= #options[:unicorn_command] ? #options[:unicorn_command] : 'unicorn' %>
UNICORN_CONF=<%= #options[:unicorn_config_path] ? #options[:unicorn_config_path] : File.join(#options[:path], 'current', 'config', 'unicorn.rb') %>
RAILS_ENV=<%= #options[:rails_env] %>
CUR_PID_FILE=<%= #options['pid'] ? #options['pid'] : File.join(#options[:path], 'current', 'shared', 'pids', "#{#options[:application_name]}.pid") %>
ENV_PATH=<%= #options[:env_dir] %>
OLD_PID_FILE=$CUR_PID_FILE.oldbin
echo "Runit service restarted (PID: $RUNIT_PID)"
function is_unicorn_alive {
set +e
if [ -n $1 ] && kill -0 $1 >/dev/null 2>&1; then
echo "yes"
fi
set -e
}
if [ -e $OLD_PID_FILE ]; then
OLD_PID=$(cat $OLD_PID_FILE)
echo "Old master detected (PID: $OLD_PID), waiting for it to quit"
while [ -n "$(is_unicorn_alive $OLD_PID)" ]; do
sleep 5
done
fi
if [ -e $CUR_PID_FILE ]; then
CUR_PID=$(cat $CUR_PID_FILE)
if [ -n "$(is_unicorn_alive $CUR_PID)" ]; then
echo "Detected running Unicorn instance (PID: $CUR_PID)"
RUNNING=true
fi
fi
function start {
unset ACTION
if [ $RUNNING ]; then
restart
else
echo 'Starting new unicorn instance'
cd $APPLICATION_PATH
exec chpst -e $ENV_PATH $BUNDLE_CMD $UNICORN_CMD -c $UNICORN_CONF -E $RAILS_ENV
sleep 3
CUR_PID=$(cat $CUR_PID_FILE)
fi
}
function stop {
unset ACTION
echo 'Initializing graceful shutdown'
kill -QUIT $CUR_PID
while [ -n "$(is_unicorn_alive $CUR_PID)" ]; do
echo '.'
sleep 2
done
echo 'Unicorn stopped, exiting Runit process'
kill -9 $RUNIT_PID
}
function restart {
unset ACTION
echo "Restart request captured, swapping old master (PID: $CUR_PID) for new master with USR2"
kill -USR2 $CUR_PID
sleep 2
echo 'Restarting Runit service to capture new master PID'
exit
}
function alarm {
unset ACTION
echo 'Unicorn process interrupted'
}
trap 'ACTION=stop' STOP TERM KILL
trap 'ACTION=restart' QUIT USR2 INT
trap 'ACTION=alarm' ALRM
[ $RUNNING ] || ACTION=start
if [ $ACTION ]; then
echo "Performing \"$ACTION\" action and going into sleep mode until new signal captured"
elif [ $RUNNING ]; then
echo "Going into sleep mode until new signal captured"
fi
if [ $ACTION ] || [ $RUNNING ]; then
while true; do
[ "$ACTION" == 'start' ] && start
[ "$ACTION" == 'stop' ] && stop
[ "$ACTION" == 'restart' ] && restart
[ "$ACTION" == 'alarm' ] && alarm
sleep 2
done
fi
This is a super weird way to use Runit, move your reload logic to the control/h script and use sv hup (or since it doesn't seem to be anything more than sending USR2 sv 2). The main run script shouldn't be involved.

Why isn't stdout set after executing a child process in a node.js script that's running as a daemon?

This works as expected if I run it from the command line (node index.js). But when I execute this Node.js (v0.10.4) script as a daemon from a init.d script the stdout return value in the exec callback is not set. How do I fix this?
node.js script:
var exec = require('child_process').exec;
setInterval(function()
{
exec('get_switch_state', function(err, stdout, stderr)
{
if(stdout == "on")
{
// Do something.
}
});
}, 5000);
init.d script:
#!/bin/bash
NODE=/development/nvm/v0.10.4/bin/node
SERVER_JS_FILE=/home/blahname/app/index.js
USER=root
OUT=/home/pi/nodejs.log
case "$1" in
start)
echo "starting node: $NODE $SERVER_JS_FILE"
sudo -u $USER $NODE $SERVER_JS_FILE > $OUT 2>$OUT &
;;
stop)
killall $NODE
;;
*)
echo "usage: $0 (start|stop)"
esac
exit 0
I ended up not using Node.js exec child_process. I modified the init.d script above (/etc/init.d/node-app.sh) as follows:
#!/bin/bash
NODE=/home/pi/development/nvm/v0.10.4/bin/node
SERVER_JS_FILE=/home/pi/development/mysql_test/index.js
USER=pi
OUT=/home/pi/development/mysql_test/nodejs.log
case "$1" in
start)
echo "starting node: $NODE $SERVER_JS_FILE"
sudo -u $USER TZ='PST' $NODE $SERVER_JS_FILE > $OUT 2>$OUT &
;;
stop)
killall $NODE
;;
*)
echo "usage: $0 (start|stop)"
esac
exit 0
This script launches the Node.js app "index.js" at boot up and everthing works as expected.

Startup script with systemd in Linux

Can I do This start up service below, there are no errors showing once run, but the server script below does not run!
ln /lib/systemd/aquarium.service aquarium.service
systemctl daemon-reload
systemctl enable aquarium.service
systemctl start aquarium.service
thanks
aquarium.service:
[Unit]
Description=Start aquarium server
[Service]
WorkingDirectory=/home/root/python/code/aquarium/
ExecStart=/bin/bash server.* start
KillMode=process
[Install]
WantedBy=multi-user.target
here is the server.sh script
#!/bin/bash
PID=""
function get_pid {
PID=`pidof python ./udpthread.py`
}
function stop {
get_pid
if [ -z $PID ]; then
echo "server is not running."
exit 1
else
echo -n "Stopping server.."
kill -9 $PID
sleep 1
echo ".. Done."
fi
}
function start {
get_pid
if [ -z $PID ]; then
echo "Starting server.."
./udpthread.py &
get_pid
echo "Done. PID=$PID"
else
echo "server is already running, PID=$PID"
fi
}
function restart {
echo "Restarting server.."
get_pid
if [ -z $PID ]; then
start
else
stop
sleep 5
start
fi
}
function status {
get_pid
if [ -z $PID ]; then
echo "Server is not running."
exit 1
else
echo "Server is running, PID=$PID"
fi
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
status)
status
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
esac
Try using "Type=forking" and use complete filename.
[Unit]
Description=Start aquarium server
[Service]
WorkingDirectory=/home/root/python/code/aquarium/
Type=forking
ExecStart=/bin/bash server.sh start
KillMode=process
[Install]
WantedBy=multi-user.target
if it not work, post output of this command:
# journalctl -u aquarium.service

Resources