mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-09-04 12:07:56 +00:00
Merge pull request #7789 from VersatusHPC/refactor/package-manager-discovery
refactor(postscripts): share RPM package manager discovery
This commit is contained in:
@@ -0,0 +1,250 @@
|
||||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use File::Copy qw(copy);
|
||||
use File::Path qw(make_path);
|
||||
use File::Slurper qw(read_text write_text);
|
||||
use File::Spec;
|
||||
use File::Temp qw(tempdir);
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin/../lib";
|
||||
use Test::More;
|
||||
|
||||
use XCAT::Test::File qw(repo_path);
|
||||
|
||||
my $postscripts = repo_path(File::Spec->catdir('xCAT', 'postscripts'));
|
||||
my $library = File::Spec->catfile( $postscripts, 'xcatpkgutils.sh' );
|
||||
my $loader = File::Spec->catfile( $postscripts, 'xcatpkgutils-loader.sh' );
|
||||
|
||||
my $tmpdir = tempdir( CLEANUP => 1 );
|
||||
my $dnf_first = File::Spec->catdir( $tmpdir, 'dnf-first' );
|
||||
my $yum_only = File::Spec->catdir( $tmpdir, 'yum-only' );
|
||||
my $neither = File::Spec->catdir( $tmpdir, 'neither' );
|
||||
make_path( $dnf_first, $yum_only, $neither );
|
||||
write_executable( File::Spec->catfile( $dnf_first, 'dnf' ), "#!/bin/sh\n" );
|
||||
write_executable( File::Spec->catfile( $dnf_first, 'yum' ), "#!/bin/sh\n" );
|
||||
write_executable( File::Spec->catfile( $yum_only, 'yum' ), "#!/bin/sh\n" );
|
||||
|
||||
SKIP: {
|
||||
skip 'the shared discovery helper is introduced by the production commit', 3
|
||||
unless helper_available();
|
||||
is_deeply(
|
||||
[ run_helper($dnf_first) ],
|
||||
[ 0, "dnf\n" ],
|
||||
'dnf is preferred when both RPM package managers are executable'
|
||||
);
|
||||
is_deeply(
|
||||
[ run_helper($yum_only) ],
|
||||
[ 0, "yum\n" ],
|
||||
'yum is used when dnf is unavailable'
|
||||
);
|
||||
is_deeply(
|
||||
[ run_helper($neither) ],
|
||||
[ 1, '' ],
|
||||
'discovery fails without output when neither package manager is executable'
|
||||
);
|
||||
}
|
||||
|
||||
my $caller_dir = File::Spec->catdir( $tmpdir, 'callers' );
|
||||
my $test_bin = File::Spec->catdir( $caller_dir, 'bin' );
|
||||
make_path($test_bin);
|
||||
stage_callers($caller_dir);
|
||||
write_executable( File::Spec->catfile( $test_bin, 'logger' ), "#!/bin/sh\nexit 0\n" );
|
||||
write_executable( File::Spec->catfile( $test_bin, 'mount' ), "#!/bin/sh\nexit 1\n" );
|
||||
write_executable(
|
||||
File::Spec->catfile( $test_bin, 'uname' ),
|
||||
"#!/bin/sh\nprintf '%s\\n' Linux\n"
|
||||
);
|
||||
write_executable( File::Spec->catfile( $test_bin, 'dpkg' ), "#!/bin/sh\nexit 1\n" );
|
||||
write_executable(
|
||||
File::Spec->catfile( $test_bin, 'rpm' ),
|
||||
<<'SH'
|
||||
#!/bin/sh
|
||||
case "$*" in
|
||||
--version) exit 0 ;;
|
||||
-q\ zypper)
|
||||
[ "$XCAT_PM_SCENARIO" = zypper ] && exit 0
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
if [ -n "${XCAT_RPM_TRACE:-}" ]; then
|
||||
printf '%s\n' "$*" >> "$XCAT_RPM_TRACE"
|
||||
exit 0
|
||||
fi
|
||||
exit 1
|
||||
SH
|
||||
);
|
||||
write_executable( File::Spec->catfile( $test_bin, 'dnf' ), "#!/bin/sh\nexit 0\n" );
|
||||
write_executable( File::Spec->catfile( $test_bin, 'yum' ), "#!/bin/sh\nexit 0\n" );
|
||||
write_executable( File::Spec->catfile( $test_bin, 'zypper' ), "#!/bin/sh\nexit 0\n" );
|
||||
|
||||
my $bash_env = File::Spec->catfile( $caller_dir, 'bash-env.sh' );
|
||||
# Fake only the absolute executable probes; the staged callers and library stay unchanged.
|
||||
write_text(
|
||||
$bash_env,
|
||||
<<'SH'
|
||||
function [
|
||||
{
|
||||
case "$1:$2:$XCAT_PM_SCENARIO" in
|
||||
-x:/usr/bin/dnf:dnf) return 0 ;;
|
||||
-x:/usr/bin/dnf:*) return 1 ;;
|
||||
-x:/usr/bin/yum:dnf|-x:/usr/bin/yum:yum) return 0 ;;
|
||||
-x:/usr/bin/yum:*) return 1 ;;
|
||||
esac
|
||||
builtin [ "$@"
|
||||
}
|
||||
|
||||
exit()
|
||||
{
|
||||
if builtin [ -n "${XCAT_PM_STATE_TRACE:-}" ]; then
|
||||
printf '%s|%s|%s|%s|%s\n' "${yumcmd:-}" "${hasrpm:-}" "${hasyum:-}" \
|
||||
"${haszypper:-}" "${supdatecommand:-}" \
|
||||
> "$XCAT_PM_STATE_TRACE"
|
||||
fi
|
||||
builtin exit "$@"
|
||||
}
|
||||
SH
|
||||
);
|
||||
|
||||
my %common_env = (
|
||||
ARCH => 'x86_64',
|
||||
BASH_ENV => $bash_env,
|
||||
INSTALLDIR => 'INSTALLDIR',
|
||||
NFSSERVER => 'package-test-server',
|
||||
NODE => 'node1',
|
||||
OSVER => 'rocky9',
|
||||
PATH => "$test_bin:$ENV{PATH}",
|
||||
);
|
||||
|
||||
for my $scenario (
|
||||
[ dnf => 'dnf||||' ],
|
||||
[ yum => 'yum||||' ],
|
||||
)
|
||||
{
|
||||
my ( $name, $expected_state ) = @{$scenario};
|
||||
my ( $status, $output, $state ) = run_caller( 'ospkgs', $name );
|
||||
is( $status, 0, "ospkgs completes with $name" ) or diag($output);
|
||||
is( $state, $expected_state, "ospkgs selects $name" );
|
||||
}
|
||||
|
||||
my ( $ospkgs_status, $ospkgs_output, $ospkgs_state ) =
|
||||
run_caller( 'ospkgs', 'neither' );
|
||||
is( $ospkgs_status, 1, 'ospkgs still stops when neither dnf nor yum is available' );
|
||||
is( $ospkgs_state, '||||', 'ospkgs leaves package-manager state empty on failure' );
|
||||
like(
|
||||
$ospkgs_output,
|
||||
qr/^Please install yum or dnf on node1\.$/m,
|
||||
'ospkgs retains its package-manager installation error'
|
||||
);
|
||||
|
||||
for my $scenario (
|
||||
[ dnf => 'dnf|1|1|0|rpm -Uvh --replacepkgs' ],
|
||||
[ yum => 'yum|1|1|0|rpm -Uvh --replacepkgs' ],
|
||||
[ zypper => '|1|0|1|rpm -Uvh --replacepkgs' ],
|
||||
[ rpm => '|1|0|0|rpm -Uvh --replacepkgs' ],
|
||||
)
|
||||
{
|
||||
my ( $name, $expected_state ) = @{$scenario};
|
||||
my ( $status, $output, $state ) = run_caller( 'otherpkgs', $name );
|
||||
is( $status, 0, "otherpkgs completes with the $name discovery outcome" )
|
||||
or diag($output);
|
||||
is( $state, $expected_state, "otherpkgs retains the $name discovery outcome" );
|
||||
}
|
||||
|
||||
like(
|
||||
read_text( File::Spec->catfile( $caller_dir, 'otherpkgs-rpm-command.trace' ) ),
|
||||
qr/^-Uvh --replacepkgs package-test\*$/m,
|
||||
'otherpkgs executes its raw RPM installation fallback'
|
||||
);
|
||||
|
||||
done_testing();
|
||||
|
||||
sub run_helper {
|
||||
my ($directory) = @_;
|
||||
return run_command(
|
||||
'/bin/sh', '-c', '. "$1"; xcat_find_rpm_package_manager "$2"',
|
||||
'package-manager-discovery-test', $library, $directory
|
||||
);
|
||||
}
|
||||
|
||||
sub helper_available {
|
||||
return system(
|
||||
'/bin/sh', '-c',
|
||||
'. "$1"; command -v xcat_find_rpm_package_manager >/dev/null 2>&1',
|
||||
'package-manager-discovery-test', $library
|
||||
) == 0;
|
||||
}
|
||||
|
||||
sub run_caller {
|
||||
my ( $caller, $scenario ) = @_;
|
||||
my $trace = File::Spec->catfile( $caller_dir, "$caller-$scenario.trace" );
|
||||
local %ENV = ( %ENV, %common_env );
|
||||
$ENV{XCAT_PM_SCENARIO} = $scenario;
|
||||
$ENV{XCAT_PM_STATE_TRACE} = $trace;
|
||||
|
||||
my @arguments;
|
||||
if ( $caller eq 'ospkgs' ) {
|
||||
delete @ENV{qw(OTHERPKGS OTHERPKGS_INDEX UPDATENODE)};
|
||||
$ENV{OSPKGS} = 'package-test';
|
||||
@arguments = ('--keeprepo');
|
||||
} else {
|
||||
delete @ENV{qw(OSPKGS OTHERPKGS)};
|
||||
$ENV{OSVER} = 'custom9';
|
||||
if ( $scenario eq 'rpm' ) {
|
||||
$ENV{OTHERPKGS1} = 'package-test';
|
||||
$ENV{OTHERPKGS_INDEX} = 1;
|
||||
$ENV{XCAT_RPM_TRACE} = File::Spec->catfile(
|
||||
$caller_dir, 'otherpkgs-rpm-command.trace'
|
||||
);
|
||||
} else {
|
||||
delete @ENV{qw(OTHERPKGS1 XCAT_RPM_TRACE)};
|
||||
$ENV{OTHERPKGS_INDEX} = 0;
|
||||
}
|
||||
$ENV{UPDATENODE} = 1;
|
||||
}
|
||||
|
||||
my ( $status, $output ) = run_command(
|
||||
File::Spec->catfile( $caller_dir, $caller ), @arguments
|
||||
);
|
||||
my $state = read_text($trace);
|
||||
chomp($state);
|
||||
return ( $status, $output, $state );
|
||||
}
|
||||
|
||||
sub stage_callers {
|
||||
my ($directory) = @_;
|
||||
for my $source (
|
||||
$library, $loader,
|
||||
map { File::Spec->catfile( $postscripts, $_ ) } qw(ospkgs otherpkgs)
|
||||
)
|
||||
{
|
||||
my $filename = ( File::Spec->splitpath($source) )[2];
|
||||
my $destination = File::Spec->catfile( $directory, $filename );
|
||||
copy( $source, $destination )
|
||||
or die "Unable to stage $source as $destination: $!";
|
||||
chmod 0755, $destination
|
||||
or die "Unable to make $destination executable: $!";
|
||||
}
|
||||
}
|
||||
|
||||
sub write_executable {
|
||||
my ( $path, $contents ) = @_;
|
||||
write_text( $path, $contents );
|
||||
chmod 0755, $path or die "Unable to make $path executable: $!";
|
||||
}
|
||||
|
||||
sub run_command {
|
||||
my (@command) = @_;
|
||||
my $pid = open( my $pipe, '-|' );
|
||||
die "Unable to fork for @command: $!" unless defined($pid);
|
||||
if ( $pid == 0 ) {
|
||||
open( STDERR, '>&', STDOUT ) or die "Unable to merge stderr: $!";
|
||||
exec { $command[0] } @command;
|
||||
die "Unable to execute @command: $!";
|
||||
}
|
||||
|
||||
my $output = do { local $/; <$pipe> } // '';
|
||||
close($pipe);
|
||||
return ( $? >> 8, $output );
|
||||
}
|
||||
@@ -892,11 +892,7 @@ elif ( pmatch "$OSVER" "ubuntu*" ); then
|
||||
fi
|
||||
else
|
||||
#check if yum or dnf is installed
|
||||
if [ -x /usr/bin/dnf ]; then
|
||||
yumcmd="dnf"
|
||||
elif [ -x /usr/bin/yum ]; then
|
||||
yumcmd="yum"
|
||||
else
|
||||
if ! yumcmd=$(xcat_find_rpm_package_manager); then
|
||||
echo "Please install yum or dnf on $NODE."
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
@@ -491,12 +491,8 @@ else
|
||||
result=`rpm --version 2>/dev/null`
|
||||
if [ $? -eq 0 ]; then
|
||||
hasrpm=1
|
||||
if [ -x /usr/bin/dnf ]; then
|
||||
if yumcmd=$(xcat_find_rpm_package_manager); then
|
||||
hasyum=1
|
||||
yumcmd="dnf"
|
||||
elif [ -x /usr/bin/yum ]; then
|
||||
hasyum=1
|
||||
yumcmd="yum"
|
||||
else
|
||||
result=`rpm -q zypper`
|
||||
if [ "$?" = "0" ]; then
|
||||
|
||||
@@ -2,6 +2,18 @@
|
||||
# EPL license http://www.eclipse.org/legal/epl-v10.html
|
||||
|
||||
# Shared POSIX shell helpers for the ospkgs and otherpkgs postscripts.
|
||||
|
||||
xcat_find_rpm_package_manager()
|
||||
{
|
||||
if [ -x "${1:-/usr/bin}/dnf" ]; then
|
||||
printf '%s\n' dnf
|
||||
elif [ -x "${1:-/usr/bin}/yum" ]; then
|
||||
printf '%s\n' yum
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Keep the marker assignment last so callers know the whole library loaded.
|
||||
|
||||
xcat_is_el_modular_pkgdir()
|
||||
|
||||
Reference in New Issue
Block a user