mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-01-07 13:55:20 +00:00
csi pvc backup action
Signed-off-by: Amos Mastbaum <68001528+amastbau@users.noreply.github.com> Update pvc_action.go Signed-off-by: Amos Mastbaum <68001528+amastbau@users.noreply.github.com> Update pvc_action.go Signed-off-by: Amos Mastbaum <68001528+amastbau@users.noreply.github.com> Adding missing test covarage + log mesasgae as suggested Signed-off-by: Amos Mastbaum <68001528+amastbau@users.noreply.github.com> Adding missing test covarage + log mesasgae as suggested Signed-off-by: Amos Mastbaum <68001528+amastbau@users.noreply.github.com>
This commit is contained in:
committed by
Xun Jiang/Bruce Jiang
parent
21fa637f17
commit
687dcf69e7
@@ -42,9 +42,11 @@ import (
|
||||
crclient "sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
|
||||
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/client"
|
||||
veleroclient "github.com/vmware-tanzu/velero/pkg/client"
|
||||
"github.com/vmware-tanzu/velero/pkg/kuberesource"
|
||||
"github.com/vmware-tanzu/velero/pkg/label"
|
||||
plugincommon "github.com/vmware-tanzu/velero/pkg/plugin/framework/common"
|
||||
@@ -267,6 +269,21 @@ func (p *pvcBackupItemAction) Execute(
|
||||
return nil, nil, "", nil, err
|
||||
}
|
||||
|
||||
// Wait until VS associated VSC snapshot handle created before
|
||||
// continue.we later require the vsc restore size
|
||||
vsc, err := csi.WaitUntilVSCHandleIsReady(
|
||||
vs,
|
||||
p.crClient,
|
||||
p.log,
|
||||
backup.Spec.CSISnapshotTimeout.Duration,
|
||||
)
|
||||
if err != nil {
|
||||
p.log.Errorf("Failed to wait for VolumeSnapshot %s/%s to become ReadyToUse within timeout %v: %s",
|
||||
vs.Namespace, vs.Name, backup.Spec.CSISnapshotTimeout.Duration, err.Error())
|
||||
csi.CleanupVolumeSnapshot(vs, p.crClient, p.log)
|
||||
return nil, nil, "", nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
labels := map[string]string{
|
||||
velerov1api.VolumeSnapshotLabel: vs.Name,
|
||||
velerov1api.BackupNameLabel: backup.Name,
|
||||
@@ -294,23 +311,6 @@ func (p *pvcBackupItemAction) Execute(
|
||||
"Backup": backup.Name,
|
||||
})
|
||||
|
||||
// Wait until VS associated VSC snapshot handle created before
|
||||
// returning with the Async operation for data mover.
|
||||
vsc, err := csi.WaitUntilVSCHandleIsReady(
|
||||
vs,
|
||||
p.crClient,
|
||||
p.log,
|
||||
backup.Spec.CSISnapshotTimeout.Duration,
|
||||
)
|
||||
if err != nil {
|
||||
dataUploadLog.Errorf(
|
||||
"Fail to wait VolumeSnapshot turned to ReadyToUse: %s",
|
||||
err.Error(),
|
||||
)
|
||||
csi.CleanupVolumeSnapshot(vs, p.crClient, p.log)
|
||||
return nil, nil, "", nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
dataUploadLog.Info("Starting data upload of backup")
|
||||
|
||||
dataUpload, err := createDataUpload(
|
||||
@@ -355,6 +355,8 @@ func (p *pvcBackupItemAction) Execute(
|
||||
dataUploadLog.Info("DataUpload is submitted successfully.")
|
||||
}
|
||||
} else {
|
||||
setPVCRequestSizeToVSRestoreSize(&pvc, vsc, p.log)
|
||||
|
||||
additionalItems = []velero.ResourceIdentifier{
|
||||
{
|
||||
GroupResource: kuberesource.VolumeSnapshots,
|
||||
@@ -571,7 +573,7 @@ func cancelDataUpload(
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewPvcBackupItemAction(f client.Factory) plugincommon.HandlerInitializer {
|
||||
func NewPvcBackupItemAction(f veleroclient.Factory) plugincommon.HandlerInitializer {
|
||||
return func(logger logrus.FieldLogger) (any, error) {
|
||||
crClient, err := f.KubebuilderClient()
|
||||
if err != nil {
|
||||
@@ -1036,3 +1038,45 @@ func (p *pvcBackupItemAction) getVGSByLabels(ctx context.Context, namespace stri
|
||||
|
||||
return &vgsList.Items[0], nil
|
||||
}
|
||||
|
||||
func setPVCRequestSizeToVSRestoreSize(
|
||||
pvc *corev1api.PersistentVolumeClaim,
|
||||
vsc *snapshotv1api.VolumeSnapshotContent,
|
||||
logger logrus.FieldLogger,
|
||||
) {
|
||||
if vsc.Status.RestoreSize != nil {
|
||||
logger.Debugf("Patching PVC request size to fit the volumesnapshot restore size %d", vsc.Status.RestoreSize)
|
||||
restoreSize := *resource.NewQuantity(*vsc.Status.RestoreSize, resource.BinarySI)
|
||||
|
||||
// It is possible that the volume provider allocated a larger
|
||||
// capacity volume than what was requested in the backed up PVC.
|
||||
// In this scenario the volumesnapshot of the PVC will end being
|
||||
// larger than its requested storage size. Such a PVC, on restore
|
||||
// as-is, will be stuck attempting to use a VolumeSnapshot as a
|
||||
// data source for a PVC that is not large enough.
|
||||
// To counter that, here we set the storage request on the PVC
|
||||
// to the larger of the PVC's storage request and the size of the
|
||||
// VolumeSnapshot
|
||||
setPVCStorageResourceRequest(pvc, restoreSize, logger)
|
||||
}
|
||||
}
|
||||
|
||||
func setPVCStorageResourceRequest(
|
||||
pvc *corev1api.PersistentVolumeClaim,
|
||||
restoreSize resource.Quantity,
|
||||
log logrus.FieldLogger,
|
||||
) {
|
||||
{
|
||||
if pvc.Spec.Resources.Requests == nil {
|
||||
pvc.Spec.Resources.Requests = corev1api.ResourceList{}
|
||||
}
|
||||
|
||||
storageReq, exists := pvc.Spec.Resources.Requests[corev1api.ResourceStorage]
|
||||
if !exists || storageReq.Cmp(restoreSize) < 0 {
|
||||
pvc.Spec.Resources.Requests[corev1api.ResourceStorage] = restoreSize
|
||||
rs := pvc.Spec.Resources.Requests[corev1api.ResourceStorage]
|
||||
log.Infof("Resetting storage requests for PVC %s/%s to %s",
|
||||
pvc.Namespace, pvc.Name, rs.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,10 +36,13 @@ import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
snapshotv1api "github.com/kubernetes-csi/external-snapshotter/client/v8/apis/volumesnapshot/v1"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/stretchr/testify/require"
|
||||
corev1api "k8s.io/api/core/v1"
|
||||
storagev1api "k8s.io/api/storage/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
@@ -54,11 +57,27 @@ import (
|
||||
factorymocks "github.com/vmware-tanzu/velero/pkg/client/mocks"
|
||||
"github.com/vmware-tanzu/velero/pkg/plugin/velero"
|
||||
velerotest "github.com/vmware-tanzu/velero/pkg/test"
|
||||
"github.com/vmware-tanzu/velero/pkg/util/boolptr"
|
||||
)
|
||||
|
||||
const testDriver = "csi.example.com"
|
||||
|
||||
// errorInjectingClient is a wrapper around a normal client that injects an error
|
||||
// when a specific resource type (VolumeSnapshot) is created.
|
||||
type errorInjectingClient struct {
|
||||
crclient.Client
|
||||
}
|
||||
|
||||
// Create overrides the embedded client's Create method.
|
||||
func (c *errorInjectingClient) Create(ctx context.Context, obj crclient.Object, opts ...crclient.CreateOption) error {
|
||||
// Check if the object being created is a VolumeSnapshot.
|
||||
if _, ok := obj.(*snapshotv1api.VolumeSnapshot); ok {
|
||||
// If it is, return our injected error instead of proceeding.
|
||||
return errors.New("injected error on create")
|
||||
}
|
||||
// For all other object types, call the original, embedded Create method.
|
||||
return c.Client.Create(ctx, obj, opts...)
|
||||
}
|
||||
|
||||
func TestExecute(t *testing.T) {
|
||||
boolTrue := true
|
||||
tests := []struct {
|
||||
@@ -70,15 +89,37 @@ func TestExecute(t *testing.T) {
|
||||
vsClass *snapshotv1api.VolumeSnapshotClass
|
||||
operationID string
|
||||
expectedErr error
|
||||
expectErr bool // Use bool for cases where we just need to check for any error
|
||||
expectedBackup *velerov1api.Backup
|
||||
expectedDataUpload *velerov2alpha1.DataUpload
|
||||
expectedPVC *corev1api.PersistentVolumeClaim
|
||||
resourcePolicy *corev1api.ConfigMap
|
||||
failVSCreate bool
|
||||
skipVSReadyUpdate bool // New flag to control VS readiness
|
||||
}{
|
||||
{
|
||||
name: "Skip PVC BIA when backup is in finalizing phase",
|
||||
backup: builder.ForBackup("velero", "test").Phase(velerov1api.BackupPhaseFinalizing).Result(),
|
||||
expectedErr: nil,
|
||||
name: "Skip PVC BIA when backup is in finalizing phase",
|
||||
backup: builder.ForBackup("velero", "test").Phase(velerov1api.BackupPhaseFinalizing).Result(),
|
||||
},
|
||||
{
|
||||
name: "Fail when creating volumesnapshot returns error",
|
||||
backup: builder.ForBackup("velero", "test").CSISnapshotTimeout(1 * time.Minute).Result(),
|
||||
pvc: builder.ForPersistentVolumeClaim("velero", "testPVC").VolumeName("testPV").StorageClass("testSC").Phase(corev1api.ClaimBound).Result(),
|
||||
pv: builder.ForPersistentVolume("testPV").CSI("hostpath", "testVolume").Result(),
|
||||
sc: builder.ForStorageClass("testSC").Provisioner("hostpath").Result(),
|
||||
vsClass: builder.ForVolumeSnapshotClass("testVSClass").Driver("hostpath").ObjectMeta(builder.WithLabels(velerov1api.VolumeSnapshotClassSelectorLabel, "")).Result(),
|
||||
failVSCreate: true,
|
||||
expectedErr: errors.New("error creating volume snapshot: injected error on create"),
|
||||
},
|
||||
{
|
||||
name: "Fail when waiting for VolumeSnapshot to be ready times out",
|
||||
backup: builder.ForBackup("velero", "test").CSISnapshotTimeout(20 * time.Millisecond).Result(), // Short timeout
|
||||
pvc: builder.ForPersistentVolumeClaim("velero", "testPVC").VolumeName("testPV").StorageClass("testSC").Phase(corev1api.ClaimBound).Result(),
|
||||
pv: builder.ForPersistentVolume("testPV").CSI("hostpath", "testVolume").Result(),
|
||||
sc: builder.ForStorageClass("testSC").Provisioner("hostpath").Result(),
|
||||
vsClass: builder.ForVolumeSnapshotClass("testVSClass").Driver("hostpath").ObjectMeta(builder.WithLabels(velerov1api.VolumeSnapshotClassSelectorLabel, "")).Result(),
|
||||
skipVSReadyUpdate: true, // This will cause the timeout
|
||||
expectErr: true, // Expect an error, but the exact message can vary
|
||||
},
|
||||
{
|
||||
name: "Test SnapshotMoveData",
|
||||
@@ -88,7 +129,6 @@ func TestExecute(t *testing.T) {
|
||||
sc: builder.ForStorageClass("testSC").Provisioner("hostpath").Result(),
|
||||
vsClass: builder.ForVolumeSnapshotClass("testVSClass").Driver("hostpath").ObjectMeta(builder.WithLabels(velerov1api.VolumeSnapshotClassSelectorLabel, "")).Result(),
|
||||
operationID: ".",
|
||||
expectedErr: nil,
|
||||
expectedDataUpload: &velerov2alpha1.DataUpload{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "DataUpload",
|
||||
@@ -134,7 +174,6 @@ func TestExecute(t *testing.T) {
|
||||
sc: builder.ForStorageClass("testSC").Provisioner("hostpath").Result(),
|
||||
vsClass: builder.ForVolumeSnapshotClass("tescVSClass").Driver("hostpath").ObjectMeta(builder.WithLabels(velerov1api.VolumeSnapshotClassSelectorLabel, "")).Result(),
|
||||
operationID: ".",
|
||||
expectedErr: nil,
|
||||
expectedPVC: builder.ForPersistentVolumeClaim("velero", "testPVC").
|
||||
ObjectMeta(builder.WithAnnotations(velerov1api.MustIncludeAdditionalItemAnnotation, "true", velerov1api.DataUploadNameAnnotation, "velero/"),
|
||||
builder.WithLabels(velerov1api.BackupNameLabel, "test")).
|
||||
@@ -142,18 +181,17 @@ func TestExecute(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "Test ResourcePolicy",
|
||||
backup: builder.ForBackup("velero", "test").ResourcePolicies("resourcePolicy").SnapshotVolumes(false).Result(),
|
||||
backup: builder.ForBackup("velero", "test").ResourcePolicies("resourcePolicy").SnapshotVolumes(false).CSISnapshotTimeout(time.Duration(3600) * time.Second).Result(),
|
||||
resourcePolicy: builder.ForConfigMap("velero", "resourcePolicy").Data("policy", "{\"version\":\"v1\", \"volumePolicies\":[{\"conditions\":{\"csi\": {}},\"action\":{\"type\":\"snapshot\"}}]}").Result(),
|
||||
pvc: builder.ForPersistentVolumeClaim("velero", "testPVC").VolumeName("testPV").StorageClass("testSC").Phase(corev1api.ClaimBound).Result(),
|
||||
pv: builder.ForPersistentVolume("testPV").CSI("hostpath", "testVolume").Result(),
|
||||
sc: builder.ForStorageClass("testSC").Provisioner("hostpath").Result(),
|
||||
vsClass: builder.ForVolumeSnapshotClass("tescVSClass").Driver("hostpath").ObjectMeta(builder.WithLabels(velerov1api.VolumeSnapshotClassSelectorLabel, "")).Result(),
|
||||
expectedErr: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(*testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
logger := logrus.New()
|
||||
logger.Level = logrus.DebugLevel
|
||||
objects := make([]runtime.Object, 0)
|
||||
@@ -173,7 +211,13 @@ func TestExecute(t *testing.T) {
|
||||
objects = append(objects, tc.resourcePolicy)
|
||||
}
|
||||
|
||||
crClient := velerotest.NewFakeControllerRuntimeClient(t, objects...)
|
||||
var crClient crclient.Client
|
||||
if tc.failVSCreate {
|
||||
realFakeClient := velerotest.NewFakeControllerRuntimeClient(t, objects...)
|
||||
crClient = &errorInjectingClient{Client: realFakeClient}
|
||||
} else {
|
||||
crClient = velerotest.NewFakeControllerRuntimeClient(t, objects...)
|
||||
}
|
||||
|
||||
pvcBIA := pvcBackupItemAction{
|
||||
log: logger,
|
||||
@@ -183,7 +227,7 @@ func TestExecute(t *testing.T) {
|
||||
pvcMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&tc.pvc)
|
||||
require.NoError(t, err)
|
||||
|
||||
if boolptr.IsSetToTrue(tc.backup.Spec.SnapshotMoveData) == true {
|
||||
if tc.pvc != nil && !tc.failVSCreate && !tc.skipVSReadyUpdate {
|
||||
go func() {
|
||||
var vsList snapshotv1api.VolumeSnapshotList
|
||||
err := wait.PollUntilContextTimeout(t.Context(), 1*time.Second, 10*time.Second, true, func(ctx context.Context) (bool, error) {
|
||||
@@ -191,8 +235,7 @@ func TestExecute(t *testing.T) {
|
||||
|
||||
require.NoError(t, err)
|
||||
if err != nil || len(vsList.Items) == 0 {
|
||||
//lint:ignore nilerr reason
|
||||
return false, nil // ignore
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
@@ -215,8 +258,18 @@ func TestExecute(t *testing.T) {
|
||||
}
|
||||
|
||||
resultUnstructed, _, _, _, err := pvcBIA.Execute(&unstructured.Unstructured{Object: pvcMap}, tc.backup)
|
||||
|
||||
if tc.expectedErr != nil {
|
||||
require.EqualError(t, err, tc.expectedErr.Error())
|
||||
} else if tc.expectErr {
|
||||
require.Error(t, err)
|
||||
// On timeout failure, check that the cleanup logic was called
|
||||
if tc.skipVSReadyUpdate {
|
||||
vsList := new(snapshotv1api.VolumeSnapshotList)
|
||||
errList := crClient.List(t.Context(), vsList, &crclient.ListOptions{Namespace: tc.pvc.Namespace})
|
||||
require.NoError(t, errList)
|
||||
require.Empty(t, vsList.Items, "VolumeSnapshot should have been cleaned up after readiness check failed")
|
||||
}
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
@@ -232,7 +285,6 @@ func TestExecute(t *testing.T) {
|
||||
if tc.expectedPVC != nil {
|
||||
resultPVC := new(corev1api.PersistentVolumeClaim)
|
||||
runtime.DefaultUnstructuredConverter.FromUnstructured(resultUnstructed.UnstructuredContent(), resultPVC)
|
||||
|
||||
require.True(t, cmp.Equal(tc.expectedPVC, resultPVC, cmpopts.IgnoreFields(corev1api.PersistentVolumeClaim{}, "ResourceVersion", "Annotations", "Labels")))
|
||||
}
|
||||
})
|
||||
@@ -296,7 +348,7 @@ func TestProgress(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(*testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
crClient := velerotest.NewFakeControllerRuntimeClient(t)
|
||||
logger := logrus.New()
|
||||
|
||||
@@ -345,7 +397,6 @@ func TestCancel(t *testing.T) {
|
||||
},
|
||||
},
|
||||
operationID: "testing",
|
||||
expectedErr: nil,
|
||||
expectedDataUpload: velerov2alpha1.DataUpload{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "DataUpload",
|
||||
@@ -366,7 +417,7 @@ func TestCancel(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(*testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
crClient := velerotest.NewFakeControllerRuntimeClient(t)
|
||||
logger := logrus.New()
|
||||
|
||||
@@ -379,9 +430,7 @@ func TestCancel(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
err = pvcBIA.Cancel(tc.operationID, tc.backup)
|
||||
if tc.expectedErr != nil {
|
||||
require.EqualError(t, err, tc.expectedErr.Error())
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
du := new(velerov2alpha1.DataUpload)
|
||||
err = crClient.Get(t.Context(), crclient.ObjectKey{Namespace: tc.dataUpload.Namespace, Name: tc.dataUpload.Name}, du)
|
||||
@@ -1554,3 +1603,85 @@ func TestHasOwnerReference(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPVCRequestSize(t *testing.T) {
|
||||
logger := logrus.New()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
pvcInitial *corev1api.PersistentVolumeClaim // Use full PVC to allow for nil Requests
|
||||
restoreSize string
|
||||
expectedSize string
|
||||
}{
|
||||
{
|
||||
name: "UpdateRequired: PVC request is lower than restore size",
|
||||
pvcInitial: func() *corev1api.PersistentVolumeClaim {
|
||||
pvc := builder.ForPersistentVolumeClaim("velero", "testPVC").Result()
|
||||
pvc.Spec.Resources.Requests = corev1api.ResourceList{
|
||||
corev1api.ResourceStorage: resource.MustParse("1Gi"),
|
||||
}
|
||||
return pvc
|
||||
}(),
|
||||
restoreSize: "2Gi",
|
||||
expectedSize: "2Gi",
|
||||
},
|
||||
{
|
||||
name: "NoUpdateRequired: PVC request is larger than restore size",
|
||||
pvcInitial: func() *corev1api.PersistentVolumeClaim {
|
||||
pvc := builder.ForPersistentVolumeClaim("velero", "testPVC").Result()
|
||||
pvc.Spec.Resources.Requests = corev1api.ResourceList{
|
||||
corev1api.ResourceStorage: resource.MustParse("3Gi"),
|
||||
}
|
||||
return pvc
|
||||
}(),
|
||||
restoreSize: "2Gi",
|
||||
expectedSize: "3Gi",
|
||||
},
|
||||
{
|
||||
name: "PVC has no initial storage request",
|
||||
pvcInitial: func() *corev1api.PersistentVolumeClaim {
|
||||
pvc := builder.ForPersistentVolumeClaim("velero", "testPVC").Result()
|
||||
pvc.Spec.Resources.Requests = corev1api.ResourceList{} // Empty request list
|
||||
return pvc
|
||||
}(),
|
||||
restoreSize: "2Gi",
|
||||
expectedSize: "2Gi",
|
||||
},
|
||||
{
|
||||
name: "PVC has no initial Resources.Requests map",
|
||||
pvcInitial: func() *corev1api.PersistentVolumeClaim {
|
||||
pvc := builder.ForPersistentVolumeClaim("velero", "testPVC").Result()
|
||||
pvc.Spec.Resources.Requests = nil // This will trigger the line to be covered
|
||||
return pvc
|
||||
}(),
|
||||
restoreSize: "2Gi",
|
||||
expectedSize: "2Gi",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// Create a VolumeSnapshotContent with restore size
|
||||
rsQty := resource.MustParse(tc.restoreSize)
|
||||
|
||||
vsc := &snapshotv1api.VolumeSnapshotContent{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "testVSC",
|
||||
},
|
||||
Status: &snapshotv1api.VolumeSnapshotContentStatus{
|
||||
RestoreSize: pointer.Int64(rsQty.Value()),
|
||||
},
|
||||
}
|
||||
|
||||
// Call the function under test
|
||||
pvc := tc.pvcInitial
|
||||
setPVCRequestSizeToVSRestoreSize(pvc, vsc, logger)
|
||||
|
||||
// Verify that the PVC storage request is updated as expected.
|
||||
updatedSize := pvc.Spec.Resources.Requests[corev1api.ResourceStorage]
|
||||
expected := resource.MustParse(tc.expectedSize)
|
||||
// Corrected line below:
|
||||
require.Equal(t, 0, expected.Cmp(updatedSize), "Expected size %s, but got %s", expected.String(), updatedSize.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user