[ESX support] Working ESX conversion for RHEL 5
With this patchset I have successfully[1] imported a RHEL 5 guest directly from ESX with the following command line: virt-v2v -ic 'esx://yellow.marston/?no_verify=1' -op transfer RHEL5-64 Login details are stored in ~/.netrc Note that this is the only guest I've tested against. I haven't for example, checked that I haven't broken Xen imports. Matt [1] With the exception of network reconfiguration. After import I manually munged the network config with virsh edit.
Command line option changes: -s -> -f -c -> -ic -c, --connect now generates an error message. 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 | 108 ++++++++++++++------------ 4 files changed, 79 insertions(+), 63 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..ad1610f 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 -f virt-v2v.conf guest-domain.xml - virt-v2v --connect qemu:///system guest-domain.xml + virt-v2v -ic qemu:///system guest-domain =head1 DESCRIPTION @@ -112,58 +112,59 @@ table below. =cut -my $help; +my $input_method = "libvirt"; -=item B<--help> - -Display brief help. - -=cut +=item B<-i input> -my $version; +Specifies how the conversion source metadata can be obtained. The default is +C<libvirt>. Supported options are: -=item B<--version> +=over -Display version number and exit. +=item I<libvirt> -=cut +Guest argument is the name of a libvirt domain. -my $uri; +=item I<libvirtxml> -=item B<--connect URI> | B<-c URI> +Guest argument is the path to an XML file describing a libvirt domain. -Connect to libvirt using the given I<URI>. If omitted, then we connect to the -default libvirt hypervisor. +=back =cut -my $input = "libvirt"; +my $input_uri; -=item B<--input input> | B<-i input> +=item B<-ic URI> -The specified guest description uses the given I<input format>. The default is -C<libvirt>. Supported options are: +Specifies the connection to use when using the libvirt input method. If omitted, +then we connect to the default libvirt hypervisor. -=over - -=item I<libvirt> - -Guest argument is the name of a libvirt domain. +=cut -=item I<libvirtxml> +my $output_uri = "qemu:///system"; -Guest argument is the path to an XML file describing a libvirt domain. +=item B<-oc URI> -=back +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<-f file>, B<--config file> Load the virt-v2v configuration from I<file>. There is no default. +=item B<--help> + +Display brief help. + +=item B<--version> + +Display version number and exit. + =back =cut @@ -171,26 +172,28 @@ Load the virt-v2v configuration from I<file>. There is no default. # Initialise the message output prefix 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 - ) or pod2usage(2); -pod2usage(0) if($help); - -if ($version) { - print "$Sys::VirtV2V::VERSION\n"; - exit(0); -} +GetOptions ("help|?" => sub { + pod2usage(0); + }, + "version" => sub { + print "$Sys::VirtV2V::VERSION\n"; + exit(0); + }, + "c|connect" => sub { + # -c|--connect is the default for other virt tools. Be nice to + # the user and point out that virt-v2v is different. + pod2usage({ -message => __("Use -ic or -oc to specify an ". + "input or an output connection"), + -exitval => 1 }); + }, + "i=s" => \$input_method, + "ic=s" => \$input_uri, + "oc=s" => \$output_uri, + "f|config=s" => \$config_file +) or pod2usage(2); 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 +209,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 +242,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
On Mon, Feb 01, 2010 at 05:23:29PM +0000, Matthew Booth wrote:
Command line option changes: -s -> -f -c -> -ic
-c, --connect now generates an error message. New option -oc specifies output connection.
Looks good, ACK. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-df lists disk usage of guests without needing to install any software inside the virtual machine. Supports Linux and Windows. http://et.redhat.com/~rjones/virt-df/
--- 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 ad1610f..82f16ce 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 @@ -208,8 +208,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", @@ -217,7 +217,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
On Mon, Feb 01, 2010 at 05:23:30PM +0000, Matthew Booth wrote:
--- 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%)
This is a fairly straightforward rename, so ACK. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-p2v converts physical machines to virtual machines. Boot with a live CD or over the network (PXE) and turn machines into Xen guests. http://et.redhat.com/~rjones/virt-p2v
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 | 140 ++++++++---- 6 files changed, 676 insertions(+), 253 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 82f16ce..b097ccd 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 @@ -133,12 +134,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 @@ -151,9 +160,18 @@ 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<-f file>, B<--config file> +=item B<-f file> Load the virt-v2v configuration from I<file>. There is no default. @@ -189,6 +207,7 @@ GetOptions ("help|?" => sub { "i=s" => \$input_method, "ic=s" => \$input_uri, "oc=s" => \$output_uri, + "op=s" => \$output_pool, "f|config=s" => \$config_file ) or pod2usage(2); @@ -208,33 +227,89 @@ 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) or + pod2usage({ -message => user_message(__"You must specify a filename"), + -exitval => 1 }); + + # 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')); + } + + $conn = Sys::VirtV2V::Connection::LibVirtXML->new($config, $path); + } + + elsif ($input_method eq "libvirt") { + my $name = shift(@ARGV) or + pod2usage({ -message => user_message(__"You must specify a guest"), + -exitval => 1 }); + + # 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); + ############################################################################### ## 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); @@ -242,11 +317,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); @@ -255,15 +325,14 @@ $g->sync(); $vmm->define_domain($dom->toString()); +exit(0); ############################################################################### ## Helper functions 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(); @@ -328,27 +397,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
On Mon, Feb 01, 2010 at 05:23:31PM +0000, Matthew Booth wrote:
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.
This is pretty similar to the previous version of the patch, ACK. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones New in Fedora 11: Fedora Windows cross-compiler. Compile Windows programs, test, and build Windows installers. Over 70 libraries supprt'd http://fedoraproject.org/wiki/MinGW http://www.annexia.org/fedora_mingw
Add a set of default devices if they are not present. These are currently defined to be a ps2 mouse, tablet input and cirrus graphics. --- lib/Sys/VirtV2V/Converter.pm | 34 +++++++++++++++++++++++++++++++++- 1 files changed, 33 insertions(+), 1 deletions(-) diff --git a/lib/Sys/VirtV2V/Converter.pm b/lib/Sys/VirtV2V/Converter.pm index 64a5a46..1de17c8 100644 --- a/lib/Sys/VirtV2V/Converter.pm +++ b/lib/Sys/VirtV2V/Converter.pm @@ -67,8 +67,12 @@ use constant KVM_XML_VIRTIO => " <interface type='network'> <model type='virtio'/> </interface> + <input type='tablet' bus='usb'/> <input type='mouse' bus='ps2'/> <graphics type='vnc' port='-1' listen='127.0.0.1'/> + <video> + <model type='cirrus' vram='9216' heads='1'/> + </video> </devices> </domain> "; @@ -86,8 +90,12 @@ use constant KVM_XML_NOVIRTIO => " <interface type='network'> <model type='e1000'/> </interface> + <input type='tablet' bus='usb'/> <input type='mouse' bus='ps2'/> <graphics type='vnc' port='-1' listen='127.0.0.1'/> + <video> + <model type='cirrus' vram='9216' heads='1'/> + </video> </devices> </domain> "; @@ -179,9 +187,12 @@ sub _configure_metadata # Remove any configuration related to a PV kernel bootloader _unconfigure_bootloaders($dom); - # Configure network and block drivers in the guest + # Configure network and block drivers _configure_drivers($dom, $virtio); + # Ensure guest has a standard set of default devices + _configure_default_devices($dom, $default_dom); + # Add a default os section if none exists _configure_os($dom, $default_dom, $arch); } @@ -229,6 +240,27 @@ sub _configure_os $type->setAttribute('arch', $arch) unless(defined($arch_attr)); } +sub _configure_default_devices +{ + my ($dom, $default_dom) = @_; + + my ($devices) = $dom->findnodes('/domain/devices'); + + # Remove any existing input, graphics or video devices + foreach my $input ($devices->findnodes('input | video | graphics')) { + $devices->removeChild($input); + } + + my ($input_devices) = $default_dom->findnodes('/domain/devices'); + + # Add new default devices from default XML + foreach my $input ($input_devices->findnodes('input | video | graphics')) { + my $new = $input->cloneNode(1); + $new->setOwnerDocument($devices->getOwnerDocument()); + $devices->appendChild($new); + } +} + sub _configure_capabilities { my ($dom, $vmm, $guestcaps) = @_; -- 1.6.6
On Mon, Feb 01, 2010 at 05:23:32PM +0000, Matthew Booth wrote:
+sub _configure_default_devices +{ + my ($dom, $default_dom) = @_; + + my ($devices) = $dom->findnodes('/domain/devices'); + + # Remove any existing input, graphics or video devices + foreach my $input ($devices->findnodes('input | video | graphics')) { + $devices->removeChild($input); + } + + my ($input_devices) = $default_dom->findnodes('/domain/devices'); + + # Add new default devices from default XML + foreach my $input ($input_devices->findnodes('input | video | graphics')) { + my $new = $input->cloneNode(1); + $new->setOwnerDocument($devices->getOwnerDocument()); + $devices->appendChild($new); + } +}
How do we know that the guest has drivers for these, or do we just assume that any guest can drive a basic Cirrus card etc? What sort of devices do ESX guests come configured with? Is the XML generated by the libvirt ESX driver an accurate reflection of this? 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
On 04/02/10 09:47, Richard W.M. Jones wrote:
On Mon, Feb 01, 2010 at 05:23:32PM +0000, Matthew Booth wrote:
+sub _configure_default_devices +{ + my ($dom, $default_dom) = @_; + + my ($devices) = $dom->findnodes('/domain/devices'); + + # Remove any existing input, graphics or video devices + foreach my $input ($devices->findnodes('input | video | graphics')) { + $devices->removeChild($input); + } + + my ($input_devices) = $default_dom->findnodes('/domain/devices'); + + # Add new default devices from default XML + foreach my $input ($input_devices->findnodes('input | video | graphics')) { + my $new = $input->cloneNode(1); + $new->setOwnerDocument($devices->getOwnerDocument()); + $devices->appendChild($new); + } +}
How do we know that the guest has drivers for these, or do we just assume that any guest can drive a basic Cirrus card etc?
Well, we're short on choices. If it can't drive a basic Cirrus card, it can't have graphics, so I guess this doesn't hurt.
What sort of devices do ESX guests come configured with? Is the XML generated by the libvirt ESX driver an accurate reflection of this?
The ESX driver XML output doesn't include any input, graphics or video elements [1]. VMware guests use the 'vmware' X driver, which afaict is provided by VMwareTools. Matt [1] I should file a bug about that. -- Matthew Booth, RHCA, RHCSS Red Hat Engineering, Virtualisation Team M: +44 (0)7977 267231 GPG ID: D33C3490 GPG FPR: 3733 612D 2D05 5458 8A8A 1600 3441 EA19 D33C 3490
On Thu, Feb 04, 2010 at 11:08:45AM +0000, Matthew Booth wrote:
The ESX driver XML output doesn't include any input, graphics or video elements [1]. VMware guests use the 'vmware' X driver, which afaict is provided by VMwareTools.
<aside> The VMWare tools are open source now: http://open-vm-tools.sourceforge.net/ http://git.opensource.vmware.com/opensource/open-vm-tools/ [down] However it's my understanding that qemu upstream have rejected adding support for VMWare devices to qemu. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming blog: http://rwmj.wordpress.com Fedora now supports 80 OCaml packages (the OPEN alternative to F#) http://cocan.org/getting_started_with_ocaml_on_red_hat_and_fedora
--- lib/Sys/VirtV2V/Converter/Linux.pm | 21 ++++++++++++++++----- 1 files changed, 16 insertions(+), 5 deletions(-) diff --git a/lib/Sys/VirtV2V/Converter/Linux.pm b/lib/Sys/VirtV2V/Converter/Linux.pm index 057ef45..4458fc3 100644 --- a/lib/Sys/VirtV2V/Converter/Linux.pm +++ b/lib/Sys/VirtV2V/Converter/Linux.pm @@ -386,6 +386,7 @@ sub _unconfigure_hv my ($guestos, $desc) = @_; _unconfigure_xen($guestos, $desc); + _unconfigure_vmware($guestos, $desc); } # Unconfigure Xen specific guest modifications @@ -393,11 +394,6 @@ sub _unconfigure_xen { my ($guestos, $desc) = @_; - carp("unconfigure called without guestos argument") - unless defined($guestos); - carp("unconfigure called without desc argument") - unless defined($desc); - my $found_kmod = 0; # Look for kmod-xenpv-*, which can be found on RHEL 3 machines @@ -462,6 +458,21 @@ sub _unconfigure_xen } } +# Unconfigure VMware specific guest modifications +sub _unconfigure_vmware +{ + my ($guestos, $desc) = @_; + + # Uninstall VMwareTools + foreach my $app (@{$desc->{apps}}) { + my $name = $app->{name}; + + if ($name eq "VMwareTools") { + $guestos->remove_application($name); + } + } +} + # Get a list of all foreign hypervisor specific kernel modules which are being # used by the guest sub _find_hv_kernel_modules -- 1.6.6
On Mon, Feb 01, 2010 at 05:23:33PM +0000, Matthew Booth wrote:
@@ -393,11 +394,6 @@ sub _unconfigure_xen { my ($guestos, $desc) = @_;
- carp("unconfigure called without guestos argument") - unless defined($guestos); - carp("unconfigure called without desc argument") - unless defined($desc); - my $found_kmod = 0;
What was the point of removing these checks? Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones New in Fedora 11: Fedora Windows cross-compiler. Compile Windows programs, test, and build Windows installers. Over 70 libraries supprt'd http://fedoraproject.org/wiki/MinGW http://www.annexia.org/fedora_mingw
On 04/02/10 09:51, Richard W.M. Jones wrote:
On Mon, Feb 01, 2010 at 05:23:33PM +0000, Matthew Booth wrote:
@@ -393,11 +394,6 @@ sub _unconfigure_xen { my ($guestos, $desc) = @_;
- carp("unconfigure called without guestos argument") - unless defined($guestos); - carp("unconfigure called without desc argument") - unless defined($desc); - my $found_kmod = 0;
What was the point of removing these checks?
They were used inconsistently. I originally put them in when the 'external' interface was larger, and I only put them on the external interface. I've been removing them for internal calls. These checks are really just a way to get round perl's inability to check functions calls at 'compile' time. In practice, though, the lack of type information makes them of limited use. For example, if I changed the second argument to be a Sys::Virt handle, it wouldn't notice. In practise, they haven't been catching the errors I've actually been making. In short, I've gone off these checks. Matt -- Matthew Booth, RHCA, RHCSS Red Hat Engineering, Virtualisation Team M: +44 (0)7977 267231 GPG ID: D33C3490 GPG FPR: 3733 612D 2D05 5458 8A8A 1600 3441 EA19 D33C 3490
On Thu, Feb 04, 2010 at 10:14:38AM +0000, Matthew Booth wrote:
On 04/02/10 09:51, Richard W.M. Jones wrote:
On Mon, Feb 01, 2010 at 05:23:33PM +0000, Matthew Booth wrote:
@@ -393,11 +394,6 @@ sub _unconfigure_xen { my ($guestos, $desc) = @_;
- carp("unconfigure called without guestos argument") - unless defined($guestos); - carp("unconfigure called without desc argument") - unless defined($desc); - my $found_kmod = 0;
What was the point of removing these checks?
They were used inconsistently. I originally put them in when the 'external' interface was larger, and I only put them on the external interface. I've been removing them for internal calls.
These checks are really just a way to get round perl's inability to check functions calls at 'compile' time. In practice, though, the lack of type information makes them of limited use. For example, if I changed the second argument to be a Sys::Virt handle, it wouldn't notice. In practise, they haven't been catching the errors I've actually been making. In short, I've gone off these checks.
ACK. You can also use Perl prototypes (not that they'll catch type errors, but hey it's a dynamically typed language ...) sub _unconfigure_xen ($$) { ... } Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones New in Fedora 11: Fedora Windows cross-compiler. Compile Windows programs, test, and build Windows installers. Over 70 libraries supprt'd http://fedoraproject.org/wiki/MinGW http://www.annexia.org/fedora_mingw
Rename _configure_metadata to _convert_metadata --- lib/Sys/VirtV2V/Converter.pm | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Sys/VirtV2V/Converter.pm b/lib/Sys/VirtV2V/Converter.pm index 1de17c8..4115c1e 100644 --- a/lib/Sys/VirtV2V/Converter.pm +++ b/lib/Sys/VirtV2V/Converter.pm @@ -150,7 +150,7 @@ sub convert unless (defined($guestcaps)); # Convert the metadata - _configure_metadata($vmm, $dom, $desc, $guestcaps); + _convert_metadata($vmm, $dom, $desc, $guestcaps); my ($name) = $dom->findnodes('/domain/name/text()'); $name = $name->getNodeValue(); @@ -164,7 +164,7 @@ sub convert } } -sub _configure_metadata +sub _convert_metadata { my ($vmm, $dom, $desc, $guestcaps) = @_; -- 1.6.6
On Mon, Feb 01, 2010 at 05:23:34PM +0000, Matthew Booth wrote:
Rename _configure_metadata to _convert_metadata --- lib/Sys/VirtV2V/Converter.pm | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/Sys/VirtV2V/Converter.pm b/lib/Sys/VirtV2V/Converter.pm index 1de17c8..4115c1e 100644 --- a/lib/Sys/VirtV2V/Converter.pm +++ b/lib/Sys/VirtV2V/Converter.pm @@ -150,7 +150,7 @@ sub convert unless (defined($guestcaps));
# Convert the metadata - _configure_metadata($vmm, $dom, $desc, $guestcaps); + _convert_metadata($vmm, $dom, $desc, $guestcaps);
my ($name) = $dom->findnodes('/domain/name/text()'); $name = $name->getNodeValue(); @@ -164,7 +164,7 @@ sub convert } }
-sub _configure_metadata +sub _convert_metadata { my ($vmm, $dom, $desc, $guestcaps) = @_;
ACK. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones New in Fedora 11: Fedora Windows cross-compiler. Compile Windows programs, test, and build Windows installers. Over 70 libraries supprt'd http://fedoraproject.org/wiki/MinGW http://www.annexia.org/fedora_mingw
Add ACPI if the guest and hypervisor support it. Add APIC and PAE if the hypervisor supports it. --- lib/Sys/VirtV2V/Converter.pm | 66 ++++++++++++++++++++++++++++++----------- 1 files changed, 48 insertions(+), 18 deletions(-) diff --git a/lib/Sys/VirtV2V/Converter.pm b/lib/Sys/VirtV2V/Converter.pm index 4115c1e..a53dd92 100644 --- a/lib/Sys/VirtV2V/Converter.pm +++ b/lib/Sys/VirtV2V/Converter.pm @@ -314,28 +314,58 @@ sub _configure_capabilities } } - # Check that /domain/features are listed in capabilities - # Get a list of supported features - my %features; - foreach my $feature ($guestcap->findnodes('features/*')) { - $features{$feature->getNodeName()} = 1; - } + # Get the domain features node + my ($domfeatures) = $dom->findnodes('/domain/features'); + + # Check existing features are supported by the hypervisor + if (defined($domfeatures)) { + # Check that /domain/features are listed in capabilities + # Get a list of supported features + my %features; + foreach my $feature ($guestcap->findnodes('features/*')) { + $features{$feature->getNodeName()} = 1; + } - foreach my $feature ($dom->findnodes('/domain/features/*')) { - my $name = $feature->getNodeName(); + foreach my $feature ($domfeatures->findnodes('*')) { + my $name = $feature->getNodeName(); - if (!exists($features{$name})) { - print STDERR user_message - (__x("The connected hypervisor does not support ". - "feature {feature}", feature => $name)); - $feature->getParentNode()->removeChild($feature); + if (!exists($features{$name})) { + print STDERR user_message + (__x("The connected hypervisor does not support ". + "feature {feature}", feature => $name)); + $feature->getParentNode()->removeChild($feature); + } + + if ($name eq 'acpi' && !$guestcaps->{acpi}) { + print STDERR user_message + (__"The target guest does not support acpi under KVM. ACPI ". + "will be disabled."); + $feature->getParentNode()->removeChild($feature); + } } + } - if ($name eq 'acpi' && !$guestcaps->{acpi}) { - print STDERR user_message - (__"The target guest does not support acpi under KVM. ACPI ". - "will be disabled."); - $feature->getParentNode()->removeChild($feature); + # Add a features element if there isn't one already + else { + $domfeatures = $dom->createElement('features'); + my ($root) = $dom->findnodes('/domain'); + $root->appendChild($domfeatures); + } + + # Add acpi support if the guest supports it + if ($guestcaps->{acpi}) { + $domfeatures->appendChild($dom->createElement('acpi')); + } + + # Add apic and pae if they're supported by the hypervisor and not already + # there + foreach my $feature ('apic', 'pae') { + my ($d) = $domfeatures->findnodes($feature); + next if (defined($d)); + + my ($c) = $guestcap->findnodes("features/$feature"); + if (defined($c)) { + $domfeatures->appendChild($dom->createElement($feature)); } } } -- 1.6.6
On Mon, Feb 01, 2010 at 05:23:35PM +0000, Matthew Booth wrote:
Add ACPI if the guest and hypervisor support it. Add APIC and PAE if the hypervisor supports it. ---
Looks good, ACK. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming blog: http://rwmj.wordpress.com Fedora now supports 80 OCaml packages (the OPEN alternative to F#) http://cocan.org/getting_started_with_ocaml_on_red_hat_and_fedora
Don't update /domain/@type just for xen as it's always set explicitly to kvm. Don't update /domain/devices/input/@bus as it's replaced by a default device. --- lib/Sys/VirtV2V/Converter.pm | 69 ++++++++---------------------------------- 1 files changed, 13 insertions(+), 56 deletions(-) diff --git a/lib/Sys/VirtV2V/Converter.pm b/lib/Sys/VirtV2V/Converter.pm index a53dd92..736de8c 100644 --- a/lib/Sys/VirtV2V/Converter.pm +++ b/lib/Sys/VirtV2V/Converter.pm @@ -197,17 +197,6 @@ sub _convert_metadata _configure_os($dom, $default_dom, $arch); } -sub _unconfigure_hvs -{ - my ($dom, $default_dom) = @_; - die("unconfigure_hvs called without dom argument") - unless defined($dom); - die("unconfigure_hvs called without default_dom argument") - unless defined($default_dom); - - _unconfigure_xen_metadata($dom, $default_dom); -} - sub _configure_os { my ($dom, $default_dom, $arch) = @_; @@ -431,32 +420,20 @@ sub _configure_drivers } } -sub _replace_with_default_metadata +sub _unconfigure_hvs { - my ($node, $xpath, $default_dom) = @_; - - # Look for a replacement in the defaults - my ($default) = $default_dom->findnodes($xpath); - if(defined($default)) { - if($node->isa('XML::DOM::Attr')) { - $node->setNodeValue($default->getNodeValue()); - } else { - my $replacement = $default->cloneNode(1); - $replacement->setOwnerDocument($node->getOwnerDocument()); - - $node->getParentNode()->replaceChild($replacement, $node); - } - } - - else { - # Warn if no replacement was found - print STDERR user_message - (__x("WARNING: No replacement found for {xpath} in ". - "domain XML. The node was removed.", - xpath => $xpath)); + my ($dom, $default_dom) = @_; + die("unconfigure_hvs called without dom argument") + unless defined($dom); + die("unconfigure_hvs called without default_dom argument") + unless defined($default_dom); - $node->getParentNode()->removeChild($node); + # Remove emulator if it is defined + foreach my $emulator ($dom->findnodes('/domain/devices/emulator')) { + $emulator->getParent()->removeChild($emulator); } + + _unconfigure_xen_metadata($dom, $default_dom); } sub _unconfigure_xen_metadata @@ -466,23 +443,6 @@ sub _unconfigure_xen_metadata # The list of target xen-specific nodes is mostly taken from inspection of # domain.rng - # Nodes which should be replaced with a default if they are present - foreach my $hv_node ( - [ '/domain/@type', 'xen' ], - [ '/domain/devices/input/@bus', 'xen' ] - ) { - my $xpath = $hv_node->[0]; - my $pattern = $hv_node->[1]; - - foreach my $node ($dom->findnodes($xpath)) { - if(defined($pattern)) { - next unless($node->getNodeValue() =~ m{$pattern}); - } - - _replace_with_default_metadata($node, $xpath, $default_dom); - } - } - # Remove machine if it has a xen-specific value # We could replace it with the generic 'pc', but 'pc' is a moving target # across QEMU releases. By removing it entirely, libvirt will automatically @@ -495,11 +455,6 @@ sub _unconfigure_xen_metadata } } - # Remove emulator if it is defined - foreach my $emulator ($dom->findnodes('/domain/devices/emulator')) { - $emulator->getParent()->removeChild($emulator); - } - # Remove the script element if its path attribute is 'vif-bridge' foreach my $script ($dom->findnodes('/domain/devices/interface/script[@path = "vif-bridge"]')) { @@ -507,6 +462,8 @@ sub _unconfigure_xen_metadata } # Other Xen related metadata is handled separately + # /domain/@type + # /domain/devices/input/@bus = xen # /domain/devices/disk/target/@bus = 'xen' # /domain/os/loader = 'xen' # /domain/bootloader -- 1.6.6
On Mon, Feb 01, 2010 at 05:23:36PM +0000, Matthew Booth wrote:
Don't update /domain/@type just for xen as it's always set explicitly to kvm. Don't update /domain/devices/input/@bus as it's replaced by a default device.
Not sure I understand the explanation for this, but the code looks OK, so ACK. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-top is 'top' for virtual machines. Tiny program with many powerful monitoring features, net stats, disk stats, logging, etc. http://et.redhat.com/~rjones/virt-top
On 04/02/10 09:54, Richard W.M. Jones wrote:
On Mon, Feb 01, 2010 at 05:23:36PM +0000, Matthew Booth wrote:
Don't update /domain/@type just for xen as it's always set explicitly to kvm. Don't update /domain/devices/input/@bus as it's replaced by a default device.
Not sure I understand the explanation for this, but the code looks OK, so ACK.
I used to have some code in there which said: if /domain/@type == xen replace it with the default value Now I just unconditionally replace it with the default value. Same for the input device. Matt -- Matthew Booth, RHCA, RHCSS Red Hat Engineering, Virtualisation Team M: +44 (0)7977 267231 GPG ID: D33C3490 GPG FPR: 3733 612D 2D05 5458 8A8A 1600 3441 EA19 D33C 3490
On Mon, Feb 1, 2010 at 5:23 PM, Matthew Booth <mbooth@redhat.com> wrote:
With this patchset I have successfully[1] imported a RHEL 5 guest directly from ESX with the following command line:
virt-v2v -ic 'esx://yellow.marston/?no_verify=1' -op transfer RHEL5-64
Login details are stored in ~/.netrc
Note that this is the only guest I've tested against. I haven't for example, checked that I haven't broken Xen imports.
Will this work, or can this be easily modified to work for VMware Server guests? Adam
Matt
[1] With the exception of network reconfiguration. After import I manually munged the network config with virsh edit.
_______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://www.redhat.com/mailman/listinfo/libguestfs
On 03/02/10 23:45, Adam Huffman wrote:
On Mon, Feb 1, 2010 at 5:23 PM, Matthew Booth <mbooth@redhat.com> wrote:
With this patchset I have successfully[1] imported a RHEL 5 guest directly from ESX with the following command line:
virt-v2v -ic 'esx://yellow.marston/?no_verify=1' -op transfer RHEL5-64
Login details are stored in ~/.netrc
Note that this is the only guest I've tested against. I haven't for example, checked that I haven't broken Xen imports.
Will this work, or can this be easily modified to work for VMware Server guests?
Adam, I haven't looked at VMware Server, but my best guess is that this wouldn't be straightforward. I would expect the guest modifications to be identical. The issue would be in obtaining the guest metadata and storage. For ESX we use libvirt's existing driver, which means we don't have to parse vmx ourselves. Also, ESX conveniently makes a raw version of the guest's storage available, which means we don't have to parse vmdk. Without looking at VMware Server, my guess would be that it embeds vmx in the guest's vmdk, and doesn't make raw storage available directly. If this is the case, we'd need to be able to parse vmdk properly, and extract and parse the vmx. While qemu nominally includes support for vmdk, it only supports a subset of internal storage types, and it doesn't support the latest version of the format. Fixing that up would probably be a prerequisite. Let me know if my assumptions are wrong! It could be easier than that. If you're in the mood for submitting patches, we can certainly help you get going. Matt -- Matthew Booth, RHCA, RHCSS Red Hat Engineering, Virtualisation Team M: +44 (0)7977 267231 GPG ID: D33C3490 GPG FPR: 3733 612D 2D05 5458 8A8A 1600 3441 EA19 D33C 3490
participants (3)
-
Adam Huffman -
Matthew Booth -
Richard W.M. Jones