LVM UUID generation (was Re: [linux-lvm] Question on duplicating equally-sized HDs with dd and changing VG name and PV UUIDs)

Daniel Tuijnman daniel at velotype.nl
Wed Sep 12 00:21:19 UTC 2007


> (I don't want't to forcefully recreate a PV, I just want to be able to
> assign a different UUID to it in order keep LVM from "thinking" that PV
> still belongs to some other VG).
> 
> But, on the other hand, I also just noticed that the UUIDs of PVs, VGs, LVs
> are formatted differently from those generated by uuidgen. Or can LVM also
> use UUIDs that are formatted differently?

In my experience: no. I ran into the same some time ago with a similar
problem: I wanted to be able to clone LV's which I use as disk for Xen-VM's.
Of course, within the LV I also use a VG to partition the disk.

Attached is my script for automating this. I didn't know at the time about
uuidgen, so I used some Perl to generate a UUID and then to massage it into
the LVM UUID format.

> So, my question about a UUID generation tool for proper UUID usage within
> LVM seems to be still valid...

I'd be very anxious to know about this too.

-- 
Daniël Tuijnman                     phone:  +31-24-377.7329
De Voorstenkamp 19-59               mobile: +31-6-4611.4589
NL-6545 GR Nijmegen                 fax:    +31-24-373.3632
-------------- next part --------------
#!/bin/bash
#
# Daniel Tuijnman
# Fri Mar  2 20:34:13 CET 2007
#
# This script clones a LVM based paravirtualized Xen-VM
# it makes a number of assumptions:

# 1. The single disk of the VM is in a Volume Group VG_domU
VMBASE="/dev/VG_domU"

# 2. The VM disk contains two partitions:
#    (1) /boot
#    (2) a single Physical Volume for the Volume Group in the VM disk
BOOTPART=1
PVPART=2

# 3. The root filesystem of the VM is in a LV called 'root'
ROOTLV="root"

# 4. The name of the Volume Group on the VM disk is the name of the Xen-VM
# with "VG_" prepended
function vm_to_vg {
    echo "VG_$1"
}

# 5. the VM boots the first kernel present in the grub.conf
# (no variables to change here, sorry)

# set paranoia mode
set -eu
# set debug mode
# set -x

function cleanup {
    echo "Cleaning up on exit"
    umount "$MNTBOOT" || true
    umount "$MNT" || true
    vgchange -a n "$SRC_VOLG" || true
    vgchange -a n "$DST_VOLG" || true
    kpartx -d "$DST_VM"
    vgscan
    return
    /bin/rm -rf "$CFGFILE" "$NEWCFGFILE" "$MNT" "$INITRDDIR"
}

# test input
if (( $# != 2 )); then
    echo "$0: wrong number of arguments" >&2
    echo "$0: usage: $0 <src-lvm> <dst-lvm>" >&2
    exit 1
fi

SRC="$1"
DST="$2"
SRC_VM="${VMBASE}/${SRC}"
DST_VM="${VMBASE}/${DST}"

if [[ ! -b "$SRC_VM" ]]; then
    echo "$0: source LV does not exist" >&2
    exit 2
fi

if [[ ! -b "$DST_VM" ]]; then
    echo "$0: destination LV does not exist, will be created" >&2
    SIZE=$(lvs --noheadings --units m -o lv_size "$SRC_VM")
    lvcreate -v -L $SIZE -n "$DST" "$VMBASE"
else
    echo "$0: warning: destination LV will be overwritten" >&2
    echo "$0: you have 5 seconds to bail out" >&2
    sleep 5
fi

# set various variables
SRC_VOLG=$(vm_to_vg "$SRC")
echo "Source VolGroup: $SRC_VOLG"
DST_VOLG=$(vm_to_vg "$DST")
echo "Destination VolGroup: $DST_VOLG"
CFGFILE="/tmp/vgcfg$$"
DST_BOOT="/dev/mapper/${DST}p${BOOTPART}"
DST_ROOT="$DST_VOLG/$ROOTLV"
DST_PV="/dev/mapper/${DST}p${PVPART}"
MNT="/tmp/mnt$$"
MNTBOOT="$MNT/boot"
INITRDDIR="/tmp/initrd$$"
mkdir "$MNT"
mkdir "$INITRDDIR"
trap cleanup EXIT ERR SIGQUIT SIGINT

# now start with the real work
echo "$0: copying LV contents" >&2
echo "$0: this may take some time" >&2
dd if="$SRC_VM" of="$DST_VM"

# make device nodes for partitions on destination VM
kpartx -a "$DST_VM"
# read VG's and backup the current config
# (VG is still SRC named!)
vgscan
vgchange -a y "$SRC_VOLG"
vgcfgbackup -f "$CFGFILE" "$SRC_VOLG"
vgchange -a n "$SRC_VOLG"

# create new UUIDs for the PV, the VG and the LV's
# for the PV, we use pvchange to also change it on disk
# and subsequently, pvs to read the new UUID
# LVM UUID's are not official UUID's, so we have to massage
# the output of the Perl modules
perl -pi -e '
    BEGIN {
        use Data::UUID;
        $uuid = new Data::UUID;
        $physvol = 0;
    }
    if ( /physical_volumes/ ) { $physvol = 1 }
    if ( /logical_volumes/  ) { $physvol = 0 }
    if ( /^\s*id\s*\=\s*\"([A-Za-z0-9-]+)\"\s*$/ ) {
        my $newuuid;
        if ( $physvol ) {
            system "pvchange", "-u", "'"$DST_PV"'";
            $newuuid = qx!pvs --noheadings --options pv_uuid '"$DST_PV"'!;
            $newuuid =~ s/\s//g;
        } else {
            $newuuid = $uuid->create_str();
            $newuuid =~ s/(\w\w)-/-$1/g;
            $newuuid =~ s/(\w{4})(\w{6})$/-$1-$2/;
        }
        s/$1/$newuuid/;
    }
' "$CFGFILE";

# restore the VG and rename it
echo "Restoring volume group" >&2
vgcfgrestore -f "$CFGFILE" "$SRC_VOLG"
echo "Renaming volume group" >&2
vgrename "$SRC_VOLG" "$DST_VOLG"

# now change the VG name in the three places it's mentioned:
# 1 /etc/fstab
# 2 /boot/grub/grub.conf
# 3 'init' on the initrd...

vgchange -a y "$DST_VOLG"
mount "/dev/$DST_VOLG/$ROOTLV" "$MNT"
mount "$DST_BOOT" "$MNTBOOT"

# /etc/fstab
ed -s "$MNT/etc/fstab" <<-EDEND
	1,\$s/$SRC_VOLG/$DST_VOLG/
	w
	q
EDEND
# /boot/grub/grub.conf
ed -s "$MNTBOOT/grub/grub.conf" <<-EDEND
	1,\$s/$SRC_VOLG/$DST_VOLG/
	w
	q
EDEND
# 'init' on initrd
# first, what's the right initrd to change?
INITRD=$(sed -n '/^[ 	]*initrd/{
	s/[ 	]*initrd[ 	]*//
	p
	q
}' "$MNTBOOT"/grub/grub.conf)

cd "$INITRDDIR"
zcat "$MNTBOOT/$INITRD" | cpio -i
ed -s init <<-EDEND
	1,\$s/$SRC_VOLG/$DST_VOLG/
	w
	q
EDEND
find . | cpio -o -H newc | gzip > "$MNTBOOT/$INITRD"

# finally, wrap up
umount "$MNTBOOT"
umount "$MNT"
vgchange -a n "$DST_VOLG"
kpartx -d "$DST_VM"
vgscan
exit 0



More information about the linux-lvm mailing list