vshost-util-vserver

Build script and sources for util-vserver.
git clone https://ccx.te2000.cz/git/vshost-util-vserver
Log | Files | Refs

vserver-copy (9116B)


      1 #!/bin/bash
      2 
      3 # Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
      4 # based on vserver-copy by Mark Lawrence <nomad@null.net>
      5 #  
      6 # This program is free software; you can redistribute it and/or modify
      7 # it under the terms of the GNU General Public License as published by
      8 # the Free Software Foundation; either version 2, or (at your option)
      9 # any later version.
     10 #  
     11 # This program is distributed in the hope that it will be useful,
     12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 # GNU General Public License for more details.
     15 #  
     16 # You should have received a copy of the GNU General Public License
     17 # along with this program; if not, write to the Free Software
     18 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     19 
     20 # Copy/Sync a virtual host from one machine to another
     21 #
     22 # History:
     23 #
     24 # 2003-04-04: Version 0.4 - Mark lawrence
     25 # - Set "ONBOOT=no" in the destination .conf file when --startstop
     26 #   is not used, in case the destination roothost reboots. We don't
     27 #   want two copies of a vserver running at the same time.
     28 #
     29 # 2003-03-04: Version 0.3 - Mark lawrence
     30 # - Changed all checks for [ "" != "$var" ] into [ -n|-z "$var" ]. "" doesn't
     31 #   seem to work for bash on the Sparc architecture.
     32 # - Changed $ssh variable into $shcmd.
     33 #
     34 # 2003-02-23: Version 0.2 - Mark Lawrence
     35 # - Set ONBOOT to "no" in the original .conf file when the "-s" flag is 
     36 #   used so that if/when you reboot the source roothost you don't have the
     37 #   same vserver and IP address running on two machines.
     38 
     39 : ${UTIL_VSERVER_VARS:=/usr/lib/util-vserver/util-vserver-vars}
     40 test -e "$UTIL_VSERVER_VARS" || {
     41     echo $"Can not find util-vserver installation (the file '$UTIL_VSERVER_VARS' would be expected); aborting..." >&2
     42     exit 1
     43 }
     44 . "$UTIL_VSERVER_VARS"
     45 
     46 VERSION="0.4"
     47 umask 022
     48 me=${0##*/}
     49 
     50 
     51 ### Helper functions ###
     52 
     53 # Save stdin and stdout for later use
     54 exec 3>&1
     55 exec 4>&2
     56 
     57 noninteractive () {
     58 	exec &> /dev/null
     59 }
     60 
     61 interactive () {
     62 	exec 1>&3
     63 	exec 2>&4
     64 }
     65 
     66 info () {
     67 	! $quiet && echo "I: $me: $1" >&3
     68 }
     69 
     70 warn () {
     71 	! $quiet && echo "W: $me: $1" >&4
     72 }
     73 
     74 error () {
     75 	! $quiet && echo "E: $me: $2" >&4
     76 	exit $1
     77 }
     78 
     79 
     80 ### Usage/Info functions ###
     81 
     82 usage () {
     83     cat <<EOF 1>&2
     84 Usage:	$me [-hVvqidrRs] vserver newname
     85 	$me [-hVvqidrRs] vserver host:[newname]
     86 EOF
     87 }
     88 
     89 full_usage () {
     90 	usage
     91         cat <<EOF
     92 
     93 $me uses rsync to make a copy of a vserver. If the destination
     94 name contains a host specification the vserver will be synchronised to
     95 the remote destination over ssh/rsh.
     96 
     97 This can be used on a running vserver to make a warm backup. With the -s
     98 flag a vserver can even be operationally moved to different hardware within
     99 seconds.
    100 
    101 The -i and -d flags can be used to minimally reconfigure the destination
    102 vserver (rewrites /etc/vservers/newname.conf and $__DEFAULT_VSERVERDIR/newname/etc/hosts)
    103 
    104 Options:
    105 	-h, --help		this help
    106 	-V, --version		copyright and version information
    107 	-v, --verbose		show all output
    108 	-q, --quiet		direct all output to /dev/null (no password
    109 				prompt for logins on remote hosts!)
    110 	-d, --domain [string]	new dns domain (must be used with -i)
    111 	-i, --ip [addr]		new IP address (must be used with -d)
    112 	-r, --vsroot		location of "/vserver/" directory
    113 	-R, --rsh		use rsh (instead of default ssh) for
    114 				network transport
    115 	-s, --stopstart		stop the local vserver before copying and start
    116 				it on the destination host afterwards
    117 
    118 EOF
    119 }
    120 
    121 full_version () {
    122     cat <<EOF
    123 $me version $VERSION
    124 Copyright (c) 2002 Mark Lawrence   <nomad@null.net>
    125 
    126 This program is free software; you can redistribute it and/or modify
    127 it under the terms of the GNU General Public License as published by
    128 the Free Software Foundation; either version 2 of the License, or (at
    129 your option) any later version.
    130 
    131 EOF
    132 }
    133 
    134 
    135 ### Default values and Command line options ###
    136 
    137 stopstart=(false)
    138 verbose=(false)
    139 quiet=(false)
    140 shcmd="ssh"
    141 rsflag="-e"
    142 rsh=(false)
    143 colon=":"
    144 domain=""
    145 ip=""
    146 vsroot=$__DEFAULT_VSERVERDIR
    147 
    148 if [ $# -eq 0 ]; then  # Script invoked with no command-line args?
    149 	usage
    150 	exit 1
    151 fi  
    152 
    153 temp=$(getopt -o hVvqd:i:rRs --long help,version,verbose,quiet,domain:,ip:,vsroot,rsh,stopstart, -n $me -- "$@")
    154 
    155 if [ $? -ne 0 ]; then
    156 	echo "	(See -h for help)"
    157         exit 1
    158 fi
    159 
    160 # Note the quotes around `$temp': they are essential!
    161 eval set -- "$temp"
    162 
    163 while true; do
    164         case "$1" in
    165 		-h|--help)	full_usage
    166 				exit 1
    167 				;;
    168 		-V|--version)	full_version
    169 				exit 1
    170 				;;
    171 		-v|--verbose)	verbose=(true)
    172 				shift
    173 				;;
    174 		-q|--quiet)	quiet=(true)
    175 				shift
    176 				;;
    177 		-d|--domain)	domain="$2"
    178 				shift 2
    179 				;;
    180 		-i|--ip)	ip="$2"
    181 				shift 2
    182 				;;
    183 		-r|--vsroot)	vsroot="$2"
    184 				shift 2
    185 				;;
    186 		-R|--rsh)	rsh=(true)
    187 				shift
    188 				;;
    189 		-s|--stopstart)	stopstart=(true)
    190 				shift
    191 				;;
    192                 --)             shift
    193 				break
    194 				;;
    195 		*)		echo "Internal error!"
    196 				exit 1
    197 				;;
    198 	esac
    199 done
    200 
    201 if [ $# -ne 2 ]; then
    202 	usage
    203 	exit 1
    204 fi
    205 
    206 
    207 ### ###
    208 
    209 # By default we are reasonably quiet (ouput only via info, warn & error)
    210 if $verbose; then
    211 	interactive
    212 else
    213 	noninteractive
    214 fi
    215 
    216 now=$(date)
    217 info "called on $(hostname) at $now"
    218 
    219 
    220 vserver=$1
    221 vconf=/etc/vservers/$vserver.conf
    222 vroot=$vsroot/$vserver
    223 
    224 if $rsh; then
    225 	shcmd="rsh"
    226 fi
    227 
    228 if (echo $2 | grep '^[a-z][a-z0-9]\+$'); then
    229 	dhost=""
    230 	newname=$2
    231 	shcmd=""
    232 	rsflag=""
    233 	colon=""
    234 	if $rsh; then
    235 		warn "rsh is set but not used for a local copy"
    236 	fi
    237 elif (echo $2 | grep '^[a-z].*[a-z0-9]:$'); then
    238 	dhost=${2/:/}
    239 	newname=$vserver
    240 elif (echo $2 | grep '^[a-z].*[a-z0-9]:[a-z].*[a-z0-9]$'); then
    241 	dhost=${2/:*/}
    242 	newname=${2/*:/}
    243 else
    244 	error 1 "Second argument must be of the form \"[host:]name\" or \"host:\""
    245 fi
    246 
    247 target=$vsroot/$newname
    248 targetconf=/etc/vservers/$newname.conf
    249 
    250 
    251 ### Perform some sanity checks ###
    252 
    253 if [ ! -d $vroot ]; then
    254 	error 1 "Directory \"$vroot\" does not exist"
    255 fi
    256 
    257 if [ ! -e $vconf ]; then
    258 	error 1 "Vserver file \"$vconf\" does not exist"
    259 fi
    260 
    261 if [ -z "$dhost" ] && [ "$vserver" == "$newname" ]; then
    262 	error 1 "Source and destination names cannot be the same on the localhost"
    263 fi
    264 
    265 if [ -n "$dhost" ] && ! (host $dhost | grep 'has address'); then
    266 	warn "$dhost does not resolve into an IP address"
    267 fi
    268 
    269 if [ \( -n "$ip" -a -z "$domain" \) -o \
    270      \( -z "$ip" -a -n "$domain" \) ]
    271 then
    272 	error 1 "Both IP address and domain must be specified together"
    273 fi
    274 
    275 if [ -n "$ip" ] && \
    276 ! (echo $ip | grep '^[0-9]\{1,3\}\(\.[0-9]\{1,3\}\)\{3\}$' ); then
    277 	error 1 "\"$ip\" is not a valid IP address"
    278 fi
    279 
    280 # This works both locally and remote
    281 if ($shcmd $dhost $__SBINDIR/vserver $newname running | grep 'is running'); then
    282 	warn "destination vserver \"$newname\" is running" 
    283 	error 1 "Cannot copy over a running vserver"
    284 fi
    285 
    286 
    287 ### Do the copy ###
    288 
    289 info "Attempting to copy $vserver to $dhost$colon$newname"
    290 
    291 if $stopstart; then
    292 	info "Stopping virtual server \"$vserver\" on localhost"
    293 	$__SBINDIR/vserver $vserver stop
    294 fi
    295 
    296 info "Syncing directories"
    297 # trailing slashes very important in the rsync!
    298 if ! rsync -Havxz --numeric-ids $rsflag $shcmd $vroot/ $dhost$colon$target/; then
    299 	error 1 "rsync failed"
    300 fi
    301 
    302 if [ -n "$ip" -a -n "$domain" ]; then
    303 	# Insert the new IPROOT/S_HOSTNAME values into the config file
    304 	info "Modifying $targetconf"
    305 	tmpf=$(tempfile)
    306 	if (sed -e "s/^S_HOSTNAME=.*/S_HOSTNAME=\"$newname\"/" \
    307 		-e "s/^IPROOT=.*/IPROOT=\"$ip\"/" $vconf > $tmpf)
    308 	then
    309 		if ! rsync -v $rsflag $shcmd $tmpf $dhost$colon$targetconf; then
    310 			error $? "vserver config file copy/change failed"
    311 		fi
    312 
    313 	else
    314 		warn "Unable to reconfigure virtual server config file"
    315 	fi
    316 
    317 	# create a new /etc/hostname
    318 	info "Creating hostname file"
    319 	echo $newname > $tmpf
    320 	if ! rsync -v $rsflag $shcmd $tmpf $dhost$colon$target/etc/hostname; then
    321 		error 1 "vserver /etc/hostname copy failed"
    322 	fi
    323 
    324 	info "Creating /etc/hosts"
    325 	cat << EOF > $tmpf
    326 # /etc/hosts (automatically generated by $me)
    327 
    328 127.0.0.1       localhost
    329 $ip	$newname.$domain	$newname
    330 
    331 # The following lines are desirable for IPv6 capable hosts
    332 
    333 ::1     ip6-localhost ip6-loopback
    334 fe00::0 ip6-localnet
    335 ff00::0 ip6-mcastprefix
    336 ff02::1 ip6-allnodes
    337 ff02::2 ip6-allrouters
    338 ff02::3 ip6-allhosts
    339 EOF
    340 
    341 	# copy /etc/hosts
    342 	if ! rsync -v $rsflag $shcmd $tmpf $dhost$colon$target/etc/hosts; then
    343 		error 1 "vserver /etc/hosts copy failed"
    344 	fi
    345 	rm -f $tmpf
    346 
    347 else
    348 	if ! $stopstart; then
    349 		# Make sure that this vserver doesn't start on the 
    350 		# destination host if it reboots
    351 		tmpf=$(tempfile)
    352 		sed -e 's/^ONBOOT=.*/ONBOOT=no/' $vconf > $tmpf
    353 		vconf=$tmpf
    354 	fi
    355 
    356 	# copy newname.conf unchanged
    357 	info "Copying $targetconf"
    358 	if ! rsync -v $rsflag $shcmd $vconf $dhost$colon$targetconf; then
    359 		error 1 "vserver config file copy/change failed"
    360 	fi
    361 
    362 	rm -f $tmpf
    363 fi
    364 
    365 
    366 if $stopstart; then
    367 	info "Starting virtual server \"$vserver\" on $dhost"
    368 	$shcmd $dhost $__SBINDIR/vserver $vserver start
    369 	if ($shcmd $dhost $__SBINDIR/vserver $vserver running | \
    370 	grep 'not running'); then
    371 		error 1 "Virtual server \"$vserver\" failed to start on $dhost"
    372 	fi
    373 
    374 	# Make sure that we don't start the original on next boot
    375 	tmpf=$(tempfile)
    376 	sed -e 's/^ONBOOT=.*/ONBOOT=no/' $vconf > $tmpf
    377 	mv $tmpf $vconf
    378 fi
    379 
    380 exit 0