cang-ying/remote-node/install/preflight-linux.py

86 lines
2.6 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
"""Read-only environment report used before installing the persistent node."""
from __future__ import annotations
import argparse
import json
import os
import platform
import shutil
import subprocess
from pathlib import Path
from typing import Any
def command(argv: list[str], timeout: int = 20) -> dict[str, Any]:
if shutil.which(argv[0]) is None:
return {"available": False}
try:
result = subprocess.run(
argv,
stdin=subprocess.DEVNULL,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
timeout=timeout,
shell=False,
)
return {
"available": True,
"exit_code": result.returncode,
"output": result.stdout[:32_000],
}
except subprocess.TimeoutExpired:
return {"available": True, "error": "timeout"}
def inspect() -> dict[str, Any]:
efi = command(["efibootmgr", "-v"])
disks = command(["lsblk", "-J", "-o", "NAME,FSTYPE,LABEL,MOUNTPOINTS"])
virt = command(["systemd-detect-virt"])
boot_text = str(efi.get("output", "")).lower()
disk_text = str(disks.get("output", "")).lower()
windows_hint = any(
marker in boot_text or marker in disk_text
for marker in ("windows boot manager", "microsoft", "ntfs", "bitlocker")
)
return {
"schema": "canger-node-preflight/v1",
"hostname": platform.node(),
"platform": platform.platform(),
"machine": platform.machine(),
"systemd_running": os.path.isdir("/run/systemd/system"),
"virtualization": virt,
"efi_boot_entries": efi,
"block_filesystems": disks,
"possible_windows_dual_boot": windows_hint,
"continuity": {
"while_linux_is_booted": "supported",
"after_reboot_back_into_linux": "supported",
"while_another_dual_boot_os_is_active": "not_possible_from_linux",
},
"note": (
"A dual-boot switch powers off Linux. Cross-OS continuity requires "
"a companion agent in the other OS, a virtual machine, or separate hardware."
),
}
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--output")
args = parser.parse_args()
report = inspect()
text = json.dumps(report, ensure_ascii=False, indent=2) + "\n"
if args.output:
target = Path(args.output)
target.parent.mkdir(parents=True, exist_ok=True)
target.write_text(text, encoding="utf-8")
os.chmod(target, 0o600)
print(text, end="")
if __name__ == "__main__":
main()