Matthew Booth
2010-Mar-31 10:26 UTC
[Libguestfs] [PATCH] Add LocalCopy transfer method to transfer local files to a target
Also changes command line parsing to require a pool to be specified when using libvirt output, meaning storage will always be copied. --- MANIFEST | 1 + lib/Sys/VirtV2V/Connection.pm | 74 +++++++++--------- lib/Sys/VirtV2V/Connection/LibVirt.pm | 18 +++-- lib/Sys/VirtV2V/Connection/LibVirtXML.pm | 11 ++- lib/Sys/VirtV2V/Target/LibVirt.pm | 18 ++--- lib/Sys/VirtV2V/Transfer/ESX.pm | 7 +- lib/Sys/VirtV2V/Transfer/LocalCopy.pm | 121 ++++++++++++++++++++++++++++++ v2v/virt-v2v.pl | 7 ++- 8 files changed, 193 insertions(+), 64 deletions(-) create mode 100644 lib/Sys/VirtV2V/Transfer/LocalCopy.pm diff --git a/MANIFEST b/MANIFEST index 1bc6018..d5debe1 100644 --- a/MANIFEST +++ b/MANIFEST @@ -15,6 +15,7 @@ lib/Sys/VirtV2V/UserMessage.pm lib/Sys/VirtV2V/Target/LibVirt.pm lib/Sys/VirtV2V/Target/RHEV.pm lib/Sys/VirtV2V/Transfer/ESX.pm +lib/Sys/VirtV2V/Transfer/LocalCopy.pm MANIFEST This list of files MANIFEST.SKIP META.yml diff --git a/lib/Sys/VirtV2V/Connection.pm b/lib/Sys/VirtV2V/Connection.pm index 5ecc7e3..5b4ed8d 100644 --- a/lib/Sys/VirtV2V/Connection.pm +++ b/lib/Sys/VirtV2V/Connection.pm @@ -22,10 +22,12 @@ use warnings; use Sys::Virt; -use Locale::TextDomain 'virt-v2v'; - +use Sys::VirtV2V::Transfer::ESX; +use Sys::VirtV2V::Transfer::LocalCopy; use Sys::VirtV2V::UserMessage qw(user_message); +use Locale::TextDomain 'virt-v2v'; + =pod =head1 NAME @@ -134,41 +136,39 @@ sub _storage_iterate else { my $path = $source->getValue(); - if (defined($transfer)) { - # Die if transfer required and no output target - die (user_message(__"No output target was specified")) - unless (defined($target)); - - # Fetch the remote storage - my $vol = $transfer->transfer($self, $path, $target); - - # Export the new path - $path = $vol->get_path(); - - # Find any existing driver element. - my ($driver) = $disk->findnodes('driver'); - - # Create a new driver element if none exists - unless (defined($driver)) { - $driver - $disk->getOwnerDocument()->createElement("driver"); - $disk->appendChild($driver); - } - $driver->setAttribute('name', 'qemu'); - $driver->setAttribute('type', $vol->get_format()); - - # Remove the @file or @dev attribute before adding a new one - $source_e->removeAttributeNode($source); - - # Set @file or @dev as appropriate - if ($vol->is_block()) - { - $disk->setAttribute('type', 'block'); - $source_e->setAttribute('dev', $path); - } else { - $disk->setAttribute('type', 'file'); - $source_e->setAttribute('file', $path); - } + # Die if transfer required and no output target + die (user_message(__"No output target was specified")) + unless (defined($target)); + + # Fetch the remote storage + my $vol = $transfer->transfer($self, $path, $target); + + # Export the new path + $path = $vol->get_path(); + + # Find any existing driver element. + my ($driver) = $disk->findnodes('driver'); + + # Create a new driver element if none exists + unless (defined($driver)) { + $driver + $disk->getOwnerDocument()->createElement("driver"); + $disk->appendChild($driver); + } + $driver->setAttribute('name', 'qemu'); + $driver->setAttribute('type', $vol->get_format()); + + # Remove the @file or @dev attribute before adding a new one + $source_e->removeAttributeNode($source); + + # Set @file or @dev as appropriate + if ($vol->is_block()) + { + $disk->setAttribute('type', 'block'); + $source_e->setAttribute('dev', $path); + } else { + $disk->setAttribute('type', 'file'); + $source_e->setAttribute('file', $path); } push(@paths, $path); diff --git a/lib/Sys/VirtV2V/Connection/LibVirt.pm b/lib/Sys/VirtV2V/Connection/LibVirt.pm index 2c289b9..43fe624 100644 --- a/lib/Sys/VirtV2V/Connection/LibVirt.pm +++ b/lib/Sys/VirtV2V/Connection/LibVirt.pm @@ -30,7 +30,6 @@ use XML::DOM; use Sys::Virt; use Sys::VirtV2V; -use Sys::VirtV2V::Transfer::ESX; use Sys::VirtV2V::UserMessage qw(user_message); use Locale::TextDomain 'virt-v2v'; @@ -46,7 +45,7 @@ Sys::VirtV2V::Connection::LibVirt - Read libvirt metadata from libvirtd use Sys::VirtV2V::Connection::LibVirt; $conn = Sys::VirtV2V::Connection::LibVirt->new - ("xen+ssh://xenserver.example.com/", $name, $pool); + ("xen+ssh://xenserver.example.com/", $name, $target); $dom = $conn->get_dom(); =head1 DESCRIPTION @@ -59,11 +58,10 @@ libvirt connection. =over -=item new(uri, name, pool) +=item new(uri, name, target) Create a new Sys::VirtV2V::Connection::LibVirt. Domain I<name> will be -obtained from I<uri>. Remote storage will be copied to a new volume, which -will be created in I<pool>. +obtained from I<uri>. Remote storage will be create on I<target>. =cut @@ -71,7 +69,7 @@ sub new { my $class = shift; - my ($uri, $name, $pool) = @_; + my ($uri, $name, $target) = @_; my $self = {}; @@ -151,7 +149,13 @@ sub new $transfer = "Sys::VirtV2V::Transfer::ESX"; } - $self->_storage_iterate($transfer, $pool); + # Default to LocalCopy + # XXX: Need transfer methods for remote libvirt connections, e.g. scp + else { + $transfer = "Sys::VirtV2V::Transfer::LocalCopy"; + } + + $self->_storage_iterate($transfer, $target); return $self; } diff --git a/lib/Sys/VirtV2V/Connection/LibVirtXML.pm b/lib/Sys/VirtV2V/Connection/LibVirtXML.pm index 03b85b1..0ce07fd 100644 --- a/lib/Sys/VirtV2V/Connection/LibVirtXML.pm +++ b/lib/Sys/VirtV2V/Connection/LibVirtXML.pm @@ -39,7 +39,7 @@ Sys::VirtV2V::Connection::LibVirtXML - Read libvirt XML from a file use Sys::VirtV2V::Connection::LibVirtXML; - $conn = Sys::VirtV2V::Connection::LibVirtXML->new($path); + $conn = Sys::VirtV2V::Connection::LibVirtXML->new($path, $target); $dom = $conn->get_dom(); =head1 DESCRIPTION @@ -52,9 +52,10 @@ file. =over -=item new(path) +=item new(path, target) Create a new LibVirtXML connection. The metadata itself is read from I<path>. +Storage will be copied to I<target>. =cut @@ -62,7 +63,7 @@ sub new { my $class = shift; - my ($path) = @_; + my ($path, $target) = @_; my $self = {}; $self->{path} = $path; @@ -71,8 +72,8 @@ sub new $self->_get_dom($path); - # No transfer methods defined yet - $self->_storage_iterate(undef, undef); + # Only support LocalCopy for libvirtxml + $self->_storage_iterate("Sys::VirtV2V::Transfer::LocalCopy", $target); return $self; } diff --git a/lib/Sys/VirtV2V/Target/LibVirt.pm b/lib/Sys/VirtV2V/Target/LibVirt.pm index 96ed513..ab95fb7 100644 --- a/lib/Sys/VirtV2V/Target/LibVirt.pm +++ b/lib/Sys/VirtV2V/Target/LibVirt.pm @@ -186,16 +186,14 @@ sub new $self->{vmm} = Sys::Virt->new(auth => 1, uri => $uri); - if (defined($poolname)) { - eval { - $self->{pool} = $self->{vmm}->get_storage_pool_by_name($poolname); - }; - - if ($@) { - die(user_message(__x("Output pool {poolname} is not a valid ". - "storage pool", - poolname => $poolname))); - } + eval { + $self->{pool} = $self->{vmm}->get_storage_pool_by_name($poolname); + }; + + if ($@) { + die(user_message(__x("Output pool {poolname} is not a valid ". + "storage pool", + poolname => $poolname))); } return $self; diff --git a/lib/Sys/VirtV2V/Transfer/ESX.pm b/lib/Sys/VirtV2V/Transfer/ESX.pm index 42b4326..9db28e0 100644 --- a/lib/Sys/VirtV2V/Transfer/ESX.pm +++ b/lib/Sys/VirtV2V/Transfer/ESX.pm @@ -120,10 +120,9 @@ sub get_volume my $target = $self->{_v2v_target}; if ($target->volume_exists($volname)) { print STDERR user_message(__x("WARNING: storage volume {name} ". - "already exists in the target ". - "pool. NOT fetching it again. ". - "Delete the volume and retry to ". - "download again.", + "already exists on the target. NOT ". + "fetching it again. Delete the volume ". + "and retry to download again.", name => $volname)); return $target->get_volume($volname); } diff --git a/lib/Sys/VirtV2V/Transfer/LocalCopy.pm b/lib/Sys/VirtV2V/Transfer/LocalCopy.pm new file mode 100644 index 0000000..814bf4a --- /dev/null +++ b/lib/Sys/VirtV2V/Transfer/LocalCopy.pm @@ -0,0 +1,121 @@ +# Sys::VirtV2V::Transfer::LocalCopy +# Copyright (C) 2010 Red Hat Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +package Sys::VirtV2V::Transfer::LocalCopy; + +use File::Spec; +use File::stat; + +use Sys::VirtV2V::UserMessage qw(user_message); + +use Locale::TextDomain 'virt-v2v'; + +=pod + +=head1 NAME + +Sys::VirtV2V::Transfer::LocalCopy - Copy a guest's local storage + +=head1 SYNOPSIS + + use Sys::VirtV2V::Transfer::LocalCopy; + + $vol = Sys::VirtV2V::Transfer::LocalCopy->transfer($conn, $path, $target); + +=head1 DESCRIPTION + +Sys::VirtV2V::Transfer::LocalCopy retrieves guest storage devices from local +storage. + +=head1 METHODS + +=over + +=item transfer(conn, path, target) + +Transfer <path> from local storage. Storage will be created using <target>. + +=cut + +sub transfer +{ + my $class = shift; + + my ($conn, $path, $target) = @_; + + my (undef, undef, $name) = File::Spec->splitpath($path); + + if ($target->volume_exists($name)) { + print STDERR user_message(__x("WARNING: storage volume {name} ". + "already exists on the target. NOT ". + "copying it again. Delete the volume ". + "and retry to copy again.", + name => $name)); + return $target->get_volume($name); + } + + my $fh; + open($fh, '<', $path) + or die(user_message(__x("Unable to open {path} for reading: {error}", + path => $path, + error => $!))); + + my $st = stat($fh) + or die(user_message(__x("Unable to stat {path}: {error}", + path => $path, + error => $!))); + + my $vol = $target->create_volume($name, $st->size); + $vol->open(); + + for (;;) { + my $buffer; + # Transfer in block chunks + my $in = sysread($fh, $buffer, $st->blksize); + die(user_message(__x("Error reading data from {path}: {error}", + path => $path, + error => $!))) if (!defined($in)); + + last if ($in == 0); + + $vol->write($buffer); + } + + $vol->close(); + + return $vol; +} + +=back + +=head1 COPYRIGHT + +Copyright (C) 2010 Red Hat Inc. + +=head1 LICENSE + +Please see the file COPYING.LIB for the full license. + +=head1 SEE ALSO + +L<Sys::VirtV2V::Converter(3pm)>, +L<virt-v2v(1)>, +L<http://libguestfs.org/>. + +=cut + +1; diff --git a/v2v/virt-v2v.pl b/v2v/virt-v2v.pl index 351caf1..c1a4728 100755 --- a/v2v/virt-v2v.pl +++ b/v2v/virt-v2v.pl @@ -225,6 +225,11 @@ if(defined($config_file)) { my $target; if ($output_method eq "libvirt") { + pod2usage({ -message => __("You must specify an output storage pool ". + "when using the libvirt output method"), + -exitval => 1 }) + unless (defined($output_pool)); + $target = new Sys::VirtV2V::Target::LibVirt($output_uri, $output_pool); } @@ -257,7 +262,7 @@ eval { modulename => 'libvirtxml')); } - $conn = Sys::VirtV2V::Connection::LibVirtXML->new($path); + $conn = Sys::VirtV2V::Connection::LibVirtXML->new($path, $target); } elsif ($input_method eq "libvirt") { -- 1.6.6.1
Richard W.M. Jones
2010-Apr-01 13:43 UTC
[Libguestfs] [PATCH] Add LocalCopy transfer method to transfer local files to a target
On Wed, Mar 31, 2010 at 11:26:33AM +0100, Matthew Booth wrote:> Also changes command line parsing to require a pool to be specified when using > libvirt output, meaning storage will always be copied. > --- > MANIFEST | 1 + > lib/Sys/VirtV2V/Connection.pm | 74 +++++++++--------- > lib/Sys/VirtV2V/Connection/LibVirt.pm | 18 +++-- > lib/Sys/VirtV2V/Connection/LibVirtXML.pm | 11 ++- > lib/Sys/VirtV2V/Target/LibVirt.pm | 18 ++--- > lib/Sys/VirtV2V/Transfer/ESX.pm | 7 +- > lib/Sys/VirtV2V/Transfer/LocalCopy.pm | 121 ++++++++++++++++++++++++++++++ > v2v/virt-v2v.pl | 7 ++- > 8 files changed, 193 insertions(+), 64 deletions(-) > create mode 100644 lib/Sys/VirtV2V/Transfer/LocalCopy.pmYes, this change makes sense, ACK. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones libguestfs lets you edit virtual machines. Supports shell scripting, bindings from many languages. http://et.redhat.com/~rjones/libguestfs/ See what it can do: http://et.redhat.com/~rjones/libguestfs/recipes.html
Possibly Parallel Threads
- [PATCH 1/2] Refactor guest and volume creation into Sys::VirtV2V::Target::LibVirt
- [PREVIEW ONLY] Refactor data transfer code
- [PATCH] Improve error message when LibvirtXML is given invalid domain XML
- [PATCH] Remove v2v-snapshot
- [PATCH] Connection: Handle case of cdrom with no <source> element