refactor: harden diagnostics and consolidate runtime code
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
# Support bundle: stage under a private os.MkdirTemp parent, not a time-derived path
|
||||
|
||||
**Date:** 2026-08-31
|
||||
**Status:** active
|
||||
|
||||
## Context
|
||||
|
||||
`BuildSupportBundle` staged into
|
||||
`os.TempDir()/bee-support-stage-<hostname>-<YYYYMMDD-HHMMSS>` and did
|
||||
`defer os.RemoveAll(stageRoot)`. The name has one-second resolution and a
|
||||
fixed hostname, so two builds started in the same wall-clock second resolve
|
||||
to the same directory: one operator double-clicking "Download Support
|
||||
Bundle", two operators, or an on-demand build racing the blackbox worker.
|
||||
|
||||
When that happened, the first build to finish ran `os.RemoveAll` on the
|
||||
shared tree while the second was still populating it or archiving it. The
|
||||
second build's `createSupportTarGz` then walked a half-deleted tree and
|
||||
produced a truncated archive - with no error. It surfaced first as a flaky
|
||||
test (`TestBuildSupportBundleIncludesExportDirContents` vs the webui
|
||||
endpoint test, run in parallel by `go test ./...`), but the same race is
|
||||
reachable in production.
|
||||
|
||||
## Decision
|
||||
|
||||
`BuildSupportBundle` creates a private parent with
|
||||
`os.MkdirTemp(os.TempDir(), "bee-support-build-")` and stages inside it. The
|
||||
leaf directory keeps the meaningful `bee-support-stage-<hostname>-<ts>` name
|
||||
(it becomes the archive's top-level directory). `defer os.RemoveAll` targets
|
||||
the unique parent. The output archive is created with `os.CreateTemp`, retaining
|
||||
the human-readable prefix while guaranteeing a unique file for each concurrent
|
||||
build. It is written under a non-published `.partial` suffix and atomically
|
||||
renamed to `.tar.gz` only after tar, gzip, and file closes succeed, so retention
|
||||
cleanup can only see completed archives.
|
||||
|
||||
Tests that exercise the real `BuildSupportBundle` set
|
||||
`t.Setenv("TMPDIR", t.TempDir())` so each test's `os.TempDir()` - staging
|
||||
parent, archive path, and the `cleanupOldSupportBundles` scan - is isolated
|
||||
from parallel packages.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Concurrent support-bundle builds are independent; neither can truncate the
|
||||
other.
|
||||
- DO NOT reintroduce a time-derived or otherwise non-unique staging path.
|
||||
See `architecture/runtime-flows.md` (Blackbox sync flow invariants).
|
||||
- The archive file itself still lands in `os.TempDir()` under a
|
||||
human-readable `SupportBundleBaseName` prefix (callers `defer os.Remove` it),
|
||||
with a random suffix preventing same-second writers from sharing one inode.
|
||||
- Tar, gzip, source-file, and destination-file close failures are propagated;
|
||||
an incomplete archive is removed instead of being returned as successful.
|
||||
- DMI-derived version/model/serial components are sanitized before becoming
|
||||
path components.
|
||||
@@ -15,3 +15,4 @@ One file per decision, named `YYYY-MM-DD-short-topic.md`.
|
||||
| 2026-08-31 | nvbandwidth: single all-GPU pass in Validate, per-socket matrix only in deep tier | active |
|
||||
| 2026-08-31 | bee-nvidia.service: never blocking `systemctl restart` on units ordered After= itself | active |
|
||||
| 2026-08-31 | "Run All" SAT planning happens on the backend, not the browser | active |
|
||||
| 2026-08-31 | Support bundle uses private staging and unique atomic output | active |
|
||||
|
||||
Reference in New Issue
Block a user