mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-08-20 22:26:07 +00:00
Merge branch 'main' into restore-pvc-ignore-wait-for-first-consumer
This commit is contained in:
@@ -46,8 +46,9 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
repoSyncPeriod = 5 * time.Minute
|
||||
defaultMaintainFrequency = 7 * 24 * time.Hour
|
||||
repoSyncPeriod = 5 * time.Minute
|
||||
defaultMaintainFrequency = 7 * 24 * time.Hour
|
||||
defaultMaintenanceStatusQueueLength = 3
|
||||
)
|
||||
|
||||
type BackupRepoReconciler struct {
|
||||
@@ -299,9 +300,9 @@ func ensureRepo(repo *velerov1api.BackupRepository, repoManager repomanager.Mana
|
||||
}
|
||||
|
||||
func (r *BackupRepoReconciler) runMaintenanceIfDue(ctx context.Context, req *velerov1api.BackupRepository, log logrus.FieldLogger) error {
|
||||
now := r.clock.Now()
|
||||
startTime := r.clock.Now()
|
||||
|
||||
if !dueForMaintenance(req, now) {
|
||||
if !dueForMaintenance(req, startTime) {
|
||||
log.Debug("not due for maintenance")
|
||||
return nil
|
||||
}
|
||||
@@ -315,16 +316,33 @@ func (r *BackupRepoReconciler) runMaintenanceIfDue(ctx context.Context, req *vel
|
||||
if err := r.repositoryManager.PruneRepo(req); err != nil {
|
||||
log.WithError(err).Warn("error pruning repository")
|
||||
return r.patchBackupRepository(ctx, req, func(rr *velerov1api.BackupRepository) {
|
||||
rr.Status.Message = err.Error()
|
||||
updateRepoMaintenanceHistory(rr, velerov1api.BackupRepositoryMaintenanceFailed, startTime, r.clock.Now(), err.Error())
|
||||
})
|
||||
}
|
||||
|
||||
return r.patchBackupRepository(ctx, req, func(rr *velerov1api.BackupRepository) {
|
||||
rr.Status.Message = ""
|
||||
rr.Status.LastMaintenanceTime = &metav1.Time{Time: now}
|
||||
completionTime := r.clock.Now()
|
||||
rr.Status.LastMaintenanceTime = &metav1.Time{Time: completionTime}
|
||||
updateRepoMaintenanceHistory(rr, velerov1api.BackupRepositoryMaintenanceSucceeded, startTime, completionTime, "")
|
||||
})
|
||||
}
|
||||
|
||||
func updateRepoMaintenanceHistory(repo *velerov1api.BackupRepository, result velerov1api.BackupRepositoryMaintenanceResult, startTime time.Time, completionTime time.Time, message string) {
|
||||
latest := velerov1api.BackupRepositoryMaintenanceStatus{
|
||||
Result: result,
|
||||
StartTimestamp: &metav1.Time{Time: startTime},
|
||||
CompleteTimestamp: &metav1.Time{Time: completionTime},
|
||||
Message: message,
|
||||
}
|
||||
|
||||
startingPos := 0
|
||||
if len(repo.Status.RecentMaintenance) >= defaultMaintenanceStatusQueueLength {
|
||||
startingPos = len(repo.Status.RecentMaintenance) - defaultMaintenanceStatusQueueLength + 1
|
||||
}
|
||||
|
||||
repo.Status.RecentMaintenance = append(repo.Status.RecentMaintenance[startingPos:], latest)
|
||||
}
|
||||
|
||||
func dueForMaintenance(req *velerov1api.BackupRepository, now time.Time) bool {
|
||||
return req.Status.LastMaintenanceTime == nil || req.Status.LastMaintenanceTime.Add(req.Spec.MaintenanceFrequency.Duration).Before(now)
|
||||
}
|
||||
|
||||
@@ -486,3 +486,180 @@ func TestGetBackupRepositoryConfig(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateRepoMaintenanceHistory(t *testing.T) {
|
||||
standardTime := time.Now()
|
||||
|
||||
backupRepoWithoutHistory := &velerov1api.BackupRepository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: velerov1api.DefaultNamespace,
|
||||
Name: "repo",
|
||||
},
|
||||
}
|
||||
|
||||
backupRepoWithHistory := &velerov1api.BackupRepository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: velerov1api.DefaultNamespace,
|
||||
Name: "repo",
|
||||
},
|
||||
Status: velerov1api.BackupRepositoryStatus{
|
||||
RecentMaintenance: []velerov1api.BackupRepositoryMaintenanceStatus{
|
||||
{
|
||||
StartTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 24)},
|
||||
CompleteTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 23)},
|
||||
Message: "fake-history-message-1",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
backupRepoWithFullHistory := &velerov1api.BackupRepository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: velerov1api.DefaultNamespace,
|
||||
Name: "repo",
|
||||
},
|
||||
Status: velerov1api.BackupRepositoryStatus{
|
||||
RecentMaintenance: []velerov1api.BackupRepositoryMaintenanceStatus{
|
||||
{
|
||||
StartTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 24)},
|
||||
CompleteTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 23)},
|
||||
Message: "fake-history-message-2",
|
||||
},
|
||||
{
|
||||
StartTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 22)},
|
||||
CompleteTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 21)},
|
||||
Message: "fake-history-message-3",
|
||||
},
|
||||
{
|
||||
StartTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 20)},
|
||||
CompleteTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 19)},
|
||||
Message: "fake-history-message-4",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
backupRepoWithOverFullHistory := &velerov1api.BackupRepository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: velerov1api.DefaultNamespace,
|
||||
Name: "repo",
|
||||
},
|
||||
Status: velerov1api.BackupRepositoryStatus{
|
||||
RecentMaintenance: []velerov1api.BackupRepositoryMaintenanceStatus{
|
||||
{
|
||||
StartTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 24)},
|
||||
CompleteTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 23)},
|
||||
Message: "fake-history-message-5",
|
||||
},
|
||||
{
|
||||
StartTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 22)},
|
||||
CompleteTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 21)},
|
||||
Message: "fake-history-message-6",
|
||||
},
|
||||
{
|
||||
StartTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 20)},
|
||||
CompleteTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 19)},
|
||||
Message: "fake-history-message-7",
|
||||
},
|
||||
{
|
||||
StartTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 18)},
|
||||
CompleteTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 17)},
|
||||
Message: "fake-history-message-8",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
backupRepo *velerov1api.BackupRepository
|
||||
result velerov1api.BackupRepositoryMaintenanceResult
|
||||
expectedHistory []velerov1api.BackupRepositoryMaintenanceStatus
|
||||
}{
|
||||
{
|
||||
name: "empty history",
|
||||
backupRepo: backupRepoWithoutHistory,
|
||||
result: velerov1api.BackupRepositoryMaintenanceSucceeded,
|
||||
expectedHistory: []velerov1api.BackupRepositoryMaintenanceStatus{
|
||||
{
|
||||
StartTimestamp: &metav1.Time{Time: standardTime},
|
||||
CompleteTimestamp: &metav1.Time{Time: standardTime.Add(time.Hour)},
|
||||
Message: "fake-message-0",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "less than history queue length",
|
||||
backupRepo: backupRepoWithHistory,
|
||||
result: velerov1api.BackupRepositoryMaintenanceSucceeded,
|
||||
expectedHistory: []velerov1api.BackupRepositoryMaintenanceStatus{
|
||||
{
|
||||
StartTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 24)},
|
||||
CompleteTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 23)},
|
||||
Message: "fake-history-message-1",
|
||||
},
|
||||
{
|
||||
StartTimestamp: &metav1.Time{Time: standardTime},
|
||||
CompleteTimestamp: &metav1.Time{Time: standardTime.Add(time.Hour)},
|
||||
Message: "fake-message-0",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "full history",
|
||||
backupRepo: backupRepoWithFullHistory,
|
||||
result: velerov1api.BackupRepositoryMaintenanceFailed,
|
||||
expectedHistory: []velerov1api.BackupRepositoryMaintenanceStatus{
|
||||
{
|
||||
StartTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 22)},
|
||||
CompleteTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 21)},
|
||||
Message: "fake-history-message-3",
|
||||
},
|
||||
{
|
||||
StartTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 20)},
|
||||
CompleteTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 19)},
|
||||
Message: "fake-history-message-4",
|
||||
},
|
||||
{
|
||||
StartTimestamp: &metav1.Time{Time: standardTime},
|
||||
CompleteTimestamp: &metav1.Time{Time: standardTime.Add(time.Hour)},
|
||||
Message: "fake-message-0",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "over full history",
|
||||
backupRepo: backupRepoWithOverFullHistory,
|
||||
result: velerov1api.BackupRepositoryMaintenanceFailed,
|
||||
expectedHistory: []velerov1api.BackupRepositoryMaintenanceStatus{
|
||||
{
|
||||
StartTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 20)},
|
||||
CompleteTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 19)},
|
||||
Message: "fake-history-message-7",
|
||||
},
|
||||
{
|
||||
StartTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 18)},
|
||||
CompleteTimestamp: &metav1.Time{Time: standardTime.Add(-time.Hour * 17)},
|
||||
Message: "fake-history-message-8",
|
||||
},
|
||||
{
|
||||
StartTimestamp: &metav1.Time{Time: standardTime},
|
||||
CompleteTimestamp: &metav1.Time{Time: standardTime.Add(time.Hour)},
|
||||
Message: "fake-message-0",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
updateRepoMaintenanceHistory(test.backupRepo, test.result, standardTime, standardTime.Add(time.Hour), "fake-message-0")
|
||||
|
||||
for at := range test.backupRepo.Status.RecentMaintenance {
|
||||
assert.Equal(t, test.expectedHistory[at].StartTimestamp.Time, test.backupRepo.Status.RecentMaintenance[at].StartTimestamp.Time)
|
||||
assert.Equal(t, test.expectedHistory[at].CompleteTimestamp.Time, test.backupRepo.Status.RecentMaintenance[at].CompleteTimestamp.Time)
|
||||
assert.Equal(t, test.expectedHistory[at].Message, test.backupRepo.Status.RecentMaintenance[at].Message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ func (r *DataDownloadReconciler) Reconcile(ctx context.Context, req ctrl.Request
|
||||
|
||||
hostingPodLabels := map[string]string{velerov1api.DataDownloadLabel: dd.Name}
|
||||
for _, k := range util.ThirdPartyLabels {
|
||||
if v, err := nodeagent.GetLabelValue(ctx, r.kubeClient, dd.Namespace, k); err != nil {
|
||||
if v, err := nodeagent.GetLabelValue(ctx, r.kubeClient, dd.Namespace, k, kube.NodeOSLinux); err != nil {
|
||||
if err != nodeagent.ErrNodeAgentLabelNotFound {
|
||||
log.WithError(err).Warnf("Failed to check node-agent label, skip adding host pod label %s", k)
|
||||
}
|
||||
|
||||
@@ -803,6 +803,15 @@ func (r *DataUploadReconciler) setupExposeParam(du *velerov2alpha1api.DataUpload
|
||||
return nil, errors.Wrapf(err, "failed to get PVC %s/%s", du.Spec.SourceNamespace, du.Spec.SourcePVC)
|
||||
}
|
||||
|
||||
nodeOS, err := kube.GetPVCAttachingNodeOS(pvc, r.kubeClient.CoreV1(), r.kubeClient.StorageV1(), r.logger)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to get attaching node OS for PVC %s/%s", du.Spec.SourceNamespace, du.Spec.SourcePVC)
|
||||
}
|
||||
|
||||
if err := kube.HasNodeWithOS(context.Background(), nodeOS, r.kubeClient.CoreV1()); err != nil {
|
||||
return nil, errors.Wrapf(err, "no appropriate node to run data upload for PVC %s/%s", du.Spec.SourceNamespace, du.Spec.SourcePVC)
|
||||
}
|
||||
|
||||
accessMode := exposer.AccessModeFileSystem
|
||||
if pvc.Spec.VolumeMode != nil && *pvc.Spec.VolumeMode == corev1.PersistentVolumeBlock {
|
||||
accessMode = exposer.AccessModeBlock
|
||||
@@ -810,7 +819,7 @@ func (r *DataUploadReconciler) setupExposeParam(du *velerov2alpha1api.DataUpload
|
||||
|
||||
hostingPodLabels := map[string]string{velerov1api.DataUploadLabel: du.Name}
|
||||
for _, k := range util.ThirdPartyLabels {
|
||||
if v, err := nodeagent.GetLabelValue(context.Background(), r.kubeClient, du.Namespace, k); err != nil {
|
||||
if v, err := nodeagent.GetLabelValue(context.Background(), r.kubeClient, du.Namespace, k, nodeOS); err != nil {
|
||||
if err != nodeagent.ErrNodeAgentLabelNotFound {
|
||||
r.logger.WithError(err).Warnf("Failed to check node-agent label, skip adding host pod label %s", k)
|
||||
}
|
||||
@@ -831,6 +840,7 @@ func (r *DataUploadReconciler) setupExposeParam(du *velerov2alpha1api.DataUpload
|
||||
Affinity: r.loadAffinity,
|
||||
BackupPVCConfig: r.backupPVCConfig,
|
||||
Resources: r.podResources,
|
||||
NodeOS: nodeOS,
|
||||
}, nil
|
||||
}
|
||||
return nil, nil
|
||||
|
||||
@@ -59,6 +59,7 @@ import (
|
||||
velerotest "github.com/vmware-tanzu/velero/pkg/test"
|
||||
"github.com/vmware-tanzu/velero/pkg/uploader"
|
||||
"github.com/vmware-tanzu/velero/pkg/util/boolptr"
|
||||
"github.com/vmware-tanzu/velero/pkg/util/kube"
|
||||
)
|
||||
|
||||
const dataUploadName = "dataupload-1"
|
||||
@@ -187,6 +188,8 @@ func initDataUploaderReconcilerWithError(needError ...error) (*DataUploadReconci
|
||||
},
|
||||
}
|
||||
|
||||
node := builder.ForNode("fake-node").Labels(map[string]string{kube.NodeOSLabel: kube.NodeOSLinux}).Result()
|
||||
|
||||
dataPathMgr := datapath.NewManager(1)
|
||||
|
||||
now, err := time.Parse(time.RFC1123, time.RFC1123)
|
||||
@@ -229,7 +232,7 @@ func initDataUploaderReconcilerWithError(needError ...error) (*DataUploadReconci
|
||||
}
|
||||
|
||||
fakeSnapshotClient := snapshotFake.NewSimpleClientset(vsObject, vscObj)
|
||||
fakeKubeClient := clientgofake.NewSimpleClientset(daemonSet)
|
||||
fakeKubeClient := clientgofake.NewSimpleClientset(daemonSet, node)
|
||||
|
||||
return NewDataUploadReconciler(
|
||||
fakeClient,
|
||||
|
||||
Reference in New Issue
Block a user