From 6b4d43142a7c9d16526772fcccefac0d5552ff71 Mon Sep 17 00:00:00 2001 From: Isteb4k Date: Thu, 27 Jun 2024 11:24:16 +0200 Subject: [PATCH] fix(vd): fix fake pvc resizing fix(vd): fix fake pvc resizing Signed-off-by: Isteb4k --- api/core/v1alpha2/vdcondition/condition.go | 2 - crds/doc-ru-virtualdisk.yaml | 1 + crds/virtualdisk.yaml | 2 + .../pkg/controller/service/disk_service.go | 18 +- .../pkg/controller/service/errors.go | 2 - .../controller/vd/internal/handler_test.go | 29 ++ .../pkg/controller/vd/internal/interfaces.go | 13 +- .../pkg/controller/vd/internal/mock.go | 131 +++++++++ .../pkg/controller/vd/internal/resizing.go | 71 +++-- .../controller/vd/internal/resizing_test.go | 257 ++++++++++-------- .../controller/vd/internal/source/errors.go | 4 +- .../pkg/controller/vd/vd_reconciler.go | 1 - 12 files changed, 377 insertions(+), 154 deletions(-) create mode 100644 images/virtualization-artifact/pkg/controller/vd/internal/handler_test.go diff --git a/api/core/v1alpha2/vdcondition/condition.go b/api/core/v1alpha2/vdcondition/condition.go index 31db8350..181db7c6 100644 --- a/api/core/v1alpha2/vdcondition/condition.go +++ b/api/core/v1alpha2/vdcondition/condition.go @@ -64,8 +64,6 @@ const ( NotRequested ResizedReason = "NotRequested" // InProgress indicates that the resize request has been detected and the operation is currently in progress. InProgress ResizedReason = "InProgress" - // TooSmallDiskSize indicates that the requested disk size is too small for the resize operation. - TooSmallDiskSize ResizedReason = "TooSmallDiskSize" // Resized indicates that the resize operation has been successfully completed. Resized ResizedReason = "Resized" ) diff --git a/crds/doc-ru-virtualdisk.yaml b/crds/doc-ru-virtualdisk.yaml index 4ffefbd2..2e65df76 100644 --- a/crds/doc-ru-virtualdisk.yaml +++ b/crds/doc-ru-virtualdisk.yaml @@ -140,6 +140,7 @@ spec: * Provisioning — идет процесс создания ресурса (копирование/загрузка/создание образа). * WaitForUserUpload — ожидание загрузки образа пользователем. Путь для загрузки образа указывается в `.status.uploadCommand`. * Ready — ресурс создан и готов к использованию. + * Resizing — идет процесс увеличения размера диска. * Failed — при создании ресурса возникла проблема. * PVCLost — дочерний PVC ресурса отсутствует. Ресурс не может быть использован. * Terminating - Ресурс находится в процессе удаления. diff --git a/crds/virtualdisk.yaml b/crds/virtualdisk.yaml index 0a1d39c6..b4ae436a 100644 --- a/crds/virtualdisk.yaml +++ b/crds/virtualdisk.yaml @@ -265,6 +265,7 @@ spec: * Provisioning - The process of resource creation (copying/downloading/filling the PVC with data/extending PVC) is in progress. * WaitForUserUpload - Waiting for the user to upload the image. The endpoint to upload the image is specified in `.status.uploadCommand`. * Ready - The resource is created and ready to use. + * Resizing — The process of resource resizing is in progress. * Failed - There was a problem when creating a resource, details can be seen in `.status.failureReason` and `.status.failureMessage`. * PVCLost - The child PVC of the resource is missing. The resource cannot be used. * Terminating - The process of resource deletion is in progress. @@ -274,6 +275,7 @@ spec: "Provisioning", "WaitForUserUpload", "Ready", + "Resizing", "Failed", "PVCLost", "Terminating", diff --git a/images/virtualization-artifact/pkg/controller/service/disk_service.go b/images/virtualization-artifact/pkg/controller/service/disk_service.go index 43a3c24d..5ff9e278 100644 --- a/images/virtualization-artifact/pkg/controller/service/disk_service.go +++ b/images/virtualization-artifact/pkg/controller/service/disk_service.go @@ -166,32 +166,22 @@ func (s DiskService) Unprotect(ctx context.Context, dv *cdiv1.DataVolume) error return s.protection.RemoveProtection(ctx, dv) } -func (s DiskService) Resize(ctx context.Context, pvc *corev1.PersistentVolumeClaim, newSize resource.Quantity, sup *supplements.Generator) error { +func (s DiskService) Resize(ctx context.Context, pvc *corev1.PersistentVolumeClaim, newSize resource.Quantity) error { if pvc == nil { return errors.New("got nil pvc") } curSize := pvc.Spec.Resources.Requests[corev1.ResourceStorage] - - if newSize.Cmp(curSize) == -1 { - return ErrTooSmallDiskSize - } - - switch newSize.Cmp(curSize) { - case 0: - return nil - case -1: - return ErrTooSmallDiskSize - default: + if newSize.Cmp(curSize) == 1 { pvc.Spec.Resources.Requests[corev1.ResourceStorage] = newSize err := s.client.Update(ctx, pvc) if err != nil { return fmt.Errorf("failed to increase pvc size: %w", err) } - - return nil } + + return nil } func (s DiskService) IsImportDone(dv *cdiv1.DataVolume, pvc *corev1.PersistentVolumeClaim) bool { diff --git a/images/virtualization-artifact/pkg/controller/service/errors.go b/images/virtualization-artifact/pkg/controller/service/errors.go index e4ca5386..c60d6695 100644 --- a/images/virtualization-artifact/pkg/controller/service/errors.go +++ b/images/virtualization-artifact/pkg/controller/service/errors.go @@ -18,8 +18,6 @@ package service import "errors" -var ErrTooSmallDiskSize = errors.New("virtual disk size is too small") - var ( ErrStorageClassNotFound = errors.New("storage class not found") ErrDefaultStorageClassNotFound = errors.New("default storage class not found") diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/handler_test.go b/images/virtualization-artifact/pkg/controller/vd/internal/handler_test.go new file mode 100644 index 00000000..68c60dea --- /dev/null +++ b/images/virtualization-artifact/pkg/controller/vd/internal/handler_test.go @@ -0,0 +1,29 @@ +/* +Copyright 2024 Flant JSC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package internal + +import ( + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +func TestHandlers(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Handlers") +} diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/interfaces.go b/images/virtualization-artifact/pkg/controller/vd/internal/interfaces.go index 3f8a94c0..31d1fc7a 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/interfaces.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/interfaces.go @@ -17,14 +17,25 @@ limitations under the License. package internal import ( + "context" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + + "github.com/deckhouse/virtualization-controller/pkg/controller/supplements" "github.com/deckhouse/virtualization-controller/pkg/controller/vd/internal/source" virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2" ) -//go:generate moq -rm -out mock.go . Handler Sources +//go:generate moq -rm -out mock.go . Handler Sources DiskService type Handler = source.Handler type Sources interface { Get(dsType virtv2.DataSourceType) (source.Handler, bool) } + +type DiskService interface { + Resize(ctx context.Context, pvc *corev1.PersistentVolumeClaim, newSize resource.Quantity) error + GetPersistentVolumeClaim(ctx context.Context, sup *supplements.Generator) (*corev1.PersistentVolumeClaim, error) +} diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/mock.go b/images/virtualization-artifact/pkg/controller/vd/internal/mock.go index 941a9fd8..0b40a061 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/mock.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/mock.go @@ -5,8 +5,11 @@ package internal import ( "context" + "github.com/deckhouse/virtualization-controller/pkg/controller/supplements" "github.com/deckhouse/virtualization-controller/pkg/controller/vd/internal/source" virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" "sync" ) @@ -247,3 +250,131 @@ func (mock *SourcesMock) GetCalls() []struct { mock.lockGet.RUnlock() return calls } + +// Ensure, that DiskServiceMock does implement DiskService. +// If this is not the case, regenerate this file with moq. +var _ DiskService = &DiskServiceMock{} + +// DiskServiceMock is a mock implementation of DiskService. +// +// func TestSomethingThatUsesDiskService(t *testing.T) { +// +// // make and configure a mocked DiskService +// mockedDiskService := &DiskServiceMock{ +// GetPersistentVolumeClaimFunc: func(ctx context.Context, sup *supplements.Generator) (*corev1.PersistentVolumeClaim, error) { +// panic("mock out the GetPersistentVolumeClaim method") +// }, +// ResizeFunc: func(ctx context.Context, pvc *corev1.PersistentVolumeClaim, newSize resource.Quantity) error { +// panic("mock out the Resize method") +// }, +// } +// +// // use mockedDiskService in code that requires DiskService +// // and then make assertions. +// +// } +type DiskServiceMock struct { + // GetPersistentVolumeClaimFunc mocks the GetPersistentVolumeClaim method. + GetPersistentVolumeClaimFunc func(ctx context.Context, sup *supplements.Generator) (*corev1.PersistentVolumeClaim, error) + + // ResizeFunc mocks the Resize method. + ResizeFunc func(ctx context.Context, pvc *corev1.PersistentVolumeClaim, newSize resource.Quantity) error + + // calls tracks calls to the methods. + calls struct { + // GetPersistentVolumeClaim holds details about calls to the GetPersistentVolumeClaim method. + GetPersistentVolumeClaim []struct { + // Ctx is the ctx argument value. + Ctx context.Context + // Sup is the sup argument value. + Sup *supplements.Generator + } + // Resize holds details about calls to the Resize method. + Resize []struct { + // Ctx is the ctx argument value. + Ctx context.Context + // Pvc is the pvc argument value. + Pvc *corev1.PersistentVolumeClaim + // NewSize is the newSize argument value. + NewSize resource.Quantity + } + } + lockGetPersistentVolumeClaim sync.RWMutex + lockResize sync.RWMutex +} + +// GetPersistentVolumeClaim calls GetPersistentVolumeClaimFunc. +func (mock *DiskServiceMock) GetPersistentVolumeClaim(ctx context.Context, sup *supplements.Generator) (*corev1.PersistentVolumeClaim, error) { + if mock.GetPersistentVolumeClaimFunc == nil { + panic("DiskServiceMock.GetPersistentVolumeClaimFunc: method is nil but DiskService.GetPersistentVolumeClaim was just called") + } + callInfo := struct { + Ctx context.Context + Sup *supplements.Generator + }{ + Ctx: ctx, + Sup: sup, + } + mock.lockGetPersistentVolumeClaim.Lock() + mock.calls.GetPersistentVolumeClaim = append(mock.calls.GetPersistentVolumeClaim, callInfo) + mock.lockGetPersistentVolumeClaim.Unlock() + return mock.GetPersistentVolumeClaimFunc(ctx, sup) +} + +// GetPersistentVolumeClaimCalls gets all the calls that were made to GetPersistentVolumeClaim. +// Check the length with: +// +// len(mockedDiskService.GetPersistentVolumeClaimCalls()) +func (mock *DiskServiceMock) GetPersistentVolumeClaimCalls() []struct { + Ctx context.Context + Sup *supplements.Generator +} { + var calls []struct { + Ctx context.Context + Sup *supplements.Generator + } + mock.lockGetPersistentVolumeClaim.RLock() + calls = mock.calls.GetPersistentVolumeClaim + mock.lockGetPersistentVolumeClaim.RUnlock() + return calls +} + +// Resize calls ResizeFunc. +func (mock *DiskServiceMock) Resize(ctx context.Context, pvc *corev1.PersistentVolumeClaim, newSize resource.Quantity) error { + if mock.ResizeFunc == nil { + panic("DiskServiceMock.ResizeFunc: method is nil but DiskService.Resize was just called") + } + callInfo := struct { + Ctx context.Context + Pvc *corev1.PersistentVolumeClaim + NewSize resource.Quantity + }{ + Ctx: ctx, + Pvc: pvc, + NewSize: newSize, + } + mock.lockResize.Lock() + mock.calls.Resize = append(mock.calls.Resize, callInfo) + mock.lockResize.Unlock() + return mock.ResizeFunc(ctx, pvc, newSize) +} + +// ResizeCalls gets all the calls that were made to Resize. +// Check the length with: +// +// len(mockedDiskService.ResizeCalls()) +func (mock *DiskServiceMock) ResizeCalls() []struct { + Ctx context.Context + Pvc *corev1.PersistentVolumeClaim + NewSize resource.Quantity +} { + var calls []struct { + Ctx context.Context + Pvc *corev1.PersistentVolumeClaim + NewSize resource.Quantity + } + mock.lockResize.RLock() + calls = mock.calls.Resize + mock.lockResize.RUnlock() + return calls +} diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/resizing.go b/images/virtualization-artifact/pkg/controller/vd/internal/resizing.go index 9792881d..6c1ec5dc 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/resizing.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/resizing.go @@ -19,8 +19,10 @@ package internal import ( "context" "errors" + "fmt" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -32,10 +34,10 @@ import ( ) type ResizingHandler struct { - diskService *service.DiskService + diskService DiskService } -func NewResizingHandler(diskService *service.DiskService) *ResizingHandler { +func NewResizingHandler(diskService DiskService) *ResizingHandler { return &ResizingHandler{ diskService: diskService, } @@ -59,8 +61,8 @@ func (h ResizingHandler) Handle(ctx context.Context, vd *virtv2.VirtualDisk) (re return reconcile.Result{}, nil } - newSize := vd.Spec.PersistentVolumeClaim.Size - if newSize == nil { + vdSpecSize := vd.Spec.PersistentVolumeClaim.Size + if vdSpecSize == nil { condition.Status = metav1.ConditionFalse condition.Reason = vdcondition.NotRequested condition.Message = "" @@ -85,33 +87,58 @@ func (h ResizingHandler) Handle(ctx context.Context, vd *virtv2.VirtualDisk) (re return reconcile.Result{}, errors.New("pvc not found for ready virtual disk") } - if newSize.Equal(pvc.Status.Capacity[corev1.ResourceStorage]) { - if condition.Reason == vdcondition.InProgress { - condition.Status = metav1.ConditionTrue - condition.Reason = vdcondition.Resized - condition.Message = "" - return reconcile.Result{}, nil + pvcSpecSize := pvc.Spec.Resources.Requests[corev1.ResourceStorage] + switch vdSpecSize.Cmp(pvcSpecSize) { + // Expected disk size is LESS THAN expected pvc size: no resize needed as resizing to a smaller size is not possible. + case -1: + condition.Status = metav1.ConditionFalse + condition.Reason = vdcondition.NotRequested + condition.Message = fmt.Sprintf("The virtual disk size is too low: should be >= %s.", pvcSpecSize.String()) + return reconcile.Result{}, nil + // Expected disk size is GREATER THAN expected pvc size: resize needed, resizing to a larger size. + case 1: + err = h.diskService.Resize(ctx, pvc, *vdSpecSize) + if err != nil { + return reconcile.Result{}, err } + vd.Status.Phase = virtv2.DiskResizing + condition.Status = metav1.ConditionFalse - condition.Reason = vdcondition.NotRequested - condition.Message = "" + condition.Reason = vdcondition.InProgress + condition.Message = "The virtual disk resizing has started." return reconcile.Result{}, nil + // Expected disk size is EQUAL TO expected pvc size: cannot definitively say whether the resize has already happened or was not needed - perform additional checks. + case 0: + } + + var vdStatusSize resource.Quantity + vdStatusSize, err = resource.ParseQuantity(vd.Status.Capacity) + if err != nil { + return reconcile.Result{}, err } - err = h.diskService.Resize(ctx, pvc, *newSize, supgen) - switch { - case err == nil: + pvcStatusSize := pvc.Status.Capacity[corev1.ResourceStorage] + + // Expected pvc size is GREATER THAN actual pvc size: resize has been requested and is in progress. + if pvcSpecSize.Cmp(pvcStatusSize) == 1 { + vd.Status.Phase = virtv2.DiskResizing + condition.Status = metav1.ConditionFalse condition.Reason = vdcondition.InProgress condition.Message = "The virtual disk is in the process of resizing." return reconcile.Result{}, nil - case errors.Is(err, service.ErrTooSmallDiskSize): - condition.Status = metav1.ConditionFalse - condition.Reason = vdcondition.TooSmallDiskSize - condition.Message = "The new size of the virtual disk must not be smaller than the current size." - return reconcile.Result{}, nil - default: - return reconcile.Result{}, err } + + // Virtual disk size DOES NOT MATCH pvc size: resize has completed, synchronize the virtual disk size. + if !vdStatusSize.Equal(pvcStatusSize) { + vd.Status.Capacity = pvcStatusSize.String() + condition.Status = metav1.ConditionTrue + condition.Reason = vdcondition.Resized + condition.Message = "" + return reconcile.Result{Requeue: true}, nil + } + + // Expected pvc size is NOT GREATER THAN actual PVC size AND virtual disk size MATCHES pvc size: keep previous status. + return reconcile.Result{}, nil } diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/resizing_test.go b/images/virtualization-artifact/pkg/controller/vd/internal/resizing_test.go index 348fa954..665e7844 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/resizing_test.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/resizing_test.go @@ -16,113 +16,150 @@ limitations under the License. package internal -// func TestResizedHandler_Handle(t *testing.T) { -// ctx := context.TODO() -// -// t.Run("VirtualDisk with DeletionTimestamp", func(t *testing.T) { -// vd := virtv2.VirtualDisk{ -// ObjectMeta: metav1.ObjectMeta{ -// DeletionTimestamp: &metav1.Time{Time: metav1.Now().Time}, -// }, -// } -// -// handler := NewResizingHandler(nil) -// _, err := handler.Handle(ctx, &vd) -// require.NoError(t, err) -// -// condition := vd.Status.Conditions[0] -// require.Equal(t, vdcondition.ResizedType, condition.Type) -// require.Equal(t, metav1.ConditionUnknown, condition.Status) -// require.Equal(t, "", condition.Reason) -// }) -// -// t.Run("Resize VirtualDisk", func(t *testing.T) { -// vd := virtv2.VirtualDisk{ -// Spec: virtv2.VirtualDiskSpec{ -// PersistentVolumeClaim: virtv2.VirtualDiskPersistentVolumeClaim{ -// Size: resource.NewQuantity(1111, resource.BinarySI), -// }, -// }, -// Status: virtv2.VirtualDiskStatus{ -// Conditions: []metav1.Condition{ -// { -// Type: vdcondition.ReadyType, -// Status: metav1.ConditionTrue, -// }, -// }, -// }, -// } -// -// resizer := DiskMock{ -// GetPersistentVolumeClaimFunc: func(ctx context.Context, sup *supplements.Generator) (*corev1.PersistentVolumeClaim, error) { -// return &corev1.PersistentVolumeClaim{ -// Status: corev1.PersistentVolumeClaimStatus{ -// Capacity: corev1.ResourceList{ -// corev1.ResourceStorage: *resource.NewQuantity(2222, resource.BinarySI), -// }, -// }, -// }, nil -// }, -// ResizeFunc: func(ctx context.Context, newSize resource.Quantity, sup *supplements.Generator) error { -// return nil -// }, -// } -// -// handler := NewResizedHandler(&resizer) -// err := handler.Handle(ctx, &vd) -// require.NoError(t, err) -// -// condition, ok := getCondition(vdcondition.ResizedType, vd.Status.Conditions) -// require.True(t, ok) -// require.Equal(t, vdcondition.ResizedType, condition.Type) -// require.Equal(t, metav1.ConditionFalse, condition.Status) -// require.Equal(t, vdcondition.ResizedReason_InProgress, condition.Reason) -// }) -// -// t.Run("VirtualDisk resized", func(t *testing.T) { -// size := resource.NewQuantity(1111, resource.BinarySI) -// -// vd := virtv2.VirtualDisk{ -// Spec: virtv2.VirtualDiskSpec{ -// PersistentVolumeClaim: virtv2.VirtualDiskPersistentVolumeClaim{ -// Size: size, -// }, -// }, -// Status: virtv2.VirtualDiskStatus{ -// Conditions: []metav1.Condition{ -// { -// Type: vdcondition.ReadyType, -// Status: metav1.ConditionTrue, -// }, -// { -// Type: vdcondition.ResizedType, -// Reason: vdcondition.ResizedReason_InProgress, -// Status: metav1.ConditionFalse, -// }, -// }, -// }, -// } -// -// resizer := DiskMock{ -// GetPersistentVolumeClaimFunc: func(ctx context.Context, sup *supplements.Generator) (*corev1.PersistentVolumeClaim, error) { -// return &corev1.PersistentVolumeClaim{ -// Status: corev1.PersistentVolumeClaimStatus{ -// Capacity: corev1.ResourceList{ -// corev1.ResourceStorage: *size, -// }, -// }, -// }, nil -// }, -// } -// -// handler := NewResizedHandler(&resizer) -// err := handler.Handle(ctx, &vd) -// require.NoError(t, err) -// -// condition, ok := getCondition(vdcondition.ResizedType, vd.Status.Conditions) -// require.True(t, ok) -// require.Equal(t, vdcondition.ResizedType, condition.Type) -// require.Equal(t, metav1.ConditionTrue, condition.Status) -// require.Equal(t, "", condition.Reason) -// }) -// } +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/deckhouse/virtualization-controller/pkg/controller/service" + "github.com/deckhouse/virtualization-controller/pkg/controller/supplements" + virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2" + "github.com/deckhouse/virtualization/api/core/v1alpha2/vdcondition" +) + +var _ = Describe("Resizing handler Run", func() { + var vd *virtv2.VirtualDisk + var pvc *corev1.PersistentVolumeClaim + var diskService *DiskServiceMock + + BeforeEach(func() { + vd = &virtv2.VirtualDisk{ + Spec: virtv2.VirtualDiskSpec{ + PersistentVolumeClaim: virtv2.VirtualDiskPersistentVolumeClaim{ + Size: new(resource.Quantity), + }, + }, + Status: virtv2.VirtualDiskStatus{ + Conditions: []metav1.Condition{ + { + Type: vdcondition.ReadyType, + Status: metav1.ConditionTrue, + }, + }, + Capacity: "", + }, + } + + pvc = &corev1.PersistentVolumeClaim{ + Spec: corev1.PersistentVolumeClaimSpec{ + Resources: corev1.VolumeResourceRequirements{ + Requests: make(corev1.ResourceList), + }, + }, + Status: corev1.PersistentVolumeClaimStatus{ + Capacity: make(corev1.ResourceList), + }, + } + + diskService = &DiskServiceMock{ + GetPersistentVolumeClaimFunc: func(ctx context.Context, sup *supplements.Generator) (*corev1.PersistentVolumeClaim, error) { + return nil, nil + }, + ResizeFunc: func(ctx context.Context, pvc *corev1.PersistentVolumeClaim, newSize resource.Quantity) error { + return nil + }, + } + }) + + It("Resize is not requested (vd.spec.size == nil)", func() { + vd.Spec.PersistentVolumeClaim.Size = nil + + h := NewResizingHandler(diskService) + + _, err := h.Handle(context.Background(), vd) + Expect(err).To(BeNil()) + Expect(vd.Status.Conditions).To(ContainElement(metav1.Condition{ + Type: vdcondition.ResizedType, + Status: metav1.ConditionFalse, + Reason: vdcondition.NotRequested, + })) + }) + + It("Resize is not requested (vd.spec.size < pvc.spec.size)", func() { + *vd.Spec.PersistentVolumeClaim.Size = resource.MustParse("1G") + diskService.GetPersistentVolumeClaimFunc = func(ctx context.Context, sup *supplements.Generator) (*corev1.PersistentVolumeClaim, error) { + pvc.Spec.Resources.Requests[corev1.ResourceStorage] = resource.MustParse("2G") + return pvc, nil + } + + h := NewResizingHandler(diskService) + + _, err := h.Handle(context.Background(), vd) + Expect(err).To(BeNil()) + resized, _ := service.GetCondition(vdcondition.ResizedType, vd.Status.Conditions) + Expect(resized.Status).To(Equal(metav1.ConditionFalse)) + Expect(resized.Reason).To(Equal(vdcondition.NotRequested)) + }) + + It("Resize has started (vd.spec.size > pvc.spec.size)", func() { + *vd.Spec.PersistentVolumeClaim.Size = resource.MustParse("2G") + diskService.GetPersistentVolumeClaimFunc = func(ctx context.Context, sup *supplements.Generator) (*corev1.PersistentVolumeClaim, error) { + pvc.Spec.Resources.Requests[corev1.ResourceStorage] = resource.MustParse("1G") + return pvc, nil + } + + h := NewResizingHandler(diskService) + + _, err := h.Handle(context.Background(), vd) + Expect(err).To(BeNil()) + + resized, _ := service.GetCondition(vdcondition.ResizedType, vd.Status.Conditions) + Expect(resized.Status).To(Equal(metav1.ConditionFalse)) + Expect(resized.Reason).To(Equal(vdcondition.InProgress)) + }) + + It("Resize is in progress (vd.spec.size == pvc.spec.size, pvc.spec.size > pvc.status.size)", func() { + *vd.Spec.PersistentVolumeClaim.Size = resource.MustParse("2G") + q := resource.MustParse("1G") + vd.Status.Capacity = q.String() + diskService.GetPersistentVolumeClaimFunc = func(ctx context.Context, sup *supplements.Generator) (*corev1.PersistentVolumeClaim, error) { + pvc.Spec.Resources.Requests[corev1.ResourceStorage] = resource.MustParse("2G") + pvc.Status.Capacity[corev1.ResourceStorage] = resource.MustParse("1G") + return pvc, nil + } + + h := NewResizingHandler(diskService) + + _, err := h.Handle(context.Background(), vd) + Expect(err).To(BeNil()) + + resized, _ := service.GetCondition(vdcondition.ResizedType, vd.Status.Conditions) + Expect(resized.Status).To(Equal(metav1.ConditionFalse)) + Expect(resized.Reason).To(Equal(vdcondition.InProgress)) + }) + + It("Resized (vd.spec.size == pvc.spec.size, pvc.spec.size == pvc.status.size)", func() { + *vd.Spec.PersistentVolumeClaim.Size = resource.MustParse("2G") + q := resource.MustParse("1G") + vd.Status.Capacity = q.String() + diskService.GetPersistentVolumeClaimFunc = func(ctx context.Context, sup *supplements.Generator) (*corev1.PersistentVolumeClaim, error) { + pvc.Spec.Resources.Requests[corev1.ResourceStorage] = resource.MustParse("2G") + pvc.Status.Capacity[corev1.ResourceStorage] = resource.MustParse("2G") + return pvc, nil + } + + h := NewResizingHandler(diskService) + + _, err := h.Handle(context.Background(), vd) + Expect(err).To(BeNil()) + + resized, _ := service.GetCondition(vdcondition.ResizedType, vd.Status.Conditions) + Expect(resized.Status).To(Equal(metav1.ConditionTrue)) + Expect(resized.Reason).To(Equal(vdcondition.Resized)) + Expect(resource.MustParse(vd.Status.Capacity)).To(Equal(pvc.Status.Capacity[corev1.ResourceStorage])) + }) +}) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/errors.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/errors.go index 5ac9b585..6d5c53f0 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/errors.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/errors.go @@ -31,7 +31,7 @@ type ImageNotReadyError struct { } func (e ImageNotReadyError) Error() string { - return fmt.Sprintf("ClusterImage %s not ready", e.name) + return fmt.Sprintf("VirtualImage %s not ready", e.name) } func NewImageNotReadyError(name string) error { @@ -45,7 +45,7 @@ type ClusterImageNotReadyError struct { } func (e ClusterImageNotReadyError) Error() string { - return fmt.Sprintf("ClusterImage %s not ready", e.name) + return fmt.Sprintf("ClusterVirtualImage %s not ready", e.name) } func NewClusterImageNotReadyError(name string) error { diff --git a/images/virtualization-artifact/pkg/controller/vd/vd_reconciler.go b/images/virtualization-artifact/pkg/controller/vd/vd_reconciler.go index 6497e5b8..82d728e7 100644 --- a/images/virtualization-artifact/pkg/controller/vd/vd_reconciler.go +++ b/images/virtualization-artifact/pkg/controller/vd/vd_reconciler.go @@ -168,7 +168,6 @@ func (r *Reconciler) SetupController(_ context.Context, mgr manager.Manager, ctr mgr.GetScheme(), mgr.GetRESTMapper(), &virtv2.VirtualDisk{}, - handler.OnlyControllerOwner(), ), predicate.Funcs{ CreateFunc: func(e event.CreateEvent) bool { return false }, DeleteFunc: func(e event.DeleteEvent) bool { return true },