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:
@@ -134,10 +134,10 @@ type StatusResponse struct {
|
||||
// BackupRecord mirrors the agent's hub.Backup — one whole-guest vzdump/PBS backup result. The
|
||||
// controller renders it read-only (it does NOT own whole-guest backup; the agent does).
|
||||
type BackupRecord struct {
|
||||
TargetID string `json:"target_id"` // backup storage name (e.g. "local", "felhom-pbs")
|
||||
TargetID string `json:"target_id"` // backup storage name (e.g. "local", "felhom-pbs")
|
||||
VMID int `json:"vmid"`
|
||||
Archive string `json:"archive"` // produced vzdump volid (e.g. "local:backup/vzdump-lxc-…")
|
||||
Mode string `json:"mode"` // snapshot | stop
|
||||
Archive string `json:"archive"` // produced vzdump volid (e.g. "local:backup/vzdump-lxc-…")
|
||||
Mode string `json:"mode"` // snapshot | stop
|
||||
CrashConsistent bool `json:"crash_consistent"`
|
||||
SizeBytes int64 `json:"size_bytes"`
|
||||
Success bool `json:"success"`
|
||||
@@ -368,6 +368,28 @@ func (c *Client) EjectDisk(ctx context.Context, where string) (EjectResult, erro
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// DecommissionResult mirrors POST /disks/decommission.
|
||||
type DecommissionResult struct {
|
||||
VMID int `json:"vmid"`
|
||||
Decommissioned string `json:"decommissioned"`
|
||||
DependentGuests []int `json:"dependent_guests"`
|
||||
}
|
||||
|
||||
// Decommission permanently removes a user-data drive (self-serve, non-destructive — the agent records
|
||||
// IntentDecommissioned, prunes the bind record, and unmounts; it NEVER formats). Data stays on the
|
||||
// drive. The agent role-gates to user-data and refuses a system/backup mount regardless.
|
||||
func (c *Client) Decommission(ctx context.Context, where string) (DecommissionResult, error) {
|
||||
var out DecommissionResult
|
||||
body, err := c.post(ctx, "/disks/decommission", map[string]string{"where": where})
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
if err := json.Unmarshal(body, &out); err != nil {
|
||||
return out, fmt.Errorf("agentapi: decode /disks/decommission: %w", err)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// FormatDisk asks the agent to format a device. The AGENT inspects the device and tiers it by ROLE
|
||||
// (its own classification, never the controller's claim):
|
||||
// - blank device → formatted.
|
||||
|
||||
Reference in New Issue
Block a user