#----------------------------------------------------------------------
# General configuration
-VERSION := 0.1
+PACKAGE := virt-p2v
+VERSION := 0.2
# i386 images also work on x86-64, so best to stick with i386.
ARCH := i386
export http_proxy := http://127.0.0.1:3128/
export ftp_proxy := http://127.0.0.1:3128/
-LABEL := virt-p2v-$(VERSION)
+LABEL := $(PACKAGE)-$(VERSION)
#----------------------------------------------------------------------
ls -lhtr *.iso
livecd.ks: livecd.ks.in livecd-post.sh Makefile
+ rm -f $@
sed \
-e 's|@BASEREPO@|$(BASEREPO)|g' \
-e 's|@LANG@|$(LANG)|g' \
-e 's|@TIMEZONE@|$(TIMEZONE)|g' \
< $< | cat - livecd-post.sh > $@
-livecd-post.sh: livecd-post.sh.in p2v.init virt-p2v.sh inittab Makefile
+livecd-post.sh: livecd-post.sh.in p2v.init virt-p2v.sh inittab lvm.conf Makefile
+ rm -f $@
sed \
-e '/@P2V.INIT@/ r p2v.init' \
-e '/@P2V.INIT@/ d' \
-e '/@VIRT-P2V.SH@/ d' \
-e '/@INITTAB@/ r inittab' \
-e '/@INITTAB@/ d' \
+ -e '/@LVM.CONF@/ r lvm.conf' \
+ -e '/@LVM.CONF@/ d' \
< $< > $@
# Run live CD under qemu.
clean:
rm -f *~ core livecd.ks livecd-post.sh
+# Manifest.
+
+dist:
+ $(MAKE) check-manifest
+ rm -rf $(PACKAGE)-$(VERSION)
+ mkdir $(PACKAGE)-$(VERSION)
+ tar -cf - -T MANIFEST | tar -C $(PACKAGE)-$(VERSION) -xf -
+ $(INSTALL) -m 0755 configure $(PACKAGE)-$(VERSION)/
+ tar zcf $(PACKAGE)-$(VERSION).tar.gz $(PACKAGE)-$(VERSION)
+ rm -rf $(PACKAGE)-$(VERSION)
+ ls -l $(PACKAGE)-$(VERSION).tar.gz
+
+check-manifest:
+ @for d in `find -type d -name CVS | grep -v '^\./debian/'`; \
+ do \
+ b=`dirname $$d`/; \
+ awk -F/ '$$1 != "D" {print $$2}' $$d/Entries | \
+ sed -e "s|^|$$b|" -e "s|^\./||"; \
+ done | sort > .check-manifest; \
+ sort MANIFEST > .orig-manifest; \
+ diff -u .orig-manifest .check-manifest; rv=$$?; \
+ rm -f .orig-manifest .check-manifest; \
+ exit $$rv
+
.PHONY: build boot checkroot
\ No newline at end of file
Copyright (C) 2007 Red Hat Inc.
+ http://et.redhat.com/~rjones/virt-p2v/
+
+Binaries
+----------------------------------------------------------------------
+
+Binaries are available from the website (live CD images which can be
+burned directly to a CD and booted on the p2v candidate machine).
+
+http://et.redhat.com/~rjones/virt-p2v/
+
+Building
+----------------------------------------------------------------------
+
+Requirements:
+ * livecd-creator (on Fedora the package is 'livecd-tools')
+ * qemu (only for testing)
+
+(1) Edit Makefile - there is some general configuration at the
+ top which you may want to change.
+
+(2) 'make build' will build an ISO image called virt-p2v-$VERSION.iso
+
+(3) Burn the image on to a CD using standard tools.
+
+Booting from USB device
+----------------------------------------------------------------------
+
+If you wish to boot from a USB keydrive, use the livecd-iso-to-disk
+tool:
+
+ livecd-iso-to-disk virt-p2v-$VERSION.iso /dev/sdX1
+
+(Replace /dev/sdX1 with the actual USB device).
+
+In my experience I also had to set up a suitable MBR:
+
+ cat /usr/lib/syslinux/mbr.bin > /dev/sdX
+
+Running
+----------------------------------------------------------------------
+
+Boot the candidate machine from the live CD or USB keydrive.
+
+You will need to have network access to another machine where it will
+save the virtual disk images. Ideally that machine will have ssh
+access (sshd service running), but there is also a simple network
+daemon that you can run on the target machine. Note that the target
+machine is usually the Xen host, but it doesn't need to be: you could
+copy the images to a staging machine, and later copy them over to the
+Xen host.
+
+Note that the live CD doesn't modify any data on the candidate
+machine.
+
+Answer the questions. There is a tutorial and explanation of some of
+the questions on the website which you may wish to follow:
+http://et.redhat.com/~rjones/virt-p2v/
+
+While the live CD is booted a shell is available on other virtual
+consoles. Go to a virtual console using [ALT] [F2] and log in as root
+with no password.
+
+If it works, the result will be disk images for each filesystem from
+the candidate machine, which should boot directly or with the minimum
+of changes.
+
+Booting P2V candidate under Xen
+----------------------------------------------------------------------
+
+
+Testing
+----------------------------------------------------------------------
+
+If you want to test the live CD without actually P2V-ing a real
+server, then you can run the ISO directly in qemu. (To do any sort of
+realistic testing you will also need an operating system image,
+eg. from /var/lib/xen/images, to experiment with). For example:
+
+ $ cp /var/lib/xen/images/rhel5gax32fv.img .
+ $ make boot HDA=rhel5gax32fv.img
+ qemu -m 512 -cdrom virt-p2v-0.1.iso -boot d -hda rhel5gax32fv.img
+
+
+Network daemon
+----------------------------------------------------------------------
# (only if override_remote_transport is 'ssh')
override_remote_directory=
-# list of local physical devices to examine, separated by spaces,
+# 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_physical_devices=""
+override_devices_to_send=""
-# list of filesystems to send (eg. "sda1 sda2 VolGroup00/LogVol00")
-override_filesystems_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
-# - if contains a filesystem name (eg. "VolGroup00/LogVol00") try to
-# auto-configure network from that
+# - "auto" means try to autoconfigure from root filesystem
# (XXX needs to contain more ways to override in future)
override_network=""
#----------------------------------------------------------------------
# Device mapper snapshotting.
+next_ramdisk=1
+
# Create a device-mapper snapshot of a device with ramdisk overlay.
# Example:
# snapshot sda1 snap
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`
--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_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
}
#----------------------------------------------------------------------
# Network configuration functions.
-# `auto_network $fs' mounts /dev/$fs read-only on /mnt/root and then
-# tries to configure the network from it. Returns true or false.
+# `auto_network $fs' tries to configure the network from the
+# root filesystem. Returns true or false.
function auto_network {
- if ! mount -o ro /dev/$1 /mnt; then return 1; fi
-
# Make sure this file exists, otherwise Fedora gives a warning.
touch /etc/resolv.conf
mv network-scripts network-scripts.saved
# Originally I symlinked these, but that causes dhclient to
- # keep open /mnt (as its cwd is in network-scripts subdir).
+ # keep open /mnt/root (as its cwd is in network-scripts subdir).
# So now we will copy them recursively instead.
- cp -r /mnt/etc/sysconfig/network .
- cp -r /mnt/etc/sysconfig/networking .
- cp -r /mnt/etc/sysconfig/network-scripts .
- # This also means we can umount /mnt early.
- umount /mnt
+ 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=$?
# Block devices configuration.
devices)
- if [ -n "$override_physical_devices" ]; then
- physical_devices="$override_physical_devices"
- state=filesystems
+ if [ -n "$override_devices_to_send" ]; then
+ devices_to_send="$override_devices_to_send"
+ state=root
else
# Returns the list of physical devices in $devices
search_devices
deviceslist=""
for d in $devices; do
- if word_in_list $d $physical_devices; then
+ if word_in_list $d $devices_to_send; then
stat=on
else
stat=off
dialog \
--extra-button --extra-label "Back" --nocancel \
--single-quoted \
- --checklist "Pick local disks to examine" 15 50 8 \
+ --checklist "Pick disks to send" 15 50 8 \
$deviceslist \
2> line
if [ $? -eq 3 ]; then state=directory
else
- physical_devices=`cat line`
- state=filesystems
+ devices_to_send=`cat line`
+ state=root
fi
fi
;;
- filesystems)
- if [ -n "$override_filesystems_to_send" ]; then
- filesystems_to_send="$override_filesystems_to_send"
- state=roots
+
+ # 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 $physical_devices
+ search_parts $devices_to_send
log partitions returned by search_parts: $parts
partslist=""
- for p in $parts; do
- if word_in_list $p $filesystems_to_send; then
- stat=on
- else
- stat=off
- fi
- gigs=$(($(blockdev --getsize /dev/$p)/2/1024/1024))
- partslist="$partslist $p /dev/$p(${gigs}GB) $stat"
- done
-
- dialog \
- --extra-button --extra-label "Back" --nocancel \
- --single-quoted \
- --checklist "Pick filesystems to send" 15 70 8 \
- $partslist \
- 2> line
- if [ $? -eq 3 ]; then state=devices
- else
- filesystems_to_send=`cat line`
- state=roots
- fi
- fi
- ;;
- roots)
- if [ -n "$override_root_filesystems" ]; then
- root_filesystems="$override_root_filesystems"
- state=network
- else
- partslist=""
- for r in $filesystems_to_send; do
- if word_in_list $r $root_filesystems; then
+ for r in $parts; do
+ if word_in_list $r $root_filesystem; then
stat=on
else
stat=off
dialog \
--extra-button --extra-label "Back" --nocancel \
--single-quoted \
- --checklist "Pick partition(s) containing a root (/) filesystem" 10 70 5 \
+ --radiolist "Pick partition containing the root (/) filesystem" 10 70 5 \
$partslist \
2> line
- if [ $? -eq 3 ]; then state=filesystems
+ if [ $? -eq 3 ]; then state=devices
else
- root_filesystems=`cat line`
+ root_filesystem=`cat line`
state=network
fi
fi
network="$override_network"
state=verify
else
- partslist=""
- for r in $root_filesystems; do
- if [ "$r" = "$network" ]; then
- stat=on
- else
- stat=off
- fi
- partslist="$partslist $r Auto-configure $stat"
- done
-
dialog \
--extra-button --extra-label "Back" --nocancel \
--radiolist "Network configuration" 10 70 5 \
- $partslist \
+ "auto" "Auto-configure from root filesystem" on \
"ask" "Manual configuration" off \
"sh" "Configure from the shell" off \
2> line
- if [ $? -eq 3 ]; then state=roots
+ if [ $? -eq 3 ]; then state=root
else
network=`cat line`
state=verify
else
dialog \
--title "Summary" \
- --yesno "Transport: $remote_transport\nRemote host: $remote_host\nRemote port: $remote_port\nRemote directory (ssh only): $remote_directory\nFilesystems to send: $filesystems_to_send\nRoot filesystem(s): $root_filesystems\nNetwork configuration: $network\n\nProceed with these settings?" \
+ --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?" \
23 70
if [ $? -eq 1 ]; then
state=transport
clear
+# 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.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
+
+# Mount the root filesystem on /mnt/root. If it's a physical
+# device then we want to mount (eg) /dev/mapper/snap_sda1.
+# If it's a LVM device (which it probably won't be for Linux because
+# Linux doesn't support it) 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
echo
echo "Please configure the network from this shell."
echo
- echo "You can modify any file under /etc (especially /etc/sysconfig)."
- echo "No changes are made to the system disks unless you mount them"
- echo "and explicitly modify them."
- echo
echo "When finished, exit with ^D or exit"
echo
shell
shell
;;
- *)
+ auto)
echo "Trying to auto-configure network from /dev/$network ..."
echo
if ! auto_network "$network"; then
fi
esac
-# Mount the root filesystem(s) using device-mapper snapshots.
-# The snapshots are called snap0, snap1, etc. with the number
-# corresponding to its index in $root_filesystems array.
-
-
-
-
+#----------------------------------------------------------------------
+# Clean up.
+umount /mnt/root
+drop_snapshot snap
# This file must end with a newline