Rewrite the code to create the transfer ISO to use the new XML config file
format, and move it out of GuestOS in to virt-v2v.pl
---
lib/Sys/VirtV2V/GuestOS.pm | 217 +++++++++++++++-------------
lib/Sys/VirtV2V/GuestOS/RedHat.pm | 294 ++++++++++++++++---------------------
v2v/virt-v2v.pl | 94 +++++++++++-
3 files changed, 328 insertions(+), 277 deletions(-)
diff --git a/lib/Sys/VirtV2V/GuestOS.pm b/lib/Sys/VirtV2V/GuestOS.pm
index 1db7590..539659e 100644
--- a/lib/Sys/VirtV2V/GuestOS.pm
+++ b/lib/Sys/VirtV2V/GuestOS.pm
@@ -43,7 +43,7 @@ Sys::VirtV2V::GuestOS - Manipulate and query a Guest OS
use Sys::VirtV2V::GuestOS;
- $guestos = Sys::VirtV2V::GuestOS->instantiate($g, $desc);
+ $guestos = Sys::VirtV2V::GuestOS->new($g, $desc, $dom, $config);
=head1 DESCRIPTION
@@ -57,25 +57,11 @@ implements methods to access backends.
Sys::VirtV2V::GuestOS uses L<Module::Pluggable> to automatically discover
backends under Sys::VirtV2V::GuestOS.
-=cut
-
-# A map of file labels to their paths relative to the transfer device
-my %files;
-
-# A map of file labels to their dependencies
-my %deps;
-
-# A map of file labels aliases
-my %aliases;
-
-# The path (on the host) to the transfer iso
-my $transferiso;
-
=head1 METHODS
=over
-=item instantiate(g, desc)
+=item new(g, desc, dom, config)
Instantiate a GuestOS object capable of manipulating the target OS.
@@ -89,123 +75,162 @@ A L<Sys::Guestfs> handle.
An OS description created by L<Sys::Guestfs::Lib>.
+=item dom
+
+An XML::DOM object containing the guest's libvirt domain XML prior to
+conversion.
+
+=item config
+
+An XML::DOM object containing the virt-v2v configuration.
+
=back
-Returns a capable Sys::VirtV2V::GuestOS backend if one is found.
+Returns a capable Sys::VirtV2V::GuestOS if one is found.
Returns undef otherwise.
=cut
-sub instantiate
+sub new
{
my $class = shift;
- my ($g, $desc) = @_;
- defined($g) or carp("get_instance called without g argument");
- defined($desc) or carp("get_instance called without desc argument");
+ my ($g, $desc, $dom, $config) = @_;
+ defined($g) or carp("instantiate called without g argument");
+ defined($desc) or carp("instantiate called without desc argument");
+ defined($dom) or carp("instantiate called without dom argument");
+ defined($config) or carp("instantiate called without config argument");
+
+ my $self = {};
+
+ $self->{g} = $g;
+ $self->{desc} = $desc;
+ $self->{dom} = $dom;
+ $self->{config} = $config;
foreach my $module ($class->modules()) {
- return $module->new($g, $desc, \%files, \%deps, \%aliases)
- if($module->can_handle($desc));
+ return $module->new($self)
+ if($module->can_handle($desc));
}
return undef;
}
-=item configure(config)
+=item get_ncpus
-=over
+Return the number of CPUS which are available to this guest
-=item config
+=cut
-The parsed virt-v2v config file, as returned by Config::Tiny.
+sub get_ncpus
+{
+ my $self = shift;
-=back
+ my ($ncpus) = $self->{dom}->findnodes('/domain/vcpu/text()');
+ if (defined($ncpus)) {
+ return $ncpus->getData();
+ } else {
+ return 1;
+ }
+}
+
+=item get_memory_kb
-Read the [files], [deps] and [aliases] sections of the virt-v2v config file.
-Create the transfer iso from the contents of [files].
+Return the amount of memory, in KB, which is available to this guest
=cut
-sub configure
+sub get_memory_kb
{
- my $class = shift;
+ my $self = shift;
- my $config = shift;
+ my ($mem_kb) = $self->{dom}->findnodes('/domain/memory/text()');
- carp("configure called without config argument") unless(defined($config));
+ return $mem_kb->getData();
+}
- # Lookup the [files] config section
- my $files_conf = $config->{files};
+=item match_app
- # Do nothing if there is no [files] config section
- return unless(defined($files_conf));
+Return a matching app entry from the virt-v2v configuration. The entry is
+returned as a hashref containing 2 entries. I<path> contains the path to the
+application itself. I<deps> contains an arrayref containing the paths of all the
+app's listed dependencies.
- # A hash, whose labels are filenames to be added to the transfer iso. We use
- # a hash here to remove duplicates.
- my %paths = ();
- foreach my $label (keys(%$files_conf)) {
- my $path = $files_conf->{$label};
+=cut
- unless(-f $path && -r $path) {
- print STDERR user_message(__x("WARNING: unable to access {path}.",
- path => $path));
- next;
- }
+sub match_app
+{
+ my $self = shift;
- $paths{$path} = 1;
+ my ($name, $arch) = @_;
- # As transfer directory hierarchy is flat, remove all directory
- # components from paths
- my (undef, undef, $filename) = File::Spec->splitpath($path);
- $files{$label} = $filename;
- }
+ my $config = $self->{config};
- # Do nothing if there are no files defined
- return if(keys(%paths) == 0);
-
- $transferiso = File::Temp->new(UNLINK => 1, SUFFIX => '.iso');
- my $eh = Sys::VirtV2V::ExecHelper->run
- ('mkisofs', '-o', $transferiso, '-r', '-J',
- '-V', '__virt-v2v_transfer__', keys(%paths));
- if($eh->status() != 0) {
- print STDERR user_message(__x("Failed to create transfer iso. Command
".
- "output was:\n{output}",
- output => $eh->output()));
- }
+ my $desc = $self->{desc};
+ my $distro = $desc->{distro};
+ my $major = $desc->{major_version};
+ my $minor = $desc->{minor_version};
+
+ # Check we've got at least a distro from OS detection
+ die(user_message(__"Didn't detect OS distribution"))
+ unless (defined($distro));
+
+ # Create a list of xpath queries against the config which look for a
+ # matching <app> config entry in descending order of specificity
- # Populate deps from the [deps] config section
- my $deps_conf = $config->{deps};
+ my $prefix = "/virt-v2v/app[\@os='$distro' and
\@name='$name'";
- if(defined($deps_conf)) {
- # Copy the deps_conf hash into %deps
- foreach my $label (keys(%$deps_conf)) {
- $deps{$label} = $deps_conf->{$label};
+ my @queries;
+ if (defined($major)) {
+ if (defined($minor)) {
+ push(@queries, $prefix." and \@major='$major' ".
+ "and \@minor='$minor' and
\@arch='$arch']");
+ push(@queries, $prefix." and \@major='$major' ".
+ "and \@minor='$minor']");
}
+
+ push(@queries, $prefix." and \@major='$major' and
\@arch='$arch']");
+ push(@queries, $prefix." and \@major='$major']");
}
- # Populate aliases from the [aliases] config section
- my $aliases_conf = $config->{aliases};
+ push(@queries, $prefix." and \@arch='$arch']");
+ push(@queries, $prefix."]");
- if(defined($aliases_conf)) {
- # Copy the aliases_conf hash into %aliases
- foreach my $label (keys(%$aliases_conf)) {
- $aliases{$label} = $aliases_conf->{$label};
- }
+ # Use the results of the first query which returns a result
+ my $app;
+ foreach my $query (@queries) {
+ ($app) = $config->findnodes($query);
+ last if (defined($app));
}
-}
-=item get_transfer_iso
+ unless (defined($app)) {
+ my $search = "distro='$distro' name='$name'";
+ $search .= " major='$major'" if (defined($major));
+ $search .= " minor='$minor'" if (defined($minor));
+ $search .= " arch='$arch'";
-Return the path (on the host) to the transfer iso image. L</configure> must have
-been called first.
+ die(user_message(__x("No app in config matches {search}",
+ search => $search)));
+ }
-=cut
+ my %app;
+ my ($path) = $app->findnodes('path/text()');
+ die(user_message(__x("app entry in config doesn't contain a path:
{xml}",
+ xml => $app->toString()))) unless (defined($path));
+ $path = $path->getData();
-sub get_transfer_iso
-{
- return $transferiso;
+ my @deps;
+ foreach my $dep ($app->findnodes('dep/text()')) {
+ push(@deps, $dep->getData());
+ }
+
+ # Return a hash containing the application path and its dependencies
+ my %ret;
+ $ret{path} = $path;
+ $ret{deps} = \@deps;
+
+ return \%ret;
}
=back
@@ -242,21 +267,15 @@ A L<Sys::Guestfs> handle.
An OS description created by L<Sys::Guestfs::Lib>.
-=item files
-
-A hash containing 'label => filename' mappings. These mappings are consulted
-when a guest needs to install a specific application.
+=item dom
-=item deps
+A parsed XML::DOM containing the libvirt domain XML for this guest prior to any
+conversion.
-A hash containing 'label => C<space separated dependency list>'. The
-dependencies are given as labels rather than specific files. This is used to
-install dependencies when installing an application in the guest.
-
-=item aliases
+=item config
-A hack containing 'label => alias'. Aliases are given as labels rather than
-specific files. This is used to substitute packages during installation.
+A parsed XML::DOM containing the virt-v2v configuration, or undef if there is
+no config.
=back
diff --git a/lib/Sys/VirtV2V/GuestOS/RedHat.pm b/lib/Sys/VirtV2V/GuestOS/RedHat.pm
index 920eea2..d6abe9b 100644
--- a/lib/Sys/VirtV2V/GuestOS/RedHat.pm
+++ b/lib/Sys/VirtV2V/GuestOS/RedHat.pm
@@ -17,9 +17,13 @@
package Sys::VirtV2V::GuestOS::RedHat;
+our @ISA = ('Sys::VirtV2V::GuestOS');
+
use strict;
use warnings;
+use File::Spec;
+
use Sys::Guestfs::Lib qw(inspect_linux_kernel);
use Sys::VirtV2V::UserMessage qw(user_message);
@@ -65,7 +69,7 @@ sub can_handle
return ($desc->{os} eq 'linux') && ($desc->{package_format} eq
'rpm');
}
-=item Sys::VirtV2V::GuestOS::RedHat->new(g, desc, files, deps, aliases)
+=item Sys::VirtV2V::GuestOS::RedHat->new(self)
See BACKEND INTERFACE in L<Sys::VirtV2V::GuestOS> for details.
@@ -75,27 +79,9 @@ sub new
{
my $class = shift;
- my $self = {};
-
- # Guest handle
- my $g = $self->{g} = shift;
- carp("new called without guest handle") unless defined($g);
-
- # Guest description
- $self->{desc} = shift;
- carp("new called without guest description") unless
defined($self->{desc});
-
- # Guest file map
- $self->{files} = shift;
- carp("new called without files description") unless
defined($self->{files});
-
- # Guest dependency map
- $self->{deps} = shift;
- carp("new called without dependencies") unless defined($self->{deps});
-
- # Guest alias map
- $self->{aliases} = shift;
- carp("new called without aliases") unless defined($self->{aliases});
+ # Self object
+ my $self = shift;
+ carp("new called without self object") unless defined($self);
bless($self, $class);
@@ -475,32 +461,113 @@ sub add_kernel
my ($kernel_pkg, $kernel_arch) = $self->_discover_kernel();
- # Install the kernel's dependencies
- $self->_install_rpms(1, $self->_resolve_deps($kernel_pkg));
+ # If the guest is using a Xen PV kernel, choose an appropriate normal kernel
+ # replacement
+ if ($kernel_pkg eq "kernel-xen" || $kernel_pkg eq "kernel-xenU")
{
+ my $desc = $self->{desc};
+
+ # Make an informed choice about a replacement kernel for distros we know
+ # about
+
+ # RHEL 5
+ if ($desc->{distro} eq 'rhel' && $desc->{major_version} eq
'5') {
+ if ($kernel_arch eq 'i686') {
+ # XXX: This assumes that PAE will be available in the
+ # hypervisor. While this is almost certainly true, it's
+ # theoretically possible that it isn't. The information we need
+ # is available in the capabilities XML.
+ # If PAE isn't available, we should choose 'kernel'.
+ $kernel_pkg = 'kernel-PAE';
+ }
+
+ # There's only 1 kernel package on RHEL 5 x86_64
+ else {
+ $kernel_pkg = 'kernel';
+ }
+ }
+
+ # RHEL 4
+ elsif ($desc->{distro} eq 'rhel' && $desc->{major_version}
eq '4') {
+ my $ncpus = $self->get_ncpus();
+
+ if ($kernel_arch eq 'i686') {
+ # If the guest has > 10G RAM, give it a hugemem kernel
+ if ($self->get_memory_kb() > 10 * 1024 * 1024) {
+ $kernel_pkg = 'kernel-hugemem';
+ }
+
+ # SMP kernel for guests with >1 CPU
+ elsif ($ncpus > 1) {
+ $kernel_pkg = 'kernel-smp';
+ }
+
+ else {
+ $kernel_pkg = 'kernel';
+ }
+ }
+
+ else {
+ if ($ncpus > 8) {
+ $kernel_pkg = 'kernel-largesmp';
+ }
+
+ elsif ($ncpus > 1) {
+ $kernel_pkg = 'kernel-smp';
+ }
+
+ else {
+ $kernel_pkg = 'kernel';
+ }
+ }
+ }
- my $filename;
+ # RHEL 3 didn't have a xen kernel
+
+ # XXX: Could do with a history of Fedora kernels in here
+
+ # For other distros, be conservative and just return 'kernel'
+ else {
+ $kernel_pkg = 'kernel';
+ }
+ }
+
+ my $app;
eval {
- # Get a matching rpm
- $filename = $self->_match_file($kernel_pkg, $kernel_arch);
+ $app = $self->match_app($kernel_pkg, $kernel_arch);
};
-
# Return undef if we didn't find a kernel
+ if ($@) {
+ print STDERR $@;
+ return undef;
+ }
+
+ my $path = $app->{path};
+
+ my @install;
+ # Install any kernel dependencies which aren't already installed
+ foreach my $dep (@{$app->{deps}}) {
+ push(@install, $dep) unless($self->_is_installed($dep));
+ }
+ $self->_install_rpms(1, @install);
+
return undef if($@);
# Inspect the rpm to work out what kernel version it contains
my $version;
my $g = $self->{g};
- foreach my $file ($g->command_lines(["rpm", "-qlp",
$filename])) {
+ foreach my $file ($g->command_lines
+ (["rpm", "-qlp", $self->_transfer_path($path)]))
+ {
if($file =~ m{^/boot/vmlinuz-(.*)$}) {
$version = $1;
last;
}
}
- die(user_message(__x("{filename} doesn't contain a valid kernel",
- filename => $filename))) if(!defined($version));
+ die(user_message(__x("{path} doesn't contain a valid kernel",
+ path => $path))) if(!defined($version));
- $self->_install_rpms(0, ($filename));
+ $self->_install_rpms(0, ($path));
# Make augeas reload so it'll find the new kernel
$g->aug_load();
@@ -508,7 +575,7 @@ sub add_kernel
return $version;
}
-# Inspect the guest description to work out what kernel should be installed.
+# Inspect the guest description to work out what kernel package is in use
# Returns ($kernel_pkg, $kernel_arch)
sub _discover_kernel
{
@@ -602,63 +669,21 @@ sub add_application
my $user_arch = $self->{desc}->{arch};
- # Get the rpm for this label
- my $rpm = $self->_match_file($label, $user_arch);
+ my $app = $self->match_app($label, $user_arch);
# Nothing to do if it's already installed
- return if(_is_installed($rpm));
+ return if($self->_is_installed($app->{path}));
- my @install = ($rpm);
+ my @install = ($app->{path});
- # Add the dependencies to the install set
- push(@install, $self->_resolve_deps($label));
+ # Add any dependencies which aren't already installed to the install set
+ foreach my $dep (@{$app->{deps}}) {
+ push(@install, $dep) unless ($self->_is_installed($dep));
+ }
$self->_install_rpms(1, @install);
}
-# Return a list of dependencies which must be installed before $label can be
-# installed. The list contains paths of rpm files. It does not contain the rpm
-# for $label itself. This is so _resolve_deps can be used to install kernel
-# dependencies with -U before the kernel itself is installed with -i.
-sub _resolve_deps
-{
- my $self = shift;
-
- my ($label, @path) = @_;
-
- my $user_arch = $self->{desc}->{arch};
-
- # Check for an alias for $label
- $label = $self->_resolve_alias($label, $user_arch);
-
- # Check that the dependency path doesn't include the given label. If it
- # does, that's a dependency loop.
- if(grep(/\Q$label\E/, @path) > 0) {
- die(user_message(__x("Found dependency loop installing {label}:
{path}",
- label => $label, path => join(' ', @path))));
- }
- push(@path, $label);
-
- my $g = $self->{g};
-
- my @depfiles = ();
-
- # Find dependencies for $label
- foreach my $dep ($self->_match_deps($label, $user_arch)) {
- my $rpm = $self->_match_file($dep, $user_arch);
-
- # Don't add the dependency if it's already installed
- next if($self->_is_installed($rpm));
-
- # Add the dependency
- push(@depfiles, $rpm);
-
- # Recursively add dependencies
- push(@depfiles, $self->_resolve_deps($dep, @path));
- }
-
- return @depfiles;
-}
# Return 1 if the requested rpm, or a newer version, is installed
# Return 0 otherwise
@@ -669,6 +694,8 @@ sub _is_installed
my $g = $self->{g};
+ $rpm = $self->_transfer_path($rpm);
+
# Get NEVRA for the rpm to be installed
my $nevra = $g->command(['rpm', '-qp', '--qf',
'%{NAME} %{EPOCH} %{VERSION} %{RELEASE} %{ARCH}',
@@ -828,94 +855,6 @@ sub get_application_owner
die($@) if($@);
}
-# Lookup a guest specific match for the given label
-sub _match
-{
- my $self = shift;
- my ($object, $label, $arch, $hash) = @_;
-
- my $desc = $self->{desc};
- my $distro = $desc->{distro};
- my $major = $desc->{major_version};
- my $minor = $desc->{minor_version};
-
- if(values(%$hash) > 0) {
- # Search for a matching entry in the file map, in descending order of
- # specificity
- for my $name ("$distro.$major.$minor.$arch.$label",
- "$distro.$major.$minor.$label",
- "$distro.$major.$arch.$label",
- "$distro.$major.$label",
- "$distro.$arch.$label",
- "$distro.$label") {
- return $name if(defined($hash->{$name}));
- }
- }
-
- die(user_message(__x("No {object} given matching {label}",
- object => $object,
- label => "$distro.$major.$minor.$arch.$label")));
-}
-
-# Return the path to an rpm for <label>.<arch>
-# Dies if no match is found
-sub _match_file
-{
- my $self = shift;
- my ($label, $arch) = @_;
-
- # Check for an alias for $label
- $label = $self->_resolve_alias($label, $arch);
-
- my $files = $self->{files};
-
- my $name = $self->_match(__"file", $label, $arch, $files);
-
- # Ensure that whatever file is returned is accessible
- $self->_ensure_transfer_mounted();
-
- return $self->{transfer_mount}.'/'.$files->{$name};
-}
-
-# Look for an alias for this label
-sub _resolve_alias
-{
- my $self = shift;
- my ($label, $arch) = @_;
-
- my $aliases = $self->{aliases};
-
- my $alias;
- eval {
- $alias = $self->_match(__"alias", $label, $arch, $aliases);
- };
-
- return $aliases->{$alias} if(defined($alias));
- return $label;
-}
-
-# Return a list of labels listed as dependencies of the given label.
-# Returns an empty list if no dependencies were specified.
-sub _match_deps
-{
- my $self = shift;
- my ($label, $arch) = @_;
-
- my $deps = $self->{deps};
-
- my $name;
- eval {
- $name = $self->_match(__"dependencies", $label, $arch, $deps);
- };
-
- # Return an empty list if there were no dependencies defined
- if($@) {
- return ();
- } else {
- return split(/\s+/, $deps->{$name});
- }
-}
-
# Install a set of rpms
sub _install_rpms
{
@@ -926,6 +865,9 @@ sub _install_rpms
# Nothing to do if we got an empty set
return if(scalar(@rpms) == 0);
+ # All paths are relative to the transfer mount. Need to make them absolute.
+ @rpms = map { $_ = $self->_transfer_path($_) } @rpms;
+
my $g = $self->{g};
eval {
$g->command(['rpm', $upgrade == 1 ? '-U' : '-i',
@rpms]);
@@ -935,6 +877,18 @@ sub _install_rpms
die($@) if($@);
}
+# Get full, local path of a file on the transfer mount
+sub _transfer_path
+{
+ my $self = shift;
+
+ my ($path) = @_;
+
+ $self->_ensure_transfer_mounted();
+
+ return File::Spec->catfile($self->{transfer_mount}, $path);
+}
+
# Ensure that the transfer device is mounted. If not, mount it.
sub _ensure_transfer_mounted
{
diff --git a/v2v/virt-v2v.pl b/v2v/virt-v2v.pl
index cf78523..a0559e9 100755
--- a/v2v/virt-v2v.pl
+++ b/v2v/virt-v2v.pl
@@ -22,7 +22,9 @@ use strict;
use Pod::Usage;
use Getopt::Long;
#use Data::Dumper;
-use Config::Tiny;
+use File::Spec;
+use File::stat;
+
use Locale::TextDomain 'virt-v2v';
use Sys::Guestfs;
@@ -31,10 +33,11 @@ use Sys::Guestfs::Lib qw(open_guest get_partitions
inspect_all_partitions
inspect_in_detail);
use Sys::VirtV2V;
-use Sys::VirtV2V::GuestOS;
use Sys::VirtV2V::Converter;
use Sys::VirtV2V::Connection::LibVirt;
use Sys::VirtV2V::Connection::LibVirtXML;
+use Sys::VirtV2V::ExecHelper;
+use Sys::VirtV2V::GuestOS;
use Sys::VirtV2V::UserMessage qw(user_message);
=encoding utf8
@@ -296,10 +299,6 @@ if ($@) {
exit(1);
}
-# Configure GuestOS ([files] and [deps] sections)
-# Need to fix GuestOS's usage of config for installing applications
-Sys::VirtV2V::GuestOS->configure({});
-
###############################################################################
## Start of processing
@@ -311,6 +310,9 @@ exit(1) unless(defined($dom));
# Get a list of the guest's transfered storage devices
my @storage = $conn->get_local_storage();
+# Create the transfer iso if required
+my $transferiso = get_transfer_iso($config, $config_file);
+
# Open a libguestfs handle on the guest's storage devices
my $g = get_guestfs_handle(\@storage, $transferiso);
@@ -321,7 +323,7 @@ $SIG{'QUIT'} = \&close_guest_handle;
my $os = inspect_guest($g);
# Instantiate a GuestOS instance to manipulate the guest
-my $guestos = Sys::VirtV2V::GuestOS->instantiate($g, $os);
+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);
@@ -346,9 +348,85 @@ sub close_guest_handle
}
}
+sub get_transfer_iso
+{
+ my ($config, $config_file) = @_;
+
+ # Nothing to do if there's no config
+ return undef unless (defined($config));
+
+ # path-root doesn't have to be defined
+ my ($root) = $config->findnodes('/virt-v2v/path-root/text()');
+ $root = $root->getData() if (defined($root));
+
+ # Construct a list of path arguments to mkisofs from paths referenced in the
+ # config file
+ # We actually use a hash here to avoid duplicates
+ my %path_args;
+ foreach my $path ($config->findnodes('/virt-v2v/app/path/text() | '.
+ '/virt-v2v/app/dep/text()')) {
+ $path = $path->getData();
+
+ # Get the absolute path if iso-root was defined
+ my $abs;
+ if (defined($root)) {
+ $abs = File::Spec->catfile($root, $path);
+ } else {
+ $abs = $path;
+ }
+
+ # Check the referenced path is accessible
+ die(user_message(__x("Unable to access {path} referenced in ".
+ "the config file",
+ path => $path))) unless (-r $abs);
+
+ $path_args{"$path=$abs"} = 1;
+ }
+
+ # Nothing further to do if there are no paths
+ return if (keys(%path_args) == 0);
+
+ # Get the path of the transfer iso
+ my ($iso_path) = $config->findnodes('/virt-v2v/iso-path/text()');
+
+ # We need this
+ die(user_message(__"<iso-path> must be specified in the configuration
".
+ "file")) unless (defined($iso_path));
+ $iso_path = $iso_path->getData();
+
+ # Check that the transfer iso exists, and is newer than the config file
+ if (-e $iso_path) {
+ my $iso_st = stat($iso_path)
+ or die(user_message(__x("Unable to stat iso file {path}: {error}",
+ path => $iso_path, error => $!)));
+
+ my $config_st = stat($config_file)
+ or die(user_message(__x("Unable to stat config file {path}: ".
+ "{error}",
+ path => $config_file, error => $!)));
+
+ # Don't need to re-create if the iso file is newer than the config file
+ return $iso_path if ($iso_st->mtime > $config_st->mtime);
+ }
+
+ # Re-create the transfer iso
+ my $eh = Sys::VirtV2V::ExecHelper->run
+ ('mkisofs', '-o', $iso_path,
+ '-r', '-J',
+ '-V', '__virt-v2v_transfer__',
+ '-graft-points', keys(%path_args));
+ die(user_message(__x("Failed to create transfer iso. ".
+ "Command output was:\n{output}",
+ output => $eh->output()))) unless ($eh->status() ==
0);
+
+ return $iso_path;
+}
+
sub get_guestfs_handle
{
- my $g = open_guest(\@_, rw => 1);
+ my ($storage, $transferiso) = @_;
+
+ my $g = open_guest($storage, rw => 1);
# Add the transfer iso if there is one
$g->add_drive($transferiso) if(defined($transferiso));
--
1.6.6