[K12OSN] server configs
Martin Woolley
sysadmin at handsworth.bham.sch.uk
Fri Jul 1 10:24:55 UTC 2005
On Friday 01 July 2005 02:07, Roger wrote:
> anybody ever run across a system to help maintain config files for
> multiple servers?
> I have a setup where some of the files will be pretty much the same,
> it would be handy to have one place to make changes, then push out the
> changes to the servers.
Some time ago I wrote the following script to cope with dhcpd.conf and
lts.conf. Most of the contents of these files are the same, with one or two
lines specific to each server. The idea of this script is that one server is
designated the "master" and said script is run on the master. The script
makes a copy of the master file, edits the copy (making changes appropiate for
the target server) and then ftp's it to the target. We don't actually use
this script, so it is largely unproven (although it is tested). You run it
by passing a list of hosts, eg sync_host bart homer marge
-- start cut --
#!/bin/bash
#-----------------------------------------------------------------------#
# @(#) sync_host v1.00 - 22/11/03 (c) 2003 Handsworth Grammar School #
# Author: Martin Woolley (Handsworth Grammar School) #
# Written: 28/11/03 #
# Reason: To ensure certain files remain in sync between main servers #
#-----------------------------------------------------------------------#
#
# lisa is deemed to be the master host; others sync to this
# files synced :-
# /etc/hosts
# /etc/dhcpd.conf
# /opt/ltsp/i386/etc/lts.conf
#
# additional input files :-
# common.hosts - the first few lines of a host file
# make.<host>.lts.conf - patch file to create lts.conf from
# the "master" lts.conf held on lisa
# make.<host>.dhcpd.conf - patch file to create dhcpd.conf from
# the "master" dhcpd.conf held on lisa
PROG=$0
VERS="1.00 - 28/11/03"
SRCDIR="/home/martin" # location of files used
MASTER="lisa" # master machine
MHOSTS="/etc/hosts" # location of master hosts
MDHCPD="/etc/dhcpd.conf" # location of master
dhcpd.conf
MLTSCONF="/opt/ltsp/i386/etc/lts.conf" # location of master lts.conf
ROOTPASS="your_root_password" # root password for
all m/c's
WRKDIR="/tmp" # all processing occurs here
WRKDIR="/home/martin/tmp" ### DEBUG
WRKFILE="${WRKDIR}/$$" # workfile
WRKFIL1="${WRKDIR}/a$$" # workfile
ht=$(tput ht) # tab
function print_usage {
# display usage and exit
#
echo "Usage: ${PROG} [-s ] host1 host2 ..."
echo
echo "Where: -s sync the hosts"
exit 1
}
function print_vers {
# display version number and exit
#
more <<EOF
${PROG} Version: ${VERS}
This script runs on the machine designated as the master (${MASTER}) and
builds host specific versions of /etc/hosts, /etc/dhcpd.conf and
/opt/ltsp/i386/etc/lts.conf. Depending on runtime options, these
built files are either compared to those resident on the specified host,
or said files are propogated to the specified host.
The following files are used by this script and must reside in ${SRCDIR}
common.hosts${ht}${ht}Host header file - common for /etc/hosts on all HOSTS
make.HOST.lts.conf${ht}ed commands to patch master lts.conf to create
${ht}${ht}${ht}HOST specific lts.conf
make.HOST.dhcpd.conf${ht}ed commands to patch master dhcpd.conf to create
${ht}${ht}${ht}HOST specific dhcpd.conf
Processing for each HOST
/etc/hosts${ht}${ht}This file is built in the work directory as HOST.hosts.
${ht}${ht}${ht}The building of this file is a two stage process.
${ht}${ht}${ht}Firstly, the common.hosts file is copied to HOSTS.host,
${ht}${ht}${ht}with the following lines customised to reflect
${ht}${ht}${ht}the destination host:
${ht}${ht}${ht}127.0.0.1 HOSTNAME
${ht}${ht}${ht}HOST.IP.ADDR server.ltsp server
${ht}${ht}${ht}Secondly, the block of i/p address for the specified
${ht}${ht}${ht}host are extracted from the master hosts file
${ht}${ht}${ht}(/etc/hosts file on ${MASTER}) and appended to the newly
${ht}${ht}${ht}created hosts file.
/etc/dhcpd.conf${ht}${ht}This is built in the work directory as
HOST.dhcpd.conf.
${ht}${ht}${ht}The build is achieved using the patch command
${ht}${ht}${ht}to convert the master dhcpd.conf file
${ht}${ht}${ht}(/etc/dhcpd.conf file on ${MASTER}). For each specified
${ht}${ht}${ht}host a patch file must exist; said file is
${ht}${ht}${ht}make.HOST.dhcpd.conf, and forms part of the sync
${ht}${ht}${ht}suite. The patch file is created on install by
${ht}${ht}${ht}comparing the master and HOST dhcpd.conf files.
${ht}${ht}${ht}Use the Unix command diff -eb and redirect the output
${ht}${ht}${ht}into the 'make' file.
/opt/.../lts.conf${ht}This is built in the work directory as HOST.lts.conf.
${ht}${ht}${ht}The build is achieved using the patch command
${ht}${ht}${ht}to convert the master lts.conf file
${ht}${ht}${ht}(/opt/.../lts.conf file on ${MASTER}). For each specified
${ht}${ht}${ht}host a patch file must exist; said file is
${ht}${ht}${ht}make.HOST.lts.conf, and forms part of the sync
${ht}${ht}${ht}suite. The patch file is created on install by
${ht}${ht}${ht}comparing the master and HOST lts.conf files.
${ht}${ht}${ht}Use the Unix command diff -eb and redirect the output
${ht}${ht}${ht}into the 'make' file.
${ht}${ht}${ht}
EOF
exit 0
}
function test_host {
# validate files are in place for HOST
#
oops=0
TMP="${SRCDIR}/make."$1".lts.conf"
if [[ ! -f ${TMP} ]] ; then
oops=1
fi
TMP="${SRCDIR}/make."$1".dhcpd.conf"
if [[ ! -f ${TMP} ]] ; then
oops=1
fi
if (( $oops != 0 )) ; then
echo "Host: $1 cannot be processed"
fi
return $oops
}
function setup_master {
# copy all master records into work direcory
#
if [[ ! -f ${MHOSTS} ]] ; then
echo "Master hosts (${MHOSTS}) cannot be found"
return 1
fi
cp ${MHOSTS} ${MASTER}.hosts
if [[ ! -f ${MDHCPD} ]] ; then
echo "Master dhcpd.conf (${MDHCPD}) cannot be found"
return 1
fi
cp ${MDHCPD} ${MASTER}.dhcpd.conf
if [[ ! -f ${MLTSCONF} ]] ; then
echo "Master lts.conf (${MLTSCONF}) cannot be found"
return 1
fi
cp ${MLTSCONF} ${MASTER}.lts.conf
return 0
}
function build_hosts {
# build a host file for specific host
# input args - HOST=hostname to build
# output file HOST.hosts
#
awk -v HOST=$1 -v MASTER=${MASTER} -v SRCDIR=${SRCDIR} '
BEGIN {
# build common section
IFILE=SRCDIR "/common.hosts"
while (( getline < IFILE ) > 0) {
if ( $2 == HOST ) { IPADDR=$1 }
if ( $1 == "127.0.0.1" && $2 == "HOSTNAME" ) {
printf("%s\t%s", $1, HOST)
for (i = 3; i <= NF; i++) { printf("\t%s", $i) }
printf "\n"
}
else if ($2 == "server.ltsp" && $3 == "server") {
printf("%s", IPADDR)
for (i = 2; i <= NF; i++) { printf("\t%s", $i) }
printf "\n"
}
else print $0
}
# build host specific section
FLG=0
PATN="# MARKER " HOST
IFILE=MASTER ".hosts"
while (( getline < IFILE ) > 0) {
if ( $0 ~ PATN ) { FLG=1 }
else if ( $0 ~ "# MARKER" ) { FLG=0 }
if (FLG == 1) { print $0 }
}
}' > $1.hosts
}
function build_dhcpd.conf {
# build a dhcpd.conf file for specific host
# input args - HOST=hostname to build
# output file HOST.dhcpd.conf
#
cp ${MASTER}.dhcpd.conf $1.dhcpd.conf
patch -e $1.dhcpd.conf ${SRCDIR}/make.$1.dhcpd.conf
}
function build_lts.conf {
# build a lts.conf file for specific host
# input args - HOST=hostname to build
# output file HOST.lts.conf
#
cp ${MASTER}.lts.conf $1.lts.conf
patch -e $1.lts.conf ${SRCDIR}/make.$1.lts.conf
}
function get_orig_files {
# get original hosts, dhcpd.conf, lts.conf from specific host (not MASTER)
#
# build sftp script
rm -f ${WRKFILE} >/dev/null 2>&1
echo "get /etc/hosts $1.hosts.orig" >> ${WRKFILE}
echo "get /etc/dhcpd.conf $1.dhcpd.conf.orig" >> ${WRKFILE}
echo "get /opt/ltsp/i386/etc/lts.conf $1.lts.conf.orig" >> ${WRKFILE}
#build expect script (which calls sftp script)
rm -f ${WRKFIL1} >/dev/null 2>&1
echo "#!/bin/bash" >> ${WRKFIL1}
echo "expect -c 'spawn sftp -b ${WRKFILE} $1 ; \\" >> ${WRKFIL1}
echo "expect {" >> ${WRKFIL1}
echo " timeout { exit 1 }" >> ${WRKFIL1}
echo " eof { exit 0 }" >> ${WRKFIL1}
echo -n ' "Connect*root@*password" { send "' >> ${WRKFIL1}
echo -n "${ROOTPASS}\\" >> ${WRKFIL1}
echo 'r" }' >> ${WRKFIL1}
echo "} ; \\" >> ${WRKFIL1}
echo "expect \\" >> ${WRKFIL1}
echo "exit 2' >/dev/null 2>&1" >> ${WRKFIL1}
echo "if (( \$? != 0 )) ; then exit \$?; fi" >> ${WRKFIL1}
echo "if [[ ! -f $1.hosts.orig ]] ; then exit 3; fi" >> ${WRKFIL1}
echo "if [[ ! -f $1.dhcpd.conf.orig ]] ; then exit 3; fi" >> ${WRKFIL1}
echo "if [[ ! -f $1.lts.conf.orig ]] ; then exit 3; fi" >> ${WRKFIL1}
echo "exit 0" >> ${WRKFIL1}
chmod +x ${WRKFIL1}
$(${WRKFIL1})
oops=$?
rm -f ${WRKFILE} >/dev/null 2>&1
rm -f ${WRKFIL1} >/dev/null 2>&1
return $oops
}
function rpt_diffs {
# report any differences between constructed files and obtained (original)
files
#
diff -q $1.hosts.orig $1.hosts
if [[ $? != 0 ]] ; then
diff $1.hosts.orig $1.hosts
fi
diff -q $1.dhcpd.conf.orig $1.dhcpd.conf
if [[ $? != 0 ]] ; then
diff $1.dhcpd.conf.orig $1.dhcpd.conf
fi
diff -q $1.lts.conf.orig $1.lts.conf
if [[ $? != 0 ]] ; then
diff $1.lts.conf.orig $1.lts.conf
fi
}
function sync_files {
# put constructed hosts, dhcpd.conf, lts.conf to specific host (not MASTER)
#
echo "syncing files"
# build sftp script
rm -f ${WRKFILE} >/dev/null 2>&1
echo "put $1.hosts /etc/hosts" >> ${WRKFILE}
echo "put $1.dhcpd.conf /etc/dhcpd.conf" >> ${WRKFILE}
echo "put $1.lts.conf /opt/ltsp/i386/etc/lts.conf" >> ${WRKFILE}
#build expect script (which calls sftp script)
rm -f ${WRKFIL1} >/dev/null 2>&1
echo "#!/bin/bash" >> ${WRKFIL1}
echo "expect -c 'spawn sftp -b ${WRKFILE} $1 ; \\" >> ${WRKFIL1}
echo "expect {" >> ${WRKFIL1}
echo " timeout { exit 1 }" >> ${WRKFIL1}
echo " eof { exit 0 }" >> ${WRKFIL1}
echo -n ' "Connect*root@*password" { send "' >> ${WRKFIL1}
echo -n "${ROOTPASS}\\" >> ${WRKFIL1}
echo 'r" }' >> ${WRKFIL1}
echo "} ; \\" >> ${WRKFIL1}
echo "expect \\" >> ${WRKFIL1}
echo "exit 2' >/dev/null 2>&1" >> ${WRKFIL1}
echo "if (( \$? != 0 )) ; then exit \$?; fi" >> ${WRKFIL1}
echo "exit 0" >> ${WRKFIL1}
chmod +x ${WRKFIL1}
$(${WRKFIL1})
oops=$?
rm -f ${WRKFILE} >/dev/null 2>&1
rm -f ${WRKFIL1} >/dev/null 2>&1
return $oops
}
function restart_dhcpd {
# restart the dhcpd service on a specific host (not MASTER)
#
echo "restarting dhcpd"
#build expect script
rm -f ${WRKFIL1} >/dev/null 2>&1
echo "#!/bin/bash" >> ${WRKFIL1}
echo "expect -c 'eval spawn ssh $1 service dhcpd restart ; \\" >> ${WRKFIL1}
echo "expect {" >> ${WRKFIL1}
echo " timeout { exit 1 }" >> ${WRKFIL1}
echo " eof { exit 0 }" >> ${WRKFIL1}
echo -n ' "root@*password" { send "' >> ${WRKFIL1}
echo -n "${ROOTPASS}\\" >> ${WRKFIL1}
echo 'r" }' >> ${WRKFIL1}
echo "} ; \\" >> ${WRKFIL1}
echo "expect \\" >> ${WRKFIL1}
echo "exit 2'" >> ${WRKFIL1}
echo "if (( \$? != 0 )) ; then exit \$?; fi" >> ${WRKFIL1}
echo "exit 0" >> ${WRKFIL1}
chmod +x ${WRKFIL1}
$(${WRKFIL1})
oops=$?
echo ">>>$oops<<<"
##rm -f ${WRKFIL1} >/dev/null 2>&1
return $oops
}
# mainline
TMP=$(hostname)
if [[ ${TMP} != "${MASTER}" ]] ; then
echo "${PROG} must only be run on host '${MASTER}'"
print_usage
fi
if [[ ! -d ${SRCDIR} ]] ; then
echo "${PROG}: ${SRCDIR}: No such file or directory"
print_usage
fi
if [[ ! -d ${WRKDIR} ]] ; then
echo "${PROG}: ${WRKDIR}: No such file or directory"
print_usage
fi
# validate runtime options
SYNC=0 # dont sync by default
while getopts ":sv" OPT ; do
case $OPT in
s) SYNC=1 ;;
v) print_vers ;;
*) print_usage ;;
esac
done
shift $(($OPTIND - 1))
if [[ -z $* ]] ; then # no hosts entered
print_usage
fi
cd ${WRKDIR} # change to work directory
setup_master # copy master files into work
if (( $? != 0 )) ; then
print_usage
fi
for HOST in "$@" ; do # process each host
echo
echo "Processing host = $HOST"
test_host ${HOST}
if (( $? != 0 )) ; then
continue
fi
build_hosts ${HOST}
build_dhcpd.conf ${HOST}
build_lts.conf ${HOST}
get_orig_files ${HOST}
oops=$?
if (( $oops != 0 )) ; then
echo "Error: non-zero return code get_orig_files ($oops)"
continue
fi
rpt_diffs ${HOST}
if (( ${SYNC} )) ; then
sync_files ${HOST}
oops=$?
if (( $oops != 0 )) ; then
echo "Error: non-zero return code sync_files ($oops)"
continue
fi
restart_dhcpd ${HOST}
oops=$?
if (( $oops != 0 )) ; then
## echo "Error: non-zero return code restart_dhcpd ($oops)"
continue
fi
fi
done
exit 0
-- end cut --
this script requires two files per host, eg
make.bart.dhcpd.conf
-- start cut --
39c
option log-servers 10.121.128.4;
.
24c
option log-servers 10.121.128.4;
.
18c
-- end cut --
make.bart.lts.conf
-- start cut --
8c
SERVER = 10.121.128.4
.
-- end cut --
these files are made with diff
any probs that this script causes is nothing to do with me, ie YMMV
--
Regards
Martin Woolley
ICT Support
Handsworth Grammar School
Isis Astarte Diana Hecate Demeter Kali Inanna
*************************************************************
This email and any files transmitted with it are confidential
and intended solely for the use of the individual or entity
to whom they are addressed. If you have received this email
in error please notify postmaster at bgfl.org
The views expressed within this email are those of the
individual, and not necessarily those of the organisation
*************************************************************
More information about the K12OSN
mailing list