#!/usr/bin/env python3 """ preflight.py - run every server-side check before a build day. The individual linters each catch one class of silent failure. This runs them together so "is the PXE server fit to image from?" is one command and one exit code, instead of four things somebody has to remember. What it runs: lint-driver-catalogue.py HardwareDriver.json vs PESetup's real matcher - missing/case-mismatched packs, empty tokens, shadowed entries. A driver miss is only a WARNING to PESetup, so the bay images with no NIC. lint-unattend.py answer files vs the schema limits. One over-length value invalidates the whole file for its pass and stops the bay at a dialog with nothing configured. build-pctype-media.py resolves the critical paths in every per-PCTYPE --verify media view; a dangling symlink is a dead view. firmware coverage models in the driver catalogues that have no entry in the BIOS models.txt, so their firmware is never offered. This one is advisory - the manifest is a curated set and most misses are out-of-fleet. Usage: ./preflight.py # everything ./preflight.py --quick # skip the media-view verify (the slow one) Exit code is non-zero if any blocking check fails. """ import argparse import os import subprocess import sys HERE = os.path.dirname(os.path.abspath(__file__)) REPO = os.path.dirname(HERE) PXE_HOST = "172.16.9.1" PXE_USER = "pxe" PXE_PASS = "pxe" MODELS_TXT = "/srv/samba/winpeapps/_shared/BIOS/models.txt" IMAGE_BASE = "/srv/samba/winpeapps" def run(label, argv, blocking=True): print("=" * 72) print(label) print("=" * 72) try: r = subprocess.run(argv, cwd=REPO) rc = r.returncode except OSError as e: print(" could not run: %s" % e) rc = 1 status = "PASS" if rc == 0 else ("FAIL" if blocking else "WARN") print("-> %s (exit %d)\n" % (status, rc)) return rc if blocking else 0 def ssh(cmd): return subprocess.run( ["sshpass", "-p", PXE_PASS, "ssh", "-o", "StrictHostKeyChecking=no", "-o", "LogLevel=ERROR", "%s@%s" % (PXE_USER, PXE_HOST), cmd], capture_output=True, text=True) def firmware_coverage(): """Models in the driver catalogues with no BIOS manifest entry. Advisory only. models.txt is deliberately curated and most uncovered models are legacy or not in this fleet - the value is spotting a model you DO image whose firmware silently never updates, which is how the OptiPlex 7020 family sat uncovered until 2026-08-06.""" print("=" * 72) print("firmware coverage (advisory)") print("=" * 72) r = ssh("cat '%s'" % MODELS_TXT) if r.returncode != 0: print(" could not read %s\n-> WARN\n" % MODELS_TXT) return 0 tokens = [ln.split("|")[0] for ln in r.stdout.splitlines() if ln.strip() and not ln.startswith("#")] r = ssh("cat %s/*/Deploy/Control/HardwareDriver.json" % IMAGE_BASE) if r.returncode != 0: print(" could not read the driver catalogues\n-> WARN\n") return 0 import json, re models = set() for blob in re.findall(r"\[.*?\n\]", r.stdout, re.S): try: for e in json.loads(blob): for t in str(e.get("modelswminame") or "").split(","): if t.strip(): models.add(t.strip()) except json.JSONDecodeError: continue missing = [m for m in sorted(models) if not any(tok.lower() in m.lower() for tok in tokens)] print(" %d catalogued models, %d covered, %d with no firmware entry" % (len(models), len(models) - len(missing), len(missing))) if missing: print(" uncovered (check any of these you actually image):") for m in missing[:15]: print(" %s" % m) if len(missing) > 15: print(" ... and %d more" % (len(missing) - 15)) print("-> WARN (advisory)\n" if missing else "-> PASS\n") return 0 def main(): ap = argparse.ArgumentParser(description="Run every pre-build check.") ap.add_argument("--quick", action="store_true", help="skip the media-view verify (the slow one)") args = ap.parse_args() rc = 0 rc |= run("driver catalogue", [sys.executable, "scripts/lint-driver-catalogue.py", "--quiet"]) rc |= run("unattend answer files", [sys.executable, "scripts/lint-unattend.py", "--quiet"]) if not args.quick: rc |= run("per-PCTYPE media views", [sys.executable, "scripts/build-pctype-media.py", "--verify"]) rc |= firmware_coverage() print("=" * 72) if rc: print("PREFLIGHT FAILED - fix the blocking findings above before imaging.") return 1 print("PREFLIGHT PASSED") return 0 if __name__ == "__main__": sys.exit(main())