Remove dependency with VolumeSnapshotClass in DataUpload. (#9040)
Some checks failed
Run the E2E test on kind / build (push) Failing after 6m30s
Run the E2E test on kind / setup-test-matrix (push) Successful in 4s
Run the E2E test on kind / run-e2e-test (push) Has been skipped
Main CI / Build (push) Failing after 1m0s
Close stale issues and PRs / stale (push) Successful in 19s
Trivy Nightly Scan / Trivy nightly scan (velero, main) (push) Failing after 1m40s
Trivy Nightly Scan / Trivy nightly scan (velero-plugin-for-aws, main) (push) Failing after 1m29s
Trivy Nightly Scan / Trivy nightly scan (velero-plugin-for-gcp, main) (push) Failing after 1m41s
Trivy Nightly Scan / Trivy nightly scan (velero-plugin-for-microsoft-azure, main) (push) Failing after 1m39s

Don't add VSClass in the additionalItems when it's empty.

Signed-off-by: Xun Jiang <xun.jiang@broadcom.com>
Signed-off-by: xun.jiang <xun.jiang@broadcom.com>
This commit is contained in:
Xun Jiang/Bruce Jiang
2025-06-26 03:36:15 +08:00
committed by GitHub
parent 37a22a3f56
commit b0b5cc4236
10 changed files with 89 additions and 131 deletions

View File

@@ -0,0 +1 @@
Remove dependency with VolumeSnapshotClass in DataUpload.

View File

@@ -87,6 +87,9 @@ spec:
of the CSI snapshot. of the CSI snapshot.
nullable: true nullable: true
properties: properties:
driver:
description: Driver is the driver used by the VolumeSnapshotContent
type: string
snapshotClass: snapshotClass:
description: SnapshotClass is the name of the snapshot class that description: SnapshotClass is the name of the snapshot class that
the volume snapshot is created with the volume snapshot is created with

File diff suppressed because one or more lines are too long

View File

@@ -402,7 +402,6 @@ func (v *BackupVolumesInformation) generateVolumeInfoForCSIVolumeSnapshot() {
tmpVolumeInfos := make([]*BackupVolumeInfo, 0) tmpVolumeInfos := make([]*BackupVolumeInfo, 0)
for _, volumeSnapshot := range v.volumeSnapshots { for _, volumeSnapshot := range v.volumeSnapshots {
var volumeSnapshotClass *snapshotv1api.VolumeSnapshotClass
var volumeSnapshotContent *snapshotv1api.VolumeSnapshotContent var volumeSnapshotContent *snapshotv1api.VolumeSnapshotContent
// This is protective logic. The passed-in VS should be all related // This is protective logic. The passed-in VS should be all related
@@ -411,11 +410,6 @@ func (v *BackupVolumesInformation) generateVolumeInfoForCSIVolumeSnapshot() {
continue continue
} }
if volumeSnapshot.Spec.VolumeSnapshotClassName == nil {
v.logger.Warnf("Cannot find VolumeSnapshotClass for VolumeSnapshot %s/%s", volumeSnapshot.Namespace, volumeSnapshot.Name)
continue
}
if volumeSnapshot.Status == nil || volumeSnapshot.Status.BoundVolumeSnapshotContentName == nil { if volumeSnapshot.Status == nil || volumeSnapshot.Status.BoundVolumeSnapshotContentName == nil {
v.logger.Warnf("Cannot fine VolumeSnapshotContent for VolumeSnapshot %s/%s", volumeSnapshot.Namespace, volumeSnapshot.Name) v.logger.Warnf("Cannot fine VolumeSnapshotContent for VolumeSnapshot %s/%s", volumeSnapshot.Namespace, volumeSnapshot.Name)
continue continue
@@ -426,20 +420,14 @@ func (v *BackupVolumesInformation) generateVolumeInfoForCSIVolumeSnapshot() {
continue continue
} }
for index := range v.volumeSnapshotClasses {
if *volumeSnapshot.Spec.VolumeSnapshotClassName == v.volumeSnapshotClasses[index].Name {
volumeSnapshotClass = &v.volumeSnapshotClasses[index]
}
}
for index := range v.volumeSnapshotContents { for index := range v.volumeSnapshotContents {
if *volumeSnapshot.Status.BoundVolumeSnapshotContentName == v.volumeSnapshotContents[index].Name { if *volumeSnapshot.Status.BoundVolumeSnapshotContentName == v.volumeSnapshotContents[index].Name {
volumeSnapshotContent = &v.volumeSnapshotContents[index] volumeSnapshotContent = &v.volumeSnapshotContents[index]
} }
} }
if volumeSnapshotClass == nil || volumeSnapshotContent == nil { if volumeSnapshotContent == nil {
v.logger.Warnf("fail to get VolumeSnapshotContent or VolumeSnapshotClass for VolumeSnapshot: %s/%s", v.logger.Warnf("fail to get VolumeSnapshotContent for VolumeSnapshot: %s/%s",
volumeSnapshot.Namespace, volumeSnapshot.Name) volumeSnapshot.Namespace, volumeSnapshot.Name)
continue continue
} }
@@ -473,7 +461,7 @@ func (v *BackupVolumesInformation) generateVolumeInfoForCSIVolumeSnapshot() {
CSISnapshotInfo: &CSISnapshotInfo{ CSISnapshotInfo: &CSISnapshotInfo{
VSCName: *volumeSnapshot.Status.BoundVolumeSnapshotContentName, VSCName: *volumeSnapshot.Status.BoundVolumeSnapshotContentName,
Size: size, Size: size,
Driver: volumeSnapshotClass.Driver, Driver: volumeSnapshotContent.Spec.Driver,
SnapshotHandle: snapshotHandle, SnapshotHandle: snapshotHandle,
OperationID: operation.Spec.OperationID, OperationID: operation.Spec.OperationID,
ReadyToUse: volumeSnapshot.Status.ReadyToUse, ReadyToUse: volumeSnapshot.Status.ReadyToUse,
@@ -581,14 +569,7 @@ func (v *BackupVolumesInformation) generateVolumeInfoFromDataUpload() {
} }
} }
var vsClassList []snapshotv1api.VolumeSnapshotClass if len(duOperationMap) <= 0 {
if len(duOperationMap) > 0 {
var err error
vsClassList, err = v.getVolumeSnapshotClasses()
if err != nil {
return
}
} else {
// No DataUpload is found. Return early. // No DataUpload is found. Return early.
return return
} }
@@ -609,13 +590,6 @@ func (v *BackupVolumesInformation) generateVolumeInfoFromDataUpload() {
continue continue
} }
driverUsedByVSClass := ""
for index := range vsClassList {
if vsClassList[index].Name == dataUpload.Spec.CSISnapshot.SnapshotClass {
driverUsedByVSClass = vsClassList[index].Driver
}
}
if pvcPVInfo := v.pvMap.retrieve( if pvcPVInfo := v.pvMap.retrieve(
"", "",
operation.Spec.ResourceIdentifier.Name, operation.Spec.ResourceIdentifier.Name,
@@ -637,7 +611,7 @@ func (v *BackupVolumesInformation) generateVolumeInfoFromDataUpload() {
SnapshotHandle: FieldValueIsUnknown, SnapshotHandle: FieldValueIsUnknown,
VSCName: FieldValueIsUnknown, VSCName: FieldValueIsUnknown,
OperationID: FieldValueIsUnknown, OperationID: FieldValueIsUnknown,
Driver: driverUsedByVSClass, Driver: dataUpload.Spec.CSISnapshot.Driver,
}, },
SnapshotDataMovementInfo: &SnapshotDataMovementInfo{ SnapshotDataMovementInfo: &SnapshotDataMovementInfo{
DataMover: dataMover, DataMover: dataMover,

View File

@@ -29,6 +29,7 @@ import (
corev1api "k8s.io/api/core/v1" corev1api "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1"
@@ -415,7 +416,6 @@ func TestGenerateVolumeInfoForCSIVolumeSnapshot(t *testing.T) {
BoundVolumeSnapshotContentName: stringPtr("testContent"), BoundVolumeSnapshotContentName: stringPtr("testContent"),
}, },
}, },
volumeSnapshotClass: *builder.ForVolumeSnapshotClass("testClass").Driver("pd.csi.storage.gke.io").Result(),
volumeSnapshotContent: *builder.ForVolumeSnapshotContent("testContent").Status(&snapshotv1api.VolumeSnapshotContentStatus{SnapshotHandle: stringPtr("testSnapshotHandle")}).Result(), volumeSnapshotContent: *builder.ForVolumeSnapshotContent("testContent").Status(&snapshotv1api.VolumeSnapshotContentStatus{SnapshotHandle: stringPtr("testSnapshotHandle")}).Result(),
expectedVolumeInfos: []*BackupVolumeInfo{}, expectedVolumeInfos: []*BackupVolumeInfo{},
}, },
@@ -440,8 +440,7 @@ func TestGenerateVolumeInfoForCSIVolumeSnapshot(t *testing.T) {
ReadyToUse: &readyToUse, ReadyToUse: &readyToUse,
}, },
}, },
volumeSnapshotClass: *builder.ForVolumeSnapshotClass("testClass").Driver("pd.csi.storage.gke.io").Result(), volumeSnapshotContent: *builder.ForVolumeSnapshotContent("testContent").Driver("pd.csi.storage.gke.io").Status(&snapshotv1api.VolumeSnapshotContentStatus{SnapshotHandle: stringPtr("testSnapshotHandle")}).Result(),
volumeSnapshotContent: *builder.ForVolumeSnapshotContent("testContent").Status(&snapshotv1api.VolumeSnapshotContentStatus{SnapshotHandle: stringPtr("testSnapshotHandle")}).Result(),
pvMap: map[string]pvcPvInfo{ pvMap: map[string]pvcPvInfo{
"testPV": { "testPV": {
PVCName: "testPVC", PVCName: "testPVC",
@@ -758,7 +757,8 @@ func TestGenerateVolumeInfoFromDataUpload(t *testing.T) {
defer features.Disable(velerov1api.CSIFeatureFlag) defer features.Disable(velerov1api.CSIFeatureFlag)
tests := []struct { tests := []struct {
name string name string
volumeSnapshotClass *snapshotv1api.VolumeSnapshotClass vs *snapshotv1api.VolumeSnapshot
vsc *snapshotv1api.VolumeSnapshotContent
dataUpload *velerov2alpha1.DataUpload dataUpload *velerov2alpha1.DataUpload
operation *itemoperation.BackupOperation operation *itemoperation.BackupOperation
pvMap map[string]pvcPvInfo pvMap map[string]pvcPvInfo
@@ -829,87 +829,20 @@ func TestGenerateVolumeInfoFromDataUpload(t *testing.T) {
}, },
expectedVolumeInfos: []*BackupVolumeInfo{}, expectedVolumeInfos: []*BackupVolumeInfo{},
}, },
{
name: "VolumeSnapshotClass cannot be found for operation",
dataUpload: builder.ForDataUpload("velero", "testDU").DataMover("velero").CSISnapshot(&velerov2alpha1.CSISnapshotSpec{
VolumeSnapshot: "testVS",
}).SnapshotID("testSnapshotHandle").StartTimestamp(&now).Result(),
operation: &itemoperation.BackupOperation{
Spec: itemoperation.BackupOperationSpec{
OperationID: "testOperation",
ResourceIdentifier: velero.ResourceIdentifier{
GroupResource: schema.GroupResource{
Group: "",
Resource: "persistentvolumeclaims",
},
Namespace: "velero",
Name: "testPVC",
},
PostOperationItems: []velero.ResourceIdentifier{
{
GroupResource: schema.GroupResource{
Group: "velero.io",
Resource: "datauploads",
},
Namespace: "velero",
Name: "testDU",
},
},
},
},
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,
},
},
},
},
expectedVolumeInfos: []*BackupVolumeInfo{
{
PVCName: "testPVC",
PVCNamespace: "velero",
PVName: "testPV",
BackupMethod: CSISnapshot,
SnapshotDataMoved: true,
StartTimestamp: &now,
CSISnapshotInfo: &CSISnapshotInfo{
SnapshotHandle: FieldValueIsUnknown,
VSCName: FieldValueIsUnknown,
OperationID: FieldValueIsUnknown,
Size: 0,
},
SnapshotDataMovementInfo: &SnapshotDataMovementInfo{
DataMover: "velero",
UploaderType: "kopia",
OperationID: "testOperation",
},
PVInfo: &PVInfo{
ReclaimPolicy: string(corev1api.PersistentVolumeReclaimDelete),
Labels: map[string]string{"a": "b"},
},
},
},
},
{ {
name: "Normal DataUpload case", name: "Normal DataUpload case",
dataUpload: builder.ForDataUpload("velero", "testDU"). dataUpload: builder.ForDataUpload("velero", "testDU").
DataMover("velero"). DataMover("velero").
CSISnapshot(&velerov2alpha1.CSISnapshotSpec{ CSISnapshot(&velerov2alpha1.CSISnapshotSpec{
VolumeSnapshot: "testVS", VolumeSnapshot: "vs-01",
SnapshotClass: "testClass", SnapshotClass: "testClass",
Driver: "pd.csi.storage.gke.io",
}).SnapshotID("testSnapshotHandle"). }).SnapshotID("testSnapshotHandle").
StartTimestamp(&now). StartTimestamp(&now).
Phase(velerov2alpha1.DataUploadPhaseCompleted). Phase(velerov2alpha1.DataUploadPhaseCompleted).
Result(), Result(),
volumeSnapshotClass: builder.ForVolumeSnapshotClass("testClass").Driver("pd.csi.storage.gke.io").Result(), vs: builder.ForVolumeSnapshot(velerov1api.DefaultNamespace, "vs-01").Status().BoundVolumeSnapshotContentName("vsc-01").Result(),
vsc: builder.ForVolumeSnapshotContent("vsc-01").Driver("pd.csi.storage.gke.io").Result(),
operation: &itemoperation.BackupOperation{ operation: &itemoperation.BackupOperation{
Spec: itemoperation.BackupOperationSpec{ Spec: itemoperation.BackupOperationSpec{
OperationID: "testOperation", OperationID: "testOperation",
@@ -995,14 +928,17 @@ func TestGenerateVolumeInfoFromDataUpload(t *testing.T) {
} }
} }
volumesInfo.crClient = velerotest.NewFakeControllerRuntimeClient(t) objects := make([]runtime.Object, 0)
if tc.dataUpload != nil { if tc.dataUpload != nil {
volumesInfo.crClient.Create(context.TODO(), tc.dataUpload) objects = append(objects, tc.dataUpload)
} }
if tc.vs != nil {
if tc.volumeSnapshotClass != nil { objects = append(objects, tc.vs)
volumesInfo.crClient.Create(context.TODO(), tc.volumeSnapshotClass)
} }
if tc.vsc != nil {
objects = append(objects, tc.vsc)
}
volumesInfo.crClient = velerotest.NewFakeControllerRuntimeClient(t, objects...)
volumesInfo.logger = logging.DefaultLogger(logrus.DebugLevel, logging.FormatJSON) volumesInfo.logger = logging.DefaultLogger(logrus.DebugLevel, logging.FormatJSON)

View File

@@ -79,6 +79,10 @@ type CSISnapshotSpec struct {
// SnapshotClass is the name of the snapshot class that the volume snapshot is created with // SnapshotClass is the name of the snapshot class that the volume snapshot is created with
// +optional // +optional
SnapshotClass string `json:"snapshotClass"` SnapshotClass string `json:"snapshotClass"`
// Driver is the driver used by the VolumeSnapshotContent
// +optional
Driver string `json:"driver,omitempty"`
} }
// DataUploadPhase represents the lifecycle phase of a DataUpload. // DataUploadPhase represents the lifecycle phase of a DataUpload.

View File

@@ -281,7 +281,7 @@ func (p *pvcBackupItemAction) Execute(
// Wait until VS associated VSC snapshot handle created before // Wait until VS associated VSC snapshot handle created before
// returning with the Async operation for data mover. // returning with the Async operation for data mover.
_, err := csi.WaitUntilVSCHandleIsReady( vsc, err := csi.WaitUntilVSCHandleIsReady(
vs, vs,
p.crClient, p.crClient,
p.log, p.log,
@@ -305,6 +305,7 @@ func (p *pvcBackupItemAction) Execute(
vs, vs,
&pvc, &pvc,
operationID, operationID,
vsc,
) )
if err != nil { if err != nil {
dataUploadLog.WithError(err).Error("failed to submit DataUpload") dataUploadLog.WithError(err).Error("failed to submit DataUpload")
@@ -441,6 +442,7 @@ func newDataUpload(
vs *snapshotv1api.VolumeSnapshot, vs *snapshotv1api.VolumeSnapshot,
pvc *corev1api.PersistentVolumeClaim, pvc *corev1api.PersistentVolumeClaim,
operationID string, operationID string,
vsc *snapshotv1api.VolumeSnapshotContent,
) *velerov2alpha1.DataUpload { ) *velerov2alpha1.DataUpload {
dataUpload := &velerov2alpha1.DataUpload{ dataUpload := &velerov2alpha1.DataUpload{
TypeMeta: metav1.TypeMeta{ TypeMeta: metav1.TypeMeta{
@@ -471,7 +473,7 @@ func newDataUpload(
CSISnapshot: &velerov2alpha1.CSISnapshotSpec{ CSISnapshot: &velerov2alpha1.CSISnapshotSpec{
VolumeSnapshot: vs.Name, VolumeSnapshot: vs.Name,
StorageClass: *pvc.Spec.StorageClassName, StorageClass: *pvc.Spec.StorageClassName,
SnapshotClass: *vs.Spec.VolumeSnapshotClassName, Driver: vsc.Spec.Driver,
}, },
SourcePVC: pvc.Name, SourcePVC: pvc.Name,
DataMover: backup.Spec.DataMover, DataMover: backup.Spec.DataMover,
@@ -481,6 +483,10 @@ func newDataUpload(
}, },
} }
if vs.Spec.VolumeSnapshotClassName != nil {
dataUpload.Spec.CSISnapshot.SnapshotClass = *vs.Spec.VolumeSnapshotClassName
}
if backup.Spec.UploaderConfig != nil && if backup.Spec.UploaderConfig != nil &&
backup.Spec.UploaderConfig.ParallelFilesUpload > 0 { backup.Spec.UploaderConfig.ParallelFilesUpload > 0 {
dataUpload.Spec.DataMoverConfig = make(map[string]string) dataUpload.Spec.DataMoverConfig = make(map[string]string)
@@ -497,8 +503,9 @@ func createDataUpload(
vs *snapshotv1api.VolumeSnapshot, vs *snapshotv1api.VolumeSnapshot,
pvc *corev1api.PersistentVolumeClaim, pvc *corev1api.PersistentVolumeClaim,
operationID string, operationID string,
vsc *snapshotv1api.VolumeSnapshotContent,
) (*velerov2alpha1.DataUpload, error) { ) (*velerov2alpha1.DataUpload, error) {
dataUpload := newDataUpload(backup, vs, pvc, operationID) dataUpload := newDataUpload(backup, vs, pvc, operationID, vsc)
err := crClient.Create(ctx, dataUpload) err := crClient.Create(ctx, dataUpload)
if err != nil { if err != nil {

View File

@@ -142,26 +142,27 @@ func TestExecute(t *testing.T) {
for _, tc := range tests { for _, tc := range tests {
t.Run(tc.name, func(*testing.T) { t.Run(tc.name, func(*testing.T) {
crClient := velerotest.NewFakeControllerRuntimeClient(t)
logger := logrus.New() logger := logrus.New()
logger.Level = logrus.DebugLevel logger.Level = logrus.DebugLevel
objects := make([]runtime.Object, 0)
if tc.pvc != nil { if tc.pvc != nil {
require.NoError(t, crClient.Create(context.Background(), tc.pvc)) objects = append(objects, tc.pvc)
} }
if tc.pv != nil { if tc.pv != nil {
require.NoError(t, crClient.Create(context.Background(), tc.pv)) objects = append(objects, tc.pv)
} }
if tc.sc != nil { if tc.sc != nil {
require.NoError(t, crClient.Create(context.Background(), tc.sc)) objects = append(objects, tc.sc)
} }
if tc.vsClass != nil { if tc.vsClass != nil {
require.NoError(t, crClient.Create(context.Background(), tc.vsClass)) objects = append(objects, tc.vsClass)
} }
if tc.resourcePolicy != nil { if tc.resourcePolicy != nil {
require.NoError(t, crClient.Create(context.Background(), tc.resourcePolicy)) objects = append(objects, tc.resourcePolicy)
} }
crClient := velerotest.NewFakeControllerRuntimeClient(t, objects...)
pvcBIA := pvcBackupItemAction{ pvcBIA := pvcBackupItemAction{
log: logger, log: logger,
crClient: crClient, crClient: crClient,

View File

@@ -84,16 +84,15 @@ func (p *volumeSnapshotBackupItemAction) Execute(
return nil, nil, "", nil, errors.WithStack(err) return nil, nil, "", nil, errors.WithStack(err)
} }
volumeSnapshotClassName := "" additionalItems := make([]velero.ResourceIdentifier, 0)
if vs.Spec.VolumeSnapshotClassName != nil { if vs.Spec.VolumeSnapshotClassName != nil {
volumeSnapshotClassName = *vs.Spec.VolumeSnapshotClassName additionalItems = append(
} additionalItems,
velero.ResourceIdentifier{
additionalItems := []velero.ResourceIdentifier{
{
GroupResource: kuberesource.VolumeSnapshotClasses, GroupResource: kuberesource.VolumeSnapshotClasses,
Name: volumeSnapshotClassName, Name: *vs.Spec.VolumeSnapshotClassName,
}, },
)
} }
p.log.Infof("Getting VolumesnapshotContent for Volumesnapshot %s/%s", p.log.Infof("Getting VolumesnapshotContent for Volumesnapshot %s/%s",

View File

@@ -86,6 +86,39 @@ func TestVSExecute(t *testing.T) {
}, },
}, },
}, },
{
name: "VS not have VSClass",
backup: builder.ForBackup("velero", "backup").
Phase(velerov1api.BackupPhaseInProgress).Result(),
vs: builder.ForVolumeSnapshot("velero", "vs").
ObjectMeta(builder.WithLabels(
velerov1api.BackupNameLabel, "backup")).
Status().
BoundVolumeSnapshotContentName("vsc").Result(),
vsc: builder.ForVolumeSnapshotContent("vsc").Status(
&snapshotv1api.VolumeSnapshotContentStatus{
SnapshotHandle: &snapshotHandle,
},
).Result(),
expectedErr: "",
expectedAdditionalItems: []velero.ResourceIdentifier{
{
GroupResource: kuberesource.VolumeSnapshotContents,
Name: "vsc",
},
},
expectedItemToUpdate: []velero.ResourceIdentifier{
{
GroupResource: kuberesource.VolumeSnapshots,
Namespace: "velero",
Name: "vs",
},
{
GroupResource: kuberesource.VolumeSnapshotContents,
Name: "vsc",
},
},
},
} }
for _, tc := range tests { for _, tc := range tests {