add fallback to volume info and backup/restore describe

Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
This commit is contained in:
Lyndon-Li
2026-09-10 18:22:35 +08:00
parent 8db945a6fd
commit 6b3e7ef5dd
16 changed files with 66 additions and 16 deletions
+1
View File
@@ -0,0 +1 @@
Add fallback full to DU/DD/PVB/PVR CRs, volume info and backup/restore describe
@@ -204,6 +204,10 @@ spec:
format: date-time
nullable: true
type: string
fallbackFull:
description: FallbackFull indicates whether the incremental backup
has fallen back to full backup
type: boolean
incrementalBytes:
description: |-
IncrementalBytes holds the number of bytes new or changed since the last backup.
@@ -204,6 +204,10 @@ spec:
format: date-time
nullable: true
type: string
fallbackFull:
description: FallbackFull indicates whether the incremental restore
has fallen back to full restore
type: boolean
incrementalBytes:
description: IncrementalBytes holds the number of bytes restored incrementally
format: int64
@@ -213,6 +213,10 @@ spec:
format: date-time
nullable: true
type: string
fallbackFull:
description: FallbackFull indicates whether the incremental restore
has fallen back to full restore
type: boolean
incrementalBytes:
description: IncrementalBytes holds the number of bytes restored incrementally
since the last snapshot
@@ -195,6 +195,10 @@ spec:
as a result of the DataUpload.
nullable: true
type: object
fallbackFull:
description: FallbackFull indicates whether the incremental backup
has fallen back to full backup
type: boolean
incrementalBytes:
description: |-
IncrementalBytes holds the number of bytes new or changed since the last backup.
+3 -3
View File
@@ -93,7 +93,7 @@ type BackupVolumeInfo struct {
// How volume data is backed up, with possible values including Full and Incremental.
BackupType velerov1api.BackupType `json:"backupType,omitempty"`
// FallbackFull indicates whether the incremental backup fallbacks to full backup
// FallbackFull indicates whether the incremental backup has fallen back to full backup
FallbackFull bool `json:"fallbackFull,omitempty"`
CSISnapshotInfo *CSISnapshotInfo `json:"csiSnapshotInfo,omitempty"`
@@ -132,7 +132,7 @@ type RestoreVolumeInfo struct {
// Indicates the type of the restore, incremental or full.
RestoreType string `json:"restoreType,omitempty"`
// FallbackFull indicates whether the incremental restore fallbacks to full restore
// FallbackFull indicates whether the incremental restore has fallen back to full restore
FallbackFull bool `json:"fallbackFull,omitempty"`
CSISnapshotInfo *CSISnapshotInfo `json:"csiSnapshotInfo,omitempty"`
@@ -300,7 +300,7 @@ 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 fallbacks to full backup
// 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.
@@ -142,7 +142,7 @@ type PodVolumeBackupStatus struct {
// +nullable
AcceptedTimestamp *metav1.Time `json:"acceptedTimestamp,omitempty"`
// FallbackFull indicates whether the incremental backup fallbacks to full backup
// FallbackFull indicates whether the incremental backup has fallen back to full backup
FallbackFull bool `json:"fallbackFull,omitempty"`
}
@@ -125,7 +125,7 @@ type PodVolumeRestoreStatus struct {
// +optional
Node string `json:"node,omitempty"`
// FallbackFull indicates whether the incremental restore fallbacks to full restore
// FallbackFull indicates whether the incremental restore has fallen back to full restore
FallbackFull bool `json:"fallbackFull,omitempty"`
}
@@ -150,7 +150,7 @@ type DataDownloadStatus struct {
// +nullable
AcceptedTimestamp *metav1.Time `json:"acceptedTimestamp,omitempty"`
// FallbackFull indicates whether the incremental restore fallbacks to full restore
// FallbackFull indicates whether the incremental restore has fallen back to full restore
FallbackFull bool `json:"fallbackFull,omitempty"`
}
@@ -199,7 +199,7 @@ type DataUploadStatus struct {
// +nullable
AcceptedTimestamp *metav1.Time `json:"acceptedTimestamp,omitempty"`
// FallbackFull indicates whether the incremental backup fallbacks to full backup
// FallbackFull indicates whether the incremental backup has fallen back to full backup
FallbackFull bool `json:"fallbackFull,omitempty"`
}
+1 -1
View File
@@ -152,7 +152,7 @@ func TestOnDataUploadCompleted(t *testing.T) {
{
name: "marshal fail",
marshalErr: errors.New("fake-marshal-error"),
expectedErr: "Failed to marshal backup result { false { } 0 <nil> 0}: fake-marshal-error",
expectedErr: "Failed to marshal backup result { false { } 0 <nil> 0 false}: fake-marshal-error",
},
{
name: "succeed",
+1 -1
View File
@@ -102,7 +102,7 @@ func TestOnDataDownloadCompleted(t *testing.T) {
{
name: "marshal fail",
marshalErr: errors.New("fake-marshal-error"),
expectedErr: "Failed to marshal restore result {{ } 0 0}: fake-marshal-error",
expectedErr: "Failed to marshal restore result {{ } 0 0 false}: fake-marshal-error",
},
{
name: "succeed",
+1 -1
View File
@@ -156,7 +156,7 @@ func TestOnDataPathCompleted(t *testing.T) {
{
name: "marshal fail",
marshalErr: errors.New("fake-marshal-error"),
expectedErr: "Failed to marshal backup result { false { } 0 <nil> 0}: fake-marshal-error",
expectedErr: "Failed to marshal backup result { false { } 0 <nil> 0 false}: fake-marshal-error",
},
{
name: "succeed",
+1 -1
View File
@@ -165,7 +165,7 @@ func TestOnPvrCompleted(t *testing.T) {
{
name: "marshal fail",
marshalErr: errors.New("fake-marshal-error"),
expectedErr: "error marshaling restore result {{ } 0 0}: fake-marshal-error",
expectedErr: "error marshaling restore result {{ } 0 0 false}: fake-marshal-error",
},
{
name: "succeed",
+8 -2
View File
@@ -128,7 +128,10 @@ func snapshotSource(
log.WithError(err).Warnf("Failed to create CBT with source %v", cbtSource)
}
fallback := (len(bitmap.Errors()) > 0)
fallback := false
if !forceFull {
fallback = (len(bitmap.Errors()) > 0)
}
snap, backupSize, err := u.Backup(source, parentBackup.parentObject, bitmap.Iterator(), uploaderCfg)
if err != nil {
@@ -251,7 +254,10 @@ func Restore(ctx context.Context, blkUp Uploader, rep udmrepo.BackupRepo, snapsh
bitmap.SetFull()
}
fallback := (len(bitmap.Errors()) > 0)
fallback := false
if incremental {
fallback = (len(bitmap.Errors()) > 0)
}
destPath, err := filepath.Abs(dest)
if err != nil {
+30 -3
View File
@@ -31,6 +31,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"k8s.io/utils/ptr"
"github.com/vmware-tanzu/velero/pkg/cbtservice"
cbtservicemocks "github.com/vmware-tanzu/velero/pkg/cbtservice/mocks"
@@ -126,6 +127,7 @@ func TestBackup(t *testing.T) {
assert.Equal(t, int64(8), info.IncrementalSize)
assert.Equal(t, int64(2048), info.SnapshotSize)
assert.Equal(t, int64(len("test-block-data")), info.SourceSize)
assert.False(t, info.Fallback)
},
},
{
@@ -149,6 +151,7 @@ func TestBackup(t *testing.T) {
assert.Equal(t, int64(8), info.IncrementalSize)
assert.Equal(t, int64(len("test-block-data")), info.SnapshotSize)
assert.Equal(t, int64(len("test-block-data")), info.SourceSize)
assert.False(t, info.Fallback)
},
},
}
@@ -210,6 +213,8 @@ func TestSnapshotSource(t *testing.T) {
testCases := []struct {
name string
forceFull *bool
parentSnapshot string
setupMocks func(blkup *mockUploader, repo *udmrepomocks.BackupRepo)
expectedErrStr string
expectedSnapID string
@@ -260,7 +265,7 @@ func TestSnapshotSource(t *testing.T) {
expectedSnapID: "snap-success",
expectedSize: 512,
expectedSnapshotSize: 2048,
expectedFallback: true,
expectedFallback: false,
},
{
name: "tags from cbtSource and snapshotTags are merged onto snapshot",
@@ -278,7 +283,7 @@ func TestSnapshotSource(t *testing.T) {
expectedSnapID: "snap-tags",
expectedSize: 256,
expectedSnapshotSize: 4096,
expectedFallback: true,
expectedFallback: false,
},
{
name: "success with cbtService getting allocated blocks",
@@ -322,6 +327,23 @@ func TestSnapshotSource(t *testing.T) {
expectedSnapID: "snap-cbt-fallback",
expectedSize: 1024,
expectedSnapshotSize: 1024,
expectedFallback: false,
},
{
name: "incremental backup falls back to full when parent snapshot load fails",
forceFull: ptr.To(false),
parentSnapshot: "snap-parent",
setupMocks: func(blkup *mockUploader, repo *udmrepomocks.BackupRepo) {
repo.On("GetSnapshot", mock.Anything, udmrepo.ID("snap-parent")).
Return(udmrepo.Snapshot{}, errors.New("parent not found"))
blkup.On("Backup", mock.Anything, udmrepo.ID(""), mock.Anything, mock.Anything).
Return(udmrepo.Snapshot{TotalSize: 1024}, int64(1024), nil)
repo.On("SaveSnapshot", mock.Anything, mock.Anything).Return(udmrepo.ID("snap-inc-fallback"), nil)
repo.On("Flush", mock.Anything).Return(nil)
},
expectedSnapID: "snap-inc-fallback",
expectedSize: 1024,
expectedSnapshotSize: 1024,
expectedFallback: true,
},
}
@@ -342,10 +364,15 @@ func TestSnapshotSource(t *testing.T) {
cbtSvc = tc.cbtService(t)
}
forceFull := true
if tc.forceFull != nil {
forceFull = *tc.forceFull
}
snapID, size, snapshotSize, fallback, err := snapshotSource(
ctx, mockRepo, mockBlkup,
baseSource,
true, "",
forceFull, tc.parentSnapshot,
cbtSrc, cbtSvc,
snapshotTags, map[string]string{},
testLog(), "Block Uploader",