[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