backea/internal/backup/backup.go
2025-03-20 22:14:45 +01:00

132 lines
4.1 KiB
Go

package backup
import (
"backea/internal/mail"
"context"
"fmt"
"log"
"sync"
)
// PerformBackups executes backups for multiple services based on configuration
func PerformBackups(ctx context.Context, configPath string, serviceName string, serviceIndex string) error {
// Create backup factory
factory, err := NewBackupFactory(configPath)
if err != nil {
return err
}
// Initialize mailer
mailer := mail.NewMailer()
// Process services
if serviceName != "" {
// Process single service group or specific service
if serviceIndex != "" {
// Process specific service within a group
return processSpecificService(ctx, factory, serviceName, serviceIndex, mailer)
} else {
// Process all services in the specified group
return processServiceGroup(ctx, factory, serviceName, mailer)
}
} else {
// Process all service groups in parallel
var wg sync.WaitGroup
errs := make(chan error, len(factory.Config.Services))
for groupName := range factory.Config.Services {
wg.Add(1)
go func(group string) {
defer wg.Done()
if err := processServiceGroup(ctx, factory, group, mailer); err != nil {
log.Printf("Failed to backup service group %s: %v", group, err)
errs <- fmt.Errorf("backup failed for group %s: %w", group, err)
}
}(groupName)
}
// Wait for all backups to complete
wg.Wait()
close(errs)
// Check if any errors occurred
var lastErr error
for err := range errs {
lastErr = err
}
return lastErr
}
}
// processServiceGroup handles the backup for all services in a group
func processServiceGroup(ctx context.Context, factory *BackupFactory, groupName string, mailer *mail.Mailer) error {
// Get service group configuration
serviceGroup, exists := factory.Config.Services[groupName]
if !exists {
log.Printf("Service group not found: %s", groupName)
return nil
}
// Execute the before hook once for the entire group
if serviceGroup.Hooks.BeforeHook != "" {
log.Printf("Executing before hook for group %s: %s", groupName, serviceGroup.Hooks.BeforeHook)
if err := RunCommand(serviceGroup.Source.Path, serviceGroup.Hooks.BeforeHook); err != nil {
log.Printf("Failed to execute before hook for group %s: %v", groupName, err)
return err
}
}
// Process all services in the group in parallel
var wg sync.WaitGroup
errs := make(chan error, len(serviceGroup.BackupConfigs))
for configIndex := range serviceGroup.BackupConfigs {
wg.Add(1)
go func(group, index string) {
defer wg.Done()
if err := processSpecificService(ctx, factory, group, index, mailer); err != nil {
log.Printf("Failed to backup service %s.%s: %v", group, index, err)
errs <- fmt.Errorf("backup failed for %s.%s: %w", group, index, err)
}
}(groupName, configIndex)
}
// Wait for all backups to complete
wg.Wait()
close(errs)
// Execute the after hook once for the entire group
if serviceGroup.Hooks.AfterHook != "" {
log.Printf("Executing after hook for group %s: %s", groupName, serviceGroup.Hooks.AfterHook)
if err := RunCommand(serviceGroup.Source.Path, serviceGroup.Hooks.AfterHook); err != nil {
log.Printf("Failed to execute after hook for group %s: %v", groupName, err)
// We don't return here because we want to process the errors from the backups
}
}
// Check if any errors occurred
var lastErr error
for err := range errs {
lastErr = err
}
return lastErr
}
// processSpecificService handles the backup for a specific service in a group
func processSpecificService(ctx context.Context, factory *BackupFactory, groupName string, configIndex string, mailer *mail.Mailer) error {
// Get service configuration
serviceGroup := factory.Config.Services[groupName]
// Create the appropriate backup strategy using the factory
strategy, err := factory.CreateBackupStrategyForService(groupName, configIndex)
if err != nil {
log.Printf("Failed to create backup strategy for service %s.%s: %v", groupName, configIndex, err)
return err
}
// Create and run service
service := NewService(
fmt.Sprintf("%s.%s", groupName, configIndex),
serviceGroup.Source.Path,
strategy,
mailer,
)
return service.Backup(ctx)
}