B2b: decommission orchestration + missing-storage indicator + re-enroll fix (v0.65.0)
agentapi.Decommission + handleStorageDecommission (migrate-all-or-none, Change 2): migrate-then-decommission via the migration done-hook, or decommission-anyway (stop apps, keep HDD_PATH). 'Hiányzó tárhely' badge on dashboard/stacks/app card when an app's drive is decommissioned/disconnected/absent. Change 4: registerStoragePath clears the decommissioned marker on re-enroll (ClearDecommissioned had no callers). Non-hollow tests incl. mutation-proven Change-4 companion. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -151,6 +151,7 @@ func (s *Server) dashboardHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
data := s.baseData("dashboard", "Vezérlőpult")
|
||||
data["Stacks"] = deployedStacks
|
||||
data["MissingStorage"] = s.missingStorageMap(deployedStacks)
|
||||
data["RunningCount"] = running
|
||||
data["StoppedCount"] = stopped
|
||||
data["TotalCount"] = len(stackList)
|
||||
@@ -195,7 +196,9 @@ func (s *Server) dashboardHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
func (s *Server) stacksHandler(w http.ResponseWriter, r *http.Request) {
|
||||
data := s.baseData("stacks", "Alkalmazások")
|
||||
data["Stacks"] = s.stackMgr.GetStacks()
|
||||
allStacks := s.stackMgr.GetStacks()
|
||||
data["Stacks"] = allStacks
|
||||
data["MissingStorage"] = s.missingStorageMap(allStacks)
|
||||
|
||||
// Build storage label lookup for deployed apps
|
||||
storageLabels := make(map[string]string) // stack name → storage label
|
||||
@@ -486,6 +489,9 @@ func (s *Server) appDetailHandler(w http.ResponseWriter, r *http.Request, slug s
|
||||
}
|
||||
data["MigrateTargets"] = targets
|
||||
data["MigrateCurrent"] = current
|
||||
if label, missing := s.missingStorageLabel(current); missing {
|
||||
data["MissingStorageLabel"] = label
|
||||
}
|
||||
}
|
||||
|
||||
s.executeTemplate(w, r, "app_info", data)
|
||||
@@ -1116,6 +1122,41 @@ func (s *Server) appsUsingPath(storagePath string) []string {
|
||||
return appsUsingPathIn(s.stackMgr.GetStacks(), s.stackMgr.LoadAppConfigByName, storagePath)
|
||||
}
|
||||
|
||||
// missingStorageLabel reports whether a deployed app's HDD_PATH resolves to an UNAVAILABLE registry
|
||||
// path (decommissioned, disconnected, or no longer registered) and returns its human label. An app
|
||||
// with no HDD_PATH (SSD-resident) is never "missing".
|
||||
func (s *Server) missingStorageLabel(hddPath string) (string, bool) {
|
||||
if hddPath == "" {
|
||||
return "", false
|
||||
}
|
||||
for _, sp := range s.settings.GetStoragePaths() {
|
||||
if sp.Path == hddPath {
|
||||
if sp.Decommissioned || sp.Disconnected {
|
||||
return s.settings.GetStorageLabel(hddPath), true
|
||||
}
|
||||
return "", false // present + available
|
||||
}
|
||||
}
|
||||
return s.settings.GetStorageLabel(hddPath), true // not in registry → its drive is gone
|
||||
}
|
||||
|
||||
// missingStorageMap returns stack-name → storage label for every deployed app whose data drive is
|
||||
// currently unavailable (drives the "Hiányzó tárhely" dashboard/stacks/app-card indicator).
|
||||
func (s *Server) missingStorageMap(list []stacks.Stack) map[string]string {
|
||||
out := map[string]string{}
|
||||
for _, st := range list {
|
||||
if !st.Deployed {
|
||||
continue
|
||||
}
|
||||
if cfg := s.stackMgr.LoadAppConfigByName(st.Name); cfg != nil {
|
||||
if label, missing := s.missingStorageLabel(cfg.Env["HDD_PATH"]); missing {
|
||||
out[st.Name] = label
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// appsUsingPathIn is the pure core of appsUsingPath (testable without a live stacks.Manager): the
|
||||
// deployed apps whose data dir (app.yaml HDD_PATH) is exactly storagePath, by display name. This is
|
||||
// the "name the apps that break" list for the type-to-confirm wipe/eject UI.
|
||||
|
||||
Reference in New Issue
Block a user