-Add support for different cloning methods and image formats to kvm

-Change default format to 'raw' for performance
-Add support for storage server side cow cloning via 'cp --reflink' (requires btrfs to work)


git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@4647 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
This commit is contained in:
jbjohnso 2009-11-22 19:41:52 +00:00
parent 8ccc09febd
commit ee8b25b822
2 changed files with 97 additions and 35 deletions

View File

@ -53,7 +53,14 @@ vm => {
'nics' => 'Network configuration parameters. Of the general form [physnet:]interface[=model],.. Generally, interface describes the vlan entity (default for native, tagged for tagged, vl[number] for a specific vlan. model is the type of device to imitate (i.e. virtio, e1000 (generally default), rtl8139, depending on the virtualization technology. physnet is a virtual switch name or port description that is used for some virtualization technologies to construct virtual switches. hypervisor.netmap can map names to hypervisor specific layouts, or the descriptions described there may be used directly here where possible.',
'bootorder' => 'Boot sequence (i.e. net,hd)',
'clockoffset' => 'Whether to have guest RTC synced to "localtime" or "utc" If not populated, xCAT will guess based on the nodetype.os contents.',
'virtflags' => 'General flags used by the virtualization method. For example, in Xen it could, among other things, specify paravirtualized setup, or direct kernel boot. For a hypervisor/dom0 entry, it is the virtualization method (i.e. "xen")',
'virtflags' => 'General flags used by the virtualization method. For example, in Xen it could, among other things, specify paravirtualized setup, or direct kernel boot. For a hypervisor/dom0 entry, it is the virtualization method (i.e. "xen"). For KVM, the following flag=value pairs are recognized:
imageformat=[raw|fullraw|qcow2]
raw is a generic sparse file that allocates storage on demand
fullraw is a generic, non-sparse file that preallocates all space
qcow2 is a sparse, copy-on-write capable format implemented at the virtualization layer rather than the filesystem level
clonemethod=[qemu-img|reflink]
qemu-img allows use of qcow2 to generate virtualization layer copy-on-write
reflink uses a generic filesystem facility to clone the files on your behalf, but requires filesystem support such as btrfs ',
'vncport' => 'Tracks the current VNC display port (currently not meant to be set',
'textconsole' => 'Tracks the Psuedo-TTY that maps to the serial port or console of a VM',
'powerstate' => "This flag is used by xCAT to track the last known power state of the VM.",

View File

@ -20,6 +20,8 @@ use IO::Select;
use strict;
#use warnings;
my $use_xhrm=0; #xCAT Hypervisor Resource Manager, to satisfy networking and storage prerequisites, default to not using it for the moment
my $imgfmt='raw'; #use raw format by default
my $clonemethod='qemu-img'; #use qemu-img command
my %vm_comm_pids;
my %offlinehyps;
my %offlinevms;
@ -85,15 +87,7 @@ sub get_path_for_nfsuri {
my $path = $2;
print $diskname." $server $path \n";
if (xCAT::Utils::thishostisnot($server)) {
my $foundmount;
my @mounts = `mount`;
foreach (@mounts) {
if (/^$server:$path/) {
s/ on (\S*) type nfs/$1/;
return $_;
}
}
die "$diskname must be mounted on the xCAT server for this operation"; #TODO: correctly return
return [$server,$path];
} else { #I am the server
return $path;
}
@ -574,6 +568,7 @@ sub getpowstate {
sub xhrm_satisfy {
my $node = shift;
my $hyp = shift;
my $rc=0;
my @nics=();
my @storage=();
if ($vmhash->{$node}->[0]->{nics}) {
@ -584,13 +579,14 @@ sub xhrm_satisfy {
}
foreach (@nics) {
s/=.*//; #this code cares not about the model of virtual nic
system("ssh $hyp xHRM bridgeprereq $_");
$rc |=system("ssh $hyp xHRM bridgeprereq $_");
}
foreach (@storage) {
if (/^nfs:\/\//) {
system("ssh $hyp xHRM storageprereq $_");
$rc |= system("ssh $hyp xHRM storageprereq $_");
}
}
return $rc;
}
sub makedom {
my $node=shift;
@ -614,25 +610,97 @@ sub createstorage {
my $filename=shift;
my $mastername=shift;
my $size=shift;
my $cfginfo = shift;
my $force = shift;
my $diskstruct = shift;
my $node = $cfginfo->{node};
my @flags = split /,/,$cfginfo->{virtflags};
foreach (@flags) {
if (/^imageformat=(.*)\z/) {
$imgfmt=$1;
} elsif (/^clonemethod=(.*)\z/) {
$clonemethod=$1;
}
}
my $mountpath;
my $storageserver;
#for nfs paths and qemu-img, we do the magic locally only for now
if ($filename =~ /^nfs:/) {
$filename = get_path_for_nfsuri($filename);
if (ref $filename) { #if we got a reference back instead of a string, it is a remote location
$storageserver = $filename->[0];
$filename = $filename->[1];
}
$mountpath = $filename;
$filename .= "/$node/".fileparse($diskstruct->[0]->{source}->{file});
}
my $basename;
my $dirname;
($basename,$dirname) = fileparse($filename);
mkpath($dirname);
unless ($storageserver) {
if (-f $filename) {
unless ($force) {
return 1,"Storage already exists, delete manually or use --force";
}
unlink $filename;
}
}
if ($storageserver and $mastername and $clonemethod eq 'reflink') {
my $rc=system("ssh $storageserver mkdir -p $dirname");
if ($rc) {
return 1,"Unable to manage storage on remote server $storageserver";
}
} elsif ($storageserver) {
my @mounts = `mount`;
my $foundmount;
foreach (@mounts) {
if (/^$storageserver:$mountpath/) {
s/ on (\S*) type nfs/$1/;
$dirname = $_;
mkpath($dirname);
$foundmount=1;
last;
}
}
unless ($foundmount) {
return 1,"qemu-img cloning requires that the management server have the directory $mountpath from $storageserver mounted";
}
} else {
mkpath($dirname);
}
if ($mastername and $size) {
return 1,"Can not specify both a master to clone and a size";
}
my $masterserver;
if ($mastername) {
unless ($mastername =~ /^\//) {
unless ($mastername =~ /^\// or $mastername =~ /^nfs:/) {
$mastername = $xCAT_plugin::kvm::masterdir.'/'.$mastername;
}
chdir($dirname);
my $rc=system("qemu-img create -f qcow2 -b $mastername $filename");
if ($mastername =~ m!nfs://([^/]*)(/.*\z)!) {
$mastername = $2;
$masterserver = $1;
}
if ($masterserver ne $storageserver) {
return 1,"Not supporting cloning between $masterserver and $storageserver at this time, for now ensure master images and target VM images are on the same server";
}
my $rc;
if ($clonemethod eq 'qemu-img') {
$rc=system("qemu-img create -f qcow2 -b $mastername $filename");
} elsif ($clonemethod eq 'reflink') {
if ($storageserver) {
$rc=system("ssh $storageserver cp --reflink $mastername $filename");
} else {
$rc=system("cp --reflink $mastername $filename");
}
}
if ($rc) {
return $rc,"Failure creating image $filename from $mastername";
}
}
if ($size) {
my $rc = system("qemu-img create -f qcow2 $filename ".getUnits($size,"g",1024));
my $rc = system("qemu-img create -f $imgfmt $filename ".getUnits($size,"g",1024));
if ($rc) {
return $rc,"Failure creating image $filename of size $size\n";
}
@ -661,24 +729,9 @@ sub mkvm {
if ($mastername or $disksize) {
return 1,"mkvm management of block device storage not implemented";
}
} elsif ($diskname =~ /^nfs:/) {
$diskname = get_path_for_nfsuri($diskname)."/$node/".fileparse($diskstruct->[0]->{source}->{file});
}
if (-f $diskname) {
if ($mastername or $disksize) {
if ($force) {
unlink $diskname;
} else {
return 1,"Storage already exists, delete manually or use --force";
}
createstorage($diskname,$mastername,$disksize);
}
} else {
if ($mastername or $disksize) {
createstorage($diskname,$mastername,$disksize);
} else {
#TODO: warn they may have no disk? the mgt may not have visibility....
}
if ($mastername or $disksize) {
return createstorage($diskname,$mastername,$disksize,$vmhash->{$node}->[0],$force,$diskstruct);
}
} else {
if ($mastername or $disksize) {
@ -710,7 +763,9 @@ sub power {
if ($subcommand eq 'on') {
unless ($dom) {
if ($use_xhrm) {
xhrm_satisfy($node,$hyp);
if (xhrm_satisfy($node,$hyp)) {
return (1,"Failure satisfying networking and storage requirements on $hyp for $node");
}
}
($dom,$errstr) = makedom($node,$cdloc);
if ($errstr) { return (1,$errstr); }