From 3c859b5180f6e7592b75757f1814cec7982cfc4d Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Thu, 19 Feb 2026 09:11:47 +0300 Subject: [PATCH 1/3] fix Signed-off-by: Valeriy Khorunzhin --- .../vmbda/internal/block_device_ready.go | 179 +++++++------- .../vmbda/internal/block_device_ready_test.go | 198 ++++++++++++++++ .../controller/vmbda/internal/interfaces.go | 6 + .../pkg/controller/vmbda/internal/mock.go | 220 +++++++++++++++++- 4 files changed, 513 insertions(+), 90 deletions(-) create mode 100644 images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready_test.go diff --git a/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready.go b/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready.go index 5ddb39a426..b93b5e9afe 100644 --- a/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready.go +++ b/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready.go @@ -33,10 +33,10 @@ import ( ) type BlockDeviceReadyHandler struct { - attachment *service.AttachmentService + attachment AttachmentService } -func NewBlockDeviceReadyHandler(attachment *service.AttachmentService) *BlockDeviceReadyHandler { +func NewBlockDeviceReadyHandler(attachment AttachmentService) *BlockDeviceReadyHandler { return &BlockDeviceReadyHandler{ attachment: attachment, } @@ -57,91 +57,7 @@ func (h BlockDeviceReadyHandler) Handle(ctx context.Context, vmbda *v1alpha2.Vir switch vmbda.Spec.BlockDeviceRef.Kind { case v1alpha2.VMBDAObjectRefKindVirtualDisk: - vdKey := types.NamespacedName{ - Name: vmbda.Spec.BlockDeviceRef.Name, - Namespace: vmbda.Namespace, - } - - vd, err := h.attachment.GetVirtualDisk(ctx, vdKey.Name, vdKey.Namespace) - if err != nil { - return reconcile.Result{}, err - } - - if vd == nil { - cb. - Status(metav1.ConditionFalse). - Reason(vmbdacondition.BlockDeviceNotReady). - Message(fmt.Sprintf("VirtualDisk %q not found.", vdKey.String())) - return reconcile.Result{}, nil - } - - if vd.GetDeletionTimestamp() != nil { - cb. - Status(metav1.ConditionFalse). - Reason(vmbdacondition.BlockDeviceNotReady). - Message(fmt.Sprintf("VirtualDisk %q is being deleted. Delete VirtualMachineBlockDeviceAttachment to detach disk from the VirtualMachine.", vdKey.String())) - return reconcile.Result{}, nil - } - - if vd.Generation != vd.Status.ObservedGeneration { - cb. - Status(metav1.ConditionFalse). - Reason(vmbdacondition.BlockDeviceNotReady). - Message(fmt.Sprintf("Waiting for the VirtualDisk %q to be observed in its latest state generation.", vdKey.String())) - return reconcile.Result{}, nil - } - - if vd.Status.Phase != v1alpha2.DiskReady && vd.Status.Phase != v1alpha2.DiskWaitForFirstConsumer { - cb. - Status(metav1.ConditionFalse). - Reason(vmbdacondition.BlockDeviceNotReady). - Message(fmt.Sprintf("VirtualDisk %q is not ready to be attached to the virtual machine: waiting for the VirtualDisk to be ready for attachment.", vdKey.String())) - return reconcile.Result{}, nil - } - - if vd.Status.Phase == v1alpha2.DiskReady { - diskReadyCondition, _ := conditions.GetCondition(vdcondition.ReadyType, vd.Status.Conditions) - if diskReadyCondition.Status != metav1.ConditionTrue { - cb. - Status(metav1.ConditionFalse). - Reason(vmbdacondition.BlockDeviceNotReady). - Message(fmt.Sprintf("VirtualDisk %q is not Ready: waiting for the VirtualDisk to be Ready.", vdKey.String())) - return reconcile.Result{}, nil - } - } - - if vd.Status.Target.PersistentVolumeClaim == "" { - cb. - Status(metav1.ConditionFalse). - Reason(vmbdacondition.BlockDeviceNotReady). - Message("Waiting until VirtualDisk has associated PersistentVolumeClaim name.") - return reconcile.Result{}, nil - } - - ad := service.NewAttachmentDiskFromVirtualDisk(vd) - pvc, err := h.attachment.GetPersistentVolumeClaim(ctx, ad) - if err != nil { - return reconcile.Result{}, err - } - - if pvc == nil { - cb. - Status(metav1.ConditionFalse). - Reason(vmbdacondition.BlockDeviceNotReady). - Message(fmt.Sprintf("Underlying PersistentVolumeClaim %q not found.", vd.Status.Target)) - return reconcile.Result{}, nil - } - - if vd.Status.Phase == v1alpha2.DiskReady && pvc.Status.Phase != corev1.ClaimBound { - cb. - Status(metav1.ConditionFalse). - Reason(vmbdacondition.BlockDeviceNotReady). - Message(fmt.Sprintf("Underlying PersistentVolumeClaim %q not bound.", vd.Status.Target)) - return reconcile.Result{}, nil - } - - cb.Status(metav1.ConditionTrue).Reason(vmbdacondition.BlockDeviceReady) - return reconcile.Result{}, nil + return reconcile.Result{}, h.ValidateVirtualDiskReady(ctx, vmbda, cb) case v1alpha2.VMBDAObjectRefKindVirtualImage: viKey := types.NamespacedName{ Name: vmbda.Spec.BlockDeviceRef.Name, @@ -285,3 +201,92 @@ func (h BlockDeviceReadyHandler) Handle(ctx context.Context, vmbda *v1alpha2.Vir return reconcile.Result{}, fmt.Errorf("unknown block device kind %s", vmbda.Spec.BlockDeviceRef.Kind) } } + +func (h BlockDeviceReadyHandler) ValidateVirtualDiskReady(ctx context.Context, vmbda *v1alpha2.VirtualMachineBlockDeviceAttachment, cb *conditions.ConditionBuilder) error { + vdKey := types.NamespacedName{ + Name: vmbda.Spec.BlockDeviceRef.Name, + Namespace: vmbda.Namespace, + } + + vd, err := h.attachment.GetVirtualDisk(ctx, vdKey.Name, vdKey.Namespace) + if err != nil { + return err + } + + if vd == nil { + cb. + Status(metav1.ConditionFalse). + Reason(vmbdacondition.BlockDeviceNotReady). + Message(fmt.Sprintf("VirtualDisk %q not found.", vdKey.String())) + return nil + } + + if vd.GetDeletionTimestamp() != nil { + cb. + Status(metav1.ConditionFalse). + Reason(vmbdacondition.BlockDeviceNotReady). + Message(fmt.Sprintf("VirtualDisk %q is being deleted. Delete VirtualMachineBlockDeviceAttachment to detach disk from the VirtualMachine.", vdKey.String())) + return nil + } + + if vd.Generation != vd.Status.ObservedGeneration { + cb. + Status(metav1.ConditionFalse). + Reason(vmbdacondition.BlockDeviceNotReady). + Message(fmt.Sprintf("Waiting for the VirtualDisk %q to be observed in its latest state generation.", vdKey.String())) + return nil + } + + diskPhaseReadyOrMigrating := vd.Status.Phase == v1alpha2.DiskReady || vd.Status.Phase == v1alpha2.DiskMigrating + if !diskPhaseReadyOrMigrating && vd.Status.Phase != v1alpha2.DiskWaitForFirstConsumer { + cb. + Status(metav1.ConditionFalse). + Reason(vmbdacondition.BlockDeviceNotReady). + Message(fmt.Sprintf("VirtualDisk %q is not ready to be attached to the virtual machine: waiting for the VirtualDisk to be ready for attachment.", vdKey.String())) + return nil + } + + if diskPhaseReadyOrMigrating { + diskReadyCondition, _ := conditions.GetCondition(vdcondition.ReadyType, vd.Status.Conditions) + if diskReadyCondition.Status != metav1.ConditionTrue { + cb. + Status(metav1.ConditionFalse). + Reason(vmbdacondition.BlockDeviceNotReady). + Message(fmt.Sprintf("VirtualDisk %q is not Ready: waiting for the VirtualDisk to be Ready.", vdKey.String())) + return nil + } + } + + if vd.Status.Target.PersistentVolumeClaim == "" { + cb. + Status(metav1.ConditionFalse). + Reason(vmbdacondition.BlockDeviceNotReady). + Message("Waiting until VirtualDisk has associated PersistentVolumeClaim name.") + return nil + } + + ad := service.NewAttachmentDiskFromVirtualDisk(vd) + pvc, err := h.attachment.GetPersistentVolumeClaim(ctx, ad) + if err != nil { + return err + } + + if pvc == nil { + cb. + Status(metav1.ConditionFalse). + Reason(vmbdacondition.BlockDeviceNotReady). + Message(fmt.Sprintf("Underlying PersistentVolumeClaim %q not found.", vd.Status.Target)) + return nil + } + + if pvc.Status.Phase != corev1.ClaimBound { + cb. + Status(metav1.ConditionFalse). + Reason(vmbdacondition.BlockDeviceNotReady). + Message(fmt.Sprintf("Underlying PersistentVolumeClaim %q not bound.", vd.Status.Target)) + return nil + } + + cb.Status(metav1.ConditionTrue).Reason(vmbdacondition.BlockDeviceReady) + return nil +} diff --git a/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready_test.go b/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready_test.go new file mode 100644 index 0000000000..bdb8317881 --- /dev/null +++ b/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready_test.go @@ -0,0 +1,198 @@ +/* +Copyright 2026 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 ( + "context" + "errors" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + vmbdaBuilder "github.com/deckhouse/virtualization-controller/pkg/builder/vmbda" + "github.com/deckhouse/virtualization-controller/pkg/controller/conditions" + "github.com/deckhouse/virtualization-controller/pkg/controller/service" + "github.com/deckhouse/virtualization/api/core/v1alpha2" + "github.com/deckhouse/virtualization/api/core/v1alpha2/vdcondition" + "github.com/deckhouse/virtualization/api/core/v1alpha2/vmbdacondition" +) + +var _ = Describe("BlockDeviceReadyHandler ValidateVirtualDiskReady", func() { + var ( + vmbda *v1alpha2.VirtualMachineBlockDeviceAttachment + cb *conditions.ConditionBuilder + attachmentServiceMock AttachmentServiceMock + ctx context.Context + ) + + BeforeEach(func() { + vmbda = vmbdaBuilder.NewEmpty("vmbda", "default") + cb = conditions.NewConditionBuilder(vmbdacondition.BlockDeviceReadyType) + attachmentServiceMock = AttachmentServiceMock{ + GetVirtualDiskFunc: func(_ context.Context, _, _ string) (*v1alpha2.VirtualDisk, error) { + return nil, nil + }, + GetPersistentVolumeClaimFunc: func(_ context.Context, _ *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { + return nil, nil + }, + } + ctx = context.Background() + }) + + It("returns error when getting VirtualDisk fails", func() { + attachmentServiceMock.GetVirtualDiskFunc = func(_ context.Context, _, _ string) (*v1alpha2.VirtualDisk, error) { + return nil, errors.New("error") + } + err := NewBlockDeviceReadyHandler(&attachmentServiceMock).ValidateVirtualDiskReady(ctx, vmbda, cb) + Expect(err).To(HaveOccurred()) + }) + + It("sets condition to False when VirtualDisk is nil", func() { + err := NewBlockDeviceReadyHandler(&attachmentServiceMock).ValidateVirtualDiskReady(ctx, vmbda, cb) + Expect(err).NotTo(HaveOccurred()) + Expect(cb.Condition().Status).To(Equal(metav1.ConditionFalse)) + Expect(cb.Condition().Reason).To(Equal(string(vmbdacondition.BlockDeviceNotReady))) + }) + + It("sets condition to False when VirtualDisk has DeletionTimestamp", func() { + attachmentServiceMock.GetVirtualDiskFunc = func(_ context.Context, _, _ string) (*v1alpha2.VirtualDisk, error) { + return &v1alpha2.VirtualDisk{ + ObjectMeta: metav1.ObjectMeta{ + DeletionTimestamp: &metav1.Time{}, + }, + }, nil + } + err := NewBlockDeviceReadyHandler(&attachmentServiceMock).ValidateVirtualDiskReady(ctx, vmbda, cb) + Expect(err).NotTo(HaveOccurred()) + Expect(cb.Condition().Status).To(Equal(metav1.ConditionFalse)) + Expect(cb.Condition().Reason).To(Equal(string(vmbdacondition.BlockDeviceNotReady))) + }) + + It("returns error when getting PVC fails", func() { + attachmentServiceMock.GetVirtualDiskFunc = func(_ context.Context, _, _ string) (*v1alpha2.VirtualDisk, error) { + return generateVD(v1alpha2.DiskReady, metav1.ConditionTrue), nil + } + attachmentServiceMock.GetPersistentVolumeClaimFunc = func(_ context.Context, _ *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { + return nil, errors.New("error") + } + err := NewBlockDeviceReadyHandler(&attachmentServiceMock).ValidateVirtualDiskReady(ctx, vmbda, cb) + Expect(err).To(HaveOccurred()) + }) + + It("sets condition to False when PVC is nil", func() { + attachmentServiceMock.GetVirtualDiskFunc = func(_ context.Context, _, _ string) (*v1alpha2.VirtualDisk, error) { + return generateVD(v1alpha2.DiskReady, metav1.ConditionTrue), nil + } + attachmentServiceMock.GetPersistentVolumeClaimFunc = func(_ context.Context, _ *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { + return nil, nil + } + err := NewBlockDeviceReadyHandler(&attachmentServiceMock).ValidateVirtualDiskReady(ctx, vmbda, cb) + Expect(err).NotTo(HaveOccurred()) + Expect(cb.Condition().Status).To(Equal(metav1.ConditionFalse)) + Expect(cb.Condition().Reason).To(Equal(string(vmbdacondition.BlockDeviceNotReady))) + }) + + It("sets condition to False when VirtualDisk DiskReady condition is False", func() { + attachmentServiceMock.GetVirtualDiskFunc = func(_ context.Context, _, _ string) (*v1alpha2.VirtualDisk, error) { + return generateVD(v1alpha2.DiskReady, metav1.ConditionFalse), nil + } + attachmentServiceMock.GetPersistentVolumeClaimFunc = func(_ context.Context, _ *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { + return nil, nil + } + err := NewBlockDeviceReadyHandler(&attachmentServiceMock).ValidateVirtualDiskReady(ctx, vmbda, cb) + Expect(err).NotTo(HaveOccurred()) + Expect(cb.Condition().Status).To(Equal(metav1.ConditionFalse)) + Expect(cb.Condition().Reason).To(Equal(string(vmbdacondition.BlockDeviceNotReady))) + }) + + DescribeTable("sets condition status based on VirtualDisk phase", func(phase v1alpha2.DiskPhase, expectedStatus metav1.ConditionStatus) { + attachmentServiceMock.GetVirtualDiskFunc = func(_ context.Context, _, _ string) (*v1alpha2.VirtualDisk, error) { + return generateVD(phase, metav1.ConditionTrue), nil + } + attachmentServiceMock.GetPersistentVolumeClaimFunc = func(_ context.Context, _ *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { + return &corev1.PersistentVolumeClaim{ + Status: corev1.PersistentVolumeClaimStatus{ + Phase: corev1.ClaimBound, + }, + }, nil + } + err := NewBlockDeviceReadyHandler(&attachmentServiceMock).ValidateVirtualDiskReady(ctx, vmbda, cb) + Expect(err).NotTo(HaveOccurred()) + Expect(cb.Condition().Status).To(Equal(expectedStatus)) + if expectedStatus == metav1.ConditionTrue { + Expect(cb.Condition().Reason).To(Equal(vmbdacondition.BlockDeviceReady.String())) + } + }, + Entry("DiskReady", v1alpha2.DiskReady, metav1.ConditionTrue), + Entry("DiskMigrating", v1alpha2.DiskMigrating, metav1.ConditionTrue), + Entry("DiskWaitForFirstConsumer", v1alpha2.DiskWaitForFirstConsumer, metav1.ConditionTrue), + Entry("DiskPending", v1alpha2.DiskPending, metav1.ConditionFalse), + Entry("DiskProvisioning", v1alpha2.DiskProvisioning, metav1.ConditionFalse), + Entry("DiskWaitForUserUpload", v1alpha2.DiskWaitForUserUpload, metav1.ConditionFalse), + Entry("DiskResizing", v1alpha2.DiskResizing, metav1.ConditionFalse), + Entry("DiskFailed", v1alpha2.DiskFailed, metav1.ConditionFalse), + Entry("DiskLost", v1alpha2.DiskLost, metav1.ConditionFalse), + Entry("DiskExporting", v1alpha2.DiskExporting, metav1.ConditionFalse), + Entry("DiskTerminating", v1alpha2.DiskTerminating, metav1.ConditionFalse), + ) + + DescribeTable("sets condition status based on PVC phase", func(phase corev1.PersistentVolumeClaimPhase, expectedStatus metav1.ConditionStatus) { + attachmentServiceMock.GetVirtualDiskFunc = func(_ context.Context, _, _ string) (*v1alpha2.VirtualDisk, error) { + return generateVD(v1alpha2.DiskReady, metav1.ConditionTrue), nil + } + attachmentServiceMock.GetPersistentVolumeClaimFunc = func(_ context.Context, _ *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { + return &corev1.PersistentVolumeClaim{ + Status: corev1.PersistentVolumeClaimStatus{ + Phase: phase, + }, + }, nil + } + err := NewBlockDeviceReadyHandler(&attachmentServiceMock).ValidateVirtualDiskReady(ctx, vmbda, cb) + Expect(err).NotTo(HaveOccurred()) + Expect(cb.Condition().Status).To(Equal(expectedStatus)) + if expectedStatus == metav1.ConditionTrue { + Expect(cb.Condition().Reason).To(Equal(vmbdacondition.BlockDeviceReady.String())) + } + }, + Entry("ClaimBound", corev1.ClaimBound, metav1.ConditionTrue), + Entry("ClaimPending", corev1.ClaimPending, metav1.ConditionFalse), + Entry("ClaimLost", corev1.ClaimLost, metav1.ConditionFalse), + ) +}) + +func generateVD(phase v1alpha2.DiskPhase, readyConditionStatus metav1.ConditionStatus) *v1alpha2.VirtualDisk { + return &v1alpha2.VirtualDisk{ + ObjectMeta: metav1.ObjectMeta{ + Name: "vd", + Namespace: "namespace", + }, + Status: v1alpha2.VirtualDiskStatus{ + Phase: phase, + Conditions: []metav1.Condition{ + { + Type: string(vdcondition.ReadyType), + Status: readyConditionStatus, + }, + }, + Target: v1alpha2.DiskTarget{ + PersistentVolumeClaim: "pvc", + }, + }, + } +} diff --git a/images/virtualization-artifact/pkg/controller/vmbda/internal/interfaces.go b/images/virtualization-artifact/pkg/controller/vmbda/internal/interfaces.go index dc7b5adb3e..5fcbf16099 100644 --- a/images/virtualization-artifact/pkg/controller/vmbda/internal/interfaces.go +++ b/images/virtualization-artifact/pkg/controller/vmbda/internal/interfaces.go @@ -19,8 +19,10 @@ package internal import ( "context" + corev1 "k8s.io/api/core/v1" virtv1 "kubevirt.io/api/core/v1" + "github.com/deckhouse/virtualization-controller/pkg/controller/service" "github.com/deckhouse/virtualization/api/core/v1alpha2" ) @@ -30,4 +32,8 @@ type AttachmentService interface { GetVirtualMachine(ctx context.Context, name, namespace string) (*v1alpha2.VirtualMachine, error) GetKVVMI(ctx context.Context, vm *v1alpha2.VirtualMachine) (*virtv1.VirtualMachineInstance, error) GetKVVM(ctx context.Context, vm *v1alpha2.VirtualMachine) (*virtv1.VirtualMachine, error) + GetVirtualDisk(ctx context.Context, name, namespace string) (*v1alpha2.VirtualDisk, error) + GetVirtualImage(ctx context.Context, name, namespace string) (*v1alpha2.VirtualImage, error) + GetClusterVirtualImage(ctx context.Context, name string) (*v1alpha2.ClusterVirtualImage, error) + GetPersistentVolumeClaim(ctx context.Context, ad *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) } diff --git a/images/virtualization-artifact/pkg/controller/vmbda/internal/mock.go b/images/virtualization-artifact/pkg/controller/vmbda/internal/mock.go index 8f0e6440c4..34b4f669ef 100644 --- a/images/virtualization-artifact/pkg/controller/vmbda/internal/mock.go +++ b/images/virtualization-artifact/pkg/controller/vmbda/internal/mock.go @@ -5,7 +5,9 @@ package internal import ( "context" + "github.com/deckhouse/virtualization-controller/pkg/controller/service" "github.com/deckhouse/virtualization/api/core/v1alpha2" + corev1 "k8s.io/api/core/v1" virtv1 "kubevirt.io/api/core/v1" "sync" ) @@ -20,12 +22,24 @@ var _ AttachmentService = &AttachmentServiceMock{} // // // make and configure a mocked AttachmentService // mockedAttachmentService := &AttachmentServiceMock{ +// GetClusterVirtualImageFunc: func(ctx context.Context, name string) (*v1alpha2.ClusterVirtualImage, error) { +// panic("mock out the GetClusterVirtualImage method") +// }, // GetKVVMFunc: func(ctx context.Context, vm *v1alpha2.VirtualMachine) (*virtv1.VirtualMachine, error) { // panic("mock out the GetKVVM method") // }, // GetKVVMIFunc: func(ctx context.Context, vm *v1alpha2.VirtualMachine) (*virtv1.VirtualMachineInstance, error) { // panic("mock out the GetKVVMI method") // }, +// GetPersistentVolumeClaimFunc: func(ctx context.Context, ad *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { +// panic("mock out the GetPersistentVolumeClaim method") +// }, +// GetVirtualDiskFunc: func(ctx context.Context, name string, namespace string) (*v1alpha2.VirtualDisk, error) { +// panic("mock out the GetVirtualDisk method") +// }, +// GetVirtualImageFunc: func(ctx context.Context, name string, namespace string) (*v1alpha2.VirtualImage, error) { +// panic("mock out the GetVirtualImage method") +// }, // GetVirtualMachineFunc: func(ctx context.Context, name string, namespace string) (*v1alpha2.VirtualMachine, error) { // panic("mock out the GetVirtualMachine method") // }, @@ -36,17 +50,36 @@ var _ AttachmentService = &AttachmentServiceMock{} // // } type AttachmentServiceMock struct { + // GetClusterVirtualImageFunc mocks the GetClusterVirtualImage method. + GetClusterVirtualImageFunc func(ctx context.Context, name string) (*v1alpha2.ClusterVirtualImage, error) + // GetKVVMFunc mocks the GetKVVM method. GetKVVMFunc func(ctx context.Context, vm *v1alpha2.VirtualMachine) (*virtv1.VirtualMachine, error) // GetKVVMIFunc mocks the GetKVVMI method. GetKVVMIFunc func(ctx context.Context, vm *v1alpha2.VirtualMachine) (*virtv1.VirtualMachineInstance, error) + // GetPersistentVolumeClaimFunc mocks the GetPersistentVolumeClaim method. + GetPersistentVolumeClaimFunc func(ctx context.Context, ad *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) + + // GetVirtualDiskFunc mocks the GetVirtualDisk method. + GetVirtualDiskFunc func(ctx context.Context, name string, namespace string) (*v1alpha2.VirtualDisk, error) + + // GetVirtualImageFunc mocks the GetVirtualImage method. + GetVirtualImageFunc func(ctx context.Context, name string, namespace string) (*v1alpha2.VirtualImage, error) + // GetVirtualMachineFunc mocks the GetVirtualMachine method. GetVirtualMachineFunc func(ctx context.Context, name string, namespace string) (*v1alpha2.VirtualMachine, error) // calls tracks calls to the methods. calls struct { + // GetClusterVirtualImage holds details about calls to the GetClusterVirtualImage method. + GetClusterVirtualImage []struct { + // Ctx is the ctx argument value. + Ctx context.Context + // Name is the name argument value. + Name string + } // GetKVVM holds details about calls to the GetKVVM method. GetKVVM []struct { // Ctx is the ctx argument value. @@ -61,6 +94,31 @@ type AttachmentServiceMock struct { // VM is the vm argument value. VM *v1alpha2.VirtualMachine } + // GetPersistentVolumeClaim holds details about calls to the GetPersistentVolumeClaim method. + GetPersistentVolumeClaim []struct { + // Ctx is the ctx argument value. + Ctx context.Context + // Ad is the ad argument value. + Ad *service.AttachmentDisk + } + // GetVirtualDisk holds details about calls to the GetVirtualDisk method. + GetVirtualDisk []struct { + // Ctx is the ctx argument value. + Ctx context.Context + // Name is the name argument value. + Name string + // Namespace is the namespace argument value. + Namespace string + } + // GetVirtualImage holds details about calls to the GetVirtualImage method. + GetVirtualImage []struct { + // Ctx is the ctx argument value. + Ctx context.Context + // Name is the name argument value. + Name string + // Namespace is the namespace argument value. + Namespace string + } // GetVirtualMachine holds details about calls to the GetVirtualMachine method. GetVirtualMachine []struct { // Ctx is the ctx argument value. @@ -71,9 +129,49 @@ type AttachmentServiceMock struct { Namespace string } } - lockGetKVVM sync.RWMutex - lockGetKVVMI sync.RWMutex - lockGetVirtualMachine sync.RWMutex + lockGetClusterVirtualImage sync.RWMutex + lockGetKVVM sync.RWMutex + lockGetKVVMI sync.RWMutex + lockGetPersistentVolumeClaim sync.RWMutex + lockGetVirtualDisk sync.RWMutex + lockGetVirtualImage sync.RWMutex + lockGetVirtualMachine sync.RWMutex +} + +// GetClusterVirtualImage calls GetClusterVirtualImageFunc. +func (mock *AttachmentServiceMock) GetClusterVirtualImage(ctx context.Context, name string) (*v1alpha2.ClusterVirtualImage, error) { + if mock.GetClusterVirtualImageFunc == nil { + panic("AttachmentServiceMock.GetClusterVirtualImageFunc: method is nil but AttachmentService.GetClusterVirtualImage was just called") + } + callInfo := struct { + Ctx context.Context + Name string + }{ + Ctx: ctx, + Name: name, + } + mock.lockGetClusterVirtualImage.Lock() + mock.calls.GetClusterVirtualImage = append(mock.calls.GetClusterVirtualImage, callInfo) + mock.lockGetClusterVirtualImage.Unlock() + return mock.GetClusterVirtualImageFunc(ctx, name) +} + +// GetClusterVirtualImageCalls gets all the calls that were made to GetClusterVirtualImage. +// Check the length with: +// +// len(mockedAttachmentService.GetClusterVirtualImageCalls()) +func (mock *AttachmentServiceMock) GetClusterVirtualImageCalls() []struct { + Ctx context.Context + Name string +} { + var calls []struct { + Ctx context.Context + Name string + } + mock.lockGetClusterVirtualImage.RLock() + calls = mock.calls.GetClusterVirtualImage + mock.lockGetClusterVirtualImage.RUnlock() + return calls } // GetKVVM calls GetKVVMFunc. @@ -148,6 +246,122 @@ func (mock *AttachmentServiceMock) GetKVVMICalls() []struct { return calls } +// GetPersistentVolumeClaim calls GetPersistentVolumeClaimFunc. +func (mock *AttachmentServiceMock) GetPersistentVolumeClaim(ctx context.Context, ad *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { + if mock.GetPersistentVolumeClaimFunc == nil { + panic("AttachmentServiceMock.GetPersistentVolumeClaimFunc: method is nil but AttachmentService.GetPersistentVolumeClaim was just called") + } + callInfo := struct { + Ctx context.Context + Ad *service.AttachmentDisk + }{ + Ctx: ctx, + Ad: ad, + } + mock.lockGetPersistentVolumeClaim.Lock() + mock.calls.GetPersistentVolumeClaim = append(mock.calls.GetPersistentVolumeClaim, callInfo) + mock.lockGetPersistentVolumeClaim.Unlock() + return mock.GetPersistentVolumeClaimFunc(ctx, ad) +} + +// GetPersistentVolumeClaimCalls gets all the calls that were made to GetPersistentVolumeClaim. +// Check the length with: +// +// len(mockedAttachmentService.GetPersistentVolumeClaimCalls()) +func (mock *AttachmentServiceMock) GetPersistentVolumeClaimCalls() []struct { + Ctx context.Context + Ad *service.AttachmentDisk +} { + var calls []struct { + Ctx context.Context + Ad *service.AttachmentDisk + } + mock.lockGetPersistentVolumeClaim.RLock() + calls = mock.calls.GetPersistentVolumeClaim + mock.lockGetPersistentVolumeClaim.RUnlock() + return calls +} + +// GetVirtualDisk calls GetVirtualDiskFunc. +func (mock *AttachmentServiceMock) GetVirtualDisk(ctx context.Context, name string, namespace string) (*v1alpha2.VirtualDisk, error) { + if mock.GetVirtualDiskFunc == nil { + panic("AttachmentServiceMock.GetVirtualDiskFunc: method is nil but AttachmentService.GetVirtualDisk was just called") + } + callInfo := struct { + Ctx context.Context + Name string + Namespace string + }{ + Ctx: ctx, + Name: name, + Namespace: namespace, + } + mock.lockGetVirtualDisk.Lock() + mock.calls.GetVirtualDisk = append(mock.calls.GetVirtualDisk, callInfo) + mock.lockGetVirtualDisk.Unlock() + return mock.GetVirtualDiskFunc(ctx, name, namespace) +} + +// GetVirtualDiskCalls gets all the calls that were made to GetVirtualDisk. +// Check the length with: +// +// len(mockedAttachmentService.GetVirtualDiskCalls()) +func (mock *AttachmentServiceMock) GetVirtualDiskCalls() []struct { + Ctx context.Context + Name string + Namespace string +} { + var calls []struct { + Ctx context.Context + Name string + Namespace string + } + mock.lockGetVirtualDisk.RLock() + calls = mock.calls.GetVirtualDisk + mock.lockGetVirtualDisk.RUnlock() + return calls +} + +// GetVirtualImage calls GetVirtualImageFunc. +func (mock *AttachmentServiceMock) GetVirtualImage(ctx context.Context, name string, namespace string) (*v1alpha2.VirtualImage, error) { + if mock.GetVirtualImageFunc == nil { + panic("AttachmentServiceMock.GetVirtualImageFunc: method is nil but AttachmentService.GetVirtualImage was just called") + } + callInfo := struct { + Ctx context.Context + Name string + Namespace string + }{ + Ctx: ctx, + Name: name, + Namespace: namespace, + } + mock.lockGetVirtualImage.Lock() + mock.calls.GetVirtualImage = append(mock.calls.GetVirtualImage, callInfo) + mock.lockGetVirtualImage.Unlock() + return mock.GetVirtualImageFunc(ctx, name, namespace) +} + +// GetVirtualImageCalls gets all the calls that were made to GetVirtualImage. +// Check the length with: +// +// len(mockedAttachmentService.GetVirtualImageCalls()) +func (mock *AttachmentServiceMock) GetVirtualImageCalls() []struct { + Ctx context.Context + Name string + Namespace string +} { + var calls []struct { + Ctx context.Context + Name string + Namespace string + } + mock.lockGetVirtualImage.RLock() + calls = mock.calls.GetVirtualImage + mock.lockGetVirtualImage.RUnlock() + return calls +} + // GetVirtualMachine calls GetVirtualMachineFunc. func (mock *AttachmentServiceMock) GetVirtualMachine(ctx context.Context, name string, namespace string) (*v1alpha2.VirtualMachine, error) { if mock.GetVirtualMachineFunc == nil { From 1042ed134d697eae014053a2ed3162f2596dc436 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Thu, 19 Feb 2026 23:41:02 +0300 Subject: [PATCH 2/3] fix Signed-off-by: Valeriy Khorunzhin --- .../vmbda/internal/block_device_ready.go | 2 +- .../vmbda/internal/block_device_ready_test.go | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready.go b/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready.go index b93b5e9afe..97e4c247f4 100644 --- a/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready.go +++ b/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready.go @@ -279,7 +279,7 @@ func (h BlockDeviceReadyHandler) ValidateVirtualDiskReady(ctx context.Context, v return nil } - if pvc.Status.Phase != corev1.ClaimBound { + if diskPhaseReadyOrMigrating && pvc.Status.Phase != corev1.ClaimBound { cb. Status(metav1.ConditionFalse). Reason(vmbdacondition.BlockDeviceNotReady). diff --git a/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready_test.go b/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready_test.go index bdb8317881..79d34f6ede 100644 --- a/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready_test.go +++ b/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready_test.go @@ -152,14 +152,14 @@ var _ = Describe("BlockDeviceReadyHandler ValidateVirtualDiskReady", func() { Entry("DiskTerminating", v1alpha2.DiskTerminating, metav1.ConditionFalse), ) - DescribeTable("sets condition status based on PVC phase", func(phase corev1.PersistentVolumeClaimPhase, expectedStatus metav1.ConditionStatus) { + DescribeTable("sets condition status based on VD and PVC phase", func(vdPhase v1alpha2.DiskPhase, pvcPhase corev1.PersistentVolumeClaimPhase, expectedStatus metav1.ConditionStatus) { attachmentServiceMock.GetVirtualDiskFunc = func(_ context.Context, _, _ string) (*v1alpha2.VirtualDisk, error) { - return generateVD(v1alpha2.DiskReady, metav1.ConditionTrue), nil + return generateVD(vdPhase, metav1.ConditionTrue), nil } attachmentServiceMock.GetPersistentVolumeClaimFunc = func(_ context.Context, _ *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { return &corev1.PersistentVolumeClaim{ Status: corev1.PersistentVolumeClaimStatus{ - Phase: phase, + Phase: pvcPhase, }, }, nil } @@ -170,9 +170,11 @@ var _ = Describe("BlockDeviceReadyHandler ValidateVirtualDiskReady", func() { Expect(cb.Condition().Reason).To(Equal(vmbdacondition.BlockDeviceReady.String())) } }, - Entry("ClaimBound", corev1.ClaimBound, metav1.ConditionTrue), - Entry("ClaimPending", corev1.ClaimPending, metav1.ConditionFalse), - Entry("ClaimLost", corev1.ClaimLost, metav1.ConditionFalse), + Entry("VirtualDisk Ready and PVC ClaimBound", v1alpha2.DiskReady, corev1.ClaimBound, metav1.ConditionTrue), + Entry("VirtualDisk Ready and PVC ClaimPending", v1alpha2.DiskReady, corev1.ClaimPending, metav1.ConditionFalse), + Entry("VirtualDisk Ready and PVC ClaimLost", v1alpha2.DiskReady, corev1.ClaimLost, metav1.ConditionFalse), + Entry("VirtualDisk Migrating and PVC ClaimLost", v1alpha2.DiskMigrating, corev1.ClaimLost, metav1.ConditionFalse), + Entry("VirtualDisk WaitForFirstConsumer and PVC ClaimLost", v1alpha2.DiskWaitForFirstConsumer, corev1.ClaimLost, metav1.ConditionTrue), ) }) From d791555e3549af96a83c710f59d98b681b453392 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Fri, 20 Feb 2026 16:39:39 +0300 Subject: [PATCH 3/3] svc Signed-off-by: Valeriy Khorunzhin --- .../vmbda/internal/block_device_ready.go | 6 +++--- .../vmbda/internal/block_device_ready_test.go | 14 +++++++------- .../controller/vmbda/internal/interfaces.go | 4 ++-- .../controller/vmbda/internal/life_cycle.go | 19 ++++++++++--------- .../pkg/controller/vmbda/internal/mock.go | 16 ++++++++-------- .../internal}/service/attachment_service.go | 5 +++-- .../service/attachment_service_test.go | 5 +++-- .../attachment_conflict_validator.go | 6 +++--- .../pkg/controller/vmbda/vmbda_controller.go | 3 ++- .../pkg/controller/vmbda/vmbda_webhook.go | 3 ++- 10 files changed, 43 insertions(+), 38 deletions(-) rename images/virtualization-artifact/pkg/controller/{ => vmbda/internal}/service/attachment_service.go (98%) rename images/virtualization-artifact/pkg/controller/{ => vmbda/internal}/service/attachment_service_test.go (97%) diff --git a/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready.go b/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready.go index 97e4c247f4..d23b3b490d 100644 --- a/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready.go +++ b/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready.go @@ -26,7 +26,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" "github.com/deckhouse/virtualization-controller/pkg/controller/conditions" - "github.com/deckhouse/virtualization-controller/pkg/controller/service" + intsvc "github.com/deckhouse/virtualization-controller/pkg/controller/vmbda/internal/service" "github.com/deckhouse/virtualization/api/core/v1alpha2" "github.com/deckhouse/virtualization/api/core/v1alpha2/vdcondition" "github.com/deckhouse/virtualization/api/core/v1alpha2/vmbdacondition" @@ -109,7 +109,7 @@ func (h BlockDeviceReadyHandler) Handle(ctx context.Context, vmbda *v1alpha2.Vir Message("Waiting until VirtualImage has associated PersistentVolumeClaim name.") return reconcile.Result{}, nil } - ad := service.NewAttachmentDiskFromVirtualImage(vi) + ad := intsvc.NewAttachmentDiskFromVirtualImage(vi) pvc, err := h.attachment.GetPersistentVolumeClaim(ctx, ad) if err != nil { return reconcile.Result{}, err @@ -265,7 +265,7 @@ func (h BlockDeviceReadyHandler) ValidateVirtualDiskReady(ctx context.Context, v return nil } - ad := service.NewAttachmentDiskFromVirtualDisk(vd) + ad := intsvc.NewAttachmentDiskFromVirtualDisk(vd) pvc, err := h.attachment.GetPersistentVolumeClaim(ctx, ad) if err != nil { return err diff --git a/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready_test.go b/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready_test.go index 79d34f6ede..334bc017d9 100644 --- a/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready_test.go +++ b/images/virtualization-artifact/pkg/controller/vmbda/internal/block_device_ready_test.go @@ -27,7 +27,7 @@ import ( vmbdaBuilder "github.com/deckhouse/virtualization-controller/pkg/builder/vmbda" "github.com/deckhouse/virtualization-controller/pkg/controller/conditions" - "github.com/deckhouse/virtualization-controller/pkg/controller/service" + intsvc "github.com/deckhouse/virtualization-controller/pkg/controller/vmbda/internal/service" "github.com/deckhouse/virtualization/api/core/v1alpha2" "github.com/deckhouse/virtualization/api/core/v1alpha2/vdcondition" "github.com/deckhouse/virtualization/api/core/v1alpha2/vmbdacondition" @@ -48,7 +48,7 @@ var _ = Describe("BlockDeviceReadyHandler ValidateVirtualDiskReady", func() { GetVirtualDiskFunc: func(_ context.Context, _, _ string) (*v1alpha2.VirtualDisk, error) { return nil, nil }, - GetPersistentVolumeClaimFunc: func(_ context.Context, _ *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { + GetPersistentVolumeClaimFunc: func(_ context.Context, _ *intsvc.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { return nil, nil }, } @@ -88,7 +88,7 @@ var _ = Describe("BlockDeviceReadyHandler ValidateVirtualDiskReady", func() { attachmentServiceMock.GetVirtualDiskFunc = func(_ context.Context, _, _ string) (*v1alpha2.VirtualDisk, error) { return generateVD(v1alpha2.DiskReady, metav1.ConditionTrue), nil } - attachmentServiceMock.GetPersistentVolumeClaimFunc = func(_ context.Context, _ *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { + attachmentServiceMock.GetPersistentVolumeClaimFunc = func(_ context.Context, _ *intsvc.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { return nil, errors.New("error") } err := NewBlockDeviceReadyHandler(&attachmentServiceMock).ValidateVirtualDiskReady(ctx, vmbda, cb) @@ -99,7 +99,7 @@ var _ = Describe("BlockDeviceReadyHandler ValidateVirtualDiskReady", func() { attachmentServiceMock.GetVirtualDiskFunc = func(_ context.Context, _, _ string) (*v1alpha2.VirtualDisk, error) { return generateVD(v1alpha2.DiskReady, metav1.ConditionTrue), nil } - attachmentServiceMock.GetPersistentVolumeClaimFunc = func(_ context.Context, _ *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { + attachmentServiceMock.GetPersistentVolumeClaimFunc = func(_ context.Context, _ *intsvc.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { return nil, nil } err := NewBlockDeviceReadyHandler(&attachmentServiceMock).ValidateVirtualDiskReady(ctx, vmbda, cb) @@ -112,7 +112,7 @@ var _ = Describe("BlockDeviceReadyHandler ValidateVirtualDiskReady", func() { attachmentServiceMock.GetVirtualDiskFunc = func(_ context.Context, _, _ string) (*v1alpha2.VirtualDisk, error) { return generateVD(v1alpha2.DiskReady, metav1.ConditionFalse), nil } - attachmentServiceMock.GetPersistentVolumeClaimFunc = func(_ context.Context, _ *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { + attachmentServiceMock.GetPersistentVolumeClaimFunc = func(_ context.Context, _ *intsvc.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { return nil, nil } err := NewBlockDeviceReadyHandler(&attachmentServiceMock).ValidateVirtualDiskReady(ctx, vmbda, cb) @@ -125,7 +125,7 @@ var _ = Describe("BlockDeviceReadyHandler ValidateVirtualDiskReady", func() { attachmentServiceMock.GetVirtualDiskFunc = func(_ context.Context, _, _ string) (*v1alpha2.VirtualDisk, error) { return generateVD(phase, metav1.ConditionTrue), nil } - attachmentServiceMock.GetPersistentVolumeClaimFunc = func(_ context.Context, _ *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { + attachmentServiceMock.GetPersistentVolumeClaimFunc = func(_ context.Context, _ *intsvc.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { return &corev1.PersistentVolumeClaim{ Status: corev1.PersistentVolumeClaimStatus{ Phase: corev1.ClaimBound, @@ -156,7 +156,7 @@ var _ = Describe("BlockDeviceReadyHandler ValidateVirtualDiskReady", func() { attachmentServiceMock.GetVirtualDiskFunc = func(_ context.Context, _, _ string) (*v1alpha2.VirtualDisk, error) { return generateVD(vdPhase, metav1.ConditionTrue), nil } - attachmentServiceMock.GetPersistentVolumeClaimFunc = func(_ context.Context, _ *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { + attachmentServiceMock.GetPersistentVolumeClaimFunc = func(_ context.Context, _ *intsvc.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { return &corev1.PersistentVolumeClaim{ Status: corev1.PersistentVolumeClaimStatus{ Phase: pvcPhase, diff --git a/images/virtualization-artifact/pkg/controller/vmbda/internal/interfaces.go b/images/virtualization-artifact/pkg/controller/vmbda/internal/interfaces.go index 5fcbf16099..38222b31e8 100644 --- a/images/virtualization-artifact/pkg/controller/vmbda/internal/interfaces.go +++ b/images/virtualization-artifact/pkg/controller/vmbda/internal/interfaces.go @@ -22,7 +22,7 @@ import ( corev1 "k8s.io/api/core/v1" virtv1 "kubevirt.io/api/core/v1" - "github.com/deckhouse/virtualization-controller/pkg/controller/service" + intsvc "github.com/deckhouse/virtualization-controller/pkg/controller/vmbda/internal/service" "github.com/deckhouse/virtualization/api/core/v1alpha2" ) @@ -35,5 +35,5 @@ type AttachmentService interface { GetVirtualDisk(ctx context.Context, name, namespace string) (*v1alpha2.VirtualDisk, error) GetVirtualImage(ctx context.Context, name, namespace string) (*v1alpha2.VirtualImage, error) GetClusterVirtualImage(ctx context.Context, name string) (*v1alpha2.ClusterVirtualImage, error) - GetPersistentVolumeClaim(ctx context.Context, ad *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) + GetPersistentVolumeClaim(ctx context.Context, ad *intsvc.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) } diff --git a/images/virtualization-artifact/pkg/controller/vmbda/internal/life_cycle.go b/images/virtualization-artifact/pkg/controller/vmbda/internal/life_cycle.go index 52b3c92f7b..d12c94f99d 100644 --- a/images/virtualization-artifact/pkg/controller/vmbda/internal/life_cycle.go +++ b/images/virtualization-artifact/pkg/controller/vmbda/internal/life_cycle.go @@ -28,16 +28,17 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/controller/conditions" "github.com/deckhouse/virtualization-controller/pkg/controller/service" + intsvc "github.com/deckhouse/virtualization-controller/pkg/controller/vmbda/internal/service" "github.com/deckhouse/virtualization-controller/pkg/logger" "github.com/deckhouse/virtualization/api/core/v1alpha2" "github.com/deckhouse/virtualization/api/core/v1alpha2/vmbdacondition" ) type LifeCycleHandler struct { - attacher *service.AttachmentService + attacher *intsvc.AttachmentService } -func NewLifeCycleHandler(attacher *service.AttachmentService) *LifeCycleHandler { +func NewLifeCycleHandler(attacher *intsvc.AttachmentService) *LifeCycleHandler { return &LifeCycleHandler{ attacher: attacher, } @@ -55,7 +56,7 @@ func (h LifeCycleHandler) Handle(ctx context.Context, vmbda *v1alpha2.VirtualMac cb.Status(metav1.ConditionUnknown).Reason(conditions.ReasonUnknown) } - var ad *service.AttachmentDisk + var ad *intsvc.AttachmentDisk switch vmbda.Spec.BlockDeviceRef.Kind { case v1alpha2.VMBDAObjectRefKindVirtualDisk: vd, err := h.attacher.GetVirtualDisk(ctx, vmbda.Spec.BlockDeviceRef.Name, vmbda.Namespace) @@ -63,7 +64,7 @@ func (h LifeCycleHandler) Handle(ctx context.Context, vmbda *v1alpha2.VirtualMac return reconcile.Result{}, err } if vd != nil { - ad = service.NewAttachmentDiskFromVirtualDisk(vd) + ad = intsvc.NewAttachmentDiskFromVirtualDisk(vd) } case v1alpha2.VMBDAObjectRefKindVirtualImage: vi, err := h.attacher.GetVirtualImage(ctx, vmbda.Spec.BlockDeviceRef.Name, vmbda.Namespace) @@ -71,7 +72,7 @@ func (h LifeCycleHandler) Handle(ctx context.Context, vmbda *v1alpha2.VirtualMac return reconcile.Result{}, err } if vi != nil { - ad = service.NewAttachmentDiskFromVirtualImage(vi) + ad = intsvc.NewAttachmentDiskFromVirtualImage(vi) } case v1alpha2.VMBDAObjectRefKindClusterVirtualImage: cvi, err := h.attacher.GetClusterVirtualImage(ctx, vmbda.Spec.BlockDeviceRef.Name) @@ -79,7 +80,7 @@ func (h LifeCycleHandler) Handle(ctx context.Context, vmbda *v1alpha2.VirtualMac return reconcile.Result{}, err } if cvi != nil { - ad = service.NewAttachmentDiskFromClusterVirtualImage(cvi) + ad = intsvc.NewAttachmentDiskFromClusterVirtualImage(cvi) } } @@ -196,7 +197,7 @@ func (h LifeCycleHandler) Handle(ctx context.Context, vmbda *v1alpha2.VirtualMac isHotPlugged, err := h.attacher.IsHotPlugged(ad, vm, kvvmi) if err != nil { - if errors.Is(err, service.ErrVolumeStatusNotReady) { + if errors.Is(err, intsvc.ErrVolumeStatusNotReady) { vmbda.Status.Phase = v1alpha2.BlockDeviceAttachmentPhaseInProgress cb. Status(metav1.ConditionFalse). @@ -277,7 +278,7 @@ func (h LifeCycleHandler) Handle(ctx context.Context, vmbda *v1alpha2.VirtualMac Reason(vmbdacondition.AttachmentRequestSent). Message("Attachment request has sent: attachment is in progress.") return reconcile.Result{}, nil - case errors.Is(err, service.ErrBlockDeviceIsSpecAttached): + case errors.Is(err, intsvc.ErrBlockDeviceIsSpecAttached): log.Info("VirtualDisk is already attached to the virtual machine spec") vmbda.Status.Phase = v1alpha2.BlockDeviceAttachmentPhaseFailed @@ -286,7 +287,7 @@ func (h LifeCycleHandler) Handle(ctx context.Context, vmbda *v1alpha2.VirtualMac Reason(vmbdacondition.Conflict). Message(service.CapitalizeFirstLetter(err.Error())) return reconcile.Result{}, nil - case errors.Is(err, service.ErrHotPlugRequestAlreadySent): + case errors.Is(err, intsvc.ErrHotPlugRequestAlreadySent): log.Info("Attachment request sent: attachment is in progress.") vmbda.Status.Phase = v1alpha2.BlockDeviceAttachmentPhaseInProgress diff --git a/images/virtualization-artifact/pkg/controller/vmbda/internal/mock.go b/images/virtualization-artifact/pkg/controller/vmbda/internal/mock.go index 34b4f669ef..522cf3ee5c 100644 --- a/images/virtualization-artifact/pkg/controller/vmbda/internal/mock.go +++ b/images/virtualization-artifact/pkg/controller/vmbda/internal/mock.go @@ -5,7 +5,7 @@ package internal import ( "context" - "github.com/deckhouse/virtualization-controller/pkg/controller/service" + intsvc "github.com/deckhouse/virtualization-controller/pkg/controller/vmbda/internal/service" "github.com/deckhouse/virtualization/api/core/v1alpha2" corev1 "k8s.io/api/core/v1" virtv1 "kubevirt.io/api/core/v1" @@ -31,7 +31,7 @@ var _ AttachmentService = &AttachmentServiceMock{} // GetKVVMIFunc: func(ctx context.Context, vm *v1alpha2.VirtualMachine) (*virtv1.VirtualMachineInstance, error) { // panic("mock out the GetKVVMI method") // }, -// GetPersistentVolumeClaimFunc: func(ctx context.Context, ad *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { +// GetPersistentVolumeClaimFunc: func(ctx context.Context, ad *intsvc.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { // panic("mock out the GetPersistentVolumeClaim method") // }, // GetVirtualDiskFunc: func(ctx context.Context, name string, namespace string) (*v1alpha2.VirtualDisk, error) { @@ -60,7 +60,7 @@ type AttachmentServiceMock struct { GetKVVMIFunc func(ctx context.Context, vm *v1alpha2.VirtualMachine) (*virtv1.VirtualMachineInstance, error) // GetPersistentVolumeClaimFunc mocks the GetPersistentVolumeClaim method. - GetPersistentVolumeClaimFunc func(ctx context.Context, ad *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) + GetPersistentVolumeClaimFunc func(ctx context.Context, ad *intsvc.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) // GetVirtualDiskFunc mocks the GetVirtualDisk method. GetVirtualDiskFunc func(ctx context.Context, name string, namespace string) (*v1alpha2.VirtualDisk, error) @@ -99,7 +99,7 @@ type AttachmentServiceMock struct { // Ctx is the ctx argument value. Ctx context.Context // Ad is the ad argument value. - Ad *service.AttachmentDisk + Ad *intsvc.AttachmentDisk } // GetVirtualDisk holds details about calls to the GetVirtualDisk method. GetVirtualDisk []struct { @@ -247,13 +247,13 @@ func (mock *AttachmentServiceMock) GetKVVMICalls() []struct { } // GetPersistentVolumeClaim calls GetPersistentVolumeClaimFunc. -func (mock *AttachmentServiceMock) GetPersistentVolumeClaim(ctx context.Context, ad *service.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { +func (mock *AttachmentServiceMock) GetPersistentVolumeClaim(ctx context.Context, ad *intsvc.AttachmentDisk) (*corev1.PersistentVolumeClaim, error) { if mock.GetPersistentVolumeClaimFunc == nil { panic("AttachmentServiceMock.GetPersistentVolumeClaimFunc: method is nil but AttachmentService.GetPersistentVolumeClaim was just called") } callInfo := struct { Ctx context.Context - Ad *service.AttachmentDisk + Ad *intsvc.AttachmentDisk }{ Ctx: ctx, Ad: ad, @@ -270,11 +270,11 @@ func (mock *AttachmentServiceMock) GetPersistentVolumeClaim(ctx context.Context, // len(mockedAttachmentService.GetPersistentVolumeClaimCalls()) func (mock *AttachmentServiceMock) GetPersistentVolumeClaimCalls() []struct { Ctx context.Context - Ad *service.AttachmentDisk + Ad *intsvc.AttachmentDisk } { var calls []struct { Ctx context.Context - Ad *service.AttachmentDisk + Ad *intsvc.AttachmentDisk } mock.lockGetPersistentVolumeClaim.RLock() calls = mock.calls.GetPersistentVolumeClaim diff --git a/images/virtualization-artifact/pkg/controller/service/attachment_service.go b/images/virtualization-artifact/pkg/controller/vmbda/internal/service/attachment_service.go similarity index 98% rename from images/virtualization-artifact/pkg/controller/service/attachment_service.go rename to images/virtualization-artifact/pkg/controller/vmbda/internal/service/attachment_service.go index 3fc9890555..39cef02fa9 100644 --- a/images/virtualization-artifact/pkg/controller/service/attachment_service.go +++ b/images/virtualization-artifact/pkg/controller/vmbda/internal/service/attachment_service.go @@ -30,18 +30,19 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/common/object" "github.com/deckhouse/virtualization-controller/pkg/controller/kvbuilder" + "github.com/deckhouse/virtualization-controller/pkg/controller/service" "github.com/deckhouse/virtualization/api/client/kubeclient" "github.com/deckhouse/virtualization/api/core/v1alpha2" subv1alpha2 "github.com/deckhouse/virtualization/api/subresources/v1alpha2" ) type AttachmentService struct { - client Client + client service.Client virtClient kubeclient.Client controllerNamespace string } -func NewAttachmentService(client Client, virtClient kubeclient.Client, controllerNamespace string) *AttachmentService { +func NewAttachmentService(client service.Client, virtClient kubeclient.Client, controllerNamespace string) *AttachmentService { return &AttachmentService{ client: client, virtClient: virtClient, diff --git a/images/virtualization-artifact/pkg/controller/service/attachment_service_test.go b/images/virtualization-artifact/pkg/controller/vmbda/internal/service/attachment_service_test.go similarity index 97% rename from images/virtualization-artifact/pkg/controller/service/attachment_service_test.go rename to images/virtualization-artifact/pkg/controller/vmbda/internal/service/attachment_service_test.go index 3643c0ef2a..d3dc88993f 100644 --- a/images/virtualization-artifact/pkg/controller/service/attachment_service_test.go +++ b/images/virtualization-artifact/pkg/controller/vmbda/internal/service/attachment_service_test.go @@ -25,11 +25,12 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" + service "github.com/deckhouse/virtualization-controller/pkg/controller/service" "github.com/deckhouse/virtualization/api/core/v1alpha2" ) var _ = Describe("AttachmentService method IsConflictedAttachment", func() { - var clientMock *ClientMock + var clientMock *service.ClientMock var vmbdaAlpha *v1alpha2.VirtualMachineBlockDeviceAttachment var vmbdaBeta *v1alpha2.VirtualMachineBlockDeviceAttachment @@ -60,7 +61,7 @@ var _ = Describe("AttachmentService method IsConflictedAttachment", func() { Spec: spec, } - clientMock = &ClientMock{} + clientMock = &service.ClientMock{} }) // T1: -->VMBDA A Should be Conflicted diff --git a/images/virtualization-artifact/pkg/controller/vmbda/internal/validators/attachment_conflict_validator.go b/images/virtualization-artifact/pkg/controller/vmbda/internal/validators/attachment_conflict_validator.go index 82d5147299..eeef8ca152 100644 --- a/images/virtualization-artifact/pkg/controller/vmbda/internal/validators/attachment_conflict_validator.go +++ b/images/virtualization-artifact/pkg/controller/vmbda/internal/validators/attachment_conflict_validator.go @@ -23,16 +23,16 @@ import ( "sigs.k8s.io/controller-runtime/pkg/webhook/admission" "github.com/deckhouse/deckhouse/pkg/log" - "github.com/deckhouse/virtualization-controller/pkg/controller/service" + intsvc "github.com/deckhouse/virtualization-controller/pkg/controller/vmbda/internal/service" "github.com/deckhouse/virtualization/api/core/v1alpha2" ) type AttachmentConflictValidator struct { log *log.Logger - service *service.AttachmentService + service *intsvc.AttachmentService } -func NewAttachmentConflictValidator(service *service.AttachmentService, log *log.Logger) *AttachmentConflictValidator { +func NewAttachmentConflictValidator(service *intsvc.AttachmentService, log *log.Logger) *AttachmentConflictValidator { return &AttachmentConflictValidator{ log: log, service: service, diff --git a/images/virtualization-artifact/pkg/controller/vmbda/vmbda_controller.go b/images/virtualization-artifact/pkg/controller/vmbda/vmbda_controller.go index 99cff3e675..7dc7d00ed7 100644 --- a/images/virtualization-artifact/pkg/controller/vmbda/vmbda_controller.go +++ b/images/virtualization-artifact/pkg/controller/vmbda/vmbda_controller.go @@ -29,6 +29,7 @@ import ( "github.com/deckhouse/deckhouse/pkg/log" "github.com/deckhouse/virtualization-controller/pkg/controller/service" "github.com/deckhouse/virtualization-controller/pkg/controller/vmbda/internal" + intsvc "github.com/deckhouse/virtualization-controller/pkg/controller/vmbda/internal/service" "github.com/deckhouse/virtualization-controller/pkg/logger" vmbdametrics "github.com/deckhouse/virtualization-controller/pkg/monitoring/metrics/vmbda" "github.com/deckhouse/virtualization/api/client/kubeclient" @@ -44,7 +45,7 @@ func NewController( lg *log.Logger, ns string, ) (controller.Controller, error) { - attacher := service.NewAttachmentService(mgr.GetClient(), virtClient, ns) + attacher := intsvc.NewAttachmentService(mgr.GetClient(), virtClient, ns) blockDeviceService := service.NewBlockDeviceService(mgr.GetClient()) reconciler := NewReconciler( diff --git a/images/virtualization-artifact/pkg/controller/vmbda/vmbda_webhook.go b/images/virtualization-artifact/pkg/controller/vmbda/vmbda_webhook.go index b355b03710..3dab83b997 100644 --- a/images/virtualization-artifact/pkg/controller/vmbda/vmbda_webhook.go +++ b/images/virtualization-artifact/pkg/controller/vmbda/vmbda_webhook.go @@ -25,6 +25,7 @@ import ( "github.com/deckhouse/deckhouse/pkg/log" "github.com/deckhouse/virtualization-controller/pkg/controller/service" + intsvc "github.com/deckhouse/virtualization-controller/pkg/controller/vmbda/internal/service" "github.com/deckhouse/virtualization-controller/pkg/controller/vmbda/internal/validators" "github.com/deckhouse/virtualization/api/core/v1alpha2" ) @@ -39,7 +40,7 @@ type Validator struct { log *log.Logger } -func NewValidator(attachmentService *service.AttachmentService, service *service.BlockDeviceService, log *log.Logger) *Validator { +func NewValidator(attachmentService *intsvc.AttachmentService, service *service.BlockDeviceService, log *log.Logger) *Validator { return &Validator{ log: log.With("webhook", "validation"), validators: []VirtualMachineBlockDeviceAttachmentValidator{