|
| 1 | +"""Smoke tests for NFD (Node Feature Discovery) topology-updater. |
| 2 | +
|
| 3 | +Validates that the NFD namespace exists, the Helm release is deployed, |
| 4 | +the topology-updater DaemonSet is healthy on GPU nodes, and |
| 5 | +NodeResourceTopology CRDs are being published. |
| 6 | +""" |
| 7 | + |
| 8 | +from __future__ import annotations |
| 9 | + |
| 10 | +import subprocess |
| 11 | + |
| 12 | +import pytest |
| 13 | +from helpers import ( |
| 14 | + assert_daemonset_healthy, |
| 15 | + find_helm_release, |
| 16 | + run_kubectl, |
| 17 | +) |
| 18 | + |
| 19 | +pytestmark = [pytest.mark.live] |
| 20 | + |
| 21 | +NAMESPACE = "nfd" |
| 22 | + |
| 23 | + |
| 24 | +# ============================================================================ |
| 25 | +# Namespace |
| 26 | +# ============================================================================ |
| 27 | + |
| 28 | + |
| 29 | +class TestNFDNamespace: |
| 30 | + """Verify NFD namespace exists.""" |
| 31 | + |
| 32 | + def test_namespace_exists(self, all_namespaces: dict) -> None: |
| 33 | + ns_names = [ns["metadata"]["name"] for ns in all_namespaces.get("items", [])] |
| 34 | + assert NAMESPACE in ns_names, f"Namespace '{NAMESPACE}' not found" |
| 35 | + |
| 36 | + |
| 37 | +# ============================================================================ |
| 38 | +# Helm Release |
| 39 | +# ============================================================================ |
| 40 | + |
| 41 | + |
| 42 | +class TestNFDHelm: |
| 43 | + """Verify NFD Helm release is deployed.""" |
| 44 | + |
| 45 | + def test_helm_release_deployed(self, all_helm_releases: list[dict]) -> None: |
| 46 | + release = find_helm_release(all_helm_releases, "nfd", namespace=NAMESPACE) |
| 47 | + assert release is not None, "Helm release 'nfd' not found in 'nfd' namespace" |
| 48 | + status = release.get("status", "") |
| 49 | + assert status == "deployed", f"NFD Helm release status is '{status}', expected 'deployed'" |
| 50 | + |
| 51 | + |
| 52 | +# ============================================================================ |
| 53 | +# Topology-updater DaemonSet |
| 54 | +# ============================================================================ |
| 55 | + |
| 56 | + |
| 57 | +class TestTopologyUpdater: |
| 58 | + """Verify topology-updater DaemonSet is healthy on GPU nodes. |
| 59 | +
|
| 60 | + allow_zero=True because the cluster may not have any GPU nodes |
| 61 | + provisioned at test time (e.g. staging with no active GPU jobs). |
| 62 | + """ |
| 63 | + |
| 64 | + def test_topology_updater_healthy(self, all_daemonsets: dict, all_nodes: dict) -> None: |
| 65 | + assert_daemonset_healthy( |
| 66 | + all_daemonsets, |
| 67 | + all_nodes, |
| 68 | + NAMESPACE, |
| 69 | + name_contains="topology-updater", |
| 70 | + allow_zero=True, |
| 71 | + ) |
| 72 | + |
| 73 | + |
| 74 | +# ============================================================================ |
| 75 | +# NodeResourceTopology CRD |
| 76 | +# ============================================================================ |
| 77 | + |
| 78 | + |
| 79 | +class TestNodeResourceTopology: |
| 80 | + """Verify NodeResourceTopology CRD is installed. |
| 81 | +
|
| 82 | + The NRT CRD is the key output of NFD topology-updater — without it |
| 83 | + the numa-scheduler has no NUMA visibility. The CRD is installed by |
| 84 | + the NFD Helm chart when topologyUpdater is enabled. |
| 85 | + """ |
| 86 | + |
| 87 | + def test_nrt_crd_exists(self) -> None: |
| 88 | + try: |
| 89 | + result = run_kubectl( |
| 90 | + ["get", "crd", "noderesourcetopologies.topology.node.k8s.io", "-o", "json"], |
| 91 | + ) |
| 92 | + except subprocess.CalledProcessError: |
| 93 | + pytest.fail("NodeResourceTopology CRD not found — NFD chart may not have installed it") |
| 94 | + name = result.get("metadata", {}).get("name", "") |
| 95 | + assert "noderesourcetopologies" in name |
0 commit comments