R-569: stack-lifecycle handlers pick their status by error KIND, not English words
stop/start/restart/update, remove and delete matched "protected", "not found", "not deployed", "still running", "not orphaned" in err.Error(). New sentinels in internal/stacks (stack_errors.go) carried by the producers in manager.go/delete.go via util.KindErrorf (message bytes unchanged); api.stackOpStatusFor maps them. Tests: reworded-message table per family, wiring check over all three handlers, producers keep kind + words. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -269,12 +269,12 @@ func (m *Manager) DeleteStack(name string, removeHDDData bool) (*DeleteResponse,
|
||||
|
||||
// Safety: never delete protected stacks
|
||||
if m.cfg.IsProtectedStack(name) {
|
||||
return nil, fmt.Errorf("stack %q is protected and cannot be deleted", name)
|
||||
return nil, util.KindErrorf(ErrProtectedStack, "stack %q is protected and cannot be deleted", name)
|
||||
}
|
||||
|
||||
stack, ok := m.GetStack(name)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("stack %q not found", name)
|
||||
return nil, util.KindErrorf(ErrStackNotFound, "stack %q not found", name)
|
||||
}
|
||||
|
||||
if m.isDebug() {
|
||||
@@ -284,7 +284,7 @@ func (m *Manager) DeleteStack(name string, removeHDDData bool) (*DeleteResponse,
|
||||
|
||||
// Must be orphaned
|
||||
if !stack.Orphaned {
|
||||
return nil, fmt.Errorf("stack %q is not orphaned — only orphaned stacks can be deleted", name)
|
||||
return nil, util.KindErrorf(ErrNotOrphaned, "stack %q is not orphaned — only orphaned stacks can be deleted", name)
|
||||
}
|
||||
|
||||
// Must not be deploying (H2 fix)
|
||||
@@ -296,7 +296,7 @@ func (m *Manager) DeleteStack(name string, removeHDDData bool) (*DeleteResponse,
|
||||
// StateDegraded (R-51) counts as running here: a degraded stack still has LIVE containers, and
|
||||
// deleting its directory out from under them would leave orphans behind.
|
||||
if stack.State == StateRunning || stack.State == StateStarting || stack.State == StateRestarting || stack.State == StateDegraded {
|
||||
return nil, fmt.Errorf("stack %q is still running — stop it first before deleting", name)
|
||||
return nil, util.KindErrorf(ErrStillRunning, "stack %q is still running — stop it first before deleting", name)
|
||||
}
|
||||
|
||||
stackDir := filepath.Dir(stack.ComposePath)
|
||||
@@ -417,7 +417,7 @@ func (m *Manager) DeleteStack(name string, removeHDDData bool) (*DeleteResponse,
|
||||
func (m *Manager) GetStackHDDData(name string) (*HDDDataResponse, error) {
|
||||
stack, ok := m.GetStack(name)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("stack %q not found", name)
|
||||
return nil, util.KindErrorf(ErrStackNotFound, "stack %q not found", name)
|
||||
}
|
||||
|
||||
// R-442: the app's own recorded HDD_PATH, not the global config (which no box sets).
|
||||
@@ -577,12 +577,12 @@ func (m *Manager) RemoveStack(name string, removeHDDData bool, backupPathsToRemo
|
||||
|
||||
// Safety: never remove protected stacks
|
||||
if m.cfg.IsProtectedStack(name) {
|
||||
return nil, fmt.Errorf("stack %q is protected and cannot be removed", name)
|
||||
return nil, util.KindErrorf(ErrProtectedStack, "stack %q is protected and cannot be removed", name)
|
||||
}
|
||||
|
||||
stack, ok := m.GetStack(name)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("stack %q not found", name)
|
||||
return nil, util.KindErrorf(ErrStackNotFound, "stack %q not found", name)
|
||||
}
|
||||
|
||||
if m.isDebug() {
|
||||
@@ -601,7 +601,7 @@ func (m *Manager) RemoveStack(name string, removeHDDData bool, backupPathsToRemo
|
||||
if !stack.Deployed {
|
||||
half, why := m.halfStateEvidence(name, stack)
|
||||
if !half {
|
||||
return nil, fmt.Errorf("stack %q is not deployed", name)
|
||||
return nil, util.KindErrorf(ErrNotDeployed, "stack %q is not deployed", name)
|
||||
}
|
||||
m.logger.Printf("[WARN] [stacks] RemoveStack %s: deployed=false but %s — removing what exists (R-634)", name, why)
|
||||
}
|
||||
@@ -632,7 +632,7 @@ func (m *Manager) RemoveStack(name string, removeHDDData bool, backupPathsToRemo
|
||||
// StateDegraded (R-51) counts as running here: a degraded stack still has LIVE containers, and
|
||||
// deleting its directory out from under them would leave orphans behind.
|
||||
if stack.State == StateRunning || stack.State == StateStarting || stack.State == StateRestarting || stack.State == StateDegraded {
|
||||
return nil, fmt.Errorf("stack %q is still running — stop it first before removing", name)
|
||||
return nil, util.KindErrorf(ErrStillRunning, "stack %q is still running — stop it first before removing", name)
|
||||
}
|
||||
|
||||
stackDir := filepath.Dir(stack.ComposePath)
|
||||
@@ -830,7 +830,7 @@ func (m *Manager) RemoveStack(name string, removeHDDData bool, backupPathsToRemo
|
||||
func (m *Manager) GetStackBackupData(name string, drivePath string, mirrorDirs []string) (*BackupDataResponse, error) {
|
||||
_, ok := m.GetStack(name)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("stack %q not found", name)
|
||||
return nil, util.KindErrorf(ErrStackNotFound, "stack %q not found", name)
|
||||
}
|
||||
|
||||
resp := &BackupDataResponse{
|
||||
|
||||
Reference in New Issue
Block a user