package report import ( "encoding/base64" "os" "time" "gitea.dooplex.hu/admin/felhom-controller/internal/backup" "gitea.dooplex.hu/admin/felhom-controller/internal/settings" ) // InfraBackup is the payload pushed to the Hub for disaster recovery. type InfraBackup struct { CustomerID string `json:"customer_id"` Domain string `json:"domain"` ControllerVersion string `json:"controller_version"` Timestamp string `json:"timestamp"` ControllerConfigB64 string `json:"controller_config_b64"` SettingsJSONB64 string `json:"settings_json_b64,omitempty"` DiskLayout backup.DiskLayout `json:"disk_layout"` DeployedStacks []InfraStack `json:"deployed_stacks"` ResticPassword string `json:"restic_password,omitempty"` CrossDrivePassword string `json:"cross_drive_password,omitempty"` } // InfraStack identifies a deployed app for disaster recovery. type InfraStack struct { Name string `json:"name"` DisplayName string `json:"display_name"` HDDPath string `json:"hdd_path,omitempty"` NeedsHDD bool `json:"needs_hdd"` } // BuildInfraBackup collects all infrastructure state for Hub backup. func BuildInfraBackup( customerID, domain, version string, controllerYAMLPath string, settingsPath string, resticPasswordFile string, systemDataPath string, sett *settings.Settings, stackProvider backup.StackDataProvider, ) (*InfraBackup, error) { ib := &InfraBackup{ CustomerID: customerID, Domain: domain, ControllerVersion: version, Timestamp: time.Now().UTC().Format(time.RFC3339), } // Read and encode controller.yaml if data, err := os.ReadFile(controllerYAMLPath); err == nil { ib.ControllerConfigB64 = base64.StdEncoding.EncodeToString(data) } // Read and encode settings.json if data, err := os.ReadFile(settingsPath); err == nil { ib.SettingsJSONB64 = base64.StdEncoding.EncodeToString(data) } // Read primary restic password if data, err := os.ReadFile(resticPasswordFile); err == nil { ib.ResticPassword = base64.StdEncoding.EncodeToString(data) } // Read cross-drive restic password if pw := sett.GetCrossDriveResticPassword(); pw != "" { ib.CrossDrivePassword = pw } // Collect disk layout from fstab + blkid ib.DiskLayout = collectDiskLayout(systemDataPath) // Collect deployed stacks deployed := stackProvider.ListDeployedStacks() for _, s := range deployed { ib.DeployedStacks = append(ib.DeployedStacks, InfraStack{ Name: s.Name, DisplayName: s.DisplayName, HDDPath: stackProvider.GetStackHDDPath(s.Name), NeedsHDD: s.NeedsHDD, }) } if ib.DeployedStacks == nil { ib.DeployedStacks = []InfraStack{} } return ib, nil }