Merge branch 'main' into report-incremental-fallback

This commit is contained in:
Yonghui Li
2026-09-08 14:11:24 +08:00
14 changed files with 558 additions and 121 deletions
+1
View File
@@ -0,0 +1 @@
Add block data mover support for Velero backup/restore describe CLI.
+154 -31
View File
@@ -29,13 +29,14 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kbclient "sigs.k8s.io/controller-runtime/pkg/client"
"github.com/vmware-tanzu/velero/pkg/label"
veleroshared "github.com/vmware-tanzu/velero/pkg/apis/velero/shared"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
velerov2alpha1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
"github.com/vmware-tanzu/velero/pkg/datamover"
"github.com/vmware-tanzu/velero/pkg/features"
"github.com/vmware-tanzu/velero/pkg/itemoperation"
"github.com/vmware-tanzu/velero/pkg/kuberesource"
"github.com/vmware-tanzu/velero/pkg/label"
"github.com/vmware-tanzu/velero/pkg/util/stringptr"
)
@@ -89,11 +90,14 @@ type BackupVolumeInfo struct {
// Whether the volume data is backed up successfully.
Result VolumeResult `json:"result,omitempty"`
CSISnapshotInfo *CSISnapshotInfo `json:"csiSnapshotInfo,omitempty"`
SnapshotDataMovementInfo *SnapshotDataMovementInfo `json:"snapshotDataMovementInfo,omitempty"`
NativeSnapshotInfo *NativeSnapshotInfo `json:"nativeSnapshotInfo,omitempty"`
PVBInfo *PodVolumeInfo `json:"pvbInfo,omitempty"`
PVInfo *PVInfo `json:"pvInfo,omitempty"`
// How volume data is backed up, with possible values including Full and Incremental.
BackupType velerov1api.BackupType `json:"backupType,omitempty"`
CSISnapshotInfo *CSISnapshotInfo `json:"csiSnapshotInfo,omitempty"`
SnapshotDataMovementInfo *BackupSnapshotDataMovementInfo `json:"snapshotDataMovementInfo,omitempty"`
NativeSnapshotInfo *NativeSnapshotInfo `json:"nativeSnapshotInfo,omitempty"`
PVBInfo *PodVolumeBackupInfo `json:"pvbInfo,omitempty"`
PVInfo *PVInfo `json:"pvInfo,omitempty"`
}
type VolumeResult string
@@ -122,10 +126,10 @@ type RestoreVolumeInfo struct {
// Whether the volume's data are restored via data movement
SnapshotDataMoved bool `json:"snapshotDataMoved"`
CSISnapshotInfo *CSISnapshotInfo `json:"csiSnapshotInfo,omitempty"`
SnapshotDataMovementInfo *SnapshotDataMovementInfo `json:"snapshotDataMovementInfo,omitempty"`
NativeSnapshotInfo *NativeSnapshotInfo `json:"nativeSnapshotInfo,omitempty"`
PVRInfo *PodVolumeInfo `json:"pvrInfo,omitempty"`
CSISnapshotInfo *CSISnapshotInfo `json:"csiSnapshotInfo,omitempty"`
SnapshotDataMovementInfo *RestoreSnapshotDataMovementInfo `json:"snapshotDataMovementInfo,omitempty"`
NativeSnapshotInfo *NativeSnapshotInfo `json:"nativeSnapshotInfo,omitempty"`
PVRInfo *PodVolumeRestoreInfo `json:"pvrInfo,omitempty"`
}
// CSISnapshotInfo is used for displaying the CSI snapshot status
@@ -146,15 +150,15 @@ type CSISnapshotInfo struct {
OperationID string `json:"operationID,omitempty"`
// The VolumeSnapshot's Status.ReadyToUse value
ReadyToUse *bool
ReadyToUse *bool `json:"readyToUse,omitempty"`
// The VolumeGroupSnapshotHandle from VSC status, used to create stub VGSC during restore
// for CSI drivers that populate this field (e.g., Ceph RBD).
VolumeGroupSnapshotHandle string `json:"volumeGroupSnapshotHandle,omitempty"`
}
// SnapshotDataMovementInfo is used for displaying the snapshot data mover status.
type SnapshotDataMovementInfo struct {
// BackupSnapshotDataMovementInfo is used for displaying the backup snapshot data mover status.
type BackupSnapshotDataMovementInfo struct {
// The data mover used by the backup. The valid values are `velero` and ``(equals to `velero`).
DataMover string `json:"dataMover"`
@@ -181,8 +185,49 @@ type SnapshotDataMovementInfo struct {
// incremental and must stay distinguishable from "unknown".
IncrementalSize *int64 `json:"incrementalSize,omitempty"`
// ParentSnapshot specifies the parent snapshot that current backup is based on.
// If its value is "" or "auto", the data mover finds the recent backup of the same volume as parent.
// If its value is "none", the data mover will do a full backup
// If its value is a specific snapshotID, the data mover finds the specific snapshot as parent.
ParentSnapshot string `json:"parentSnapshot,omitempty"`
// The DataUpload's Status.Phase value
Phase velerov2alpha1.DataUploadPhase
Phase velerov2alpha1.DataUploadPhase `json:"phase"`
}
// RestoreSnapshotDataMovementInfo is used for displaying the restore snapshot data mover status.
type RestoreSnapshotDataMovementInfo struct {
// The data mover used by the backup. The valid values are `velero` and ``(equals to `velero`).
DataMover string `json:"dataMover"`
// The type of the uploader that uploads the snapshot data. The valid values are `kopia` and `restic`.
UploaderType string `json:"uploaderType"`
// The name or ID of the snapshot associated object(SAO).
// SAO is used to support local snapshots for the snapshot data mover,
// e.g. it could be a VolumeSnapshot for CSI snapshot data movement.
RetainedSnapshot string `json:"retainedSnapshot,omitempty"`
// It's the filesystem repository's snapshot ID.
SnapshotHandle string `json:"snapshotHandle"`
// The Async Operation's ID.
OperationID string `json:"operationID"`
// Moved snapshot data size.
Size int64 `json:"size"`
// Moved snapshot incremental size, i.e. the bytes actually transferred. Nil means
// the uploader reported no figure (including backups taken before this was
// recorded); a pointer to 0 means it transferred nothing, which is the ideal
// incremental and must stay distinguishable from "unknown".
IncrementalSize *int64 `json:"incrementalSize,omitempty"`
// The DataDownload's Status.Phase value
Phase velerov2alpha1.DataDownloadPhase `json:"phase"`
// Indicates the type of the restore, incremental or full.
RestoreType string `json:"restoreType,omitempty"`
}
// NativeSnapshotInfo is used for displaying the Velero native snapshot status.
@@ -203,7 +248,7 @@ type NativeSnapshotInfo struct {
IOPS string `json:"iops"`
// The NativeSnapshot's Status.Phase value
Phase SnapshotPhase
Phase SnapshotPhase `json:"phase,omitempty"`
}
func newNativeSnapshotInfo(s *Snapshot) *NativeSnapshotInfo {
@@ -220,9 +265,9 @@ func newNativeSnapshotInfo(s *Snapshot) *NativeSnapshotInfo {
}
}
// PodVolumeInfo is used for displaying the PodVolumeBackup/PodVolumeRestore snapshot status.
type PodVolumeInfo struct {
// It's the file-system uploader's snapshot ID for PodVolumeBackup/PodVolumeRestore.
// PodVolumeBackupInfo is used for displaying the PodVolumeBackup snapshot status.
type PodVolumeBackupInfo struct {
// It's the file-system uploader's snapshot ID for PodVolumeBackup.
SnapshotHandle string `json:"snapshotHandle,omitempty"`
// The snapshot corresponding volume size.
@@ -250,11 +295,47 @@ type PodVolumeInfo struct {
NodeName string `json:"nodeName,omitempty"`
// The PVB's Status.Phase value
Phase velerov1api.PodVolumeBackupPhase
Phase velerov1api.PodVolumeBackupPhase `json:"phase,omitempty"`
}
func newPodVolumeInfoFromPVB(pvb *velerov1api.PodVolumeBackup) *PodVolumeInfo {
return &PodVolumeInfo{
// PodVolumeRestoreInfo is used for displaying the PodVolumeRestore snapshot status.
type PodVolumeRestoreInfo struct {
// It's the file-system uploader's snapshot ID for PodVolumeRestore.
SnapshotHandle string `json:"snapshotHandle,omitempty"`
// The snapshot corresponding volume size.
Size int64 `json:"size,omitempty"`
// The incremental snapshot size, i.e. the bytes actually transferred. Nil means
// the uploader reported no figure; a pointer to 0 means it transferred nothing.
IncrementalSize *int64 `json:"incrementalSize,omitempty"`
// The type of the uploader that uploads the data. The valid values are `kopia` and `restic`.
UploaderType string `json:"uploaderType"`
// The PVC's corresponding volume name used by Pod
// https://github.com/kubernetes/kubernetes/blob/e4b74dd12fa8cb63c174091d5536a10b8ec19d34/pkg/apis/core/types.go#L48
VolumeName string `json:"volumeName"`
// The Pod name mounting this PVC.
PodName string `json:"podName"`
// The Pod namespace
PodNamespace string `json:"podNamespace"`
// The PVB-taken k8s node's name.
// This field will be empty when the struct is used to represent a podvolumerestore.
NodeName string `json:"nodeName,omitempty"`
// The PVR's Status.Phase value
Phase velerov1api.PodVolumeRestorePhase `json:"phase,omitempty"`
// Indicates the type of the restore, incremental or full.
RestoreType string `json:"restoreType,omitempty"`
}
func newPodVolumeInfoFromPVB(pvb *velerov1api.PodVolumeBackup) *PodVolumeBackupInfo {
return &PodVolumeBackupInfo{
SnapshotHandle: pvb.Status.SnapshotID,
Size: pvb.Status.Progress.TotalBytes,
IncrementalSize: pvb.Status.IncrementalBytes,
@@ -267,14 +348,16 @@ func newPodVolumeInfoFromPVB(pvb *velerov1api.PodVolumeBackup) *PodVolumeInfo {
}
}
func newPodVolumeInfoFromPVR(pvr *velerov1api.PodVolumeRestore) *PodVolumeInfo {
return &PodVolumeInfo{
func newPodVolumeInfoFromPVR(pvr *velerov1api.PodVolumeRestore) *PodVolumeRestoreInfo {
return &PodVolumeRestoreInfo{
SnapshotHandle: pvr.Spec.SnapshotID,
Size: pvr.Status.Progress.TotalBytes,
UploaderType: pvr.Spec.UploaderType,
VolumeName: pvr.Spec.Volume,
PodName: pvr.Spec.Pod.Name,
PodNamespace: pvr.Spec.Pod.Namespace,
Phase: pvr.Status.Phase,
RestoreType: pvr.Spec.RestoreType,
}
}
@@ -470,6 +553,11 @@ func (v *BackupVolumesInformation) generateVolumeInfoForCSIVolumeSnapshot() {
volumeGroupSnapshotHandle = *volumeSnapshotContent.Status.VolumeGroupSnapshotHandle
}
if pvcPVInfo := v.pvMap.retrieve("", *volumeSnapshot.Spec.Source.PersistentVolumeClaimName, volumeSnapshot.Namespace); pvcPVInfo != nil {
volumeResult := VolumeResultFailed
if volumeSnapshot.Status != nil && volumeSnapshot.Status.ReadyToUse != nil && *volumeSnapshot.Status.ReadyToUse {
volumeResult = VolumeResultSucceeded
}
volumeInfo := &BackupVolumeInfo{
BackupMethod: CSISnapshot,
PVCName: pvcPVInfo.PVCName,
@@ -478,6 +566,7 @@ func (v *BackupVolumesInformation) generateVolumeInfoForCSIVolumeSnapshot() {
Skipped: false,
SnapshotDataMoved: false,
PreserveLocalSnapshot: true,
Result: volumeResult,
CSISnapshotInfo: &CSISnapshotInfo{
VSCName: *volumeSnapshot.Status.BoundVolumeSnapshotContentName,
Size: size,
@@ -519,6 +608,11 @@ func (v *BackupVolumesInformation) generateVolumeInfoFromPVB() {
StartTimestamp: pvb.Status.StartTimestamp,
CompletionTimestamp: pvb.Status.CompletionTimestamp,
PVBInfo: newPodVolumeInfoFromPVB(pvb),
BackupType: velerov1api.BackupTypeIncremental,
}
if pvb.Spec.ParentSnapshot == veleroshared.ParentSnapshotNone {
volumeInfo.BackupType = velerov1api.BackupTypeFull
}
// Only set Succeeded to true when the PVB's phase is Completed.
@@ -622,6 +716,11 @@ func (v *BackupVolumesInformation) generateVolumeInfoFromDataUpload() {
dataMover = dataUpload.Spec.DataMover
}
volumeResult := VolumeResultFailed
if dataUpload.Status.Phase == velerov2alpha1.DataUploadPhaseCompleted {
volumeResult = VolumeResultSucceeded
}
volumeInfo := &BackupVolumeInfo{
BackupMethod: CSISnapshot,
PVCName: pvcPVInfo.PVCName,
@@ -629,17 +728,22 @@ func (v *BackupVolumesInformation) generateVolumeInfoFromDataUpload() {
PVName: pvcPVInfo.PV.Name,
SnapshotDataMoved: true,
Skipped: false,
Result: volumeResult,
BackupType: velerov1api.BackupTypeIncremental,
CSISnapshotInfo: &CSISnapshotInfo{
SnapshotHandle: FieldValueIsUnknown,
VSCName: FieldValueIsUnknown,
OperationID: FieldValueIsUnknown,
Driver: dataUpload.Spec.CSISnapshot.Driver,
},
SnapshotDataMovementInfo: &SnapshotDataMovementInfo{
DataMover: dataMover,
UploaderType: velerov1api.BackupRepositoryTypeKopia,
OperationID: operation.Spec.OperationID,
Phase: dataUpload.Status.Phase,
SnapshotDataMovementInfo: &BackupSnapshotDataMovementInfo{
DataMover: dataMover,
UploaderType: datamover.GetUploaderType(dataMover),
OperationID: operation.Spec.OperationID,
Phase: dataUpload.Status.Phase,
ParentSnapshot: dataUpload.Spec.ParentSnapshot,
Size: dataUpload.Status.Progress.TotalBytes,
SnapshotHandle: dataUpload.Status.SnapshotID,
},
PVInfo: &PVInfo{
ReclaimPolicy: string(pvcPVInfo.PV.Spec.PersistentVolumeReclaimPolicy),
@@ -647,10 +751,22 @@ func (v *BackupVolumesInformation) generateVolumeInfoFromDataUpload() {
},
}
if dataUpload.Spec.ParentSnapshot == veleroshared.ParentSnapshotNone {
volumeInfo.BackupType = velerov1api.BackupTypeFull
}
if dataUpload.Status.StartTimestamp != nil {
volumeInfo.StartTimestamp = dataUpload.Status.StartTimestamp
}
if dataUpload.Status.CompletionTimestamp != nil {
volumeInfo.CompletionTimestamp = dataUpload.Status.CompletionTimestamp
}
if dataUpload.Status.IncrementalBytes != nil {
volumeInfo.SnapshotDataMovementInfo.IncrementalSize = dataUpload.Status.IncrementalBytes
}
tmpVolumeInfos = append(tmpVolumeInfos, volumeInfo)
} else {
v.logger.Warnf("Cannot find info for PVC %s/%s", operation.Spec.ResourceIdentifier.Namespace, operation.Spec.ResourceIdentifier.Name)
@@ -878,14 +994,21 @@ func (t *RestoreVolumeInfoTracker) Result() []*RestoreVolumeInfo {
// the datadownload was initiated in CSI plugin
// For the same reason, no CSI snapshot info will be populated into volumeInfo
RestoreMethod: CSISnapshot,
SnapshotDataMovementInfo: &SnapshotDataMovementInfo{
SnapshotDataMovementInfo: &RestoreSnapshotDataMovementInfo{
DataMover: dataMover,
UploaderType: velerov1api.BackupRepositoryTypeKopia,
UploaderType: datamover.GetUploaderType(dataMover),
SnapshotHandle: dd.Spec.SnapshotID,
OperationID: operationID,
RestoreType: dd.Spec.RestoreType,
Size: dd.Status.Progress.TotalBytes,
Phase: dd.Status.Phase,
},
}
if dd.Status.IncrementalBytes != nil {
volumeInfo.SnapshotDataMovementInfo.IncrementalSize = dd.Status.IncrementalBytes
}
volumeInfos = append(volumeInfos, volumeInfo)
}
+230 -18
View File
@@ -17,6 +17,7 @@ limitations under the License.
package volume
import (
"encoding/json"
"sync"
"testing"
@@ -30,7 +31,9 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/utils/ptr"
veleroshared "github.com/vmware-tanzu/velero/pkg/apis/velero/shared"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
velerov2alpha1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
"github.com/vmware-tanzu/velero/pkg/builder"
@@ -474,6 +477,7 @@ func TestGenerateVolumeInfoForCSIVolumeSnapshot(t *testing.T) {
PVCNamespace: "velero",
PVName: "testPV",
BackupMethod: CSISnapshot,
Result: VolumeResultSucceeded,
StartTimestamp: &now,
PreserveLocalSnapshot: true,
CSISnapshotInfo: &CSISnapshotInfo{
@@ -562,8 +566,9 @@ func TestGenerateVolumeInfoFromPVB(t *testing.T) {
PVCNamespace: "",
PVName: "",
BackupMethod: PodVolumeBackup,
BackupType: velerov1api.BackupTypeIncremental,
Result: VolumeResultFailed,
PVBInfo: &PodVolumeInfo{
PVBInfo: &PodVolumeBackupInfo{
PodName: "testPod",
PodNamespace: "velero",
},
@@ -641,10 +646,11 @@ func TestGenerateVolumeInfoFromPVB(t *testing.T) {
PVCNamespace: "velero",
PVName: "testPV",
BackupMethod: PodVolumeBackup,
BackupType: velerov1api.BackupTypeIncremental,
StartTimestamp: &now,
CompletionTimestamp: &now,
Result: VolumeResultFailed,
PVBInfo: &PodVolumeInfo{
PVBInfo: &PodVolumeBackupInfo{
PodName: "testPod",
PodNamespace: "velero",
Phase: velerov1api.PodVolumeBackupPhaseFailed,
@@ -704,10 +710,11 @@ func TestGenerateVolumeInfoFromPVB(t *testing.T) {
PVCNamespace: "velero",
PVName: "testPV",
BackupMethod: PodVolumeBackup,
BackupType: velerov1api.BackupTypeIncremental,
StartTimestamp: &now,
CompletionTimestamp: &now,
Result: VolumeResultSucceeded,
PVBInfo: &PodVolumeInfo{
PVBInfo: &PodVolumeBackupInfo{
PodName: "testPod",
PodNamespace: "velero",
Phase: velerov1api.PodVolumeBackupPhaseCompleted,
@@ -838,6 +845,9 @@ func TestGenerateVolumeInfoFromDataUpload(t *testing.T) {
Driver: "pd.csi.storage.gke.io",
}).SnapshotID("testSnapshotHandle").
StartTimestamp(&now).
CompletionTimestamp(&now).
TotalBytes(1024).
IncrementalBytes(512).
Phase(velerov2alpha1.DataUploadPhaseCompleted).
Result(),
vs: builder.ForVolumeSnapshot(velerov1api.DefaultNamespace, "vs-01").Status().BoundVolumeSnapshotContentName("vsc-01").Result(),
@@ -882,12 +892,15 @@ func TestGenerateVolumeInfoFromDataUpload(t *testing.T) {
},
expectedVolumeInfos: []*BackupVolumeInfo{
{
PVCName: "testPVC",
PVCNamespace: "velero",
PVName: "testPV",
BackupMethod: CSISnapshot,
SnapshotDataMoved: true,
StartTimestamp: &now,
PVCName: "testPVC",
PVCNamespace: "velero",
PVName: "testPV",
BackupMethod: CSISnapshot,
SnapshotDataMoved: true,
BackupType: velerov1api.BackupTypeIncremental,
Result: VolumeResultSucceeded,
StartTimestamp: &now,
CompletionTimestamp: &now,
CSISnapshotInfo: &CSISnapshotInfo{
VSCName: FieldValueIsUnknown,
SnapshotHandle: FieldValueIsUnknown,
@@ -895,11 +908,14 @@ func TestGenerateVolumeInfoFromDataUpload(t *testing.T) {
Size: 0,
Driver: "pd.csi.storage.gke.io",
},
SnapshotDataMovementInfo: &SnapshotDataMovementInfo{
DataMover: "velero",
UploaderType: "kopia",
OperationID: "testOperation",
Phase: velerov2alpha1.DataUploadPhaseCompleted,
SnapshotDataMovementInfo: &BackupSnapshotDataMovementInfo{
DataMover: "velero",
UploaderType: "kopia",
OperationID: "testOperation",
Phase: velerov2alpha1.DataUploadPhaseCompleted,
SnapshotHandle: "testSnapshotHandle",
Size: 1024,
IncrementalSize: ptr.To(int64(512)),
},
PVInfo: &PVInfo{
ReclaimPolicy: string(corev1api.PersistentVolumeReclaimDelete),
@@ -947,6 +963,19 @@ func TestGenerateVolumeInfoFromDataUpload(t *testing.T) {
require.Equal(t, tc.expectedVolumeInfos[0].PVInfo, volumesInfo.volumeInfos[0].PVInfo)
require.Equal(t, tc.expectedVolumeInfos[0].SnapshotDataMovementInfo, volumesInfo.volumeInfos[0].SnapshotDataMovementInfo)
require.Equal(t, tc.expectedVolumeInfos[0].CSISnapshotInfo, volumesInfo.volumeInfos[0].CSISnapshotInfo)
require.Equal(t, tc.expectedVolumeInfos[0].Result, volumesInfo.volumeInfos[0].Result)
if tc.expectedVolumeInfos[0].StartTimestamp != nil {
require.NotNil(t, volumesInfo.volumeInfos[0].StartTimestamp)
require.True(t, tc.expectedVolumeInfos[0].StartTimestamp.Equal(volumesInfo.volumeInfos[0].StartTimestamp))
} else {
require.Nil(t, volumesInfo.volumeInfos[0].StartTimestamp)
}
if tc.expectedVolumeInfos[0].CompletionTimestamp != nil {
require.NotNil(t, volumesInfo.volumeInfos[0].CompletionTimestamp)
require.True(t, tc.expectedVolumeInfos[0].CompletionTimestamp.Equal(volumesInfo.volumeInfos[0].CompletionTimestamp))
} else {
require.Nil(t, volumesInfo.volumeInfos[0].CompletionTimestamp)
}
}
})
}
@@ -1057,7 +1086,7 @@ func TestRestoreVolumeInfoResult(t *testing.T) {
PVName: "testPV2",
RestoreMethod: PodVolumeRestore,
SnapshotDataMoved: false,
PVRInfo: &PodVolumeInfo{
PVRInfo: &PodVolumeRestoreInfo{
SnapshotHandle: "pvr-snap-001",
PodName: "testPod",
PodNamespace: "testNS",
@@ -1127,7 +1156,7 @@ func TestRestoreVolumeInfoResult(t *testing.T) {
PVName: "testPV2",
RestoreMethod: PodVolumeRestore,
SnapshotDataMoved: false,
PVRInfo: &PodVolumeInfo{
PVRInfo: &PodVolumeRestoreInfo{
SnapshotHandle: "pvr-snap-001",
PodName: "testPod",
PodNamespace: "testNS",
@@ -1182,6 +1211,9 @@ func TestRestoreVolumeInfoResult(t *testing.T) {
PVC: "testPVC",
Namespace: "testNS",
}).
Phase(velerov2alpha1.DataDownloadPhaseCompleted).
Progress(veleroshared.DataMoveOperationProgress{TotalBytes: 2048}).
RestoreType("Incremental").
Result(),
*builder.ForDataDownload("velero", "testDataDownload-2").
ObjectMeta(builder.WithLabels(velerov1api.AsyncOperationIDLabel, "dd-operation-002")).
@@ -1190,6 +1222,9 @@ func TestRestoreVolumeInfoResult(t *testing.T) {
PVC: "testPVC2",
Namespace: "testNS",
}).
Phase(velerov2alpha1.DataDownloadPhaseCompleted).
Progress(veleroshared.DataMoveOperationProgress{TotalBytes: 4096}).
RestoreType("Full").
Result(),
},
},
@@ -1202,11 +1237,14 @@ func TestRestoreVolumeInfoResult(t *testing.T) {
PVName: "testPV",
RestoreMethod: CSISnapshot,
SnapshotDataMoved: true,
SnapshotDataMovementInfo: &SnapshotDataMovementInfo{
SnapshotDataMovementInfo: &RestoreSnapshotDataMovementInfo{
DataMover: "velero",
UploaderType: velerov1api.BackupRepositoryTypeKopia,
SnapshotHandle: "dd-snap-001",
OperationID: "dd-operation-001",
Phase: velerov2alpha1.DataDownloadPhaseCompleted,
Size: 2048,
RestoreType: "Incremental",
},
},
{
@@ -1215,11 +1253,14 @@ func TestRestoreVolumeInfoResult(t *testing.T) {
PVName: "testPV2",
RestoreMethod: CSISnapshot,
SnapshotDataMoved: true,
SnapshotDataMovementInfo: &SnapshotDataMovementInfo{
SnapshotDataMovementInfo: &RestoreSnapshotDataMovementInfo{
DataMover: "velero",
UploaderType: velerov1api.BackupRepositoryTypeKopia,
SnapshotHandle: "dd-snap-002",
OperationID: "dd-operation-002",
Phase: velerov2alpha1.DataDownloadPhaseCompleted,
Size: 4096,
RestoreType: "Full",
},
},
},
@@ -1262,3 +1303,174 @@ func TestGetVolumeSnapshotClasses(t *testing.T) {
require.NoError(t, err)
require.Equal(t, []snapshotv1api.VolumeSnapshotClass{*class}, result)
}
func TestBackupVolumeInfoJSONRoundTrip(t *testing.T) {
orig := BackupVolumeInfo{
PVCName: "pvc-1",
PVCNamespace: "ns-1",
PVName: "pv-1",
BackupMethod: CSISnapshot,
SnapshotDataMoved: true,
PreserveLocalSnapshot: false,
Skipped: false,
Result: VolumeResultSucceeded,
BackupType: velerov1api.BackupTypeIncremental,
CSISnapshotInfo: &CSISnapshotInfo{
SnapshotHandle: "csi-snap-1",
Size: 2000,
Driver: "csi.driver.com",
VSCName: "vsc-1",
OperationID: "op-2",
VolumeGroupSnapshotHandle: "vgsh-1",
},
SnapshotDataMovementInfo: &BackupSnapshotDataMovementInfo{
DataMover: "velero",
UploaderType: "kopia",
RetainedSnapshot: "retain-1",
SnapshotHandle: "snap-1",
OperationID: "op-1",
Size: 1000,
IncrementalSize: int64Ptr(200),
ParentSnapshot: "parent-1",
Phase: velerov2alpha1.DataUploadPhaseCompleted,
},
NativeSnapshotInfo: &NativeSnapshotInfo{
SnapshotHandle: "native-snap-1",
VolumeType: "gp3",
VolumeAZ: "us-west-2a",
IOPS: "3000",
},
PVBInfo: &PodVolumeBackupInfo{
SnapshotHandle: "pvb-snap-1",
Size: 500,
IncrementalSize: int64Ptr(50),
UploaderType: "kopia",
VolumeName: "vol-1",
PodName: "pod-1",
PodNamespace: "ns-1",
NodeName: "node-1",
Phase: velerov1api.PodVolumeBackupPhaseCompleted,
},
PVInfo: &PVInfo{
ReclaimPolicy: "Delete",
Labels: map[string]string{"env": "test"},
},
}
data, err := json.Marshal(orig)
require.NoError(t, err)
jsonStr := string(data)
assert.Contains(t, jsonStr, `"pvcName":"pvc-1"`)
assert.Contains(t, jsonStr, `"pvcNamespace":"ns-1"`)
assert.Contains(t, jsonStr, `"pvName":"pv-1"`)
assert.Contains(t, jsonStr, `"backupMethod":"CSISnapshot"`)
assert.Contains(t, jsonStr, `"snapshotDataMoved":true`)
assert.Contains(t, jsonStr, `"result":"succeeded"`)
assert.Contains(t, jsonStr, `"backupType":"Incremental"`)
assert.Contains(t, jsonStr, `"snapshotDataMovementInfo":{`)
assert.Contains(t, jsonStr, `"dataMover":"velero"`)
assert.Contains(t, jsonStr, `"uploaderType":"kopia"`)
assert.Contains(t, jsonStr, `"retainedSnapshot":"retain-1"`)
assert.Contains(t, jsonStr, `"snapshotHandle":"snap-1"`)
assert.Contains(t, jsonStr, `"operationID":"op-1"`)
assert.Contains(t, jsonStr, `"size":1000`)
assert.Contains(t, jsonStr, `"incrementalSize":200`)
assert.Contains(t, jsonStr, `"parentSnapshot":"parent-1"`)
assert.Contains(t, jsonStr, `"phase":"Completed"`)
assert.Contains(t, jsonStr, `"pvbInfo":{`)
assert.Contains(t, jsonStr, `"podName":"pod-1"`)
assert.Contains(t, jsonStr, `"podNamespace":"ns-1"`)
assert.Contains(t, jsonStr, `"nodeName":"node-1"`)
assert.Contains(t, jsonStr, `"csiSnapshotInfo":{`)
assert.Contains(t, jsonStr, `"driver":"csi.driver.com"`)
assert.Contains(t, jsonStr, `"vscName":"vsc-1"`)
assert.Contains(t, jsonStr, `"volumeGroupSnapshotHandle":"vgsh-1"`)
assert.Contains(t, jsonStr, `"nativeSnapshotInfo":{`)
assert.Contains(t, jsonStr, `"volumeType":"gp3"`)
assert.Contains(t, jsonStr, `"volumeAZ":"us-west-2a"`)
assert.Contains(t, jsonStr, `"iops":"3000"`)
assert.Contains(t, jsonStr, `"pvInfo":{`)
assert.Contains(t, jsonStr, `"reclaimPolicy":"Delete"`)
var unmarshaled BackupVolumeInfo
err = json.Unmarshal(data, &unmarshaled)
require.NoError(t, err)
assert.Equal(t, orig, unmarshaled)
}
func TestRestoreVolumeInfoJSONRoundTrip(t *testing.T) {
orig := RestoreVolumeInfo{
PVCName: "pvc-2",
PVCNamespace: "ns-2",
PVName: "pv-2",
RestoreMethod: CSISnapshot,
SnapshotDataMoved: true,
SnapshotDataMovementInfo: &RestoreSnapshotDataMovementInfo{
DataMover: "velero",
UploaderType: "kopia",
RetainedSnapshot: "retain-2",
SnapshotHandle: "snap-2",
OperationID: "op-3",
Size: 3000,
IncrementalSize: int64Ptr(300),
Phase: velerov2alpha1.DataDownloadPhaseCompleted,
RestoreType: "Incremental",
},
PVRInfo: &PodVolumeRestoreInfo{
SnapshotHandle: "pvr-snap-1",
Size: 600,
IncrementalSize: int64Ptr(60),
UploaderType: "kopia",
VolumeName: "vol-2",
PodName: "pod-2",
PodNamespace: "ns-2",
NodeName: "node-2",
Phase: velerov1api.PodVolumeRestorePhaseCompleted,
RestoreType: "Incremental",
},
CSISnapshotInfo: &CSISnapshotInfo{
SnapshotHandle: "csi-snap-2",
Size: 4000,
Driver: "csi.driver.com",
VSCName: "vsc-2",
},
NativeSnapshotInfo: &NativeSnapshotInfo{
SnapshotHandle: "native-snap-2",
VolumeType: "ebs",
VolumeAZ: "us-east-1a",
IOPS: "1000",
},
}
data, err := json.Marshal(orig)
require.NoError(t, err)
jsonStr := string(data)
assert.Contains(t, jsonStr, `"pvcName":"pvc-2"`)
assert.Contains(t, jsonStr, `"pvcNamespace":"ns-2"`)
assert.Contains(t, jsonStr, `"pvName":"pv-2"`)
assert.Contains(t, jsonStr, `"restoreMethod":"CSISnapshot"`)
assert.Contains(t, jsonStr, `"snapshotDataMoved":true`)
assert.Contains(t, jsonStr, `"snapshotDataMovementInfo":{`)
assert.Contains(t, jsonStr, `"dataMover":"velero"`)
assert.Contains(t, jsonStr, `"uploaderType":"kopia"`)
assert.Contains(t, jsonStr, `"retainedSnapshot":"retain-2"`)
assert.Contains(t, jsonStr, `"snapshotHandle":"snap-2"`)
assert.Contains(t, jsonStr, `"operationID":"op-3"`)
assert.Contains(t, jsonStr, `"size":3000`)
assert.Contains(t, jsonStr, `"incrementalSize":300`)
assert.Contains(t, jsonStr, `"phase":"Completed"`)
assert.Contains(t, jsonStr, `"restoreType":"Incremental"`)
assert.Contains(t, jsonStr, `"pvrInfo":{`)
assert.Contains(t, jsonStr, `"podName":"pod-2"`)
assert.Contains(t, jsonStr, `"podNamespace":"ns-2"`)
assert.Contains(t, jsonStr, `"nodeName":"node-2"`)
assert.Contains(t, jsonStr, `"csiSnapshotInfo":{`)
assert.Contains(t, jsonStr, `"nativeSnapshotInfo":{`)
var unmarshaled RestoreVolumeInfo
err = json.Unmarshal(data, &unmarshaled)
require.NoError(t, err)
assert.Equal(t, orig, unmarshaled)
}
+4 -4
View File
@@ -5666,7 +5666,7 @@ func TestUpdateVolumeInfos(t *testing.T) {
PVCName: "pvc-1",
PVCNamespace: "ns-1",
CompletionTimestamp: &metav1.Time{},
SnapshotDataMovementInfo: &volume.SnapshotDataMovementInfo{
SnapshotDataMovementInfo: &volume.BackupSnapshotDataMovementInfo{
DataMover: "velero",
},
},
@@ -5677,7 +5677,7 @@ func TestUpdateVolumeInfos(t *testing.T) {
PVCNamespace: "ns-1",
CompletionTimestamp: &now,
Result: volume.VolumeResultFailed,
SnapshotDataMovementInfo: &volume.SnapshotDataMovementInfo{
SnapshotDataMovementInfo: &volume.BackupSnapshotDataMovementInfo{
DataMover: "velero",
RetainedSnapshot: "vs-1",
SnapshotHandle: "snapshot-id",
@@ -5706,7 +5706,7 @@ func TestUpdateVolumeInfos(t *testing.T) {
PVCName: "pvc-1",
PVCNamespace: "ns-1",
CompletionTimestamp: &metav1.Time{},
SnapshotDataMovementInfo: &volume.SnapshotDataMovementInfo{
SnapshotDataMovementInfo: &volume.BackupSnapshotDataMovementInfo{
DataMover: "velero",
},
},
@@ -5717,7 +5717,7 @@ func TestUpdateVolumeInfos(t *testing.T) {
PVCNamespace: "ns-1",
CompletionTimestamp: &now,
Result: volume.VolumeResultSucceeded,
SnapshotDataMovementInfo: &volume.SnapshotDataMovementInfo{
SnapshotDataMovementInfo: &volume.BackupSnapshotDataMovementInfo{
DataMover: "velero",
RetainedSnapshot: "vs-1",
SnapshotHandle: "snapshot-id",
+6
View File
@@ -61,6 +61,12 @@ func (d *DataDownloadBuilder) Phase(phase velerov2alpha1api.DataDownloadPhase) *
return d
}
// RestoreType sets the DataDownload's RestoreType.
func (d *DataDownloadBuilder) RestoreType(restoreType string) *DataDownloadBuilder {
d.object.Spec.RestoreType = restoreType
return d
}
// SnapshotID sets the DataDownload's SnapshotID.
func (d *DataDownloadBuilder) SnapshotID(id string) *DataDownloadBuilder {
d.object.Spec.SnapshotID = id
+8
View File
@@ -249,6 +249,10 @@ func DescribeBackupSpec(d *Describer, spec velerov1api.BackupSpec) {
}
d.Printf("Data Mover:\t%s\n", s)
if string(spec.BackupType) != "" {
d.Printf("Backup Type:\t%s\n", spec.BackupType)
}
d.Println()
d.Printf("TTL:\t%s\n", spec.TTL.Duration)
@@ -746,6 +750,10 @@ func describeDataMovement(d *Describer, details bool, info *volume.BackupVolumeI
if info.SnapshotDataMovementInfo.IncrementalSize != nil {
d.Printf("\t\t\t\tIncremental data Size (bytes): %d\n", *info.SnapshotDataMovementInfo.IncrementalSize)
}
if info.SnapshotDataMovementInfo.ParentSnapshot != "" {
d.Printf("\t\t\t\tParent Snapshot: %s\n", info.SnapshotDataMovementInfo.ParentSnapshot)
}
d.Printf("\t\t\t\tResult: %s\n", info.Result)
} else {
d.Printf("\t\t\tData Movement: %s\n", "included, specify --details for more information")
+8 -3
View File
@@ -108,6 +108,7 @@ func TestDescribeBackupSpec(t *testing.T) {
TTL(72 * time.Hour).
CSISnapshotTimeout(10 * time.Minute).
DataMover("mover").
BackupType(velerov1api.BackupTypeFull).
Hooks(velerov1api.BackupHooks{
Resources: []velerov1api.BackupResourceHookSpec{
{
@@ -156,6 +157,7 @@ Storage Location: backup-location
Velero-Native Snapshot PVs: auto
Snapshot Move Data: auto
Data Mover: mover
Backup Type: Full
TTL: 72h0m0s
@@ -575,7 +577,7 @@ func TestCSISnapshots(t *testing.T) {
PVCNamespace: "pvc-ns-3",
PVCName: "pvc-3",
SnapshotDataMoved: true,
SnapshotDataMovementInfo: &volume.SnapshotDataMovementInfo{
SnapshotDataMovementInfo: &volume.BackupSnapshotDataMovementInfo{
DataMover: "velero",
UploaderType: "fake-uploader",
SnapshotHandle: "fake-repo-id-3",
@@ -597,7 +599,7 @@ func TestCSISnapshots(t *testing.T) {
PVCName: "pvc-4",
SnapshotDataMoved: true,
Result: volume.VolumeResultSucceeded,
SnapshotDataMovementInfo: &volume.SnapshotDataMovementInfo{
SnapshotDataMovementInfo: &volume.BackupSnapshotDataMovementInfo{
DataMover: "velero",
UploaderType: "fake-uploader",
SnapshotHandle: "fake-repo-id-4",
@@ -625,13 +627,15 @@ func TestCSISnapshots(t *testing.T) {
PVCName: "pvc-5",
Result: volume.VolumeResultFailed,
SnapshotDataMoved: true,
SnapshotDataMovementInfo: &volume.SnapshotDataMovementInfo{
BackupType: velerov1api.BackupTypeIncremental,
SnapshotDataMovementInfo: &volume.BackupSnapshotDataMovementInfo{
UploaderType: "fake-uploader",
SnapshotHandle: "fake-repo-id-5",
OperationID: "fake-operation-5",
Size: 100,
IncrementalSize: ptr.To(int64(50)),
Phase: velerov2alpha1.DataUploadPhaseFailed,
ParentSnapshot: "fake-parent-snapshot",
},
},
},
@@ -644,6 +648,7 @@ func TestCSISnapshots(t *testing.T) {
Uploader Type: fake-uploader
Moved data Size (bytes): 100
Incremental data Size (bytes): 50
Parent Snapshot: fake-parent-snapshot
Result: failed
`,
},
@@ -136,6 +136,9 @@ func DescribeBackupSpecInSF(d *StructuredDescriber, spec velerov1api.BackupSpec)
s = spec.DataMover
}
backupSpecInfo["dataMover"] = s
if string(spec.BackupType) != "" {
backupSpecInfo["backupType"] = spec.BackupType
}
// describe TTL
backupSpecInfo["TTL"] = spec.TTL.Duration.String()
@@ -475,6 +478,9 @@ func describeDataMovementInSF(details bool, info *volume.BackupVolumeInfo, snaps
if info.SnapshotDataMovementInfo.IncrementalSize != nil {
dataMovement["incrementalSize"] = *info.SnapshotDataMovementInfo.IncrementalSize
}
if info.SnapshotDataMovementInfo.ParentSnapshot != "" {
dataMovement["parentSnapshot"] = info.SnapshotDataMovementInfo.ParentSnapshot
}
snapshotDetail["dataMovement"] = dataMovement
} else {
@@ -24,9 +24,11 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1api "k8s.io/api/core/v1"
"k8s.io/utils/ptr"
"github.com/vmware-tanzu/velero/internal/volume"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
velerov2alpha1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v2alpha1"
"github.com/vmware-tanzu/velero/pkg/builder"
"github.com/vmware-tanzu/velero/pkg/util/results"
)
@@ -45,6 +47,7 @@ func TestDescribeBackupInSF(t *testing.T) {
TTL(72 * time.Hour).
CSISnapshotTimeout(10 * time.Minute).
DataMover("mover").
BackupType(velerov1api.BackupTypeFull).
Hooks(velerov1api.BackupHooks{
Resources: []velerov1api.BackupResourceHookSpec{
{
@@ -87,6 +90,7 @@ func TestDescribeBackupInSF(t *testing.T) {
"clusterScoped": "auto",
},
"dataMover": "mover",
"backupType": velerov1api.BackupTypeFull,
"labelSelector": emptyDisplay,
"storageLocation": "backup-location",
"veleroNativeSnapshotPVs": "auto",
@@ -517,7 +521,7 @@ func TestDescribeCSISnapshotsInSF(t *testing.T) {
PVCNamespace: "pvc-ns-3",
PVCName: "pvc-3",
SnapshotDataMoved: true,
SnapshotDataMovementInfo: &volume.SnapshotDataMovementInfo{
SnapshotDataMovementInfo: &volume.BackupSnapshotDataMovementInfo{
DataMover: "velero",
UploaderType: "fake-uploader",
SnapshotHandle: "fake-repo-id-3",
@@ -542,7 +546,7 @@ func TestDescribeCSISnapshotsInSF(t *testing.T) {
PVCName: "pvc-4",
SnapshotDataMoved: true,
Result: volume.VolumeResultSucceeded,
SnapshotDataMovementInfo: &volume.SnapshotDataMovementInfo{
SnapshotDataMovementInfo: &volume.BackupSnapshotDataMovementInfo{
DataMover: "velero",
UploaderType: "fake-uploader",
SnapshotHandle: "fake-repo-id-4",
@@ -573,10 +577,15 @@ func TestDescribeCSISnapshotsInSF(t *testing.T) {
Result: volume.VolumeResultFailed,
PVCName: "pvc-4",
SnapshotDataMoved: true,
SnapshotDataMovementInfo: &volume.SnapshotDataMovementInfo{
UploaderType: "fake-uploader",
SnapshotHandle: "fake-repo-id-4",
OperationID: "fake-operation-4",
BackupType: velerov1api.BackupTypeIncremental,
SnapshotDataMovementInfo: &volume.BackupSnapshotDataMovementInfo{
UploaderType: "fake-uploader",
SnapshotHandle: "fake-repo-id-4",
OperationID: "fake-operation-4",
Size: 100,
IncrementalSize: ptr.To(int64(50)),
Phase: velerov2alpha1.DataUploadPhaseFailed,
ParentSnapshot: "fake-parent-snapshot",
},
},
},
@@ -585,10 +594,13 @@ func TestDescribeCSISnapshotsInSF(t *testing.T) {
"csiSnapshots": map[string]any{
"pvc-ns-4/pvc-4": map[string]any{
"dataMovement": map[string]any{
"operationID": "fake-operation-4",
"dataMover": "velero",
"uploaderType": "fake-uploader",
"result": "failed",
"operationID": "fake-operation-4",
"dataMover": "velero",
"uploaderType": "fake-uploader",
"size": int64(100),
"incrementalSize": int64(50),
"result": "failed",
"parentSnapshot": "fake-parent-snapshot",
},
},
},
+14
View File
@@ -209,6 +209,11 @@ func DescribeRestore(
s = string(restore.Spec.ExistingResourcePolicy)
}
d.Printf("Existing Resource Policy: \t%s\n", s)
s = emptyDisplay
if restore.Spec.ExistingVolumeDataPolicy != "" {
s = string(restore.Spec.ExistingVolumeDataPolicy)
}
d.Printf("Existing Volume Data Policy: \t%s\n", s)
d.Printf("ItemOperationTimeout:\t%s\n", restore.Spec.ItemOperationTimeout.Duration)
d.Println()
@@ -468,6 +473,15 @@ func describeCSISnapshotsRestores(d *Describer, restoreVolInfo []volume.RestoreV
d.Printf("\t\t\tOperation ID: %s\n", info.SnapshotDataMovementInfo.OperationID)
d.Printf("\t\t\tData Mover: %s\n", info.SnapshotDataMovementInfo.DataMover)
d.Printf("\t\t\tUploader Type: %s\n", info.SnapshotDataMovementInfo.UploaderType)
if info.SnapshotDataMovementInfo.RestoreType != "" {
d.Printf("\t\t\tRestore Type: %s\n", info.SnapshotDataMovementInfo.RestoreType)
}
if info.SnapshotDataMovementInfo.Size > 0 {
d.Printf("\t\t\tRestored data Size (bytes): %d\n", info.SnapshotDataMovementInfo.Size)
}
if info.SnapshotDataMovementInfo.IncrementalSize != nil {
d.Printf("\t\t\tIncremental data Size (bytes): %d\n", *info.SnapshotDataMovementInfo.IncrementalSize)
}
} else {
d.Printf("\t\tData Movement: specify --details for more information\n")
}
+27 -6
View File
@@ -2,6 +2,7 @@ package output
import (
"bytes"
"context"
"fmt"
"testing"
"text/tabwriter"
@@ -10,11 +11,13 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
corev1api "k8s.io/api/core/v1"
"k8s.io/utils/ptr"
"github.com/vmware-tanzu/velero/internal/volume"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
"github.com/vmware-tanzu/velero/pkg/builder"
"github.com/vmware-tanzu/velero/pkg/itemoperation"
velerotest "github.com/vmware-tanzu/velero/pkg/test"
"github.com/vmware-tanzu/velero/pkg/util/boolptr"
"github.com/vmware-tanzu/velero/pkg/util/results"
)
@@ -309,11 +312,13 @@ CSI Snapshot Restores:
PVName: "pv-3",
RestoreMethod: volume.CSISnapshot,
SnapshotDataMoved: true,
SnapshotDataMovementInfo: &volume.SnapshotDataMovementInfo{
OperationID: "op-3",
DataMover: "velero",
UploaderType: "kopia",
Size: 1234,
SnapshotDataMovementInfo: &volume.RestoreSnapshotDataMovementInfo{
OperationID: "op-3",
DataMover: "velero",
UploaderType: "kopia",
Size: 1234,
IncrementalSize: ptr.To(int64(500)),
RestoreType: "Incremental",
},
},
},
@@ -325,6 +330,9 @@ CSI Snapshot Restores:
Operation ID: op-3
Data Mover: velero
Uploader Type: kopia
Restore Type: Incremental
Restored data Size (bytes): 1234
Incremental data Size (bytes): 500
`,
},
{
@@ -336,7 +344,7 @@ CSI Snapshot Restores:
PVName: "pv-3",
RestoreMethod: volume.CSISnapshot,
SnapshotDataMoved: true,
SnapshotDataMovementInfo: &volume.SnapshotDataMovementInfo{
SnapshotDataMovementInfo: &volume.RestoreSnapshotDataMovementInfo{
OperationID: "op-3",
DataMover: "velero",
UploaderType: "kopia",
@@ -415,3 +423,16 @@ func TestDescribeResourceModifier(t *testing.T) {
fmt.Println(d.buf.String())
require.Equal(t, expectOutput, d.buf.String())
}
func TestDescribeRestore(t *testing.T) {
kbClient := velerotest.NewFakeControllerRuntimeClient(t)
restore := builder.ForRestore("velero", "test-restore").
Backup("test-backup").
ExistingResourcePolicy(string(velerov1api.ResourcePolicyTypeUpdate)).
ExistingVolumeDataPolicy(string(velerov1api.VolumeDataPolicyTypeFull)).
Result()
out := DescribeRestore(context.Background(), kbClient, restore, nil, false, false, "")
assert.Contains(t, out, "Existing Resource Policy: update")
assert.Contains(t, out, "Existing Volume Data Policy: full")
}
@@ -196,6 +196,13 @@ func describeRestoreSpecInSF(d *StructuredDescriber, spec velerov1api.RestoreSpe
specInfo["existingResourcePolicy"] = emptyDisplay
}
// existing volume data policy
if spec.ExistingVolumeDataPolicy != "" {
specInfo["existingVolumeDataPolicy"] = string(spec.ExistingVolumeDataPolicy)
} else {
specInfo["existingVolumeDataPolicy"] = emptyDisplay
}
specInfo["itemOperationTimeout"] = spec.ItemOperationTimeout.Duration.String()
specInfo["preserveNodePorts"] = BoolPointerString(spec.PreserveNodePorts, "false", "true", "auto")
@@ -360,12 +367,22 @@ func describeCSISnapshotsRestoresInSF(d *StructuredDescriber, restoreVolInfo []v
}
continue
}
dmInfo := map[string]any{
"operationID": info.SnapshotDataMovementInfo.OperationID,
"dataMover": info.SnapshotDataMovementInfo.DataMover,
"uploaderType": info.SnapshotDataMovementInfo.UploaderType,
}
if info.SnapshotDataMovementInfo.RestoreType != "" {
dmInfo["restoreType"] = info.SnapshotDataMovementInfo.RestoreType
}
if info.SnapshotDataMovementInfo.Size > 0 {
dmInfo["size"] = info.SnapshotDataMovementInfo.Size
}
if info.SnapshotDataMovementInfo.IncrementalSize != nil {
dmInfo["incrementalSize"] = *info.SnapshotDataMovementInfo.IncrementalSize
}
csiRestores[key] = map[string]any{
"dataMovement": map[string]any{
"operationID": info.SnapshotDataMovementInfo.OperationID,
"dataMover": info.SnapshotDataMovementInfo.DataMover,
"uploaderType": info.SnapshotDataMovementInfo.UploaderType,
},
"dataMovement": dmInfo,
}
} else {
csiRestores[key] = map[string]any{
@@ -28,6 +28,7 @@ import (
"github.com/stretchr/testify/require"
corev1api "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"
"github.com/vmware-tanzu/velero/internal/volume"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
@@ -156,25 +157,27 @@ func TestDescribeRestoreSpecInSF(t *testing.T) {
"excluded": emptyDisplay,
"clusterScoped": "auto",
},
"namespaceMappings": emptyDisplay,
"labelSelector": emptyDisplay,
"orLabelSelectors": emptyDisplay,
"restorePVs": "auto",
"existingResourcePolicy": emptyDisplay,
"itemOperationTimeout": "0s",
"preserveNodePorts": "auto",
"namespaceMappings": emptyDisplay,
"labelSelector": emptyDisplay,
"orLabelSelectors": emptyDisplay,
"restorePVs": "auto",
"existingResourcePolicy": emptyDisplay,
"existingVolumeDataPolicy": emptyDisplay,
"itemOperationTimeout": "0s",
"preserveNodePorts": "auto",
},
},
},
{
name: "included namespaces wildcard treated as all",
spec: velerov1api.RestoreSpec{
BackupName: "backup-2",
IncludedNamespaces: []string{"*"},
ExcludedNamespaces: []string{"kube-system"},
IncludedResources: []string{"pods", "configmaps"},
ExcludedResources: []string{"secrets"},
ExistingResourcePolicy: velerov1api.ResourcePolicyTypeUpdate,
BackupName: "backup-2",
IncludedNamespaces: []string{"*"},
ExcludedNamespaces: []string{"kube-system"},
IncludedResources: []string{"pods", "configmaps"},
ExcludedResources: []string{"secrets"},
ExistingResourcePolicy: velerov1api.ResourcePolicyTypeUpdate,
ExistingVolumeDataPolicy: velerov1api.VolumeDataPolicyTypeFull,
},
expect: map[string]any{
"spec": map[string]any{
@@ -188,13 +191,14 @@ func TestDescribeRestoreSpecInSF(t *testing.T) {
"excluded": "secrets",
"clusterScoped": "auto",
},
"namespaceMappings": emptyDisplay,
"labelSelector": emptyDisplay,
"orLabelSelectors": emptyDisplay,
"restorePVs": "auto",
"existingResourcePolicy": string(velerov1api.ResourcePolicyTypeUpdate),
"itemOperationTimeout": "0s",
"preserveNodePorts": "auto",
"namespaceMappings": emptyDisplay,
"labelSelector": emptyDisplay,
"orLabelSelectors": emptyDisplay,
"restorePVs": "auto",
"existingResourcePolicy": string(velerov1api.ResourcePolicyTypeUpdate),
"existingVolumeDataPolicy": string(velerov1api.VolumeDataPolicyTypeFull),
"itemOperationTimeout": "0s",
"preserveNodePorts": "auto",
},
},
},
@@ -223,13 +227,14 @@ func TestDescribeRestoreSpecInSF(t *testing.T) {
"excluded": emptyDisplay,
"clusterScoped": "auto",
},
"namespaceMappings": emptyDisplay,
"labelSelector": emptyDisplay,
"orLabelSelectors": emptyDisplay,
"restorePVs": "auto",
"existingResourcePolicy": emptyDisplay,
"itemOperationTimeout": "0s",
"preserveNodePorts": "auto",
"namespaceMappings": emptyDisplay,
"labelSelector": emptyDisplay,
"orLabelSelectors": emptyDisplay,
"restorePVs": "auto",
"existingResourcePolicy": emptyDisplay,
"existingVolumeDataPolicy": emptyDisplay,
"itemOperationTimeout": "0s",
"preserveNodePorts": "auto",
"resourceModifier": map[string]any{
"type": "ConfigMap",
"name": "my-modifier",
@@ -272,13 +277,14 @@ func TestDescribeRestoreSpecInSF(t *testing.T) {
"excluded": emptyDisplay,
"clusterScoped": "included",
},
"namespaceMappings": map[string]string{"ns-a": "ns-a-new"},
"labelSelector": "app=nginx",
"orLabelSelectors": "env=prod or env=stage",
"restorePVs": "true",
"existingResourcePolicy": emptyDisplay,
"itemOperationTimeout": "0s",
"preserveNodePorts": "false",
"namespaceMappings": map[string]string{"ns-a": "ns-a-new"},
"labelSelector": "app=nginx",
"orLabelSelectors": "env=prod or env=stage",
"restorePVs": "true",
"existingResourcePolicy": emptyDisplay,
"existingVolumeDataPolicy": emptyDisplay,
"itemOperationTimeout": "0s",
"preserveNodePorts": "false",
"resourcePolicy": map[string]any{
"type": "configmap",
"name": "volume-policy",
@@ -467,10 +473,13 @@ func TestDescribeRestoreCSISnapshotsInSF_NoData(t *testing.T) {
SnapshotDataMoved: true,
PVCName: "pvc-3",
PVCNamespace: "ns-3",
SnapshotDataMovementInfo: &volume.SnapshotDataMovementInfo{
OperationID: "op-3",
DataMover: "velero",
UploaderType: "kopia",
SnapshotDataMovementInfo: &volume.RestoreSnapshotDataMovementInfo{
OperationID: "op-3",
DataMover: "velero",
UploaderType: "kopia",
Size: 1234,
IncrementalSize: ptr.To(int64(500)),
RestoreType: "Incremental",
},
},
},
@@ -479,9 +488,12 @@ func TestDescribeRestoreCSISnapshotsInSF_NoData(t *testing.T) {
"csiSnapshotRestores": map[string]any{
"ns-3/pvc-3": map[string]any{
"dataMovement": map[string]any{
"operationID": "op-3",
"dataMover": "velero",
"uploaderType": "kopia",
"operationID": "op-3",
"dataMover": "velero",
"uploaderType": "kopia",
"size": int64(1234),
"incrementalSize": int64(500),
"restoreType": "Incremental",
},
},
},
@@ -495,7 +507,7 @@ func TestDescribeRestoreCSISnapshotsInSF_NoData(t *testing.T) {
SnapshotDataMoved: true,
PVCName: "pvc-3",
PVCNamespace: "ns-3",
SnapshotDataMovementInfo: &volume.SnapshotDataMovementInfo{
SnapshotDataMovementInfo: &volume.RestoreSnapshotDataMovementInfo{
OperationID: "op-3",
DataMover: "velero",
UploaderType: "kopia",
+2 -2
View File
@@ -118,7 +118,7 @@ func TestRestorePVWithVolumeInfo(t *testing.T) {
"pv-1": {
BackupMethod: volume.PodVolumeBackup,
PVName: "pv-1",
PVBInfo: &volume.PodVolumeInfo{
PVBInfo: &volume.PodVolumeBackupInfo{
SnapshotHandle: "testSnapshotHandle",
Size: 100,
NodeName: "testNode",
@@ -173,7 +173,7 @@ func TestRestorePVWithVolumeInfo(t *testing.T) {
CSISnapshotInfo: &volume.CSISnapshotInfo{
Driver: "pd.csi.storage.gke.io",
},
SnapshotDataMovementInfo: &volume.SnapshotDataMovementInfo{
SnapshotDataMovementInfo: &volume.BackupSnapshotDataMovementInfo{
DataMover: "velero",
},
},