mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-09-10 11:36:25 +00:00
test(xcat-core): Introduce BATS & convert shell scripting tests to it
The go-xcat shell behavior tests were written as Perl harnesses, which made the shell assertions harder to read and kept shell-specific setup outside a native shell test framework. Add BATS to the GitHub Actions dependency set, run BATS tests from the same preserved source tree as the Perl unit suite, and move the go-xcat repository checks into xCAT-test/autotest/bats. Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
This commit is contained in:
@@ -7,7 +7,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Install dependencies
|
||||
run: sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends --no-install-suggests build-essential fakeroot reprepro devscripts debhelper libcapture-tiny-perl libfile-slurper-perl libjson-perl libparallel-forkmanager-perl libsoap-lite-perl libdbi-perl libcgi-pm-perl quilt openssh-server dpkg looptools genometools software-properties-common
|
||||
run: sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends --no-install-suggests bats build-essential fakeroot reprepro devscripts debhelper libcapture-tiny-perl libfile-slurper-perl libjson-perl libparallel-forkmanager-perl libsoap-lite-perl libdbi-perl libcgi-pm-perl quilt openssh-server dpkg looptools genometools software-properties-common
|
||||
- name: Run tests
|
||||
run: perl github_action_xcat_test.pl
|
||||
|
||||
|
||||
@@ -311,8 +311,11 @@ sub preserve_source_tree{
|
||||
return 1;
|
||||
}
|
||||
|
||||
@output = runcmd("ls $unitsrc/xCAT-test/unit/*.t | wc -l");
|
||||
print "[preserve_source_tree] preserved $srcdir in $unitsrc ($output[0] unit tests)\n";
|
||||
@output = runcmd("find $unitsrc/xCAT-test/unit -name '*.t' | wc -l");
|
||||
my $perl_count = $output[0];
|
||||
@output = runcmd("find $unitsrc/xCAT-test/autotest/bats -name '*.bats' 2>/dev/null | wc -l");
|
||||
my $bats_count = $output[0];
|
||||
print "[preserve_source_tree] preserved $srcdir in $unitsrc ($perl_count Perl unit tests, $bats_count BATS tests)\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -466,6 +469,39 @@ sub run_unit_tests{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#--------------------------------------------------------
|
||||
# Fuction name: run_bats_tests
|
||||
# Description: Run shell-script unit tests under xCAT-test/autotest/bats.
|
||||
# Runs against the pre-build copy of the source tree taken by
|
||||
# preserve_source_tree(), like the Perl unit tests.
|
||||
# Attributes:
|
||||
# Return code: 0 all tests passed, 1 otherwise
|
||||
#--------------------------------------------------------
|
||||
sub run_bats_tests{
|
||||
my $testdir = "$unitsrc/xCAT-test/autotest/bats";
|
||||
my @output = runcmd("find $testdir -name '*.bats' -print -quit 2>/dev/null");
|
||||
if (!@output) {
|
||||
print "[run_bats_tests] no BATS tests found under $testdir\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
my $cmd = "cd $unitsrc && bats -r xCAT-test/autotest/bats";
|
||||
print "[run_bats_tests] running $cmd\n";
|
||||
@output = runcmd("$cmd");
|
||||
print Dumper \@output;
|
||||
if($::RUNCMD_RC){
|
||||
print RED "[run_bats_tests] $cmd ....[Failed]\n";
|
||||
$check_result_str .= "> **BATS TESTS Failed** : Please click ``Details`` label in ``Merge pull request`` box for detailed information\n";
|
||||
print $check_result_str;
|
||||
return 1;
|
||||
}
|
||||
|
||||
print "[run_bats_tests] $cmd ....[Pass]\n";
|
||||
$check_result_str .= "> **BATS TESTS Successful**\n";
|
||||
print $check_result_str;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#--------------------------------------------------------
|
||||
# Fuction name: check_syntax
|
||||
# Description:
|
||||
@@ -689,6 +725,15 @@ if($rst){
|
||||
}
|
||||
mark_time("run_unit_tests");
|
||||
|
||||
#Run shell-script unit tests.
|
||||
print GREEN "\n------Running xCAT-test BATS tests ------\n";
|
||||
$rst = run_bats_tests();
|
||||
if($rst){
|
||||
print RED "Run of xCAT-test BATS tests failed\n";
|
||||
exit $rst;
|
||||
}
|
||||
mark_time("run_bats_tests");
|
||||
|
||||
#Check the syntax of changing code
|
||||
print GREEN "\n------ Checking the syntax of changed code------\n";
|
||||
$rst = check_syntax();
|
||||
|
||||
@@ -9,14 +9,15 @@ depends() {
|
||||
}
|
||||
|
||||
installkernel() {
|
||||
local modules_dep modfile modname
|
||||
local modules_dep modules_root modfile modname
|
||||
|
||||
if [[ -n "${kernel:-}" && -r "/lib/modules/$kernel/modules.dep" ]]; then
|
||||
modules_dep="/lib/modules/$kernel/modules.dep"
|
||||
elif [[ -n "${KERNELVERSION:-}" && -r "/lib/modules/$KERNELVERSION/modules.dep" ]]; then
|
||||
modules_dep="/lib/modules/$KERNELVERSION/modules.dep"
|
||||
modules_root="${DRACUT_MODULES_ROOT:-/lib/modules}"
|
||||
if [[ -n "${kernel:-}" && -r "$modules_root/$kernel/modules.dep" ]]; then
|
||||
modules_dep="$modules_root/$kernel/modules.dep"
|
||||
elif [[ -n "${KERNELVERSION:-}" && -r "$modules_root/$KERNELVERSION/modules.dep" ]]; then
|
||||
modules_dep="$modules_root/$KERNELVERSION/modules.dep"
|
||||
else
|
||||
modules_dep=$(ls -1 /lib/modules/*/modules.dep 2>/dev/null | head -n 1)
|
||||
modules_dep=$(ls -1 "$modules_root"/*/modules.dep 2>/dev/null | head -n 1)
|
||||
fi
|
||||
|
||||
[[ -r "$modules_dep" ]] || return 0
|
||||
|
||||
@@ -9,14 +9,15 @@ depends() {
|
||||
}
|
||||
|
||||
installkernel() {
|
||||
local modules_dep modfile modname
|
||||
local modules_dep modules_root modfile modname
|
||||
|
||||
if [[ -n "${kernel:-}" && -r "/lib/modules/$kernel/modules.dep" ]]; then
|
||||
modules_dep="/lib/modules/$kernel/modules.dep"
|
||||
elif [[ -n "${KERNELVERSION:-}" && -r "/lib/modules/$KERNELVERSION/modules.dep" ]]; then
|
||||
modules_dep="/lib/modules/$KERNELVERSION/modules.dep"
|
||||
modules_root="${DRACUT_MODULES_ROOT:-/lib/modules}"
|
||||
if [[ -n "${kernel:-}" && -r "$modules_root/$kernel/modules.dep" ]]; then
|
||||
modules_dep="$modules_root/$kernel/modules.dep"
|
||||
elif [[ -n "${KERNELVERSION:-}" && -r "$modules_root/$KERNELVERSION/modules.dep" ]]; then
|
||||
modules_dep="$modules_root/$KERNELVERSION/modules.dep"
|
||||
else
|
||||
modules_dep=$(ls -1 /lib/modules/*/modules.dep 2>/dev/null | head -n 1)
|
||||
modules_dep=$(ls -1 "$modules_root"/*/modules.dep 2>/dev/null | head -n 1)
|
||||
fi
|
||||
|
||||
[[ -r "$modules_dep" ]] || return 0
|
||||
|
||||
@@ -100,10 +100,7 @@ if [ ! -x /usr/bin/wget ]; then
|
||||
sleep 36500d
|
||||
fi
|
||||
|
||||
# These dispatcher scripts are not needed by the legacy post.xcat path. Newer
|
||||
# wget parses HTML-looking regex strings inside downloaded scripts and fails the
|
||||
# whole recursive download on bogus URLs.
|
||||
wget -l inf -N -r --waitretry=10 --random-wait --retry-connrefused -e robots=off -nH --cut-dirs=2 --reject "index.html*,post.xcat.ng,post.xcat.rhels10" --no-parent -t 20 -T 60 http://${MASTER_IP}:${HTTPPORT}${INSTALLDIR}/postscripts/ -P /xcatpost 2> /tmp/wget.log
|
||||
xcat_download_postscripts "${MASTER_IP}:${HTTPPORT}" "$INSTALLDIR" "/xcatpost" "/tmp/wget.log"
|
||||
if [ "$?" != "0" ]; then
|
||||
msgutil_r "$MASTER_IP" "error" "failed to download postscripts from http://$MASTER_IP$INSTALLDIR/postscripts/,check /tmp/wget.log on the node, halt ..." "/var/log/xcat/xcat.log" "$log_label"
|
||||
/tmp/updateflag $MASTER $XCATIPORT "installstatus failed"
|
||||
|
||||
@@ -191,17 +191,6 @@ if [ -e "/tmp/xcat.install_disk" ]; then
|
||||
fi
|
||||
|
||||
msgutil_r "$MASTER_IP" "info" "Found $instdisk, generate partition file..." "/var/log/xcat/xcat.log" "$log_label"
|
||||
set_sles11_uefi_bootloader()
|
||||
{
|
||||
if grep -E 'install=.*sles11' /proc/cmdline >/dev/null 2>&1; then
|
||||
# SLES 11 AutoYaST keeps the template's legacy MBR bootloader
|
||||
# location unless the UEFI path explicitly selects elilo.
|
||||
sed -i -e '/<lba_support /d' \
|
||||
-e '/<linear /d' \
|
||||
-e 's!<location>mbr</location>!<loader_type>elilo</loader_type>!' \
|
||||
/tmp/profile/modified.xml
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -d /sys/firmware/efi ]; then
|
||||
sed -e 's!<device>XCATPARTITIONHOOK</device>!<device>'$instdisk'</device><partitions config:type="list"><partition><filesystem config:type="symbol">vfat</filesystem><mount>/boot/efi</mount><size>128mb</size></partition><partition><mount>swap</mount><size>auto</size></partition><partition><mount>/</mount><size>auto</size></partition></partitions>!' /tmp/profile/autoinst.xml > /tmp/profile/modified.xml
|
||||
|
||||
@@ -63,3 +63,27 @@ declare -F xcat_enable_active_nm_autoconnect &>/dev/null || function xcat_enable
|
||||
nmcli con mod "$con_name" connection.autoconnect yes
|
||||
done
|
||||
}
|
||||
|
||||
declare -F xcat_download_postscripts &>/dev/null || function xcat_download_postscripts {
|
||||
local server="$1"
|
||||
local install_dir="${2:-/install}"
|
||||
local postroot="${3:-/xcatpost}"
|
||||
local log_file="${4:-/tmp/wget.log}"
|
||||
|
||||
export LANG=C
|
||||
wget -l inf -N -r --waitretry=10 --random-wait --retry-connrefused -e robots=off -nH --cut-dirs=2 --reject "index.html*,post.xcat.ng,post.xcat.rhels10" --no-parent -t 20 -T 60 "http://${server}${install_dir}/postscripts/" -P "$postroot" 2> "$log_file"
|
||||
}
|
||||
|
||||
declare -F set_sles11_uefi_bootloader &>/dev/null || function set_sles11_uefi_bootloader {
|
||||
local cmdline="${1:-/proc/cmdline}"
|
||||
local profile="${2:-/tmp/profile/modified.xml}"
|
||||
|
||||
if grep -E 'install=.*sles11' "$cmdline" >/dev/null 2>&1; then
|
||||
# SLES 11 AutoYaST keeps the template's legacy MBR bootloader
|
||||
# location unless the UEFI path explicitly selects elilo.
|
||||
sed -i -e '/<lba_support /d' \
|
||||
-e '/<linear /d' \
|
||||
-e 's!<location>mbr</location>!<loader_type>elilo</loader_type>!' \
|
||||
"$profile"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# xCAT-test
|
||||
|
||||
Unit tests that run from the source checkout are split by implementation
|
||||
language:
|
||||
|
||||
| Test type | Location | Runner |
|
||||
| --------- | -------- | ------ |
|
||||
| Perl unit tests | `xCAT-test/unit/*.t` | `prove -r xCAT-test/unit` |
|
||||
| Shell unit tests | `xCAT-test/autotest/bats/*.bats` | `bats -r xCAT-test/autotest/bats` |
|
||||
|
||||
Use Perl `.t` tests for Perl modules, Perl scripts, templates, and repository
|
||||
artifacts. Use BATS tests for shell-script behavior that can be exercised from
|
||||
the checkout by sourcing a shell library or script and shadowing external
|
||||
commands.
|
||||
|
||||
Shell behavior should not be tested by Perl tests that grep shell source. Put
|
||||
those tests under `xCAT-test/autotest/bats` instead.
|
||||
|
||||
See `unit/README.md` and `autotest/bats/README.md` for the detailed rules for
|
||||
each unit-test suite.
|
||||
@@ -0,0 +1,21 @@
|
||||
# xCAT-test/autotest/bats
|
||||
|
||||
Shell-script unit tests live here and run with:
|
||||
|
||||
```bash
|
||||
bats -r xCAT-test/autotest/bats
|
||||
```
|
||||
|
||||
The GitHub Actions `xcat_test` workflow runs this command after the Perl `.t`
|
||||
unit tests. Use BATS for shell behavior that can be exercised from the source
|
||||
tree without an installed xCAT, a live management node, or real services.
|
||||
|
||||
Prefer sourcing an existing shell library or sourceable script and calling the
|
||||
function under test. Keep reusable install-template helpers in
|
||||
`xCAT-server/share/xcat/install/scripts/scriptlib`, and reusable postscript
|
||||
helpers in `xCAT/postscripts/xcatlib.sh`. Use scratch directories and shadowed
|
||||
commands so tests cannot write to the host.
|
||||
|
||||
Extraction helpers in `helpers/shell_source.bash` are only for legacy code that
|
||||
cannot safely be sourced yet. Do not add Perl `.t` tests that grep shell source
|
||||
when the behavior can be tested with BATS.
|
||||
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
load 'helpers/shell_source'
|
||||
|
||||
setup()
|
||||
{
|
||||
GENESIS_SPEC="$(repo_path 'xCAT-genesis-builder/xCAT-genesis-base.spec')"
|
||||
DRACUT_MODULE="$(repo_path 'xCAT-genesis-builder/dracut_105/el/module-setup.sh')"
|
||||
DOXCAT="$(repo_path 'xCAT-genesis-scripts/usr/bin/doxcat')"
|
||||
[ -r "$GENESIS_SPEC" ] || skip "$GENESIS_SPEC is required"
|
||||
[ -r "$DRACUT_MODULE" ] || skip "$DRACUT_MODULE is required"
|
||||
[ -r "$DOXCAT" ] || skip "$DOXCAT is required"
|
||||
export GENESIS_SPEC DRACUT_MODULE DOXCAT
|
||||
}
|
||||
|
||||
run_installkernel()
|
||||
{
|
||||
local modules_root="$1"
|
||||
local instmods_log="$2"
|
||||
|
||||
kernel=5.14.0-test
|
||||
DRACUT_MODULES_ROOT="$modules_root"
|
||||
instmods()
|
||||
{
|
||||
printf '%s\n' "$1" >>"$instmods_log"
|
||||
}
|
||||
|
||||
source "$DRACUT_MODULE"
|
||||
installkernel
|
||||
}
|
||||
|
||||
run_doxcat_modprobe_preamble()
|
||||
{
|
||||
local preamble="$1"
|
||||
local modprobe_log="$2"
|
||||
|
||||
modprobe()
|
||||
{
|
||||
printf '%s\n' "$*" >>"$modprobe_log"
|
||||
}
|
||||
|
||||
eval "$preamble"
|
||||
}
|
||||
|
||||
run_doxcat_bootif_block()
|
||||
{
|
||||
local block="$1"
|
||||
|
||||
BOOTIF=01-aa-bb-cc-dd-ee-ff
|
||||
bootnic=
|
||||
log_label=test
|
||||
gripeiter=2
|
||||
|
||||
logger() { :; }
|
||||
sleep() { :; }
|
||||
ip()
|
||||
{
|
||||
printf '%s\n' "$*" >>"$IP_LOG"
|
||||
if [ "$*" = "link show" ]; then
|
||||
cat <<'EOF'
|
||||
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP mode DEFAULT group default qlen 1000
|
||||
link/ether 00:11:22:33:44:55 brd ff:ff:ff:ff:ff:ff
|
||||
3: ib0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65520 qdisc mq state UP mode DEFAULT group default qlen 256
|
||||
link/infiniband 00:bb:cc:dd:ee:ff brd 00:ff:ff:ff:ff:ff
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
|
||||
eval "$block"
|
||||
printf '%s\n' "$bootnic"
|
||||
}
|
||||
|
||||
@test "genesis build requires kernel module packages" {
|
||||
grep -Fxq 'BuildRequires: kernel-core' "$GENESIS_SPEC"
|
||||
grep -Fxq 'BuildRequires: kernel-modules' "$GENESIS_SPEC"
|
||||
grep -Fxq 'BuildRequires: kernel-modules-extra' "$GENESIS_SPEC"
|
||||
}
|
||||
|
||||
@test "dracut genesis module installs every module from modules.dep" {
|
||||
local modules_root="${BATS_TEST_TMPDIR}/modules"
|
||||
local modules_dep="${modules_root}/5.14.0-test/modules.dep"
|
||||
local instmods_log="${BATS_TEST_TMPDIR}/instmods.log"
|
||||
|
||||
mkdir -p "${modules_root}/5.14.0-test"
|
||||
cat >"$modules_dep" <<'EOF'
|
||||
kernel/drivers/infiniband/ulp/ipoib/ib_ipoib.ko.xz:
|
||||
kernel/drivers/net/ethernet/intel/e1000e/e1000e.ko.xz:
|
||||
EOF
|
||||
|
||||
run run_installkernel "$modules_root" "$instmods_log"
|
||||
[ "$status" -eq 0 ]
|
||||
grep -Fxq 'ib_ipoib' "$instmods_log"
|
||||
grep -Fxq 'e1000e' "$instmods_log"
|
||||
}
|
||||
|
||||
@test "doxcat loads IP over InfiniBand support during startup" {
|
||||
local preamble
|
||||
local modprobe_log="${BATS_TEST_TMPDIR}/modprobe.log"
|
||||
|
||||
preamble="$(extract_line_range "$DOXCAT" '^modprobe acpi_cpufreq' '^modprobe ib_ipoib$')" || return 1
|
||||
|
||||
run run_doxcat_modprobe_preamble "$preamble" "$modprobe_log"
|
||||
[ "$status" -eq 0 ]
|
||||
grep -Fxq 'ib_ipoib' "$modprobe_log"
|
||||
}
|
||||
|
||||
@test "doxcat falls back to InfiniBand BOOTIF lookup after Ethernet lookup misses" {
|
||||
local block
|
||||
|
||||
IP_LOG="${BATS_TEST_TMPDIR}/ip.log"
|
||||
export IP_LOG
|
||||
block="$(extract_shell_if_block "$DOXCAT" 'if [ ! -z "$BOOTIF" ]; then')" || return 1
|
||||
|
||||
run run_doxcat_bootif_block "$block"
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" = "ib0" ]
|
||||
[ "$(grep -c '^link show$' "$IP_LOG")" -eq 2 ]
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
load 'helpers/go_xcat'
|
||||
|
||||
setup()
|
||||
{
|
||||
go_xcat_require_source
|
||||
}
|
||||
|
||||
run_common_repository_case()
|
||||
{
|
||||
local case_dir="$1"
|
||||
local common_present="$2"
|
||||
shift 2
|
||||
|
||||
mkdir -p "$case_dir"
|
||||
export ADD_LOG="${case_dir}/add.log"
|
||||
export COMMON_PRESENT="$common_present"
|
||||
export DOWNLOAD_LOG="${case_dir}/download.log"
|
||||
export ID_LOG="${case_dir}/id.log"
|
||||
export TEST_TMP="$case_dir"
|
||||
|
||||
go_xcat_load_functions \
|
||||
add_xcat_dep_common_repo_yum_or_zypper \
|
||||
xcat_dep_common_repo_configured \
|
||||
refresh_xcat_dep_repository_ids
|
||||
|
||||
TMP_DIR="$TEST_TMP"
|
||||
GO_XCAT_DEFAULT_BASE_URL=https://repo.example.invalid
|
||||
GO_XCAT_DEP_REPOSITORY_IDS=(xcat-dep)
|
||||
|
||||
yum() { :; }
|
||||
|
||||
download_file()
|
||||
{
|
||||
printf '%s\n' "$1" >>"$DOWNLOAD_LOG"
|
||||
[[ ${COMMON_PRESENT:-0} == 1 ]] || return 1
|
||||
: >"$2"
|
||||
}
|
||||
|
||||
add_repo_by_url_yum_or_zypper()
|
||||
{
|
||||
printf '%s %s\n' "$1" "$2" >>"$ADD_LOG"
|
||||
}
|
||||
|
||||
xcat_dep_common_repo_configured()
|
||||
{
|
||||
[[ -s "$ADD_LOG" ]]
|
||||
}
|
||||
|
||||
( add_xcat_dep_common_repo_yum_or_zypper "$@" )
|
||||
refresh_xcat_dep_repository_ids
|
||||
printf '%s\n' "${GO_XCAT_DEP_REPOSITORY_IDS[*]}" >"$ID_LOG"
|
||||
}
|
||||
|
||||
run_template_generation()
|
||||
{
|
||||
local tmp_dir="$1"
|
||||
local repo_log="$2"
|
||||
|
||||
mkdir -p "$tmp_dir"
|
||||
export REPO_LOG="$repo_log"
|
||||
export TEST_TMP="$tmp_dir"
|
||||
|
||||
go_xcat_load_functions add_repo_by_url_yum_or_zypper
|
||||
|
||||
TMP_DIR="$TEST_TMP"
|
||||
GO_XCAT_DEFAULT_INSTALL_PATH=/install/xcat
|
||||
yum() { :; }
|
||||
add_repo_by_file() { cp "$1" "$REPO_LOG"; }
|
||||
|
||||
add_repo_by_url_yum_or_zypper \
|
||||
https://repo.example.invalid/xcat-dep/common xcat-dep-common optional
|
||||
}
|
||||
|
||||
@test "an available remote common repository is enabled" {
|
||||
local case_dir="${BATS_TEST_TMPDIR}/remote-present"
|
||||
|
||||
run run_common_repository_case "$case_dir" 1 "" latest
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$(read_file_or_empty "${case_dir}/download.log")" = "https://repo.example.invalid/yum/latest/xcat-dep/common/repodata/repomd.xml" ]
|
||||
[ "$(read_file_or_empty "${case_dir}/add.log")" = "https://repo.example.invalid/yum/latest/xcat-dep/common xcat-dep-common" ]
|
||||
[ "$(read_file_or_empty "${case_dir}/id.log")" = "xcat-dep xcat-dep-common" ]
|
||||
}
|
||||
|
||||
@test "a release without the remote common repository remains usable" {
|
||||
local case_dir="${BATS_TEST_TMPDIR}/remote-missing"
|
||||
|
||||
run run_common_repository_case "$case_dir" 0 "" 2.18
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$(read_file_or_empty "${case_dir}/add.log")" = "" ]
|
||||
[ "$(read_file_or_empty "${case_dir}/id.log")" = "xcat-dep" ]
|
||||
}
|
||||
|
||||
@test "a custom repository file does not guess an unrelated common repository" {
|
||||
local case_dir="${BATS_TEST_TMPDIR}/repo-file"
|
||||
|
||||
run run_common_repository_case "$case_dir" 1 https://repo.example.invalid/custom/xcat-dep.repo latest
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$(read_file_or_empty "${case_dir}/download.log")" = "" ]
|
||||
[ "$(read_file_or_empty "${case_dir}/add.log")" = "" ]
|
||||
}
|
||||
|
||||
@test "a local common repository is enabled beside the distribution repository" {
|
||||
local local_root="${BATS_TEST_TMPDIR}/local-repository"
|
||||
local case_dir="${BATS_TEST_TMPDIR}/local-present"
|
||||
mkdir -p "${local_root}/common/repodata"
|
||||
: >"${local_root}/common/repodata/repomd.xml"
|
||||
|
||||
run run_common_repository_case "$case_dir" 0 "$local_root" latest
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$(read_file_or_empty "${case_dir}/add.log")" = "${local_root}/common xcat-dep-common" ]
|
||||
}
|
||||
|
||||
@test "the optional common repository template tolerates outages and verifies metadata" {
|
||||
local template_log="${BATS_TEST_TMPDIR}/generated-common.repo"
|
||||
|
||||
run run_template_generation "$BATS_TEST_TMPDIR" "$template_log"
|
||||
[ "$status" -eq 0 ]
|
||||
grep -Fxq 'skip_if_unavailable=1' "$template_log"
|
||||
grep -Fxq 'repo_gpgcheck=1' "$template_log"
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
load 'helpers/go_xcat'
|
||||
|
||||
setup()
|
||||
{
|
||||
go_xcat_require_source
|
||||
export CALLS="${BATS_TEST_TMPDIR}/calls"
|
||||
export GO_XCAT_ARCH=x86_64
|
||||
export GO_XCAT_LINUX_DISTRO=rocky
|
||||
export GO_XCAT_LINUX_VERSION=10.2
|
||||
export EPEL_HAS=1
|
||||
export CRB_HAS=1
|
||||
export QUERY_FAIL=0
|
||||
export QUERY_WARNS=0
|
||||
export SOURCE_ONLY=0
|
||||
export ENTRY=check
|
||||
}
|
||||
|
||||
run_el_repo_check()
|
||||
{
|
||||
rm -f "$CALLS"
|
||||
|
||||
go_xcat_load_functions \
|
||||
repo_carries \
|
||||
el_epel_and_crb_check \
|
||||
install_packages_dnf \
|
||||
install_packages_yum
|
||||
|
||||
EL_EPEL_TEST_RPM=perl-Crypt-CBC
|
||||
EL_CRB_TEST_RPM=perl-IO-Tty
|
||||
|
||||
dnf()
|
||||
{
|
||||
echo "$*" >>"$CALLS"
|
||||
if [[ ${QUERY_FAIL:-0} == 1 ]]; then
|
||||
echo "Error: Failed to download metadata for repo 'epel'" >&2
|
||||
return 1
|
||||
fi
|
||||
[[ ${QUERY_WARNS:-0} == 1 ]] && echo "Warning: repository 'extras' metadata is stale" >&2
|
||||
|
||||
local has=0
|
||||
case "$*" in
|
||||
*perl-Crypt-CBC*) has="$EPEL_HAS" ;;
|
||||
*perl-IO-Tty*) has="$CRB_HAS" ;;
|
||||
esac
|
||||
|
||||
[[ ${SOURCE_ONLY:-0} == 1 && "$*" != *"--arch"* ]] && has=1
|
||||
case "$1" in
|
||||
repoquery) [[ $has == 1 ]] && { echo "${@: -1}"; echo "${@: -1}"; }; return 0 ;;
|
||||
list) [[ $has == 1 ]] && return 0; return 1 ;;
|
||||
esac
|
||||
return 0
|
||||
}
|
||||
|
||||
yum()
|
||||
{
|
||||
dnf "$@"
|
||||
}
|
||||
|
||||
case "${ENTRY:-check}" in
|
||||
dnf) install_packages_dnf -y xCAT ;;
|
||||
yum) install_packages_yum -y xCAT ;;
|
||||
*) el_epel_and_crb_check dnf ;;
|
||||
esac
|
||||
}
|
||||
|
||||
@test "EL9 with EPEL and CRB passes after probing binary repositories" {
|
||||
export GO_XCAT_LINUX_VERSION=9.5
|
||||
|
||||
run run_el_repo_check
|
||||
[ "$status" -eq 0 ]
|
||||
probes="$(joined_file_lines "$CALLS")"
|
||||
[[ "$probes" =~ perl-Crypt-CBC.*\;.*perl-IO-Tty ]]
|
||||
[[ "$probes" =~ ^repoquery\ ]]
|
||||
[[ "$probes" =~ --arch\ x86_64,noarch ]]
|
||||
}
|
||||
|
||||
@test "EL9 without EPEL stops and names the EL9 release package" {
|
||||
export GO_XCAT_LINUX_VERSION=9.5
|
||||
export EPEL_HAS=0
|
||||
|
||||
run run_el_repo_check
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" =~ epel-release-latest-9\.noarch ]]
|
||||
}
|
||||
|
||||
@test "EL10 with EPEL and CRB passes after probing both repositories" {
|
||||
run run_el_repo_check
|
||||
[ "$status" -eq 0 ]
|
||||
probes="$(joined_file_lines "$CALLS")"
|
||||
[[ "$probes" =~ perl-Crypt-CBC.*\;.*perl-IO-Tty ]]
|
||||
}
|
||||
|
||||
@test "EL10 without EPEL stops with the EL10 EPEL release package" {
|
||||
export EPEL_HAS=0
|
||||
|
||||
run run_el_repo_check
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" =~ requires\ EPEL\ repository ]]
|
||||
[[ "$output" =~ epel-release-latest-10\.noarch ]]
|
||||
}
|
||||
|
||||
@test "EL10 without CRB stops with current CRB guidance" {
|
||||
export GO_XCAT_LINUX_DISTRO=rhel
|
||||
export CRB_HAS=0
|
||||
|
||||
run run_el_repo_check
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" =~ requires\ CRB\ repository ]]
|
||||
[[ "$output" =~ "'dnf update epel-release' and then 'crb enable'" ]]
|
||||
[[ ! "$output" =~ gpgcheck=0|centos-crb|subscription-manager ]]
|
||||
}
|
||||
|
||||
@test "a source repository does not stand in for the binary one" {
|
||||
export EPEL_HAS=0
|
||||
export SOURCE_ONLY=1
|
||||
|
||||
run run_el_repo_check
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" =~ requires\ EPEL\ repository ]]
|
||||
}
|
||||
|
||||
@test "Oracle Linux 10 without CRB names its CodeReady Builder command" {
|
||||
export GO_XCAT_LINUX_DISTRO=ol
|
||||
export GO_XCAT_LINUX_VERSION=10.1
|
||||
export CRB_HAS=0
|
||||
|
||||
run run_el_repo_check
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" =~ dnf\ config-manager\ --enable\ ol10_codeready_builder ]]
|
||||
}
|
||||
|
||||
@test "a failed repository query stops with the package manager error" {
|
||||
export QUERY_FAIL=1
|
||||
|
||||
run run_el_repo_check
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" =~ Failed\ to\ download\ metadata ]]
|
||||
[[ ! "$output" =~ requires\ EPEL\ repository ]]
|
||||
}
|
||||
|
||||
@test "a warning on stderr does not stand in for a package" {
|
||||
export EPEL_HAS=0
|
||||
export QUERY_WARNS=1
|
||||
|
||||
run run_el_repo_check
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" =~ requires\ EPEL\ repository ]]
|
||||
}
|
||||
|
||||
@test "a warning beside a real match does not fail the check" {
|
||||
export QUERY_WARNS=1
|
||||
|
||||
run run_el_repo_check
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "CentOS Stream 10, which reports the major version alone, is checked" {
|
||||
export GO_XCAT_LINUX_DISTRO=centos
|
||||
export GO_XCAT_LINUX_VERSION=10
|
||||
export EPEL_HAS=0
|
||||
export CRB_HAS=0
|
||||
|
||||
run run_el_repo_check
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" =~ requires\ EPEL\ repository ]]
|
||||
}
|
||||
|
||||
@test "EL8 and Fedora are not checked" {
|
||||
export GO_XCAT_LINUX_VERSION=8.10
|
||||
export EPEL_HAS=0
|
||||
export CRB_HAS=0
|
||||
|
||||
run run_el_repo_check
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$(joined_file_lines "$CALLS")" = "" ]
|
||||
|
||||
export GO_XCAT_LINUX_DISTRO=fedora
|
||||
export GO_XCAT_LINUX_VERSION=42
|
||||
|
||||
run run_el_repo_check
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "dnf and yum installer paths run the check before installing" {
|
||||
for entry in dnf yum; do
|
||||
export ENTRY="$entry"
|
||||
export EPEL_HAS=0
|
||||
export CRB_HAS=1
|
||||
|
||||
run run_el_repo_check
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" =~ requires\ EPEL\ repository ]]
|
||||
probes="$(joined_file_lines "$CALLS")"
|
||||
[[ ! "$probes" =~ install ]]
|
||||
|
||||
export EPEL_HAS=1
|
||||
export CRB_HAS=1
|
||||
|
||||
run run_el_repo_check
|
||||
[ "$status" -eq 0 ]
|
||||
probes="$(joined_file_lines "$CALLS")"
|
||||
[[ "$probes" =~ perl-IO-Tty.*\;.*install\ initscripts.*\;.*install\ xCAT ]]
|
||||
done
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
go_xcat_default_source()
|
||||
{
|
||||
printf '%s\n' "${BATS_TEST_DIRNAME}/../../../xCAT-server/share/xcat/tools/go-xcat"
|
||||
}
|
||||
|
||||
go_xcat_require_source()
|
||||
{
|
||||
GO_XCAT_SOURCE="${XCAT_TEST_GO_XCAT:-$(go_xcat_default_source)}"
|
||||
export GO_XCAT_SOURCE
|
||||
[ -r "$GO_XCAT_SOURCE" ] || skip "$GO_XCAT_SOURCE is required"
|
||||
}
|
||||
|
||||
go_xcat_extract_functions()
|
||||
{
|
||||
local function_name
|
||||
for function_name in "$@"; do
|
||||
awk -v name="$function_name" '
|
||||
$0 == "function " name "()" { copy = 1 }
|
||||
copy { print }
|
||||
copy && /^}$/ { exit }
|
||||
' "$GO_XCAT_SOURCE"
|
||||
done
|
||||
}
|
||||
|
||||
go_xcat_load_functions()
|
||||
{
|
||||
local function_body function_name
|
||||
function_body="$(go_xcat_extract_functions "$@")" || return 1
|
||||
eval "$function_body"
|
||||
for function_name in "$@"; do
|
||||
declare -F "$function_name" >/dev/null || {
|
||||
printf 'missing %s\n' "$function_name" >&2
|
||||
return 70
|
||||
}
|
||||
done
|
||||
}
|
||||
|
||||
read_file_or_empty()
|
||||
{
|
||||
local path="$1"
|
||||
[ -f "$path" ] || return 0
|
||||
cat "$path"
|
||||
}
|
||||
|
||||
joined_file_lines()
|
||||
{
|
||||
local path="$1"
|
||||
local line separator=""
|
||||
[ -f "$path" ] || return 0
|
||||
while IFS= read -r line; do
|
||||
printf '%s%s' "$separator" "$line"
|
||||
separator=";"
|
||||
done <"$path"
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
repo_root()
|
||||
{
|
||||
printf '%s\n' "${BATS_TEST_DIRNAME}/../../.."
|
||||
}
|
||||
|
||||
repo_path()
|
||||
{
|
||||
printf '%s/%s\n' "$(repo_root)" "$1"
|
||||
}
|
||||
|
||||
require_repo_file()
|
||||
{
|
||||
local path
|
||||
path="$(repo_path "$1")"
|
||||
[ -r "$path" ] || skip "$path is required"
|
||||
printf '%s\n' "$path"
|
||||
}
|
||||
|
||||
read_file_or_empty()
|
||||
{
|
||||
local path="$1"
|
||||
[ -f "$path" ] || return 0
|
||||
cat "$path"
|
||||
}
|
||||
|
||||
extract_shell_function()
|
||||
{
|
||||
local file="$1"
|
||||
local name="$2"
|
||||
|
||||
awk -v name="$name" '
|
||||
BEGIN {
|
||||
signature = "^[[:space:]]*(function[[:space:]]+)?" name "([[:space:]]*\\(\\))?[[:space:]]*$"
|
||||
inline_signature = "^[[:space:]]*(function[[:space:]]+)?" name "([[:space:]]*\\(\\))?[[:space:]]*\\{"
|
||||
}
|
||||
$0 ~ signature || $0 ~ inline_signature {
|
||||
copy = 1
|
||||
}
|
||||
copy {
|
||||
print
|
||||
opened += gsub(/\{/, "{")
|
||||
closed += gsub(/\}/, "}")
|
||||
if (opened > 0 && opened == closed) {
|
||||
found = 1
|
||||
exit
|
||||
}
|
||||
}
|
||||
END {
|
||||
if (!found) {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
' "$file"
|
||||
}
|
||||
|
||||
extract_shell_if_block()
|
||||
{
|
||||
local file="$1"
|
||||
local start="$2"
|
||||
|
||||
awk -v start="$start" '
|
||||
index($0, start) {
|
||||
copy = 1
|
||||
}
|
||||
copy {
|
||||
print
|
||||
if ($0 ~ /^[[:space:]]*if[[:space:]\[]/) {
|
||||
depth++
|
||||
}
|
||||
line = $0
|
||||
while (line ~ /(^|[;[:space:]])fi([;[:space:]]|$)/) {
|
||||
depth--
|
||||
sub(/(^|[;[:space:]])fi([;[:space:]]|$)/, " ", line)
|
||||
}
|
||||
if (depth == 0) {
|
||||
found = 1
|
||||
exit
|
||||
}
|
||||
}
|
||||
END {
|
||||
if (!found) {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
' "$file"
|
||||
}
|
||||
|
||||
extract_line_range()
|
||||
{
|
||||
local file="$1"
|
||||
local start="$2"
|
||||
local end="$3"
|
||||
|
||||
awk -v start="$start" -v end="$end" '
|
||||
$0 ~ start {
|
||||
copy = 1
|
||||
}
|
||||
copy {
|
||||
print
|
||||
if ($0 ~ end) {
|
||||
found = 1
|
||||
exit
|
||||
}
|
||||
}
|
||||
END {
|
||||
if (!found) {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
' "$file"
|
||||
}
|
||||
|
||||
extract_first_matching_line()
|
||||
{
|
||||
local file="$1"
|
||||
local pattern="$2"
|
||||
|
||||
awk -v pattern="$pattern" '
|
||||
$0 ~ pattern {
|
||||
print
|
||||
found = 1
|
||||
exit
|
||||
}
|
||||
END {
|
||||
if (!found) {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
' "$file"
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
load 'helpers/shell_source'
|
||||
|
||||
setup()
|
||||
{
|
||||
SCRIPT_LIB="$(repo_path 'xCAT-server/share/xcat/install/scripts/scriptlib')"
|
||||
XCATLIB="$(repo_path 'xCAT/postscripts/xcatlib.sh')"
|
||||
[ -r "$SCRIPT_LIB" ] || skip "$SCRIPT_LIB is required"
|
||||
[ -r "$XCATLIB" ] || skip "$XCATLIB is required"
|
||||
export SCRIPT_LIB XCATLIB
|
||||
}
|
||||
|
||||
capture_install_scriptlib_wget()
|
||||
{
|
||||
local wget_log="$1"
|
||||
|
||||
wget()
|
||||
{
|
||||
printf '%s\n' "$*" >"$wget_log"
|
||||
return 0
|
||||
}
|
||||
|
||||
source "$SCRIPT_LIB"
|
||||
xcat_download_postscripts "192.0.2.10:80" "/install" "/xcatpost" "$wget_log"
|
||||
}
|
||||
|
||||
capture_xcatlib_wget()
|
||||
{
|
||||
local wget_log="$1"
|
||||
|
||||
xcatpost="${BATS_TEST_TMPDIR}/xcatpost"
|
||||
INSTALLDIR=/install
|
||||
|
||||
echolog() { :; }
|
||||
sleep() { :; }
|
||||
grep()
|
||||
{
|
||||
[ "${*: -1}" = "/tmp/wget.log" ] && return 1
|
||||
command grep "$@"
|
||||
}
|
||||
wget()
|
||||
{
|
||||
printf '%s\n' "$*" >"$wget_log"
|
||||
return 0
|
||||
}
|
||||
|
||||
source "$XCATLIB"
|
||||
download_postscripts 192.0.2.10:80
|
||||
}
|
||||
|
||||
assert_download_policy()
|
||||
{
|
||||
local args="$1"
|
||||
|
||||
[[ "$args" == *'--reject index.html*,post.xcat.ng,post.xcat.rhels10'* ]]
|
||||
[[ "$args" == *'--no-parent'* ]]
|
||||
[[ "$args" == *'postscripts/'* ]]
|
||||
[[ "$args" != *'<a href='* ]]
|
||||
}
|
||||
|
||||
@test "install scriptlib recursive download rejects dispatcher scripts" {
|
||||
local wget_log="${BATS_TEST_TMPDIR}/post-xcat-wget.log"
|
||||
|
||||
run capture_install_scriptlib_wget "$wget_log"
|
||||
[ "$status" -eq 0 ]
|
||||
assert_download_policy "$(read_file_or_empty "$wget_log")"
|
||||
}
|
||||
|
||||
@test "postscript xcatlib recursive download rejects dispatcher scripts" {
|
||||
local wget_log="${BATS_TEST_TMPDIR}/xcatdsklspost-wget.log"
|
||||
|
||||
run capture_xcatlib_wget "$wget_log"
|
||||
[ "$status" -eq 0 ]
|
||||
assert_download_policy "$(read_file_or_empty "$wget_log")"
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
load 'helpers/shell_source'
|
||||
|
||||
setup()
|
||||
{
|
||||
XCATLIB="$(repo_path 'xCAT/postscripts/xcatlib.sh')"
|
||||
[ -r "$XCATLIB" ] || skip "$XCATLIB is required"
|
||||
export XCATLIB
|
||||
}
|
||||
|
||||
run_restart_fallback()
|
||||
{
|
||||
ps()
|
||||
{
|
||||
cat <<'EOF'
|
||||
root 4321 0.0 0.0 15432 2048 ? Ss 10:00 0:00 /usr/sbin/sshd
|
||||
EOF
|
||||
}
|
||||
kill()
|
||||
{
|
||||
printf '%s\n' "$*" >>"$KILL_LOG"
|
||||
[ "$1" = "-0" ] && return 1
|
||||
return 0
|
||||
}
|
||||
sleep() { :; }
|
||||
sshd()
|
||||
{
|
||||
printf '%s\n' start >>"$SSHD_LOG"
|
||||
}
|
||||
|
||||
source "$XCATLIB"
|
||||
xcat_restart_sshd_after_failed_service_restart sshd
|
||||
}
|
||||
|
||||
run_wait_for_processes()
|
||||
{
|
||||
local rc
|
||||
|
||||
source "$XCATLIB"
|
||||
xcat_wait_for_processes_to_exit "$*" 3
|
||||
rc=$?
|
||||
printf '%s\n' "$rc"
|
||||
return 0
|
||||
}
|
||||
|
||||
@test "remoteshell restart fallback sends an uncatchable signal before starting sshd" {
|
||||
KILL_LOG="${BATS_TEST_TMPDIR}/kill.log"
|
||||
SSHD_LOG="${BATS_TEST_TMPDIR}/sshd.log"
|
||||
export KILL_LOG SSHD_LOG
|
||||
|
||||
run run_restart_fallback
|
||||
[ "$status" -eq 0 ]
|
||||
grep -Fxq -- '-9 4321' "$KILL_LOG"
|
||||
! grep -Eq '^9( |$)' "$KILL_LOG"
|
||||
[ "$(read_file_or_empty "$SSHD_LOG")" = "start" ]
|
||||
}
|
||||
|
||||
@test "remoteshell wait loop reports a still-running process and gives up" {
|
||||
local child
|
||||
|
||||
sleep 30 &
|
||||
child=$!
|
||||
|
||||
run run_wait_for_processes "$child"
|
||||
kill -KILL "$child" 2>/dev/null || true
|
||||
wait "$child" 2>/dev/null || true
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" = "1" ]
|
||||
}
|
||||
|
||||
@test "remoteshell wait loop returns as soon as killed processes are gone" {
|
||||
run run_wait_for_processes 999999
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" = "0" ]
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
load 'helpers/shell_source'
|
||||
|
||||
setup()
|
||||
{
|
||||
SCRIPT_LIB="$(repo_path 'xCAT-server/share/xcat/install/scripts/scriptlib')"
|
||||
[ -r "$SCRIPT_LIB" ] || skip "$SCRIPT_LIB is required"
|
||||
export SCRIPT_LIB
|
||||
}
|
||||
|
||||
@test "SLES 11 UEFI install changes the AutoYaST bootloader to elilo" {
|
||||
local cmdline="${BATS_TEST_TMPDIR}/cmdline"
|
||||
local profile="${BATS_TEST_TMPDIR}/modified.xml"
|
||||
|
||||
printf '%s\n' 'BOOT_IMAGE=/linux install=http://192.0.2.10/install/sles11/ppc64le' >"$cmdline"
|
||||
cat >"$profile" <<'EOF'
|
||||
<bootloader>
|
||||
<lba_support config:type="boolean">true</lba_support>
|
||||
<linear config:type="boolean">true</linear>
|
||||
<location>mbr</location>
|
||||
</bootloader>
|
||||
EOF
|
||||
|
||||
source "$SCRIPT_LIB"
|
||||
run set_sles11_uefi_bootloader "$cmdline" "$profile"
|
||||
[ "$status" -eq 0 ]
|
||||
grep -Fxq '<loader_type>elilo</loader_type>' "$profile"
|
||||
! grep -q '<location>mbr</location>' "$profile"
|
||||
! grep -q '<lba_support ' "$profile"
|
||||
! grep -q '<linear ' "$profile"
|
||||
}
|
||||
|
||||
@test "non-SLES 11 install media keeps the legacy bootloader template value" {
|
||||
local cmdline="${BATS_TEST_TMPDIR}/cmdline"
|
||||
local profile="${BATS_TEST_TMPDIR}/modified.xml"
|
||||
|
||||
printf '%s\n' 'BOOT_IMAGE=/linux install=http://192.0.2.10/install/sles15/ppc64le' >"$cmdline"
|
||||
printf '%s\n' '<location>mbr</location>' >"$profile"
|
||||
|
||||
source "$SCRIPT_LIB"
|
||||
run set_sles11_uefi_bootloader "$cmdline" "$profile"
|
||||
[ "$status" -eq 0 ]
|
||||
grep -Fxq '<location>mbr</location>' "$profile"
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
load 'helpers/shell_source'
|
||||
|
||||
setup()
|
||||
{
|
||||
ADD_SSH="$(repo_path 'xCAT-server/share/xcat/netboot/add-on/statelite/add_ssh')"
|
||||
[ -r "$ADD_SSH" ] || skip "$ADD_SSH is required"
|
||||
export ADD_SSH
|
||||
}
|
||||
|
||||
run_sshd_config_block()
|
||||
{
|
||||
local root="$1"
|
||||
local block
|
||||
|
||||
block="$(extract_shell_if_block "$ADD_SSH" 'if [ -r $ROOTDIR/etc/ssh/sshd_config ]')" || return 1
|
||||
ROOTDIR="$root"
|
||||
eval "$block"
|
||||
}
|
||||
|
||||
@test "statelite add_ssh writes sshd settings below systemd's open-file limit" {
|
||||
local root="${BATS_TEST_TMPDIR}/rootimg"
|
||||
local sshd_config="${root}/etc/ssh/sshd_config"
|
||||
|
||||
mkdir -p "${root}/etc/ssh"
|
||||
cat >"$sshd_config" <<'EOF'
|
||||
X11Forwarding no
|
||||
KeyRegenerationInterval 3600
|
||||
MaxStartups 1024
|
||||
EOF
|
||||
|
||||
run run_sshd_config_block "$root"
|
||||
[ "$status" -eq 0 ]
|
||||
grep -Fxq 'X11Forwarding yes' "$sshd_config"
|
||||
grep -Fxq 'KeyRegenerationInterval 0' "$sshd_config"
|
||||
grep -Fxq '#MaxStartups 1024' "$sshd_config"
|
||||
grep -Fxq 'MaxStartups 100:30:200' "$sshd_config"
|
||||
! grep -Fxq 'MaxStartups 1024' "$sshd_config"
|
||||
}
|
||||
@@ -46,6 +46,11 @@ so putting a test in `integration/` does not cost it CI coverage. What differs i
|
||||
each suite is allowed to depend on, and that unit tests also run standalone from a
|
||||
bare checkout with no xCAT at all.
|
||||
|
||||
Shell-script unit tests belong in [`../autotest/bats`](../autotest/bats/README.md)
|
||||
and run with BATS. Do not add Perl `.t` tests that grep shell source when the
|
||||
behavior can be exercised by sourcing a shell library or script and shadowing the
|
||||
external commands it calls.
|
||||
|
||||
The distinction matters because a test that needs an absent environment does not fail
|
||||
-- it calls `plan skip_all` and reports as skipped. A handful of those in a suite of
|
||||
several hundred assertions is easy to stop reading. Keeping the two kinds in separate
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use File::Spec;
|
||||
use FindBin;
|
||||
use Test::More;
|
||||
|
||||
my $repo_root = File::Spec->rel2abs(File::Spec->catdir($FindBin::Bin, '..', '..'));
|
||||
|
||||
my $spec = read_file('xCAT-genesis-builder/xCAT-genesis-base.spec');
|
||||
like($spec, qr/^BuildRequires:\s+kernel-core$/m, 'genesis build installs the kernel core');
|
||||
like($spec, qr/^BuildRequires:\s+kernel-modules$/m, 'genesis build installs the standard kernel modules');
|
||||
like($spec, qr/^BuildRequires:\s+kernel-modules-extra$/m, 'genesis build installs the extra kernel modules');
|
||||
|
||||
my $dracut_module = read_file('xCAT-genesis-builder/dracut_105/el/module-setup.sh');
|
||||
like(
|
||||
$dracut_module,
|
||||
qr/installkernel\(\) \{.*?modules_dep=.*?while IFS= read -r modfile;.*?instmods "\$modname".*?done < "\$modules_dep"/s,
|
||||
'genesis dracut module installs every module available to the build'
|
||||
);
|
||||
|
||||
my $doxcat = read_file('xCAT-genesis-scripts/usr/bin/doxcat');
|
||||
like($doxcat, qr/^modprobe ib_ipoib$/m, 'genesis loads the IP over InfiniBand module');
|
||||
like(
|
||||
$doxcat,
|
||||
qr/if \[ -z "\$bootnic" \]; then\s+bootnic=`ip link show\|grep -B1 infiniband/s,
|
||||
'genesis checks InfiniBand addresses only after the Ethernet lookup misses'
|
||||
);
|
||||
|
||||
done_testing();
|
||||
|
||||
sub read_file {
|
||||
my ($file) = @_;
|
||||
my $path = File::Spec->catfile($repo_root, split m{/}, $file);
|
||||
open(my $fh, '<', $path) or die "open $path: $!";
|
||||
my $contents = do { local $/; <$fh> };
|
||||
close($fh) or die "close $path: $!";
|
||||
return $contents;
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use File::Path qw(make_path);
|
||||
use File::Temp qw(tempdir);
|
||||
use FindBin;
|
||||
use Test::More;
|
||||
|
||||
my $go_xcat = "$FindBin::Bin/../../xCAT-server/share/xcat/tools/go-xcat";
|
||||
my $tmpdir = tempdir(CLEANUP => 1);
|
||||
my $driver = "$tmpdir/driver.sh";
|
||||
|
||||
open(my $driver_fh, '>', $driver) or die "open $driver: $!";
|
||||
print {$driver_fh} <<'DRIVER';
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
function_body=$(
|
||||
for function_name in \
|
||||
add_xcat_dep_common_repo_yum_or_zypper \
|
||||
xcat_dep_common_repo_configured \
|
||||
refresh_xcat_dep_repository_ids
|
||||
do
|
||||
awk -v name="$function_name" '
|
||||
$0 == "function " name "()" { copy = 1 }
|
||||
copy { print }
|
||||
copy && /^}$/ { exit }
|
||||
' "$GO_XCAT_SOURCE"
|
||||
done
|
||||
)
|
||||
eval "$function_body"
|
||||
|
||||
TMP_DIR=$TEST_TMP
|
||||
GO_XCAT_DEFAULT_BASE_URL=https://repo.example.invalid
|
||||
GO_XCAT_DEP_REPOSITORY_IDS=(xcat-dep)
|
||||
|
||||
yum() { :; }
|
||||
|
||||
download_file() {
|
||||
printf '%s\n' "$1" >>"$DOWNLOAD_LOG"
|
||||
[[ ${COMMON_PRESENT:-0} == 1 ]] || return 1
|
||||
: >"$2"
|
||||
}
|
||||
|
||||
add_repo_by_url_yum_or_zypper() {
|
||||
printf '%s %s\n' "$1" "$2" >>"$ADD_LOG"
|
||||
}
|
||||
|
||||
xcat_dep_common_repo_configured() { [[ -s "$ADD_LOG" ]]; }
|
||||
( add_xcat_dep_common_repo_yum_or_zypper "$@" )
|
||||
refresh_xcat_dep_repository_ids
|
||||
printf '%s\n' "${GO_XCAT_DEP_REPOSITORY_IDS[*]}" >"$ID_LOG"
|
||||
DRIVER
|
||||
close($driver_fh) or die "close $driver: $!";
|
||||
chmod(0755, $driver) or die "chmod $driver: $!";
|
||||
|
||||
sub run_case {
|
||||
my ($name, $present, @arguments) = @_;
|
||||
my $case_dir = "$tmpdir/$name";
|
||||
make_path($case_dir);
|
||||
local %ENV = (
|
||||
%ENV,
|
||||
ADD_LOG => "$case_dir/add.log",
|
||||
COMMON_PRESENT => $present,
|
||||
DOWNLOAD_LOG => "$case_dir/download.log",
|
||||
GO_XCAT_SOURCE => $go_xcat,
|
||||
ID_LOG => "$case_dir/id.log",
|
||||
TEST_TMP => $case_dir,
|
||||
);
|
||||
my $status = system('bash', $driver, @arguments);
|
||||
return ($status >> 8, $case_dir);
|
||||
}
|
||||
|
||||
sub read_file {
|
||||
my ($path) = @_;
|
||||
return '' unless -f $path;
|
||||
open(my $fh, '<', $path) or die "open $path: $!";
|
||||
my $content = do { local $/; <$fh> };
|
||||
close($fh) or die "close $path: $!";
|
||||
return $content;
|
||||
}
|
||||
|
||||
my ($status, $case_dir) = run_case('remote-present', 1, '', 'latest');
|
||||
is($status, 0, 'an available common repository is accepted');
|
||||
is(
|
||||
read_file("$case_dir/download.log"),
|
||||
"https://repo.example.invalid/yum/latest/xcat-dep/common/repodata/repomd.xml\n",
|
||||
'the default repository is probed before it is enabled',
|
||||
);
|
||||
is(
|
||||
read_file("$case_dir/add.log"),
|
||||
"https://repo.example.invalid/yum/latest/xcat-dep/common xcat-dep-common\n",
|
||||
'the common repository uses its own repository ID',
|
||||
);
|
||||
is(read_file("$case_dir/id.log"), "xcat-dep xcat-dep-common\n",
|
||||
'common packages are included in repository listings');
|
||||
|
||||
($status, $case_dir) = run_case('remote-missing', 0, '', '2.18');
|
||||
is($status, 0, 'a release without the common repository remains usable');
|
||||
is(read_file("$case_dir/add.log"), '', 'a missing common repository is not enabled');
|
||||
is(read_file("$case_dir/id.log"), "xcat-dep\n",
|
||||
'legacy package listings remain unchanged when common is absent');
|
||||
|
||||
($status, $case_dir) = run_case(
|
||||
'repo-file', 1, 'https://repo.example.invalid/custom/xcat-dep.repo', 'latest'
|
||||
);
|
||||
is($status, 0, 'a custom repository file remains supported');
|
||||
is(read_file("$case_dir/download.log"), '',
|
||||
'the common URL is not guessed from a custom repository file');
|
||||
is(read_file("$case_dir/add.log"), '',
|
||||
'a custom repository file does not enable an unrelated repository');
|
||||
|
||||
my $local_root = "$tmpdir/local-repository";
|
||||
make_path("$local_root/common/repodata");
|
||||
open(my $repomd_fh, '>', "$local_root/common/repodata/repomd.xml") or die $!;
|
||||
close($repomd_fh) or die $!;
|
||||
($status, $case_dir) = run_case('local-present', 0, $local_root, 'latest');
|
||||
is($status, 0, 'a local common repository is accepted');
|
||||
is(
|
||||
read_file("$case_dir/add.log"),
|
||||
"$local_root/common xcat-dep-common\n",
|
||||
'the local common repository is enabled beside the distribution repository',
|
||||
);
|
||||
|
||||
my $template_driver = "$tmpdir/template-driver.sh";
|
||||
open(my $template_fh, '>', $template_driver) or die "open $template_driver: $!";
|
||||
print {$template_fh} <<'DRIVER';
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
function_body=$(
|
||||
awk '
|
||||
/^function add_repo_by_url_yum_or_zypper\(\)/ { copy = 1 }
|
||||
copy { print }
|
||||
copy && /^}$/ { exit }
|
||||
' "$GO_XCAT_SOURCE"
|
||||
)
|
||||
eval "$function_body"
|
||||
|
||||
TMP_DIR=$TEST_TMP
|
||||
GO_XCAT_DEFAULT_INSTALL_PATH=/install/xcat
|
||||
yum() { :; }
|
||||
add_repo_by_file() { cp "$1" "$REPO_LOG"; }
|
||||
add_repo_by_url_yum_or_zypper \
|
||||
https://repo.example.invalid/xcat-dep/common xcat-dep-common optional
|
||||
DRIVER
|
||||
close($template_fh) or die "close $template_driver: $!";
|
||||
chmod(0755, $template_driver) or die "chmod $template_driver: $!";
|
||||
|
||||
my $template_log = "$tmpdir/generated-common.repo";
|
||||
local %ENV = (
|
||||
%ENV,
|
||||
GO_XCAT_SOURCE => $go_xcat,
|
||||
REPO_LOG => $template_log,
|
||||
TEST_TMP => $tmpdir,
|
||||
);
|
||||
$status = system('bash', $template_driver);
|
||||
is($status >> 8, 0, 'go-xcat can generate the optional common repository');
|
||||
like(read_file($template_log), qr/^skip_if_unavailable=1$/m,
|
||||
'the generated common repository stays optional during outages');
|
||||
like(read_file($template_log), qr/^repo_gpgcheck=1$/m,
|
||||
'the generated common repository verifies signed metadata');
|
||||
|
||||
done_testing();
|
||||
@@ -1,161 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use File::Temp qw(tempdir);
|
||||
use FindBin;
|
||||
use Test::More;
|
||||
|
||||
# go-xcat checked for the EPEL and CRB repositories on EL9 only, and only when the version
|
||||
# carried a minor number, so CentOS Stream was never checked. On EL10 a management node without
|
||||
# them failed inside dnf install with a dependency error instead of the message that names the
|
||||
# missing repository, and the CRB message proposed a CentOS Stream repository file with
|
||||
# signature checks disabled. The probe used dnf list, which an installed copy of the probe
|
||||
# package satisfies, and which reports a failed query as a missing repository. The check
|
||||
# functions are taken from the shipped script and run against a dnf stand-in that answers for
|
||||
# each probe and records what was asked.
|
||||
|
||||
my $go_xcat = "$FindBin::Bin/../../xCAT-server/share/xcat/tools/go-xcat";
|
||||
plan skip_all => 'go-xcat not found' unless -r $go_xcat;
|
||||
|
||||
my $tmpdir = tempdir( CLEANUP => 1 );
|
||||
my $driver = "$tmpdir/driver.sh";
|
||||
my $calls = "$tmpdir/calls";
|
||||
open( my $fh, '>', $driver ) or die "open $driver: $!";
|
||||
print {$fh} <<'DRIVER';
|
||||
#!/bin/bash
|
||||
set -uo pipefail
|
||||
eval "$(awk '
|
||||
/^function (repo_carries|el9?_epel_and_crb_check|install_packages_(dnf|yum))\(\)/ { copy = 1 }
|
||||
copy { print }
|
||||
copy && /^}$/ { copy = 0 }
|
||||
' "$GO_XCAT_SOURCE")"
|
||||
EL9_EPEL_TEST_RPM="perl-Crypt-CBC"; EL_EPEL_TEST_RPM="perl-Crypt-CBC"
|
||||
EL9_CRB_TEST_RPM="perl-IO-Tty"; EL_CRB_TEST_RPM="perl-IO-Tty"
|
||||
# repoquery prints the name when an enabled repository carries the package and nothing
|
||||
# otherwise, and fails with a message when the repositories cannot be read. list -q exits 1
|
||||
# when neither a repository nor the installed set has the package.
|
||||
dnf() {
|
||||
echo "$*" >> "$CALLS"
|
||||
if [[ ${QUERY_FAIL:-0} == 1 ]]; then
|
||||
echo "Error: Failed to download metadata for repo 'epel'" >&2
|
||||
return 1
|
||||
fi
|
||||
[[ ${QUERY_WARNS:-0} == 1 ]] && echo "Warning: repository 'extras' metadata is stale" >&2
|
||||
local has=0
|
||||
case "$*" in
|
||||
*perl-Crypt-CBC*) has="$EPEL_HAS" ;;
|
||||
*perl-IO-Tty*) has="$CRB_HAS" ;;
|
||||
esac
|
||||
# A source repository answers for the name unless the query is limited to binary architectures.
|
||||
[[ ${SOURCE_ONLY:-0} == 1 && "$*" != *"--arch"* ]] && has=1
|
||||
case "$1" in
|
||||
repoquery) [[ $has == 1 ]] && { echo "${@: -1}"; echo "${@: -1}"; }; return 0 ;;
|
||||
list) [[ $has == 1 ]] && return 0; return 1 ;;
|
||||
esac
|
||||
return 0
|
||||
}
|
||||
yum() { dnf "$@"; }
|
||||
# ENTRY=dnf or yum runs the installer function go-xcat dispatches to, which owns the check.
|
||||
case "${ENTRY:-check}" in
|
||||
dnf) install_packages_dnf -y xCAT ;;
|
||||
yum) install_packages_yum -y xCAT ;;
|
||||
*) if declare -F el_epel_and_crb_check >/dev/null; then el_epel_and_crb_check dnf; else el9_epel_and_crb_check dnf; fi ;;
|
||||
esac
|
||||
DRIVER
|
||||
close($fh);
|
||||
|
||||
# Runs the check as go-xcat would on a host of this distro and version. Returns the exit status,
|
||||
# the output, and the probes the dnf stand-in saw.
|
||||
sub check {
|
||||
my (%host) = @_;
|
||||
unlink $calls;
|
||||
local $ENV{GO_XCAT_SOURCE} = $go_xcat;
|
||||
local $ENV{CALLS} = $calls;
|
||||
local $ENV{GO_XCAT_LINUX_DISTRO} = $host{distro} || 'rocky';
|
||||
local $ENV{GO_XCAT_LINUX_VERSION} = $host{version};
|
||||
local $ENV{GO_XCAT_ARCH} = 'x86_64';
|
||||
local $ENV{EPEL_HAS} = $host{epel} ? 1 : 0;
|
||||
local $ENV{CRB_HAS} = $host{crb} ? 1 : 0;
|
||||
local $ENV{QUERY_FAIL} = $host{query_fail} ? 1 : 0;
|
||||
local $ENV{QUERY_WARNS} = $host{query_warns} ? 1 : 0;
|
||||
local $ENV{SOURCE_ONLY} = $host{source_only} ? 1 : 0;
|
||||
local $ENV{ENTRY} = $host{entry} || 'check';
|
||||
my $out = `bash '$driver' 2>&1`;
|
||||
my $rc = $? >> 8;
|
||||
my @probes;
|
||||
if ( open( my $cfh, '<', $calls ) ) { chomp( @probes = <$cfh> ); close($cfh); }
|
||||
return ( $rc, $out, join( ';', @probes ) );
|
||||
}
|
||||
|
||||
my ( $rc, $out, $probes );
|
||||
|
||||
( $rc, $out, $probes ) = check( version => '9.5', epel => 1, crb => 1 );
|
||||
is( $rc, 0, 'EL9 with EPEL and CRB passes' );
|
||||
like( $probes, qr/perl-Crypt-CBC.*;.*perl-IO-Tty/, '... after probing both repositories' );
|
||||
like( $probes, qr/^repoquery /, '... through repoquery, which an installed copy does not satisfy' );
|
||||
like( $probes, qr/--arch x86_64,noarch/, '... limited to the binary architectures' );
|
||||
|
||||
( $rc, $out, $probes ) = check( version => '9.5', epel => 0, crb => 1 );
|
||||
is( $rc, 1, 'EL9 without EPEL stops' );
|
||||
like( $out, qr/epel-release-latest-9\.noarch/, '... and names the EL9 EPEL release package' );
|
||||
|
||||
( $rc, $out, $probes ) = check( version => '10.2', epel => 1, crb => 1 );
|
||||
is( $rc, 0, 'EL10 with EPEL and CRB passes' );
|
||||
like( $probes, qr/perl-Crypt-CBC.*;.*perl-IO-Tty/, '... after probing both repositories' );
|
||||
|
||||
( $rc, $out, $probes ) = check( version => '10.2', epel => 0, crb => 1 );
|
||||
is( $rc, 1, 'EL10 without EPEL stops' );
|
||||
like( $out, qr/requires EPEL repository/, '... and names the missing repository' );
|
||||
like( $out, qr/epel-release-latest-10\.noarch/, '... and the EL10 EPEL release package' );
|
||||
|
||||
( $rc, $out, $probes ) = check( distro => 'rhel', version => '10.2', epel => 1, crb => 0 );
|
||||
is( $rc, 1, 'EL10 without CRB stops' );
|
||||
like( $out, qr/requires CRB repository/, '... and names the missing repository' );
|
||||
like( $out, qr/'dnf update epel-release' and then 'crb enable'/, '... with a current crb helper, which covers RHEL under RHSM and RHUI' );
|
||||
unlike( $out, qr/gpgcheck=0|centos-crb|subscription-manager/, '... and no repository file or subscription-only command' );
|
||||
|
||||
( $rc, $out, $probes ) = check( version => '10.2', epel => 0, crb => 1, source_only => 1 );
|
||||
is( $rc, 1, 'a source repository does not stand in for the binary one' );
|
||||
like( $out, qr/requires EPEL repository/, '... so the missing repository is still reported' );
|
||||
|
||||
( $rc, $out, $probes ) = check( distro => 'ol', version => '10.1', epel => 1, crb => 0 );
|
||||
is( $rc, 1, 'Oracle Linux 10 without CRB stops' );
|
||||
like( $out, qr/dnf config-manager --enable ol10_codeready_builder/, '... with the command that enables its CodeReady Builder' );
|
||||
|
||||
( $rc, $out, $probes ) = check( version => '10.2', epel => 1, crb => 1, query_fail => 1 );
|
||||
is( $rc, 1, 'a failed repository query stops' );
|
||||
like( $out, qr/Failed to download metadata/, '... with the package manager error' );
|
||||
unlike( $out, qr/requires EPEL repository/, '... and not as a missing repository' );
|
||||
|
||||
( $rc, $out, $probes ) = check( version => '10.2', epel => 0, crb => 1, query_warns => 1 );
|
||||
is( $rc, 1, 'a warning on stderr does not stand in for a package' );
|
||||
like( $out, qr/requires EPEL repository/, '... so the missing repository is still reported' );
|
||||
|
||||
( $rc, $out, $probes ) = check( version => '10.2', epel => 1, crb => 1, query_warns => 1 );
|
||||
is( $rc, 0, 'a warning beside a real match does not fail the check' );
|
||||
|
||||
( $rc, $out, $probes ) = check( distro => 'centos', version => '10', epel => 0, crb => 0 );
|
||||
is( $rc, 1, 'CentOS Stream 10, which reports the major version alone, is checked' );
|
||||
like( $out, qr/requires EPEL repository/, '... and told about EPEL' );
|
||||
|
||||
( $rc, $out, $probes ) = check( version => '8.10', epel => 0, crb => 0 );
|
||||
is( $rc, 0, 'EL8 is not checked' );
|
||||
is( $probes, '', '... and nothing is probed' );
|
||||
|
||||
( $rc, $out, $probes ) = check( distro => 'fedora', version => '42', epel => 0, crb => 0 );
|
||||
is( $rc, 0, 'Fedora is not checked' );
|
||||
|
||||
# The installer functions go-xcat dispatches to run the check before they install anything.
|
||||
foreach my $entry (qw(dnf yum)) {
|
||||
( $rc, $out, $probes ) = check( entry => $entry, version => '10.2', epel => 0, crb => 1 );
|
||||
is( $rc, 1, "install_packages_$entry on EL10 without EPEL stops" );
|
||||
like( $out, qr/requires EPEL repository/, '... with the EPEL message' );
|
||||
unlike( $probes, qr/install/, '... before anything is installed' );
|
||||
|
||||
( $rc, $out, $probes ) = check( entry => $entry, version => '10.2', epel => 1, crb => 1 );
|
||||
is( $rc, 0, "install_packages_$entry on EL10 with EPEL and CRB installs" );
|
||||
like( $probes, qr/perl-IO-Tty.*;.*install initscripts.*;.*install xCAT/, '... after the check passed' );
|
||||
}
|
||||
|
||||
done_testing();
|
||||
@@ -1,48 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use FindBin;
|
||||
use File::Spec;
|
||||
use Test::More;
|
||||
|
||||
my $repo_root = File::Spec->catdir( $FindBin::Bin, '..', '..' );
|
||||
my %scripts = (
|
||||
'legacy install post.xcat' => File::Spec->catfile(
|
||||
$repo_root,
|
||||
'xCAT-server/share/xcat/install/scripts/post.xcat'
|
||||
),
|
||||
'legacy netboot xcatdsklspost' => File::Spec->catfile(
|
||||
$repo_root,
|
||||
'xCAT/postscripts/xcatdsklspost'
|
||||
),
|
||||
);
|
||||
|
||||
foreach my $path ( values %scripts ) {
|
||||
plan skip_all => "$path not found" unless -r $path;
|
||||
}
|
||||
|
||||
foreach my $name ( sort keys %scripts ) {
|
||||
my $path = $scripts{$name};
|
||||
open( my $fh, '<', $path ) or die "Unable to read $path: $!";
|
||||
my $script = do { local $/; <$fh> };
|
||||
close($fh);
|
||||
|
||||
like(
|
||||
$script,
|
||||
qr/--reject\s+"index\.html\*,post\.xcat\.ng,post\.xcat\.rhels10"/,
|
||||
"$name recursive wget ignores dispatcher scripts that contain literal HTML-link regexes"
|
||||
);
|
||||
like(
|
||||
$script,
|
||||
qr/Newer\s+(?:#\s+)?wget\s+parses\s+HTML-looking\s+regex\s+strings/s,
|
||||
"$name download policy documents why dispatcher scripts are excluded"
|
||||
);
|
||||
unlike(
|
||||
$script,
|
||||
qr/<a\s+href=/i,
|
||||
"$name comments do not contain HTML links that wget can recurse into"
|
||||
);
|
||||
}
|
||||
|
||||
done_testing();
|
||||
@@ -1,26 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use File::Spec;
|
||||
use FindBin;
|
||||
use Test::More;
|
||||
|
||||
my $script = File::Spec->catfile( $FindBin::Bin, '..', '..',
|
||||
'xCAT', 'postscripts', 'remoteshell' );
|
||||
plan skip_all => 'remoteshell not found' unless -r $script;
|
||||
|
||||
open( my $fh, '<', $script ) or die "Unable to read $script: $!";
|
||||
my $source = do { local $/; <$fh> };
|
||||
close($fh);
|
||||
|
||||
# A kill without the hyphen reads the signal number as one more process id, so
|
||||
# the target gets the default signal, which a process can catch, and the
|
||||
# process with that id is signalled as well.
|
||||
my @bare = ( $source =~ /^[^#\n]*\bkill\s+\d/gm );
|
||||
is( scalar(@bare), 0, 'no kill gives the signal number without a hyphen' );
|
||||
|
||||
like( $source, qr/kill -9 \$PIDLIST/,
|
||||
'the ssh daemon gets the signal that a process cannot catch' );
|
||||
|
||||
done_testing();
|
||||
@@ -1,62 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use File::Spec;
|
||||
use FindBin;
|
||||
use Test::More;
|
||||
|
||||
my $script = File::Spec->catfile( $FindBin::Bin, '..', '..',
|
||||
'xCAT', 'postscripts', 'remoteshell' );
|
||||
plan skip_all => 'remoteshell not found' unless -r $script;
|
||||
plan skip_all => 'no bash' unless -x '/bin/bash';
|
||||
|
||||
open( my $fh, '<', $script ) or die "Unable to read $script: $!";
|
||||
my $source = do { local $/; <$fh> };
|
||||
close($fh);
|
||||
|
||||
my ($loop) = $source =~ /(waited=0\n.*?\n done)/s;
|
||||
ok( defined($loop), 'the wait loop was found in the postscript' );
|
||||
|
||||
# Run the loop of the postscript against real processes, with a shorter bound
|
||||
# so that the test does not spend the whole timeout of the postscript.
|
||||
sub waits_for {
|
||||
my (@pids) = @_;
|
||||
( my $body = $loop ) =~ s/\$waited -lt 10/\$waited -lt 3/;
|
||||
my $list = join( ' ', @pids );
|
||||
my $out = `/bin/bash -c 'PIDLIST="$list"\n$body\necho \$alive' 2>/dev/null`;
|
||||
chomp $out;
|
||||
return $out;
|
||||
}
|
||||
|
||||
# A process that is still running must be reported as alive, and the loop must
|
||||
# give up rather than run for ever.
|
||||
my $child = fork();
|
||||
if ( !defined $child ) { plan skip_all => 'cannot fork' }
|
||||
if ( $child == 0 ) { exec( 'sleep', '30' ); exit 1 }
|
||||
my $start = time;
|
||||
is( waits_for($child), '1', 'a process that is still running is reported alive' );
|
||||
cmp_ok( time - $start, '<', 10, 'the loop gives up instead of waiting for ever' );
|
||||
kill 'KILL', $child;
|
||||
waitpid( $child, 0 );
|
||||
|
||||
# A process that has ended must be reported as gone, without waiting.
|
||||
my $gone = fork();
|
||||
if ( $gone == 0 ) { exit 0 }
|
||||
waitpid( $gone, 0 );
|
||||
$start = time;
|
||||
is( waits_for($gone), '0', 'a process that has ended is reported gone' );
|
||||
cmp_ok( time - $start, '<', 3, 'no time is spent once the process is gone' );
|
||||
|
||||
# The bound of the postscript itself, and the shape of the test.
|
||||
like( $source, qr/while \[ \$waited -lt 10 \]/, 'the postscript waits at most ten seconds' );
|
||||
like( $source, qr/kill -0 \$pid/, 'the check for a running process sends no signal' );
|
||||
like( $source, qr/kill -9 \$PIDLIST/, 'the daemon still gets the signal it cannot catch' );
|
||||
|
||||
# The wait has to happen before the new daemon starts.
|
||||
my ($block) = $source =~ /(PIDLIST=.*?\/usr\/sbin\/sshd)/s;
|
||||
ok( defined($block), 'the fallback block was found' );
|
||||
cmp_ok( index( $block, 'waited=0' ), '<', index( $block, '/usr/sbin/sshd' ),
|
||||
'the wait comes before the new daemon starts' );
|
||||
|
||||
done_testing();
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More;
|
||||
|
||||
my $pre_sles_path = defined $ENV{XCATROOT} ? "$ENV{XCATROOT}/share/xcat/install/scripts/pre.sles" : '';
|
||||
$pre_sles_path = "xCAT-server/share/xcat/install/scripts/pre.sles"
|
||||
unless -f $pre_sles_path;
|
||||
|
||||
plan skip_all => "pre.sles not found" unless -f $pre_sles_path;
|
||||
|
||||
my $src = do { local $/; open my $fh, '<', $pre_sles_path or die $!; <$fh> };
|
||||
|
||||
like($src, qr/sub set_sles11_uefi_bootloader\b|set_sles11_uefi_bootloader\(\)/, 'SLES UEFI bootloader helper exists');
|
||||
like($src, qr/install=\.\*sles11/, 'SLES 11 UEFI bootloader change is scoped to SLES 11 install media');
|
||||
like($src, qr/<loader_type>elilo<\/loader_type>/, 'SLES 11 UEFI install selects elilo');
|
||||
like($src, qr/<location>mbr<\/location>/, 'legacy MBR template value is replaced at install time');
|
||||
like($src, qr/if \[ -d \/sys\/firmware\/efi \]; then\s+sed .*?set_sles11_uefi_bootloader/s, 'UEFI default partitioning applies bootloader helper');
|
||||
|
||||
done_testing();
|
||||
@@ -1,17 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
use Test::More;
|
||||
|
||||
my $script_path = defined $ENV{XCATROOT} ? "$ENV{XCATROOT}/share/xcat/netboot/add-on/statelite/add_ssh" : '';
|
||||
$script_path = "xCAT-server/share/xcat/netboot/add-on/statelite/add_ssh"
|
||||
unless -f $script_path;
|
||||
|
||||
plan skip_all => "add_ssh not found" unless -f $script_path;
|
||||
|
||||
my $script = do { local $/; open my $fh, '<', $script_path or die $!; <$fh> };
|
||||
|
||||
like($script, qr/MaxStartups 100:30:200/, 'add_ssh caps MaxStartups below systemd soft nofile limit');
|
||||
unlike($script, qr/echo\s+"MaxStartups 1024"/, 'add_ssh does not force MaxStartups 1024');
|
||||
|
||||
done_testing();
|
||||
@@ -631,20 +631,6 @@ fi
|
||||
#if the service restart with "service/systemctl" failed
|
||||
#try to kill the process and start
|
||||
if [ "$?" != "0" ];then
|
||||
PIDLIST=`ps aux | grep -v grep | grep "/usr/sbin/sshd"|awk -F" " '{print $2}'|xargs`
|
||||
if [ -n "$PIDLIST" ]; then
|
||||
kill -9 $PIDLIST
|
||||
waited=0
|
||||
while [ $waited -lt 10 ]; do
|
||||
alive=0
|
||||
for pid in $PIDLIST; do
|
||||
if kill -0 $pid 2>/dev/null; then alive=1; fi
|
||||
done
|
||||
if [ $alive -eq 0 ]; then break; fi
|
||||
sleep 1
|
||||
waited=`expr $waited + 1`
|
||||
done
|
||||
fi
|
||||
/usr/sbin/sshd
|
||||
xcat_restart_sshd_after_failed_service_restart
|
||||
fi
|
||||
kill -9 $CREDPID
|
||||
|
||||
@@ -19,7 +19,12 @@
|
||||
#
|
||||
#####################################################
|
||||
|
||||
[ -f "/xcatpost/xcatlib.sh" ] && . /xcatpost/xcatlib.sh
|
||||
if [ -f "/xcatpost/xcatlib.sh" ]; then
|
||||
. /xcatpost/xcatlib.sh
|
||||
else
|
||||
str_dir_name=`dirname $0`
|
||||
[ -f "$str_dir_name/xcatlib.sh" ] && . "$str_dir_name/xcatlib.sh"
|
||||
fi
|
||||
|
||||
if [ -f /xcatpost/mypostscript.post ]; then
|
||||
XCATDEBUGMODE=`grep 'XCATDEBUGMODE=' /xcatpost/mypostscript.post | cut -d= -f2 | tr -d \'\" | tr A-Z a-z`
|
||||
@@ -83,66 +88,6 @@ echolog()
|
||||
}
|
||||
|
||||
|
||||
download_postscripts()
|
||||
{
|
||||
server=$1
|
||||
if [ -z $server ]; then
|
||||
return 1;
|
||||
fi
|
||||
|
||||
# Do not override the parameter --installdir
|
||||
if [ -z "$INSTALLDIR" ]; then
|
||||
if [ -f /opt/xcat/xcatinfo ]; then
|
||||
INSTALLDIR=`grep 'INSTALLDIR' /opt/xcat/xcatinfo |cut -d= -f2`
|
||||
fi
|
||||
if [ -z "$INSTALLDIR" ]; then
|
||||
INSTALLDIR="/install"
|
||||
fi
|
||||
fi
|
||||
echolog "debug" "trying to download postscripts from http://$server$INSTALLDIR/postscripts/"
|
||||
max_retries=5
|
||||
retry=0
|
||||
rc=1 # this is a fail return
|
||||
while [ 0 -eq 0 ]; do
|
||||
if [ -e "$xcatpost" ]; then
|
||||
rm -rf "$xcatpost"
|
||||
fi
|
||||
|
||||
# These dispatcher scripts are not needed by the legacy netboot post
|
||||
# path. Newer wget parses HTML-looking regex strings inside downloaded
|
||||
# scripts and fails the whole recursive download on bogus URLs.
|
||||
export LANG=C; wget -l inf -nH -N -r --waitretry=10 --random-wait -e robots=off -T 60 -nH --cut-dirs=2 --reject "index.html*,post.xcat.ng,post.xcat.rhels10" --no-parent http://$server$INSTALLDIR/postscripts/ -P /$xcatpost 2> /tmp/wget.log
|
||||
rc=$?
|
||||
if [ $rc -eq 0 ]; then
|
||||
# return from wget was 0 but some OS do not return errors, so we
|
||||
# have additional checks for
|
||||
# failed: Connection httpd not running
|
||||
# 404: Not Found - if directory does not exist
|
||||
grep -i -E "... failed: Connection refused.$" /tmp/wget.log
|
||||
rc1=$?
|
||||
grep -i -E "ERROR 404: Not Found.$" /tmp/wget.log
|
||||
rc2=$?
|
||||
# check to see no errors at all, grep returns 1
|
||||
if [ $rc1 -eq 1 ] && [ $rc2 -eq 1 ]; then
|
||||
echolog "debug" "postscripts are downloaded from $server successfully."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
retry=$(($retry+1))
|
||||
echolog "debug" "download_postscripts retry $retry"
|
||||
if [ $retry -eq $max_retries ]; then
|
||||
echolog "debug" "failed to download postscripts from http://$server$INSTALLDIR/postscripts/ after several retries."
|
||||
break
|
||||
fi
|
||||
|
||||
SLI=$(awk 'BEGIN{srand(); printf("%d\n",rand()*20)}')
|
||||
sleep $SLI
|
||||
done
|
||||
return $rc
|
||||
}
|
||||
|
||||
|
||||
download_mypostscript()
|
||||
{
|
||||
server=$1
|
||||
|
||||
@@ -833,6 +833,107 @@ function msgutil {
|
||||
msgutil_r "" "$@"
|
||||
}
|
||||
|
||||
function xcat_download_postscripts {
|
||||
local server="$1"
|
||||
local install_dir="${2:-${INSTALLDIR:-/install}}"
|
||||
local postroot="${3:-/$xcatpost}"
|
||||
local log_file="${4:-/tmp/wget.log}"
|
||||
|
||||
export LANG=C
|
||||
wget -l inf -nH -N -r --waitretry=10 --random-wait -e robots=off -T 60 -nH --cut-dirs=2 --reject "index.html*,post.xcat.ng,post.xcat.rhels10" --no-parent "http://$server$install_dir/postscripts/" -P "$postroot" 2> "$log_file"
|
||||
}
|
||||
|
||||
function download_postscripts {
|
||||
server=$1
|
||||
if [ -z $server ]; then
|
||||
return 1;
|
||||
fi
|
||||
|
||||
# Do not override the parameter --installdir
|
||||
if [ -z "$INSTALLDIR" ]; then
|
||||
if [ -f /opt/xcat/xcatinfo ]; then
|
||||
INSTALLDIR=`grep 'INSTALLDIR' /opt/xcat/xcatinfo |cut -d= -f2`
|
||||
fi
|
||||
if [ -z "$INSTALLDIR" ]; then
|
||||
INSTALLDIR="/install"
|
||||
fi
|
||||
fi
|
||||
echolog "debug" "trying to download postscripts from http://$server$INSTALLDIR/postscripts/"
|
||||
max_retries=5
|
||||
retry=0
|
||||
rc=1 # this is a fail return
|
||||
while [ 0 -eq 0 ]; do
|
||||
if [ -e "$xcatpost" ]; then
|
||||
rm -rf "$xcatpost"
|
||||
fi
|
||||
|
||||
xcat_download_postscripts "$server" "$INSTALLDIR" "/$xcatpost" "/tmp/wget.log"
|
||||
rc=$?
|
||||
if [ $rc -eq 0 ]; then
|
||||
# return from wget was 0 but some OS do not return errors, so we
|
||||
# have additional checks for
|
||||
# failed: Connection httpd not running
|
||||
# 404: Not Found - if directory does not exist
|
||||
grep -i -E "... failed: Connection refused.$" /tmp/wget.log
|
||||
rc1=$?
|
||||
grep -i -E "ERROR 404: Not Found.$" /tmp/wget.log
|
||||
rc2=$?
|
||||
# check to see no errors at all, grep returns 1
|
||||
if [ $rc1 -eq 1 ] && [ $rc2 -eq 1 ]; then
|
||||
echolog "debug" "postscripts are downloaded from $server successfully."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
retry=$(($retry+1))
|
||||
echolog "debug" "download_postscripts retry $retry"
|
||||
if [ $retry -eq $max_retries ]; then
|
||||
echolog "debug" "failed to download postscripts from http://$server$INSTALLDIR/postscripts/ after several retries."
|
||||
break
|
||||
fi
|
||||
|
||||
SLI=$(awk 'BEGIN{srand(); printf("%d\n",rand()*20)}')
|
||||
sleep $SLI
|
||||
done
|
||||
return $rc
|
||||
}
|
||||
|
||||
function xcat_wait_for_processes_to_exit {
|
||||
local pidlist="$1"
|
||||
local max_wait="${2:-10}"
|
||||
local waited=0
|
||||
local alive
|
||||
local pid
|
||||
|
||||
while [ $waited -lt $max_wait ]; do
|
||||
alive=0
|
||||
for pid in $pidlist; do
|
||||
if kill -0 $pid 2>/dev/null; then
|
||||
alive=1
|
||||
fi
|
||||
done
|
||||
if [ $alive -eq 0 ]; then
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
waited=`expr $waited + 1`
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
function xcat_restart_sshd_after_failed_service_restart {
|
||||
local sshd_cmd="${1:-/usr/sbin/sshd}"
|
||||
local PIDLIST
|
||||
|
||||
PIDLIST=`ps aux | grep -v grep | grep "/usr/sbin/sshd"|awk -F" " '{print $2}'|xargs`
|
||||
if [ -n "$PIDLIST" ]; then
|
||||
kill -9 $PIDLIST
|
||||
xcat_wait_for_processes_to_exit "$PIDLIST"
|
||||
fi
|
||||
$sshd_cmd
|
||||
}
|
||||
|
||||
function fetch_mypostscript {
|
||||
local postroot
|
||||
postroot=$1
|
||||
|
||||
Reference in New Issue
Block a user