Files

222 lines
5.0 KiB
Go
Raw Permalink Normal View History

2026-07-27 14:41:04 +02:00
package models
import (
"errors"
"fmt"
"time"
)
func GetLocalNode() NodeInfo {
mu.RLock()
defer mu.RUnlock()
return cfg.Node
}
func UpdateLocalNode(n NodeInfo) error {
mu.Lock()
defer mu.Unlock()
if n.Hostname != "" {
cfg.Node.Hostname = n.Hostname
}
if n.Description != "" {
cfg.Node.Description = n.Description
}
if n.ResticPassword != "" {
cfg.Node.ResticPassword = n.ResticPassword
}
return persist()
}
// GetResticPassword returns the node-wide restic repository password used to
// encrypt/decrypt every restic backup target on this node.
func GetResticPassword() string {
mu.RLock()
defer mu.RUnlock()
return cfg.Node.ResticPassword
}
func GetUpdateHistory() []UpdateRecord {
mu.RLock()
defer mu.RUnlock()
result := make([]UpdateRecord, len(cfg.Node.UpdateHistory))
copy(result, cfg.Node.UpdateHistory)
return result
}
func GetUpdateRecord(id string) (UpdateRecord, error) {
mu.RLock()
defer mu.RUnlock()
for _, r := range cfg.Node.UpdateHistory {
if r.ID == id {
return r, nil
}
}
return UpdateRecord{}, errors.New("update record not found")
}
func AddUpdateRecord(r UpdateRecord) (UpdateRecord, error) {
mu.Lock()
defer mu.Unlock()
r.ID = fmt.Sprintf("upd_%d", time.Now().UnixNano())
r.Timestamp = time.Now().UTC()
cfg.Node.UpdateHistory = append(cfg.Node.UpdateHistory, r)
return r, persist()
}
func DeleteUpdateRecord(id string) error {
mu.Lock()
defer mu.Unlock()
for i, r := range cfg.Node.UpdateHistory {
if r.ID == id {
cfg.Node.UpdateHistory = append(cfg.Node.UpdateHistory[:i], cfg.Node.UpdateHistory[i+1:]...)
return persist()
}
}
return errors.New("update record not found")
}
func GetNodeBackupConfig() BackupConfig {
mu.RLock()
defer mu.RUnlock()
return cfg.Node.Backup
}
func UpdateNodeBackupConfig(bc BackupConfig) error {
mu.Lock()
history := cfg.Node.Backup.History
cfg.Node.Backup = bc
cfg.Node.Backup.History = history
err := persist()
mu.Unlock()
if err != nil {
return err
}
SyncSchedule()
return nil
}
func AppendNodeBackupExecution(ex BackupExecution) error {
mu.Lock()
defer mu.Unlock()
cfg.Node.Backup.History = append(cfg.Node.Backup.History, ex)
now := time.Now().UTC()
cfg.Node.Backup.LastRun = &now
for i, t := range cfg.Node.Backup.Targets {
if t.ID == ex.TargetID {
cfg.Node.Backup.Targets[i].LastRun = &now
break
}
}
return persist()
}
// GetNodeBackupTargets lists the node's individual backup target definitions.
func GetNodeBackupTargets() []BackupTarget {
mu.RLock()
defer mu.RUnlock()
result := make([]BackupTarget, len(cfg.Node.Backup.Targets))
copy(result, cfg.Node.Backup.Targets)
return result
}
// GetNodeBackupTarget returns a single node backup target by ID.
func GetNodeBackupTarget(tid string) (BackupTarget, error) {
mu.RLock()
defer mu.RUnlock()
for _, t := range cfg.Node.Backup.Targets {
if t.ID == tid {
return t, nil
}
}
return BackupTarget{}, errors.New("backup target not found")
}
// AddNodeBackupTarget creates a new backup target definition for the node.
func AddNodeBackupTarget(t BackupTarget) (BackupTarget, error) {
if err := validateBackupTarget(t); err != nil {
return BackupTarget{}, err
}
mu.Lock()
t.ID = fmt.Sprintf("bt_%d", time.Now().UnixNano())
cfg.Node.Backup.Targets = append(cfg.Node.Backup.Targets, t)
err := persist()
mu.Unlock()
if err != nil {
return BackupTarget{}, err
}
SyncSchedule()
return t, nil
}
// UpdateNodeBackupTarget replaces an existing node backup target definition.
func UpdateNodeBackupTarget(tid string, t BackupTarget) (BackupTarget, error) {
if err := validateBackupTarget(t); err != nil {
return BackupTarget{}, err
}
mu.Lock()
found := false
for i, existing := range cfg.Node.Backup.Targets {
if existing.ID == tid {
t.ID = tid
t.LastRun = existing.LastRun
cfg.Node.Backup.Targets[i] = t
found = true
break
}
}
if !found {
mu.Unlock()
return BackupTarget{}, errors.New("backup target not found")
}
err := persist()
mu.Unlock()
if err != nil {
return BackupTarget{}, err
}
SyncSchedule()
return t, nil
}
// DeleteNodeBackupTarget removes a node backup target definition.
func DeleteNodeBackupTarget(tid string) error {
mu.Lock()
found := false
for i, t := range cfg.Node.Backup.Targets {
if t.ID == tid {
cfg.Node.Backup.Targets = append(cfg.Node.Backup.Targets[:i], cfg.Node.Backup.Targets[i+1:]...)
found = true
break
}
}
if !found {
mu.Unlock()
return errors.New("backup target not found")
}
err := persist()
mu.Unlock()
if err != nil {
return err
}
SyncSchedule()
return nil
}
// RunNodeBackup runs the node's backup for the given target IDs (nil/empty
// means all targets), appending an execution record per target.
func RunNodeBackup(targetIDs []string) error {
bc := GetNodeBackupConfig()
targets := filterTargets(bc.Targets, targetIDs)
if len(targets) == 0 {
return errors.New("no matching backup targets")
}
sourcePath := bc.SourcePath
if sourcePath == "" {
sourcePath = ConfigPath()
}
results := RunBackup("node", targets, sourcePath)
for _, ex := range results {
_ = AppendNodeBackupExecution(ex)
}
return nil
}