Track server configuration file changes using Git versioning system
When a server is managed by more than one admin, it’s always a challenge to keep track of the changes made to the configuration. And when in a multiserver environment managed by more than one admin, this is going to be more complex. It would have been much saner if there was a utility to handle all this. The ones that we found were quite complicated and was made for handling huge numbers. All we wanted was a very simple utility to do just the job, without much bells and whistles. And so, we started out on our own. Here’s what we have now.
We were using the Git for our Drupal code base version controlling. We thought the same could be made use of for system configuration file versioning. We created a bash script that did just that and scheduled it to execute once every hour.
The script compares configuration files with the ones we have in the git repo, and if changes are found, it copies them to a directory called conf and adds the changes to git. It reads the details of files to be tracked from a configuration file kept for the same.
Cron was used for scheduling jobs.
The script can run both as root as well as any normal user.
If the script finds any difference it sends out an email to the recipient address stored in the script.
The script requires that you have a git server and that you have already created a repo for the same.
Here is the script (you might have to modify the email, hostname variables):. You can also follow this at https://github.com/anoopjohn/utils/tree/master/chkconfig
#!/bin/bash
DEBUG=0
LOG_FILE="log.txt"
email_to_address="email1@example.com"
email_cc_address="email2@example.com"
# Debug function
function db {
if [ $DEBUG -eq 1 ];
then
echo "$1"
fi
}
# Log function
function log {
# If there are parameters read from parameters
if [ $# -gt 0 ]; then
echo "[$(date +"%D %T")] $@" >> $LOG_FILE
db "$@"
else
# If there are no parameters read from stdin
while read data
do
echo "[$(date +"%D %T")] $data" >> $LOG_FILE
db "$data"
done
fi
}
# Change to the dir this script resides in
script_path=`readlink -f $0`
script_dir=`dirname "$script_path"`
cd "$script_dir"
# Run copy operations if run as root
if [ $(id -u) -eq 0 ]; then
db "Running copy operations"
# Copy files to the conf folder
while read path
do
# Ignore comments and empty lines
echo "$path" | egrep '(^\s*#)|(^\s*$)' >/dev/null 2>&1 && continue
db "$path read from the file"
source="$path"
destination="./conf/`hostname`$path"
if [ -f "$source" ]; then
# If file then copy
param='-f'
elif [ -d $source ]; then
# If folder then deep copy
param='-fR'
destination="`dirname \"$destination\"`"
# Create the destination folder if it does not exist
if [ ! -d "$destination" ]; then
log "$destination does not exist. Creating dir"
mkdir -p "$destination"
fi
else
log "$path: Illegal path found."
# Continue on to the next path
continue
fi
db "Copying $source to $destination"
(nice cp $param "$source" "$destination" 2>&1) | log
done < ./`hostname`.conf
db "Changing ownership of conf/`hostname` to metheuser"
chown -R metheuser: metheuser "conf/`hostname`"
# Run git operations if run as normaluser
else
db "Running git operations"
# Run git diff to find changes
file_diff=`git diff --no-prefix`
diff_lines=$(($(echo -n "$file_diff" | wc -l)))
# Run git status to check if untracked files are present
git status|grep untracked > /dev/null
if [ $? -eq 0 ]; then
has_untracked=1
git_status=`git status`
fi
# If there is a difference
if [[ $diff_lines -gt 0 || $has_untracked -eq 1 ]]; then
log "$diff_lines line(s) of difference found"
log "Has untracked = $has_untracked"
# Get latest changes from other servers
log "Pulling changes (if any) from server"
(git pull 2>&1) | log
# Commit the difference on the machine
(git add -A 2>&1) | log
(git commit -m "Adding changes from $(hostname)" 2>&1) | log
(git push 2>&1) | log
db $file_diff
subject="[CONFIG-TRACK] `hostname` - Status Report - $(date)"
git_differences="`echo -e "$file_diff\n$git_status"`"
log "Sending differences via email"
log "$git_differences"
echo -e "$git_differences" | mail -s "$subject" -c $email_cc_address $email_to_address 2>&1 | log
else
db "No differences found"
fi
fi