X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=virt-p2v.sh;fp=virt-p2v.sh;h=fa2e7051e3cb3934a04b02b226971d18a4eb95d8;hb=1835c920726e5ce4f012ba1fc4cba0d33c9b316a;hp=44184c703b5c17616b128e125e7fa86d0b8e555f;hpb=cc7a490c49e75e0c0b29098f212ed3c0f3f73612;p=virt-p2v.git diff --git a/virt-p2v.sh b/virt-p2v.sh index 44184c7..fa2e705 100755 --- a/virt-p2v.sh +++ b/virt-p2v.sh @@ -6,6 +6,7 @@ # By Richard W.M. Jones # # Copyright (C) 2007 Red Hat Inc. +# $Id$ export PATH=/usr/sbin:/sbin:/usr/local/bin:/usr/kerberos/bin:/usr/bin:/bin @@ -14,7 +15,7 @@ export PATH=/usr/sbin:/sbin:/usr/local/bin:/usr/kerberos/bin:/usr/bin:/bin # these variables to something, and the script won't ask the user for # input. -# greeting=no +# Use 'greeting=no' to suppress greeting and final verification screens. greeting= override_remote_host= @@ -28,8 +29,46 @@ override_remote_transport= override_remote_directory= # list of 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 +# "VolGroup00/LogVol00") +override_root_filesystems="" + +#---------------------------------------------------------------------- +# Logging. + +function log { + echo "$@" >> /tmp/virt-p2v.log +} + +#---------------------------------------------------------------------- +# Helper functions. + +# 'matches_regexp regexp string' returns true if string matches regexp. +# It uses egrep for extended regexps. +function matches_regexp { + local re="$1"; shift + echo "$@" | grep -Esq "$re" +} + +# 'string_contains needle haystack' returns true if needle in haystack. +function string_contains { + echo "$2" | grep -Fsq "$1" +} + +# 'word_in_list word ...'. '...' (list of parameters) is a list of +# words. Returns true if 'word' is in the list. +function word_in_list { + local word="$1"; shift + local w + for w in "$@"; do + [ "$w" = "$word" ] && return 0 + done + return 1 +} + #---------------------------------------------------------------------- # Device mapper snapshotting. @@ -41,11 +80,10 @@ override_devices_to_send="" # XXX Error checking. function snapshot { - dev=$1 - name=$2 + local dev=$1 name=$2 # Get size of the device in sectors. - sectors=`blockdev --getsize $dev` + local sectors=`blockdev --getsize $dev` dmsetup create ${name}_org \ --table="0 $sectors snapshot-origin $dev" @@ -62,6 +100,110 @@ function drop_snapshot { dmsetup remove /dev/mapper/${name}_org } +#---------------------------------------------------------------------- +# Searching for devices, partitions and LVs. + +# Convert "/dev/foo" into "foo". Returns $device. +function strip_slash_dev { + device=$(echo "$1" | sed 's|^/dev/||') +} + +# The 'lvs' utility returns devices like '/dev/sda2(0)'. I've no +# idea what the number in parentheses is, but remove /dev/ and the +# strange number. +function device_of_lvs_device { + strip_slash_dev "$1" + device=$(echo "$device" | sed 's|(.*)$||') +} + +# All functions in this section assume that physical block devices +# (things corresponding to hard disks in the system) are called +# hd[a-z]+ or sd[a-z]+ + +# Get list of physical block devices. Sets variable $devices +# to something like "sda sdb". +function search_devices { + devices=$(cd /sys/block && /bin/ls -d [hs]d*) +} + +# Get list of partitions from a physical block device. Sets +# variable $partitions to something like "sda1 sda2 sda3". +# See also: search_parts +function get_partitions { + partitions=$(cd /sys/block/"$1" && /bin/ls -d "$1"*) +} + +# Given a partition (eg. "sda1" or "VolGroup00/LogVol00") return +# the physical block device which contains it. In the case where +# we are given an LV, this is supposed to do the right thing and +# go back through the layers until it gets to the physical block +# device. Returns $device set to something like "sda". +function block_device_of_part { + local part="$1" vg_name lv_name pv + + if matches_regexp '^[hs]d[a-z]+[0-9]*$' "$part"; then + device=$(echo "$part" | sed 's|[0-9]*$||') + return 0 + fi + + # Not a partition name, so it's a LV name. Ask lvs to + # do the hard work. + lvs --noheadings -o vg_name,lv_name,devices > lvs + while read vg_name lv_name pv; do + if [ "$vg_name/$lv_name" = "$part" \ + -o "mapper/$vg_name-$lv_name" = "$part" ]; then + device_of_lvs_device "$pv" ;# sets $device to (eg.) "sda1" + block_device_of_part "$device" + return 0 + fi + done < lvs + + # Help ... block device not found. + log block_device_of_part: block device cannot be resolved: $part + device="$part" +} + +# search_parts $devices examines the list of devices and looks for +# partitions or LVs on just those devices. Sets variable $parts to +# something like "sda1 VolGroup00/LogVol00". +function search_parts { + local vg_name lv_name pv pvs="" device partition partitions + + parts="" + + lvs --noheadings -o vg_name,lv_name,devices > lvs + while read vg_name lv_name pv; do + # Get just the partition name (eg. "sda2"). + device_of_lvs_device "$pv"; pv="$device" + # Get just the block device name (eg. "sda"). + block_device_of_part "$pv" + + log search_parts: pv $pv device $device lv $vg_name/$lv_name + + # A device in our list of devices to consider? + if word_in_list $device "$@"; then + log search_parts: adding $vg_name/$lv_name + parts="$parts $vg_name/$lv_name" + pvs="$pvs $pv" + fi + done < lvs + + log search_parts: after lvs, parts $parts pvs $pvs + + # Look for non-LVM partitions, but ignore any which are PVs + # as identified above. + for device in "$@"; do + get_partitions "$device" + for partition in $partitions; do + if ! word_in_list $partition $pvs; then + log search_parts: adding $partition + parts="$parts $partition" + fi + done + done + + # $parts is returned. +} #---------------------------------------------------------------------- # General script setup. @@ -72,6 +214,9 @@ cd /tmp #---------------------------------------------------------------------- # Dialog with the user. +log +log virt-p2v starting up at `date` + if [ "$greeting" != "no" ]; then dialog \ --title "virt-p2v" \ @@ -85,24 +230,53 @@ fi # (unless [Back] is pressed, in which case it jumps back to the previous # state). Finally the 'exit' state causes us to quit the loop. -state=hostname +remote_port=22 +remote_directory=/var/lib/xen/images +state=transport + while [ "$state" != "exit" ]; do + log next state = $state case "$state" in + transport) + if [ -n "$override_remote_transport" ]; then + remote_transport="$override_remote_transport" + state=hostname + else + case "$remote_transport" in + tcp) ssh_on=off; tcp_on=on;; + *) ssh_on=on; tcp_on=off;; + esac + dialog \ + --nocancel \ + --radiolist "Connection type" 10 50 2 \ + "ssh" "SSH (secure shell - recommended)" $ssh_on \ + "tcp" "TCP socket" $tcp_on \ + 2> line + remote_transport=`cat line` + state=hostname + fi + ;; hostname) if [ -n "$override_remote_host" ]; then remote_host="$override_remote_host" + state=port else dialog \ - --nocancel \ + --extra-button --extra-label "Back" --nocancel \ --inputbox "Remote host" 10 50 "$remote_host" \ 2> line - remote_host=`cat line` - state=port + if [ $? -eq 3 ]; then state=transport + else + remote_host=`cat line` + if [ -n "$remote_host" ]; then state=port; fi + # else stay in same state and demand a hostname! + fi fi ;; port) if [ -n "$override_remote_port" ]; then remote_port="$override_remote_port" + state=directory else dialog \ --extra-button --extra-label "Back" --nocancel \ @@ -111,18 +285,135 @@ while [ "$state" != "exit" ]; do if [ $? -eq 3 ]; then state=hostname else remote_port=`cat line` - state=exit + state=directory + fi + fi + ;; + directory) + if [ "$remote_transport" = "tcp" ]; then + state=devices + elif [ -n "$override_remote_directory" ]; then + remote_directory="$override_remote_directory" + state=devices + else + dialog \ + --extra-button --extra-label "Back" --nocancel \ + --inputbox "Remote directory containing guest images" \ + 10 50 \ + "$remote_directory" \ + 2> line + if [ $? -eq 3 ]; then state=port + else + remote_directory=`cat line` + state=devices + fi + fi + ;; + devices) + if [ -n "$override_devices_to_send" ]; then + devices_to_send="$override_devices_to_send" + state=roots + else + # Returns the list of possible devices in $devices + search_devices + + log devices returned by search_devices: $devices + + deviceslist="" + for d in $devices; do + if word_in_list $d $devices_to_send; then + stat=on + else + stat=off + fi + deviceslist="$deviceslist $d /dev/$d $stat" + done + + dialog \ + --extra-button --extra-label "Back" --nocancel \ + --single-quoted \ + --checklist "Pick which local disk images to send" 10 50 5 \ + $deviceslist \ + 2> line + if [ $? -eq 3 ]; then state=directory + else + devices_to_send=`cat line` + state=roots + log user selected devices_to_send = $devices_to_send fi fi ;; + roots) + if [ -n "$override_root_filesystems" ]; then + root_filesystems="$override_root_filesystems" + state=verify + else + # Returns the list of possible partitions / LVs in $parts + search_parts $devices_to_send + + log filesystems 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 + else + root_filesystems=`cat line` + state=verify + log user selected root_filesystems = $root_filesystems + fi + fi + fi + ;; + 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 + if [ $? -eq 1 ]; then + state=transport + else + state=exit + fi + fi + ;; *) echo "Invalid state: $state" - state=hostname + state=transport ;; esac done clear -echo remote_host $remote_host -echo remote_port $remote_port \ No newline at end of file + +# Mount the root filesystem(s) using device-mapper snapshots. + + + + + + + + +# This file must end with a newline +