Matthew Booth
2010-Feb-01 17:23 UTC
[Libguestfs] [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.
Matthew Booth
2010-Feb-01 17:23 UTC
[Libguestfs] [PATCH 1/8] MetadataReader: Allow different libvirt connections for input and output
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
Matthew Booth
2010-Feb-01 17:23 UTC
[Libguestfs] [PATCH 2/8] 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 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
Matthew Booth
2010-Feb-01 17:23 UTC
[Libguestfs] [PATCH 3/8] 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 | 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
Matthew Booth
2010-Feb-01 17:23 UTC
[Libguestfs] [PATCH 4/8] Converter: Configure default devices
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
Matthew Booth
2010-Feb-01 17:23 UTC
[Libguestfs] [PATCH 5/8] Converter: Remove VMware tools if it is installed
---
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
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
Matthew Booth
2010-Feb-01 17:23 UTC
[Libguestfs] [PATCH 7/8] Converter: add default <features> if none are present
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
Matthew Booth
2010-Feb-01 17:23 UTC
[Libguestfs] [PATCH 8/8] Converter: Remove obsolete xen-specific configuration
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
Adam Huffman
2010-Feb-03 23:45 UTC
[Libguestfs] [ESX support] Working ESX conversion for RHEL 5
On Mon, Feb 1, 2010 at 5:23 PM, Matthew Booth <mbooth at 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 at redhat.com > https://www.redhat.com/mailman/listinfo/libguestfs >