mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-08-15 19:56:06 +00:00
Update Exposer to recreate the target PV if the volume mode is different with the restore PVC (#10257)
Run the E2E test on kind / setup-test-matrix (push) Successful in 3s
e2e-test-kind.yaml / extract (push) Failing after 6s
Run the E2E test on kind / get-go-version (push) Failing after 7s
Run the E2E test on kind / build (push) Skipped
Run the E2E test on kind / run-e2e-test (push) Skipped
Run the E2E test on kind / setup-test-matrix (push) Successful in 3s
e2e-test-kind.yaml / extract (push) Failing after 6s
Run the E2E test on kind / get-go-version (push) Failing after 7s
Run the E2E test on kind / build (push) Skipped
Run the E2E test on kind / run-e2e-test (push) Skipped
Update Exposer to recreate the target PV if the volume mode is different with t he restore PVC Signed-off-by: Wenkai Yin(尹文开) <yinw@vmware.com>
This commit is contained in:
@@ -855,9 +855,6 @@ func (e *genericRestoreExposer) createRestorePVC(ctx context.Context, ownerObjec
|
||||
Resources: targetPVC.Spec.Resources,
|
||||
},
|
||||
}
|
||||
if targetPV != nil {
|
||||
pvcObj.Spec.VolumeName = targetPV.Name
|
||||
}
|
||||
|
||||
if selectedNode != "" {
|
||||
if pvcObj.Annotations == nil {
|
||||
@@ -874,12 +871,56 @@ func (e *genericRestoreExposer) createRestorePVC(ctx context.Context, ownerObjec
|
||||
*pvcObj.Spec.VolumeMode = corev1api.PersistentVolumeBlock
|
||||
}
|
||||
|
||||
volumeName := ""
|
||||
sameVolumeMode := true
|
||||
if targetPV != nil {
|
||||
volumeName = targetPV.Name
|
||||
sameVolumeMode = kube.GetVolumeModeByPVC(pvcObj) == kube.GetVolumeModeByPV(targetPV)
|
||||
if !sameVolumeMode {
|
||||
volumeName = ownerObject.Name
|
||||
}
|
||||
pvcObj.Spec.VolumeName = volumeName
|
||||
}
|
||||
|
||||
restorePVC, err := e.kubeClient.CoreV1().PersistentVolumeClaims(pvcObj.Namespace).Create(ctx, pvcObj, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "fail to create the restore PVC %s in namespace %s", pvcObj.Name, pvcObj.Namespace)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
kube.DeletePVCIfAny(ctx, e.kubeClient.CoreV1(), pvcObj.Name, pvcObj.Namespace, 0, e.log)
|
||||
}
|
||||
}()
|
||||
|
||||
if targetPV != nil {
|
||||
if !sameVolumeMode {
|
||||
tmpPV := &corev1api.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: volumeName,
|
||||
},
|
||||
Spec: *targetPV.Spec.DeepCopy(),
|
||||
}
|
||||
tmpPV.Spec.VolumeMode = restorePVC.Spec.VolumeMode
|
||||
e.log.Infof("the volume mode is different, creating temporary PV %s with volume mode %s", tmpPV.Name, tmpPV.Spec.VolumeMode)
|
||||
tmpPV, err = e.kubeClient.CoreV1().PersistentVolumes().Create(ctx, tmpPV, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "fail to create the temporary PV %s", volumeName)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err != nil {
|
||||
kube.DeletePVIfAny(ctx, e.kubeClient.CoreV1(), tmpPV.Name, e.log)
|
||||
}
|
||||
}()
|
||||
|
||||
e.log.Infof("deleting the target PV %s", targetPV.Name)
|
||||
if err = e.kubeClient.CoreV1().PersistentVolumes().Delete(ctx, targetPV.Name, metav1.DeleteOptions{}); err != nil {
|
||||
return nil, errors.Wrapf(err, "fail to delete the target PV %s", targetPV.Name)
|
||||
}
|
||||
targetPV = tmpPV
|
||||
}
|
||||
|
||||
if _, err = kube.ResetPVBinding(ctx, e.kubeClient.CoreV1(), targetPV, nil, restorePVC); err != nil {
|
||||
return nil, errors.Wrapf(err, "fail to reset PV %s binding to restore PVC %s/%s", targetPV.Name, restorePVC.Namespace, restorePVC.Name)
|
||||
}
|
||||
|
||||
@@ -67,6 +67,16 @@ func TestRestoreExpose(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
modeBlock := corev1api.PersistentVolumeBlock
|
||||
targetPVObjWithDifferentVolumeMode := &corev1api.PersistentVolume{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "fake-target-pv",
|
||||
},
|
||||
Spec: corev1api.PersistentVolumeSpec{
|
||||
VolumeMode: &modeBlock,
|
||||
},
|
||||
}
|
||||
|
||||
modeFilesystem := corev1api.PersistentVolumeFilesystem
|
||||
targetPVCObjWithVolumeMode := &corev1api.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
@@ -130,6 +140,7 @@ func TestRestoreExpose(t *testing.T) {
|
||||
expectBackupPod bool
|
||||
expectBackupPVC bool
|
||||
expectCachePVC bool
|
||||
expectBackupPV bool
|
||||
err string
|
||||
}{
|
||||
{
|
||||
@@ -244,6 +255,96 @@ func TestRestoreExpose(t *testing.T) {
|
||||
expectBackupPod: true,
|
||||
expectBackupPVC: true,
|
||||
},
|
||||
{
|
||||
name: "create temporary PV fail",
|
||||
targetPVCName: "fake-target-pvc",
|
||||
targetNamespace: "fake-ns",
|
||||
targetPVName: "fake-target-pv",
|
||||
ownerRestore: restore,
|
||||
kubeClientObj: []runtime.Object{
|
||||
targetPVCObj,
|
||||
targetPVObjWithDifferentVolumeMode,
|
||||
daemonSet,
|
||||
storageClass,
|
||||
},
|
||||
kubeReactors: []reactor{
|
||||
{
|
||||
verb: "create",
|
||||
resource: "persistentvolumes",
|
||||
reactorFunc: func(action clientTesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
return true, nil, errors.New("fake-create-pv-error")
|
||||
},
|
||||
},
|
||||
},
|
||||
err: "error to create restore pvc: fail to create the temporary PV fake-restore: fake-create-pv-error",
|
||||
},
|
||||
{
|
||||
name: "delete original PV fail",
|
||||
targetPVCName: "fake-target-pvc",
|
||||
targetNamespace: "fake-ns",
|
||||
targetPVName: "fake-target-pv",
|
||||
ownerRestore: restore,
|
||||
kubeClientObj: []runtime.Object{
|
||||
targetPVCObj,
|
||||
targetPVObjWithDifferentVolumeMode,
|
||||
daemonSet,
|
||||
storageClass,
|
||||
},
|
||||
kubeReactors: []reactor{
|
||||
{
|
||||
verb: "delete",
|
||||
resource: "persistentvolumes",
|
||||
reactorFunc: func(action clientTesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
deleteAction := action.(clientTesting.DeleteAction)
|
||||
if deleteAction.GetName() == "fake-target-pv" {
|
||||
return true, nil, errors.New("fake-delete-pv-error")
|
||||
}
|
||||
return false, nil, nil
|
||||
},
|
||||
},
|
||||
},
|
||||
err: "error to create restore pvc: fail to delete the target PV fake-target-pv: fake-delete-pv-error",
|
||||
},
|
||||
{
|
||||
name: "succeed with target PV set and different volume mode",
|
||||
targetPVCName: "fake-target-pvc",
|
||||
targetNamespace: "fake-ns",
|
||||
targetPVName: "fake-target-pv",
|
||||
ownerRestore: restore,
|
||||
kubeClientObj: []runtime.Object{
|
||||
targetPVCObj,
|
||||
targetPVObjWithDifferentVolumeMode,
|
||||
daemonSet,
|
||||
storageClass,
|
||||
},
|
||||
kubeReactors: []reactor{
|
||||
{
|
||||
verb: "get",
|
||||
resource: "persistentvolumeclaims",
|
||||
reactorFunc: func(action clientTesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
getAction := action.(clientTesting.GetAction)
|
||||
if getAction.GetName() == "fake-restore" {
|
||||
return true, &corev1api.PersistentVolumeClaim{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "fake-restore",
|
||||
Namespace: velerov1.DefaultNamespace,
|
||||
},
|
||||
Spec: corev1api.PersistentVolumeClaimSpec{
|
||||
VolumeName: "fake-restore",
|
||||
},
|
||||
Status: corev1api.PersistentVolumeClaimStatus{
|
||||
Phase: corev1api.ClaimBound,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
return false, nil, nil
|
||||
},
|
||||
},
|
||||
},
|
||||
expectBackupPod: true,
|
||||
expectBackupPVC: true,
|
||||
expectBackupPV: true,
|
||||
},
|
||||
{
|
||||
name: "succeed, cache config, no cache volume",
|
||||
targetPVCName: "fake-target-pvc",
|
||||
@@ -375,7 +476,7 @@ func TestRestoreExpose(t *testing.T) {
|
||||
if test.expectBackupPod {
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
require.True(t, apierrors.IsNotFound(err))
|
||||
require.True(t, apierrors.IsNotFound(err), "expected IsNotFound, got %v", err)
|
||||
}
|
||||
|
||||
pvc, err := exposer.kubeClient.CoreV1().PersistentVolumeClaims(ownerObject.Namespace).Get(t.Context(), ownerObject.Name, metav1.GetOptions{})
|
||||
@@ -386,14 +487,31 @@ func TestRestoreExpose(t *testing.T) {
|
||||
require.Equal(t, corev1api.PersistentVolumeBlock, *pvc.Spec.VolumeMode)
|
||||
}
|
||||
} else {
|
||||
require.True(t, apierrors.IsNotFound(err))
|
||||
require.True(t, apierrors.IsNotFound(err), "expected IsNotFound, got %v", err)
|
||||
}
|
||||
|
||||
_, err = exposer.kubeClient.CoreV1().PersistentVolumeClaims(ownerObject.Namespace).Get(t.Context(), getCachePVCName(ownerObject), metav1.GetOptions{})
|
||||
if test.expectCachePVC {
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
require.True(t, apierrors.IsNotFound(err))
|
||||
require.True(t, apierrors.IsNotFound(err), "expected IsNotFound, got %v", err)
|
||||
}
|
||||
|
||||
_, err = exposer.kubeClient.CoreV1().PersistentVolumes().Get(t.Context(), ownerObject.Name, metav1.GetOptions{})
|
||||
if test.expectBackupPV {
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
require.True(t, apierrors.IsNotFound(err), "expected IsNotFound, got %v", err)
|
||||
}
|
||||
|
||||
if test.targetPVName != "" && !test.expectBackupPV && test.err == "" {
|
||||
// if targetPVName was provided, and sameVolumeMode was true, the original PV should still exist
|
||||
_, err = exposer.kubeClient.CoreV1().PersistentVolumes().Get(t.Context(), test.targetPVName, metav1.GetOptions{})
|
||||
require.NoError(t, err)
|
||||
} else if test.targetPVName != "" && test.expectBackupPV {
|
||||
// if targetPVName was provided, and sameVolumeMode was false (expectBackupPV is true), the original PV should be deleted
|
||||
_, err = exposer.kubeClient.CoreV1().PersistentVolumes().Get(t.Context(), test.targetPVName, metav1.GetOptions{})
|
||||
require.True(t, apierrors.IsNotFound(err), "expected original PV %s to be deleted, but it still exists", test.targetPVName)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user