Dan asked me if it was possible to use libguestfs to convert an LVM-based guest to a partition-based guest. Of course, this is possible, but not particularly easy. In this post I’ll show you some useful scripts to get started.
The first is virt-explode. It takes a disk image and extracts the filesystems from it. Here is what it looks like when you run it:
$ virt-explode.pl RHEL4x64 downloading /dev/sda1 to sda1.img (101.9 MBytes) downloading /dev/VolGroup00/LogVol00 to VolGroup00_LogVol00.img (7072.0 MBytes) downloading /dev/VolGroup00/LogVol01 to VolGroup00_LogVol01.img (992.0 MBytes) $ ll *.img -rw-r--r--. 1 root root 106896384 Nov 15 12:25 sda1.img -rw-r--r--. 1 root root 7415529472 Nov 15 12:29 VolGroup00_LogVol00.img -rw-r--r--. 1 root root 1040187392 Nov 15 12:30 VolGroup00_LogVol01.img
Each extracted filesystem is an ext* filesystem, a swap partition, etc:
$ file VolGroup00_LogVol00.img VolGroup00_LogVol00.img: Linux rev 1.0 ext3 filesystem data, UUID=7851e822-24a7-445c-a980-bcd5ebafbb1e (large files)
Here is the virt-explode script:
#!/usr/bin/perl -w
use strict;
use Sys::Guestfs;
die "$0 disk.img" unless @ARGV == 1;
my $g = Sys::Guestfs->new ();
$g->add_drive_opts ($ARGV[0], readonly => 1);
$g->launch ();
my %fses = $g->list_filesystems ();
my $name;
foreach $name (keys %fses) {
my $filename = $name;
$filename =~ s{^/dev/}{};
$filename =~ s{/}{_}g;
$filename .= ".img";
my $size;
eval { $size = $g->blockdev_getsize64 ($name) };
if (defined $size) {
printf "downloading %s to %s (%.1f MBytes)\n",
($name, $filename, $size / 1024.0 / 1024.0);
$g->download ($name, $filename);
}
}
Next up, virt-implode …

#!usr/bin/perl -w
should really be
#!usr/bin/env perl
use warnings;
in order to be more portable