146 lines
4.3 KiB
Go
146 lines
4.3 KiB
Go
package strategy
|
|
|
|
import (
|
|
"backea/internal/backup/models"
|
|
"backea/internal/backup/strategy/kopia"
|
|
"backea/internal/logging"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
)
|
|
|
|
// StrategyError represents an error in strategy operations
|
|
type StrategyError struct {
|
|
Message string
|
|
Cause error
|
|
}
|
|
|
|
func (e *StrategyError) Error() string {
|
|
if e.Cause != nil {
|
|
return e.Message + ": " + e.Cause.Error()
|
|
}
|
|
return e.Message
|
|
}
|
|
|
|
func (e *StrategyError) Unwrap() error {
|
|
return e.Cause
|
|
}
|
|
|
|
func NewStrategyError(message string, cause error) *StrategyError {
|
|
return &StrategyError{
|
|
Message: message,
|
|
Cause: cause,
|
|
}
|
|
}
|
|
|
|
// Factory handles backup strategy creation
|
|
type Factory struct {
|
|
Config *models.Configuration
|
|
ConfigPath string
|
|
logger *logging.Logger
|
|
}
|
|
|
|
// NewFactory initializes and returns a Factory
|
|
func NewFactory(configPath string) (*Factory, error) {
|
|
cfg, err := models.LoadConfig(configPath)
|
|
if err != nil {
|
|
return nil, NewStrategyError("failed to load config", err)
|
|
}
|
|
return &Factory{
|
|
Config: cfg,
|
|
ConfigPath: configPath,
|
|
logger: logging.GetLogger(),
|
|
}, nil
|
|
}
|
|
|
|
// CreateBackupStrategyForService returns a backup strategy based on config
|
|
func (f *Factory) CreateBackupStrategyForService(groupName, serviceIndex string) (Strategy, error) {
|
|
serviceConfig, err := f.getServiceConfig(groupName, serviceIndex)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
sourcePath, err := f.getServicePath(groupName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
switch serviceConfig.BackupStrategy.Type {
|
|
case "kopia":
|
|
return f.createKopiaStrategy(serviceConfig, sourcePath)
|
|
default:
|
|
return nil, NewStrategyError(fmt.Sprintf("unknown strategy type: %s", serviceConfig.BackupStrategy.Type), nil)
|
|
}
|
|
}
|
|
|
|
// createKopiaStrategy initializes a Kopia strategy
|
|
func (f *Factory) createKopiaStrategy(serviceConfig *models.BackupConfig, sourcePath string) (Strategy, error) {
|
|
provider, err := f.createKopiaProvider(serviceConfig.BackupStrategy)
|
|
if err != nil {
|
|
return nil, NewStrategyError("failed to create kopia provider", err)
|
|
}
|
|
|
|
retention := kopia.Retention(serviceConfig.BackupStrategy.Retention)
|
|
configPath := generateTempConfigPath(provider.GetProviderType())
|
|
|
|
return kopia.NewStrategy(retention, provider, configPath, sourcePath), nil
|
|
}
|
|
|
|
// createKopiaProvider returns a Kopia storage provider
|
|
func (f *Factory) createKopiaProvider(strategyConfig models.StrategyConfig) (kopia.Provider, error) {
|
|
switch strategyConfig.Provider {
|
|
case "local":
|
|
return kopia.NewLocalProvider(strategyConfig.Destination.Path), nil
|
|
|
|
case "b2", "backblaze":
|
|
return kopia.NewB2Provider(), nil
|
|
|
|
case "sftp":
|
|
host := strategyConfig.Destination.Host
|
|
basepath := strategyConfig.Destination.Path
|
|
username := strategyConfig.Destination.Username
|
|
keyFile := strategyConfig.Destination.SSHKey
|
|
return kopia.NewSFTPProvider(host, basepath, username, keyFile), nil
|
|
|
|
default:
|
|
return nil, NewStrategyError(fmt.Sprintf("unknown kopia provider type: %s", strategyConfig.Provider), nil)
|
|
}
|
|
}
|
|
|
|
// getServicePath returns a service's path
|
|
func (f *Factory) getServicePath(groupName string) (string, error) {
|
|
if serviceGroup, exists := f.Config.Services[groupName]; exists {
|
|
return serviceGroup.Source.Path, nil
|
|
}
|
|
return "", NewStrategyError(fmt.Sprintf("service group not found: %s", groupName), nil)
|
|
}
|
|
|
|
// getServiceConfig returns a service's config
|
|
func (f *Factory) getServiceConfig(groupName, serviceIndex string) (*models.BackupConfig, error) {
|
|
if serviceGroup, exists := f.Config.Services[groupName]; exists {
|
|
if backupConfig, exists := serviceGroup.BackupConfigs[serviceIndex]; exists {
|
|
return &backupConfig, nil
|
|
}
|
|
return nil, NewStrategyError(fmt.Sprintf("service index not found: %s.%s", groupName, serviceIndex), nil)
|
|
}
|
|
return nil, NewStrategyError(fmt.Sprintf("service group not found: %s", groupName), nil)
|
|
}
|
|
|
|
// ReloadConfig reloads configuration
|
|
func (f *Factory) ReloadConfig() error {
|
|
cfg, err := models.LoadConfig(f.ConfigPath)
|
|
if err != nil {
|
|
return NewStrategyError("could not reload config", err)
|
|
}
|
|
f.Config = cfg
|
|
return nil
|
|
}
|
|
|
|
// generateTempConfigPath creates a temp Kopia config path
|
|
func generateTempConfigPath(providerType string) string {
|
|
tmpConfigDir := filepath.Join(os.TempDir(), "kopia_configs")
|
|
_ = os.MkdirAll(tmpConfigDir, 0755) // Ensure directory exists
|
|
return filepath.Join(tmpConfigDir, fmt.Sprintf("kopia_%s_%d.config", providerType, time.Now().UnixNano()))
|
|
}
|