mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-09-05 12:37:54 +00:00
401 lines
13 KiB
Perl
401 lines
13 KiB
Perl
#!/usr/bin/perl -w
|
|
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
|
|
# #(C)IBM Corp
|
|
package imgutils;
|
|
|
|
use strict;
|
|
use warnings "all";
|
|
|
|
use File::Basename;
|
|
use File::Find;
|
|
use File::Path;
|
|
use Cwd qw(realpath);
|
|
use xCAT::SvrUtils;
|
|
|
|
sub el_major_version {
|
|
my $version = shift;
|
|
|
|
return if !defined($version);
|
|
|
|
my ($os_family, $os_major) = xCAT::SvrUtils::parseosver($version);
|
|
return
|
|
if !defined($os_family)
|
|
|| $os_family !~ /^(?:rhels?|rhelc|rhelhpc|centos(?:-stream)?|rocky|alma(?:linux)?|ol)$/;
|
|
|
|
return $os_major if length($os_major);
|
|
return;
|
|
}
|
|
|
|
sub rpm_installroot_command {
|
|
my ( $osver, $rootimg_dir, $non_interactive, $dnf_available ) = @_;
|
|
$non_interactive ||= "";
|
|
$dnf_available = -x "/usr/bin/dnf" unless defined($dnf_available);
|
|
my $majorrel = el_major_version($osver);
|
|
my $pkgmgr = "yum";
|
|
|
|
# EL8 and newer are dnf-native. Keep yum as the fallback for legacy
|
|
# systems and minimal environments that still provide only yum.
|
|
if (defined($majorrel) && $majorrel > 7 && $dnf_available) {
|
|
$pkgmgr = "dnf";
|
|
}
|
|
|
|
my $cmd = "$pkgmgr $non_interactive -c /tmp/genimage.$$.yum.conf --installroot=$rootimg_dir/ --disablerepo=* ";
|
|
if (defined($majorrel) && $majorrel > 7) {
|
|
$cmd .= "--releasever=" . $majorrel . " ";
|
|
$cmd .= "--setopt=module_platform_id=platform:el" . $majorrel . " ";
|
|
}
|
|
|
|
return $cmd;
|
|
}
|
|
|
|
sub varsubinline{
|
|
my $line=shift;
|
|
my $refvardict=shift;
|
|
|
|
my @varsinline= $line =~ /\$\{?(\w+)\}?/g;
|
|
my @unresolvedvars;
|
|
foreach my $var(@varsinline){
|
|
if(exists $refvardict->{$var}){
|
|
$line=~ s/\$\{$var\}/$refvardict->{$var}/g;
|
|
$line=~ s/\$$var/$refvardict->{$var}/g;
|
|
}else{
|
|
push @unresolvedvars,$var;
|
|
}
|
|
}
|
|
|
|
return $line;
|
|
}
|
|
|
|
sub _profile_lookup_osbase_list {
|
|
my $osver = shift;
|
|
|
|
# OS version on s390x can contain 'sp', e.g. sles11sp1
|
|
# If OS version contains 'sp', get the index of 'sp' instead of '.'
|
|
if ($osver =~ /sles/ && $osver =~ /sp/) {
|
|
my $dotpos = rindex($osver, "sp");
|
|
return (substr($osver, 0, $dotpos));
|
|
}
|
|
|
|
return grep { $_ ne $osver } xCAT::SvrUtils::get_os_search_list($osver);
|
|
}
|
|
|
|
sub resolver_library_paths {
|
|
my $arch = shift;
|
|
my $libdir = $arch =~ /x86_64|aarch64|riscv64/ ? 'lib64' : 'lib';
|
|
|
|
return ( "$libdir/libnss_dns.so.2", "$libdir/libresolv.so.2" );
|
|
}
|
|
|
|
sub get_profile_def_filename {
|
|
my $osver = shift;
|
|
my $profile = shift;
|
|
my $arch = shift;
|
|
|
|
my $tmp_base = shift;
|
|
my $base = realpath($tmp_base); #get the full path
|
|
if (!$base) { $base = $tmp_base; }
|
|
|
|
my $ext = shift;
|
|
|
|
my @osbase = _profile_lookup_osbase_list($osver);
|
|
my $fallbackos;
|
|
if ($osver =~ /^leap15/) {
|
|
$fallbackos = "sle15";
|
|
}
|
|
if (-r "$base/$profile.$osver.$arch.$ext") {
|
|
return "$base/$profile.$osver.$arch.$ext";
|
|
}
|
|
foreach my $osbase (@osbase) {
|
|
if (-r "$base/$profile.$osbase.$arch.$ext") {
|
|
return "$base/$profile.$osbase.$arch.$ext";
|
|
}
|
|
}
|
|
if ($fallbackos && -r "$base/$profile.$fallbackos.$arch.$ext") {
|
|
return "$base/$profile.$fallbackos.$arch.$ext";
|
|
} elsif (-r "$base/$profile.$arch.$ext") {
|
|
return "$base/$profile.$arch.$ext";
|
|
} elsif (-r "$base/$profile.$osver.$ext") {
|
|
return "$base/$profile.$osver.$ext";
|
|
}
|
|
foreach my $osbase (@osbase) {
|
|
if (-r "$base/$profile.$osbase.$ext") {
|
|
return "$base/$profile.$osbase.$ext";
|
|
}
|
|
}
|
|
if ($fallbackos && -r "$base/$profile.$fallbackos.$ext") {
|
|
return "$base/$profile.$fallbackos.$ext";
|
|
} elsif (-r "$base/$profile.$ext") {
|
|
return "$base/$profile.$ext";
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
sub include_file
|
|
{
|
|
my $file = shift;
|
|
my $idir = shift;
|
|
my @text = ();
|
|
|
|
$file=varsubinline($file,\%ENV);
|
|
unless ($file =~ /^\//) {
|
|
$file = $idir . "/" . $file;
|
|
}
|
|
|
|
open(INCLUDE, $file) ||
|
|
return "#INCLUDEBAD:cannot open $file#";
|
|
|
|
while (<INCLUDE>) {
|
|
chomp($_);
|
|
s/\s+$//; #remove trailing spaces
|
|
next if /^\s*$/; #-- skip empty lines
|
|
next
|
|
if (/^\s*#/
|
|
&& !/^\s*#INCLUDE:[^#^\n]+#/
|
|
&& !/^\s*#NEW_INSTALL_LIST#/
|
|
&& !/^\s*#ENV:[^#^\n]+#/); #-- skip comments
|
|
push(@text, $_);
|
|
}
|
|
|
|
close(INCLUDE);
|
|
|
|
return join(',', @text);
|
|
}
|
|
|
|
sub get_package_names {
|
|
my $plist_file_list = shift;
|
|
my %pkgnames = ();
|
|
|
|
my @plist_file_names = split ',', $plist_file_list;
|
|
foreach my $plist_file_name (@plist_file_names) {
|
|
|
|
# this variable needs to be cleaned when loop the pkglist files
|
|
my @tmp_array = ();
|
|
|
|
if ($plist_file_name && -r $plist_file_name) {
|
|
my $pkgfile;
|
|
open($pkgfile, "<", "$plist_file_name");
|
|
while (<$pkgfile>) {
|
|
chomp;
|
|
s/\s+$//; #remove trailing white spaces
|
|
next if /^\s*$/; #-- skip empty lines
|
|
next
|
|
if (/^\s*#/
|
|
&& !/^\s*#INCLUDE:[^#^\n]+#/
|
|
&& !/^\s*#NEW_INSTALL_LIST#/
|
|
&& !/^\s*#ENV:[^#^\n]+#/); #-- skip comments
|
|
push(@tmp_array, $_);
|
|
}
|
|
close($pkgfile);
|
|
|
|
if (@tmp_array > 0) {
|
|
my $pkgtext = join(',', @tmp_array);
|
|
|
|
#handle the #INLCUDE# tag recursively
|
|
my $idir = dirname($plist_file_name);
|
|
my $doneincludes = 0;
|
|
while (not $doneincludes) {
|
|
$doneincludes = 1;
|
|
if ($pkgtext =~ /#INCLUDE:[^#^\n]+#/) {
|
|
$doneincludes = 0;
|
|
$pkgtext =~ s/#INCLUDE:([^#^\n]+)#/include_file($1,$idir)/eg;
|
|
}
|
|
}
|
|
#print "\n\npkgtext=$pkgtext\n\n";
|
|
my @tmp = split(',', $pkgtext);
|
|
my $pass = 1;
|
|
foreach (@tmp) {
|
|
my $idir;
|
|
if (/^--/) {
|
|
$idir = "POST_REMOVE"; #line starts with -- means the package should be removed after otherpkgs are installed
|
|
s/^--//;
|
|
} elsif (/^-/) {
|
|
$idir = "PRE_REMOVE"; #line starts with single - means the package should be removed before otherpkgs are installed
|
|
s/^-//;
|
|
} elsif (/^#NEW_INSTALL_LIST#/) {
|
|
$pass++;
|
|
next;
|
|
} elsif (/^#ENV:([^#^\n]+)#/) {
|
|
my $pa = $pkgnames{$pass}{ENVLIST};
|
|
my $env = $1;
|
|
if (exists($pkgnames{$pass}{ENVLIST})) {
|
|
push(@$pa, $env);
|
|
} else {
|
|
$pkgnames{$pass}{ENVLIST} = [$env];
|
|
}
|
|
next;
|
|
} elsif (/^#INCLUDEBAD:([^#^\n]+)#/) {
|
|
my $pa = $pkgnames{$pass}{INCLUDEBAD};
|
|
my $file = $1;
|
|
if (exists($pkgnames{$pass}{INCLUDEBAD})) {
|
|
push(@$pa, $file);
|
|
} else {
|
|
$pkgnames{$pass}{INCLUDEBAD} = [$file];
|
|
}
|
|
next;
|
|
} elsif (/^#/) {
|
|
|
|
# ignore all other comment lines
|
|
next;
|
|
} else {
|
|
$idir = dirname($_);
|
|
}
|
|
my $fn = basename($_);
|
|
if (exists($pkgnames{$pass}{$idir})) {
|
|
my $pa = $pkgnames{$pass}{$idir};
|
|
push(@$pa, $fn);
|
|
} else {
|
|
$pkgnames{$pass}{$idir} = [$fn];
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return %pkgnames;
|
|
}
|
|
|
|
sub default_net_drivers {
|
|
my ( $family, $arch ) = @_;
|
|
|
|
my %drivers = (
|
|
rh => {
|
|
x86 => [qw(tg3 bnx2 bnx2x e1000 e1000e igb mlx_en mlx5_core virtio_net be2net)],
|
|
x86_64 => [qw(tg3 bnx2 bnx2x e1000 e1000e igb mlx_en mlx5_core virtio_net be2net)],
|
|
aarch64 => [qw(tg3 bnx2 bnx2x e1000e igb mlx_en mlx5_core virtio_net)],
|
|
riscv64 => [qw(e1000 e1000e igb ixgbe r8169 tg3 bnx2x mlx5_core virtio_net)],
|
|
ppc64 => [qw(e1000 e1000e igb ibmveth ehea)],
|
|
s390x => [qw(qdio ccwgroup)],
|
|
},
|
|
sles => {
|
|
x86 => [qw(tg3 bnx2 bnx2x e1000 e1000e virtio_net virtio_balloon igb mlx4_en mlx5_core be2net)],
|
|
x86_64 => [qw(tg3 bnx2 bnx2x e1000 e1000e virtio_net virtio_balloon igb mlx4_en mlx5_core be2net)],
|
|
ppc64 => [qw(tg3 e1000 e1000e igb ibmveth ehea be2net)],
|
|
s390x => [qw(qdio ccwgroup qeth qeth_l2 qeth_l3)],
|
|
},
|
|
ubuntu => {
|
|
x86 => [qw(tg3 bnx2 bnx2x e1000 e1000e igb mlx_en mlx5_core virtio_net overlay)],
|
|
x86_64 => [qw(tg3 bnx2 bnx2x e1000 e1000e igb mlx_en mlx5_core virtio_net overlay)],
|
|
ppc64el => [qw(tg3 bnx2 bnx2x e1000 e1000e igb ibmveth ehea mlx_en mlx4_en mlx5_core virtio_net overlay)],
|
|
ppc64 => [qw(e1000 e1000e igb ibmveth ehea)],
|
|
s390x => [qw(qdio ccwgroup)],
|
|
},
|
|
);
|
|
|
|
return () if !exists($drivers{$family}) || !exists($drivers{$family}{$arch});
|
|
return @{ $drivers{$family}{$arch} };
|
|
}
|
|
|
|
sub _kernel_module_name {
|
|
my $path = shift;
|
|
my $name = basename($path);
|
|
|
|
$name =~ s/\.ko(?:\.(?:gz|xz|zst))?$//x;
|
|
$name =~ tr/-/_/;
|
|
return $name;
|
|
}
|
|
|
|
sub target_kernel_module_availability {
|
|
my ( $rootimg_dir, $kernelver, @modules ) = @_;
|
|
my %requested = map { _kernel_module_name($_) => 1 } @modules;
|
|
my %available = map { $_ => 0 } keys %requested;
|
|
my $module_root = "$rootimg_dir/lib/modules/$kernelver";
|
|
|
|
my $modules_dep = "$module_root/modules.dep";
|
|
if (open(my $dep_fh, '<', $modules_dep)) {
|
|
while (my $line = <$dep_fh>) {
|
|
my ($path) = split /:/x, $line, 2;
|
|
my $name = _kernel_module_name($path);
|
|
if ($requested{$name} && -f "$module_root/$path") {
|
|
$available{$name} = 1;
|
|
}
|
|
}
|
|
close($dep_fh);
|
|
}
|
|
|
|
my $modules_builtin = "$module_root/modules.builtin";
|
|
if (open(my $builtin_fh, '<', $modules_builtin)) {
|
|
while (my $path = <$builtin_fh>) {
|
|
chomp($path);
|
|
my $name = _kernel_module_name($path);
|
|
$available{$name} = 1 if $requested{$name};
|
|
}
|
|
close($builtin_fh);
|
|
}
|
|
|
|
if (-d $module_root && grep { !$available{$_} } keys %requested) {
|
|
find(
|
|
{
|
|
no_chdir => 1,
|
|
wanted => sub {
|
|
return if !-f $File::Find::name;
|
|
return if $File::Find::name !~ /\.ko(?:\.(?:gz|xz|zst))?$/x;
|
|
my $name = _kernel_module_name($File::Find::name);
|
|
$available{$name} = 1 if $requested{$name};
|
|
},
|
|
},
|
|
$module_root,
|
|
);
|
|
}
|
|
|
|
return %available;
|
|
}
|
|
|
|
sub resolve_mellanox_default_net_drivers {
|
|
my ( $rootimg_dir, $kernelver, $requested_drivers, @default_drivers ) = @_;
|
|
my @drivers;
|
|
my %seen;
|
|
my $has_mellanox_defaults = grep {
|
|
_kernel_module_name($_) =~ /^mlx(?:_en|4_en|5_core)$/x
|
|
} @default_drivers;
|
|
my $has_mellanox_drivers = $has_mellanox_defaults || grep {
|
|
_kernel_module_name($_) =~ /^mlx(?:_en|4_en|5_core)$/x
|
|
} @{$requested_drivers};
|
|
if (!$has_mellanox_drivers) {
|
|
return grep { !$seen{$_}++ } (@{$requested_drivers}, @default_drivers);
|
|
}
|
|
|
|
my %available = target_kernel_module_availability(
|
|
$rootimg_dir,
|
|
$kernelver,
|
|
qw(mlx_en mlx4_en mlx5_core mlx4_ib mlx5_ib ib_ipoib),
|
|
);
|
|
|
|
# Keep unavailable explicit requests, except for the historical mlx4 alias.
|
|
foreach my $driver (@{$requested_drivers}) {
|
|
my $name = _kernel_module_name($driver);
|
|
if ($name eq 'mlx_en'
|
|
&& !$available{'mlx_en'}
|
|
&& $available{'mlx4_en'})
|
|
{
|
|
$driver =~ s/mlx_en/mlx4_en/;
|
|
}
|
|
push @drivers, $driver;
|
|
}
|
|
|
|
foreach my $driver (@default_drivers) {
|
|
my $name = _kernel_module_name($driver);
|
|
if ($name eq 'mlx_en') {
|
|
if (!$available{'mlx_en'}) {
|
|
next if !$available{'mlx4_en'};
|
|
$driver =~ s/mlx_en/mlx4_en/;
|
|
}
|
|
} elsif ($name eq 'mlx4_en' || $name eq 'mlx5_core') {
|
|
next if !$available{$name};
|
|
}
|
|
push @drivers, $driver;
|
|
}
|
|
|
|
if ($has_mellanox_defaults) {
|
|
my @mellanox_ib_drivers = grep { $available{$_} } qw(mlx4_ib mlx5_ib);
|
|
push @drivers, map { "$_.ko" } @mellanox_ib_drivers;
|
|
if (@mellanox_ib_drivers && $available{'ib_ipoib'}) {
|
|
push @drivers, 'ib_ipoib.ko';
|
|
}
|
|
}
|
|
|
|
return grep { !$seen{$_}++ } @drivers;
|
|
}
|
|
|
|
1;
|