diff --git a/changelogs/unreleased/9941-Lyndon-Li b/changelogs/unreleased/9941-Lyndon-Li new file mode 100644 index 000000000..fd29540a3 --- /dev/null +++ b/changelogs/unreleased/9941-Lyndon-Li @@ -0,0 +1 @@ +Decide restorePVC volumeMode by data mover type for block data mover \ No newline at end of file diff --git a/pkg/controller/data_download_controller.go b/pkg/controller/data_download_controller.go index 1f442ecd9..06ce3479e 100644 --- a/pkg/controller/data_download_controller.go +++ b/pkg/controller/data_download_controller.go @@ -949,6 +949,7 @@ func (r *DataDownloadReconciler) setupExposeParam(dd *velerov2alpha1api.DataDown PriorityClassName: r.dataMovePriorityClass, RestoreSize: dd.Spec.SnapshotSize, CacheVolume: cacheVolume, + DataMover: dd.Spec.DataMover, }, nil } diff --git a/pkg/controller/data_download_controller_test.go b/pkg/controller/data_download_controller_test.go index ac45df540..518788635 100644 --- a/pkg/controller/data_download_controller_test.go +++ b/pkg/controller/data_download_controller_test.go @@ -1429,6 +1429,7 @@ func TestDataDownloadSetupExposeParam(t *testing.T) { // Core fields assert.Equal(t, baseDataDownload.Spec.TargetVolume.PVC, got.TargetPVCName) assert.Equal(t, baseDataDownload.Spec.TargetVolume.Namespace, got.TargetNamespace) + assert.Equal(t, baseDataDownload.Spec.DataMover, got.DataMover) // Labels and Annotations assert.Equal(t, tt.want.labels, got.HostingPodLabels) diff --git a/pkg/exposer/generic_restore.go b/pkg/exposer/generic_restore.go index f79b0b629..3137f223f 100644 --- a/pkg/exposer/generic_restore.go +++ b/pkg/exposer/generic_restore.go @@ -31,6 +31,7 @@ import ( "k8s.io/client-go/kubernetes" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/vmware-tanzu/velero/pkg/datamover" "github.com/vmware-tanzu/velero/pkg/nodeagent" velerotypes "github.com/vmware-tanzu/velero/pkg/types" "github.com/vmware-tanzu/velero/pkg/util/boolptr" @@ -80,6 +81,9 @@ type GenericRestoreExposeParam struct { // CacheVolume specifies the info for cache volumes CacheVolume *CacheConfigs + + // DataMover is the data mover type, e.g., velero-fs, velero-block + DataMover string } // GenericRestoreRebindVolumeParam define the input param for Generic Restore Rebind Volume @@ -192,10 +196,23 @@ func (e *genericRestoreExposer) Expose(ctx context.Context, ownerObject corev1ap } } + restorePVC, err := e.createRestorePVC(ctx, ownerObject, targetPVC, selectedNode, param.DataMover) + if err != nil { + return errors.Wrap(err, "error to create restore pvc") + } + + curLog.WithField("pvc name", restorePVC.Name).Info("Restore PVC is created") + + defer func() { + if err != nil { + kube.DeletePVAndPVCIfAny(ctx, e.kubeClient.CoreV1(), restorePVC.Name, restorePVC.Namespace, 0, curLog) + } + }() + restorePod, err := e.createRestorePod( ctx, ownerObject, - targetPVC, + restorePVC, param.OperationTimeout, param.HostingPodLabels, param.HostingPodAnnotations, @@ -219,19 +236,6 @@ func (e *genericRestoreExposer) Expose(ctx context.Context, ownerObject corev1ap } }() - restorePVC, err := e.createRestorePVC(ctx, ownerObject, targetPVC, selectedNode) - if err != nil { - return errors.Wrap(err, "error to create restore pvc") - } - - curLog.WithField("pvc name", restorePVC.Name).Info("Restore PVC is created") - - defer func() { - if err != nil { - kube.DeletePVAndPVCIfAny(ctx, e.kubeClient.CoreV1(), restorePVC.Name, restorePVC.Namespace, 0, curLog) - } - }() - return nil } @@ -802,7 +806,7 @@ func (e *genericRestoreExposer) createRestorePod( return e.kubeClient.CoreV1().Pods(ownerObject.Namespace).Create(ctx, pod, metav1.CreateOptions{}) } -func (e *genericRestoreExposer) createRestorePVC(ctx context.Context, ownerObject corev1api.ObjectReference, targetPVC *corev1api.PersistentVolumeClaim, selectedNode string) (*corev1api.PersistentVolumeClaim, error) { +func (e *genericRestoreExposer) createRestorePVC(ctx context.Context, ownerObject corev1api.ObjectReference, targetPVC *corev1api.PersistentVolumeClaim, selectedNode string, dataMover string) (*corev1api.PersistentVolumeClaim, error) { restorePVCName := ownerObject.Name pvcObj := &corev1api.PersistentVolumeClaim{ @@ -835,5 +839,13 @@ func (e *genericRestoreExposer) createRestorePVC(ctx context.Context, ownerObjec } } + if dataMover == datamover.DataMoverTypeVeleroBlock { + if pvcObj.Spec.VolumeMode == nil { + pvcObj.Spec.VolumeMode = new(corev1api.PersistentVolumeMode) + } + + *pvcObj.Spec.VolumeMode = corev1api.PersistentVolumeBlock + } + return e.kubeClient.CoreV1().PersistentVolumeClaims(pvcObj.Namespace).Create(ctx, pvcObj, metav1.CreateOptions{}) } diff --git a/pkg/exposer/generic_restore_test.go b/pkg/exposer/generic_restore_test.go index b5b7530d6..48526a5fd 100644 --- a/pkg/exposer/generic_restore_test.go +++ b/pkg/exposer/generic_restore_test.go @@ -33,6 +33,7 @@ import ( clientTesting "k8s.io/client-go/testing" velerov1 "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" + "github.com/vmware-tanzu/velero/pkg/datamover" velerotest "github.com/vmware-tanzu/velero/pkg/test" "github.com/vmware-tanzu/velero/pkg/util/kube" ) @@ -61,6 +62,18 @@ func TestRestoreExpose(t *testing.T) { }, } + modeFilesystem := corev1api.PersistentVolumeFilesystem + targetPVCObjWithVolumeMode := &corev1api.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "fake-ns", + Name: "fake-target-pvc", + }, + Spec: corev1api.PersistentVolumeClaimSpec{ + StorageClassName: &scName, + VolumeMode: &modeFilesystem, + }, + } + storageClass := &storagev1api.StorageClass{ ObjectMeta: metav1.ObjectMeta{ Name: "fake-sc", @@ -107,6 +120,7 @@ func TestRestoreExpose(t *testing.T) { targetNamespace string kubeReactors []reactor cacheVolume *CacheConfigs + dataMover string expectBackupPod bool expectBackupPVC bool expectCachePVC bool @@ -236,6 +250,34 @@ func TestRestoreExpose(t *testing.T) { expectBackupPVC: true, expectCachePVC: true, }, + { + name: "succeed with velero-block data mover", + targetPVCName: "fake-target-pvc", + targetNamespace: "fake-ns", + ownerRestore: restore, + kubeClientObj: []runtime.Object{ + targetPVCObj, + daemonSet, + storageClass, + }, + dataMover: datamover.DataMoverTypeVeleroBlock, + expectBackupPod: true, + expectBackupPVC: true, + }, + { + name: "succeed with velero-block data mover and existing volume mode", + targetPVCName: "fake-target-pvc", + targetNamespace: "fake-ns", + ownerRestore: restore, + kubeClientObj: []runtime.Object{ + targetPVCObjWithVolumeMode, + daemonSet, + storageClass, + }, + dataMover: datamover.DataMoverTypeVeleroBlock, + expectBackupPod: true, + expectBackupPVC: true, + }, } for _, test := range tests { @@ -273,6 +315,7 @@ func TestRestoreExpose(t *testing.T) { ExposeTimeout: time.Millisecond, LoadAffinity: nil, CacheVolume: test.cacheVolume, + DataMover: test.dataMover, }, ) @@ -289,9 +332,13 @@ func TestRestoreExpose(t *testing.T) { require.True(t, apierrors.IsNotFound(err)) } - _, err = exposer.kubeClient.CoreV1().PersistentVolumeClaims(ownerObject.Namespace).Get(t.Context(), ownerObject.Name, metav1.GetOptions{}) + pvc, err := exposer.kubeClient.CoreV1().PersistentVolumeClaims(ownerObject.Namespace).Get(t.Context(), ownerObject.Name, metav1.GetOptions{}) if test.expectBackupPVC { require.NoError(t, err) + if test.dataMover == datamover.DataMoverTypeVeleroBlock { + require.NotNil(t, pvc.Spec.VolumeMode) + require.Equal(t, corev1api.PersistentVolumeBlock, *pvc.Spec.VolumeMode) + } } else { require.True(t, apierrors.IsNotFound(err)) }