update fallbackFull in restore finalizer

Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
This commit is contained in:
Lyndon-Li
2026-09-11 16:59:51 +08:00
parent 13a630a15a
commit a827f607b5
6 changed files with 155 additions and 34 deletions
-7
View File
@@ -300,12 +300,6 @@ type PodVolumeBackupInfo struct {
// This field will be empty when the struct is used to represent a podvolumerestore.
NodeName string `json:"nodeName,omitempty"`
// FallbackFull indicates whether the incremental backup has fallen back to full backup
FallbackFull bool `json:"fallbackFull,omitempty"`
// BackupType indicates the type of the backup, incremental or full.
BackupType string `json:"backupType,omitempty"`
// The PVB's Status.Phase value
Phase velerov1api.PodVolumeBackupPhase `json:"phase,omitempty"`
}
@@ -355,7 +349,6 @@ func newPodVolumeInfoFromPVB(pvb *velerov1api.PodVolumeBackup) *PodVolumeBackupI
PodNamespace: pvb.Spec.Pod.Namespace,
NodeName: pvb.Spec.Node,
Phase: pvb.Status.Phase,
FallbackFull: pvb.Status.FallbackFull,
}
}
+89 -11
View File
@@ -730,6 +730,79 @@ func TestGenerateVolumeInfoFromPVB(t *testing.T) {
},
},
},
{
name: "PVB's volume has a PVC with fallback to full",
pvMap: map[string]pvcPvInfo{
"testPV": {
PVCName: "testPVC",
PVCNamespace: "velero",
PV: corev1api.PersistentVolume{
ObjectMeta: metav1.ObjectMeta{
Name: "testPV",
Labels: map[string]string{"a": "b"},
},
Spec: corev1api.PersistentVolumeSpec{
PersistentVolumeReclaimPolicy: corev1api.PersistentVolumeReclaimDelete,
},
},
},
},
pvb: func() *velerov1api.PodVolumeBackup {
pvb := builder.ForPodVolumeBackup("velero", "testPVB").
PodName("testPod").
PodNamespace("velero").
StartTimestamp(&now).
CompletionTimestamp(&now).
Phase(velerov1api.PodVolumeBackupPhaseCompleted).
TotalBytes(1024).
IncrementalBytes(512).
Result()
pvb.Status.FallbackFull = true
return pvb
}(),
pod: builder.ForPod("velero", "testPod").Containers(&corev1api.Container{
Name: "test",
VolumeMounts: []corev1api.VolumeMount{
{
Name: "testVolume",
MountPath: "/data",
},
},
}).Volumes(
&corev1api.Volume{
Name: "",
VolumeSource: corev1api.VolumeSource{
PersistentVolumeClaim: &corev1api.PersistentVolumeClaimVolumeSource{
ClaimName: "testPVC",
},
},
},
).Result(),
expectedVolumeInfos: []*BackupVolumeInfo{
{
PVCName: "testPVC",
PVCNamespace: "velero",
PVName: "testPV",
BackupMethod: PodVolumeBackup,
BackupType: velerov1api.BackupTypeIncremental,
FallbackFull: true,
StartTimestamp: &now,
CompletionTimestamp: &now,
Result: VolumeResultSucceeded,
PVBInfo: &PodVolumeBackupInfo{
PodName: "testPod",
PodNamespace: "velero",
Phase: velerov1api.PodVolumeBackupPhaseCompleted,
Size: 1024,
IncrementalSize: ptr.To(int64(512)),
},
PVInfo: &PVInfo{
ReclaimPolicy: string(corev1api.PersistentVolumeReclaimDelete),
Labels: map[string]string{"a": "b"},
},
},
},
},
}
for _, tc := range tests {
@@ -1095,6 +1168,7 @@ func TestRestoreVolumeInfoResult(t *testing.T) {
PVName: "testPV2",
RestoreMethod: PodVolumeRestore,
SnapshotDataMoved: false,
RestoreType: "Incremental",
PVRInfo: &PodVolumeRestoreInfo{
SnapshotHandle: "pvr-snap-001",
PodName: "testPod",
@@ -1557,17 +1631,21 @@ func TestNewPodVolumeInfoFromPVB(t *testing.T) {
}{
{
name: "all fields populated including incremental bytes",
pvb: builder.ForPodVolumeBackup("velero", "pvb-1").
SnapshotID("snap-1").
Volume("vol-1").
PodName("pod-1").
PodNamespace("ns-1").
Node("node-1").
UploaderType("kopia").
Phase(velerov1api.PodVolumeBackupPhaseCompleted).
TotalBytes(2048).
IncrementalBytes(512).
Result(),
pvb: func() *velerov1api.PodVolumeBackup {
pvb := builder.ForPodVolumeBackup("velero", "pvb-1").
SnapshotID("snap-1").
Volume("vol-1").
PodName("pod-1").
PodNamespace("ns-1").
Node("node-1").
UploaderType("kopia").
Phase(velerov1api.PodVolumeBackupPhaseCompleted).
TotalBytes(2048).
IncrementalBytes(512).
Result()
pvb.Status.FallbackFull = true
return pvb
}(),
expected: &PodVolumeBackupInfo{
SnapshotHandle: "snap-1",
Size: 2048,
+6
View File
@@ -160,6 +160,12 @@ func (d *DataDownloadBuilder) IncrementalBytes(incrementalBytes int64) *DataDown
return d
}
// FallbackFull sets the DataDownload's FallbackFull status.
func (d *DataDownloadBuilder) FallbackFull(fallbackFull bool) *DataDownloadBuilder {
d.object.Status.FallbackFull = fallbackFull
return d
}
// Node sets the DataDownload's Node.
func (d *DataDownloadBuilder) Node(node string) *DataDownloadBuilder {
d.object.Status.Node = node
+12
View File
@@ -36,6 +36,18 @@ func TestDataDownloadBuilder_Bytes(t *testing.T) {
assert.Equal(t, int64(512), *dd.Status.IncrementalBytes)
}
func TestDataDownloadBuilder_FallbackFull(t *testing.T) {
dd1 := ForDataDownload("velero", "dd-1").
FallbackFull(true).
Result()
assert.True(t, dd1.Status.FallbackFull)
dd2 := ForDataDownload("velero", "dd-2").
FallbackFull(false).
Result()
assert.False(t, dd2.Status.FallbackFull)
}
func TestPodVolumeBackupBuilder_ProgressAndBytes(t *testing.T) {
pvb1 := ForPodVolumeBackup("velero", "pvb-1").
Progress(shared.DataMoveOperationProgress{
@@ -603,6 +603,7 @@ func (ctx *finalizerContext) updateVolumeInfos() (errs results.Result) {
ctx.restoreVolumeInfos[index].SnapshotDataMovementInfo != nil {
ctx.restoreVolumeInfos[index].SnapshotDataMovementInfo.Size = dataDownload.Status.Progress.TotalBytes
ctx.restoreVolumeInfos[index].SnapshotDataMovementInfo.IncrementalSize = dataDownload.Status.IncrementalBytes
ctx.restoreVolumeInfos[index].FallbackFull = dataDownload.Status.FallbackFull
ctx.restoreVolumeInfos[index].SnapshotDataMovementInfo.Phase = dataDownload.Status.Phase
}
}
@@ -1199,17 +1199,18 @@ func TestCleanupStubVGSC(t *testing.T) {
func TestUpdateVolumeInfos(t *testing.T) {
tests := []struct {
name string
restore *velerov1api.Restore
restoreVolumeInfos []*volume.RestoreVolumeInfo
dataDownloads []*velerov2alpha1.DataDownload
listErr error
putErr error
expectedSize int64
expectedIncrSize *int64
expectedPhase velerov2alpha1.DataDownloadPhase
expectErrs bool
expectErrMsg string
name string
restore *velerov1api.Restore
restoreVolumeInfos []*volume.RestoreVolumeInfo
dataDownloads []*velerov2alpha1.DataDownload
listErr error
putErr error
expectedSize int64
expectedIncrSize *int64
expectedPhase velerov2alpha1.DataDownloadPhase
expectedFallbackFull bool
expectErrs bool
expectErrMsg string
}{
{
name: "successful update of restore volume infos from data downloads",
@@ -1238,6 +1239,16 @@ func TestUpdateVolumeInfos(t *testing.T) {
Phase: velerov2alpha1.DataDownloadPhaseCompleted,
},
},
{
PVCName: "pvc-4",
PVCNamespace: "ns-4",
FallbackFull: true,
SnapshotDataMovementInfo: &volume.RestoreSnapshotDataMovementInfo{
DataMover: "velero",
Size: 0,
Phase: "",
},
},
},
dataDownloads: []*velerov2alpha1.DataDownload{
builder.ForDataDownload("velero", "dd-1").
@@ -1246,6 +1257,7 @@ func TestUpdateVolumeInfos(t *testing.T) {
TotalBytes(4096).
IncrementalBytes(1024).
Phase(velerov2alpha1.DataDownloadPhaseCompleted).
FallbackFull(true).
Result(),
builder.ForDataDownload("velero", "dd-2").
ObjectMeta(builder.WithLabelsMap(map[string]string{velerov1api.RestoreNameLabel: "restore-1"})).
@@ -1253,6 +1265,7 @@ func TestUpdateVolumeInfos(t *testing.T) {
TotalBytes(2048).
IncrementalBytes(512).
Phase(velerov2alpha1.DataDownloadPhaseCompleted).
FallbackFull(true).
Result(),
builder.ForDataDownload("velero", "dd-other-restore").
ObjectMeta(builder.WithLabelsMap(map[string]string{velerov1api.RestoreNameLabel: "restore-other"})).
@@ -1260,12 +1273,22 @@ func TestUpdateVolumeInfos(t *testing.T) {
TotalBytes(9999).
IncrementalBytes(8888).
Phase(velerov2alpha1.DataDownloadPhaseFailed).
FallbackFull(true).
Result(),
builder.ForDataDownload("velero", "dd-4").
ObjectMeta(builder.WithLabelsMap(map[string]string{velerov1api.RestoreNameLabel: "restore-1"})).
TargetVolume(velerov2alpha1.TargetVolumeSpec{PVC: "pvc-4", Namespace: "ns-4"}).
TotalBytes(1024).
IncrementalBytes(256).
Phase(velerov2alpha1.DataDownloadPhaseCompleted).
FallbackFull(false).
Result(),
},
expectedSize: 4096,
expectedIncrSize: ptr.To(int64(1024)),
expectedPhase: velerov2alpha1.DataDownloadPhaseCompleted,
expectErrs: false,
expectedSize: 4096,
expectedIncrSize: ptr.To(int64(1024)),
expectedPhase: velerov2alpha1.DataDownloadPhaseCompleted,
expectedFallbackFull: true,
expectErrs: false,
},
{
name: "failed to list data downloads",
@@ -1350,10 +1373,18 @@ func TestUpdateVolumeInfos(t *testing.T) {
assert.Equal(t, tc.expectedSize, ctx.restoreVolumeInfos[0].SnapshotDataMovementInfo.Size)
assert.Equal(t, tc.expectedIncrSize, ctx.restoreVolumeInfos[0].SnapshotDataMovementInfo.IncrementalSize)
assert.Equal(t, tc.expectedPhase, ctx.restoreVolumeInfos[0].SnapshotDataMovementInfo.Phase)
// pvc-2 had nil SnapshotDataMovementInfo and should remain nil
assert.Equal(t, tc.expectedFallbackFull, ctx.restoreVolumeInfos[0].FallbackFull)
// pvc-2 had nil SnapshotDataMovementInfo and should remain nil, FallbackFull should remain false
assert.Nil(t, ctx.restoreVolumeInfos[1].SnapshotDataMovementInfo)
assert.False(t, ctx.restoreVolumeInfos[1].FallbackFull)
// pvc-3 belonged to another restore and should be untouched
assert.Equal(t, int64(100), ctx.restoreVolumeInfos[2].SnapshotDataMovementInfo.Size)
assert.False(t, ctx.restoreVolumeInfos[2].FallbackFull)
// pvc-4 had FallbackFull updated to false from data download
assert.Equal(t, int64(1024), ctx.restoreVolumeInfos[3].SnapshotDataMovementInfo.Size)
assert.Equal(t, ptr.To(int64(256)), ctx.restoreVolumeInfos[3].SnapshotDataMovementInfo.IncrementalSize)
assert.Equal(t, velerov2alpha1.DataDownloadPhaseCompleted, ctx.restoreVolumeInfos[3].SnapshotDataMovementInfo.Phase)
assert.False(t, ctx.restoreVolumeInfos[3].FallbackFull)
// Verify the content uploaded to backup store can be decoded and matches
require.NotEmpty(t, uploadedData)