Move all target-specific functionality into its own module in preparation for
output to RHEV.
---
MANIFEST | 1 +
lib/Sys/VirtV2V/Connection.pm | 46 ++---
lib/Sys/VirtV2V/Converter.pm | 138 +------------
lib/Sys/VirtV2V/Target/LibVirt.pm | 419 +++++++++++++++++++++++++++++++++++++
lib/Sys/VirtV2V/Transfer/ESX.pm | 91 +++------
po/POTFILES.in | 1 +
v2v/virt-v2v.pl | 69 ++++---
7 files changed, 511 insertions(+), 254 deletions(-)
create mode 100644 lib/Sys/VirtV2V/Target/LibVirt.pm
diff --git a/MANIFEST b/MANIFEST
index cc6dd92..d4dd140 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/Target/LibVirt.pm
lib/Sys/VirtV2V/Transfer/ESX.pm
MANIFEST This list of files
MANIFEST.SKIP
diff --git a/lib/Sys/VirtV2V/Connection.pm b/lib/Sys/VirtV2V/Connection.pm
index 46bd020..5ecc7e3 100644
--- a/lib/Sys/VirtV2V/Connection.pm
+++ b/lib/Sys/VirtV2V/Connection.pm
@@ -36,7 +36,7 @@ Sys::VirtV2V::Connection - Obtain domain metadata
use Sys::VirtV2V::Connection::LibVirt;
- $conn = Sys::VirtV2V::Connection::LibVirt->new($uri, $name, $pool);
+ $conn = Sys::VirtV2V::Connection::LibVirt->new($uri, $name, $target);
$dom = $conn->get_dom();
$storage = $conn->get_storage_paths();
$devices = $conn->get_storage_devices();
@@ -106,7 +106,7 @@ sub _storage_iterate
{
my $self = shift;
- my ($transfer, $pool) = @_;
+ my ($transfer, $target) = @_;
my $dom = $self->get_dom();
@@ -121,8 +121,8 @@ sub _storage_iterate
defined($source) or die("source element has neither dev nor file: \n".
$dom->toString());
- my ($target) = $disk->findnodes('target/@dev');
- defined($target) or die("disk does not have a target device: \n".
+ my ($dev) = $disk->findnodes('target/@dev');
+ defined($dev) or die("disk does not have a target device: \n".
$dom->toString());
# If the disk is a floppy or a cdrom, blank its source
@@ -135,16 +135,15 @@ sub _storage_iterate
my $path = $source->getValue();
if (defined($transfer)) {
- # Die if transfer required and no output pool
- die (user_message(__"No output pool was specified"))
- unless (defined($pool));
+ # Die if transfer required and no output target
+ die (user_message(__"No output target was specified"))
+ unless (defined($target));
# Fetch the remote storage
- my $vol = $transfer->transfer($self, $path, $pool);
+ my $vol = $transfer->transfer($self, $path, $target);
- # Parse the XML description of the returned volume
- my $voldom =
- new XML::DOM::Parser->parse($vol->get_xml_description());
+ # Export the new path
+ $path = $vol->get_path();
# Find any existing driver element.
my ($driver) = $disk->findnodes('driver');
@@ -156,37 +155,24 @@ sub _storage_iterate
$disk->appendChild($driver);
}
$driver->setAttribute('name', 'qemu');
-
- # Get the volume format for passing to the qemu driver
- my ($format) =
- $voldom->findnodes('/volume/target/format/@type');
-
- $format = $format->getValue() if (defined($format));
-
- # Auto-detect if no format is specified explicitly
- $format ||= 'auto';
-
- $driver->setAttribute('type', $format);
+ $driver->setAttribute('type', $vol->get_format());
# 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)
+ if ($vol->is_block())
{
- $disk->setAttribute('type', 'file');
- $source_e->setAttribute('file', $path);
- } else {
$disk->setAttribute('type', 'block');
$source_e->setAttribute('dev', $path);
+ } else {
+ $disk->setAttribute('type', 'file');
+ $source_e->setAttribute('file', $path);
}
}
push(@paths, $path);
- push(@devices, $target->getNodeValue());
+ push(@devices, $dev->getNodeValue());
}
}
diff --git a/lib/Sys/VirtV2V/Converter.pm b/lib/Sys/VirtV2V/Converter.pm
index b817f49..fbcaa51 100644
--- a/lib/Sys/VirtV2V/Converter.pm
+++ b/lib/Sys/VirtV2V/Converter.pm
@@ -42,7 +42,7 @@ Sys::VirtV2V::Converter - Convert a guest to run on KVM
use Sys::VirtV2V::Converter;
my $guestos = Sys::VirtV2V::GuestOS->new($g, $os, $dom, $config);
- Sys::VirtV2V::Converter->convert($vmm, $guestos, $config, $dom, $os, $devices);
+ Sys::VirtV2V::Converter->convert($guestos, $config, $dom, $os, $devices);
=head1 DESCRIPTION
@@ -102,16 +102,12 @@ use constant KVM_XML_NOVIRTIO => "
</domain>
";
-=item Sys::VirtV2V::Converter->convert(vmm, guestos, dom, desc)
+=item Sys::VirtV2V::Converter->convert(guestos, dom, desc)
Instantiate an appropriate backend and call convert on it.
=over
-=item vmm
-
-A Sys::Virt connection.
-
=item guestos
An initialised Sys::VirtV2V::GuestOS object for the guest.
@@ -137,8 +133,7 @@ sub convert
{
my $class = shift;
- my ($vmm, $guestos, $config, $dom, $desc, $devices) = @_;
- carp("convert called without vmm argument") unless defined($vmm);
+ my ($guestos, $config, $dom, $desc, $devices) = @_;
carp("convert called without guestos argument") unless defined($guestos);
# config will be undefined if no config was specified
carp("convert called without dom argument") unless defined($dom);
@@ -162,23 +157,14 @@ sub convert
_map_networks($dom, $config) if (defined($config));
# Convert the metadata
- _convert_metadata($vmm, $dom, $desc, $devices, $guestcaps);
-
- my ($name) = $dom->findnodes('/domain/name/text()');
- $name = $name->getNodeValue();
+ _convert_metadata($dom, $desc, $devices, $guestcaps);
- if($guestcaps->{virtio}) {
- print user_message
- (__x("{name} configured with virtio drivers", name => $name));
- } else {
- print user_message
- (__x("{name} configured without virtio drivers", name =>
$name));
- }
+ return $guestcaps;
}
sub _convert_metadata
{
- my ($vmm, $dom, $desc, $devices, $guestcaps) = @_;
+ my ($dom, $desc, $devices, $guestcaps) = @_;
my $arch = $guestcaps->{arch};
my $virtio = $guestcaps->{virtio};
@@ -193,9 +179,6 @@ sub _convert_metadata
# Replace source hypervisor metadata with KVM defaults
_unconfigure_hvs($dom, $default_dom);
- # Configure guest according to local hypervisor's capabilities
- _configure_capabilities($dom, $vmm, $guestcaps);
-
# Remove any configuration related to a PV kernel bootloader
_unconfigure_bootloaders($dom);
@@ -264,115 +247,6 @@ sub _configure_default_devices
}
}
-sub _configure_capabilities
-{
- my ($dom, $vmm, $guestcaps) = @_;
-
- # Parse the capabilities of the connected libvirt
- my $caps = new XML::DOM::Parser->parse($vmm->get_capabilities());
-
- my $arch = $guestcaps->{arch};
-
- (my $guestcap) = $caps->findnodes
-
("/capabilities/guest[arch[\@name='$arch']/domain/\@type='kvm']");
-
- die(__x("The connected hypervisor does not support a {arch} kvm guest",
- arch => $arch)) unless(defined($guestcap));
-
- # Ensure that /domain/@type = 'kvm'
- my ($type) = $dom->findnodes('/domain/@type');
- $type->setNodeValue('kvm');
-
- # Set /domain/os/type to the value taken from capabilities
- my ($os_type) = $dom->findnodes('/domain/os/type/text()');
- if(defined($os_type)) {
- my ($caps_os_type) = $guestcap->findnodes('os_type/text()');
- $os_type->setNodeValue($caps_os_type->getNodeValue());
- }
-
- # Check that /domain/os/type/@machine, if set, is listed in capabilities
- my ($machine) = $dom->findnodes('/domain/os/type/@machine');
- if(defined($machine)) {
- my @machine_caps = $guestcap->findnodes
- ("arch[\@name='$arch']/machine/text()");
-
- my $found = 0;
- foreach my $machine_cap (@machine_caps) {
- if($machine eq $machine_cap) {
- $found = 1;
- last;
- }
- }
-
- # If the machine isn't listed as a capability, warn and remove it
- if(!$found) {
- print STDERR user_message
- (__x("The connected hypervisor does not support a ".
- "machine type of {machine}. It will be set to the ".
- "current default.",
- machine => $machine->getValue()));
-
- my ($type) = $dom->findnodes('/domain/os/type');
- $type->getAttributes()->removeNamedItem('machine');
- }
- }
-
- # 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 ($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 ($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));
- }
- }
-}
-
sub _unconfigure_bootloaders
{
my ($dom) = @_;
diff --git a/lib/Sys/VirtV2V/Target/LibVirt.pm b/lib/Sys/VirtV2V/Target/LibVirt.pm
new file mode 100644
index 0000000..96ed513
--- /dev/null
+++ b/lib/Sys/VirtV2V/Target/LibVirt.pm
@@ -0,0 +1,419 @@
+# Sys::VirtV2V::Target::LibVirt
+# 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
+
+use strict;
+use warnings;
+
+package Sys::VirtV2V::Target::LibVirt::Vol;
+
+sub _new
+{
+ my $class = shift;
+ my ($vol) = @_;
+
+ my $self = {};
+ bless($self, $class);
+
+ $self->{vol} = $vol;
+
+ return $self;
+}
+
+sub _create
+{
+ my $class = shift;
+ my ($pool, $name, $size) = @_;
+
+ my $vol_xml = "
+ <volume>
+ <name>$name</name>
+ <capacity>$size</capacity>
+ </volume>
+ ";
+
+ my $vol;
+ eval {
+ $vol = $pool->create_volume($vol_xml);
+ };
+ die(user_message(__x("Failed to create storage volume: {error}",
+ error => $@->stringify()))) if ($@);
+
+ return $class->_new($vol);
+}
+
+sub _get
+{
+ my $class = shift;
+ my ($pool, $name) = @_;
+
+ my $vol;
+ eval {
+ $vol = $pool->get_volume_by_name($name);
+ };
+ die(user_message(__x("Failed to get storage volume: {error}",
+ error => $@->stringify()))) if ($@);
+
+ return $class->_new($vol);
+}
+
+sub get_path
+{
+ my $self = shift;
+
+ return $self->{vol}->get_path();
+}
+
+sub get_format
+{
+ my $self = shift;
+
+ my $vol = $self->{vol};
+ my $voldom = new XML::DOM::Parser->parse($vol->get_xml_description());
+
+ my ($format) = $voldom->findnodes('/volume/target/format/@type');
+ $format = $format->getValue() if (defined($format));
+ $format ||= 'auto';
+
+ return $format;
+}
+
+sub is_block
+{
+ my $self = shift;
+
+ my $type = $self->{vol}->get_info()->{type};
+ return $type == Sys::Virt::StorageVol::TYPE_BLOCK;
+}
+
+sub open
+{
+ my $self = shift;
+
+ my $path = $self->get_path();
+ open(my $fd, '>', $path)
+ or die(user_message(__x("Error opening storage volume {path} ".
+ "for writing: {error}", error => $!)));
+
+ $self->{fd} = $fd;
+}
+
+sub write
+{
+ my $self = shift;
+ my ($data) = @_;
+
+ defined($self->{fd}) or die("write called without open");
+
+ syswrite($self->{fd}, $data)
+ or die(user_message(__x("Error writing to {path}: {error}",
+ path => $self->get_path(),
+ error => $!)));
+}
+
+sub close
+{
+ my $self = shift;
+
+ close($self->{fd})
+ or die(user_message(__x("Error closing volume handle: {error}",
+ error => $!)));
+
+ delete($self->{fd});
+}
+
+package Sys::VirtV2V::Target::LibVirt;
+
+use Locale::TextDomain 'virt-v2v';
+
+=head1 NAME
+
+Sys::VirtV2V::Target::LibVirt - Output to libvirt
+
+=head1 SYNOPSIS
+
+ use Sys::VirtV2V::Target::LibVirt;
+
+ my $target = new Sys::VirtV2V::Target::LibVirt($uri, $poolname);
+
+=head1 DESCRIPTION
+
+Sys::VirtV2V::Target::LibVirt creates a new libvirt domain using the given
+target URI. New storage will be created in the target pool.
+
+=head1 METHODS
+
+=over
+
+=item Sys::VirtV2V::Target::LibVirt->new(uri, poolname)
+
+Create a new Sys::VirtV2V::Target::LibVirt object.
+
+=over
+
+=item uri
+
+A libvirt connection URI
+
+=item poolname
+
+The name of a storage pool managed by the target libvirt daemon.
+
+=back
+
+=cut
+
+sub new
+{
+ my $class = shift;
+ my ($uri, $poolname) = @_;
+
+ my $self = {};
+ bless($self, $class);
+
+ $self->{vmm} = Sys::Virt->new(auth => 1, uri => $uri);
+
+ if (defined($poolname)) {
+ eval {
+ $self->{pool} = $self->{vmm}->get_storage_pool_by_name($poolname);
+ };
+
+ if ($@) {
+ die(user_message(__x("Output pool {poolname} is not a valid ".
+ "storage pool",
+ poolname => $poolname)));
+ }
+ }
+
+ return $self;
+}
+
+=item create_volume(name, size)
+
+Create a new volume in the pool whose name was passed to new().
+
+=over
+
+=item name
+
+The name of the volume which is being created.
+
+=item size
+
+The size of the volume which is being created in bytes.
+
+=back
+
+create_volume() returns a Sys::VirtV2V::Target::LibVirt::Vol object.
+
+=cut
+
+sub create_volume
+{
+ my $self = shift;
+ my ($name, $size) = @_;
+
+ return Sys::VirtV2V::Target::LibVirt::Vol->_create($self->{pool},
+ $name, $size);
+}
+
+=item volume_exists (name)
+
+Check if volume I<name> exists in the target pool.
+
+Returns 1 if it exists, 0 otherwise.
+
+=cut
+
+sub volume_exists
+{
+ my $self = shift;
+ my ($name) = @_;
+
+ my $vol;
+ eval {
+ $vol = $self->{pool}->get_volume_by_name($name);
+ };
+
+ # The above command will generate VIR_ERR_NO_STORAGE_VOL if the
+ # volume doesn't exist
+ if ($@ && $@->code == Sys::Virt::Error::ERR_NO_STORAGE_VOL) {
+ return 0;
+ }
+
+ if ($@) {
+ # We got an error, but not the one we expected
+ die(user_message(__x("Unexpected error accessing storage pool: ",
+ "{error}", error => $@->stringify())));
+ }
+
+ return 1;
+}
+
+=item get_volume (name)
+
+Get a reference to an existing volume. See L<create_volume> for return value.
+
+=cut
+
+sub get_volume
+{
+ my $self = shift;
+ my ($name) = @_;
+
+ return Sys::VirtV2V::Target::LibVirt::Vol->_get($self->{pool}, $name);
+}
+
+=item create_guest(dom)
+
+Create the guest in the target
+
+=cut
+
+sub create_guest
+{
+ my $self = shift;
+ my ($dom, $guestcaps) = @_;
+
+ my $vmm = $self->{vmm};
+
+ _configure_capabilities($vmm, $dom, $guestcaps);
+
+ $vmm->define_domain($dom->toString());
+}
+
+# Configure guest according to target hypervisor's capabilities
+sub _configure_capabilities
+{
+ my ($vmm, $dom, $guestcaps) = @_;
+
+ # Parse the capabilities of the connected libvirt
+ my $caps = new XML::DOM::Parser->parse($vmm->get_capabilities());
+
+ my $arch = $guestcaps->{arch};
+
+ (my $guestcap) = $caps->findnodes
+
("/capabilities/guest[arch[\@name='$arch']/domain/\@type='kvm']");
+
+ die(__x("The connected hypervisor does not support a {arch} kvm guest",
+ arch => $arch)) unless(defined($guestcap));
+
+ # Ensure that /domain/@type = 'kvm'
+ my ($type) = $dom->findnodes('/domain/@type');
+ $type->setNodeValue('kvm');
+
+ # Set /domain/os/type to the value taken from capabilities
+ my ($os_type) = $dom->findnodes('/domain/os/type/text()');
+ if(defined($os_type)) {
+ my ($caps_os_type) = $guestcap->findnodes('os_type/text()');
+ $os_type->setNodeValue($caps_os_type->getNodeValue());
+ }
+
+ # Check that /domain/os/type/@machine, if set, is listed in capabilities
+ my ($machine) = $dom->findnodes('/domain/os/type/@machine');
+ if(defined($machine)) {
+ my @machine_caps = $guestcap->findnodes
+ ("arch[\@name='$arch']/machine/text()");
+
+ my $found = 0;
+ foreach my $machine_cap (@machine_caps) {
+ if($machine eq $machine_cap) {
+ $found = 1;
+ last;
+ }
+ }
+
+ # If the machine isn't listed as a capability, warn and remove it
+ if(!$found) {
+ print STDERR user_message
+ (__x("The connected hypervisor does not support a ".
+ "machine type of {machine}. It will be set to the ".
+ "current default.",
+ machine => $machine->getValue()));
+
+ my ($type) = $dom->findnodes('/domain/os/type');
+ $type->getAttributes()->removeNamedItem('machine');
+ }
+ }
+
+ # 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 ($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 ($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));
+ }
+ }
+}
+
+=back
+
+=head1 COPYRIGHT
+
+Copyright (C) 2010 Red Hat Inc.
+
+=head1 LICENSE
+
+Please see the file COPYING for the full license.
+
+=cut
+
+1;
diff --git a/lib/Sys/VirtV2V/Transfer/ESX.pm b/lib/Sys/VirtV2V/Transfer/ESX.pm
index 66ba515..2d15732 100644
--- a/lib/Sys/VirtV2V/Transfer/ESX.pm
+++ b/lib/Sys/VirtV2V/Transfer/ESX.pm
@@ -71,7 +71,7 @@ sub new {
});
$self->{_v2v_server} = $server;
- $self->{_v2v_pool} = $pool;
+ $self->{_v2v_target} = $target;
$self->{_v2v_username} = $username;
$self->{_v2v_password} = $password;
@@ -113,31 +113,19 @@ sub get_volume
$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 $volname = $vmdk;
+ $volname =~ s,/,_,g;
+ $self->{_v2v_volname} = $volname;
+
+ my $target = $self->{_v2v_target};
+ if ($target->volume_exists($volname)) {
+ print STDERR user_message(__x("WARNING: storage volume {name} ".
+ "already exists in the target ".
+ "pool. NOT fetching it again. ".
+ "Delete the volume and retry to ".
+ "download again.",
+ name => $volname));
+ return $target->get_volume($volname);
}
$self->{_v2v_received} = 0;
@@ -150,11 +138,9 @@ sub get_volume
my $died = $r->header('X-Died');
die($died) if (defined($died));
- # Close the volume file descriptor
- close($self->{_v2v_volfh})
- or die(user_message(__x("Error closing volume handle: {error}",
- error => $!)));
- return $self->{_v2v_vol};
+ my $vol = $self->{_v2v_vol};
+ $vol->close();
+ return $vol;
}
die(user_message(__x("Didn't receive full volume. Received {received} of
".
@@ -192,14 +178,8 @@ sub handle_data
my ($data, $response) = @_;
- my $volfh = $self->{_v2v_volfh};
-
$self->{_v2v_received} += length($data);
-
- syswrite($volfh, $data)
- or die(user_message(__x("Error writing to {path}: {error}",
- path => $self->{_v2v_volpath},
- error => $!)));
+ $self->{_v2v_vol}->write($data);
}
sub create_volume
@@ -208,9 +188,8 @@ sub create_volume
my ($response) = @_;
- my $pool = $self->{_v2v_pool};
+ my $target = $self->{_v2v_target};
- # 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));
@@ -218,27 +197,9 @@ sub create_volume
my $size = $response->content_length();
$self->{_v2v_volsize} = $size;
- 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;
+ my $vol = $target->create_volume($name, $size);
+ $vol->open();
+ $self->{_v2v_vol} = $vol;
}
sub verify_certificate
@@ -295,10 +256,10 @@ Sys::VirtV2V::Transfer::ESX retrieves guest storage devices from an
ESX server.
=over
-=item transfer(conn, path, pool)
+=item transfer(conn, path, target)
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>.
+be taken from <conn>. Storage will be created using <target>.
=cut
@@ -306,7 +267,7 @@ sub transfer
{
my $class = shift;
- my ($conn, $path, $pool) = @_;
+ my ($conn, $path, $target) = @_;
my $uri = $conn->{uri};
my $username = $conn->{username};
@@ -330,7 +291,7 @@ sub transfer
my $ua = Sys::VirtV2V::Transfer::ESX::UA->new($conn->{hostname},
$username,
$password,
- $pool,
+ $target,
$noverify);
return $ua->get_volume($path);
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 3874426..ffdf250 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -7,6 +7,7 @@
../lib/Sys/VirtV2V/GuestOS.pm
../lib/Sys/VirtV2V/GuestOS/RedHat.pm
../lib/Sys/VirtV2V.pm
+../lib/Sys/VirtV2V/Target/LibVirt.pm
../lib/Sys/VirtV2V/Transfer/ESX.pm
../lib/Sys/VirtV2V/UserMessage.pm
../snapshot/v2v-snapshot.pl
diff --git a/v2v/virt-v2v.pl b/v2v/virt-v2v.pl
index 33e65f3..a9e834f 100755
--- a/v2v/virt-v2v.pl
+++ b/v2v/virt-v2v.pl
@@ -36,6 +36,7 @@ use Sys::VirtV2V;
use Sys::VirtV2V::Converter;
use Sys::VirtV2V::Connection::LibVirt;
use Sys::VirtV2V::Connection::LibVirtXML;
+use Sys::VirtV2V::Target::LibVirt;
use Sys::VirtV2V::ExecHelper;
use Sys::VirtV2V::GuestOS;
use Sys::VirtV2V::UserMessage qw(user_message);
@@ -99,11 +100,29 @@ my $input_transport;
=item B<-it method>
-Species the transport method used to obtain raw storage from the source guest.
+Specifies the transport method used to obtain raw storage from the source guest.
This is currently only a placeholder, and does nothing.
=cut
+my $output_method = "libvirt";
+
+=item B<-o method>
+
+Specifies the output method. Supported output methods are:
+
+=over
+
+=item libvirt
+
+Create a libvirt guest. See the I<-oc> and I<-op> options.
+
+=back
+
+If no output type is specified, it defaults to libvirt.
+
+=cut
+
my $output_uri = "qemu:///system";
=item B<-oc URI>
@@ -186,11 +205,13 @@ if(defined($config_file)) {
path => $config_file, error => $@))) if ($@);
}
-# Connect to target libvirt
-my $vmm = Sys::Virt->new(
- auth => 1,
- uri => $output_uri
-);
+my $target;
+if ($output_method eq "libvirt") {
+ $target = new Sys::VirtV2V::Target::LibVirt($output_uri, $output_pool);
+} else {
+ die(user_message(__x("{output} is not a valid output method",
+ output => $output_method)));
+}
# Get an appropriate Connection
my $conn;
@@ -215,24 +236,8 @@ eval {
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);
+ $target);
# Warn if we were given more than 1 argument
if(scalar(@_) > 0) {
@@ -280,10 +285,20 @@ my $os = inspect_guest($g);
my $guestos = Sys::VirtV2V::GuestOS->new($g, $os, $dom, $config);
# Modify the guest and its metadata for the target hypervisor
-Sys::VirtV2V::Converter->convert($vmm, $guestos, $config, $dom, $os,
- $conn->get_storage_devices());
-
-$vmm->define_domain($dom->toString());
+my $guestcaps = Sys::VirtV2V::Converter->convert($guestos, $config, $dom, $os,
+ $conn->get_storage_devices());
+
+$target->create_guest($dom, $guestcaps);
+
+my ($name) = $dom->findnodes('/domain/name/text()');
+$name = $name->getNodeValue();
+if($guestcaps->{virtio}) {
+ print user_message
+ (__x("{name} configured with virtio drivers", name => $name));
+} else {
+ print user_message
+ (__x("{name} configured without virtio drivers", name => $name));
+}
exit(0);
--
1.6.6.1