#!/usr/bin/perl
use strict;
use vars qw( $opt_t $opt_o $opt_n $opt_i $opt_m $opt_g $opt_s $opt_h $opt_a );
use Getopt::Std;
sub chkopts {
getopts( 'ahs:t:o:n:i:k:g:b:c:m:' );
$opt_h = 1 unless ( $opt_t && $opt_o && $opt_n && $opt_i && $opt_m &&
$opt_g && $opt_s );
if ( $opt_h ) {
print <<EOF;
usage: kvmclone.pl [-aontsimg]
-a: Activate vm after cloning
-o: Original domain name
-n: New domain name
-t: Target disk image file
-s: Server hostname
-i: IP Address
-m: Net mask
-g: Default gateway
EOF
exit 0;
}
$opt_t = "/var/lib/libvirt/images/" . $opt_t unless ( $opt_t =~ m/^\// );
}
sub log_cmd {
print "===> Exec: $_[ 0 ]\n";
system ( $_[ 0 ] );
}
sub chkvm {
if ( system( "virsh dominfo $opt_o | grep -E \"^State: +shut off\$\" >/dev/null 2>&1" ) ) {
print "Domain $opt_o is running, shutdown first.\n\n";
exit 1;
}
}
sub clonfiles {
my ( $old_mac, $mac, $loopdev, $s );
my @dpart;
my $tmpmnt = "/tmp/tmpmnt$$";
print( "\nCloning disk image file of $opt_o to $opt_t...\n" );
log_cmd( "virt-clone --prompt --original $opt_o --name $opt_n --file $opt_t --nonsparse" );
$_ = `grep \"mac address\" /etc/libvirt/qemu/${opt_o}.xml`;
$_ =~ m/address=\'(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)\'/; $old_mac = $1;
$_ = `grep \"mac address\" /etc/libvirt/qemu/${opt_n}.xml`;
$_ =~ m/address=\'(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)\'/; $mac = $1;
print "\nModifying network information in the new disk image...\n\n";
print "Now trying to find root partition...\n";
$loopdev = `losetup -f`; chomp $loopdev;
log_cmd ( "losetup $loopdev $opt_t" );
$s = `kpartx -av $loopdev`; @dpart = split( /\n/, $s );
log_cmd ( "mkdir -p $tmpmnt" );
foreach $s ( @dpart ) {
$s = $1 if ( $s =~ m/add map (\w+) :/ );
log_cmd ( "mount /dev/mapper/$s $tmpmnt" );
if ( -d "$tmpmnt/etc/sysconfig" ) {
print "\nFound root partition on $s\n";
goto OUT;
} else {
log_cmd ( "umount $tmpmnt" );
}
}
print "Failed to find root partition.\n";
log_cmd ( "kpartx -d $loopdev; losetup -d $loopdev; rmdir $tmpmnt" );
exit 1;
OUT:
open ( IN, "<$tmpmnt/etc/sysconfig/hwconf" );
open ( OUT, ">$tmpmnt/etc/sysconfig/hwconf_new" );
while (<IN>) {
$_ =~ s/\r\n$/\n/;
$_ =~ s/^network.hwaddr: $old_mac/network.hwaddr: $mac/;
print OUT $_;
}
close OUT;
close IN;
log_cmd ( "mv -f $tmpmnt/etc/sysconfig/hwconf_new $tmpmnt/etc/sysconfig/hwconf" );
print "\nNew mac address in hwconf file....\n";
print "---------------------------\n";
system ( "grep \"network.hwaddr\" $tmpmnt/etc/sysconfig/hwconf" );
print "---------------------------\n";
open ( IN, "<$tmpmnt/etc/sysconfig/network" );
open ( OUT, ">$tmpmnt/etc/sysconfig/network_new" );
while (<IN>) {
$_ =~ s/\r\n$/\n/;
$_ =~ s/HOSTNAME\s*=\s*[\w-]+/HOSTNAME=$opt_s/;
$_ =~ s/GATEWAY\s*=\s*[\d\.]+/GATEWAY=$opt_g/;
print OUT $_;
}
close OUT;
close IN;
log_cmd ( "mv -f $tmpmnt/etc/sysconfig/network_new $tmpmnt/etc/sysconfig/network" );
print "\nNew network config file....\n";
print "---------------------------\n";
system ( "cat $tmpmnt/etc/sysconfig/network" );
print "---------------------------\n";
open ( IN, "<$tmpmnt/etc/sysconfig/network-scripts/ifcfg-eth0" );
open ( OUT, ">$tmpmnt/etc/sysconfig/network-scripts/ifcfg-eth0_new" );
while (<IN>) {
$_ =~ s/\r\n$/\n/;
$_ =~ s/HWADDR\s*=\s*[\w:]+/HWADDR=$mac/;
$_ =~ s/IPADDR\s*=\s*[\d\.]+/IPADDR=$opt_i/;
$_ =~ s/NETMASK\s*=\s*[\d\.]+/NETMASK=$opt_m/;
$_ =~ s/GATEWAY\s*=\s*[\d\.]+/GATEWAY=$opt_g/;
print OUT $_;
}
close OUT;
close IN;
log_cmd ( "mv -f $tmpmnt/etc/sysconfig/network-scripts/ifcfg-eth0_new $tmpmnt/etc/sysconfig/network-scripts/ifcfg-eth0" );
print "\nNew interface eth0 config file....\n";
print "---------------------------\n";
system ( "cat $tmpmnt/etc/sysconfig/network-scripts/ifcfg-eth0" );
print "---------------------------\n";
log_cmd ( "umount $tmpmnt" );
log_cmd ( "kpartx -d $loopdev; losetup -d $loopdev; rmdir $tmpmnt" );
}
MAIN: {
chkopts();
chkvm();
clonfiles();
if ( $opt_a ) {
print "\nActivate new vm $opt_n\n";
log_cmd ( "virsh start $opt_n" );
}
print "Done.\n";
}