LVM is a wonderful feature of Linux which I use all over the place.
It has always struck me as somewhat odd, however, that there is no command to copy or move a Logical Volume from one Volume Group to another.
Therefore I came up with a Bash script to do the job for me, and whilst I was at it, I made it work between servers as well.
#!/bin/bash
# Copy or move a Logical Volume from one Volume Group to another
# possibly on another machine
if [ -z "$4" ]
then
echo "Usage: $0 LV fromVG [host:]toVG <copy|keep|move> [nocheck]"
exit 1
fi
# 1. Make sure LV exists on source VG
# 2. Parse destination VG - if it contains a colon, it means hostname:VG
# 3. Make sure LV does not exist on destination VG
# 4. Get size of source LV
# 5. Create destination LV
# 6. Copy content
# 7. Compare source vs. destination if required
# 8. If match, delete source and any log files
host=
LV=$1
fromVG=$2
toVG=$3
task=$4
check=$5
[ "$toVG" = "${toVG/:}" ] || host="${toVG%%:*}"
[ -n "$host" ] && toVG="${toVG##*:}"
needed="ddrescue lvdisplay diff"
for need in $needed
do
if ! which $need &>/dev/null
then
echo "Sorry, I need $need installed before this can work."
exit 1
fi
done
if lvdisplay $fromVG/$LV &>/dev/null
then
if [ -n "$host" ]
then
if ssh $host "lvdisplay $toVG/$LV 2>/dev/null" | grep -q $LV
then
echo "Logical Volume $LV already exists in Volume Group $toVG on $host"
exit 1
fi
else
if lvdisplay $toVG/$LV &>/dev/null
then
echo "Logical Volume $LV already exists in Volume Group $toVG"
exit 1
fi
fi
lvsize=`lvdisplay $fromVG/$LV | grep "Current LE" | tr -s ' ' | cut -d' ' -f4`
if [ -n "$host" ]
then
echo "Creating new LV $LV on destination VG $toVG on $host"
ssh $host "lvcreate -y -l $lvsize -n $LV $toVG"
echo "Copying content (be patient)..."
dd if=/dev/$fromVG/$LV bs=1M | ssh $host dd bs=1M of=/dev/$toVG/$LV
else
echo "Creating new LV $LV on destination VG $toVG"
lvcreate -y -l $lvsize -n $LV $toVG
echo "Copying content..."
ddrescue -f /dev/$fromVG/$LV /dev/$toVG/$LV /tmp/$LV.log
fi
OK=no
if [ "$check" = "nocheck" ]
then
OK=yes
else
if [ -n "$host" ]
then
echo "Checking the copy..."
diff -q <(md5sum /dev/$fromVG/$LV | cut -d' ' -f1) <(ssh $host md5sum /dev/$toVG/$LV | cut -d' ' -f1) && OK=yes
else
echo "Checking the copy (this will take approximately as long as the copy did)..."
diff -q /dev/$fromVG/$LV /dev/$toVG/$LV && OK=yes
fi
fi
if [ "$OK" = "yes" ]
then
if [ "$task" = "keep" -o "$task" = "copy" ]
then
rm -f /tmp/$LV.log
echo "$LV successfully copied from $fromVG to $toVG"
exit 0
elif [ "$task" = "move" ]
then
lvremove -y $fromVG/$LV
rm -f /tmp/$LV.log
echo "$LV successfully moved from $fromVG to $toVG"
exit 0
else
echo "$LV successfully copied from $fromVG to $toVG"
echo "but not sure whether you wanted to delete the original, therefore keeping both."
exit 0
fi
else
echo "Something went wrong."
exit 1
fi
else
echo "Logical Volume $LV not found in Volume Group $fromVG"
exit 1
fi
The script uses ddrescue if you're working on a single server, but has to use dd (which is just as effective, but produces no progress output) if you're working between two machines.
Between two machines, the script works best if you have passwordless public-key login access between the machines (but will still prompt for a password (several times) if this is not in place).
Go up
Return to main index.