I want to run simple unmount command before starting my "file-system" service on my node.
Is there any way to call bash script as cluster service?
You can run any script as a cluster service. The script needs to be LSB compliant: i.e. needs to know start, stop, restart, status, etc. I usually copy something simple from /etc/init.d and modify it for myself.
Put the script in /etc/ha.d/resource.d
Test it from command line
# sh /etc/ha.d/resource.d/start (see if it unmounts)
Now if you haven't already, create resource group. Add in all your resources into the same group. Then add your new script in the resource group. You can configure constraints so that all resources depend on your first application resource to run first.
That's about it. You don't need to actually have anything configured for stop and status except "exit" since you just want your script to run once (to unmount)
Here is a script that might work in /etc/ha.d/resource.d
#!/bin/sh
#
# description: testapp auto start-stop script.
#
. /etc/rc.status
case "$1" in
start)
umount [filesystem]
;;
stop)
;;
reload*|restart*|force-reload*)
;;
status)
;;
*)
echo "options: start|stop|reload|restart|force-reload|status"
exit 1
;;
esac
exit
Hope that helps
I have an outline of my steps for building clusters plus an ebook here:
http://geekswing.com/geek/building-a-two-node-sles11-sp2-linux-cluster-on-vmware/
Related
We are using Azure DevOps Pipelines to orchestrate bash scripts on EC2 instances in AWS, running Ubuntu 18.04.
Within the pipelines, we mostly have bash tasks with inline scripts.
We'd like the bash tasks to pick up environment variables from both ~/.bashrc and /etc/profiles, so we made sure to uncheck the advanced options "Don't load the profile startup/initialization files" and "Don't read the ~/.bashrc initialization file".
Nevertheless, neither init file seems to be read.
See our example bash script:
#!/bin/bash -i
echo "HTTP_PROXY=${HTTP_PROXY}"
source /etc/profile
echo "HTTP_PROXY=${HTTP_PROXY}"
echo "SOMEVAR=${SOMEVAR}"
source ~/.bashrc
echo "SOMEVAR=${SOMEVAR}"
... will ouput:
HTTP_PROXY=
HTTP_PROXY=<some-proxy-host>:<some-port>
SOMEVAR=
SOMEVAR=
We only get our proxy variables after sourcing /etc/profiles explicitly.
Also, sourcing ~/.bashrc does not work as expected; possibly this is because the script is not run in interactive bash mode.
Looking into ~/.bashrc we see that interactive mode is needed, otherwise it will quit immediately:
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
Why does /etc/profiles not get sourced automatically?
How can we make sure to have the bash tasks run in interactive mode?
I have the following code in my script:
case "$1" in
(-h)
display_help
exit 0
;;
(start)
start_services
;;
(stop)
stop_services
;;
(*)
display_help
exit 0
;;
esac
I want to be able to pass in an argument when one of these commands is called. For example, I want to start only a users service. I would issue the following command:
./services.sh start users
If I just enter:
./services.sh start
That works as expected, all services are started. However, if I issue the command with a service attached to it, like described above, it still starts all services, not just that service. The code in the start_services() function looks for an argument to start that service.
How do I get it so that it only starts that one service within the case statement?
If start_services looks for an argument, you have to pass it:
start_services "$2"
(Sorry for bad English, I'm German)
I'm trying (without success) to make my own program start automatically after booting (on a raspberry with raspian).
This is my script: (Note: You have to run this program with root privileges) (Note#2: There must be an empty file called "/home/testLog.txt" with write privileges for every user):
rm /etc/init.d/RMStart
echo "
#! /bin/sh
### BEGIN INIT INFO
# Provides: bla1
# Required-Start:
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: bla2
# Description: bla3
### END INIT INFO
#Switch case for the first parameter
case \"\$1\" in
start)
echo \"Start\" >> /home/testLog.txt
echo runlevel >> /home/testLog.txt
;;
stop)
echo \"Stop\" >> /home/testLog.txt
echo runlevel >> /home/testLog.txt
;;
restart)
echo \"Restart\" >> /home/testLog.txt
echo runlevel >> /home/testLog.txt
;;
*)
echo \"something else\" >> /home/testLog.txt
;;
esac
exit 0
" >> /etc/init.d/RMStart
chmod +x /etc/init.d/RMStart
update-rc.d RMStart remove #Remove older versions of this program ... in theory
update-rc.d RMStart defaults #Install new version of this program ... in theory
I've rebooted the raspberry, but the file /home/testLog.txt is still empty.
However, if I run the command: "/etc/init.d/RMStart" or "/etc/init.d/RMStart start" there is a new entry in /home/testLog.txt.
I would be thankful if anyone knows why the file /home/testLog.txt is still empty and how I could fix that.
Update:
I've tried a new installation script:
#RMS install script
chmod +x botComp.sh
rm /home/pi/RMS
pkill RMS
./botComp.sh
cp RMS /home/pi
chmod +x /home/pi/RMS
rm /etc/init.d/startRMS
sudo echo "#!/bin/sh
### BEGIN INIT INFO
# Provides: fqew
# Required-Start:
# Required-Stop:
# Default-Start: 3 4 5
# Default-Stop: 0 1 6
# Short-Description: sfwef
# Description: gfewf
### END INIT INFO
# Actions
case \"\$1\" in
start)
# START
su pi sh -c \" /home/pi/RMS \"
;;
stop)
# STOP
;;
restart)
# RESTART
;;
esac
exit 0 " >> /etc/init.d/startRMS
chmod +x /etc/init.d/startRMS
update-rc.d startRMS remove
update-rc.d startRMS defaults
The only difference I can see is the name of the script (/etc/init.d/startRMS instead of /etc/init.d/RMStart).
The script works, RMS is running.
It's not really a problem, but the script outputs:
insserv: script RMStart: service F already provided!
insserv: script RMStart: service F already provided!
I've added the line system("runlevel >> /home/pi/runlevelLog.txt"); In the program (RMS) but the content of /home/pi/runlevelLog.txt is: "unknown".
Does RMS start at runlevel 3? How I can I verify this? (I think runlevel 3 is ideal, because RMS needs Network Connection.) Thank you for your help.
is /etc/init.d/RMStart definitely being executed on reboot? use ls -lu to check the last time the file was accessed, wait a minute before rebooting, and repeat the command once you're back up. If the access time hasn't moved on then your script isn't being run which would explain the empty file as your script looks Ok.
You should also double check that update-rc.d has created symbolic links to your script in the appropriate run level directives e.g. does /etc/rc2.d/RMStart exist?
Another sanity check would be running your script using the symbolic links in the above directory rather than from /etc/init.d e.g. does /etc/rc2.d/RMStart
generate output in /home/testLog.txt?
Let me know what you find and we'll take it from there.
EDIT: attempting to replicate..
Well I managed to find my PI; the good news is that neither of us are going mad because it worked perfectly first time as we both believed it should.
I took a copy of your file, and I wrote a quick script (x) to check the exit codes from update-rc.d just to make 100% sure it wasn't complaining about anything.
Hopefully you can follow what I did in the screen shot above - I replicated the steps you followed almost exactly with a bit of extra checking along the way. The script certainly works as designed when called directly.
I then rebooted immediately and checked testLog.txt as soon soon as the system was up. You can see two entries in the file which is expected behaviour as init would have run /etc/rc6.d/K01RMStart as the system went down for reboot, and /etc/rc5.d/S01RMStart as it came up again.
Unfortunately this doesn't help you much.....
The only significant differnce between our tests was that I ran everything as root rather than using sudo. This shouldn't make a difference but the next logical thing for you to try is probably copying my test exactly and seeing if it works for you?
Not that this should be at all significant but I'm running Raspbian 8 (kernel 4.1.13+).
EDIT2: awesome... great stuff. I'd still like to know what the problem was but the main thing in that it's working.
System V based distributions will usually start in either level 3 or level 5, the difference being that level 5 will start the GUI whereas level 3 will start in text mode, their default runlevel is controlled by a line in /etc/inittab.
Debian(Raspian) distros are a bit different - (https://www.debian.org/doc/debian-policy/ch-opersys.html#s-sysvinit). They make no distinction between run levels 2-5 and leave it up the user to configure them to suit their requirements by adding services using the mechanism that's been causing us pain for the last 24 hours. They always start in level 5 unless a "init=" kernel boot parameter has been set, which you can do either at boot time or with a tool like bum or raspi-config.
The command runlevel will tell you the current level on raspian.
You can change the runlevel on the fly with telinit new_runlevel if you need to, but whatever you do, don't set the default runlevel to 0 :-)
I have a java program that stops often due to errors which is logged in a .log file. What can be a simple shell script to detect a particular text in the last/latest line say
[INFO] Stream closed
and then run the following command
java -jar xyz.jar
This should keep on happening forever(possibly after every two minutes or so) because xyz.jar writes the log file.
The text stream closed can arrive a lot of times in the log file. I just want it to take an action when it comes in the last line.
How about
while [[ true ]];
do
sleep 120
tail -1 logfile | grep -q "[INFO] Stream Closed"
if [[ $? -eq 1 ]]
then
java -jar xyz.jar &
fi
done
There may be condition where the tailed last log "Stream Closed" is not the real last log and the process is still logging the messages. We can avoid this condition by checking if the process is alive or not. If the process exited and the last log is "Stream Closed" then we need to restart the application.
#!/bin/bash
java -jar xyz.jar &
PID=$1
while [ true ]
do
tail -1 logfile | grep -q "Stream Closed" && kill -0 $PID && sleep 20 && continue
java -jar xyz.jar &
PID=$1
done
I would prefer checking whether the corresponding process is still running and restart the program on that event. There might be other errors that cause the process to stop. You can use a cronjob to periodically (like every minute) perform such a check.
Also, you might want to improve your java code so that it does not crash that often (if you have access to the code).
i solved this using a watchdog script that checks directly (grep) if program(s) is(are) running. by calling watchdog every minute (from cron under ubuntu), i basically guarantee (programs and environment are VERY stable) that no program will stay offline for more than 59 seconds.
this script will check a list of programs using the name in an array and see if each one is running, and, in case not, start it.
#!/bin/bash
#
# watchdog
#
# Run as a cron job to keep an eye on what_to_monitor which should always
# be running. Restart what_to_monitor and send notification as needed.
#
# This needs to be run as root or a user that can start system services.
#
# Revisions: 0.1 (20100506), 0.2 (20100507)
# first prog to check
NAME[0]=soc_gt2
# 2nd
NAME[1]=soc_gt0
# 3rd, etc etc
NAME[2]=soc_gp00
# START=/usr/sbin/$NAME
NOTIFY=you#gmail.com
NOTIFYCC=you2#mail.com
GREP=/bin/grep
PS=/bin/ps
NOP=/bin/true
DATE=/bin/date
MAIL=/bin/mail
RM=/bin/rm
for nameTemp in "${NAME[#]}"; do
$PS -ef|$GREP -v grep|$GREP $nameTemp >/dev/null 2>&1
case "$?" in
0)
# It is running in this case so we do nothing.
echo "$nameTemp is RUNNING OK. Relax."
$NOP
;;
1)
echo "$nameTemp is NOT RUNNING. Starting $nameTemp and sending notices."
START=/usr/sbin/$nameTemp
$START 2>&1 >/dev/null &
NOTICE=/tmp/watchdog.txt
echo "$NAME was not running and was started on `$DATE`" > $NOTICE
# $MAIL -n -s "watchdog notice" -c $NOTIFYCC $NOTIFY < $NOTICE
$RM -f $NOTICE
;;
esac
done
exit
i do not use the log verification, though you could easily incorporate that into your own version (just change grep for log check, for example).
if you run it from command line (or putty, if you are remotely connected), you will see what was working and what wasnt. have been using it for months now without a hiccup. just call it whenever you want to see what's working (regardless of it running under cron).
you could also place all your critical programs in one folder, do a directory list and check if every file in that folder has a program running under the same name. or read a txt file line by line, with every line correspoding to a program that is supposed to be running. etcetcetc
A good way is to use the awk command:
tail -f somelog.log | awk '/.*[INFO] Stream Closed.*/ { system("java -jar xyz.jar") }'
This continually monitors the log stream and when the regular expression matches its fires off whatever system command you have set, which is anything you would type into a shell.
If you really wanna be good you can put that line into a .sh file and run that .sh file from a process monitoring daemon like upstart to ensure that it never dies.
Nice and clean =D
I am a novice at Bash scripting but I'm a quick learner. Usually. I'm trying to write a script to kill and restart an instance of Hudson--it needs to be restarted to pick up changes in environment variables. What I have so far:
#!/bin/bash
h=`pgrep -f hudson`
if test "$h" != ""; then
kill $h
while [ "$h" != "" ]; do
sleep 1
unset h
h=`pgrep -f hudson`
done
fi
java -jar ~/hudson/hudson.war &
The script correctly determines the running Hudson instance's PID and kills it. However, it just waits after the "kill" line and doesn't proceed. If I hit a key there it completes killing the process and exits the script, never even getting to the while loop. Clearly I'm missing something about how the process should be killed. It's not that the Hudson process is hung and not responding to "kill"; it exits normally, just not until I intervene.
I'm also sure this could be much more efficient but right now I would just like to understand where I'm going wrong.
Thanks in advance.
This represents some straightforward improvements to your script:
#!/bin/bash
h=$(pgrep -f hudson) # $() is preferred over backticks
if [[ -n $h ]]; then # this checks whether a variable is non-empty
kill $h
while [[ -n $h ]]; do
sleep 1
h=$(pgrep -f hudson) # it's usually unnecessary to unset a variable before you set it
done
fi
java -jar ~/hudson/hudson.war &
However, it's likely that this is all you need (or use the provided facility that mrooney referred to):
while pkill hudson; do sleep 1; done
java -jar ~/hudson/hudson.war &
How about being nice to Hudson and let it shut down itself. I found the following statement in the Hudson forum:
I added http://server/hudson/exit to
1.161. Accessing this URL will shutdown the VM that runs Hudson.
You can call the URL with wget. You can still kill Hudson if it doesn't shut down in an appropriate time.
EDIT: I just stumbled over another thread, with interesting restart options. It uses commands of the build in Winstone server. Not sure if it will pick up changes to environment variables.
If you are using Hudson via an RPM, it comes with an init script already. If not, I'd take a look at them and see if you can base your script off of them: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main/rpm/SOURCES/ (guest//guest).