The following patches are where I'm currently at with ESX support. I can now import a domain from ESX along with its storage. Note that I'm not yet doing any conversion. In fact, I've never even tested past the import stage (I just had an exit in there). The meat is really in the 4th patch. The rename of MetadataReader->Connection was because the Connection is now really providing the whole guest, rather than just its metadata. I intend to add more transfer methods once ESX conversion is working. A copy method for LibVirtXML is required at least. _storage_iterate in Sys::VirtV2V::Connection does interesting things with the domain's storage devices. I'd especially appreciate a close look there. Matt
Matthew Booth
2010-Jan-29 18:05 UTC
[Libguestfs] [PATCH 1/4] LibVirt: Fix typo in user message
--- lib/Sys/VirtV2V/MetadataReader/LibVirt.pm | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/lib/Sys/VirtV2V/MetadataReader/LibVirt.pm b/lib/Sys/VirtV2V/MetadataReader/LibVirt.pm index 0d6fb31..d18f432 100644 --- a/lib/Sys/VirtV2V/MetadataReader/LibVirt.pm +++ b/lib/Sys/VirtV2V/MetadataReader/LibVirt.pm @@ -84,7 +84,7 @@ sub _handle_args # Warn if we were given more than 1 argument if(scalar(@_) > 0) { print STDERR user_message - (__x("WARNING: {modulename} only takes a single filename.", + (__x("WARNING: {modulename} only takes a single domain name.", modulename => NAME)); } } -- 1.6.6
Matthew Booth
2010-Jan-29 18:05 UTC
[Libguestfs] [PATCH 2/4] MetadataReader: Allow different libvirt connections for input and output
Command line option changes: --config -> -c -c -> -ic New option -oc specifies output connection. --- lib/Sys/VirtV2V/MetadataReader.pm | 20 ++++---- lib/Sys/VirtV2V/MetadataReader/LibVirt.pm | 9 +++- lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm | 5 +- v2v/virt-v2v.pl | 66 +++++++++++++++----------- 4 files changed, 59 insertions(+), 41 deletions(-) diff --git a/lib/Sys/VirtV2V/MetadataReader.pm b/lib/Sys/VirtV2V/MetadataReader.pm index 6a1bec3..7b5e7d5 100644 --- a/lib/Sys/VirtV2V/MetadataReader.pm +++ b/lib/Sys/VirtV2V/MetadataReader.pm @@ -36,7 +36,9 @@ Sys::VirtV2V::MetadataReader - Read a variety of guest metadata formats use Sys::VirtV2V::MetadataReader; - $reader = Sys::VirtV2V::MetadataReader->instantiate("libvirtxml", $vmm, @args); + $reader = Sys::VirtV2V::MetadataReader->instantiate("libvirtxml", $uri, + $config, @args); + exit 1 unless($mdr->is_configured()); $dom = $reader->get_dom(); =head1 DESCRIPTION @@ -53,7 +55,7 @@ implements methods to access backends. =over -=item instantiate(name, vmm, @args) +=item instantiate(name, $uri, $config, @args) =over @@ -61,13 +63,13 @@ implements methods to access backends. The name of the module to instantiate. -=item config +=item uri -A parsed virt-v2v configuration file. +A URI describing the target connection. -=item vmm +=item config -A Sys::Virt connection. +A parsed virt-v2v configuration file. =item args @@ -83,15 +85,15 @@ sub instantiate { my $class = shift; - my ($name, $config, $vmm, @args) = @_; + my ($name, $uri, $config, @args) = @_; defined($name) or carp("instantiate called without name argument"); + defined($uri) or carp("instantiate called without uri argument"); defined($config) or carp("instantiate called without config argument"); - defined($vmm) or carp("instantiate called without vmm argument"); foreach my $module ($class->modules()) { if($module->get_name() eq $name) { - return $module->_new($config->{$name}, $vmm, @args); + return $module->_new($uri, $config->{$name}, @args); } } diff --git a/lib/Sys/VirtV2V/MetadataReader/LibVirt.pm b/lib/Sys/VirtV2V/MetadataReader/LibVirt.pm index d18f432..e6fcfff 100644 --- a/lib/Sys/VirtV2V/MetadataReader/LibVirt.pm +++ b/lib/Sys/VirtV2V/MetadataReader/LibVirt.pm @@ -38,7 +38,8 @@ Sys::VirtV2V::MetadataReader::LibVirt - Read libvirt metadata from libvirtd use Sys::VirtV2V::MetadataReader; - $reader = Sys::VirtV2V::MetadataReader->instantiate("libvirt", $vmm, @args); + $reader = Sys::VirtV2V::MetadataReader->instantiate + ("libvirt", "xen+ssh://xenserver.example.com/", $config, @args); $dom = $reader->get_dom(); =head1 DESCRIPTION @@ -62,12 +63,16 @@ sub _new { my $class = shift; - my ($config, $vmm, @args) = @_; + my ($uri, $config, @args) = @_; my $self = {}; bless($self, $class); + my @vmm_params = (auth => 1); + push(@vmm_params, url => $uri) if defined($uri); + my $vmm = Sys::Virt->new(@vmm_params); + $self->{vmm} = $vmm; $self->_handle_args(@args); diff --git a/lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm b/lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm index 877b7e5..191210f 100644 --- a/lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm +++ b/lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm @@ -37,7 +37,8 @@ Sys::VirtV2V::MetadataReader::LibVirtXML - Read libvirt XML from a file use Sys::VirtV2V::MetadataReader; - $reader = Sys::VirtV2V::MetadataReader->instantiate("libvirtxml", $vmm, @args); + $reader = Sys::VirtV2V::MetadataReader->instantiate("libvirtxml", undef, + $config, @args); $dom = $reader->get_dom(); =head1 DESCRIPTION @@ -61,7 +62,7 @@ sub _new { my $class = shift; - my ($config, $vmm, @args) = @_; + my ($uri, $config, @args) = @_; my %obj = (); my $self = \%obj; diff --git a/v2v/virt-v2v.pl b/v2v/virt-v2v.pl index 0ad3c6e..1784f2a 100755 --- a/v2v/virt-v2v.pl +++ b/v2v/virt-v2v.pl @@ -46,9 +46,9 @@ virt-v2v - Convert a guest to use KVM virt-v2v guest-domain.xml - virt-v2v -s virt-v2v.conf guest-domain.xml + virt-v2v -c virt-v2v.conf guest-domain.xml - virt-v2v --connect qemu:///system guest-domain.xml + virt-v2v -ic qemu:///system guest-domain =head1 DESCRIPTION @@ -128,21 +128,12 @@ Display version number and exit. =cut -my $uri; +my $input_method = "libvirt"; -=item B<--connect URI> | B<-c URI> +=item B<-i input> -Connect to libvirt using the given I<URI>. If omitted, then we connect to the -default libvirt hypervisor. - -=cut - -my $input = "libvirt"; - -=item B<--input input> | B<-i input> - -The specified guest description uses the given I<input format>. The default is -C<libvirt>. Supported options are: +Specifies how the conversion source metadata can be obtained. The default is +C<libvirt>. Supported options are: =over @@ -158,9 +149,27 @@ Guest argument is the path to an XML file describing a libvirt domain. =cut +my $input_uri; + +=item B<-ic URI> + +Specifies the connection to use when using the libvirt input method. If omitted, +then we connect to the default libvirt hypervisor. + +=cut + +my $output_uri = "qemu:///system"; + +=item B<-oc URI> + +Specifies the libvirt connection to use to create the converted guest. If +ommitted, this defaults to qemu:///system. + +=cut + my $config_file; -=item B<--config file> | B<-s file> +=item B<-c file> Load the virt-v2v configuration from I<file>. There is no default. @@ -173,9 +182,10 @@ Sys::VirtV2V::UserMessage->set_identifier('virt-v2v'); GetOptions ("help|?" => \$help, "version" => \$version, - "connect|c=s" => \$uri, - "input|i=s" => \$input, - "config|s=s" => \$config_file + "i=s" => \$input_method, + "ic=s" => \$input_uri, + "oc=s" => \$output_uri, + "c=s" => \$config_file ) or pod2usage(2); pod2usage(0) if($help); @@ -186,11 +196,6 @@ if ($version) { pod2usage(user_message(__"no guest argument given")) if @ARGV == 0; -# Connect to libvirt -my @vmm_params = (auth => 1); -push(@vmm_params, uri => $uri) if(defined($uri)); -my $vmm = Sys::Virt->new(@vmm_params); - # Read the config file if one was given my $config = {}; if(defined($config_file)) { @@ -206,11 +211,11 @@ if(defined($config_file)) { } # Get an appropriate MetadataReader -my $mdr = Sys::VirtV2V::MetadataReader->instantiate($input, $config, - $vmm, @ARGV); +my $mdr = Sys::VirtV2V::MetadataReader->instantiate($input_method, $input_uri, + $config, @ARGV); if(!defined($mdr)) { - print STDERR user_message __x("{input} is not a valid metadata format", - input => $input); + print STDERR user_message __x("{input} is not a valid input method", + input => $input_method); exit(1); } @@ -239,6 +244,11 @@ my $os = inspect_guest($g); # Instantiate a GuestOS instance to manipulate the guest my $guestos = Sys::VirtV2V::GuestOS->instantiate($g, $os); +# Connect to target libvirt +my @vmm_params = (auth => 1); +push(@vmm_params, uri => $output_uri) if(defined($output_uri)); +my $vmm = Sys::Virt->new(@vmm_params); + # Modify the guest and its metadata for the target hypervisor Sys::VirtV2V::Converter->convert($vmm, $guestos, $dom, $os); -- 1.6.6
Matthew Booth
2010-Jan-29 18:05 UTC
[Libguestfs] [PATCH 3/4] Connection: Rename MetadataReader to Connection
--- MANIFEST | 6 ++-- lib/Sys/VirtV2V.pm | 2 +- .../VirtV2V/{MetadataReader.pm => Connection.pm} | 22 ++++++++-------- .../{MetadataReader => Connection}/LibVirt.pm | 26 ++++++++++---------- .../{MetadataReader => Connection}/LibVirtXML.pm | 26 ++++++++++---------- po/POTFILES.in | 6 ++-- po/es.po | 16 ++++++------ po/fr.po | 16 ++++++------ po/it.po | 16 ++++++------ po/pl.po | 16 ++++++------ po/ru.po | 16 ++++++------ po/virt-v2v.pot | 16 ++++++------ po/zh_CN.po | 16 ++++++------ snapshot/v2v-snapshot.pl | 6 ++-- v2v/virt-v2v.pl | 8 +++--- 15 files changed, 107 insertions(+), 107 deletions(-) rename lib/Sys/VirtV2V/{MetadataReader.pm => Connection.pm} (80%) rename lib/Sys/VirtV2V/{MetadataReader => Connection}/LibVirt.pm (84%) rename lib/Sys/VirtV2V/{MetadataReader => Connection}/LibVirtXML.pm (85%) diff --git a/MANIFEST b/MANIFEST index 8603430..7bfad76 100644 --- a/MANIFEST +++ b/MANIFEST @@ -8,9 +8,9 @@ lib/Sys/VirtV2V/GuestOS.pm lib/Sys/VirtV2V/GuestOS/RedHat.pm lib/Sys/VirtV2V/Converter.pm lib/Sys/VirtV2V/Converter/Linux.pm -lib/Sys/VirtV2V/MetadataReader.pm -lib/Sys/VirtV2V/MetadataReader/LibVirt.pm -lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm +lib/Sys/VirtV2V/Connection.pm +lib/Sys/VirtV2V/Connection/LibVirt.pm +lib/Sys/VirtV2V/Connection/LibVirtXML.pm lib/Sys/VirtV2V/UserMessage.pm MANIFEST This list of files MANIFEST.SKIP diff --git a/lib/Sys/VirtV2V.pm b/lib/Sys/VirtV2V.pm index a8731af..f74f347 100644 --- a/lib/Sys/VirtV2V.pm +++ b/lib/Sys/VirtV2V.pm @@ -64,7 +64,7 @@ L<v2v-snapshot(1)>, L<Sys::VirtV2V::GuestOS(3pm)>, L<Sys::VirtV2V::HVSource(3pm)>, L<Sys::VirtV2V::Converter(3pm)>, -L<Sys::VirtV2V::MetadataReader(3pm)>, +L<Sys::VirtV2V::Connection(3pm)>, L<http://libguestfs.org/> =cut diff --git a/lib/Sys/VirtV2V/MetadataReader.pm b/lib/Sys/VirtV2V/Connection.pm similarity index 80% rename from lib/Sys/VirtV2V/MetadataReader.pm rename to lib/Sys/VirtV2V/Connection.pm index 7b5e7d5..31fbdb3 100644 --- a/lib/Sys/VirtV2V/MetadataReader.pm +++ b/lib/Sys/VirtV2V/Connection.pm @@ -1,4 +1,4 @@ -# Sys::VirtV2V::MetadataReader +# Sys::VirtV2V::Connection # Copyright (C) 2009 Red Hat Inc. # # This library is free software; you can redistribute it and/or @@ -15,13 +15,13 @@ # 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::MetadataReader; +package Sys::VirtV2V::Connection; use strict; use warnings; use Module::Pluggable sub_name => 'modules', - search_path => ['Sys::VirtV2V::MetadataReader'], + search_path => ['Sys::VirtV2V::Connection'], require => 1; use Carp; @@ -30,25 +30,25 @@ use Carp; =head1 NAME -Sys::VirtV2V::MetadataReader - Read a variety of guest metadata formats +Sys::VirtV2V::Connection - Read a variety of guest metadata formats =head1 SYNOPSIS - use Sys::VirtV2V::MetadataReader; + use Sys::VirtV2V::Connection; - $reader = Sys::VirtV2V::MetadataReader->instantiate("libvirtxml", $uri, + $reader = Sys::VirtV2V::Connection->instantiate("libvirtxml", $uri, $config, @args); exit 1 unless($mdr->is_configured()); $dom = $reader->get_dom(); =head1 DESCRIPTION -Sys::VirtV2V::MetadataReader reads the metadata of a, possibly foreign, +Sys::VirtV2V::Connection reads the metadata of a, possibly foreign, guest. It provides the DOM representation of an equivalent libvirt XML representation. -Sys::VirtV2V::MetadataReader is an interface to various backends, each of -which implement a consistent API. Sys::VirtV2V::MetadataReader itself only +Sys::VirtV2V::Connection is an interface to various backends, each of +which implement a consistent API. Sys::VirtV2V::Connection itself only implements methods to access backends. =head1 METHODS @@ -134,8 +134,8 @@ Please see the file COPYING.LIB for the full license. =head1 SEE ALSO -L<Sys::VirtV2V::MetadataReader::LibVirt(3pm)>, -L<Sys::VirtV2V::MetadataReader::LibVirtXML(3pm)>, +L<Sys::VirtV2V::Connection::LibVirt(3pm)>, +L<Sys::VirtV2V::Connection::LibVirtXML(3pm)>, L<virt-v2v(1)>, L<v2v-snapshot(1)>, L<http://libguestfs.org/>. diff --git a/lib/Sys/VirtV2V/MetadataReader/LibVirt.pm b/lib/Sys/VirtV2V/Connection/LibVirt.pm similarity index 84% rename from lib/Sys/VirtV2V/MetadataReader/LibVirt.pm rename to lib/Sys/VirtV2V/Connection/LibVirt.pm index e6fcfff..d3aa80d 100644 --- a/lib/Sys/VirtV2V/MetadataReader/LibVirt.pm +++ b/lib/Sys/VirtV2V/Connection/LibVirt.pm @@ -1,4 +1,4 @@ -# Sys::VirtV2V::MetadataReader::LibVirt +# Sys::VirtV2V::Connection::LibVirt # Copyright (C) 2009 Red Hat Inc. # # This library is free software; you can redistribute it and/or @@ -15,7 +15,7 @@ # 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::MetadataReader::LibVirt; +package Sys::VirtV2V::Connection::LibVirt; use strict; use warnings; @@ -32,25 +32,25 @@ use Locale::TextDomain 'virt-v2v'; =head1 NAME -Sys::VirtV2V::MetadataReader::LibVirt - Read libvirt metadata from libvirtd +Sys::VirtV2V::Connection::LibVirt - Read libvirt metadata from libvirtd =head1 SYNOPSIS - use Sys::VirtV2V::MetadataReader; + use Sys::VirtV2V::Connection; - $reader = Sys::VirtV2V::MetadataReader->instantiate + $reader = Sys::VirtV2V::Connection->instantiate ("libvirt", "xen+ssh://xenserver.example.com/", $config, @args); $dom = $reader->get_dom(); =head1 DESCRIPTION -Sys::VirtV2V::MetadataReader::LibVirt is a backend for -Sys::VirtV2V::MetadataReader which reads a guest's libvirt XML directly from a +Sys::VirtV2V::Connection::LibVirt is a backend for +Sys::VirtV2V::Connection which reads a guest's libvirt XML directly from a libvirt connection. =head1 METHODS -See BACKEND INTERFACE in L<Sys::VirtV2V::MetadataReader> for a detailed +See BACKEND INTERFACE in L<Sys::VirtV2V::Connection> for a detailed description of its exported methods. =over @@ -94,9 +94,9 @@ sub _handle_args } } -=item Sys::VirtV2V::MetadataReader::LibVirtXML->get_name() +=item Sys::VirtV2V::Connection::LibVirtXML->get_name() -See BACKEND INTERFACE in L<Sys::VirtV2V::MetadataReader> for details. +See BACKEND INTERFACE in L<Sys::VirtV2V::Connection> for details. =cut @@ -109,7 +109,7 @@ sub get_name =item is_configured() -See BACKEND INTERFACE in L<Sys::VirtV2V::MetadataReader> for details. +See BACKEND INTERFACE in L<Sys::VirtV2V::Connection> for details. =cut @@ -183,7 +183,7 @@ sub _get_domain =item get_dom() -See BACKEND INTERFACE in L<Sys::VirtV2V::MetadataReader> for details. +See BACKEND INTERFACE in L<Sys::VirtV2V::Connection> for details. =cut @@ -216,7 +216,7 @@ Please see the file COPYING.LIB for the full license. =head1 SEE ALSO -L<Sys::VirtV2V::MetadataReader(3)>, +L<Sys::VirtV2V::Connection(3)>, L<virt-v2v(1)>, L<v2v-snapshot(1)>, L<http://libguestfs.org/>. diff --git a/lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm b/lib/Sys/VirtV2V/Connection/LibVirtXML.pm similarity index 85% rename from lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm rename to lib/Sys/VirtV2V/Connection/LibVirtXML.pm index 191210f..c05aa0f 100644 --- a/lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm +++ b/lib/Sys/VirtV2V/Connection/LibVirtXML.pm @@ -1,4 +1,4 @@ -# Sys::VirtV2V::MetadataReader::LibVirtXML +# Sys::VirtV2V::Connection::LibVirtXML # Copyright (C) 2009 Red Hat Inc. # # This library is free software; you can redistribute it and/or @@ -15,7 +15,7 @@ # 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::MetadataReader::LibVirtXML; +package Sys::VirtV2V::Connection::LibVirtXML; use strict; use warnings; @@ -31,25 +31,25 @@ use Locale::TextDomain 'virt-v2v'; =head1 NAME -Sys::VirtV2V::MetadataReader::LibVirtXML - Read libvirt XML from a file +Sys::VirtV2V::Connection::LibVirtXML - Read libvirt XML from a file =head1 SYNOPSIS - use Sys::VirtV2V::MetadataReader; + use Sys::VirtV2V::Connection; - $reader = Sys::VirtV2V::MetadataReader->instantiate("libvirtxml", undef, + $reader = Sys::VirtV2V::Connection->instantiate("libvirtxml", undef, $config, @args); $dom = $reader->get_dom(); =head1 DESCRIPTION -Sys::VirtV2V::MetadataReader::LibVirtXML is a backend for -Sys::VirtV2V::MetadataReader which reads libvirt XML guest descriptions from a +Sys::VirtV2V::Connection::LibVirtXML is a backend for +Sys::VirtV2V::Connection which reads libvirt XML guest descriptions from a file. =head1 METHODS -See BACKEND INTERFACE in L<Sys::VirtV2V::MetadataReader> for a detailed +See BACKEND INTERFACE in L<Sys::VirtV2V::Connection> for a detailed description of its exported methods. =over @@ -116,9 +116,9 @@ sub _handle_args } } -=item Sys::VirtV2V::MetadataReader::LibVirtXML->get_name() +=item Sys::VirtV2V::Connection::LibVirtXML->get_name() -See BACKEND INTERFACE in L<Sys::VirtV2V::MetadataReader> for details. +See BACKEND INTERFACE in L<Sys::VirtV2V::Connection> for details. =cut @@ -131,7 +131,7 @@ sub get_name =item is_configured() -See BACKEND INTERFACE in L<Sys::VirtV2V::MetadataReader> for details. +See BACKEND INTERFACE in L<Sys::VirtV2V::Connection> for details. =cut @@ -153,7 +153,7 @@ sub is_configured =item get_dom() -See BACKEND INTERFACE in L<Sys::VirtV2V::MetadataReader> for details. +See BACKEND INTERFACE in L<Sys::VirtV2V::Connection> for details. =cut @@ -220,7 +220,7 @@ Please see the file COPYING.LIB for the full license. =head1 SEE ALSO -L<Sys::VirtV2V::MetadataReader(3)>, +L<Sys::VirtV2V::Connection(3)>, L<virt-v2v(1)>, L<v2v-snapshot(1)>, L<http://libguestfs.org/>. diff --git a/po/POTFILES.in b/po/POTFILES.in index 40331c8..8fa921c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -4,8 +4,8 @@ ../lib/Sys/VirtV2V/HVSource/Xen/Linux.pm ../lib/Sys/VirtV2V/Converter/Linux.pm ../lib/Sys/VirtV2V/Converter.pm -../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm -../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm -../lib/Sys/VirtV2V/MetadataReader.pm +../lib/Sys/VirtV2V/Connection/LibVirt.pm +../lib/Sys/VirtV2V/Connection/LibVirtXML.pm +../lib/Sys/VirtV2V/Connection.pm ../snapshot/v2v-snapshot.pl ../v2v/virt-v2v.pl diff --git a/po/es.po b/po/es.po index 4ca3dcc..2ee7eff 100644 --- a/po/es.po +++ b/po/es.po @@ -177,40 +177,40 @@ msgstr "El hipervisor conectado no soporta la caracter??stica {feature}" msgid "Unable to find a module to configure this guest" msgstr "No es posible encontrar un m??dulo para configurar este hu??sped" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:85 -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:113 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:85 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:113 #, perl-brace-format msgid "WARNING: {modulename} only takes a single filename." msgstr "ADVERTENCIA: {modulename} s??lo necesita un nombre de archivo." -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:125 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:125 #, perl-brace-format msgid "Guest {name} must be shutdown first" msgstr "Hu??sped {name} se debe apagar primero" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:145 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:145 #, perl-brace-format msgid "{name} isn't a valid guest name" msgstr "{name} no es un nombre de hu??sped v??lido" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:90 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:90 #, perl-brace-format msgid "WARNING: unknown configuration directive {directive} in {name} section." msgstr "" "ADVERTENCIA: directiva {directive} de configuraci??n desconocida en la " "secci??n {name}. " -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:143 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:143 #, perl-brace-format msgid "You must specify a filename when using {modulename}" msgstr "Debe especificar un nombre de archivo cuando utilice {modulename}" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:167 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:167 #, perl-brace-format msgid "Failed to open {path}: {error}" msgstr "Fall?? al abrir {path}: {error}" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:180 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:180 #, perl-brace-format msgid "Unable to parse {path}: {error}" msgstr "Imposible analizar sint??cticamente a {path}: {error}" diff --git a/po/fr.po b/po/fr.po index d95a3c0..ff3c893 100644 --- a/po/fr.po +++ b/po/fr.po @@ -159,38 +159,38 @@ msgstr "" msgid "Unable to find a module to configure this guest" msgstr "" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:85 -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:113 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:85 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:113 #, perl-brace-format msgid "WARNING: {modulename} only takes a single filename." msgstr "" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:125 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:125 #, perl-brace-format msgid "Guest {name} must be shutdown first" msgstr "" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:145 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:145 #, perl-brace-format msgid "{name} isn't a valid guest name" msgstr "" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:90 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:90 #, perl-brace-format msgid "WARNING: unknown configuration directive {directive} in {name} section." msgstr "" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:143 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:143 #, perl-brace-format msgid "You must specify a filename when using {modulename}" msgstr "" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:167 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:167 #, perl-brace-format msgid "Failed to open {path}: {error}" msgstr "" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:180 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:180 #, perl-brace-format msgid "Unable to parse {path}: {error}" msgstr "" diff --git a/po/it.po b/po/it.po index 2324fe3..56f6f92 100644 --- a/po/it.po +++ b/po/it.po @@ -174,40 +174,40 @@ msgstr "L'hypervisor connesso non supporta la funzione {feature}" msgid "Unable to find a module to configure this guest" msgstr "Impossibile trovare un modulo per la configurazione dell'ospite" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:85 -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:113 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:85 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:113 #, perl-brace-format msgid "WARNING: {modulename} only takes a single filename." msgstr "ATTENZIONE: {modulename} accetta un solo nome file." -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:125 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:125 #, perl-brace-format msgid "Guest {name} must be shutdown first" msgstr "" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:145 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:145 #, perl-brace-format msgid "{name} isn't a valid guest name" msgstr "{name} non ?? un nome di ospite valido" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:90 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:90 #, perl-brace-format msgid "WARNING: unknown configuration directive {directive} in {name} section." msgstr "" "ATTENZIONE: direttiva di configurazione {directive} sconosciuta nella " "sezione {name}." -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:143 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:143 #, perl-brace-format msgid "You must specify a filename when using {modulename}" msgstr "Quando si usa {modulename} ?? necessario specificare un nome file" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:167 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:167 #, perl-brace-format msgid "Failed to open {path}: {error}" msgstr "Impossibile aprire {path}: {error}" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:180 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:180 #, perl-brace-format msgid "Unable to parse {path}: {error}" msgstr "Impossibile eseguire il parsing di {path}: {error}" diff --git a/po/pl.po b/po/pl.po index 8e06175..6329aba 100644 --- a/po/pl.po +++ b/po/pl.po @@ -167,39 +167,39 @@ msgstr "Po????czony nadzorca nie obs??uguje funkcji {feature}" msgid "Unable to find a module to configure this guest" msgstr "Nie mo??na odnale???? modu??u do skonfigurowania tego go??cia" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:85 -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:113 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:85 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:113 #, perl-brace-format msgid "WARNING: {modulename} only takes a single filename." msgstr "OSTRZE??ENIE: {modulename} przyjmuje tylko jedn?? nazw?? pliku." -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:125 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:125 #, perl-brace-format msgid "Guest {name} must be shutdown first" msgstr "Go???? {name} musi najpierw zosta?? wy????czony" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:145 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:145 #, perl-brace-format msgid "{name} isn't a valid guest name" msgstr "{name} nie jest prawid??ow?? nazw?? go??cia" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:90 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:90 #, perl-brace-format msgid "WARNING: unknown configuration directive {directive} in {name} section." msgstr "" "OSTRZE??ENIE: nieznana dyrektywa konfiguracji {directive} w sekcji {name}." -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:143 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:143 #, perl-brace-format msgid "You must specify a filename when using {modulename}" msgstr "Nale??y poda?? nazw?? pliku podczas u??ywania {modulename}" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:167 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:167 #, perl-brace-format msgid "Failed to open {path}: {error}" msgstr "Otwarcie {path} nie powiod??o si??: {error}" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:180 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:180 #, perl-brace-format msgid "Unable to parse {path}: {error}" msgstr "Nie mo??na przetworzy?? {path}: {error}" diff --git a/po/ru.po b/po/ru.po index 436160a..cd1d5f9 100644 --- a/po/ru.po +++ b/po/ru.po @@ -167,38 +167,38 @@ msgstr "???????????????????????? ???????????????????? ???? ???????????????????? msgid "Unable to find a module to configure this guest" msgstr "???? ???????????? ???????????? ?????? ?????????????????? ?????????? ??????????" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:85 -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:113 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:85 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:113 #, perl-brace-format msgid "WARNING: {modulename} only takes a single filename." msgstr "????????????????: {modulename} ?????????? ?????????????????? ???????????? ???????? ?????? ??????????." -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:125 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:125 #, perl-brace-format msgid "Guest {name} must be shutdown first" msgstr "" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:145 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:145 #, perl-brace-format msgid "{name} isn't a valid guest name" msgstr "???????????????????????? ?????? ??????????: {name}" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:90 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:90 #, perl-brace-format msgid "WARNING: unknown configuration directive {directive} in {name} section." msgstr "????????????????: ?????????????????????? ?????????????????? ?????????????????? {directive} ?? ???????????? {name}." -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:143 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:143 #, perl-brace-format msgid "You must specify a filename when using {modulename}" msgstr "???????????????????? ?????????????? ?????? ?????????? ?????? ?????????????????????????? {modulename}" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:167 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:167 #, perl-brace-format msgid "Failed to open {path}: {error}" msgstr "???? ?????????????? ?????????????? {path}: {error}" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:180 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:180 #, perl-brace-format msgid "Unable to parse {path}: {error}" msgstr "???? ?????????????? ?????????????????? {path}: {error}" diff --git a/po/virt-v2v.pot b/po/virt-v2v.pot index d95a3c0..ff3c893 100644 --- a/po/virt-v2v.pot +++ b/po/virt-v2v.pot @@ -159,38 +159,38 @@ msgstr "" msgid "Unable to find a module to configure this guest" msgstr "" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:85 -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:113 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:85 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:113 #, perl-brace-format msgid "WARNING: {modulename} only takes a single filename." msgstr "" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:125 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:125 #, perl-brace-format msgid "Guest {name} must be shutdown first" msgstr "" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:145 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:145 #, perl-brace-format msgid "{name} isn't a valid guest name" msgstr "" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:90 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:90 #, perl-brace-format msgid "WARNING: unknown configuration directive {directive} in {name} section." msgstr "" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:143 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:143 #, perl-brace-format msgid "You must specify a filename when using {modulename}" msgstr "" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:167 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:167 #, perl-brace-format msgid "Failed to open {path}: {error}" msgstr "" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:180 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:180 #, perl-brace-format msgid "Unable to parse {path}: {error}" msgstr "" diff --git a/po/zh_CN.po b/po/zh_CN.po index 1200971..6af4d70 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -166,38 +166,38 @@ msgstr "???????????????????????????????????? {feature}" msgid "Unable to find a module to configure this guest" msgstr "??????????????????????????????????????????" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:85 -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:113 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:85 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:113 #, perl-brace-format msgid "WARNING: {modulename} only takes a single filename." msgstr "?????????{modulename} ???????????????????????????" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:125 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:125 #, perl-brace-format msgid "Guest {name} must be shutdown first" msgstr "??????????????????????????? {name}" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirt.pm:145 +#: ../lib/Sys/VirtV2V/Connection/LibVirt.pm:145 #, perl-brace-format msgid "{name} isn't a valid guest name" msgstr "{name} ????????????????????????" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:90 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:90 #, perl-brace-format msgid "WARNING: unknown configuration directive {directive} in {name} section." msgstr "?????????{name} ??????????????????????????? {directive}???" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:143 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:143 #, perl-brace-format msgid "You must specify a filename when using {modulename}" msgstr "?????? {modulename} ????????????????????????" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:167 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:167 #, perl-brace-format msgid "Failed to open {path}: {error}" msgstr "?????? {path} ?????????{error}" -#: ../lib/Sys/VirtV2V/MetadataReader/LibVirtXML.pm:180 +#: ../lib/Sys/VirtV2V/Connection/LibVirtXML.pm:180 #, perl-brace-format msgid "Unable to parse {path}: {error}" msgstr "???????????? {path}???{error}" diff --git a/snapshot/v2v-snapshot.pl b/snapshot/v2v-snapshot.pl index 86e4393..ccbc907 100755 --- a/snapshot/v2v-snapshot.pl +++ b/snapshot/v2v-snapshot.pl @@ -31,7 +31,7 @@ use Sys::Virt; use Sys::VirtV2V; use Sys::VirtV2V::ExecHelper; -use Sys::VirtV2V::MetadataReader; +use Sys::VirtV2V::Connection; use Sys::VirtV2V::UserMessage qw(user_message); =encoding utf8 @@ -239,8 +239,8 @@ if (!defined($datadir)) { } } -# Get an appropriate MetadataReader -my $mdr = Sys::VirtV2V::MetadataReader->instantiate($input, {}, $vmm, @ARGV); +# Get an appropriate Connection +my $mdr = Sys::VirtV2V::Connection->instantiate($input, {}, $vmm, @ARGV); if(!defined($mdr)) { print STDERR user_message(__x("{input} is not a valid input format", input => $input)); diff --git a/v2v/virt-v2v.pl b/v2v/virt-v2v.pl index 1784f2a..c853e91 100755 --- a/v2v/virt-v2v.pl +++ b/v2v/virt-v2v.pl @@ -33,7 +33,7 @@ use Sys::Guestfs::Lib qw(open_guest get_partitions inspect_all_partitions use Sys::VirtV2V; use Sys::VirtV2V::GuestOS; use Sys::VirtV2V::Converter; -use Sys::VirtV2V::MetadataReader; +use Sys::VirtV2V::Connection; use Sys::VirtV2V::UserMessage qw(user_message); =encoding utf8 @@ -210,8 +210,8 @@ if(defined($config_file)) { } } -# Get an appropriate MetadataReader -my $mdr = Sys::VirtV2V::MetadataReader->instantiate($input_method, $input_uri, +# Get an appropriate Connection +my $mdr = Sys::VirtV2V::Connection->instantiate($input_method, $input_uri, $config, @ARGV); if(!defined($mdr)) { print STDERR user_message __x("{input} is not a valid input method", @@ -219,7 +219,7 @@ if(!defined($mdr)) { exit(1); } -# Check MetadataReader is properly initialised +# Check Connection is properly initialised exit 1 unless($mdr->is_configured()); # Configure GuestOS ([files] and [deps] sections) -- 1.6.6
Matthew Booth
2010-Jan-29 18:05 UTC
[Libguestfs] [PATCH 4/4] ESX: Import guests from VMware's ESX server
This change adds the ability to import a guest and its storage from VMware's ESX server using the LibVirt connection. An example command line: virt-v2v -ic 'esx://yellow.marston/?no_verify=1' -op transfer RHEL5-64 This will import the guest RHEL5-64 from esx server yellow.marston, copying its storage to a local pool called transfer. Sys::VirtV2V::Connection is refactored to be a superclass. Subclasses are now created explicitly by virt-v2v.pl rather than using a generic instantiate mechanism. Sys::VirtV2V::Connection::LibVirt knows explicitly about ESX, and will use the new Sys::VirtV2V::Transfer::ESX to fetch its storage. virt-v2v.pl is updated to reflect the other changes. --- MANIFEST | 1 + lib/Sys/VirtV2V/Connection.pm | 160 +++++++++----- lib/Sys/VirtV2V/Connection/LibVirt.pm | 185 ++++++++++------- lib/Sys/VirtV2V/Connection/LibVirtXML.pm | 99 ++------- lib/Sys/VirtV2V/Transfer/ESX.pm | 344 ++++++++++++++++++++++++++++++ v2v/virt-v2v.pl | 131 ++++++++---- 6 files changed, 668 insertions(+), 252 deletions(-) create mode 100644 lib/Sys/VirtV2V/Transfer/ESX.pm diff --git a/MANIFEST b/MANIFEST index 7bfad76..3d6bf00 100644 --- a/MANIFEST +++ b/MANIFEST @@ -12,6 +12,7 @@ lib/Sys/VirtV2V/Connection.pm lib/Sys/VirtV2V/Connection/LibVirt.pm lib/Sys/VirtV2V/Connection/LibVirtXML.pm lib/Sys/VirtV2V/UserMessage.pm +lib/Sys/VirtV2V/Transfer/ESX.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 31fbdb3..6a967d0 100644 --- a/lib/Sys/VirtV2V/Connection.pm +++ b/lib/Sys/VirtV2V/Connection.pm @@ -20,113 +20,163 @@ package Sys::VirtV2V::Connection; use strict; use warnings; -use Module::Pluggable sub_name => 'modules', - search_path => ['Sys::VirtV2V::Connection'], - require => 1; +use Sys::Virt; -use Carp; +use Locale::TextDomain 'virt-v2v'; =pod =head1 NAME -Sys::VirtV2V::Connection - Read a variety of guest metadata formats +Sys::VirtV2V::Connection - Obtain domain metadata =head1 SYNOPSIS - use Sys::VirtV2V::Connection; + use Sys::VirtV2V::Connection::LibVirt; - $reader = Sys::VirtV2V::Connection->instantiate("libvirtxml", $uri, - $config, @args); - exit 1 unless($mdr->is_configured()); - $dom = $reader->get_dom(); + $conn = Sys::VirtV2V::Connection::LibVirt->new($uri, $name, $pool); + $dom = $conn->get_dom(); + @storage = $conn->get_local_storage(); =head1 DESCRIPTION -Sys::VirtV2V::Connection reads the metadata of a, possibly foreign, -guest. It provides the DOM representation of an equivalent libvirt XML -representation. +Sys::VirtV2V::Connection describes a connection to a, possibly remote, source of +guest metadata and storage. It is a virtual superclass and can't be instantiated +directly. Use one of the subclasses: -Sys::VirtV2V::Connection is an interface to various backends, each of -which implement a consistent API. Sys::VirtV2V::Connection itself only -implements methods to access backends. + Sys::VirtV2V::Connection::LibVirt + Sys::VirtV2V::Connection::LibVirtXML =head1 METHODS =over -=item instantiate(name, $uri, $config, @args) +=item get_local_storage -=over - -=item name +Return a list of the domain's storage devices. The returned list contains local +paths. -The name of the module to instantiate. +=cut -=item uri +sub get_local_storage +{ + my $self = shift; -A URI describing the target connection. + return @{$self->{storage}}; +} -=item config +=item get_dom() -A parsed virt-v2v configuration file. +Returns an XML::DOM::Document describing a libvirt configuration equivalent to +the input. -=item args +Returns undef and displays an error if there was an error -Backend-specific arguments describing where its data is located. +=cut -=back +sub get_dom +{ + my $self = shift; -Instantiate a backend instance with the given name. + return $self->{dom}; +} -=cut -sub instantiate +# Iterate over returned storage. Transfer it and update DOM as necessary. To be +# called by subclasses. +sub _storage_iterate { - my $class = shift; + my $self = shift; + + my ($transfer, $pool) = @_; + + my $dom = $self->get_dom(); - my ($name, $uri, $config, @args) = @_; + # Create a hash of guest devices to their paths + my @storage; + foreach my $disk ($dom->findnodes('/domain/devices/disk')) { + my ($source_e) = $disk->findnodes('source'); - defined($name) or carp("instantiate called without name argument"); - defined($uri) or carp("instantiate called without uri argument"); - defined($config) or carp("instantiate called without config argument"); + my ($source) = $source_e->findnodes('@file | @dev'); + defined($source) or die("source element has neither dev nor file: \n". + $dom.toString()); - foreach my $module ($class->modules()) { - if($module->get_name() eq $name) { - return $module->_new($uri, $config->{$name}, @args); + my ($target) = $disk->findnodes('target/@dev'); + defined($target) or die("disk does not have a target device: \n". + $dom.toString()); + + # If the disk is a floppy or a cdrom, blank its source + my $device = $disk->getAttribute('device'); + if ($device eq 'floppy' || $device eq 'cdrom') { + $source_e->setAttribute($source->getName(), ''); } - } - return undef; -} + else { + my $path = $source->getValue(); -=back + if (defined($transfer)) { + # Die if transfer required and no output pool + die (user_message(__"No output pool was specified")) + unless (defined($pool)); -=head1 BACKEND INTERFACE + # Fetch the remote storage + my $vol = $transfer->transfer($self, $path, $pool); -=over + # Parse the XML description of the returned volume + my $voldom + new XML::DOM::Parser->parse($vol->get_xml_description()); -=item CLASS->get_name() + # Find any existing driver element. + my ($driver) = $disk->findnodes('driver'); -Return the module's name. + # Create a new driver element if none exists + unless (defined($driver)) { + $driver + $disk->getOwnerDocument()->createElement("driver"); + $disk->appendChild($driver); + } + $driver->setAttribute('name', 'qemu'); -=item is_configured() + # Get the volume format for passing to the qemu driver + my ($format) + $voldom->findnodes('/volume/target/format/@type'); -Return 1 if the module has been suffiently configured to proceed. -Return 0 and display an error message otherwise. + $format = $format->getValue() if (defined($format)); -=item get_dom() + # Auto-detect if no format is specified explicitly + $format ||= 'auto'; -Returns an XML::DOM::Document describing a libvirt configuration equivalent to -the input. + $driver->setAttribute('type', $format); -Returns undef and displays an error if there was an error + # Remove the @file or @dev attribute before adding a new one + $source_e->removeAttributeNode($source); + + $path = $vol->get_path(); + + # Set @file or @dev as appropriate + if ($vol->get_info()->{type} =+ Sys::Virt::StorageVol::TYPE_FILE) + { + $disk->setAttribute('type', 'file'); + $source_e->setAttribute('file', $path); + } else { + $disk->setAttribute('type', 'block'); + $source_e->setAttribute('dev', $path); + } + } + + push(@storage, $path); + } + } + + $self->{storage} = \@storage; +} =back =head1 COPYRIGHT -Copyright (C) 2009 Red Hat Inc. +Copyright (C) 2009,2010 Red Hat Inc. =head1 LICENSE diff --git a/lib/Sys/VirtV2V/Connection/LibVirt.pm b/lib/Sys/VirtV2V/Connection/LibVirt.pm index d3aa80d..59e4913 100644 --- a/lib/Sys/VirtV2V/Connection/LibVirt.pm +++ b/lib/Sys/VirtV2V/Connection/LibVirt.pm @@ -20,10 +20,17 @@ package Sys::VirtV2V::Connection::LibVirt; use strict; use warnings; +use Sys::VirtV2V::Connection; +our @ISA = ("Sys::VirtV2V::Connection"); + +use Net::Netrc; +use URI; 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'; @@ -36,107 +43,133 @@ Sys::VirtV2V::Connection::LibVirt - Read libvirt metadata from libvirtd =head1 SYNOPSIS - use Sys::VirtV2V::Connection; + use Sys::VirtV2V::Connection::LibVirt; - $reader = Sys::VirtV2V::Connection->instantiate - ("libvirt", "xen+ssh://xenserver.example.com/", $config, @args); - $dom = $reader->get_dom(); + $conn = Sys::VirtV2V::Connection::LibVirt->new + ("xen+ssh://xenserver.example.com/", $name, $pool); + $dom = $conn->get_dom(); =head1 DESCRIPTION -Sys::VirtV2V::Connection::LibVirt is a backend for +Sys::VirtV2V::Connection::LibVirt is an implementation of Sys::VirtV2V::Connection which reads a guest's libvirt XML directly from a libvirt connection. =head1 METHODS -See BACKEND INTERFACE in L<Sys::VirtV2V::Connection> for a detailed -description of its exported methods. - =over -=cut +=item new(uri, name, pool) -use constant NAME => "libvirt"; +Create a new Sys::VirtV2V::Connection::LibVirt. Domain I<name> will be +downloaded from I<uri>. Remote storage will be copied to a new volume, which +will be create in <pool>. + +=cut -sub _new +sub new { my $class = shift; - my ($uri, $config, @args) = @_; + my ($uri, $name, $pool) = @_; my $self = {}; bless($self, $class); - my @vmm_params = (auth => 1); - push(@vmm_params, url => $uri) if defined($uri); - my $vmm = Sys::Virt->new(@vmm_params); + $self->{uri} = URI->new($uri); + $self->{name} = $name; - $self->{vmm} = $vmm; - $self->_handle_args(@args); + # Parse uri authority for hostname and username + $self->{uri}->authority() =~ /^(?:([^:]*)(?::([^@]*))?@)?(.*)$/ + or die(user_message(__x("Unable to parse URI authority: {auth}", + auth => $self->{uri}->authority()))); - return $self; -} + my $username = $self->{username} = $1; + my $hostname = $self->{hostname} = $3; -sub _handle_args -{ - my $self = shift; + print STDERR user_message(__("WARNING: Specifying a password in the ". + "connection URI is not supported. It has ". + "been ignored.")) if (defined($2)); - # The first argument is the name of a libvirt domain - $self->{name} = shift; + # Look for credentials in .netrc if the URI contains a hostname + if (defined($hostname)) { + if (defined($username)) { + my $mach = Net::Netrc->lookup($hostname, $username); + $self->{password} = $mach->password if (defined($mach)); + } - # Warn if we were given more than 1 argument - if(scalar(@_) > 0) { - print STDERR user_message - (__x("WARNING: {modulename} only takes a single domain name.", - modulename => NAME)); - } -} + else { + my $mach = Net::Netrc->lookup($hostname); -=item Sys::VirtV2V::Connection::LibVirtXML->get_name() + if (defined($mach)) { + $self->{username} = $mach->login; + $self->{password} = $mach->password; + } + } + } -See BACKEND INTERFACE in L<Sys::VirtV2V::Connection> for details. + my $sourcevmm; + eval { + $sourcevmm = Sys::Virt->new( + uri => $uri, + readonly => 1, + auth => 1, + credlist => [ + Sys::Virt::CRED_AUTHNAME, + Sys::Virt::CRED_PASSPHRASE + ], + callback => sub { + my $creds = shift; + + foreach my $cred (@$creds) { + if ($cred->{type} == Sys::Virt::CRED_AUTHNAME) { + $cred->{result} = $self->{username}; + } + + elsif ($cred->{type} == Sys::Virt::CRED_PASSPHRASE) { + $cred->{result} = $self->{password}; + } + + else { die($cred->{type}, "\n"); } + } + } + ); + }; + die(user_message(__x("Failed to connect to {uri}: {error}", + uri => $uri, + error => $@->stringify()))) if ($@); -=cut + $self->{sourcevmm} = $sourcevmm; -sub get_name -{ - my $class = shift; + $self->_check_shutdown(); - return NAME; -} + $self->_get_dom(); -=item is_configured() + my $transfer; + if ($self->{uri}->scheme eq "esx") { + $transfer = "Sys::VirtV2V::Transfer::ESX"; + } -See BACKEND INTERFACE in L<Sys::VirtV2V::Connection> for details. + $self->_storage_iterate($transfer, $pool); -=cut + return $self; +} -sub is_configured +sub _check_shutdown { my $self = shift; my $vmm = $self->{vmm}; - my $name = $self->{name}; - - # Check the given domain exists - my $domain = _get_domain($vmm, $name); - - # Don't continue if it isn't - return 0 unless(defined($domain)); + my $domain = $self->_get_domain(); # Check the domain is shutdown - unless ($domain->get_info()->{state} == Sys::Virt::Domain::STATE_SHUTOFF) { - print STDERR user_message - (__x("Guest {name} is currently {state}. ". - "It must be shut down first.", - state => _state_string($domain->get_info()->{state}), - name => $name)); - return 0; - } - - return 1; + die(user_message(__x("Guest {name} is currently {state}. It must be ". + "shut down first.", + state => _state_string($domain->get_info()->{state}), + name => $self->{name}))) + unless ($domain->get_info()->{state} =+ Sys::Virt::Domain::STATE_SHUTOFF); } sub _state_string @@ -164,30 +197,30 @@ sub _state_string sub _get_domain { - my ($vmm, $name) = @_; + my $self = shift; + + return $self->{domain} if (defined($self->{domain})); + + my $vmm = $self->{sourcevmm}; + my $name = $self->{name}; # Lookup the domain my $domain; eval { $domain = $vmm->get_domain_by_name($name); }; + die($@) if ($@); - # Warn and exit if we didn't find it - unless($domain) { - print STDERR user_message - (__x("{name} isn't a valid guest name", name => $name)); - } + # Check we found it + die(user_message(__x("{name} isn't a valid guest name", name => $name))) + unless($domain); + + $self->{domain} = $domain; return $domain; } -=item get_dom() - -See BACKEND INTERFACE in L<Sys::VirtV2V::Connection> for details. - -=cut - -sub get_dom +sub _get_dom { my $self = shift; @@ -195,13 +228,15 @@ sub get_dom my $name = $self->{name}; # Lookup the domain - my $domain = _get_domain($vmm, $name); + my $domain = $self->_get_domain(); # Warn and exit if we didn't find it return undef unless(defined($domain)); my $xml = $domain->get_xml_description(); - return new XML::DOM::Parser->parse($xml); + + my $dom = new XML::DOM::Parser->parse($xml); + $self->{dom} = $dom; } =back diff --git a/lib/Sys/VirtV2V/Connection/LibVirtXML.pm b/lib/Sys/VirtV2V/Connection/LibVirtXML.pm index c05aa0f..6867a9b 100644 --- a/lib/Sys/VirtV2V/Connection/LibVirtXML.pm +++ b/lib/Sys/VirtV2V/Connection/LibVirtXML.pm @@ -20,6 +20,8 @@ package Sys::VirtV2V::Connection::LibVirtXML; use strict; use warnings; +our @ISA = ("Sys::VirtV2V::Connection"); + use XML::DOM; use XML::DOM::XPath; @@ -35,34 +37,33 @@ Sys::VirtV2V::Connection::LibVirtXML - Read libvirt XML from a file =head1 SYNOPSIS - use Sys::VirtV2V::Connection; + use Sys::VirtV2V::Connection::LibVirtXML; - $reader = Sys::VirtV2V::Connection->instantiate("libvirtxml", undef, - $config, @args); - $dom = $reader->get_dom(); + $conn = Sys::VirtV2V::Connection::LibVirtXML->new($config, $path); + $dom = $conn->get_dom(); =head1 DESCRIPTION -Sys::VirtV2V::Connection::LibVirtXML is a backend for +Sys::VirtV2V::Connection::LibVirtXML is an implementation of Sys::VirtV2V::Connection which reads libvirt XML guest descriptions from a file. =head1 METHODS -See BACKEND INTERFACE in L<Sys::VirtV2V::Connection> for a detailed -description of its exported methods. - =over -=cut +=item new(config, path) -use constant NAME => "libvirtxml"; +Create a new LibVirtXML connection. Configuration for transforming the metadata +is taken from I<config>, and the metadata itself is read from I<path>. + +=cut -sub _new +sub new { my $class = shift; - my ($uri, $config, @args) = @_; + my ($config, $path) = @_; my %obj = (); my $self = \%obj; @@ -87,77 +88,22 @@ sub _new } else { - print STDERR user_message - (__x("WARNING: unknown configuration directive ". - "{directive} in {name} section.", - directive => $directive, name => NAME)); - $self->{invalidconfig} = 1; + die(__x("WARNING: unknown configuration directive ". + "{directive} in {name} section.", + directive => $directive, name => 'libvirtxml')); } } } - $self->_handle_args(@args); - - return $self; -} - -sub _handle_args -{ - my $self = shift; - - # The first argument is the libvirt xml file's path - $self->{path} = shift; - - # Warn if we were given more than 1 argument - if(scalar(@_) > 0) { - print STDERR user_message - (__x("WARNING: {modulename} only takes a single filename.", - modulename => NAME)); - } -} - -=item Sys::VirtV2V::Connection::LibVirtXML->get_name() - -See BACKEND INTERFACE in L<Sys::VirtV2V::Connection> for details. - -=cut - -sub get_name -{ - my $class = shift; - - return NAME; -} - -=item is_configured() - -See BACKEND INTERFACE in L<Sys::VirtV2V::Connection> for details. - -=cut - -sub is_configured -{ - my $self = shift; - - if(!defined($self->{path})) { - print STDERR user_message - (__x("You must specify a filename when using {modulename}", - modulename => NAME)); - return 0; - } + $self->_get_dom($path); - return 0 if(exists($self->{invalidconfig})); + # No transfer methods defined yet + $self->_storage_iterate(undef, undef); - return 1; + return $self; } -=item get_dom() - -See BACKEND INTERFACE in L<Sys::VirtV2V::Connection> for details. - -=cut - -sub get_dom +sub _get_dom { my $self = shift; @@ -212,7 +158,7 @@ sub get_dom =head1 COPYRIGHT -Copyright (C) 2009 Red Hat Inc. +Copyright (C) 2009,2010 Red Hat Inc. =head1 LICENSE @@ -220,7 +166,6 @@ Please see the file COPYING.LIB for the full license. =head1 SEE ALSO -L<Sys::VirtV2V::Connection(3)>, L<virt-v2v(1)>, L<v2v-snapshot(1)>, L<http://libguestfs.org/>. diff --git a/lib/Sys/VirtV2V/Transfer/ESX.pm b/lib/Sys/VirtV2V/Transfer/ESX.pm new file mode 100644 index 0000000..353c10d --- /dev/null +++ b/lib/Sys/VirtV2V/Transfer/ESX.pm @@ -0,0 +1,344 @@ +# Sys::VirtV2V::Transfer::ESX +# 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::ESX::UA; + +use strict; +use warnings; + +use Sys::Virt::Error; + +use Sys::VirtV2V; + +use Sys::VirtV2V::UserMessage qw(user_message); + +use Locale::TextDomain 'virt-v2v'; + +# This is a gross hack to bring sanity to Net::HTTPS's SSL handling. Net::HTTPS +# can use either Net::SSL or IO::Socket::SSL, depending on which is available at +# runtime. It does not expose which of these it is using, or provide any common +# interface for configuring them. Neither of these libraries will verify a peer +# certificate by default. The configuration required to ensure certificates are +# verified is custom to the driver in use. If the wrong driver is configured, it +# will silently do nothing. +# +# To try to fix this situation, we hardcode here that we want Net::SSL. In the +# _new constructor, we check that Net::SSL was actually used, and die() if it +# wasn't. We subsequently only include configuration for Net::SSL. +BEGIN { + use Net::HTTPS; + + $Net::HTTPS::SSL_SOCKET_CLASS = "Net::SSL"; +} + +use LWP::UserAgent; +our @ISA = ("LWP::UserAgent"); + +our %handles; + +sub new { + my $class = shift; + + my ($server, $username, $password, $pool, $verify) = @_; + + my $self = $class->SUPER::new( + agent => 'virt-v2v/'.$Sys::VirtV2V::VERSION, + protocols_allowed => [ 'https' ] + ); + $self->show_progress(1); + + $self->add_handler(response_header => sub { + my ($response, $self, $h) = @_; + + if ($response->is_success) { + $self->verify_certificate($response) if ($verify); + $self->create_volume($response); + } + }); + + $self->{_v2v_server} = $server; + $self->{_v2v_pool} = $pool; + $self->{_v2v_username} = $username; + $self->{_v2v_password} = $password; + + if ($verify) { + # Leave HTTPS_CA_DIR alone if it is already set + # Setting HTTPS_CA_DIR to the empty string results in it using the + # compiled-in default paths + $ENV{HTTPS_CA_DIR} = "" unless (exists($ENV{HTTPS_CA_DIR})); + } else { + # Unset HTTPS_CA_DIR if it is already set + delete($ENV{HTTPS_CA_DIR}); + } + + die("Invalid configuration of Net::HTTPS") + unless(Net::HTTPS->isa('Net::SSL')); + + return $self; +} + +sub get_volume +{ + my $self = shift; + + my ($path) = @_; + + # Need to turn this: + # [yellow:storage1] win2k3r2-32/win2k3r2-32.vmdk + # into this: + # https://yellow.rhev.marston/folder/win2k3r2-32/win2k3r2-32-flat.vmdk? \ + # dcPath=ha-datacenter&dsName=yellow:storage1 + + $path =~ /^\[(.*)\]\s+(.*)\.vmdk$/ + or die("Failed to parse ESX path: $path"); + my $datastore = $1; + my $vmdk = $2; + + my $url = URI->new("https://".$self->{_v2v_server}); + $url->path("/folder/$vmdk-flat.vmdk"); + $url->query_form(dcPath => "ha-datacenter", dsName => $datastore); + + # Replace / with _ so the vmdk name can be used as a volume name + $self->{_v2v_volname} = $vmdk; + $self->{_v2v_volname} =~ s,/,_,g; + + # Check to see if this volume already exists + eval { + my $pool = $self->{_v2v_pool}; + $self->{_v2v_vol} = $pool->get_volume_by_name($self->{_v2v_volname}); + }; + + # The above command should generate VIR_ERR_NO_STORAGE_VOL because the + # volume doesn't exist + unless($@ && $@->code == Sys::Virt::Error::ERR_NO_STORAGE_VOL) { + unless ($@) { + 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.", + name => $self->{_v2v_volname})); + return $self->{_v2v_vol}; + } + + # We got an error, but not the one we expected + die(user_message(__x("Unexpected error accessing storage pool: ", + "{error}", error => $@->stringify()))); + } + + my $r = $self->SUPER::get($url, + ':content_cb' => sub { $self->handle_data(@_); }, + ':read_size_hint' => 64 * 1024); + + if ($r->is_success) { + # It reports success even if one of the callbacks died + my $died = $r->header('X-Died'); + die($died) if (defined($died)); + + # Close the volume file descriptor + close($self->{_v2v_volfh}); + return $self->{_v2v_vol}; + } + + if ($r->code == 401) { + die(user_message(__x("Authentication error connecting to ". + "{server}. Used credentials for {username} ". + "from .netrc.", + server => $self->{_v2v_server}, + username => $self->{_v2v_username}))) + } + + die(user_message(__x("Failed to connect to ESX server: {error}", + error => $r->status_line))); +} + +sub get_basic_credentials +{ + my $self = shift; + + my ($realm, $uri, $isproxy) = @_; # Not interested in any of these things + # because we only ever contact a single + # server in a single context + + return ($self->{_v2v_username}, $self->{_v2v_password}); +} + +sub handle_data +{ + my $self = shift; + + my ($data, $response) = @_; + + my $volfh = $self->{_v2v_volfh}; + + syswrite($volfh, $data) + or die(user_message(__x("Error writing to {path}: {error}", + path => $self->{_v2v_volpath}, + error => $!))); +} + +sub create_volume +{ + my $self = shift; + + my ($response) = @_; + + my $pool = $self->{_v2v_pool}; + + # Create a volume in the target storage pool of the correct size + my $name = $self->{_v2v_volname}; + die("create_volume called, but _v2v_volname is not set") + unless (defined($name)); + + my $size = $response->content_length(); + + my $vol_xml = " + <volume> + <name>$name</name> + <capacity>$size</capacity> + </volume> + "; + + my $volume; + eval { + $volume = $pool->create_volume($vol_xml); + }; + die(user_message(__x("Failed to create storage volume: {error}", + error => $@->stringify()))) if ($@); + $self->{_v2v_vol} = $volume; + + # Open the volume for writing + open(my $volfh, '>', $volume->get_path()) + or die(user_message(__x("Error opening storage volume {path} ". + "for writing: {error}", error => $!))); + + $self->{_v2v_volfh} = $volfh; +} + +sub verify_certificate +{ + my $self = shift; + + my ($r) = @_; + + # No point in trying to verify headers if the request failed anyway + return unless ($r->is_success); + + my $subject = $r->header('Client-SSL-Cert-Subject'); + die(user_message(__"Server response didn't include an SSL subject")) + unless ($subject); + + $subject =~ /\/CN=([^\/]*)/ + or die(user_message(__x("SSL Certification Subject doesn't contain a ". + "common name: {subject}", + subject => $subject))); + my $cn = $1; + + $self->{_v2v_server} =~ /(^|\.)\Q$cn\E$/ + or die(user_message(__x("Server {server} presented an SSL certificate ". + "for {commonname}", + server => $self->{_v2v_server}, + commonname => $cn))); +} + +package Sys::VirtV2V::Transfer::ESX; + +use Sys::Virt; + +use Sys::VirtV2V::UserMessage qw(user_message); + +use Locale::TextDomain 'virt-v2v'; + +=pod + +=head1 NAME + +Sys::VirtV2V::Transfer::ESX - Transfer guest storage from an ESX server + +=head1 SYNOPSIS + + use Sys::VirtV2V::Transfer::ESX; + + $vol = Sys::VirtV2V::Transfer::ESX->transfer($conn, $path, $pool); + +=head1 DESCRIPTION + +Sys::VirtV2V::Transfer::ESX retrieves guest storage devices from an ESX server. + +=head1 METHODS + +=over + +=item transfer(conn, path, pool) + +Transfer <path> from a remote ESX server. Server and authentication details will +be taken from <conn>. Storage will be copied to a new volume created in <pool>. + +=cut + +sub transfer +{ + my $class = shift; + + my ($conn, $path, $pool) = @_; + + my $uri = $conn->{uri}; + my $username = $conn->{username}; + my $password = $conn->{password}; + + die("URI not defined for connection") unless (defined($uri)); + + die(user_message(__x("Authentication is required to connect to ". + "{server} and no credentials were found in ". + ".netrc.", + server => $conn->{hostname}))) + unless (defined($username)); + + # Look for no_verify in the URI + my %query = $uri->query_form; + + my $noverify = 0; + $noverify = 1 if (exists($query{no_verify}) && $query{no_verify} eq "1"); + + # Initialise a user agent + my $ua = Sys::VirtV2V::Transfer::ESX::UA->new($conn->{hostname}, + $username, + $password, + $pool); + + return $ua->get_volume($path); +} + +=back + +=head1 COPYRIGHT + +Copyright (C) 2009, 2010 Red Hat Inc. + +=head1 LICENSE + +Please see the file COPYING.LIB for the full license. + +=head1 SEE ALSO + +L<virt-v2v(1)>, +L<v2v-snapshot(1)>, +L<http://libguestfs.org/>. + +=cut + +1; diff --git a/v2v/virt-v2v.pl b/v2v/virt-v2v.pl index c853e91..11f866a 100755 --- a/v2v/virt-v2v.pl +++ b/v2v/virt-v2v.pl @@ -33,7 +33,8 @@ use Sys::Guestfs::Lib qw(open_guest get_partitions inspect_all_partitions use Sys::VirtV2V; use Sys::VirtV2V::GuestOS; use Sys::VirtV2V::Converter; -use Sys::VirtV2V::Connection; +use Sys::VirtV2V::Connection::LibVirt; +use Sys::VirtV2V::Connection::LibVirtXML; use Sys::VirtV2V::UserMessage qw(user_message); =encoding utf8 @@ -149,12 +150,20 @@ Guest argument is the path to an XML file describing a libvirt domain. =cut -my $input_uri; +my $input_uri = "qemu:///system"; =item B<-ic URI> Specifies the connection to use when using the libvirt input method. If omitted, -then we connect to the default libvirt hypervisor. +this defaults to qemu:///system. + +=cut + +my $input_transport; + +=item B<-it method> + +Species the transport method used to obtain raw storage from the source guest. =cut @@ -167,6 +176,15 @@ ommitted, this defaults to qemu:///system. =cut +my $output_pool; + +=item B<-op pool> + +Specifies the pool which will be used to create new storage for the converted +guest. + +=cut + my $config_file; =item B<-c file> @@ -185,6 +203,7 @@ GetOptions ("help|?" => \$help, "i=s" => \$input_method, "ic=s" => \$input_uri, "oc=s" => \$output_uri, + "op=s" => \$output_pool, "c=s" => \$config_file ) or pod2usage(2); pod2usage(0) if($help); @@ -210,18 +229,68 @@ if(defined($config_file)) { } } +# Connect to target libvirt +my $vmm = Sys::Virt->new( + auth => 1, + uri => $output_uri +); + # Get an appropriate Connection -my $mdr = Sys::VirtV2V::Connection->instantiate($input_method, $input_uri, - $config, @ARGV); -if(!defined($mdr)) { - print STDERR user_message __x("{input} is not a valid input method", - input => $input_method); +my $conn; +eval { + if ($input_method eq "libvirtxml") { + my $path = shift(@ARGV); + $conn = Sys::VirtV2V::Connection::LibVirtXML->new($config, $path); + + # Warn if we were given more than 1 argument + if(scalar(@_) > 0) { + print STDERR user_message + (__x("WARNING: {modulename} only takes a single filename.", + modulename => 'libvirtxml')); + } + } + + elsif ($input_method eq "libvirt") { + my $name = shift(@ARGV); + + # Get a handle to the output pool if one is defined + my $pool; + if (defined($output_pool)) { + eval { + $pool = $vmm->get_storage_pool_by_name($output_pool); + }; + + if ($@) { + print STDERR user_message + (__x("Output pool {poolname} is not a valid local ". + "storage pool", + poolname => $output_pool)); + exit(1); + } + } + + $conn = Sys::VirtV2V::Connection::LibVirt->new($input_uri, $name, + $pool); + + # Warn if we were given more than 1 argument + if(scalar(@_) > 0) { + print STDERR user_message + (__x("WARNING: {modulename} only takes a single domain name.", + modulename => 'libvirt')); + } + } + + else { + print STDERR user_message __x("{input} is not a valid input method", + input => $input_method); + exit(1); + } +}; +if ($@) { + print STDERR $@; exit(1); } -# Check Connection is properly initialised -exit 1 unless($mdr->is_configured()); - # Configure GuestOS ([files] and [deps] sections) Sys::VirtV2V::GuestOS->configure($config); @@ -229,14 +298,14 @@ Sys::VirtV2V::GuestOS->configure($config); ## Start of processing # Get a libvirt configuration for the guest -my $dom = $mdr->get_dom(); +my $dom = $conn->get_dom(); exit(1) unless(defined($dom)); -# Get a list of the guest's storage devices -my @devices = get_guest_devices($dom); +# Get a list of the guest's transfered storage devices +my @storage = $conn->get_local_storage(); -# Open a libguestfs handle on the guest's devices -my $g = get_guestfs_handle(@devices); +# Open a libguestfs handle on the guest's storage devices +my $g = get_guestfs_handle(@storage); # Inspect the guest my $os = inspect_guest($g); @@ -244,11 +313,6 @@ my $os = inspect_guest($g); # Instantiate a GuestOS instance to manipulate the guest my $guestos = Sys::VirtV2V::GuestOS->instantiate($g, $os); -# Connect to target libvirt -my @vmm_params = (auth => 1); -push(@vmm_params, uri => $output_uri) if(defined($output_uri)); -my $vmm = Sys::Virt->new(@vmm_params); - # Modify the guest and its metadata for the target hypervisor Sys::VirtV2V::Converter->convert($vmm, $guestos, $dom, $os); @@ -263,9 +327,7 @@ $vmm->define_domain($dom->toString()); sub get_guestfs_handle { - my @params = \@_; # Initialise parameters with list of devices - - my $g = open_guest(@params, rw => 1); + my $g = open_guest(@_, rw => 1); # Mount the transfer iso if GuestOS needs it my $transferiso = Sys::VirtV2V::GuestOS->get_transfer_iso(); @@ -330,27 +392,6 @@ sub inspect_guest return $os; } -sub get_guest_devices -{ - my $dom = shift; - - my @devices; - foreach my $source ($dom->findnodes('/domain/devices/disk/source')) { - my $attrs = $source->getAttributes(); - - # Get either dev or file, whichever is defined - my $attr = $attrs->getNamedItem("dev"); - $attr = $attrs->getNamedItem("file") if(!defined($attr)); - - defined($attr) or die("source element has neither dev nor file: ". - $source.toString()); - - push(@devices, $attr->getValue()); - } - - return @devices; -} - =head1 PREPARING TO RUN VIRT-V2V =head2 Backup the guest -- 1.6.6