v0.21.2: Fix config apply on Docker bind mounts

os.Rename() fails with "device or resource busy" on bind-mounted files.
Fall back to direct os.WriteFile when rename fails.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-20 20:11:33 +01:00
parent 7d69d96cf3
commit 7953f657cc
2 changed files with 12 additions and 4 deletions
+3
View File
@@ -1,5 +1,8 @@
## Changelog
### v0.21.2 — Config Apply Bind Mount Fix (2026-02-20)
- **Fix config apply on Docker bind mounts**: `POST /api/config/apply` failed with "device or resource busy" because `os.Rename()` doesn't work on bind-mounted files. Now falls back to direct write when rename fails.
### v0.21.1 — Config Content Endpoint (2026-02-20)
- **`GET /api/config`**: New endpoint returning raw controller.yaml content (text/yaml). Used by Hub for live config diff and pull operations. Same auth as other config endpoints (Bearer token or session cookie).
+9 -4
View File
@@ -954,7 +954,8 @@ func (r *Router) configApply(w http.ResponseWriter, req *http.Request) {
return
}
// Atomic write: write to .tmp, then rename
// Write config: try atomic rename first, fall back to direct write
// (os.Rename fails on Docker bind mounts with "device or resource busy")
tmpPath := r.configPath + ".tmp"
if err := os.WriteFile(tmpPath, body, 0644); err != nil {
r.logger.Printf("[ERROR] Config apply: failed to write temp file: %v", err)
@@ -964,9 +965,13 @@ func (r *Router) configApply(w http.ResponseWriter, req *http.Request) {
if err := os.Rename(tmpPath, r.configPath); err != nil {
os.Remove(tmpPath)
r.logger.Printf("[ERROR] Config apply: failed to rename temp file: %v", err)
writeJSON(w, http.StatusInternalServerError, apiResponse{OK: false, Error: "failed to apply config"})
return
// Rename failed (likely Docker bind mount) — write directly
if err := os.WriteFile(r.configPath, body, 0644); err != nil {
r.logger.Printf("[ERROR] Config apply: failed to write config: %v", err)
writeJSON(w, http.StatusInternalServerError, apiResponse{OK: false, Error: "failed to apply config"})
return
}
r.logger.Printf("[API] Config apply: rename failed, wrote directly (bind mount)")
}
r.logger.Printf("[API] Config applied from Hub (%d bytes), restart needed to take effect", len(body))