diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c368031..076f137 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1340,6 +1340,10 @@ jobs: has_cmd() { command -v "$1" >/dev/null 2>&1; } + is_ablestack_host() { + [[ "${PRETTY_NAME:-}" == *"ABLESTACK"* ]] + } + resolve_first_cmd() { local cmd= for cmd in "$@"; do @@ -1352,6 +1356,10 @@ jobs: } rpm_pkg_manager_cmd() { + if is_ablestack_host && has_cmd aspm; then + command -v aspm + return 0 + fi resolve_first_cmd dnf aspm || { echo "[ERROR] Neither dnf nor ABLESTACK aspm was found." >&2 return 127 @@ -1365,6 +1373,10 @@ jobs: } rpm_query_cmd() { + if is_ablestack_host && has_cmd aspkg; then + command -v aspkg + return 0 + fi resolve_first_cmd rpm aspkg || { echo "[ERROR] Neither rpm nor ABLESTACK aspkg was found." >&2 return 127 @@ -1644,8 +1656,8 @@ jobs: run: | set -e bash -n release/install-linux.sh - grep -q 'resolve_first_cmd dnf aspm' release/install-linux.sh - grep -q 'resolve_first_cmd rpm aspkg' release/install-linux.sh + grep -q 'is_ablestack_host && has_cmd aspm' release/install-linux.sh + grep -q 'is_ablestack_host && has_cmd aspkg' release/install-linux.sh - name: Create uninstall-linux.sh run: | @@ -1672,6 +1684,10 @@ jobs: has_cmd() { command -v "$1" >/dev/null 2>&1; } + is_ablestack_host() { + [[ "${PRETTY_NAME:-}" == *"ABLESTACK"* ]] + } + resolve_first_cmd() { local cmd= for cmd in "$@"; do @@ -1684,6 +1700,10 @@ jobs: } rpm_pkg_manager_cmd() { + if is_ablestack_host && has_cmd aspm; then + command -v aspm + return 0 + fi resolve_first_cmd dnf aspm || { echo "[ERROR] Neither dnf nor ABLESTACK aspm was found." >&2 return 127 @@ -1697,6 +1717,10 @@ jobs: } rpm_query_cmd() { + if is_ablestack_host && has_cmd aspkg; then + command -v aspkg + return 0 + fi resolve_first_cmd rpm aspkg || { echo "[ERROR] Neither rpm nor ABLESTACK aspkg was found." >&2 return 127 @@ -1777,8 +1801,8 @@ jobs: run: | set -e bash -n release/uninstall-linux.sh - grep -q 'resolve_first_cmd dnf aspm' release/uninstall-linux.sh - grep -q 'resolve_first_cmd rpm aspkg' release/uninstall-linux.sh + grep -q 'is_ablestack_host && has_cmd aspm' release/uninstall-linux.sh + grep -q 'is_ablestack_host && has_cmd aspkg' release/uninstall-linux.sh - name: Generate release notes (changelog) run: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fcaf308..7991bd3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,3 +20,7 @@ jobs: run: | echo "Running CI build (basic validation)" make all + + - name: ISO package manager selection smoke + run: | + tests/iso_pkg_manager_selection_smoke.sh diff --git a/docs/ablestack_iso_pkg_manager_selection_design.md b/docs/ablestack_iso_pkg_manager_selection_design.md new file mode 100644 index 0000000..cdf9b7d --- /dev/null +++ b/docs/ablestack_iso_pkg_manager_selection_design.md @@ -0,0 +1,19 @@ +# ABLESTACK ISO package manager selection design + +## Background + +Newer ABLESTACK hosts may keep `dnf`, `yum`, or `rpm` commands on disk while blocking their direct use. Operators are expected to use `aspm` for package transactions and `aspkg` for RPM queries. The ISO installer already wrapped package operations, but it selected commands only by existence and preferred `dnf` before `aspm`. + +That means an ABLESTACK host can print `dnf, yum usage is blocked` before the installer ever reaches the bundled V2K/N2K add-on install steps. + +## Policy + +- On ABLESTACK hosts, prefer `aspm` for RPM package manager operations when it exists. +- On ABLESTACK hosts, prefer `aspkg` for RPM query operations when it exists. +- On non-ABLESTACK RPM hosts, keep the existing native `dnf` and `rpm` preference. +- Keep the existing `dnf`/`rpm` fallback for ordinary Rocky, RHEL, CentOS, AlmaLinux, and Fedora systems. +- Apply the same command selection policy to both `install-linux.sh` and `uninstall-linux.sh`. + +## Validation + +The smoke test extracts the generated installer and uninstaller script bodies from the release workflow, then injects fake commands where `dnf` and `rpm` exist but are blocked. It verifies that ABLESTACK `PRETTY_NAME` selects `aspm` and `aspkg`, while a regular Rocky `PRETTY_NAME` still selects `dnf` and `rpm`. diff --git a/tests/iso_pkg_manager_selection_smoke.sh b/tests/iso_pkg_manager_selection_smoke.sh new file mode 100755 index 0000000..e311fdf --- /dev/null +++ b/tests/iso_pkg_manager_selection_smoke.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" +WORKFLOW="${ROOT_DIR}/.github/workflows/build.yml" +TMP_DIR="$(mktemp -d)" +trap 'rm -rf "${TMP_DIR}"' EXIT + +extract_generated_script() { + local target="$1" + local output="$2" + awk -v target="${target}" ' + index($0, "cat <<'\''EOF'\'' > " target) { capture = 1; next } + capture && $0 == " EOF" { exit } + capture { + sub(/^ /, "") + print + } + ' "${WORKFLOW}" > "${output}" +} + +extract_function_prefix() { + local script="$1" + local output="$2" + awk ' + /^case .*DISTRO.* in/ { exit } + { print } + ' "${script}" > "${output}" +} + +write_fake_cmd() { + local path="$1" + local body="$2" + printf '#!/usr/bin/env bash\n%s\n' "${body}" > "${path}" + chmod +x "${path}" +} + +assert_selection() { + local prefix="$1" + local pretty_name="$2" + local expected_manager="$3" + local expected_query="$4" + + ( + # shellcheck disable=SC1090 + source "${prefix}" >/dev/null + PRETTY_NAME="${pretty_name}" + + manager_cmd="$(rpm_pkg_manager_cmd)" + query_cmd="$(rpm_query_cmd)" + + [[ "$(basename "${manager_cmd}")" == "${expected_manager}" ]] || { + echo "expected package manager ${expected_manager}, got ${manager_cmd}" >&2 + exit 1 + } + [[ "$(basename "${query_cmd}")" == "${expected_query}" ]] || { + echo "expected query command ${expected_query}, got ${query_cmd}" >&2 + exit 1 + } + ) +} + +mkdir -p "${TMP_DIR}/bin" +write_fake_cmd "${TMP_DIR}/bin/dnf" 'echo "dnf, yum usage is blocked" >&2; exit 64' +write_fake_cmd "${TMP_DIR}/bin/rpm" 'echo "rpm usage is blocked" >&2; exit 64' +write_fake_cmd "${TMP_DIR}/bin/aspm" 'exit 0' +write_fake_cmd "${TMP_DIR}/bin/aspkg" 'exit 0' + +extract_generated_script "release/install-linux.sh" "${TMP_DIR}/install-linux.sh" +extract_generated_script "release/uninstall-linux.sh" "${TMP_DIR}/uninstall-linux.sh" +bash -n "${TMP_DIR}/install-linux.sh" +bash -n "${TMP_DIR}/uninstall-linux.sh" +extract_function_prefix "${TMP_DIR}/install-linux.sh" "${TMP_DIR}/install-prefix.sh" +extract_function_prefix "${TMP_DIR}/uninstall-linux.sh" "${TMP_DIR}/uninstall-prefix.sh" + +PATH="${TMP_DIR}/bin:${PATH}" +export PATH + +assert_selection "${TMP_DIR}/install-prefix.sh" "ABLESTACK Host 9" aspm aspkg +assert_selection "${TMP_DIR}/uninstall-prefix.sh" "ABLESTACK Host 9" aspm aspkg +assert_selection "${TMP_DIR}/install-prefix.sh" "Rocky Linux 9.6" dnf rpm +assert_selection "${TMP_DIR}/uninstall-prefix.sh" "Rocky Linux 9.6" dnf rpm + +echo "[OK] ISO package manager selection smoke test passed"