Mac mini support: arm64 cross-build installed beside the binary and pushed by arch; ARM machine name from the device tree

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Mitchell-Johnson
2026-09-18 14:13:09 -07:00
co-authored by Claude Fable 5.1
parent b6502ba362
commit a372378098
6 changed files with 28 additions and 4 deletions
+5 -1
View File
@@ -23,7 +23,11 @@ go:
dev: dev:
cd web && npm run dev cd web && npm run dev
deploy: build # arm64 sibling for aarch64 machines (Mac mini); the hub pushes it to them
cross:
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 $(GO) build -trimpath -ldflags "-s -w -X main.version=$(VERSION)" -o bin/hamlab-linux-arm64 ./cmd/hamlab
deploy: build cross
./deploy/install.sh ./deploy/install.sh
@sleep 1; $(PREFIX)/hamlab push-nodes || true @sleep 1; $(PREFIX)/hamlab push-nodes || true
+4 -1
View File
@@ -200,7 +200,10 @@ something long in one, switch away and back, refresh — it's all still there.
it last, so one deploy on the hub updates every machine. First install on a new host it last, so one deploy on the hub updates every machine. First install on a new host
is still by hand (scp binary + `install.sh`, `hamlab passwd`, `tls auto`). Still to is still by hand (scp binary + `install.sh`, `hamlab passwd`, `tls auto`). Still to
do: Phase 2 Datacenter overview; optional firewall rule limiting a node's port to do: Phase 2 Datacenter overview; optional firewall rule limiting a node's port to
the hub; cross-architecture builds for the Mac mini. the hub. **Cross-architecture** (2026-09-18): `make deploy` also builds
`bin/hamlab-linux-arm64`, `install.sh` installs it beside the binary as
`hamlab-arm64`, and the hub picks the sibling matching a node's `/api/me.arch` when
pushing — the Mac mini (Fedora Asahi, aarch64, node `mac`) updates like the rest.
- **Auth hardening** — WebAuthn passkeys (phone Face ID), TOTP fallback, session - **Auth hardening** — WebAuthn passkeys (phone Face ID), TOTP fallback, session
list + revoke, optional NPM access list restricting to WireGuard/LAN. list + revoke, optional NPM access list restricting to WireGuard/LAN.
- **Files tab** — **shipped 2026-09-18** (`internal/files`, `Files.tsx`): browse from - **Files tab** — **shipped 2026-09-18** (`internal/files`, `Files.tsx`): browse from
+2
View File
@@ -36,6 +36,8 @@ through the switcher at the top of the rail.
Updating: `make deploy` on the hub installs the new build there and then pushes it to Updating: `make deploy` on the hub installs the new build there and then pushes it to
every managed machine (`hamlab push-nodes`), which install it and restart. The Machines every managed machine (`hamlab push-nodes`), which install it and restart. The Machines
page flags machines running an older version and offers the same push per machine. page flags machines running an older version and offers the same push per machine.
Mixed architectures are fine: `make deploy` also cross-compiles arm64, and the hub sends
each machine the build for its own architecture.
- On `core` it is public at `https://hamlab.bigham.dev` behind Nginx Proxy Manager. - On `core` it is public at `https://hamlab.bigham.dev` behind Nginx Proxy Manager.
- Installable as a PWA. - Installable as a PWA.
+4
View File
@@ -19,6 +19,10 @@ sed -e "s|@USER@|$USER_NAME|g" -e "s|@GROUP@|$GROUP_NAME|g" -e "s|@HOME@|$HOME_D
deploy/hamlab.service > "$unit" deploy/hamlab.service > "$unit"
sudo install -m 0755 bin/hamlab "$PREFIX/hamlab" sudo install -m 0755 bin/hamlab "$PREFIX/hamlab"
# other-architecture builds sit beside the binary so the hub can push them to matching machines
for alt in bin/hamlab-linux-*; do
[ -f "$alt" ] && sudo install -m 0755 "$alt" "$PREFIX/hamlab-${alt##*-linux-}"
done
sudo install -m 0644 "$unit" /etc/systemd/system/hamlab.service sudo install -m 0644 "$unit" /etc/systemd/system/hamlab.service
rm -f "$unit" rm -f "$unit"
sudo systemctl daemon-reload sudo systemctl daemon-reload
+6
View File
@@ -914,6 +914,12 @@ var cpuModel = func() string {
} }
} }
} }
// ARM boards don't put a model name in cpuinfo; the device tree names the machine.
for _, p := range []string{"/sys/firmware/devicetree/base/model", "/proc/device-tree/model", "/sys/devices/virtual/dmi/id/product_name"} {
if m := strings.TrimRight(strings.TrimSpace(readStr(p)), "\x00"); m != "" {
return m
}
}
return "" return ""
}() }()
+6 -1
View File
@@ -313,9 +313,14 @@ func (m *Manager) Push(ctx context.Context, name, binPath, ourArch string) PushR
_ = json.NewDecoder(io.LimitReader(resp.Body, 64<<10)).Decode(&me) _ = json.NewDecoder(io.LimitReader(resp.Body, 64<<10)).Decode(&me)
resp.Body.Close() resp.Body.Close()
if me.Arch != "" && ourArch != "" && me.Arch != ourArch { if me.Arch != "" && ourArch != "" && me.Arch != ourArch {
res.Error = fmt.Sprintf("architecture mismatch: node is %s, this binary is %s — build for it and deploy by hand", me.Arch, ourArch) // look for a sibling build: /usr/local/bin/hamlab-arm64 next to /usr/local/bin/hamlab
alt := binPath + "-" + me.Arch
if _, err := os.Stat(alt); err != nil {
res.Error = fmt.Sprintf("node is %s but only a %s build is installed here (expected %s; run make deploy, which builds it)", me.Arch, ourArch, alt)
return res return res
} }
binPath = alt
}
f, err := os.Open(binPath) f, err := os.Open(binPath)
if err != nil { if err != nil {
res.Error = err.Error() res.Error = err.Error()