#!/bin/bash # Copyright (C) 2003 Enrico Scholz # based on vserver-copy by Mark Lawrence # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Copy/Sync a virtual host from one machine to another # # History: # # 2003-04-04: Version 0.4 - Mark lawrence # - Set "ONBOOT=no" in the destination .conf file when --startstop # is not used, in case the destination roothost reboots. We don't # want two copies of a vserver running at the same time. # # 2003-03-04: Version 0.3 - Mark lawrence # - Changed all checks for [ "" != "$var" ] into [ -n|-z "$var" ]. "" doesn't # seem to work for bash on the Sparc architecture. # - Changed $ssh variable into $shcmd. # # 2003-02-23: Version 0.2 - Mark Lawrence # - Set ONBOOT to "no" in the original .conf file when the "-s" flag is # used so that if/when you reboot the source roothost you don't have the # same vserver and IP address running on two machines. : ${UTIL_VSERVER_VARS:=/usr/lib/util-vserver/util-vserver-vars} test -e "$UTIL_VSERVER_VARS" || { echo $"Can not find util-vserver installation (the file '$UTIL_VSERVER_VARS' would be expected); aborting..." >&2 exit 1 } . "$UTIL_VSERVER_VARS" VERSION="0.4" umask 022 me=${0##*/} ### Helper functions ### # Save stdin and stdout for later use exec 3>&1 exec 4>&2 noninteractive () { exec &> /dev/null } interactive () { exec 1>&3 exec 2>&4 } info () { ! $quiet && echo "I: $me: $1" >&3 } warn () { ! $quiet && echo "W: $me: $1" >&4 } error () { ! $quiet && echo "E: $me: $2" >&4 exit $1 } ### Usage/Info functions ### usage () { cat <&2 Usage: $me [-hVvqidrRs] vserver newname $me [-hVvqidrRs] vserver host:[newname] EOF } full_usage () { usage cat < This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. EOF } ### Default values and Command line options ### stopstart=(false) verbose=(false) quiet=(false) shcmd="ssh" rsflag="-e" rsh=(false) colon=":" domain="" ip="" vsroot=$__DEFAULT_VSERVERDIR if [ $# -eq 0 ]; then # Script invoked with no command-line args? usage exit 1 fi temp=$(getopt -o hVvqd:i:rRs --long help,version,verbose,quiet,domain:,ip:,vsroot,rsh,stopstart, -n $me -- "$@") if [ $? -ne 0 ]; then echo " (See -h for help)" exit 1 fi # Note the quotes around `$temp': they are essential! eval set -- "$temp" while true; do case "$1" in -h|--help) full_usage exit 1 ;; -V|--version) full_version exit 1 ;; -v|--verbose) verbose=(true) shift ;; -q|--quiet) quiet=(true) shift ;; -d|--domain) domain="$2" shift 2 ;; -i|--ip) ip="$2" shift 2 ;; -r|--vsroot) vsroot="$2" shift 2 ;; -R|--rsh) rsh=(true) shift ;; -s|--stopstart) stopstart=(true) shift ;; --) shift break ;; *) echo "Internal error!" exit 1 ;; esac done if [ $# -ne 2 ]; then usage exit 1 fi ### ### # By default we are reasonably quiet (ouput only via info, warn & error) if $verbose; then interactive else noninteractive fi now=$(date) info "called on $(hostname) at $now" vserver=$1 vconf=/etc/vservers/$vserver.conf vroot=$vsroot/$vserver if $rsh; then shcmd="rsh" fi if (echo $2 | grep '^[a-z][a-z0-9]\+$'); then dhost="" newname=$2 shcmd="" rsflag="" colon="" if $rsh; then warn "rsh is set but not used for a local copy" fi elif (echo $2 | grep '^[a-z].*[a-z0-9]:$'); then dhost=${2/:/} newname=$vserver elif (echo $2 | grep '^[a-z].*[a-z0-9]:[a-z].*[a-z0-9]$'); then dhost=${2/:*/} newname=${2/*:/} else error 1 "Second argument must be of the form \"[host:]name\" or \"host:\"" fi target=$vsroot/$newname targetconf=/etc/vservers/$newname.conf ### Perform some sanity checks ### if [ ! -d $vroot ]; then error 1 "Directory \"$vroot\" does not exist" fi if [ ! -e $vconf ]; then error 1 "Vserver file \"$vconf\" does not exist" fi if [ -z "$dhost" ] && [ "$vserver" == "$newname" ]; then error 1 "Source and destination names cannot be the same on the localhost" fi if [ -n "$dhost" ] && ! (host $dhost | grep 'has address'); then warn "$dhost does not resolve into an IP address" fi if [ \( -n "$ip" -a -z "$domain" \) -o \ \( -z "$ip" -a -n "$domain" \) ] then error 1 "Both IP address and domain must be specified together" fi if [ -n "$ip" ] && \ ! (echo $ip | grep '^[0-9]\{1,3\}\(\.[0-9]\{1,3\}\)\{3\}$' ); then error 1 "\"$ip\" is not a valid IP address" fi # This works both locally and remote if ($shcmd $dhost $__SBINDIR/vserver $newname running | grep 'is running'); then warn "destination vserver \"$newname\" is running" error 1 "Cannot copy over a running vserver" fi ### Do the copy ### info "Attempting to copy $vserver to $dhost$colon$newname" if $stopstart; then info "Stopping virtual server \"$vserver\" on localhost" $__SBINDIR/vserver $vserver stop fi info "Syncing directories" # trailing slashes very important in the rsync! if ! rsync -Havxz --numeric-ids $rsflag $shcmd $vroot/ $dhost$colon$target/; then error 1 "rsync failed" fi if [ -n "$ip" -a -n "$domain" ]; then # Insert the new IPROOT/S_HOSTNAME values into the config file info "Modifying $targetconf" tmpf=$(tempfile) if (sed -e "s/^S_HOSTNAME=.*/S_HOSTNAME=\"$newname\"/" \ -e "s/^IPROOT=.*/IPROOT=\"$ip\"/" $vconf > $tmpf) then if ! rsync -v $rsflag $shcmd $tmpf $dhost$colon$targetconf; then error $? "vserver config file copy/change failed" fi else warn "Unable to reconfigure virtual server config file" fi # create a new /etc/hostname info "Creating hostname file" echo $newname > $tmpf if ! rsync -v $rsflag $shcmd $tmpf $dhost$colon$target/etc/hostname; then error 1 "vserver /etc/hostname copy failed" fi info "Creating /etc/hosts" cat << EOF > $tmpf # /etc/hosts (automatically generated by $me) 127.0.0.1 localhost $ip $newname.$domain $newname # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters ff02::3 ip6-allhosts EOF # copy /etc/hosts if ! rsync -v $rsflag $shcmd $tmpf $dhost$colon$target/etc/hosts; then error 1 "vserver /etc/hosts copy failed" fi rm -f $tmpf else if ! $stopstart; then # Make sure that this vserver doesn't start on the # destination host if it reboots tmpf=$(tempfile) sed -e 's/^ONBOOT=.*/ONBOOT=no/' $vconf > $tmpf vconf=$tmpf fi # copy newname.conf unchanged info "Copying $targetconf" if ! rsync -v $rsflag $shcmd $vconf $dhost$colon$targetconf; then error 1 "vserver config file copy/change failed" fi rm -f $tmpf fi if $stopstart; then info "Starting virtual server \"$vserver\" on $dhost" $shcmd $dhost $__SBINDIR/vserver $vserver start if ($shcmd $dhost $__SBINDIR/vserver $vserver running | \ grep 'not running'); then error 1 "Virtual server \"$vserver\" failed to start on $dhost" fi # Make sure that we don't start the original on next boot tmpf=$(tempfile) sed -e 's/^ONBOOT=.*/ONBOOT=no/' $vconf > $tmpf mv $tmpf $vconf fi exit 0