188 lines
5.7 KiB
Go
188 lines
5.7 KiB
Go
package backup
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// BackupFactory creates backup strategies and managers
|
|
type BackupFactory struct {
|
|
Config *Configuration
|
|
ConfigPath string
|
|
}
|
|
|
|
// NewBackupFactory creates a new backup factory
|
|
func NewBackupFactory(configPath string) (*BackupFactory, error) {
|
|
// Load configuration
|
|
config, err := LoadConfig(configPath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not load config: %w", err)
|
|
}
|
|
return &BackupFactory{
|
|
Config: config,
|
|
ConfigPath: configPath,
|
|
}, nil
|
|
}
|
|
|
|
// CreateKopiaStrategy creates a new Kopia backup strategy with specific retention settings and provider
|
|
func (f *BackupFactory) CreateKopiaStrategy(retention Retention, provider KopiaProvider) *KopiaStrategy {
|
|
// Create temp directory for Kopia configs if it doesn't exist
|
|
tmpConfigDir := filepath.Join(os.TempDir(), "kopia_configs")
|
|
if err := os.MkdirAll(tmpConfigDir, 0755); err != nil {
|
|
log.Printf("Warning: failed to create temp config directory: %v", err)
|
|
// Fall back to default config path
|
|
tmpConfigDir = os.TempDir()
|
|
}
|
|
|
|
// Generate a unique config file path for this instance
|
|
configPath := filepath.Join(tmpConfigDir, fmt.Sprintf("kopia_%s_%d.config",
|
|
provider.GetProviderType(), time.Now().UnixNano()))
|
|
|
|
// Need to update this line to pass configPath
|
|
return NewKopiaStrategy(retention, provider, configPath)
|
|
}
|
|
|
|
// CreateKopiaProvider creates the appropriate Kopia provider based on config
|
|
func (f *BackupFactory) CreateKopiaProvider(strategyConfig StrategyConfig) (KopiaProvider, error) {
|
|
switch strategyConfig.Provider {
|
|
case "b2_backblaze":
|
|
return NewKopiaB2Provider(), nil
|
|
case "local":
|
|
// Extract options for local path if specified
|
|
basePath := ""
|
|
if strategyConfig.Options != "" {
|
|
basePath = strategyConfig.Options
|
|
} else {
|
|
// Default to ~/.backea/repos if not specified
|
|
basePath = filepath.Join(os.Getenv("HOME"), ".backea", "repos")
|
|
}
|
|
return NewKopiaLocalProvider(basePath), nil
|
|
case "sftp":
|
|
// Parse options for SFTP - expected format: "user@host:/path/to/backups"
|
|
host := strategyConfig.Destination.Host
|
|
path := strategyConfig.Destination.Path
|
|
sshKey := strategyConfig.Destination.SSHKey
|
|
|
|
if host == "" {
|
|
return nil, fmt.Errorf("SFTP provider requires host in destination config")
|
|
}
|
|
if path == "" {
|
|
return nil, fmt.Errorf("SFTP provider requires path in destination config")
|
|
}
|
|
|
|
// Default SSH key if not specified
|
|
if sshKey == "" {
|
|
sshKey = filepath.Join(os.Getenv("HOME"), ".ssh", "id_rsa")
|
|
}
|
|
|
|
// Extract username from host if in format user@host
|
|
username := "root" // default
|
|
if hostParts := strings.Split(host, "@"); len(hostParts) > 1 {
|
|
username = hostParts[0]
|
|
host = hostParts[1]
|
|
}
|
|
|
|
return NewKopiaSFTPProvider(host, path, username, sshKey), nil
|
|
default:
|
|
return nil, fmt.Errorf("unsupported Kopia provider: %s", strategyConfig.Provider)
|
|
}
|
|
}
|
|
|
|
// CreateBackupStrategyForService creates a backup strategy for the specified service within a group
|
|
func (f *BackupFactory) CreateBackupStrategyForService(groupName string, serviceIndex string) (Strategy, error) {
|
|
// Find service group
|
|
serviceGroup, exists := f.Config.Services[groupName]
|
|
if !exists {
|
|
return nil, fmt.Errorf("service group not found: %s", groupName)
|
|
}
|
|
|
|
// Find specific backup config within the group
|
|
backupConfig, exists := serviceGroup.BackupConfigs[serviceIndex]
|
|
if !exists {
|
|
return nil, fmt.Errorf("backup config not found: %s.%s", groupName, serviceIndex)
|
|
}
|
|
|
|
// Create appropriate strategy based on type
|
|
strategyConfig := backupConfig.BackupStrategy
|
|
|
|
// Extract retention settings once
|
|
retention := Retention{
|
|
KeepLatest: strategyConfig.Retention.KeepLatest,
|
|
KeepHourly: strategyConfig.Retention.KeepHourly,
|
|
KeepDaily: strategyConfig.Retention.KeepDaily,
|
|
KeepWeekly: strategyConfig.Retention.KeepWeekly,
|
|
KeepMonthly: strategyConfig.Retention.KeepMonthly,
|
|
KeepYearly: strategyConfig.Retention.KeepYearly,
|
|
}
|
|
|
|
switch strategyConfig.Type {
|
|
case "kopia":
|
|
// Create appropriate provider based on configuration
|
|
provider, err := f.CreateKopiaProvider(strategyConfig)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to create kopia provider: %w", err)
|
|
}
|
|
return f.CreateKopiaStrategy(retention, provider), nil
|
|
case "rsync":
|
|
// Uncomment when rsync implementation is ready
|
|
// return NewRsyncStrategy(
|
|
// strategyConfig.Options,
|
|
// Destination{
|
|
// Host: strategyConfig.Destination.Host,
|
|
// Path: strategyConfig.Destination.Path,
|
|
// SSHKey: strategyConfig.Destination.SSHKey,
|
|
// },
|
|
// ), nil
|
|
fallthrough
|
|
default:
|
|
// Default to local kopia if type is unknown or rsync (temporarily)
|
|
provider, _ := f.CreateKopiaProvider(StrategyConfig{Provider: "local"})
|
|
return f.CreateKopiaStrategy(retention, provider), nil
|
|
}
|
|
}
|
|
|
|
// ExecuteGroupHooks runs the hooks for a service group
|
|
func (f *BackupFactory) ExecuteGroupHooks(groupName string, isBeforeHook bool) error {
|
|
serviceGroup, exists := f.Config.Services[groupName]
|
|
if !exists {
|
|
return fmt.Errorf("service group not found: %s", groupName)
|
|
}
|
|
|
|
var hook string
|
|
if isBeforeHook {
|
|
hook = serviceGroup.Hooks.BeforeHook
|
|
} else {
|
|
hook = serviceGroup.Hooks.AfterHook
|
|
}
|
|
|
|
if hook == "" {
|
|
return nil
|
|
}
|
|
|
|
// Execute the hook
|
|
cmd := exec.Command("sh", "-c", hook)
|
|
output, err := cmd.CombinedOutput()
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("hook execution failed: %w, output: %s", err, string(output))
|
|
}
|
|
|
|
log.Printf("Hook executed successfully: %s, output: %s", hook, string(output))
|
|
return nil
|
|
}
|
|
|
|
// ReloadConfig refreshes the configuration from the config file
|
|
func (f *BackupFactory) ReloadConfig() error {
|
|
config, err := LoadConfig(f.ConfigPath)
|
|
if err != nil {
|
|
return fmt.Errorf("could not reload config: %w", err)
|
|
}
|
|
f.Config = config
|
|
return nil
|
|
}
|