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