2015-09-13 15:29:22 +02:00
#!/bin/sh
# EvoMaintenance script
2016-12-08 16:51:55 +01:00
# Dependencies (all OS): git postgresql-client
# Dependencies (Debian): sudo
2015-09-13 15:29:22 +02:00
2018-09-25 11:55:41 +02:00
# version 0.4.1
2018-09-05 00:04:22 +02:00
# Copyright 2007-2018 Gregory Colpart <reg@evolix.fr>, Jérémy Lecour <jlecour@evolix.fr>, Evolix <info@evolix.fr>
2016-12-08 16:32:35 +01:00
2018-09-25 09:48:29 +02:00
get_system( ) {
2019-03-07 22:21:44 +01:00
uname -s
2018-09-25 09:48:29 +02:00
}
get_fqdn( ) {
2019-03-07 22:21:44 +01:00
if [ " $( get_system) " = "Linux" ] ; then
hostname --fqdn
elif [ " $( get_system) " = "OpenBSD" ] ; then
hostname
else
echo "OS not detected!"
exit 1
fi
2018-09-25 09:48:29 +02:00
}
get_tty( ) {
2019-03-07 22:21:44 +01:00
if [ " $( get_system) " = "Linux" ] ; then
ps -o tty = | tail -1
elif [ " $( get_system) " = "OpenBSD" ] ; then
env | grep SSH_TTY | cut -d"/" -f3
else
echo "OS not detected!"
exit 1
fi
2018-09-25 09:48:29 +02:00
}
get_who( ) {
2019-03-07 22:21:44 +01:00
who = $( LC_ALL = C who -m)
2018-09-25 09:48:29 +02:00
2019-03-07 22:21:44 +01:00
if [ -n " ${ who } " ] ; then
echo " ${ who } "
else
LC_ALL = C who | grep $( get_tty) | tr -s ' '
fi
2018-09-25 09:48:29 +02:00
}
get_begin_date( ) {
2019-03-07 22:21:44 +01:00
echo " $( date "+%Y" ) $( echo $( get_who) | cut -d" " -f3,4,5) "
2018-09-25 09:48:29 +02:00
}
get_ip( ) {
2019-03-07 22:21:44 +01:00
ip = $( echo $( get_who) | cut -d" " -f6 | sed -e " s/^(// ; s/) $// " )
[ -z " ${ ip } " ] && ip = "unknown (no tty)"
[ " ${ ip } " = ":0" ] && ip = "localhost"
2018-09-25 09:48:29 +02:00
2019-03-07 22:21:44 +01:00
echo " ${ ip } "
2018-09-25 09:48:29 +02:00
}
get_end_date( ) {
2019-03-07 22:21:44 +01:00
date +"%Y %b %d %H:%M"
2018-09-25 09:48:29 +02:00
}
get_now( ) {
2019-03-07 22:21:44 +01:00
date +"%Y-%m-%dT%H:%M:%S%z"
2018-09-25 09:48:29 +02:00
}
2019-03-09 20:56:53 +01:00
2019-03-07 23:04:06 +01:00
get_complete_hostname( ) {
REAL_HOSTNAME = $( get_fqdn)
if [ " ${ HOSTNAME } " = " ${ REAL_HOSTNAME } " ] ; then
echo " ${ HOSTNAME } "
else
echo " ${ HOSTNAME } ( ${ REAL_HOSTNAME } ) "
fi
}
2019-03-09 20:56:53 +01:00
2019-03-07 23:04:06 +01:00
get_repository_status( ) {
dir = $1
# tell Git where to find the repository and the work tree (no need to `cd …` there)
export GIT_DIR = " ${ dir } /.git " GIT_WORK_TREE = " ${ dir } "
# If the repository and the work tree exist, try to commit changes
if test -d " ${ GIT_DIR } " && test -d " ${ GIT_WORK_TREE } " ; then
CHANGED_LINES = $( ${ GIT_BIN } status --porcelain | wc -l | tr -d ' ' )
if [ " ${ CHANGED_LINES } " != "0" ] ; then
STATUS = $( ${ GIT_BIN } status --short | tail -n 10)
2019-03-07 23:20:31 +01:00
printf "%s\n%s\n" " ${ GIT_DIR } (last 10 lines) " " ${ STATUS } " | sed -e '/^$/d'
2019-03-07 23:04:06 +01:00
fi
fi
# unset environment variables to prevent accidental influence on other git commands
unset GIT_DIR GIT_WORK_TREE
}
2018-09-25 09:48:29 +02:00
2019-03-09 21:42:05 +01:00
print_summary( ) {
BLOB = $( cat <<END
Host : $HOSTNAME_TEXT
User : $USER
IP : $IP
Begin : $BEGIN_DATE
End : $END_DATE
Message : $MESSAGE
END
)
echo " ${ BLOB } "
echo ""
}
print_options( ) {
echo "********** Options ****************"
echo " MESSAGE: ${ MESSAGE } "
echo " OPT_COMMIT: ${ OPT_COMMIT } "
echo " OPT_DB: ${ OPT_DB } "
echo " OPT_MAIL: ${ OPT_MAIL } "
echo " DRY_RUN: ${ DRY_RUN } "
echo "***********************************\n"
}
2019-03-07 23:04:19 +01:00
hook_commit( ) {
2019-03-07 22:32:58 +01:00
GIT_COMMITS = ""
if test -x " ${ GIT_BIN } " ; then
# loop on possible directories managed by GIT
for dir in ${ GIT_REPOSITORIES } ; do
# tell Git where to find the repository and the work tree (no need to `cd …` there)
export GIT_DIR = " ${ dir } /.git " GIT_WORK_TREE = " ${ dir } "
# If the repository and the work tree exist, try to commit changes
if test -d " ${ GIT_DIR } " && test -d " ${ GIT_WORK_TREE } " ; then
CHANGED_LINES = $( ${ GIT_BIN } status --porcelain | wc -l | tr -d ' ' )
if [ " ${ CHANGED_LINES } " != "0" ] ; then
2019-03-09 13:48:38 +01:00
if [ " ${ DRY_RUN } " = "1" ] ; then
STATS = $( ${ GIT_BIN } diff --stat | tail -1)
GIT_COMMITS = $( printf "%s\n%s : %s" " ${ GIT_COMMITS } " " ${ GIT_DIR } " " ${ STATS } " | sed -e '/^$/d' )
else
${ GIT_BIN } add --all
2019-03-09 14:01:38 +01:00
${ GIT_BIN } commit --message " ${ MESSAGE } " --author= " ${ USER } < ${ USER } @evolix.net> " --quiet
2019-03-09 13:48:38 +01:00
# Add the SHA to the log file if something has been committed
SHA = $( ${ GIT_BIN } rev-parse --short HEAD)
STATS = $( ${ GIT_BIN } show --stat | tail -1)
# append commit data, without empty lines
GIT_COMMITS = $( printf "%s\n%s : %s – %s" " ${ GIT_COMMITS } " " ${ GIT_DIR } " " ${ SHA } " " ${ STATS } " | sed -e '/^$/d' )
fi
2019-03-07 22:32:58 +01:00
fi
fi
# unset environment variables to prevent accidental influence on other git commands
unset GIT_DIR GIT_WORK_TREE
done
if [ -n " ${ GIT_COMMITS } " ] ; then
2019-03-09 20:56:53 +01:00
if [ " ${ VERBOSE } " = "1" ] ; then
2019-03-09 13:48:38 +01:00
echo " \n\n********** Commits ****************\n ${ GIT_COMMITS } \n*********************************** "
2019-03-09 20:56:53 +01:00
fi
if [ " ${ DRY_RUN } " != "1" ] ; then
2019-03-09 13:48:38 +01:00
echo " ${ GIT_COMMITS } " >> " ${ LOGFILE } "
fi
2019-03-07 22:32:58 +01:00
fi
fi
}
2019-03-07 23:04:19 +01:00
hook_db( ) {
2019-03-09 14:01:38 +01:00
SQL_DETAILS = $( echo " ${ MESSAGE } " | sed "s/'/''/g" )
PG_QUERY = " INSERT INTO evomaint(hostname,userid,ipaddress,begin_date,end_date,details) VALUES (' ${ HOSTNAME } ',' ${ USER } ',' ${ IP } ',' ${ BEGIN_DATE } ',now(),' ${ SQL_DETAILS } ') "
2019-03-09 13:48:38 +01:00
2019-03-09 20:56:53 +01:00
if [ " ${ VERBOSE } " = "1" ] ; then
2019-03-09 13:48:38 +01:00
echo " \n\n********** DB query **************\n ${ PG_QUERY } \n*********************************** "
2019-03-09 20:56:53 +01:00
fi
if [ " ${ DRY_RUN } " != "1" ] ; then
2019-03-09 13:48:38 +01:00
echo " ${ PG_QUERY } " | psql ${ PGDB } ${ PGTABLE } -h ${ PGHOST }
fi
2019-03-07 22:32:58 +01:00
}
2019-03-07 23:04:19 +01:00
hook_mail( ) {
2019-03-09 14:01:38 +01:00
MAIL_TEXTE = $( echo " ${ MESSAGE } " | sed -e "s@/@\\\\\/@g ; s@&@\\\\&@" )
2019-03-07 22:32:58 +01:00
MAIL_GIT_COMMITS = $( echo " ${ GIT_COMMITS } " | sed -e "s@/@\\\\\/@g ; s@&@\\\\&@" )
2019-03-09 20:56:53 +01:00
MAIL_CONTENT = $( sed -e " s/__TO__/ ${ EVOMAINTMAIL } / ; s/__HOSTNAME__/ ${ HOSTNAME_TEXT } / ; s/__USER__/ ${ USER } / ; s/__BEGIN_DATE__/ ${ BEGIN_DATE } / ; s/__END_DATE__/ ${ END_DATE } / ; s/__GIT_COMMITS__/ ${ MAIL_GIT_COMMITS } / ; s/__TEXTE__/ ${ MAIL_TEXTE } / ; s/__IP__/ ${ IP } / ; s/__FULLFROM__/ ${ FULLFROM } / ; s/__FROM__/ ${ FROM } / ; s/__URGENCYFROM__/ ${ URGENCYFROM } / ; s/__URGENCYTEL__/ ${ URGENCYTEL } / " /usr/share/scripts/evomaintenance.tpl)
2019-03-07 22:32:58 +01:00
2019-03-09 20:56:53 +01:00
if [ " ${ VERBOSE } " = "1" ] ; then
2019-03-09 13:48:38 +01:00
echo " \n\n********** Mail *******************\n ${ MAIL_CONTENT } \n*********************************** "
2019-03-09 20:56:53 +01:00
fi
if [ " ${ DRY_RUN } " != "1" ] ; then
2019-03-09 13:48:38 +01:00
echo " ${ MAIL_CONTENT } " | ${ SENDMAIL_BIN } -oi -t -f ${ FROM }
fi
2019-03-07 22:32:58 +01:00
}
2019-03-09 20:56:53 +01:00
hook_log( ) {
echo " ----------- $( get_now) --------------- " >> " ${ LOGFILE } "
echo " ${ BLOB } " >> " ${ LOGFILE } "
}
# load configuration if present.
2015-09-13 15:29:22 +02:00
test -f /etc/evomaintenance.cf && . /etc/evomaintenance.cf
2018-09-25 09:48:29 +02:00
[ -n " ${ HOSTNAME } " ] || HOSTNAME = $( get_fqdn)
2018-09-20 16:10:03 +02:00
[ -n " ${ EVOMAINTMAIL } " ] || EVOMAINTMAIL = evomaintenance-$( echo " ${ HOSTNAME } " | cut -d- -f1) @${ REALM }
[ -n " ${ LOGFILE } " ] || LOGFILE = /var/log/evomaintenance.log
2018-09-20 14:25:16 +02:00
2019-03-07 22:32:58 +01:00
[ -n " ${ OPT_COMMIT } " ] || OPT_COMMIT = 1
[ -n " ${ OPT_DB } " ] || OPT_DB = 1
[ -n " ${ OPT_MAIL } " ] || OPT_MAIL = 1
2019-03-07 23:26:24 +01:00
[ -n " ${ DRY_RUN } " ] || DRY_RUN = 0
2019-03-09 20:56:53 +01:00
[ -n " ${ VERBOSE } " ] || VERBOSE = 0
# initialize variable
MESSAGE = ""
2019-03-07 22:32:58 +01:00
2019-03-07 22:50:18 +01:00
# Parse options
2019-03-09 14:01:38 +01:00
# based on https://gist.github.com/deshion/10d3cb5f88a21671e17a
2019-03-07 22:50:18 +01:00
while :; do
case $1 in
# -h|-\?|--help) # Call a "show_help" function to display a synopsis, then exit.
# show_help
# exit
# ;;
2019-03-09 20:56:53 +01:00
-m| --message)
# message options, with value speparated by space
2019-03-09 14:01:38 +01:00
if [ -n " $2 " ] ; then
MESSAGE = $2
shift
else
printf 'ERROR: "--message" requires a non-empty option argument.\n' >& 2
exit 1
fi
; ;
--message= ?*)
2019-03-09 20:56:53 +01:00
# message options, with value speparated by =
MESSAGE = ${ 1 #*= }
2019-03-09 14:01:38 +01:00
; ;
2019-03-09 20:56:53 +01:00
--message= )
# message options, without value
2019-03-09 14:01:38 +01:00
printf 'ERROR: "--message" requires a non-empty option argument.\n' >& 2
exit 1
; ;
2019-03-09 20:56:53 +01:00
--no-commit)
# disable commit hook
2019-03-07 22:50:18 +01:00
OPT_COMMIT = 0
; ;
2019-03-09 20:56:53 +01:00
--commit)
# enable commit hook
2019-03-07 22:50:18 +01:00
OPT_COMMIT = 1
; ;
2019-03-09 20:56:53 +01:00
--no-db)
# disable DB hook
2019-03-07 22:50:18 +01:00
OPT_DB = 0
; ;
2019-03-09 20:56:53 +01:00
--db)
# enable DB hook
2019-03-07 22:50:18 +01:00
OPT_DB = 1
; ;
2019-03-09 20:56:53 +01:00
--no-mail)
# disable mail hook
2019-03-07 22:50:18 +01:00
OPT_MAIL = 0
; ;
2019-03-09 20:56:53 +01:00
--mail)
# enable mail hook
2019-03-07 22:50:18 +01:00
OPT_MAIL = 1
; ;
2019-03-09 20:56:53 +01:00
-n| --dry-run)
# disable actual commands
2019-03-07 23:26:24 +01:00
DRY_RUN = 1
; ;
2019-03-09 20:56:53 +01:00
-v| --verbose)
# print verbose information
VERBOSE = 1
; ;
--)
# End of all options.
2019-03-07 22:50:18 +01:00
shift
break
; ;
-?*)
2019-03-09 20:56:53 +01:00
# ignore unknown options
2019-03-07 22:50:18 +01:00
printf 'WARN: Unknown option (ignored): %s\n' " $1 " >& 2
; ;
2019-03-09 20:56:53 +01:00
*)
# Default case: If no more options then break out of the loop.
2019-03-07 22:50:18 +01:00
break
esac
shift
done
2019-03-09 20:56:53 +01:00
if [ " ${ VERBOSE } " = "1" ] ; then
2019-03-09 21:42:05 +01:00
print_options
2019-03-09 20:56:53 +01:00
fi
2018-09-20 15:56:13 +02:00
# Treat unset variables as an error when substituting.
# Only after this line, because some config variables might be missing.
set -u
2019-03-07 22:50:18 +01:00
# Gather information
2019-03-07 23:04:06 +01:00
HOSTNAME_TEXT = $( get_complete_hostname)
2018-09-25 09:48:29 +02:00
# TTY=$(get_tty)
# WHO=$(get_who)
IP = $( get_ip)
BEGIN_DATE = $( get_begin_date)
END_DATE = $( get_end_date)
USER = $( logname)
2018-09-05 18:44:53 +02:00
PATH = ${ PATH } :/usr/sbin
2015-09-13 15:29:22 +02:00
2018-09-20 15:23:52 +02:00
SENDMAIL_BIN = $( command -v sendmail)
2018-09-20 14:23:54 +02:00
GIT_BIN = $( command -v git)
2018-09-20 15:24:46 +02:00
GIT_REPOSITORIES = "/etc /etc/bind"
2019-03-09 20:56:53 +01:00
# initialize variable
2018-09-20 15:56:25 +02:00
GIT_STATUSES = ""
2019-03-09 20:56:53 +01:00
# git statuses
2018-09-20 15:24:46 +02:00
if test -x " ${ GIT_BIN } " ; then
# loop on possible directories managed by GIT
for dir in ${ GIT_REPOSITORIES } ; do
2019-03-07 23:04:06 +01:00
RESULT = $( get_repository_status " ${ dir } " )
if test -n " ${ RESULT } " ; then
2019-03-07 23:20:31 +01:00
# append diff data, without empty lines
2019-03-07 23:04:06 +01:00
GIT_STATUSES = $( printf "%s\n%s\n" " ${ GIT_STATUSES } " " ${ RESULT } " | sed -e '/^$/d' )
2018-09-20 15:24:46 +02:00
fi
2019-03-07 23:20:31 +01:00
unset RESULT
2018-09-20 15:24:46 +02:00
done
fi
2019-03-09 20:56:53 +01:00
# find out if running in interactive mode, or not
2019-03-09 14:01:38 +01:00
if [ -t 0 ] ; then
INTERACTIVE = 1
else
INTERACTIVE = 0
fi
2019-03-09 20:56:53 +01:00
if [ -z " ${ MESSAGE } " ] && [ " ${ INTERACTIVE } " = "1" ] ; then
2019-03-09 14:01:38 +01:00
# get input from stdin
echo "> Please, enter details about your maintenance"
2019-03-09 20:56:53 +01:00
read -r MESSAGE
2019-03-09 14:01:38 +01:00
fi
2015-09-13 15:29:22 +02:00
2019-03-09 14:01:38 +01:00
if test -z " ${ MESSAGE } " ; then
2015-09-13 15:29:22 +02:00
echo "no value..."
exit 1
fi
2019-03-09 21:42:05 +01:00
print_summary
2015-09-13 15:29:22 +02:00
2019-03-09 20:56:53 +01:00
# Log hook
if [ " ${ DRY_RUN } " != "1" ] ; then
hook_log
fi
# Commit hook
if [ " ${ INTERACTIVE } " = "1" ] ; then
if test -n " ${ GIT_STATUSES } " && [ " ${ OPT_COMMIT } " = "1" ] ; then
echo "/!\ There are some uncommited changes."
echo " ${ GIT_STATUSES } "
echo ""
y = "Y" ; n = "n"
answer = ""
while true; do
2019-03-09 21:59:37 +01:00
echo " Do you want to commit the changes? [ ${ y } ${ n } ] "
2019-03-09 20:56:53 +01:00
read -r answer
case $answer in
[ Yy] )
hook_commit;
break
; ;
[ Nn] )
break
; ;
"" )
if [ " ${ OPT_COMMIT } " = "1" ] ; then
hook_commit
fi
break
; ;
* )
echo "answer with a valid choice"
; ;
esac
done
fi
2019-03-07 23:26:24 +01:00
else
2019-03-09 20:56:53 +01:00
if [ " ${ OPT_COMMIT } " = "1" ] ; then
hook_commit
fi
fi
# Database hook
if [ " ${ INTERACTIVE } " = "1" ] ; then
if [ " ${ OPT_DB } " = "1" ] ; then
y = "Y" ; n = "n"
else
y = "y" ; n = "N"
fi
answer = ""
while true; do
2019-03-09 21:59:37 +01:00
echo " Do you want to insert your message into the database? [ ${ y } ${ n } ] "
2019-03-09 20:56:53 +01:00
read -r answer
case $answer in
[ Yy] )
hook_db;
break
; ;
[ Nn] )
break
; ;
"" )
if [ " ${ OPT_DB } " = "1" ] ; then
hook_db
fi
break
; ;
* )
echo "answer with a valid choice"
; ;
esac
done
else
if [ " ${ OPT_DB } " = "1" ] ; then
hook_db
fi
fi
# Mail hook
if [ " ${ INTERACTIVE } " = "1" ] ; then
if [ " ${ OPT_MAIL } " = "1" ] ; then
y = "Y" ; n = "n"
else
y = "y" ; n = "N"
fi
answer = ""
while true; do
2019-03-09 21:59:17 +01:00
echo " Do you want to send an email to < ${ EVOMAINTMAIL } >? [ ${ y } ${ n } e] "
2019-03-09 20:56:53 +01:00
read -r answer
case $answer in
[ Yy] )
2019-03-09 22:03:09 +01:00
hook_mail;
2019-03-09 20:56:53 +01:00
break
; ;
[ Nn] )
break
; ;
2019-03-09 21:59:17 +01:00
[ Ee] )
echo " To: [ ${ EVOMAINTMAIL } ] "
read -r mail_recipient
if [ -n " ${ mail_recipient } " ] ; then
EVOMAINTMAIL = " ${ mail_recipient } "
echo " changed to ${ EVOMAINTMAIL } "
fi
; ;
2019-03-09 20:56:53 +01:00
"" )
if [ " ${ OPT_MAIL } " = "1" ] ; then
hook_mail
fi
break
; ;
* )
echo "answer with a valid choice"
; ;
esac
done
else
if [ " ${ OPT_MAIL } " = "1" ] ; then
hook_mail
fi
2019-03-07 23:26:24 +01:00
fi
2019-03-09 13:48:38 +01:00
exit 0