install page: say when the host has too little swap behind the guest (R-1192 follow-up); restore record log says when a cut restore was put back; unreleased
gates / gates (push) Successful in 1m36s

This commit is contained in:
2026-10-21 22:11:16 +02:00
parent d582feb245
commit 37b79caad9
11 changed files with 78 additions and 6 deletions
+7 -1
View File
@@ -28,7 +28,13 @@
- **Fixed: `TestR603_GoNamedValuesDoNotHideBehindHTMLEscaping` was red on main since v0.337.0** (CI runs the gates, not
`go test`): two English texts added that day carried an apostrophe (`flash.kept.changed`,
`err.stacks.memory_overcommit_slow`); reworded.
- Tests (each seen failing first): `TestR1177_*` (5), `TestR1195_*` (5), `TestR1178_*`, `TestR1180_*`.
- **R-1192 follow-up — the install page says when the host has too little swap.** When the memory warning shows and
the agent (≥ the swap release) reports the host's swap below the guest's RAM, the page adds „A gépen nincs elég
cserehely (swap), ezért nagy feltöltéskor a doboz lelassulhat, és percekig sem válaszolhat. Szólj a Felhomnak, mi
rendbe tesszük." (EN „The machine has too little swap space, so during large uploads the box can slow down and not
answer for minutes. Tell Felhom; we will fix it."). An older agent is not judged (`agentapi.GuestMemoryInfo`
`host_swap_mb`/`guest_swap_mb`, 2 s timeout). The `deploy_new` i18n fixture regenerated on purpose (one line).
- Tests (each seen failing first): `TestR1177_*` (5), `TestR1195_*` (5), `TestR1178_*`, `TestR1180_*`, `TestR1192_SwapShort*`.
## v0.337.0 (2026-10-21) — kept second-drive copies (D25: R-1175, R-1181, R-1179); a `.fab` import keeps the family gate (R-1191); a stale restore temp no longer blocks the retry (R-1188 c); the overcommit sentence made true (R-1192); escrow recorded before the floor (R-1176); a finished off-site abandonment closes on the hub's word (R-1182); storage labels follow the language (W26)
+4
View File
@@ -587,6 +587,10 @@ type GuestMemoryInfo struct {
MaxMB int64 `json:"max_mb"`
FloorMB int64 `json:"floor_mb"`
Running bool `json:"running"`
// HostSwapMB / GuestSwapMB (agent ≥ the R-1192 swap release): the host's swap and this guest's swap allowance.
// nil = an older agent (not judged).
HostSwapMB *int64 `json:"host_swap_mb,omitempty"`
GuestSwapMB *int64 `json:"guest_swap_mb,omitempty"`
}
// MemoryResizeResult mirrors the agent's POST /guest/memory success body.
+6 -2
View File
@@ -102,8 +102,12 @@ func (m *Manager) LoadRestoreRecordAfterRecovery(putBack []string) *RestoreOpRes
m.opInterrupted[rec.Stack] = res
m.opRunning = false
if m.logger != nil {
m.logger.Printf("[WARN] [backup] restore of %s (%s, started %s) was INTERRUPTED by a controller stop — recorded as failed; the household is told to run it again",
rec.Stack, rec.Op, rec.StartedAt.Format(time.RFC3339))
tail := "the household is told to run it again"
if res.PutBack {
tail = "the start-up put its data back as it was before the restore (R-1195), and the household is told so"
}
m.logger.Printf("[WARN] [backup] restore of %s (%s, started %s) was INTERRUPTED by a controller stop — recorded as failed; %s",
rec.Stack, rec.Op, rec.StartedAt.Format(time.RFC3339), tail)
}
m.persistRestoreRecordLocked()
out := res
+1
View File
@@ -2823,5 +2823,6 @@
"flash.kept.changed": "Another folder is in the place of the copy now, so it was not removed.",
"flash.kept.remove_failed": "The kept copy could not be removed: %s",
"deploy.memory_overcommit_slow": "The apps' peak load can exceed the available memory. The box can then slow down during large uploads and may not answer for minutes. If this happens often, remove an app.",
"deploy.memory_swap_short": "The machine has too little swap space, so during large uploads the box can slow down and not answer for minutes. Tell Felhom; we will fix it.",
"err.stacks.memory_overcommit_slow": "The peak load of the apps can exceed the available memory. The box can then slow down during large uploads and may not answer for minutes. If this happens often, remove an app."
}
+1
View File
@@ -2811,5 +2811,6 @@
"flash.kept.changed": "A másolat helyén már egy másik mappa van, ezért nem távolítottuk el.",
"flash.kept.remove_failed": "A megőrzött másolatot nem sikerült eltávolítani: %s",
"deploy.memory_overcommit_slow": "Az alkalmazások csúcsterhelése meghaladhatja a rendelkezésre álló memóriát. Ilyenkor a doboz nagy feltöltések alatt lelassulhat, és akár percekig sem válaszol. Ha ez gyakran előfordul, távolíts el egy alkalmazást.",
"deploy.memory_swap_short": "A gépen nincs elég cserehely (swap), ezért nagy feltöltéskor a doboz lelassulhat, és percekig sem válaszolhat. Szólj a Felhomnak, mi rendbe tesszük.",
"err.stacks.memory_overcommit_slow": "Az alkalmazások csúcsterhelése meghaladhatja a rendelkezésre álló memóriát. Ilyenkor a doboz nagy feltöltések alatt lelassulhat, és akár percekig sem válaszol. Ha ez gyakran előfordul, távolíts el egy alkalmazást."
}
+5
View File
@@ -720,6 +720,11 @@ func (s *Server) deployPageData(w http.ResponseWriter, r *http.Request, name str
memInfo["UsedPercent"] = usedPercent
memInfo["Blocked"] = newReqMB > 0 && afterMB > usableMB
memInfo["OvercommitWarn"] = newLimitMB > 0 && afterLimitMB > totalMB
// R-1192 follow-up: when memory is tight, say so if the HOST has too little swap behind the guest — the
// guest swap fix then has nothing to give, and a big upload can freeze the box.
if memInfo["OvercommitWarn"] == true {
memInfo["SwapShort"] = s.hostSwapShort()
}
}
data["MemoryInfo"] = memInfo
}
+1 -1
View File
@@ -400,7 +400,7 @@ func i18nDeployData(deployed bool, st stacks.ContainerState, variant int) map[st
d["GeoAppOverride"] = true
d["AppEmailGlobalOn"] = false
d["AppEmailAppOn"] = true
d["MemoryInfo"] = map[string]interface{}{"Available": true, "Blocked": false, "OvercommitWarn": true, "AfterMB": 3000, "UsableMB": 4000,
d["MemoryInfo"] = map[string]interface{}{"Available": true, "Blocked": false, "OvercommitWarn": true, "SwapShort": true, "AfterMB": 3000, "UsableMB": 4000,
"Percent": 75, "UsedPercent": 70, "UsedMB": 2800, "NewRequestMB": 128}
d["StorageInfo"] = map[string]interface{}{"Label": "HDD egy", "Path": "/mnt/hdd1", "DataSizeHuman": "2 GB", "FreeHuman": "500 GB", "FreePercent": 50.0}
d["OtherStoragePaths"] = []string{"/mnt/hdd2"}
@@ -0,0 +1,28 @@
package web
import (
"testing"
"gitea.dooplex.hu/admin/felhom-controller/internal/agentapi"
)
// R-1192 follow-up (night 2026-10-21): the install page adds „A gépen nincs elég cserehely (swap)…" when memory is
// tight AND the agent reports the host's swap below the guest's RAM. An older agent (no number) is not judged.
// RED-PROOF: swapShort returning false always → the first case fails.
func TestR1192_SwapShortJudgesTheHostSwapAgainstTheGuestRAM(t *testing.T) {
mb := func(v int64) *int64 { return &v }
for _, c := range []struct {
name string
info agentapi.GuestMemoryInfo
want bool
}{
{"a host with no swap", agentapi.GuestMemoryInfo{AllocatedMB: 4096, HostSwapMB: mb(0)}, true},
{"a host with 2 GB swap behind a 4 GB guest", agentapi.GuestMemoryInfo{AllocatedMB: 4096, HostSwapMB: mb(2048)}, true},
{"the installer's 8 GB host (7.75 GB swap)", agentapi.GuestMemoryInfo{AllocatedMB: 4096, HostSwapMB: mb(7935)}, false},
{"an older agent (no number)", agentapi.GuestMemoryInfo{AllocatedMB: 4096}, false},
} {
if got := swapShort(c.info); got != c.want {
t.Errorf("%s: swapShort = %v, want %v", c.name, got, c.want)
}
}
}
@@ -192,3 +192,26 @@ func procMemTotalMB() int64 {
}
return 0
}
// hostSwapShort (R-1192 follow-up, night 2026-10-21) asks the agent whether the HOST's swap is below this guest's RAM
// — the guest swap fix (swap = RAM) puts a memory burst there, and a host with none gets nothing from it. False when
// it cannot tell (an older agent, an agent that does not answer within 2 s): the install page then shows only the
// overcommit sentence, as before.
func (s *Server) hostSwapShort() bool {
agent, err := s.memAgentForResize()
if err != nil || agent == nil {
return false
}
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
info, err := agent.GuestMemory(ctx)
if err != nil {
return false
}
return swapShort(info)
}
// swapShort: the host's swap is known and below the guest's RAM.
func swapShort(info agentapi.GuestMemoryInfo) bool {
return info.HostSwapMB != nil && info.AllocatedMB > 0 && *info.HostSwapMB < info.AllocatedMB
}
@@ -55,7 +55,7 @@
</div>
{{if .OvercommitWarn}}
<div class="alert alert-warning" style="margin-top:0.5rem;margin-bottom:0">
{{T "deploy.memory_overcommit_slow"}}
{{T "deploy.memory_overcommit_slow"}}{{if .SwapShort}} {{T "deploy.memory_swap_short"}}{{end}}
</div>
{{end}}
{{end}}
@@ -214,7 +214,7 @@
</div>
<div class="alert alert-warning" style="margin-top:0.5rem;margin-bottom:0">
Az alkalmazások csúcsterhelése meghaladhatja a rendelkezésre álló memóriát. Ilyenkor a doboz nagy feltöltések alatt lelassulhat, és akár percekig sem válaszol. Ha ez gyakran előfordul, távolíts el egy alkalmazást.
Az alkalmazások csúcsterhelése meghaladhatja a rendelkezésre álló memóriát. Ilyenkor a doboz nagy feltöltések alatt lelassulhat, és akár percekig sem válaszol. Ha ez gyakran előfordul, távolíts el egy alkalmazást. A gépen nincs elég cserehely (swap), ezért nagy feltöltéskor a doboz lelassulhat, és percekig sem válaszolhat. Szólj a Felhomnak, mi rendbe tesszük.
</div>