Sometimes, we find ourselves having to pilote infrastructures services supported by panels managements and … between us, I have a holy horror of Plesk, Cpanel, Ispconfig, Webmin … Especially when under certain circumstances some components are falling down. It’s often badly done and messy that it’s difficult to find your way around. Between abobinable logs management (yes, I already found php logs in syslog), a non-existent server optimization… well I stop here because it is not the purpose of this post.
In fact, what happened lately is that I discovered on a “certain version” of a “certain panel” that I won’t write here, php-fpm is crashing miserably and randomly. Of course, just to make it funny, this incident leads to a service outage for about 200 users, cool no?
So, at some point you have to say f*ck and drive the mess properly, so you get the bash out. So yes, you tell me, why bother, just use a service like monit? Well I tested but no.
So, just to make it right, we start our script the following way.
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
#/ Usage: ./main.sh
#/ Description: This script monitore services
#/ Examples: ./main.sh
#/ Options:
#/ --help: Display this help message
usage() { grep '^#/' "$0" | cut -c4- ; exit 0 ; }
expr "$*" : ".*--help" > /dev/null && usage
readonly LOG_FILE="/tmp/$(basename "$0").log"
info() { echo "$(date -u) [INFO] $*" | tee -a "$LOG_FILE" >&2 ; }
warning() { echo "$(date -u) [WARNING] $*" | tee -a "$LOG_FILE" >&2 ; }
error() { echo "$(date -u) [ERROR] $*" | tee -a "$LOG_FILE" >&2 ; }
fatal() { echo "$(date -u) [FATAL] $*" | tee -a "$LOG_FILE" >&2 ; exit 1 ; }
# Debug
# Cleaning if exit
cleanup() {
rm "$LOG_FILE"
}
trap cleanup EXIT
So far, nothing extraordinary, we have our shebang, different logging functions and a clean service with trap.
As I like to be alerted of the actions of my scripts, we’re going to declare a mail sending function:
# Func mail
sendMail() {
echo "$(date) : $1 restarted on $HOSTNAME" | mail -s "$1 restarted on $HOSTNAME" "my@mail"
}
We will then declare our function for a given service (at random, a service that never falls…):
# Func php-fpm
php-fpm() {
if pgrep php5-fpm > /dev/null
then
info "Php-FPM service is up."
:
else
warning "Php-FPM service down, restarting it !"
if /etc/init.d/php5-fpm restart > /dev/null
then
info "Php-FPM service restarted"
sendMail "php-FPM"
fi
fi
}
Here we check if the service has an active pid, in which case it is restarted, logged and sent a mail.
Repeat the operation with the other services involved if necessary and call the main:
if [[ "${BASH_SOURCE[0]}" = "$0" ]]; then
info "Starting..."
while true; do
# Functions call
php-fpm
sleep 5
# vos autres fonctions ici
done
fi
Full version :
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
#/ Usage: ./main.sh
#/ Description: This script monitore Plesk Web services
#/ Examples: ./main.sh
#/ Options:
#/ --help: Display this help message
usage() { grep '^#/' "$0" | cut -c4- ; exit 0 ; }
expr "$*" : ".*--help" > /dev/null && usage
readonly LOG_FILE="/tmp/$(basename "$0").log"
info() { echo "$(date -u) [INFO] $*" | tee -a "$LOG_FILE" >&2 ; }
warning() { echo "$(date -u) [WARNING] $*" | tee -a "$LOG_FILE" >&2 ; }
error() { echo "$(date -u) [ERROR] $*" | tee -a "$LOG_FILE" >&2 ; }
fatal() { echo "$(date -u) [FATAL] $*" | tee -a "$LOG_FILE" >&2 ; exit 1 ; }
# Debug
# Cleaning if exit
# cleanup() {
# rm "$LOG_FILE"
# }
# trap cleanup EXIT
# Functions
# Func mail
sendMail() {
echo "$(date) : $1 restarted on $HOSTNAME" | mail -s "$1 restarted on $HOSTNAME" "my@mail"
}
# Func nginx
nginx() {
if pgrep nginx > /dev/null
then
# info "Nginx service is up."
:
else
warning "Nginx service down, restarting it !"
if /etc/init.d/nginx restart > /dev/null
then
info "Nginx service restarted"
sendMail "nginx"
fi
fi
}
# Func php-fpm
php-fpm() {
if pgrep php5-fpm > /dev/null
then
# info "Php-FPM service is up."
:
else
warning "Php-FPM service down, restarting it !"
if /etc/init.d/php5-fpm restart > /dev/null
then
info "Php-FPM service restarted"
sendMail "php-FPM"
fi
fi
}
# Func mysql
mysql(){
if pgrep mysql > /dev/null
then
# info "Mysql service is up."
:
else
warning "Mysql service down, restarting it !"
if /etc/init.d/mysql restart > /dev/null
then
info "Mysql service restarted"
sendMail "mysql"
fi
fi
}
# Func apache
apache(){
if pgrep apache2 > /dev/null
then
# info "Apache2 service is up."
:
else
warning "Apache2 service down, restarting it !"
if /etc/init.d/apache2 restart > /dev/null
then
info "Apache2 service restarted"
sendMail "apache2"
fi
fi
}
if [[ "${BASH_SOURCE[0]}" = "$0" ]]; then
# If root :
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root"
exit 1
fi
info "Starting..."
while true; do
# Functions call
nginx
sleep 5
php-fpm
sleep 5
mysql
sleep 5
apache
sleep 5
done
fi
Well, it’s nothing too crazy, but I find that doing things manually really helps you target exactly what you want to do.
As usual, the sources are available!
In a future post, we’ll see how to factorize all this script to avoid repetition and make it more readable.
See you soon!