|
42 | 42 | from .cleanup import cleanup_stale_entries, collect_active_volume_handles |
43 | 43 | from .identity import IdentityServicer |
44 | 44 |
|
| 45 | +_NIXKUBE_DRIVERS = {"nixkube", "nix.csi.store"} |
| 46 | + |
| 47 | + |
| 48 | +async def check_csi_volume_mounts(pod: Pod) -> None: |
| 49 | + """Emit warning events for nixkube CSI volumes with common mount misconfigurations. |
| 50 | +
|
| 51 | + Checks two conditions for each nixkube CSI volume in the pod spec: |
| 52 | + - MissingSubPath: a volumeMount exists without subPath='nix', which causes |
| 53 | + the volume root (not the nix/ subtree) to be mounted, making /nix/store |
| 54 | + paths inaccessible at the expected location. |
| 55 | + - MissingNixMount: no container mounts the volume at /nix, so /nix/store |
| 56 | + paths will never be reachable regardless of subPath. |
| 57 | + """ |
| 58 | + spec = pod.raw.get("spec", {}) |
| 59 | + all_containers = spec.get("containers", []) + spec.get("initContainers", []) |
| 60 | + |
| 61 | + for volume in spec.get("volumes", []): |
| 62 | + if volume.get("csi", {}).get("driver") not in _NIXKUBE_DRIVERS: |
| 63 | + continue |
| 64 | + vol_name = volume["name"] |
| 65 | + |
| 66 | + vol_mounts = [ |
| 67 | + (container, vm) |
| 68 | + for container in all_containers |
| 69 | + for vm in container.get("volumeMounts", []) |
| 70 | + if vm["name"] == vol_name |
| 71 | + ] |
| 72 | + |
| 73 | + for container, vm in vol_mounts: |
| 74 | + if not vm.get("subPath"): |
| 75 | + await report_event( |
| 76 | + pod, |
| 77 | + reason="MissingSubPath", |
| 78 | + note=( |
| 79 | + f"Volume '{vol_name}' in container '{container['name']}' " |
| 80 | + f"mounted at '{vm['mountPath']}' is missing subPath='nix'. " |
| 81 | + f"Nix store paths will not be accessible at the mount point." |
| 82 | + ), |
| 83 | + event_type="Warning", |
| 84 | + ) |
| 85 | + |
| 86 | + if not any(vm["mountPath"] == "/nix" for _, vm in vol_mounts): |
| 87 | + await report_event( |
| 88 | + pod, |
| 89 | + reason="MissingNixMount", |
| 90 | + note=( |
| 91 | + f"Volume '{vol_name}' has no mount at '/nix' in any container. " |
| 92 | + f"Nix store paths will not be accessible." |
| 93 | + ), |
| 94 | + event_type="Warning", |
| 95 | + ) |
| 96 | + |
45 | 97 |
|
46 | 98 | def csi_error_handler( |
47 | 99 | func: Any, |
@@ -139,6 +191,11 @@ async def NodePublishVolume( |
139 | 191 | f"Pod UID mismatch: {pod.metadata.uid} != {pod_uid}" |
140 | 192 | ) |
141 | 193 |
|
| 194 | + try: |
| 195 | + await check_csi_volume_mounts(pod) |
| 196 | + except Exception: |
| 197 | + log.warning("csi_mount_check_failed", exc_info=True) |
| 198 | + |
142 | 199 | # Emit deprecation warning if using compatibility driver |
143 | 200 | if self.plugin_name == "nix.csi.store": |
144 | 201 | try: |
|
0 commit comments