|
|
|
|
@@ -89,6 +89,83 @@ Side paths:
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Multi-architecture PXE
|
|
|
|
|
|
|
|
|
|
The bastion serves both `x86_64` and `aarch64` over the network. Nothing about this is
|
|
|
|
|
operator-configured -- there is no `--arch` flag, by design.
|
|
|
|
|
|
|
|
|
|
### How a client's architecture is decided
|
|
|
|
|
|
|
|
|
|
1. **DHCP option 93** (Client System Architecture) picks the *bootloader*. dnsmasq matches
|
|
|
|
|
it and hands out a matching iPXE binary:
|
|
|
|
|
|
|
|
|
|
| Option 93 | Client | Served |
|
|
|
|
|
|---|---|---|
|
|
|
|
|
| `0` | x86 BIOS | `undionly.kpxe` (TFTP) |
|
|
|
|
|
| `7`, `9` | x64 UEFI | `ipxe.efi` (TFTP) |
|
|
|
|
|
| `11` | **ARM64 UEFI** | `ipxe-arm64.efi` (TFTP) |
|
|
|
|
|
| `16` | x64 UEFI HTTP Boot | `http://…/ipxe.efi` |
|
|
|
|
|
| `19` | **ARM64 UEFI HTTP Boot** | `http://…/ipxe-arm64.efi` |
|
|
|
|
|
|
|
|
|
|
Values come from the IANA Processor Architecture Types registry. Note `19`, not `20` --
|
|
|
|
|
`20` is *pc/at bios boot from http*. EDK2/AAVMF prefers HTTP Boot over TFTP PXE, so the
|
|
|
|
|
iPXE binaries are staged in **both** `tftpDir` and `httpDir` (symlinked by `main.ts`).
|
|
|
|
|
|
|
|
|
|
2. **`/dispatch` picks the kernel.** Option 93 never reaches the HTTP endpoint, so
|
|
|
|
|
`boot.ipxe` passes iPXE's own `${buildarch}` as `?arch=`. `resolveArch()` prefers, in
|
|
|
|
|
order: the tracked machine record → the reported `?arch=` → the configured default.
|
|
|
|
|
The record wins because it is what we observed on the machine itself.
|
|
|
|
|
|
|
|
|
|
### Artifact naming
|
|
|
|
|
|
|
|
|
|
`x86_64` keeps the original unsuffixed paths so its rendered iPXE scripts are unchanged;
|
|
|
|
|
everything else is suffixed. `kernelPath()` / `initrdPath()` in `templates/boot.ipxe.ts`
|
|
|
|
|
are the single source of truth, used by both the templates and `main.ts` staging.
|
|
|
|
|
|
|
|
|
|
| arch | kernel | initrd |
|
|
|
|
|
|---|---|---|
|
|
|
|
|
| `x86_64` | `/vmlinuz` | `/initrd.img` |
|
|
|
|
|
| `aarch64` | `/vmlinuz-aarch64` | `/initrd-aarch64.img` |
|
|
|
|
|
|
|
|
|
|
`tests/ipxe-x86-regression.test.ts` pins the x86_64 output against a golden fixture.
|
|
|
|
|
|
|
|
|
|
### arm64 gotchas
|
|
|
|
|
|
|
|
|
|
- **LoadFile2 is mandatory.** arm64 has no `HdrS` boot protocol; the kernel's EFI stub
|
|
|
|
|
fetches the initrd over the UEFI `EFI_LOAD_FILE2_PROTOCOL`. An iPXE build without it
|
|
|
|
|
accepts the `initrd` line, silently drops it, and the kernel panics with
|
|
|
|
|
`VFS: Unable to mount root fs on unknown-block(0,0)`. Fedora's
|
|
|
|
|
`ipxe-bootimgs-aarch64` implements it; the integration test asserts this up front so
|
|
|
|
|
the failure names itself instead of looking like a disk problem.
|
|
|
|
|
- **`nomodeset` is x86-only.** On arm64 there is no VGA path to fall back to. aarch64 gets
|
|
|
|
|
`console=tty0 console=ttyAMA0,115200` instead — the last `console=` wins for
|
|
|
|
|
`/dev/console`, so serial is the interactive one.
|
|
|
|
|
- **Ubuntu is x86_64-only.** `releases.ubuntu.com` publishes no arm64 netboot artifacts.
|
|
|
|
|
`osSupportsArch()` encodes this, and both the install guard and `/dispatch` refuse the
|
|
|
|
|
combination rather than serving an x86 kernel to an ARM machine.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Onboarding classification (vendor OS)
|
|
|
|
|
|
|
|
|
|
Machines carry an `onboard` field: `"pxe"` (default) or `"ssh"`, plus `vendor_os` naming
|
|
|
|
|
what they run. `classifyOnboard()` in `@lab/shared` sets it from DMI identity, with known
|
|
|
|
|
hardware also matched by MAC — a machine can sit in state for a long time with no DMI, and
|
|
|
|
|
a DMI-only rule would fail open exactly where it matters.
|
|
|
|
|
|
|
|
|
|
`onboard: "ssh"` means *we cannot rebuild this machine's OS*. Installs are refused at both
|
|
|
|
|
entry points (`/api/install` and the labd `command-install` handler) with an error naming
|
|
|
|
|
the machine and pointing at `provision debug`. **Rescue is never guarded** — being unable
|
|
|
|
|
to reinstall a machine is precisely when a rescue shell is needed.
|
|
|
|
|
|
|
|
|
|
This is a fact about the machine, not a blocklist. The refusal follows from "no image in
|
|
|
|
|
our pipeline restores `vendor_os`", so adding a DGX OS image to the pipeline is what
|
|
|
|
|
unblocks the DGX Sparks — no entry needs deleting.
|
|
|
|
|
|
|
|
|
|
Current classifications: NVIDIA DGX Spark (`spark-2935`, `spark-3a1c`) → `dgx-os`.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Packages
|
|
|
|
|
|
|
|
|
|
### Monorepo Structure
|
|
|
|
|
|