X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=virt-p2v.sh;h=274b087fc04ea6740db6e948b5ab8291aae75327;hb=3f6e98377d6789442c27e7427094235d2f76a6bd;hp=92b840fcc43a8b9f482ea97b4799da12b757da0f;hpb=ec30750022c2f6cb15a88606d1c85d0d3205ea61;p=virt-p2v.git diff --git a/virt-p2v.sh b/virt-p2v.sh index 92b840f..274b087 100755 --- a/virt-p2v.sh +++ b/virt-p2v.sh @@ -6,6 +6,20 @@ # Copyright (C) 2007 Red Hat Inc. # Written by Richard W.M. Jones # +# 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. +# +# 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 +# # $Id$ export PATH=/usr/sbin:/sbin:/usr/local/bin:/usr/kerberos/bin:/usr/bin:/bin @@ -28,13 +42,20 @@ override_remote_transport= # (only if override_remote_transport is 'ssh') override_remote_directory= -# list of devices to send, separated by spaces, if empty ask user +# list of local physical devices to send, separated by spaces, +# if empty ask user. # this is usually a list of whole disk devices (eg. "sda") override_devices_to_send="" -# list of root filesystems to examine (eg. "sda3" or +# the root filesystem containing /etc/fstab (eg. "sda3" or # "VolGroup00/LogVol00") -override_root_filesystems="" +override_root_filesystem="" + +# network configuration +# - if empty, ask user +# - "auto" means try to autoconfigure from root filesystem +# (XXX needs to contain more ways to override in future) +override_network="" #---------------------------------------------------------------------- # Logging. @@ -70,25 +91,44 @@ function word_in_list { } #---------------------------------------------------------------------- +# I/O functions + +# Use the function read_line instead of the shell built-in read. +# It reads from the console. +function read_line { + read "$*" /dev/console 2>&1 +} + +#---------------------------------------------------------------------- # Device mapper snapshotting. +next_ramdisk=1 + # Create a device-mapper snapshot of a device with ramdisk overlay. # Example: # snapshot sda1 snap # creates a snapshot of /dev/sda1 called /dev/mapper/snap - - -# XXX Error checking. function snapshot { local dev=$1 name=$2 + # Next free ramdisk (/dev/ram$i) + local i=$next_ramdisk + next_ramdisk=$(($next_ramdisk+1)) + # Get size of the device in sectors. local sectors=`blockdev --getsize /dev/$dev` dmsetup create ${name}_org \ --table="0 $sectors snapshot-origin /dev/$dev" + if [ $? -ne 0 ]; then exit 1; fi dmsetup create $name \ - --table="0 $sectors snapshot /dev/mapper/${name}_org /dev/ram1 n 64" + --table="0 $sectors snapshot /dev/mapper/${name}_org /dev/ram$i n 64" + if [ $? -ne 0 ]; then exit 1; fi } # Drop an existing snapshot created by snapshot function. @@ -96,6 +136,8 @@ function snapshot { # drop_snapshot snap # drops a snapshot called /dev/mapper/snap function drop_snapshot { + local name=$1 + dmsetup remove /dev/mapper/$name dmsetup remove /dev/mapper/${name}_org } @@ -206,6 +248,55 @@ function search_parts { } #---------------------------------------------------------------------- +# Network configuration functions. + +# `auto_network' tries to configure the network from the +# root filesystem. Returns true or false. +function auto_network { + # Make sure this file exists, otherwise Fedora gives a warning. + touch /etc/resolv.conf + + pushd /etc/sysconfig + + mv network network.saved + mv networking networking.saved + mv network-scripts network-scripts.saved + + # Originally I symlinked these, but that causes dhclient to + # keep open /mnt/root (as its cwd is in network-scripts subdir). + # So now we will copy them recursively instead. + cp -r /mnt/root/etc/sysconfig/network . + cp -r /mnt/root/etc/sysconfig/networking . + cp -r /mnt/root/etc/sysconfig/network-scripts . + + /etc/init.d/network start + local status=$? + + rm -rf network networking network-scripts + mv network.saved network + mv networking.saved networking + mv network-scripts.saved network-scripts + + popd + + ping -c 3 $remote_host + + if [ "$greeting" != "no" ]; then + echo "Did automatic network configuration work?" + echo "(Hint: if not sure, there is a shell on console [ALT] [F2])" + echo -n " (y/n) " + local line + read_line line line if [ $? -eq 3 ]; then state=directory else devices_to_send=`cat line` - state=roots - log user selected devices_to_send = $devices_to_send + state=root fi fi ;; - roots) - if [ -n "$override_root_filesystems" ]; then - root_filesystems="$override_root_filesystems" - state=verify + + # Root filesystem. + root) + if [ -n "$override_root_filesystem" ]; then + root_filesystem="$override_root_filesystem" + state=network else # Returns the list of possible partitions / LVs in $parts search_parts $devices_to_send - log filesystems returned by search_parts: $parts + log partitions returned by search_parts: $parts - if [ -z "$parts" ]; then - root_filesystems="" - state=verify - else - partslist="" - for r in $parts; do - if word_in_list $r $root_filesystems; then - stat=on - else - stat=off - fi - partslist="$partslist $r /dev/$r $stat" - done - - dialog \ - --extra-button --extra-label "Back" --nocancel \ - --single-quoted \ - --checklist "Pick partition(s) containing root (/) filesystem" 10 70 5 \ - $partslist \ - 2> line - if [ $? -eq 3 ]; then state=devices + partslist="" + for r in $parts; do + if word_in_list $r $root_filesystem; then + stat=on else - root_filesystems=`cat line` - state=verify - log user selected root_filesystems = $root_filesystems + stat=off fi + partslist="$partslist $r /dev/$r $stat" + done + + dialog \ + --extra-button --extra-label "Back" --nocancel \ + --single-quoted \ + --radiolist "Pick partition containing the root (/) filesystem" 10 70 5 \ + $partslist \ + 2> line + if [ $? -eq 3 ]; then state=devices + else + root_filesystem=`cat line` + state=network fi fi ;; + + # Network configuration. + network) + if [ -n "$override_network" ]; then + network="$override_network" + state=verify + else + dialog \ + --extra-button --extra-label "Back" --nocancel \ + --radiolist "Network configuration" 10 70 5 \ + "auto" "Auto-configure from root filesystem" on \ + "ask" "Manual configuration" off \ + "sh" "Configure from the shell" off \ + 2> line + if [ $? -eq 3 ]; then state=root + else + network=`cat line` + state=verify + fi + fi + ;; + + # Verify configuration. verify) if [ "$greeting" = "no" ]; then state=exit else dialog \ --title "Summary" \ - --yesno "Transport: $remote_transport\nRemote host: $remote_host\nRemote port: $remote_port\nRemote directory (ssh only): $remote_directory\nDisks to send: $devices\nRoot filesystem(s): $root_filesystems\n\nProceed with these settings?" \ - 23 70 + --yesno "Transport: $remote_transport\nRemote host: $remote_host\nRemote port: $remote_port\nRemote directory (ssh only): $remote_directory\nDisks to send: $devices_to_send\nRoot filesystem: $root_filesystem\nNetwork configuration: $network\n\nProceed with these settings?" \ + 18 70 if [ $? -eq 1 ]; then state=transport else @@ -406,16 +518,148 @@ done clear -# Mount the root filesystem(s) using device-mapper snapshots. -# For example, if asked to examine VolGroup00/LogVol00, then -# we might find that it is located on physical device sda, and -# the snapshot in that case will be called sda_snap. +#---------------------------------------------------------------------- +# De-activate all volume groups and switch to new dm-only LVM config. +log deactivating volume groups + +vgchange -a n +mv /etc/lvm/lvm.conf /etc/lvm/lvm.conf.old +mv /etc/lvm/lvm.conf.new /etc/lvm/lvm.conf +rm -f /etc/lvm/cache/.cache + +# Snapshot the block devices. +for d in $devices_to_send; do + log snapshotting block device /dev/$d ... + + snapshot $d snap_$d + + # The block devices are whole disks. Use kpartx to repartition them. + log running kpartx -a /dev/mapper/snap_$d ... + kpartx -a /dev/mapper/snap_$d +done +# Rescan for LVs. +log running vgscan +vgscan +vgchange -a y +# Mount the root filesystem on /mnt/root. If it's a physical +# device then we want to mount (eg) /dev/mapper/snap_sda2. +# If it's a LVM device then we can just mount the LVM partition. +log mount $root_filesystem as /mnt/root + +if [ -f /dev/mapper/snap_$root_filesystem ]; then + mount /dev/mapper/snap_$root_filesystem /mnt/root +else + mount /dev/$root_filesystem /mnt/root +fi + +#---------------------------------------------------------------------- +# Now see if we can get a network configuration. +log network configuration $network + +case "$network" in + sh) + echo "Network configuration" + echo + echo "Please configure the network from this shell." + echo + echo "When finished, exit with ^D or exit" + echo + shell + ;; + + ask) + # XXX Not implemented + echo "Sorry, we didn't implement this one yet." + shell + ;; + + auto) + echo "Trying to auto-configure network from root filesystem ..." + echo + if ! auto_network; then + echo "Auto-configuration failed. Starting a shell." + echo + shell + fi +esac + +#---------------------------------------------------------------------- +# Rewrite /mnt/root/etc/fstab + +log rewriting /etc/fstab + +cp /mnt/root/etc/fstab /mnt/root/etc/fstab.p2vsaved +while read dev mountpoint fstype options freq passno; do + # If device is /dev/sd* then on the target fullvirt machine + # it will be /dev/sd* + if matches_regexp "^/dev/sd[[:alpha:]]+[[:digit:]]+$" "$dev"; then + dev=`echo $dev | sed 's|^/dev/sd|/dev/hd|'` + fi + # Print out again with all the fields nicely lined up. + printf "%-23s %-23s %-7s %-15s %d %d\n" \ + "$dev" "$mountpoint" "$fstype" "$options" "$freq" "$passno" +done < /mnt/root/etc/fstab.p2vsaved > /mnt/root/etc/fstab +#---------------------------------------------------------------------- +# XXX Look for other files which might need to be changed here ... + + + +# We've now finished with /mnt/root (the real root filesystem), +# so unmount it and synch everything. +umount /mnt/root +sync + +#---------------------------------------------------------------------- +# Send the device snapshots (underlying device + changes in ramdisk) +# to the remote server. + +log sending disks + +# XXX Effectively this is using the hostname derived from network +# configuration, but we might want to ask the user instead. +# XXX How do we ensure that we won't overwrite target files? Currently +# tries to use the current date as a uniquifier. + +# Names will be something like +# p2v-oirase-200709011249-hda.img +basename=p2v-`hostname -s|tr -cd '[0-9a-zA-Z]'`-`date +'%Y%m%d%H%M'` + +for dev in $devices_to_send; do + rdev=`echo $dev | sed 's|^sd|hd|'` + name="$basename-$rdev.img" + log sending $dev to $name + + sectors=`blockdev --getsize /dev/mapper/snap_$dev` + + gigs=$(($sectors/2/1024/1024)) + echo "Sending /dev/$dev (${gigs} GB) to remote machine" + + dd if=/dev/mapper/snap_$dev | + case "$remote_transport" in + ssh) + ssh -p "$remote_port" "$remote_host" \ + "cat > $remote_directory/$name" + ;; + tcp) + echo "p2v $name $sectors" > header + cat header - | nc "$remote_host" "$remote_port" + ;; + esac +done + + +#---------------------------------------------------------------------- +# Clean up. +#for d in $devices_to_send; do +# kpartx -d /dev/mapper/snap_$d +# drop_snapshot snap_$d +#done # This file must end with a newline