Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions internal/pods/pods.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,23 @@ func (m *Manager) publicHTMLMount(user string) (host, spec string) {
return host, host + ":/home/dev/public_html"
}

// hasMount reports whether the named container already has a mount at the given
// destination path. Used to detect pods created before a mount was introduced so
// ensure can recreate them. A failed inspect reports false (treat as missing).
func (m *Manager) hasMount(name, dest string) bool {
out, err := exec.Command(m.engine, "container", "inspect",
"-f", "{{range .Mounts}}{{println .Destination}}{{end}}", name).Output()
if err != nil {
return false
}
for _, line := range strings.Split(string(out), "\n") {
if strings.TrimSpace(line) == dest {
return true
}
}
return false
}

// Engine reports the active container engine.
func (m *Manager) Engine() string { return m.engine }

Expand Down Expand Up @@ -106,9 +123,21 @@ func (m *Manager) ensure(user string) (string, error) {
}
// Already exists?
if err := exec.Command(m.engine, "container", "inspect", name).Run(); err == nil {
_ = exec.Command(m.engine, "start", name).Run() // no-op if running
m.tuneApt(name)
return name, nil
// Self-heal pods created before the homepage bind existed: recreate so
// ~/public_html maps to the served dir. The named home volume persists
// across rm, so the member's files are kept. Only heal when the pod is
// idle (no live session) — never pull a running pod out from under an
// active session; a still-unbound pod heals on its next idle attach.
m.mu.Lock()
idle := m.attached[name] == 0
m.mu.Unlock()
if pubSpec != "" && idle && !m.hasMount(name, "/home/dev/public_html") {
_ = exec.Command(m.engine, "rm", "-f", name).Run() // fall through to recreate with the bind
} else {
_ = exec.Command(m.engine, "start", name).Run() // no-op if running
m.tuneApt(name)
return name, nil
}
}
args := []string{
"run", "-d",
Expand Down
Loading