diff --git a/.github/workflows/test-features.yml b/.github/workflows/test-features.yml index 27349ac0..1ccdacce 100644 --- a/.github/workflows/test-features.yml +++ b/.github/workflows/test-features.yml @@ -22,6 +22,8 @@ on: - 'tests/test_vm_backup_jobs_api.py' - 'tests/test_backup_storage_retention.cjs' - 'tests/test_figurine_installation.py' + - 'scripts/gpu_tpu/nvidia_installer.sh' + - 'tests/test_nvidia*.py' - 'scripts/post_install/customizable_post_install.sh' - 'AppImage/scripts/post_install_versions.py' - 'AppImage/scripts/flask_proxmenux_routes.py' @@ -169,6 +171,21 @@ jobs: NODE_PATH: ${{ github.workspace }}/.github/ci/offline-node/node_modules run: node tests/test_backup_storage_retention.cjs + nvidia-installer: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Check NVIDIA parser, cache and Secure Boot regressions + run: | + bash -n scripts/gpu_tpu/nvidia_installer.sh + python3 -B -m unittest discover -s tests -p 'test_nvidia*.py' -v + installer-and-release: runs-on: ubuntu-latest timeout-minutes: 10 diff --git a/scripts/gpu_tpu/nvidia_installer.sh b/scripts/gpu_tpu/nvidia_installer.sh index a296c786..293969e7 100644 --- a/scripts/gpu_tpu/nvidia_installer.sh +++ b/scripts/gpu_tpu/nvidia_installer.sh @@ -866,11 +866,9 @@ KEYLASE_PATCH_URL="https://raw.githubusercontent.com/keylase/nvidia-patch/master NVIDIA_BRANCHES_CACHE="/var/cache/proxmenux/nvidia_stable_branches.txt" NVIDIA_PRODUCTION_HEAD_CACHE="/var/cache/proxmenux/nvidia_production_head.txt" NVIDIA_BRANCH_HEADS_CACHE="/var/cache/proxmenux/nvidia_branch_heads.txt" -# v2: the first generation of these files scraped the whole page and so -# included the legacy table (see _nvidia_supported_ids_from_page). Those -# files say a branch supports GPUs it has dropped, so they are left -# behind rather than reused. -NVIDIA_GPU_SUPPORT_CACHE_PREFIX="/var/cache/proxmenux/nvidia_gpu_support_v2_" +# v3: discard older caches, which either included legacy GPUs (v1) or +# omitted devices listed only with subsystem qualifiers (v2). +NVIDIA_GPU_SUPPORT_CACHE_PREFIX="/var/cache/proxmenux/nvidia_gpu_support_v3_" NVIDIA_BRANCHES_TTL_SECONDS=$((24 * 3600)) NVIDIA_BRANCHES_URL="https://www.nvidia.com/en-us/drivers/unix/" @@ -975,13 +973,17 @@ get_nvidia_branch_head() { # card NVIDIA ever shipped — which is how a Quadro P1000 came to be # offered the 595 branch that refuses it at probe time, after compiling # and installing perfectly. Everything from that heading on is cut away. +# NVIDIA identifies each GPU row as devidXXXX or devidXXXX_VENDOR_SUBDEVICE. +# Read the primary device ID from that identifier, not an exact four-digit +# table cell: T400/T1000 variants have three IDs in the cell. Subsystem IDs +# and GPU names such as A100 must not become independent supported devices. _nvidia_supported_ids_from_page() { awk ' /legacy GPUs that are no longer supported/ { exit } { print } ' \ - | grep -aoiE '[0-9A-F]{4}' \ - | grep -aoiE '[0-9A-F]{4}' \ + | grep -aoiE 'NVIDIA T1000 8GB +1FF0 1028 1612 +NVIDIA T400 4GB +1FF2 10DE 18FF +'''), ["1ff0", "1ff2"]) + + def test_unqualified_and_duplicate_rows_are_sorted_and_deduplicated(self): + self.assertEqual(self.parse(''' +Quadro RTX 60001E30 +Quadro RTX 8000 +A10020B0 +'''), ["1e30", "20b0"]) + + def test_legacy_rows_and_unrelated_hex_cells_are_excluded(self): + self.assertEqual(self.parse(''' +A10020B0 +1234 +

Below are the legacy GPUs that are no longer supported in the +current driver.

+Quadro P10001CB1 +'''), ["20b0"]) + + def test_cache_refresh_does_not_reuse_fresh_v2_device_list(self): + prefix = re.search(r'^NVIDIA_GPU_SUPPORT_CACHE_PREFIX="([^"]+)"', SOURCE, re.M).group(1) + self.assertTrue(prefix.endswith("_v3_")) + with tempfile.TemporaryDirectory() as directory: + root = Path(directory) + (root / "nvidia_gpu_support_v2_595.txt").write_text("1e30\n") + script = '\n'.join([ + 'NVIDIA_GPU_SUPPORT_CACHE_PREFIX="' + str(root / Path(prefix).name) + '"', + 'NVIDIA_BRANCHES_TTL_SECONDS=86400', + 'get_nvidia_branch_head() { echo 595.112.07; }', + 'curl() { echo \'1FF2 10DE 18FF\'; }', + function("_nvidia_supported_ids_from_page"), + function("refresh_nvidia_gpu_support_for_major"), + 'refresh_nvidia_gpu_support_for_major 595', + ]) + result = subprocess.run(["bash", "-c", script], text=True, capture_output=True) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertEqual((root / "nvidia_gpu_support_v3_595.txt").read_text(), "1ff2\n") + + +if __name__ == "__main__": + unittest.main()