initial commit
This commit is contained in:
@@ -0,0 +1,316 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func GetAllServices() []Service {
|
||||
mu.RLock()
|
||||
defer mu.RUnlock()
|
||||
result := make([]Service, len(cfg.Services))
|
||||
copy(result, cfg.Services)
|
||||
return result
|
||||
}
|
||||
|
||||
func GetService(id string) (Service, error) {
|
||||
mu.RLock()
|
||||
defer mu.RUnlock()
|
||||
for _, s := range cfg.Services {
|
||||
if s.ID == id {
|
||||
return s, nil
|
||||
}
|
||||
}
|
||||
return Service{}, errors.New("service not found")
|
||||
}
|
||||
|
||||
func AddService(s Service) (Service, error) {
|
||||
mu.Lock()
|
||||
s.ID = fmt.Sprintf("svc_%d", time.Now().UnixNano())
|
||||
if s.Backup != nil {
|
||||
if s.Backup.Targets == nil {
|
||||
s.Backup.Targets = []BackupTarget{}
|
||||
}
|
||||
if s.Backup.History == nil {
|
||||
s.Backup.History = []BackupExecution{}
|
||||
}
|
||||
}
|
||||
cfg.Services = append(cfg.Services, s)
|
||||
err := persist()
|
||||
mu.Unlock()
|
||||
if err != nil {
|
||||
return Service{}, err
|
||||
}
|
||||
SyncSchedule()
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func UpdateService(id string, s Service) (Service, error) {
|
||||
mu.Lock()
|
||||
found := false
|
||||
for i, svc := range cfg.Services {
|
||||
if svc.ID == id {
|
||||
s.ID = id
|
||||
if s.Backup != nil && svc.Backup != nil {
|
||||
s.Backup.History = svc.Backup.History
|
||||
}
|
||||
cfg.Services[i] = s
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
mu.Unlock()
|
||||
return Service{}, errors.New("service not found")
|
||||
}
|
||||
err := persist()
|
||||
mu.Unlock()
|
||||
if err != nil {
|
||||
return Service{}, err
|
||||
}
|
||||
SyncSchedule()
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func DeleteService(id string) error {
|
||||
mu.Lock()
|
||||
found := false
|
||||
for i, s := range cfg.Services {
|
||||
if s.ID == id {
|
||||
cfg.Services = append(cfg.Services[:i], cfg.Services[i+1:]...)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
mu.Unlock()
|
||||
return errors.New("service not found")
|
||||
}
|
||||
err := persist()
|
||||
mu.Unlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
SyncSchedule()
|
||||
return nil
|
||||
}
|
||||
|
||||
func UpdateServiceStatus(id, status string) error {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
for i, s := range cfg.Services {
|
||||
if s.ID == id {
|
||||
cfg.Services[i].Status = status
|
||||
return persist()
|
||||
}
|
||||
}
|
||||
return errors.New("service not found")
|
||||
}
|
||||
|
||||
func AppendServiceBackupExecution(id string, ex BackupExecution) error {
|
||||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
for i, s := range cfg.Services {
|
||||
if s.ID == id {
|
||||
if cfg.Services[i].Backup == nil {
|
||||
cfg.Services[i].Backup = &BackupConfig{
|
||||
Targets: []BackupTarget{},
|
||||
History: []BackupExecution{},
|
||||
}
|
||||
}
|
||||
cfg.Services[i].Backup.History = append(cfg.Services[i].Backup.History, ex)
|
||||
now := time.Now().UTC()
|
||||
cfg.Services[i].Backup.LastRun = &now
|
||||
for j, t := range cfg.Services[i].Backup.Targets {
|
||||
if t.ID == ex.TargetID {
|
||||
cfg.Services[i].Backup.Targets[j].LastRun = &now
|
||||
break
|
||||
}
|
||||
}
|
||||
return persist()
|
||||
}
|
||||
}
|
||||
return errors.New("service not found")
|
||||
}
|
||||
|
||||
// GetServiceBackupTargets lists a service's individual backup target definitions.
|
||||
func GetServiceBackupTargets(id string) ([]BackupTarget, error) {
|
||||
mu.RLock()
|
||||
defer mu.RUnlock()
|
||||
for _, s := range cfg.Services {
|
||||
if s.ID == id {
|
||||
if s.Backup == nil {
|
||||
return []BackupTarget{}, nil
|
||||
}
|
||||
result := make([]BackupTarget, len(s.Backup.Targets))
|
||||
copy(result, s.Backup.Targets)
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("service not found")
|
||||
}
|
||||
|
||||
// GetServiceBackupTarget returns a single backup target by ID for a service.
|
||||
func GetServiceBackupTarget(id, tid string) (BackupTarget, error) {
|
||||
mu.RLock()
|
||||
defer mu.RUnlock()
|
||||
for _, s := range cfg.Services {
|
||||
if s.ID == id {
|
||||
if s.Backup == nil {
|
||||
return BackupTarget{}, errors.New("backup target not found")
|
||||
}
|
||||
for _, t := range s.Backup.Targets {
|
||||
if t.ID == tid {
|
||||
return t, nil
|
||||
}
|
||||
}
|
||||
return BackupTarget{}, errors.New("backup target not found")
|
||||
}
|
||||
}
|
||||
return BackupTarget{}, errors.New("service not found")
|
||||
}
|
||||
|
||||
// AddServiceBackupTarget creates a new backup target definition for a service.
|
||||
func AddServiceBackupTarget(id string, t BackupTarget) (BackupTarget, error) {
|
||||
if err := validateBackupTarget(t); err != nil {
|
||||
return BackupTarget{}, err
|
||||
}
|
||||
mu.Lock()
|
||||
idx := -1
|
||||
for i, s := range cfg.Services {
|
||||
if s.ID == id {
|
||||
idx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if idx == -1 {
|
||||
mu.Unlock()
|
||||
return BackupTarget{}, errors.New("service not found")
|
||||
}
|
||||
if cfg.Services[idx].Backup == nil {
|
||||
cfg.Services[idx].Backup = &BackupConfig{
|
||||
Targets: []BackupTarget{},
|
||||
History: []BackupExecution{},
|
||||
}
|
||||
}
|
||||
t.ID = fmt.Sprintf("bt_%d", time.Now().UnixNano())
|
||||
cfg.Services[idx].Backup.Targets = append(cfg.Services[idx].Backup.Targets, t)
|
||||
err := persist()
|
||||
mu.Unlock()
|
||||
if err != nil {
|
||||
return BackupTarget{}, err
|
||||
}
|
||||
SyncSchedule()
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// UpdateServiceBackupTarget replaces an existing backup target definition for a service.
|
||||
func UpdateServiceBackupTarget(id, tid string, t BackupTarget) (BackupTarget, error) {
|
||||
if err := validateBackupTarget(t); err != nil {
|
||||
return BackupTarget{}, err
|
||||
}
|
||||
mu.Lock()
|
||||
svcIdx := -1
|
||||
for i, s := range cfg.Services {
|
||||
if s.ID == id {
|
||||
svcIdx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if svcIdx == -1 || cfg.Services[svcIdx].Backup == nil {
|
||||
mu.Unlock()
|
||||
return BackupTarget{}, errors.New("service not found")
|
||||
}
|
||||
found := false
|
||||
for i, existing := range cfg.Services[svcIdx].Backup.Targets {
|
||||
if existing.ID == tid {
|
||||
t.ID = tid
|
||||
t.LastRun = existing.LastRun
|
||||
cfg.Services[svcIdx].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
|
||||
}
|
||||
|
||||
// DeleteServiceBackupTarget removes a backup target definition from a service.
|
||||
func DeleteServiceBackupTarget(id, tid string) error {
|
||||
mu.Lock()
|
||||
svcIdx := -1
|
||||
for i, s := range cfg.Services {
|
||||
if s.ID == id {
|
||||
svcIdx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if svcIdx == -1 || cfg.Services[svcIdx].Backup == nil {
|
||||
mu.Unlock()
|
||||
return errors.New("service not found")
|
||||
}
|
||||
found := false
|
||||
for i, t := range cfg.Services[svcIdx].Backup.Targets {
|
||||
if t.ID == tid {
|
||||
cfg.Services[svcIdx].Backup.Targets = append(
|
||||
cfg.Services[svcIdx].Backup.Targets[:i],
|
||||
cfg.Services[svcIdx].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
|
||||
}
|
||||
|
||||
// RunServiceBackup runs a service's backup for the given target IDs (nil/empty
|
||||
// means all targets), honoring StopOnBackup, and appends an execution record
|
||||
// per target.
|
||||
func RunServiceBackup(id string, targetIDs []string) error {
|
||||
svc, err := GetService(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if svc.Backup == nil || len(svc.Backup.Targets) == 0 {
|
||||
return errors.New("no backup targets configured for this service")
|
||||
}
|
||||
targets := filterTargets(svc.Backup.Targets, targetIDs)
|
||||
if len(targets) == 0 {
|
||||
return errors.New("no matching backup targets")
|
||||
}
|
||||
sourcePath := svc.BackupFolder
|
||||
if svc.Backup.SourcePath != "" {
|
||||
sourcePath = svc.Backup.SourcePath
|
||||
}
|
||||
if svc.StopOnBackup {
|
||||
_ = StopService(svc)
|
||||
}
|
||||
results := RunBackup("svc:"+id, targets, sourcePath)
|
||||
for _, ex := range results {
|
||||
_ = AppendServiceBackupExecution(id, ex)
|
||||
}
|
||||
if svc.StopOnBackup {
|
||||
_ = StartService(svc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user