Bug bash 3: solid HUD dialogs, remote stacks deployed from the hub's shell, stopped-on-purpose is not down, the New stack dialog keeps what you typed

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Mitchell-Johnson
2026-09-20 12:30:15 -07:00
co-authored by Claude Fable 5.1
parent 634e286796
commit a446a03b7d
7 changed files with 130 additions and 21 deletions
+6 -2
View File
@@ -710,8 +710,8 @@ func (s *Server) stackAction(w http.ResponseWriter, r *http.Request) {
return fmt.Sprintf("%s exec %s%s docker compose %s %s", dockerTool(), env, priv.Quote([]string{st.Via}), flags, args)
}
env := ""
if st.Remote != "" {
env = priv.Quote([]string{"DOCKER_HOST=" + st.Remote}) + " "
if st.Remote != "" { // through env(1): a quoted NAME=value in front of a command is a command name to sh, not an assignment
env = "env " + priv.Quote([]string{"DOCKER_HOST=" + st.Remote}) + " "
}
return fmt.Sprintf("cd %s && %s%s compose %s %s", priv.Quote([]string{filepath.Dir(files[0])}), env, dockerTool(), flags, args)
}
@@ -725,6 +725,10 @@ func (s *Server) stackAction(w http.ResponseWriter, r *http.Request) {
remember += " && " + priv.Quote(priv.Wrap("cp", "-p", p, p+".hamlab-deployed"))
}
var script string
if a := r.PathValue("action"); len(st.Containers) == 0 && (a == "restart" || a == "stop" || a == "down") {
jsonErr(w, 409, st.Name+" isn't deployed: there is nothing to "+a)
return
}
switch r.PathValue("action") {
case "deploy":
script = base("up -d --remove-orphans") + remember
+10 -5
View File
@@ -176,13 +176,16 @@ func (p *statusSensors) containers(ctx context.Context, t int64) []sensors.Senso
// them apart: Docker refused to start it (State.Error: yesterday's Gitea), it is stuck
// restarting, or it died with a non-zero code that no restart policy picked up. Under
// `always` / `unless-stopped` a crash is restarted by Docker, so "exited" there means a
// person stopped it.
// person stopped it. With no restart policy, `docker stop` leaves 143 (the process took the
// SIGTERM), 137 (it didn't, and Docker killed it after the grace period) or 130 (SIGINT):
// also a person, unless the kernel did the killing for want of memory.
type stopped struct {
Name string
State struct {
Status string
ExitCode int
Error string
Status string
ExitCode int
Error string
OOMKilled bool
}
HostConfig struct{ RestartPolicy struct{ Name string } }
}
@@ -206,8 +209,10 @@ func (p *statusSensors) containers(ctx context.Context, t int64) []sensors.Senso
for _, c := range list {
pol := c.HostConfig.RestartPolicy.Name
managed := pol == "always" || pol == "unless-stopped"
code := c.State.ExitCode
byHand := (code == 130 || code == 137 || code == 143) && !c.State.OOMKilled
down[strings.TrimPrefix(c.Name, "/")] = c.State.Status == "restarting" || c.State.Status == "dead" || c.State.Error != "" ||
(!managed && c.State.Status == "exited" && c.State.ExitCode != 0)
(!managed && c.State.Status == "exited" && code != 0 && !byHand)
}
}
}