mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-10-02 00:41:42 +00:00
refactor(xcat-server): move the builder repository name out of the postscript
The name of the EL builder repository was decided inside servicenode, so a test of that decision had to load the postscript. It is a table with one row per vendor and EL major version, and it belongs in a module. ELBuilderRepo ships in /install/postscripts and is copied to /xcatpost with the postscripts, so it loads on a service node that has no xCAT package yet. servicenode keeps the side effects: enable EPEL, ask the module for the ids, enable the first one dnf knows, and report what it could not enable. servicenode_builder_repo.t is now a table: Alma, Rocky, CentOS Stream, RHEL and Oracle Linux across EL8, EL9 and EL10, plus the capitalised PowerTools that Rocky 8.4 and earlier shipped. Returning crb for EL8 fails nine of its assertions. Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
This commit is contained in:
@@ -6,46 +6,60 @@ use File::Spec;
|
||||
use FindBin;
|
||||
use Test::More;
|
||||
|
||||
# xCAT-server requires perl modules that EL keeps in the distribution builder repository:
|
||||
# perl-IO-Tty, perl-Crypt-CBC, perl-Crypt-Rijndael and perl(Expect). That repository is
|
||||
# DISABLED on a fresh EL install, so dnf install xCATsn on a service node does not resolve and
|
||||
# the node ends with no xcatd. The servicenode postscript enabled EPEL and nothing else.
|
||||
# xCAT-server requires perl modules EL keeps in the distribution builder repository:
|
||||
# perl-IO-Tty, perl-Crypt-CBC, perl-Crypt-Rijndael and perl(Expect). That repository is disabled
|
||||
# on a fresh EL install, so dnf install xCATsn on a service node does not resolve and the node
|
||||
# ends with no xcatd. The servicenode postscript enabled EPEL and nothing else.
|
||||
#
|
||||
# The repository has a different id on every EL vendor and release, so the decision is a sub and
|
||||
# this test drives it. Enabling the repository is a side effect and stays in the postscript.
|
||||
# The repository is not called crb on EL8, and each vendor names it differently, so the decision
|
||||
# is a module and this is its table. Enabling the repository is a side effect and stays in the
|
||||
# postscript.
|
||||
|
||||
my $script = File::Spec->catfile($FindBin::Bin, '..', '..', 'xCAT', 'postscripts', 'servicenode');
|
||||
plan skip_all => "servicenode not found" unless -f $script;
|
||||
# The postscript guards its own body with caller(), so requiring it compiles the subs and runs
|
||||
# nothing. A postscript that loses that guard executes here, which is the loud failure to have.
|
||||
eval { require $script; 1 } or plan skip_all => "could not load servicenode: $@";
|
||||
can_ok('main', 'builder_repo_ids') or done_testing() && exit;
|
||||
use lib File::Spec->catdir($FindBin::Bin, '..', '..', 'xCAT', 'postscripts');
|
||||
use_ok('ELBuilderRepo') or done_testing() && exit;
|
||||
|
||||
sub ids { return [ main::builder_repo_ids(@_) ] }
|
||||
my @table = (
|
||||
# vendor major arch expected ids
|
||||
[ 'almalinux', 8, 'x86_64', [ 'powertools', 'PowerTools' ] ],
|
||||
[ 'almalinux', 9, 'x86_64', ['crb'] ],
|
||||
[ 'almalinux', 10, 'x86_64', ['crb'] ],
|
||||
[ 'rocky', 8, 'x86_64', [ 'powertools', 'PowerTools' ] ],
|
||||
[ 'rocky', 9, 'ppc64le', ['crb'] ],
|
||||
[ 'rocky', 10, 'x86_64', ['crb'] ],
|
||||
[ 'centos', 8, 'x86_64', [ 'powertools', 'PowerTools' ] ],
|
||||
[ 'centos', 9, 'x86_64', ['crb'] ],
|
||||
[ 'centos', 10, 'x86_64', ['crb'] ],
|
||||
[ 'rhel', 8, 'ppc64le', ['codeready-builder-for-rhel-8-ppc64le-rpms'] ],
|
||||
[ 'rhel', 9, 'x86_64', ['codeready-builder-for-rhel-9-x86_64-rpms'] ],
|
||||
[ 'rhel', 10, 'x86_64', ['codeready-builder-for-rhel-10-x86_64-rpms'] ],
|
||||
[ 'ol', 8, 'x86_64', ['ol8_codeready_builder'] ],
|
||||
[ 'ol', 9, 'x86_64', ['ol9_codeready_builder'] ],
|
||||
[ 'ol', 10, 'x86_64', ['ol10_codeready_builder'] ],
|
||||
);
|
||||
|
||||
is_deeply(ids('almalinux', '9.8', 'x86_64'), ['crb'],
|
||||
'AlmaLinux 9 names crb');
|
||||
is_deeply(ids('rocky', '10.0', 'x86_64'), ['crb'],
|
||||
'Rocky 10 names crb');
|
||||
is_deeply(ids('centos', '9', 'ppc64le'), ['crb'],
|
||||
'CentOS Stream 9 names crb');
|
||||
is_deeply(ids('almalinux', '8.10', 'x86_64'), [ 'powertools', 'PowerTools' ],
|
||||
'AlmaLinux 8 names powertools, and the CentOS 8 spelling after it');
|
||||
is_deeply(ids('rhel', '9.4', 'x86_64'), ['codeready-builder-for-rhel-9-x86_64-rpms'],
|
||||
'RHEL 9 names its arch-qualified codeready-builder repository');
|
||||
is_deeply(ids('rhel', '8.9', 'ppc64le'), ['codeready-builder-for-rhel-8-ppc64le-rpms'],
|
||||
'RHEL 8 keeps the arch in the repository id');
|
||||
is_deeply(ids('ol', '9.3', 'x86_64'), ['ol9_codeready_builder'],
|
||||
'Oracle Linux 9 names its own codeready builder repository');
|
||||
for my $row (@table) {
|
||||
my ($vendor, $major, $arch, $want) = @$row;
|
||||
my @got = ELBuilderRepo::builder_repo_ids($vendor, $major, $arch);
|
||||
is_deeply(\@got, $want, "$vendor EL$major names @$want");
|
||||
}
|
||||
|
||||
# A caller with nothing to go on must get nothing to enable, not a guess.
|
||||
is_deeply(ids(undef, '9', 'x86_64'), [], 'no distribution id yields no repository');
|
||||
is_deeply(ids('almalinux', undef, 'x86_64'), [], 'no version yields no repository');
|
||||
is_deeply(ids('almalinux', 'rawhide', 'x86_64'), [], 'a version with no major number yields no repository');
|
||||
# The EL8 name is the one that is easy to get wrong: the display name reads
|
||||
# "AlmaLinux 8 - PowerTools" while the id is lowercase, and crb does not exist there at all.
|
||||
for my $vendor (qw(almalinux rocky centos)) {
|
||||
my @got = ELBuilderRepo::builder_repo_ids($vendor, 8, 'x86_64');
|
||||
ok(!grep({ $_ eq 'crb' } @got), "$vendor EL8 does not name crb");
|
||||
is($got[0], 'powertools', "$vendor EL8 tries the lowercase id first");
|
||||
}
|
||||
|
||||
# The arch only reaches the RHEL id. A missing arch must not build a repository id with a hole
|
||||
# in it, which dnf would accept as an unknown repository and silently skip.
|
||||
is_deeply(ids('rhel', '9.4', undef), ['codeready-builder-for-rhel-9-x86_64-rpms'],
|
||||
'a missing arch falls back to x86_64 rather than an empty field');
|
||||
# Nothing to go on must yield nothing to enable, not a guess.
|
||||
is_deeply([ ELBuilderRepo::builder_repo_ids(undef, 9, 'x86_64') ], [], 'no vendor yields no repository');
|
||||
is_deeply([ ELBuilderRepo::builder_repo_ids('almalinux', undef, 'x86_64') ], [], 'no major version yields no repository');
|
||||
is_deeply([ ELBuilderRepo::builder_repo_ids('almalinux', '9.8', 'x86_64') ], [],
|
||||
'a version that is not a bare major yields no repository, so the caller must parse it');
|
||||
|
||||
# The arch reaches the RHEL id alone. A missing arch must not leave a hole in it, which dnf
|
||||
# accepts as an unknown repository and skips without a word.
|
||||
is_deeply([ ELBuilderRepo::builder_repo_ids('rhel', 9, undef) ],
|
||||
['codeready-builder-for-rhel-9-x86_64-rpms'], 'a missing arch falls back to x86_64');
|
||||
|
||||
done_testing();
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package ELBuilderRepo;
|
||||
|
||||
# The repository ids that carry the EL builder packages.
|
||||
#
|
||||
# xCAT-server requires perl-IO-Tty, perl-Crypt-CBC, perl-Crypt-Rijndael and perl(Expect). EL
|
||||
# keeps them in the distribution builder repository, which is disabled on a fresh install, so
|
||||
# dnf install xCATsn on a service node does not resolve. Every vendor names that repository
|
||||
# differently and the name changed at EL9: it is not crb on EL8.
|
||||
#
|
||||
# This module ships in /install/postscripts and is copied to /xcatpost with the postscripts, so
|
||||
# it loads on a node that has no xCAT packages yet.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
=head3 builder_repo_ids
|
||||
|
||||
Arguments:
|
||||
$vendor the ID field of /etc/os-release, for example almalinux, rocky, centos, rhel, ol
|
||||
$major the EL major version, 8, 9 or 10
|
||||
$arch the machine architecture. Only the RHEL id carries one
|
||||
|
||||
Returns:
|
||||
the repository ids to try, most likely first, or an empty list when the arguments name
|
||||
no EL release. An empty list is the answer for "do not guess".
|
||||
|
||||
Covered: AlmaLinux, Rocky and CentOS Stream (crb on 9 and later, powertools on 8, with the
|
||||
capitalised PowerTools that Rocky 8.4 and earlier shipped after it), RHEL
|
||||
(codeready-builder-for-rhel-<major>-<arch>-rpms) and Oracle Linux
|
||||
(ol<major>_codeready_builder). Another vendor takes the community spellings, which is a
|
||||
guess.
|
||||
|
||||
=cut
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
sub builder_repo_ids {
|
||||
my ($vendor, $major, $arch) = @_;
|
||||
|
||||
return () unless defined $vendor && length $vendor;
|
||||
return () unless defined $major && $major =~ /^\d+$/;
|
||||
$arch = 'x86_64' unless defined $arch && length $arch;
|
||||
|
||||
return ("codeready-builder-for-rhel-$major-$arch-rpms") if $vendor eq 'rhel';
|
||||
return ("ol${major}_codeready_builder") if $vendor eq 'ol';
|
||||
return ('powertools', 'PowerTools') if $major == 8;
|
||||
return ('crb');
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -44,6 +44,10 @@ if ($^O =~ /^aix/i) {
|
||||
}
|
||||
|
||||
use lib "$::XCATROOT/lib/perl";
|
||||
# ELBuilderRepo ships beside this script and reaches the node in /xcatpost with it.
|
||||
use File::Basename qw(dirname);
|
||||
use Cwd qw(abs_path);
|
||||
use lib dirname(abs_path($0));
|
||||
use strict;
|
||||
|
||||
# MAIN
|
||||
@@ -177,52 +181,14 @@ exit $rc;
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
=head3 builder_repo_ids
|
||||
|
||||
The repository ids that carry the EL builder packages, most likely first.
|
||||
|
||||
xCAT-server requires perl-IO-Tty, perl-Crypt-CBC, perl-Crypt-Rijndael and perl(Expect).
|
||||
EL keeps them in the builder repository, which every vendor names differently and which is
|
||||
disabled on a fresh install. The caller enables the first id dnf knows.
|
||||
|
||||
Covered: AlmaLinux, Rocky and CentOS Stream (crb on 9 and 10, powertools on 8), RHEL
|
||||
(codeready-builder-for-rhel-<major>-<arch>-rpms) and Oracle Linux
|
||||
(ol<major>_codeready_builder). Not covered: any other vendor, which gets crb on 9 and later
|
||||
and powertools on 8 because those are the community spellings.
|
||||
|
||||
Arguments:
|
||||
$id the ID field of /etc/os-release
|
||||
$version the VERSION_ID field of /etc/os-release
|
||||
$arch the machine architecture, for the RHEL id only
|
||||
Returns:
|
||||
the repository ids to try, in order, or an empty list when the arguments name no EL
|
||||
release. An empty list is the answer for "do not guess".
|
||||
|
||||
=cut
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
sub builder_repo_ids {
|
||||
my ($id, $version, $arch) = @_;
|
||||
|
||||
return () unless defined $id && length $id;
|
||||
return () unless defined $version;
|
||||
my ($major) = $version =~ /^(\d+)/;
|
||||
return () unless defined $major;
|
||||
$arch = 'x86_64' unless defined $arch && length $arch;
|
||||
|
||||
return ("codeready-builder-for-rhel-$major-$arch-rpms") if $id eq 'rhel';
|
||||
return ("ol${major}_codeready_builder") if $id eq 'ol';
|
||||
return ('powertools', 'PowerTools') if $major == 8;
|
||||
return ('crb');
|
||||
}
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
=head3 enable_el_dependency_repos
|
||||
|
||||
Enable EPEL and the builder repository on an EL service node, and say so when either is
|
||||
still absent. Neither is fatal: a site can run without EPEL, and xcat-dep carries the same
|
||||
perl closure. What must not happen is silence.
|
||||
Enable EPEL and the distribution builder repository on an EL service node, and say so when
|
||||
either is still absent. Neither is fatal: a site can run without EPEL, and xcat-dep carries
|
||||
the same perl closure. What must not happen is silence.
|
||||
|
||||
ELBuilderRepo names the builder repository. It ships beside this script and reaches the node
|
||||
in /xcatpost with it, so it loads where no xCAT package is installed yet.
|
||||
|
||||
=cut
|
||||
|
||||
@@ -231,41 +197,56 @@ sub enable_el_dependency_repos {
|
||||
my ($log_label) = @_;
|
||||
|
||||
my $osrel = `cat /etc/os-release 2>/dev/null` || '';
|
||||
my ($id) = $osrel =~ /^ID="?([^"\n]+)"?/m;
|
||||
my ($vendor) = $osrel =~ /^ID="?([^"\n]+)"?/m;
|
||||
my ($version) = $osrel =~ /^VERSION_ID="?([^"\n]+)"?/m;
|
||||
my ($major) = defined $version ? $version =~ /^(\d+)/ : ();
|
||||
my $arch = `uname -m 2>/dev/null`;
|
||||
chomp $arch if defined $arch;
|
||||
|
||||
`logger -t $log_label -p local4.info servicenode: enabling EPEL and the builder repository for xCAT-server dependencies`;
|
||||
&runcmd("dnf -y install epel-release");
|
||||
unless (`dnf repolist --enabled 2>/dev/null` =~ /^epel\b/m) {
|
||||
my $m = "servicenode: EPEL is not enabled on $::hname. xCAT-server perl dependencies must"
|
||||
. " then come from xcat-dep, or xCATsn will not install.";
|
||||
print "$m\n";
|
||||
`logger -t $log_label -p local4.warning "$m"`;
|
||||
&report_missing_repo($log_label, "EPEL", "");
|
||||
}
|
||||
|
||||
my @ids = &builder_repo_ids($id, $version, $arch);
|
||||
my $known = `dnf repolist --all 2>/dev/null` || '';
|
||||
my $enabled = '';
|
||||
foreach my $repo (@ids) {
|
||||
next unless $known =~ /^\Q$repo\E\s/m;
|
||||
&runcmd("dnf -y install dnf-plugins-core") unless -x "/usr/bin/dnf-3";
|
||||
if (&runcmd("dnf config-manager --set-enabled $repo") == 0) {
|
||||
$enabled = $repo;
|
||||
last;
|
||||
}
|
||||
}
|
||||
if ($enabled) {
|
||||
`logger -t $log_label -p local4.info "servicenode: enabled the builder repository $enabled"`;
|
||||
my @ids;
|
||||
if (eval { require ELBuilderRepo; 1 }) {
|
||||
@ids = ELBuilderRepo::builder_repo_ids($vendor, $major, $arch);
|
||||
}
|
||||
else {
|
||||
my $m = "servicenode: no builder repository could be enabled on $::hname (tried: "
|
||||
. join(', ', @ids) . "). perl-IO-Tty, perl-Crypt-CBC, perl-Crypt-Rijndael and"
|
||||
. " perl(Expect) must then come from xcat-dep, or xCATsn will not install.";
|
||||
print "$m\n";
|
||||
`logger -t $log_label -p local4.warning "$m"`;
|
||||
`logger -t $log_label -p local4.warning "servicenode: ELBuilderRepo did not load: $@"`;
|
||||
}
|
||||
|
||||
my $known = `dnf repolist --all 2>/dev/null` || '';
|
||||
foreach my $repo (@ids) {
|
||||
next unless $known =~ /^\Q$repo\E\s/m;
|
||||
&runcmd("dnf -y install dnf-plugins-core");
|
||||
next unless &runcmd("dnf config-manager --set-enabled $repo") == 0;
|
||||
`logger -t $log_label -p local4.info "servicenode: enabled the builder repository $repo"`;
|
||||
return 0;
|
||||
}
|
||||
&report_missing_repo($log_label, "no builder repository", " (tried: " . join(', ', @ids) . ")");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
=head3 report_missing_repo
|
||||
|
||||
Print and log that a repository could not be enabled. Printing is what makes it visible: the
|
||||
node copies this script's output into /var/log/xcat/xcat.log, while the EPEL step reported
|
||||
only to syslog, where nothing read it.
|
||||
|
||||
=cut
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
sub report_missing_repo {
|
||||
my ($log_label, $what, $detail) = @_;
|
||||
my $m = "servicenode: $what could be enabled on $::hname$detail. perl-IO-Tty, perl-Crypt-CBC,"
|
||||
. " perl-Crypt-Rijndael and perl(Expect) must then come from xcat-dep, or xCATsn will"
|
||||
. " not install.";
|
||||
print "$m\n";
|
||||
`logger -t $log_label -p local4.warning "$m"`;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user