On Friday, October 11, 2013 04:57:32 PM Mike Latimer wrote:
I think I've addressed all the concerns you raised in the
following patch.
Can you take a look and let me know if I've created any new ones? ;)
Other than the concern about being a little too obsessed about the 79
character line length. ;) This version of the patch has all the unecessary
cleanup removed, and only the necessary cleanup left. Should be easier to deal
with.
-Mike
---
.../VirtConvert/Converter/{RedHat.pm => Linux.pm} | 679
+++++++++++++++++----
1 file changed, 567 insertions(+), 112 deletions(-)
rename lib/Sys/VirtConvert/Converter/{RedHat.pm => Linux.pm} (77%)
diff --git a/lib/Sys/VirtConvert/Converter/RedHat.pm
b/lib/Sys/VirtConvert/Converter/Linux.pm
similarity index 77%
rename from lib/Sys/VirtConvert/Converter/RedHat.pm
rename to lib/Sys/VirtConvert/Converter/Linux.pm
index 612ab2e..808d90f 100644
--- a/lib/Sys/VirtConvert/Converter/RedHat.pm
+++ b/lib/Sys/VirtConvert/Converter/Linux.pm
@@ -1,5 +1,6 @@
-# Sys::VirtConvert::Converter::RedHat
+# Sys::VirtConvert::Converter::Linux
# Copyright (C) 2009-2012 Red Hat Inc.
+# Copyright (C) 2013 SUSE Inc.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -19,9 +20,9 @@ use strict;
use warnings;
-# Functions supported by grubby, and therefore common between gruby legacy
and
-# grub2
-package Sys::VirtConvert::Converter::RedHat::Grub;
+# Functions supported by grubby or perl-Bootloader, and therefore common
+# between grub legacy and grub2
+package Sys::VirtConvert::Converter::Linux::Grub;
use Sys::VirtConvert::Util;
use Locale::TextDomain 'virt-v2v';
@@ -30,16 +31,85 @@ sub get_initrd
{
my $self = shift;
my ($path) = @_;
+ my $initrd;
my $g = $self->{g};
- foreach my $line ($g->command_lines(['grubby', '--info', $path]))
{
- return $1 if $line =~ /^initrd=(\S+)/;
+ if ($g->exists('/sbin/grubby')) {
+ foreach my $line ($g->command_lines(['grubby', '--info',
$path])) {
+ return $1 if $line =~ /^initrd=(\S+)/;
+ }
+ } else {
+ # If grubby did not work, try perl-Bootloader (for SUSE environments)
+ $initrd = eval { $g->command(['/usr/bin/perl',
+ '-MBootloader::Tools',
+ '-e', 'InitLibrary(); '.
+ 'my @sections = '.
+ 'GetSectionList(type=>image, image=>"'.$path.'");
'.
+ 'my $section = GetSection(@sections); '.
+ 'my $initrd = $section->{initrd}; '.
+ 'print $initrd;']) };
+
+ if (defined($initrd)) {
+ # If the initrd starts with (hdX,X), remove it.
+ $initrd =~ s/^\(hd.*\)//;
+ return $initrd if ($initrd =~ /^\//);
+ }
}
+ # If all else fails, use heuristics if the file exists
+ ($initrd = $path) =~ s/vmlinuz/initrd/;
+ return $initrd if ($g->exists($initrd));
+
v2vdie __x('Didn\'t find initrd for kernel {path}', path => $path);
}
+sub get_default_image
+{
+ my $self = shift;
+ my $default;
+
+ my $g = $self->{g};
+
+ if ($g->exists('/sbin/grubby')) {
+ $default = $g->command(['grubby', '--default-kernel']);
+ } else {
+ $default = eval { $g->command(['/usr/bin/perl',
+ '-MBootloader::Tools',
+ '-e', 'InitLibrary(); '.
+ 'my $default=Bootloader::Tools::GetDefaultSection(); '.
+ 'print $default->{image};']) };
+ # If the image starts with (hdX,X), remove it.
+ $default =~ s/^\(hd.*\)//;
+ }
+
+ chomp($default);
+ return $default;
+}
+
+sub set_default_image
+{
+ my $self = shift;
+ my ($path) = @_;
+
+ my $g = $self->{g};
+
+ if ($g->exists('/sbin/grubby')) {
+ $g->command(['grubby', '--set-default', $path]);
+ } else {
+ # Using the image path to set a default image is not always reliable.
+ # To be safe, get the image name, then set that as the default image.
+ eval { $g->command(['/usr/bin/perl',
+ '-MBootloader::Tools',
+ '-e', 'InitLibrary(); '.
+ 'my @sections = '.
+ 'GetSectionList(type=>image, image=>"'.$path.'");
'.
+ 'my $section = GetSection(@sections); '.
+ 'my $newdefault = $section->{name}; '.
+ 'SetGlobals(default, "$newdefault");']) };
+ }
+}
+
sub check_efi
{
my $self = shift;
@@ -61,15 +131,15 @@ sub check_efi
# Methods for inspecting and manipulating grub legacy
-package Sys::VirtConvert::Converter::RedHat::GrubLegacy;
+package Sys::VirtConvert::Converter::Linux::GrubLegacy;
-use Sys::VirtConvert::Util;
+use Sys::VirtConvert::Util qw(:DEFAULT augeas_error);
use File::Basename;
use Locale::TextDomain 'virt-v2v';
-@Sys::VirtConvert::Converter::RedHat::GrubLegacy::ISA =
- qw(Sys::VirtConvert::Converter::RedHat::Grub);
+@Sys::VirtConvert::Converter::Linux::GrubLegacy::ISA =
+ qw(Sys::VirtConvert::Converter::Linux::Grub);
sub new
{
@@ -236,7 +306,7 @@ sub update_console
sub check
{
my $self = shift;
- my ($path) = @_;
+ my ($path, $root) = @_;
my $g = $self->{g};
my $grub_conf = $self->{grub_conf};
@@ -251,15 +321,17 @@ sub check
return if scalar(@entries) > 0;
my $kernel =
- Sys::VirtConvert::Converter::RedHat::_inspect_linux_kernel($g,
$path);
+ Sys::VirtConvert::Converter::Linux::_inspect_linux_kernel($g, $path);
my $version = $kernel->{version};
my $grub_initrd = dirname($path)."/initrd-$version";
- # No point in dying if /etc/redhat-release can't be read
- my ($title) = eval { $g->read_lines('/etc/redhat-release') };
+ # No point in dying if /etc/(distro)-release can't be read
+ my ($title) = eval { $g->inspect_get_product_name($root) };
$title ||= 'Linux';
- # This is how new-kernel-pkg does it
+ # Remove codename or architecture
+ $title =~ s/ \(.*\)//;
+ # Remove release string and add version (like new-kernel-pkg)
$title =~ s/ release.*//;
$title .= " ($version)";
@@ -365,13 +437,13 @@ sub convert_efi
# attempt to use grub2's configuration because it's utterly insane. Instead,
# we reverse engineer the way the config is automatically generated and use
# that instead.
-package Sys::VirtConvert::Converter::RedHat::Grub2;
+package Sys::VirtConvert::Converter::Linux::Grub2;
use Sys::VirtConvert::Util qw(:DEFAULT augeas_error);
use Locale::TextDomain 'virt-v2v';
-@Sys::VirtConvert::Converter::RedHat::Grub2::ISA =
- qw(Sys::VirtConvert::Converter::RedHat::Grub);
+@Sys::VirtConvert::Converter::Linux::Grub2::ISA =
+ qw(Sys::VirtConvert::Converter::Linux::Grub);
sub new
{
@@ -407,8 +479,7 @@ sub list_kernels
my @kernels;
# Start by adding the default kernel
- my $default = $g->command(['grubby', '--default-kernel']);
- chomp($default);
+ my $default = $self->get_default_image();
push(@kernels, $default) if length($default) > 0;
# This is how the grub2 config generator enumerates kernels
@@ -430,8 +501,15 @@ sub update_console
my $g = $self->{g};
+ my $grub_cmdline;
+ if ($g->exists('/etc/sysconfig/grub')) {
+ $grub_cmdline = '/files/etc/sysconfig/grub/GRUB_CMDLINE_LINUX';
+ } else {
+ $grub_cmdline = '/files/etc/default/grub/GRUB_CMDLINE_LINUX_DEFAULT';
+ }
+
my $cmdline =
- eval { $g->aug_get('/files/etc/sysconfig/grub/GRUB_CMDLINE_LINUX') };
+ eval { $g->aug_get($grub_cmdline) };
if (defined($cmdline) && $cmdline =~ /\bconsole=(?:x|h)vc0\b/) {
if ($remove) {
@@ -441,7 +519,7 @@ sub update_console
}
eval {
- $g->aug_set('/files/etc/sysconfig/grub/GRUB_CMDLINE_LINUX',
$cmdline);
+ $g->aug_set($grub_cmdline, $cmdline);
$g->aug_save();
};
augeas_error($g, $@) if ($@);
@@ -463,11 +541,14 @@ sub write
my $g = $self->{g};
- my $default = $g->command(['grubby', '--default-kernel']);
- chomp($default);
+ my $default = $self->get_default_image();
if ($default ne $path) {
- $g->command(['grubby', '--set-default', $path]);
+ eval { $self->set_default_image($path) };
+ if ($@) {
+ logmsg WARN, __x('Unable to set default kernel to {path}',
+ path => $path);
+ }
}
}
@@ -486,7 +567,7 @@ sub convert_efi
# EFI systems boot using grub2-efi, and probably don't have the base grub2
# package installed.
- Sys::VirtConvert::Convert::RedHat::_install_any
+ Sys::VirtConvert::Convert::Linux::_install_any
(undef, ['grub2'], undef, $g, $self->{root}, $self->{config},
$self)
or v2vdie __x('Failed to install non-EFI grub2');
@@ -509,7 +590,7 @@ sub convert_efi
}
-package Sys::VirtConvert::Converter::RedHat;
+package Sys::VirtConvert::Converter::Linux;
use Sys::VirtConvert::Util qw(:DEFAULT augeas_error scsi_first_cmp);
use Locale::TextDomain 'virt-v2v';
@@ -518,7 +599,7 @@ use Locale::TextDomain 'virt-v2v';
=head1 NAME
-Sys::VirtConvert::Converter::RedHat - Convert a Red Hat based guest to run on
KVM
+Sys::VirtConvert::Converter::Linux - Convert a Linux based guest to run on
KVM
=head1 SYNOPSIS
@@ -528,7 +609,7 @@ Sys::VirtConvert::Converter::RedHat - Convert a Red Hat
based guest to run on KV
=head1 DESCRIPTION
-Sys::VirtConvert::Converter::RedHat converts a Red Hat based guest to use
KVM.
+Sys::VirtConvert::Converter::Linux converts a Linux based guest to use KVM.
=head1 METHODS
@@ -544,9 +625,17 @@ sub _is_rhel_family
($g->inspect_get_distro($root) =~ /^(rhel|centos|scientificlinux|
redhat-based)$/);
}
-=item Sys::VirtConvert::Converter::RedHat->can_handle(g, root)
+sub _is_suse_family
+{
+ my ($g, $root) = @_;
+
+ return ($g->inspect_get_type($root) eq 'linux') &&
+ ($g->inspect_get_distro($root) =~ /^(sles|suse-based|opensuse)$/);
+}
-Return 1 if Sys::VirtConvert::Converter::RedHat can convert the given guest
+=item Sys::VirtConvert::Converter::Linux->can_handle(g, root)
+
+Return 1 if Sys::VirtConvert::Converter::Linux can convert the given guest
=cut
@@ -556,13 +645,16 @@ sub can_handle
my ($g, $root) = @_;
- return ($g->inspect_get_type($root) eq 'linux' &&
- (_is_rhel_family($g, $root) || $g->inspect_get_distro($root) eq
'fedora'));
+ if ($g->inspect_get_type($root) eq 'linux') {
+ return (_is_rhel_family($g, $root) ||
+ ($g->inspect_get_distro($root) eq 'fedora') ||
+ _is_suse_family($g, $root));
+ }
}
-=item Sys::VirtConvert::Converter::RedHat->convert(g, root, config, meta,
options)
+=item Sys::VirtConvert::Converter::Linux->convert(g, root, config, meta,
options)
-Convert a Red Hat based guest. Assume that can_handle has previously returned
1.
+Convert a Linux based guest. Assume that can_handle has previously returned
1.
=over
@@ -601,8 +693,10 @@ sub convert
_init_augeas($g);
my $grub;
- $grub = eval { Sys::VirtConvert::Converter::RedHat::Grub2->new($g, $root,
$config) };
- $grub = eval { Sys::VirtConvert::Converter::RedHat::GrubLegacy->new($g,
$root) }
+ $grub = eval
+ { Sys::VirtConvert::Converter::Linux::Grub2->new($g, $root, $config) };
+ $grub = eval
+ { Sys::VirtConvert::Converter::Linux::GrubLegacy->new($g, $root) }
unless defined($grub);
v2vdie __('No grub configuration found') unless defined($grub);
@@ -625,8 +719,9 @@ sub convert
my $remove_serial_console = exists($options->{NO_SERIAL_CONSOLE});
_configure_console($g, $grub, $remove_serial_console);
- _configure_display_driver($g, $root, $config, $meta, $grub);
- _remap_block_devices($meta, $virtio, $g, $root);
+ my $driver = _get_display_driver($g, $root);
+ _configure_display_driver($g, $root, $config, $meta, $grub, $driver);
+ _remap_block_devices($meta, $virtio, $g, $root, $grub);
_configure_kernel_modules($g, $virtio);
_configure_boot($kernel, $virtio, $g, $root, $grub);
@@ -842,7 +937,7 @@ sub _configure_console
sub _configure_display_driver
{
- my ($g, $root, $config, $meta, $grub) = @_;
+ my ($g, $root, $config, $meta, $grub, $driver) = @_;
# Update the display driver if it exists
my $updated = 0;
@@ -866,7 +961,7 @@ sub _configure_display_driver
}
foreach my $path
($g->aug_match('/files'.$xorg.'/Device/Driver')) {
- $g->aug_set($path, 'qxl');
+ $g->aug_set($path, $driver);
$updated = 1;
}
@@ -885,13 +980,14 @@ sub _configure_display_driver
augeas_error($g, $@) if ($@);
# If we updated the X driver, check if X itself is actually installed. If
it
- # is, ensure the qxl driver is installed.
+ # is, ensure the specified driver is installed.
if ($updated &&
($g->exists('/usr/bin/X') || $g->exists('/usr/bin/X11/X'))
&&
- !_install_capability('qxl', $g, $root, $config, $meta, $grub))
+ !_install_capability($driver, $g, $root, $config, $meta, $grub))
{
- logmsg WARN, __('Display driver was updated to qxl, but unable to '.
- 'install qxl driver. X may not function correctly');
+ logmsg WARN, __x('Display driver was updated to {driver}, but unable
'.
+ 'to install {driver} driver. X may not function '.
+ 'correctly', driver => $driver);
}
}
@@ -925,20 +1021,45 @@ sub _inspect_linux_kernel
# If this is a packaged kernel, try to work out the name of the package
# which installed it. This lets us know what to install to replace it
with,
# e.g. kernel, kernel-smp, kernel-hugemem, kernel-PAE
- my $package = eval { $g->command(['rpm', '-qf', '--qf',
- '%{NAME}', $path]) };
- $kernel{package} = $package if defined($package);;
+ #
+ # Due to the inclusion of a build number in SUSE packages, the version
+ # found through file and the kernel filename does not always match the
+ # version required for installation later. Get the full version-release
+ # here and track it through $kernel{fullversion}.
+ my $package;
+ my $flavor;
+ my $rpminfo = eval { $g->command(['rpm', '-qf', '--qf',
+ '%{NAME} %{VERSION}-%{RELEASE}', $path])
};
+ if (defined($rpminfo)) {
+ $rpminfo =~ /(\S+)\s(\S+)/;
+ $package = $1;
+ my $fullversion = $2;
+
+ # Some SUSE kernels are from a -base package, but it's more correct
to
+ # use the non -base package name.
+ $package =~ s/-base$//;
+ $kernel{package} = $package;
+
+ # fullversion must include the flavor (xen, smp, default, etc.) of the
+ # kernel as well (if one exists)
+ ($flavor = $package) =~ s/^kernel//;
+ $fullversion = $fullversion.$flavor if defined($flavor);
+ $kernel{fullversion} = $fullversion;
+ }
# Try to get the kernel version by running file against it
my $version;
my $filedesc = $g->file($path);
- if($filedesc =~ /^$path: Linux kernel .*\bversion\s+(\S+)\b/) {
+ if($filedesc =~ /Linux.* [kK]ernel.*\b[vV]ersion\s+(\S+)\b/) {
$version = $1;
+ # SUSE kernel version strings do not include the flavor
+ $version = $version.$flavor if defined($flavor);
+ # If $version is not correct here, default to the filename method
+ undef $version if(!$g->is_dir("/lib/modules/$version"));
}
-
# Sometimes file can't work out the kernel version, for example because
it's
# a Xen PV kernel. In this case try to guess the version from the filename
- else {
+ if (!defined($version)) {
if($path =~ m{/boot/vmlinuz-(.*)}) {
$version = $1;
@@ -988,6 +1109,7 @@ sub _configure_kernel
# Pick first appropriate kernel returned by list_kernels
my $boot_kernel;
+ my $backup_ver;
foreach my $path ($grub->list_kernels()) {
my $kernel = _inspect_linux_kernel($g, $path);
my $version = $kernel->{version};
@@ -998,7 +1120,16 @@ sub _configure_kernel
# If we're configuring virtio, check this kernel supports it
next if ($virtio && !_supports_virtio($version, $g));
- $boot_kernel = $version;
+
+ # SUSE kernel installations require the version string which includes
+ # the build number. Change it here, but backup the original version
as
+ # it must be restored later.
+ if (_is_suse_family($g, $root)) {
+ $boot_kernel = $kernel->{fullversion};
+ $backup_ver = $version;
+ } else {
+ $boot_kernel = $version;
+ }
last;
}
@@ -1013,7 +1144,7 @@ sub _configure_kernel
# 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") {
+ if ($kernel_pkg =~ /^kernel-xen/) {
$kernel_pkg = _get_replacement_kernel_name($g, $root,
$kernel_arch, $meta);
@@ -1055,7 +1186,7 @@ sub _configure_kernel
unless defined($boot_kernel);
} else {
v2vdie __x('Failed to find a {name} package to install',
- name => "kernel_pkg.$kernel_arch");
+ name => "$kernel_pkg.$kernel_arch");
}
}
}
@@ -1084,6 +1215,9 @@ sub _configure_kernel
augeas_error($g, $@) if ($@);
}
+ # If the kernel version was backed up previously (SUSE environments),
+ # restore the original value before returning it.
+ $boot_kernel = $backup_ver if defined($backup_ver);
return $boot_kernel;
}
@@ -1121,8 +1255,8 @@ sub _get_os_arch
# Default to x86_64 if we still didn't find an architecture
return 'x86_64' unless defined($arch);
- # We want an i686 guest for i[345]86
- return 'i686' if($arch =~ /^i[345]86$/);
+ # Change i386 to i[56]86
+ $arch = _set_32bit_arch($g, $root, $arch);
return $arch;
}
@@ -1168,7 +1302,7 @@ sub _unconfigure_hv
my @apps = $g->inspect_list_applications($root);
- _unconfigure_xen($g, \@apps);
+ _unconfigure_xen($g, $root, \@apps);
_unconfigure_vbox($g, \@apps);
_unconfigure_vmware($g, \@apps);
_unconfigure_citrix($g, \@apps);
@@ -1177,7 +1311,7 @@ sub _unconfigure_hv
# Unconfigure Xen specific guest modifications
sub _unconfigure_xen
{
- my ($g, $apps) = @_;
+ my ($g, $root, $apps) = @_;
# Look for kmod-xenpv-*, which can be found on RHEL 3 machines
my @remove;
@@ -1230,6 +1364,27 @@ sub _unconfigure_xen
$g->write_file('/etc/rc.local', join("\n",
@rc_local)."\n",
$size);
}
}
+
+ if (_is_suse_family($g, $root)) {
+ # Remove xen modules from INITRD_MODULES and DOMU_INITRD_MODULES
+ my $sysconfig = '/etc/sysconfig/kernel';
+ my @variables = qw(INITRD_MODULES DOMU_INITRD_MODULES);
+ my @xen_modules = qw(xennet xen-vnif xenblk xen-vbd);
+ my $modified;
+
+ foreach my $var (@variables) {
+ foreach my $xen_mod (@xen_modules) {
+ foreach my $entry
+ ($g->aug_match("/files$sysconfig/$var/'.
+ 'value[. = '$xen_mod']"))
+ {
+ $g->aug_rm($entry);
+ $modified = 1;
+ }
+ }
+ }
+ $g->aug_save if (defined($modified));
+ }
}
# Unconfigure VirtualBox specific guest modifications
@@ -1506,13 +1661,13 @@ sub _install_capability
# 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")
+ if ($kernel_pkg =~ /^kernel-xen/)
{
$kernel_pkg =
_get_replacement_kernel_name($g, $root, $kernel_arch,
$meta);
- # Check if we've got already got an appropriate kernel
+ # Check if we've already got an appropriate kernel
my ($inst) =
_get_installed("$kernel_pkg.$kernel_arch", $g);
@@ -1523,7 +1678,7 @@ sub _install_capability
{
# filter out xen/xenU from release field
if (defined($kernel_release) &&
- $kernel_release =~ /^(\S+?)(xen)?(U)?$/)
+ $kernel_release =~ /^(\S+?)(-xen)?(U)?$/)
{
$kernel_release = $1;
}
@@ -1631,14 +1786,22 @@ sub _install_any
# If we're installing a kernel, check which kernels are there first
my @k_before = $g->glob_expand('/boot/vmlinuz-*') if defined($kernel);
+ # Workaround for SUSE bnc#836521
+ my $pbl_fix = _modify_perlBootloader($g) if (defined($kernel) &&
+ (_is_suse_family($g, $root)));
+
my $success = 0;
_net_run($g, sub {
eval {
# Try to fetch these dependencies using the guest's native update
# tool
- $success = _install_up2date($kernel, $install, $upgrade, $g);
- $success = _install_yum($kernel, $install, $upgrade, $g)
- unless ($success);
+ if (_is_suse_family($g, $root)) {
+ $success = _install_zypper($kernel, $install, $upgrade, $g);
+ } else {
+ $success = _install_up2date($kernel, $install, $upgrade, $g);
+ $success = _install_yum($kernel, $install, $upgrade, $g)
+ unless ($success);
+ }
# Fall back to local config if the above didn't work
$success = _install_config($kernel, $install, $upgrade,
@@ -1648,6 +1811,9 @@ sub _install_any
warn($@) if $@;
});
+ # Undo the previous workaround for SUSE bnc#836521
+ _restore_perlBootloader($g) if ($pbl_fix == 1);
+
# Make augeas reload to pick up any altered configuration
eval { $g->aug_load() };
augeas_error($g, $@) if ($@);
@@ -1657,7 +1823,7 @@ sub _install_any
if (defined($kernel)) {
foreach my $k ($g->glob_expand('/boot/vmlinuz-*')) {
if (!grep(/^$k$/, @k_before)) {
- $grub->check($k);
+ $grub->check($k, $root);
last;
}
}
@@ -1780,6 +1946,90 @@ sub _install_yum
return $success;
}
+sub _install_zypper
+{
+ my ($kernel, $install, $update, $g) = @_;
+
+ # Check this system has zypper
+ return 0 unless ($g->exists('/usr/bin/zypper'));
+
+ # Install or update the kernel?
+ # If it isn't installed (because we're replacing a PV kernel), we need to
+ # install
+ # If we're installing a specific version, we need to install
+ # If the kernel package we're installing is already installed and we're
+ # just upgrading to the latest version, we need to update
+ if (defined($kernel)) {
+ my @installed = _get_installed($kernel->[0], $g);
+
+ # Don't modify the contents of $install and $update in case we fall
+ # through and they're reused in another function
+ if (@installed == 0 || defined($kernel->[2])) {
+ my @tmp = defined($install) ? @$install : ();
+ push(@tmp, $kernel);
+ $install = \@tmp;
+ } else {
+ my @tmp = defined($update) ? @$update : ();
+ push(@tmp, $kernel);
+ $update = \@tmp;
+ }
+ }
+
+ my $success = 1;
+ # Error when installing: "No provider of 'pkg' found."
+ # (Not an) Error when updating: "Package 'pkg' is not available in your
+ # repositories. Cannot reinstall, upgrade, or downgrade."
+ ZYPPER: foreach my $task (
+ [ "install", $install, qr/(^No package|already installed)/ ],
+ [ "update", $update, qr/(^No Packages|not available)/ ]
+ ) {
+ my ($action, $list, $failure) = @$task;
+
+ # Build a list of packages to install
+ my @pkgs;
+ foreach my $entry (@$list) {
+ next unless (defined($entry));
+
+ # zypper doesn't need arch or epoch
+ my ($name, undef, undef, $version, $release) = @$entry;
+
+ # Construct n-v-r
+ my $pkg = $name;
+ $pkg .= "-$version" if (defined($version));
+ $pkg .= "-$release" if (defined($release));
+
+
+ push(@pkgs, "$pkg");
+ }
+
+ if (@pkgs) {
+ my @output =
+ eval { $g->command(['/usr/bin/zypper', '-n', $action,
+ @pkgs]) };
+ if ($@) {
+ # Ignore 'No provider' errors as an install from the virt-v2v
+ # repo will be attempted next.
+ if ($@ !~ /No provider/) {
+ logmsg WARN, __x('Failed to install packages. '.
+ 'Error was: {error}', error => $@);
+ }
+ $success = 0;
+ last ZYPPER;
+ }
+ foreach my $line (@output) {
+ # Don't report an error or results if package is already
+ # installed or not found in a repo
+ if ($line =~ /$failure/) {
+ $success = 0;
+ last ZYPPER;
+ }
+ }
+ }
+ }
+
+ return $success;
+}
+
sub _install_config
{
my ($kernel_naevr, $install, $upgrade, $g, $root, $config) = @_;
@@ -1806,6 +2056,7 @@ sub _install_config
}
}
+
my @user_paths = _get_deppaths($g, $root, $config,
\@missing, $g->inspect_get_arch($root),
@$user);
@@ -1814,11 +2065,33 @@ sub _install_config
'files referenced in the configuration file are '.
'required, but missing: {list}',
list => join(' ', @missing)) if scalar(@missing) > 0;
- # Install any non-kernel requirements
- _install_rpms($g, $config, 1, @user_paths);
- if (defined($kernel)) {
- _install_rpms($g, $config, 0, ($kernel));
+ # If a SUSE kernel is being added, a -base kernel could have been added
to
+ # to @user_paths (as a dep app). If so, move it to a new list containing
+ # both kernel and kernel-base packages to satisfy dependencies, and
+ # 'install' instead of 'upgrade' the packages.
+ if (_is_suse_family($g, $root) && (defined($kernel))) {
+ my @kernel_paths;
+ push(@kernel_paths, $kernel);
+ if (@user_paths) {
+ for my $index (reverse 0 .. scalar(@user_paths-1)) {
+ if ($user_paths[$index] =~ /(.*\/)kernel/) {
+ push(@kernel_paths, $user_paths[$index]);
+ splice(@user_paths, $index, 1);
+ }
+ }
+ # Install any non-kernel requirements
+ _install_rpms($g, $config, 1, @user_paths);
+ }
+ # Install kernel packages
+ _install_rpms($g, $config, 0, @kernel_paths);
+ } else {
+ # Install any non-kernel requirements
+ _install_rpms($g, $config, 1, @user_paths);
+
+ if (defined($kernel)) {
+ _install_rpms($g, $config, 0, ($kernel));
+ }
}
return 1;
@@ -1963,7 +2236,12 @@ sub _discover_kernel
$kernel_pkg = $kernel->{package};
# Get the kernel package version
- $kernel_ver = $kernel->{version};
+ # SUSE requires the fullversion string
+ if (_is_suse_family($g, $root)) {
+ $kernel_ver = $kernel->{fullversion};
+ } else {
+ $kernel_ver = $kernel->{version};
+ }
last;
}
@@ -1975,9 +2253,8 @@ sub _discover_kernel
# directly detected
$kernel_arch = $g->inspect_get_arch($root) unless defined($kernel_arch);
- # We haven't supported anything other than i686 for the kernel on 32 bit
for
- # a very long time.
- $kernel_arch = 'i686' if ('i386' eq $kernel_arch);
+ # Change i386 to i[56]86
+ $kernel_arch = _set_32bit_arch($g, $root, $kernel_arch);
return ($kernel_pkg, $kernel_arch, $kernel_ver);
}
@@ -1989,57 +2266,115 @@ sub _get_replacement_kernel_name
# Make an informed choice about a replacement kernel for distros we know
# about
- # RHEL 5
- if (_is_rhel_family($g, $root) && $g->inspect_get_major_version($root) eq
'5') {
- if ($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'.
- return 'kernel-PAE';
+ # RedHat kernels
+ if (_is_rhel_family($g, $root)) {
+ # RHEL 5
+ if ($g->inspect_get_major_version($root) eq '5') {
+ if ($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'.
+ return 'kernel-PAE';
+ }
+
+ # There's only 1 kernel package on RHEL 5 x86_64
+ else {
+ return 'kernel';
+ }
}
- # There's only 1 kernel package on RHEL 5 x86_64
- else {
- return 'kernel';
+ # RHEL 4
+ elsif ($g->inspect_get_major_version($root) eq '4') {
+ if ($arch eq 'i686') {
+ # If the guest has > 10G RAM, give it a hugemem kernel
+ if ($meta->{memory} > 10 * 1024 * 1024 * 1024) {
+ return 'kernel-hugemem';
+ }
+
+ # SMP kernel for guests with >1 CPU
+ elsif ($meta->{cpus} > 1) {
+ return 'kernel-smp';
+ }
+
+ else {
+ return 'kernel';
+ }
+ }
+
+ else {
+ if ($meta->{cpus} > 8) {
+ return 'kernel-largesmp';
+ }
+
+ elsif ($meta->{cpus} > 1) {
+ return 'kernel-smp';
+ }
+ else {
+ return 'kernel';
+ }
+ }
}
+
+ # RHEL 3 didn't have a xen kernel
}
- # RHEL 4
- elsif (_is_rhel_family($g, $root) && $g->inspect_get_major_version($root)
eq '4') {
- if ($arch eq 'i686') {
- # If the guest has > 10G RAM, give it a hugemem kernel
- if ($meta->{memory} > 10 * 1024 * 1024 * 1024) {
- return 'kernel-hugemem';
- }
+ # SUSE kernels
+ elsif (_is_suse_family($g, $root)) {
+ # openSUSE should always use kernel-default
+ if ($g->inspect_get_distro($root) eq 'opensuse') {
+ return 'kernel-default';
+ }
+ # SLES 11+
+ elsif ($g->inspect_get_major_version($root) ge '11') {
+ if ($arch eq 'i586') {
+ # If the guest has > 10G RAM, give it a pae kernel
+ if ($meta->{memory} > 10 * 1024 * 1024 * 1024) {
+ return 'kernel-pae';
+ }
- # SMP kernel for guests with >1 CPU
- elsif ($meta->{cpus} > 1) {
- return 'kernel-smp';
+ else {
+ return 'kernel-default';
+ }
}
+ # There is only 1 kernel which should be used on SLES 11 x86_64
else {
- return 'kernel';
+ return 'kernel-default';
}
}
- else {
- if ($meta->{cpus} > 8) {
- return 'kernel-largesmp';
- }
+ # SLES 10
+ elsif ($g->inspect_get_major_version($root) eq '10') {
+ if ($arch eq 'i586') {
+ # If the guest has > 10G RAM, give it a bigsmp kernel
+ if ($meta->{memory} > 10 * 1024 * 1024 * 1024) {
+ return 'kernel-bigsmp';
+ }
- elsif ($meta->{cpus} > 1) {
- return 'kernel-smp';
+ # SMP kernel for guests with >1 CPU
+ elsif ($meta->{cpus} > 1) {
+ return 'kernel-smp';
+ }
+
+ else {
+ return 'kernel-default';
+ }
}
+
else {
- return 'kernel';
+ if ($meta->{cpus} > 1) {
+ return 'kernel-smp';
+ }
+
+ else {
+ return 'kernel-default';
+ }
}
}
}
- # 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'
@@ -2076,7 +2411,7 @@ sub _get_installed
or die("Unexpected return from rpm command: $installed");
my ($epoch, $version, $release) = ($1, $2, $3);
- # Ensure iepoch is always numeric
+ # Ensure epoch is always numeric
$epoch = 0 if('(none)' eq $epoch);
push(@installed, [$epoch, $version, $release]);
@@ -2203,7 +2538,7 @@ sub _rpmvercmp
sub _remap_block_devices
{
- my ($meta, $virtio, $g, $root) = @_;
+ my ($meta, $virtio, $g, $root, $grub) = @_;
my @devices = map { $_->{device} } @{$meta->{disks}};
@devices = sort { scsi_first_cmp($a, $b) } @devices;
@@ -2235,6 +2570,12 @@ sub _remap_block_devices
# Fedora has used libata since FC7, which is long out of support. We
assume
# that all Fedora distributions in use use libata.
+ # SUSE uses libata, but IDE devices can be presented as hdX in some
+ # environments (such as fully virtual machines).
+ if (_is_suse_family($g, $root)) {
+ $libata = 0;
+ }
+
if ($libata) {
# If there are any IDE devices, the guest will have named these sdX
# after any SCSI devices. i.e. If we have disks hda, hdb, sda and
sdb,
@@ -2290,13 +2631,46 @@ sub _remap_block_devices
}
eval {
- # Update bare device references in fstab and grub's device.map
- foreach my $spec ($g->aug_match('/files/etc/fstab/*/spec'),
- $g->aug_match('/files/boot/grub/device.map/*'.
- '[label() !=
"#comment"]'))
+ my @checklist;
+ my @matchlist;
+ my $grub2_remap;
+
+ # Add standard configuration files to the checklist
+ push (@checklist, '/files/etc/fstab/*/spec');
+
+ # Add grub or grub2 files to the checklist
+ if (defined($grub->{grub_conf})) {
+ push (@checklist, "/files$grub->{grub_conf}*/kernel/root");
+ push (@checklist, "/files$grub->{grub_conf}*/kernel/resume");
+ push (@checklist, '/files/boot/grub/device.map/*'.
+ '[label() != "#comment"]');
+ }
+ elsif (defined($grub->{cfg})) {
+ push (@checklist, '/files/etc/sysconfig/grub/GRUB_CMDLINE_LINUX');
+ push (@checklist, '/files/etc/default/grub/'.
+ 'GRUB_CMDLINE_LINUX_DEFAULT');
+ }
+
+ # Search through all checklist entries and add matches to a matchlist
+ foreach my $entry (@checklist) {
+ push (@matchlist, $g->aug_match($entry));
+ }
+
+ # Update device references for every entry in the matchlist
+ foreach my $spec (@matchlist)
{
my $device = $g->aug_get($spec);
+ # If this is a grub2 environment, isolate 'resume=' value
+ my $grub2_start;
+ my $grub2_end;
+ if (($spec =~ /.*GRUB_CMDLINE.*/) &&
+ ($device =~ /(.*resume=)(\S+)(\s.*)/)) {
+ $grub2_start = $1;
+ $device = $2;
+ $grub2_end = $3;
+ }
+
# Match device names and partition numbers
my $name; my $part;
foreach my $r (qr{^/dev/(cciss/c\d+d\d+)(?:p(\d+))?$},
@@ -2318,7 +2692,9 @@ sub _remap_block_devices
# about. The user will have to fix this post-conversion.
if (!exists($map{$name})) {
my $warned = 0;
- for my $file ('/etc/fstab', '/boot/grub/device.map') {
+ for my $file ('/etc/fstab', '/boot/grub/device.map',
+ '/boot/grub/menu.lst',
'/etc/sysconfig/grub',
+ '/etc/default/grub') {
if ($spec =~ m{^/files$file}) {
logmsg WARN, __x('{file} references unknown device '.
'{device}. This entry must be '.
@@ -2341,10 +2717,22 @@ sub _remap_block_devices
my $mapped = '/dev/'.$map{$name};
$mapped .= $part if defined($part);
+
+ # If this is a grub2 entry, rebuild the entire entry
+ if ($spec =~ /.*GRUB_CMDLINE.*/) {
+ $mapped = $grub2_start.$mapped.$grub2_end;
+ $grub2_remap = 1;
+ }
+
$g->aug_set($spec, $mapped);
}
$g->aug_save();
+
+ # Re-generate the grub2 config if grub2 files were changed
+ if (defined($grub2_remap)) {
+ $g->command(['grub2-mkconfig', '-o', $grub->{cfg}]);
+ }
};
augeas_error($g, $@) if ($@);
@@ -2372,6 +2760,12 @@ sub _prepare_bootable
$grub_initrd, $version]);
}
+ elsif (_is_suse_family($g, $root) &&
($g->exists('/sbin/mkinitrd'))) {
+ $g->sh('/sbin/mkinitrd -m "'.join(' ',
@modules).'" '.
+ ' -i '.$grub_initrd.' -k /boot/vmlinuz-'.$version);
+ }
+
+ # Default to original mkinitrd, if not SUSE and dracut does not exist
elsif ($g->exists('/sbin/mkinitrd')) {
# Create a new initrd which probes the required kernel modules
my @module_args = ();
@@ -2467,6 +2861,67 @@ sub _supports_virtio
return 1;
}
+sub _get_display_driver
+{
+ my ($g, $root) = @_;
+
+ if (_is_suse_family($g, $root)) {
+ return 'cirrus';
+ } else {
+ return 'qxl';
+ }
+}
+
+# RedHat and SUSE use different 32bit architectures (i686 -vs- i586)
+sub _set_32bit_arch
+{
+ my ($g, $root, $arch) = @_;
+
+ # We want an i586 or i686 guest for i[345]86
+ if ($arch =~ /^i[345]86$/) {
+ if (_is_sles_family($g, $root)) {
+ $arch = 'i586';
+ } else {
+ $arch = 'i686';
+ }
+ }
+
+ return $arch;
+}
+
+# The next two functions are a SUSE-specific temporary workaround to
+# bnc#836521. This is required to prevent root being set to (hd*) instead
+# of the correct (hd*,*). The actual fix is in a new perl-Bootloader, which
+# will likely not be on most guests.
+sub _modify_perlBootloader
+{
+ my ($g) = @_;
+ my $module = $g->sh('rpm -ql perl-Bootloader | grep GRUB.pm');
+ chomp($module);
+ my $module_bak = "$module.v2vtmp";
+
+ if ($g->grep('/dev/(?:vx', "$module")) {
+ $g->mv($module, $module_bak);
+ $g->sh("/usr/bin/sed -e's/vx/xv/' $module_bak >
$module");
+
+ return 1;
+ }
+
+ return 0;
+}
+
+sub _restore_perlBootloader
+{
+ my ($g) = @_;
+ my $module = $g->sh('rpm -ql perl-Bootloader | grep GRUB.pm');
+ chomp($module);
+ my $module_bak = "$module.v2vtmp";
+
+ if ($g->exists($module_bak)) {
+ $g->mv($module_bak, $module);
+ }
+}
+
=back
=head1 COPYRIGHT
--
1.8.1.4