mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-09-20 15:04:17 +00:00
Kopia Pod Volume Backup/Restore (#5259)
* kopia pvbr Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
This commit is contained in:
@@ -45,6 +45,8 @@ import (
|
||||
"github.com/vmware-tanzu/velero/pkg/util/kube"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/vmware-tanzu/velero/pkg/podvolume"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -506,17 +508,5 @@ func getSnapshotsInBackup(ctx context.Context, backup *velerov1api.Backup, kbCli
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
var res []repository.SnapshotIdentifier
|
||||
for _, item := range podVolumeBackups.Items {
|
||||
if item.Status.SnapshotID == "" {
|
||||
continue
|
||||
}
|
||||
res = append(res, repository.SnapshotIdentifier{
|
||||
VolumeNamespace: item.Spec.Pod.Namespace,
|
||||
BackupStorageLocation: backup.Spec.StorageLocation,
|
||||
SnapshotID: item.Status.SnapshotID,
|
||||
})
|
||||
}
|
||||
|
||||
return res, nil
|
||||
return podvolume.GetSnapshotIdentifier(podVolumeBackups), nil
|
||||
}
|
||||
|
||||
@@ -771,10 +771,12 @@ func TestGetSnapshotsInBackup(t *testing.T) {
|
||||
{
|
||||
VolumeNamespace: "ns-1",
|
||||
SnapshotID: "snap-3",
|
||||
RepositoryType: "restic",
|
||||
},
|
||||
{
|
||||
VolumeNamespace: "ns-1",
|
||||
SnapshotID: "snap-4",
|
||||
RepositoryType: "restic",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -822,6 +824,7 @@ func TestGetSnapshotsInBackup(t *testing.T) {
|
||||
{
|
||||
VolumeNamespace: "ns-1",
|
||||
SnapshotID: "snap-3",
|
||||
RepositoryType: "restic",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -32,39 +32,34 @@ import (
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/repository"
|
||||
repoconfig "github.com/vmware-tanzu/velero/pkg/repository/config"
|
||||
"github.com/vmware-tanzu/velero/pkg/restic"
|
||||
"github.com/vmware-tanzu/velero/pkg/util/kube"
|
||||
)
|
||||
|
||||
const (
|
||||
repoSyncPeriod = 5 * time.Minute
|
||||
repoSyncPeriod = 5 * time.Minute
|
||||
defaultMaintainFrequency = 7 * 24 * time.Hour
|
||||
)
|
||||
|
||||
type ResticRepoReconciler struct {
|
||||
client.Client
|
||||
namespace string
|
||||
logger logrus.FieldLogger
|
||||
clock clock.Clock
|
||||
defaultMaintenanceFrequency time.Duration
|
||||
repositoryManager repository.Manager
|
||||
namespace string
|
||||
logger logrus.FieldLogger
|
||||
clock clock.Clock
|
||||
maintenanceFrequency time.Duration
|
||||
repositoryManager repository.Manager
|
||||
}
|
||||
|
||||
func NewResticRepoReconciler(namespace string, logger logrus.FieldLogger, client client.Client,
|
||||
defaultMaintenanceFrequency time.Duration, repositoryManager repository.Manager) *ResticRepoReconciler {
|
||||
maintenanceFrequency time.Duration, repositoryManager repository.Manager) *ResticRepoReconciler {
|
||||
c := &ResticRepoReconciler{
|
||||
client,
|
||||
namespace,
|
||||
logger,
|
||||
clock.RealClock{},
|
||||
defaultMaintenanceFrequency,
|
||||
maintenanceFrequency,
|
||||
repositoryManager,
|
||||
}
|
||||
|
||||
if c.defaultMaintenanceFrequency <= 0 {
|
||||
logger.Infof("Invalid default restic maintenance frequency, setting to %v", restic.DefaultMaintenanceFrequency)
|
||||
c.defaultMaintenanceFrequency = restic.DefaultMaintenanceFrequency
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
@@ -135,7 +130,7 @@ func (r *ResticRepoReconciler) initializeRepo(ctx context.Context, req *velerov1
|
||||
rr.Status.Phase = velerov1api.BackupRepositoryPhaseNotReady
|
||||
|
||||
if rr.Spec.MaintenanceFrequency.Duration <= 0 {
|
||||
rr.Spec.MaintenanceFrequency = metav1.Duration{Duration: r.defaultMaintenanceFrequency}
|
||||
rr.Spec.MaintenanceFrequency = metav1.Duration{Duration: r.getRepositoryMaintenanceFrequency(req)}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -145,7 +140,7 @@ func (r *ResticRepoReconciler) initializeRepo(ctx context.Context, req *velerov1
|
||||
rr.Spec.ResticIdentifier = repoIdentifier
|
||||
|
||||
if rr.Spec.MaintenanceFrequency.Duration <= 0 {
|
||||
rr.Spec.MaintenanceFrequency = metav1.Duration{Duration: r.defaultMaintenanceFrequency}
|
||||
rr.Spec.MaintenanceFrequency = metav1.Duration{Duration: r.getRepositoryMaintenanceFrequency(req)}
|
||||
}
|
||||
}); err != nil {
|
||||
return err
|
||||
@@ -161,6 +156,23 @@ func (r *ResticRepoReconciler) initializeRepo(ctx context.Context, req *velerov1
|
||||
})
|
||||
}
|
||||
|
||||
func (r *ResticRepoReconciler) getRepositoryMaintenanceFrequency(req *velerov1api.BackupRepository) time.Duration {
|
||||
if r.maintenanceFrequency > 0 {
|
||||
r.logger.WithField("frequency", r.maintenanceFrequency).Info("Set user defined maintenance frequency")
|
||||
return r.maintenanceFrequency
|
||||
} else {
|
||||
frequency, err := r.repositoryManager.DefaultMaintenanceFrequency(req)
|
||||
if err != nil || frequency <= 0 {
|
||||
r.logger.WithError(err).WithField("returned frequency", frequency).Warn("Failed to get maitanance frequency, use the default one")
|
||||
frequency = defaultMaintainFrequency
|
||||
} else {
|
||||
r.logger.WithField("frequency", frequency).Info("Set matainenance according to repository suggestion")
|
||||
}
|
||||
|
||||
return frequency
|
||||
}
|
||||
}
|
||||
|
||||
// ensureRepo checks to see if a repository exists, and attempts to initialize it if
|
||||
// it does not exist. An error is returned if the repository can't be connected to
|
||||
// or initialized.
|
||||
|
||||
@@ -15,20 +15,23 @@ package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
|
||||
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
|
||||
"github.com/vmware-tanzu/velero/pkg/repository"
|
||||
repomokes "github.com/vmware-tanzu/velero/pkg/repository/mocks"
|
||||
velerotest "github.com/vmware-tanzu/velero/pkg/test"
|
||||
)
|
||||
|
||||
const defaultMaintenanceFrequency = 10 * time.Minute
|
||||
const testMaintenanceFrequency = 10 * time.Minute
|
||||
|
||||
func mockResticRepoReconciler(t *testing.T, rr *velerov1api.BackupRepository, mockOn string, arg interface{}, ret interface{}) *ResticRepoReconciler {
|
||||
mgr := &repomokes.RepositoryManager{}
|
||||
@@ -39,7 +42,7 @@ func mockResticRepoReconciler(t *testing.T, rr *velerov1api.BackupRepository, mo
|
||||
velerov1api.DefaultNamespace,
|
||||
velerotest.NewLogger(),
|
||||
velerotest.NewFakeControllerRuntimeClient(t),
|
||||
defaultMaintenanceFrequency,
|
||||
testMaintenanceFrequency,
|
||||
mgr,
|
||||
)
|
||||
}
|
||||
@@ -51,7 +54,7 @@ func mockResticRepositoryCR() *velerov1api.BackupRepository {
|
||||
Name: "repo",
|
||||
},
|
||||
Spec: velerov1api.BackupRepositorySpec{
|
||||
MaintenanceFrequency: metav1.Duration{defaultMaintenanceFrequency},
|
||||
MaintenanceFrequency: metav1.Duration{testMaintenanceFrequency},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -138,7 +141,7 @@ func TestResticRepoReconcile(t *testing.T) {
|
||||
Name: "unknown",
|
||||
},
|
||||
Spec: velerov1api.BackupRepositorySpec{
|
||||
MaintenanceFrequency: metav1.Duration{defaultMaintenanceFrequency},
|
||||
MaintenanceFrequency: metav1.Duration{testMaintenanceFrequency},
|
||||
},
|
||||
},
|
||||
expectNil: true,
|
||||
@@ -151,7 +154,7 @@ func TestResticRepoReconcile(t *testing.T) {
|
||||
Name: "repo",
|
||||
},
|
||||
Spec: velerov1api.BackupRepositorySpec{
|
||||
MaintenanceFrequency: metav1.Duration{defaultMaintenanceFrequency},
|
||||
MaintenanceFrequency: metav1.Duration{testMaintenanceFrequency},
|
||||
},
|
||||
},
|
||||
expectNil: true,
|
||||
@@ -164,7 +167,7 @@ func TestResticRepoReconcile(t *testing.T) {
|
||||
Name: "repo",
|
||||
},
|
||||
Spec: velerov1api.BackupRepositorySpec{
|
||||
MaintenanceFrequency: metav1.Duration{defaultMaintenanceFrequency},
|
||||
MaintenanceFrequency: metav1.Duration{testMaintenanceFrequency},
|
||||
},
|
||||
Status: velerov1api.BackupRepositoryStatus{
|
||||
Phase: velerov1api.BackupRepositoryPhaseNew,
|
||||
@@ -187,3 +190,53 @@ func TestResticRepoReconcile(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRepositoryMaintenanceFrequency(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
mgr repository.Manager
|
||||
repo *velerov1api.BackupRepository
|
||||
freqReturn time.Duration
|
||||
freqError error
|
||||
userDefinedFreq time.Duration
|
||||
expectFreq time.Duration
|
||||
}{
|
||||
{
|
||||
name: "user defined valid",
|
||||
userDefinedFreq: time.Duration(time.Hour),
|
||||
expectFreq: time.Duration(time.Hour),
|
||||
},
|
||||
{
|
||||
name: "repo return valid",
|
||||
freqReturn: time.Duration(time.Hour * 2),
|
||||
expectFreq: time.Duration(time.Hour * 2),
|
||||
},
|
||||
{
|
||||
name: "fall to default",
|
||||
userDefinedFreq: -1,
|
||||
freqError: errors.New("fake-error"),
|
||||
expectFreq: defaultMaintainFrequency,
|
||||
},
|
||||
{
|
||||
name: "fall to default, no freq error",
|
||||
freqReturn: -1,
|
||||
expectFreq: defaultMaintainFrequency,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
mgr := repomokes.RepositoryManager{}
|
||||
mgr.On("DefaultMaintenanceFrequency", mock.Anything).Return(test.freqReturn, test.freqError)
|
||||
reconciler := NewResticRepoReconciler(
|
||||
velerov1api.DefaultNamespace,
|
||||
velerotest.NewLogger(),
|
||||
velerotest.NewFakeControllerRuntimeClient(t),
|
||||
test.userDefinedFreq,
|
||||
&mgr,
|
||||
)
|
||||
|
||||
freq := reconciler.getRepositoryMaintenanceFrequency(test.repo)
|
||||
assert.Equal(t, test.expectFreq, freq)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user