5 use Data::Dump qw(dump);
9 my $hostname = `hostname -s`;
12 # path to create vmdk into (not on same disk as backup)
13 my $vmdk="/mnt/backup/${hostname}.vmdk";
15 # root disk device name
18 # name of new backup vg
19 my $vg_backup="backup";
21 # where to mount new filesystem while creating vmdk
22 my $tmp = "/tmp/backup";
25 warn "collecting filesystem info\n";
28 open(my $blkid, '-|', 'blkid');
31 my ( $dev, $params ) = split(/:\s+/, $_, 2);
32 foreach my $single ( split(/\s+/, $params ) ) {
33 my ( $name, $value ) = split(/=/, $single, 2);
35 $blks->{$dev}->{$name} = $value;
38 warn "blks = ",dump($blks);
41 open(my $pv, '-|', "pvs --noheadings --options pv_name --unbuffered");
45 if ( s{$sda}{nbd0p} ) {
51 warn "# pvs = ",dump(@pvs);
54 my @lv_create_snapshot;
56 open(my $lvs, '-|', "lvs --noheadings --options lv_name,vg_name,lv_size --units k");
61 my ($name,$vg,$size) = split(/\s+/, $_, 3);
62 if ( $vg eq $vg_backup ) {
63 warn "SKIP $name in $vg_backup !\n";
66 push @lv_create, "lvcreate --name $name --size $size $vg_backup";
67 next if $name =~ m/swap/;
68 push @lv_create, "lvcreate --snapshot /dev/$vg/$name --name ${name}-snap --size 100M";
69 push @lv_remove, "/dev/$vg/$name-snap";
71 warn "# lv_create = ",dump(@lv_create);
74 open(my $mount, '-|', 'mount');
77 my ($dev, undef, $path, undef, $fs, undef) = split(/\s+/,$_);
78 push @mounts, [ $dev, $path, $fs ];
80 warn "# mounts = ",dump(@mounts);
84 system @_ unless $ENV{DEBUG};
88 warn "begin vmdk creation...\n";
90 my $size = `blockdev --getsize64 /dev/$sda`;
91 sh "qemu-img create -f vmdk -o compat6 $vmdk $size";
93 sh "modprobe nbd max_part=8";
96 if ( $nbd_pid = fork ) {
99 sh "qemu-nbd --verbose --connect /dev/nbd0 $vmdk";
106 sh "sfdisk -d /dev/$sda | sfdisk --force /dev/nbd0";
108 sh "pvcreate $_" foreach @pvs;
110 sh "vgcreate $vg_backup @pvs";
112 sh $_ foreach @lv_create;
114 mkdir $tmp unless -d $tmp;
120 $dev =~ s{/dev/$sda}{/dev/nbd0p} ||
121 $dev =~ s{/dev/mapper/.+-([^-]+)}{/dev/mapper/$vg_backup-$1} ||
122 die "can't map $dev to new backup device!";
126 foreach my $mount ( @mounts ) {
127 my ( $dev, $path, $fs ) = @$mount;
128 if ( exists $blks->{$dev} ) {
129 warn "working on $dev $path $fs\n";
130 my $dev_backup = dev_to_backup($dev);
131 my $label = $blks->{$dev}->{LABEL};
132 $label = $label ? "-L $label" : '';
133 sh "mkfs.$fs $label $dev_backup";
134 mkdir $tmp . $path unless -e $tmp . $path;
135 sh "mount $dev_backup $tmp$path";
136 unshift @umount, $tmp . $path;
137 $dev .= '-snap' if -e $dev . '-snap';
139 sh "dump -0 -f - $dev | restore -r -f -";
141 warn "SKIP $dev $path $fs";
147 if ( my $swap = (grep { $blks->{$_}->{TYPE} eq 'swap' } keys %$blks)[0] ) {
148 my $dev = dev_to_backup($swap);
149 my $label = $blks->{$swap}->{LABEL};
150 $label = $label ? "-L $label" : '';
151 warn "create swap on $dev\n";
152 sh "mkswap $label $dev";
157 sh "umount $_" foreach @umount;
159 sh "lvremove -f $_" foreach @lv_remove;
161 sh "vgchange --available n $vg_backup";
163 sh "vgexport $vg_backup";
165 warn "finished in ", time() - $start_t, " seconds\n";
167 sh "qemu-nbd --disconnect /dev/nbd0";