mirror of
https://github.com/garethgeorge/backrest.git
synced 2025-12-12 16:55:39 +00:00
122 lines
2.7 KiB
Go
122 lines
2.7 KiB
Go
package orchestrator
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"sync"
|
|
|
|
v1 "github.com/garethgeorge/resticui/gen/go/v1"
|
|
"github.com/garethgeorge/resticui/internal/config"
|
|
"github.com/garethgeorge/resticui/pkg/restic"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
var ErrRepoNotFound = errors.New("repo not found")
|
|
var ErrRepoInitializationFailed = errors.New("repo initialization failed")
|
|
var ErrPlanNotFound = errors.New("plan not found")
|
|
|
|
|
|
|
|
// Orchestrator is responsible for managing repos and backups.
|
|
type Orchestrator struct {
|
|
configProvider config.ConfigStore
|
|
repoPool *resticRepoPool
|
|
}
|
|
|
|
func NewOrchestrator(configProvider config.ConfigStore) *Orchestrator {
|
|
return &Orchestrator{
|
|
configProvider: configProvider,
|
|
repoPool: newResticRepoPool(configProvider),
|
|
}
|
|
}
|
|
|
|
func (o *Orchestrator) GetRepo(repoId string) (repo *RepoOrchestrator, err error) {
|
|
r, err := o.repoPool.GetRepo(repoId)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get repo %q: %w", repoId, err)
|
|
}
|
|
return r, nil
|
|
}
|
|
|
|
func (o *Orchestrator) GetPlan(planId string) (*v1.Plan, error) {
|
|
cfg, err := o.configProvider.Get()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get config: %w", err)
|
|
}
|
|
|
|
if cfg.Plans == nil {
|
|
return nil, ErrPlanNotFound
|
|
}
|
|
|
|
for _, p := range cfg.Plans {
|
|
if p.Id == planId {
|
|
return p, nil
|
|
}
|
|
}
|
|
|
|
return nil, ErrPlanNotFound
|
|
}
|
|
|
|
// resticRepoPool caches restic repos.
|
|
type resticRepoPool struct {
|
|
mu sync.Mutex
|
|
repos map[string]*RepoOrchestrator
|
|
configProvider config.ConfigStore
|
|
}
|
|
|
|
|
|
func newResticRepoPool(configProvider config.ConfigStore) *resticRepoPool {
|
|
return &resticRepoPool{
|
|
repos: make(map[string]*RepoOrchestrator),
|
|
configProvider: configProvider,
|
|
}
|
|
}
|
|
|
|
func (rp *resticRepoPool) GetRepo(repoId string) (repo *RepoOrchestrator, err error) {
|
|
cfg, err := rp.configProvider.Get()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to get config: %w", err)
|
|
}
|
|
|
|
rp.mu.Lock()
|
|
defer rp.mu.Unlock()
|
|
|
|
if cfg.Repos == nil {
|
|
return nil, ErrRepoNotFound
|
|
}
|
|
|
|
var repoProto *v1.Repo
|
|
for _, r := range cfg.Repos {
|
|
if r.GetId() == repoId {
|
|
repoProto = r
|
|
}
|
|
}
|
|
|
|
if repoProto == nil {
|
|
return nil, ErrRepoNotFound
|
|
}
|
|
|
|
// Check if we already have a repo for this id, if we do return it.
|
|
repo, ok := rp.repos[repoId]
|
|
if ok && proto.Equal(repo.repoConfig, repoProto) {
|
|
return repo, nil
|
|
}
|
|
delete(rp.repos, repoId);
|
|
|
|
var opts []restic.GenericOption
|
|
if len(repoProto.GetEnv()) > 0 {
|
|
opts = append(opts, restic.WithEnv(repoProto.GetEnv()...))
|
|
}
|
|
if len(repoProto.GetFlags()) > 0 {
|
|
opts = append(opts, restic.WithFlags(repoProto.GetFlags()...))
|
|
}
|
|
|
|
// Otherwise create a new repo.
|
|
repo = &RepoOrchestrator{
|
|
repoConfig: repoProto,
|
|
repo: restic.NewRepo(repoProto, opts...),
|
|
}
|
|
rp.repos[repoId] = repo
|
|
return repo, nil
|
|
}
|