From a14e78078e7097a860fece869ec8632e35ae46ad Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Wed, 18 Dec 2024 15:33:31 +0300 Subject: [PATCH 01/23] add Signed-off-by: Valeriy Khorunzhin --- api/core/v1alpha2/vdcondition/condition.go | 15 ++ .../controller/vd/internal/quota_exceeded.go | 133 ++++++++++++++++++ .../pkg/controller/vd/vd_controller.go | 1 + 3 files changed, 149 insertions(+) create mode 100644 images/virtualization-artifact/pkg/controller/vd/internal/quota_exceeded.go diff --git a/api/core/v1alpha2/vdcondition/condition.go b/api/core/v1alpha2/vdcondition/condition.go index 0c60e6a36..ad50a9fd1 100644 --- a/api/core/v1alpha2/vdcondition/condition.go +++ b/api/core/v1alpha2/vdcondition/condition.go @@ -36,6 +36,8 @@ const ( StorageClassReadyType Type = "StorageClassReady" // InUseType indicates whether the VirtualDisk is attached to a running VirtualMachine or is being used in a process of an image creation. InUseType Type = "InUse" + // QuotaNotExceededType indicates whether the disk not exceed project quotas. + QuotaNotExceededType Type = "QuotaNotExceeded" ) type ( @@ -51,6 +53,8 @@ type ( StorageClassReadyReason string // InUseReason represents the various reasons for the InUse condition type. InUseReason string + // QuotaNotExceededReason represents the various reasons for the QuotaNotExceeded condition type. + QuotaNotExceededReason string ) func (s DatasourceReadyReason) String() string { @@ -77,6 +81,10 @@ func (s InUseReason) String() string { return string(s) } +func (s QuotaNotExceededReason) String() string { + return string(s) +} + const ( // DatasourceReady indicates that the datasource is ready for use, allowing the import process to start. DatasourceReady DatasourceReadyReason = "DatasourceReady" @@ -133,4 +141,11 @@ const ( AttachedToVirtualMachine InUseReason = "AttachedToVirtualMachine" // NotInUse indicates that VirtualDisk free for use. NotInUse InUseReason = "NotInUse" + + // QuotaNotExceeded indicates that the VirtualDisk is not reached project quotas. + QuotaNotExceeded QuotaNotExceededReason = "QuotaNotExceeded" + // QuotaExceeded indicates that the VirtualDisk is reached project quotas and can not be provisioned. + QuotaExceeded QuotaNotExceededReason = "QuotaExceeded" + // PVCIsPending indicates that the VirtualDisk has unknown state of provisioning and need to check DataVolume and PVC manually. + PVCIsPending QuotaNotExceededReason = "PVCIsPending" ) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/quota_exceeded.go b/images/virtualization-artifact/pkg/controller/vd/internal/quota_exceeded.go new file mode 100644 index 000000000..390a78e03 --- /dev/null +++ b/images/virtualization-artifact/pkg/controller/vd/internal/quota_exceeded.go @@ -0,0 +1,133 @@ +/* +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 ( + "context" + "strings" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/deckhouse/virtualization-controller/pkg/common/annotations" + "github.com/deckhouse/virtualization-controller/pkg/controller/conditions" + "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" +) + +const ( + DVBoundConditionType string = "Bound" + DVRunningConditionType string = "Running" + DVReadyConditionType string = "Ready" + DVErrExceededQuotaReason string = "ErrExceededQuota" +) + +type QuotaExceededHandler struct { + diskService *service.DiskService +} + +func NewQuotaExceededHandler(client client.Client) *QuotaExceededHandler { + return &QuotaExceededHandler{ + diskService: service.NewDiskService(client, nil, nil), + } +} + +func (q *QuotaExceededHandler) Handle(ctx context.Context, vd *virtv2.VirtualDisk) (reconcile.Result, error) { + if vd.DeletionTimestamp != nil { + return reconcile.Result{}, nil + } + + cb := conditions.NewConditionBuilder(vdcondition.QuotaNotExceededType).Generation(vd.Generation) + defer func() { + conditions.SetCondition(cb, &vd.Status.Conditions) + }() + + readyCondition, ok := conditions.GetCondition(vdcondition.ReadyType, vd.Status.Conditions) + if !ok || readyCondition.Status == metav1.ConditionTrue { + return reconcile.Result{}, nil + } + + supgen := supplements.NewGenerator(annotations.VDShortName, vd.Name, vd.Namespace, vd.UID) + dv, err := q.diskService.GetDataVolume(ctx, supgen) + if err != nil { + return reconcile.Result{}, err + } + + if dv == nil { + return reconcile.Result{}, nil + } + + boundCondition, ok := getDVCondition(dv, DVBoundConditionType) + if !ok { + return reconcile.Result{}, nil + } + + readyDVCondition, ok := getDVCondition(dv, DVReadyConditionType) + if !ok { + return reconcile.Result{}, nil + } + + runningCondition, ok := getDVCondition(dv, DVRunningConditionType) + if !ok { + return reconcile.Result{}, nil + } + + if runningCondition.Status == corev1.ConditionTrue { + cb. + Reason(vdcondition.QuotaNotExceeded). + Message("") + } else { + switch { + case boundCondition.Reason == DVErrExceededQuotaReason: + cb. + Status(metav1.ConditionFalse). + Reason(vdcondition.QuotaExceeded). + Message(service.CapitalizeFirstLetter(boundCondition.Message)) + case readyDVCondition.Reason == DVErrExceededQuotaReason: + cb. + Status(metav1.ConditionFalse). + Reason(vdcondition.QuotaExceeded). + Message(service.CapitalizeFirstLetter(readyDVCondition.Message)) + case runningCondition.Reason == DVErrExceededQuotaReason: + cb. + Status(metav1.ConditionFalse). + Reason(vdcondition.QuotaExceeded). + Message(service.CapitalizeFirstLetter(runningCondition.Message)) + case strings.Contains(boundCondition.Message, "Pending"): + cb. + Reason(vdcondition.PVCIsPending). + Message("PVC in pending state, if this continues for a long time, check the status of PVC and DataVolume manually.") + } + } + + return reconcile.Result{}, nil +} + +func getDVCondition(dv *cdiv1.DataVolume, conditionType string) (*cdiv1.DataVolumeCondition, bool) { + for _, cond := range dv.Status.Conditions { + if string(cond.Type) == conditionType { + return &cond, true + } + } + + return nil, false +} diff --git a/images/virtualization-artifact/pkg/controller/vd/vd_controller.go b/images/virtualization-artifact/pkg/controller/vd/vd_controller.go index cb30f79a9..1aeb9e949 100644 --- a/images/virtualization-artifact/pkg/controller/vd/vd_controller.go +++ b/images/virtualization-artifact/pkg/controller/vd/vd_controller.go @@ -87,6 +87,7 @@ func NewController( internal.NewAttacheeHandler(mgr.GetClient()), internal.NewStatsHandler(stat, importer, uploader), internal.NewInUseHandler(mgr.GetClient()), + internal.NewQuotaExceededHandler(mgr.GetClient()), ) vdController, err := controller.New(ControllerName, mgr, controller.Options{ From 79183333eb1e68fb2dce987c0865e52bb5a49a5f Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Thu, 19 Dec 2024 02:22:35 +0300 Subject: [PATCH 02/23] change ready condition logic Signed-off-by: Valeriy Khorunzhin --- api/core/v1alpha2/vdcondition/condition.go | 17 +-- .../controller/vd/internal/quota_exceeded.go | 133 ------------------ .../controller/vd/internal/source/blank.go | 16 +++ .../pkg/controller/vd/internal/source/http.go | 15 ++ .../vd/internal/source/object_ref_cvi.go | 15 ++ .../vd/internal/source/object_ref_vi_dvcr.go | 15 ++ .../vd/internal/source/object_ref_vi_pvc.go | 15 ++ .../controller/vd/internal/source/registry.go | 16 +++ .../controller/vd/internal/source/sources.go | 52 +++++++ .../controller/vd/internal/source/upload.go | 16 +++ .../pkg/controller/vd/vd_controller.go | 1 - 11 files changed, 162 insertions(+), 149 deletions(-) delete mode 100644 images/virtualization-artifact/pkg/controller/vd/internal/quota_exceeded.go diff --git a/api/core/v1alpha2/vdcondition/condition.go b/api/core/v1alpha2/vdcondition/condition.go index ad50a9fd1..3d512e7cd 100644 --- a/api/core/v1alpha2/vdcondition/condition.go +++ b/api/core/v1alpha2/vdcondition/condition.go @@ -36,8 +36,6 @@ const ( StorageClassReadyType Type = "StorageClassReady" // InUseType indicates whether the VirtualDisk is attached to a running VirtualMachine or is being used in a process of an image creation. InUseType Type = "InUse" - // QuotaNotExceededType indicates whether the disk not exceed project quotas. - QuotaNotExceededType Type = "QuotaNotExceeded" ) type ( @@ -53,8 +51,6 @@ type ( StorageClassReadyReason string // InUseReason represents the various reasons for the InUse condition type. InUseReason string - // QuotaNotExceededReason represents the various reasons for the QuotaNotExceeded condition type. - QuotaNotExceededReason string ) func (s DatasourceReadyReason) String() string { @@ -81,10 +77,6 @@ func (s InUseReason) String() string { return string(s) } -func (s QuotaNotExceededReason) String() string { - return string(s) -} - const ( // DatasourceReady indicates that the datasource is ready for use, allowing the import process to start. DatasourceReady DatasourceReadyReason = "DatasourceReady" @@ -113,6 +105,8 @@ const ( Ready ReadyReason = "Ready" // Lost indicates that the underlying PersistentVolumeClaim has been lost and the `VirtualDisk` can no longer be used. Lost ReadyReason = "PVCLost" + // QuotaExceeded indicates that the VirtualDisk is reached project quotas and can not be provisioned. + QuotaExceeded ReadyReason = "QuotaExceeded" // ResizingNotRequested indicates that the resize operation has not been requested yet. ResizingNotRequested ResizedReason = "NotRequested" @@ -141,11 +135,4 @@ const ( AttachedToVirtualMachine InUseReason = "AttachedToVirtualMachine" // NotInUse indicates that VirtualDisk free for use. NotInUse InUseReason = "NotInUse" - - // QuotaNotExceeded indicates that the VirtualDisk is not reached project quotas. - QuotaNotExceeded QuotaNotExceededReason = "QuotaNotExceeded" - // QuotaExceeded indicates that the VirtualDisk is reached project quotas and can not be provisioned. - QuotaExceeded QuotaNotExceededReason = "QuotaExceeded" - // PVCIsPending indicates that the VirtualDisk has unknown state of provisioning and need to check DataVolume and PVC manually. - PVCIsPending QuotaNotExceededReason = "PVCIsPending" ) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/quota_exceeded.go b/images/virtualization-artifact/pkg/controller/vd/internal/quota_exceeded.go deleted file mode 100644 index 390a78e03..000000000 --- a/images/virtualization-artifact/pkg/controller/vd/internal/quota_exceeded.go +++ /dev/null @@ -1,133 +0,0 @@ -/* -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 ( - "context" - "strings" - - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - "github.com/deckhouse/virtualization-controller/pkg/common/annotations" - "github.com/deckhouse/virtualization-controller/pkg/controller/conditions" - "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" -) - -const ( - DVBoundConditionType string = "Bound" - DVRunningConditionType string = "Running" - DVReadyConditionType string = "Ready" - DVErrExceededQuotaReason string = "ErrExceededQuota" -) - -type QuotaExceededHandler struct { - diskService *service.DiskService -} - -func NewQuotaExceededHandler(client client.Client) *QuotaExceededHandler { - return &QuotaExceededHandler{ - diskService: service.NewDiskService(client, nil, nil), - } -} - -func (q *QuotaExceededHandler) Handle(ctx context.Context, vd *virtv2.VirtualDisk) (reconcile.Result, error) { - if vd.DeletionTimestamp != nil { - return reconcile.Result{}, nil - } - - cb := conditions.NewConditionBuilder(vdcondition.QuotaNotExceededType).Generation(vd.Generation) - defer func() { - conditions.SetCondition(cb, &vd.Status.Conditions) - }() - - readyCondition, ok := conditions.GetCondition(vdcondition.ReadyType, vd.Status.Conditions) - if !ok || readyCondition.Status == metav1.ConditionTrue { - return reconcile.Result{}, nil - } - - supgen := supplements.NewGenerator(annotations.VDShortName, vd.Name, vd.Namespace, vd.UID) - dv, err := q.diskService.GetDataVolume(ctx, supgen) - if err != nil { - return reconcile.Result{}, err - } - - if dv == nil { - return reconcile.Result{}, nil - } - - boundCondition, ok := getDVCondition(dv, DVBoundConditionType) - if !ok { - return reconcile.Result{}, nil - } - - readyDVCondition, ok := getDVCondition(dv, DVReadyConditionType) - if !ok { - return reconcile.Result{}, nil - } - - runningCondition, ok := getDVCondition(dv, DVRunningConditionType) - if !ok { - return reconcile.Result{}, nil - } - - if runningCondition.Status == corev1.ConditionTrue { - cb. - Reason(vdcondition.QuotaNotExceeded). - Message("") - } else { - switch { - case boundCondition.Reason == DVErrExceededQuotaReason: - cb. - Status(metav1.ConditionFalse). - Reason(vdcondition.QuotaExceeded). - Message(service.CapitalizeFirstLetter(boundCondition.Message)) - case readyDVCondition.Reason == DVErrExceededQuotaReason: - cb. - Status(metav1.ConditionFalse). - Reason(vdcondition.QuotaExceeded). - Message(service.CapitalizeFirstLetter(readyDVCondition.Message)) - case runningCondition.Reason == DVErrExceededQuotaReason: - cb. - Status(metav1.ConditionFalse). - Reason(vdcondition.QuotaExceeded). - Message(service.CapitalizeFirstLetter(runningCondition.Message)) - case strings.Contains(boundCondition.Message, "Pending"): - cb. - Reason(vdcondition.PVCIsPending). - Message("PVC in pending state, if this continues for a long time, check the status of PVC and DataVolume manually.") - } - } - - return reconcile.Result{}, nil -} - -func getDVCondition(dv *cdiv1.DataVolume, conditionType string) (*cdiv1.DataVolumeCondition, bool) { - for _, cond := range dv.Status.Conditions { - if string(cond.Type) == conditionType { - return &cond, true - } - } - - return nil, false -} diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go index 96507b2b1..9945370cf 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go @@ -84,6 +84,8 @@ func (ds BlankDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (rec return reconcile.Result{}, err } + quotaExceeded, quotaExceededMessage := checkIfQuotaExceeded(dv) + switch { case isDiskProvisioningFinished(condition): log.Debug("Disk provisioning finished: clean up") @@ -139,6 +141,12 @@ func (ds BlankDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (rec Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil + case quotaExceeded: + cb. + Status(metav1.ConditionFalse). + Reason(vdcondition.QuotaExceeded). + Message(quotaExceededMessage) + return reconcile.Result{}, nil case pvc == nil: vd.Status.Phase = virtv2.DiskProvisioning cb. @@ -181,6 +189,14 @@ func (ds BlankDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (rec if err = setPhaseConditionForPVCProvisioningDisk(ctx, dv, vd, pvc, sc, cb, ds.diskService); err != nil { return reconcile.Result{}, err } + + if pvc.Status.Phase == "Pending" { + cb. + Status(metav1.ConditionFalse). + Reason(vdcondition.Provisioning). + Message("PVC in pending state, if this continues for a long time, check the status of PVC and DataVolume manually.") + } + return reconcile.Result{}, nil } diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go index d5424dd9e..17be407ff 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go @@ -106,6 +106,8 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (reco return reconcile.Result{}, err } + quotaExceeded, quotaExceededMessage := checkIfQuotaExceeded(dv) + switch { case isDiskProvisioningFinished(condition): log.Debug("Disk provisioning finished: clean up") @@ -257,6 +259,12 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (reco Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil + case quotaExceeded: + cb. + Status(metav1.ConditionFalse). + Reason(vdcondition.QuotaExceeded). + Message(quotaExceededMessage) + return reconcile.Result{}, nil case pvc == nil: vd.Status.Phase = virtv2.DiskProvisioning cb. @@ -308,6 +316,13 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (reco return reconcile.Result{}, err } + if pvc.Status.Phase == "Pending" { + cb. + Status(metav1.ConditionFalse). + Reason(vdcondition.Provisioning). + Message("PVC in pending state, if this continues for a long time, check the status of PVC and DataVolume manually.") + } + return reconcile.Result{}, nil } diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go index 92517f718..023149139 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go @@ -103,6 +103,8 @@ func (ds ObjectRefClusterVirtualImage) Sync(ctx context.Context, vd *virtv2.Virt return reconcile.Result{}, err } + quotaExceeded, quotaExceededMessage := checkIfQuotaExceeded(dv) + switch { case isDiskProvisioningFinished(condition): log.Debug("Disk provisioning finished: clean up") @@ -172,6 +174,12 @@ func (ds ObjectRefClusterVirtualImage) Sync(ctx context.Context, vd *virtv2.Virt Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil + case quotaExceeded: + cb. + Status(metav1.ConditionFalse). + Reason(vdcondition.QuotaExceeded). + Message(quotaExceededMessage) + return reconcile.Result{}, nil case pvc == nil: vd.Status.Phase = virtv2.DiskProvisioning cb. @@ -221,6 +229,13 @@ func (ds ObjectRefClusterVirtualImage) Sync(ctx context.Context, vd *virtv2.Virt return reconcile.Result{}, err } + if pvc.Status.Phase == "Pending" { + cb. + Status(metav1.ConditionFalse). + Reason(vdcondition.Provisioning). + Message("PVC in pending state, if this continues for a long time, check the status of PVC and DataVolume manually.") + } + return reconcile.Result{}, nil } diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go index 40084881e..cd3a453f4 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go @@ -102,6 +102,8 @@ func (ds ObjectRefVirtualImageDVCR) Sync(ctx context.Context, vd *virtv2.Virtual return reconcile.Result{}, err } + quotaExceeded, quotaExceededMessage := checkIfQuotaExceeded(dv) + switch { case isDiskProvisioningFinished(condition): log.Debug("Disk provisioning finished: clean up") @@ -171,6 +173,12 @@ func (ds ObjectRefVirtualImageDVCR) Sync(ctx context.Context, vd *virtv2.Virtual Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil + case quotaExceeded: + cb. + Status(metav1.ConditionFalse). + Reason(vdcondition.QuotaExceeded). + Message(quotaExceededMessage) + return reconcile.Result{}, nil case pvc == nil: vd.Status.Phase = virtv2.DiskProvisioning cb. @@ -220,6 +228,13 @@ func (ds ObjectRefVirtualImageDVCR) Sync(ctx context.Context, vd *virtv2.Virtual return reconcile.Result{}, err } + if pvc.Status.Phase == "Pending" { + cb. + Status(metav1.ConditionFalse). + Reason(vdcondition.Provisioning). + Message("") + } + return reconcile.Result{}, nil } diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go index 16034ac82..66a036065 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go @@ -98,6 +98,8 @@ func (ds ObjectRefVirtualImagePVC) Sync(ctx context.Context, vd *virtv2.VirtualD return reconcile.Result{}, err } + quotaExceeded, quotaExceededMessage := checkIfQuotaExceeded(dv) + switch { case isDiskProvisioningFinished(condition): log.Info("Disk provisioning finished: clean up") @@ -172,6 +174,12 @@ func (ds ObjectRefVirtualImagePVC) Sync(ctx context.Context, vd *virtv2.VirtualD Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil + case quotaExceeded: + cb. + Status(metav1.ConditionFalse). + Reason(vdcondition.QuotaExceeded). + Message(quotaExceededMessage) + return reconcile.Result{}, nil case pvc == nil: vd.Status.Phase = virtv2.DiskProvisioning cb. @@ -222,6 +230,13 @@ func (ds ObjectRefVirtualImagePVC) Sync(ctx context.Context, vd *virtv2.VirtualD return reconcile.Result{}, err } + if pvc.Status.Phase == "Pending" { + cb. + Status(metav1.ConditionFalse). + Reason(vdcondition.Provisioning). + Message("PVC in pending state, if this continues for a long time, check the status of PVC and DataVolume manually.") + } + return reconcile.Result{}, nil } diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go index c3b9ee44c..3ac862f35 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go @@ -107,6 +107,8 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) ( return reconcile.Result{}, err } + quotaExceeded, quotaExceededMessage := checkIfQuotaExceeded(dv) + switch { case isDiskProvisioningFinished(condition): log.Debug("Disk provisioning finished: clean up") @@ -255,6 +257,12 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) ( Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil + case quotaExceeded: + cb. + Status(metav1.ConditionFalse). + Reason(vdcondition.QuotaExceeded). + Message(quotaExceededMessage) + return reconcile.Result{}, nil case pvc == nil: vd.Status.Phase = virtv2.DiskProvisioning cb. @@ -304,6 +312,14 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) ( if err = setPhaseConditionForPVCProvisioningDisk(ctx, dv, vd, pvc, sc, cb, ds.diskService); err != nil { return reconcile.Result{}, err } + + if pvc.Status.Phase == "Pending" { + cb. + Status(metav1.ConditionFalse). + Reason(vdcondition.Provisioning). + Message("PVC in pending state, if this continues for a long time, check the status of PVC and DataVolume manually.") + } + return reconcile.Result{}, nil } diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go index 106e2c99c..2850a0688 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go @@ -416,3 +416,55 @@ func setPhaseConditionToFailed(cb *conditions.ConditionBuilder, phase *virtv2.Di Reason(vdcondition.ProvisioningFailed). Message(service.CapitalizeFirstLetter(err.Error()) + ".") } + +const ( + DVBoundConditionType string = "Bound" + DVRunningConditionType string = "Running" + DVReadyConditionType string = "Ready" + DVErrExceededQuotaReason string = "ErrExceededQuota" +) + +func checkIfQuotaExceeded(dv *cdiv1.DataVolume) (bool, string) { + if dv == nil { + return false, "" + } + + boundCondition, ok := getDVCondition(dv, DVBoundConditionType) + if !ok { + return false, "" + } + + readyDVCondition, ok := getDVCondition(dv, DVReadyConditionType) + if !ok { + return false, "" + } + + runningCondition, ok := getDVCondition(dv, DVRunningConditionType) + if !ok { + return false, "" + } + + if boundCondition.Reason == DVErrExceededQuotaReason { + return true, service.CapitalizeFirstLetter(boundCondition.Message) + } + + if readyDVCondition.Reason == DVErrExceededQuotaReason { + return true, service.CapitalizeFirstLetter(readyDVCondition.Message) + } + + if runningCondition.Reason == DVErrExceededQuotaReason { + return true, service.CapitalizeFirstLetter(runningCondition.Message) + } + + return false, "" +} + +func getDVCondition(dv *cdiv1.DataVolume, conditionType string) (*cdiv1.DataVolumeCondition, bool) { + for _, cond := range dv.Status.Conditions { + if string(cond.Type) == conditionType { + return &cond, true + } + } + + return nil, false +} diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go index e0b10438f..d169a643e 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go @@ -114,6 +114,8 @@ func (ds UploadDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (re return reconcile.Result{}, err } + quotaExceeded, quotaExceededMessage := checkIfQuotaExceeded(dv) + switch { case isDiskProvisioningFinished(condition): log.Debug("Disk provisioning finished: clean up") @@ -284,6 +286,12 @@ func (ds UploadDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (re Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil + case quotaExceeded: + cb. + Status(metav1.ConditionFalse). + Reason(vdcondition.QuotaExceeded). + Message(quotaExceededMessage) + return reconcile.Result{}, nil case pvc == nil: vd.Status.Phase = virtv2.DiskProvisioning cb. @@ -335,6 +343,14 @@ func (ds UploadDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (re if err = setPhaseConditionForPVCProvisioningDisk(ctx, dv, vd, pvc, sc, cb, ds.diskService); err != nil { return reconcile.Result{}, err } + + if pvc.Status.Phase == "Pending" { + cb. + Status(metav1.ConditionFalse). + Reason(vdcondition.Provisioning). + Message("PVC in pending state, if this continues for a long time, check the status of PVC and DataVolume manually.") + } + return reconcile.Result{}, nil } diff --git a/images/virtualization-artifact/pkg/controller/vd/vd_controller.go b/images/virtualization-artifact/pkg/controller/vd/vd_controller.go index 1aeb9e949..cb30f79a9 100644 --- a/images/virtualization-artifact/pkg/controller/vd/vd_controller.go +++ b/images/virtualization-artifact/pkg/controller/vd/vd_controller.go @@ -87,7 +87,6 @@ func NewController( internal.NewAttacheeHandler(mgr.GetClient()), internal.NewStatsHandler(stat, importer, uploader), internal.NewInUseHandler(mgr.GetClient()), - internal.NewQuotaExceededHandler(mgr.GetClient()), ) vdController, err := controller.New(ControllerName, mgr, controller.Options{ From 52dc9d07adaeeab2a1273da26efb92c0d8be4353 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Thu, 19 Dec 2024 02:25:17 +0300 Subject: [PATCH 03/23] refactoring Signed-off-by: Valeriy Khorunzhin --- .../vd/internal/source/object_ref_vi_dvcr.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go index cd3a453f4..4d64a7bd6 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go @@ -174,11 +174,11 @@ func (ds ObjectRefVirtualImageDVCR) Sync(ctx context.Context, vd *virtv2.Virtual return reconcile.Result{Requeue: true}, nil case quotaExceeded: - cb. - Status(metav1.ConditionFalse). - Reason(vdcondition.QuotaExceeded). - Message(quotaExceededMessage) - return reconcile.Result{}, nil + cb. + Status(metav1.ConditionFalse). + Reason(vdcondition.QuotaExceeded). + Message(quotaExceededMessage) + return reconcile.Result{}, nil case pvc == nil: vd.Status.Phase = virtv2.DiskProvisioning cb. @@ -229,10 +229,10 @@ func (ds ObjectRefVirtualImageDVCR) Sync(ctx context.Context, vd *virtv2.Virtual } if pvc.Status.Phase == "Pending" { - cb. - Status(metav1.ConditionFalse). - Reason(vdcondition.Provisioning). - Message("") + cb. + Status(metav1.ConditionFalse). + Reason(vdcondition.Provisioning). + Message("") } return reconcile.Result{}, nil From 52bb25bee522eac175fc404d0f1949bdb6e2af56 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Thu, 19 Dec 2024 16:26:13 +0300 Subject: [PATCH 04/23] fix Signed-off-by: Valeriy Khorunzhin --- .../pkg/controller/vd/internal/source/blank.go | 8 -------- .../pkg/controller/vd/internal/source/http.go | 8 -------- .../pkg/controller/vd/internal/source/object_ref_cvi.go | 8 -------- .../controller/vd/internal/source/object_ref_vi_dvcr.go | 8 -------- .../controller/vd/internal/source/object_ref_vi_pvc.go | 7 ------- .../pkg/controller/vd/internal/source/registry.go | 8 -------- .../pkg/controller/vd/internal/source/upload.go | 8 -------- 7 files changed, 55 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go index 9945370cf..b2d55aabf 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go @@ -189,14 +189,6 @@ func (ds BlankDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (rec if err = setPhaseConditionForPVCProvisioningDisk(ctx, dv, vd, pvc, sc, cb, ds.diskService); err != nil { return reconcile.Result{}, err } - - if pvc.Status.Phase == "Pending" { - cb. - Status(metav1.ConditionFalse). - Reason(vdcondition.Provisioning). - Message("PVC in pending state, if this continues for a long time, check the status of PVC and DataVolume manually.") - } - return reconcile.Result{}, nil } diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go index 17be407ff..631e9d90e 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go @@ -315,14 +315,6 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (reco if err = setPhaseConditionForPVCProvisioningDisk(ctx, dv, vd, pvc, sc, cb, ds.diskService); err != nil { return reconcile.Result{}, err } - - if pvc.Status.Phase == "Pending" { - cb. - Status(metav1.ConditionFalse). - Reason(vdcondition.Provisioning). - Message("PVC in pending state, if this continues for a long time, check the status of PVC and DataVolume manually.") - } - return reconcile.Result{}, nil } diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go index 023149139..c0c9f4a53 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go @@ -228,14 +228,6 @@ func (ds ObjectRefClusterVirtualImage) Sync(ctx context.Context, vd *virtv2.Virt if err = setPhaseConditionForPVCProvisioningDisk(ctx, dv, vd, pvc, sc, cb, ds.diskService); err != nil { return reconcile.Result{}, err } - - if pvc.Status.Phase == "Pending" { - cb. - Status(metav1.ConditionFalse). - Reason(vdcondition.Provisioning). - Message("PVC in pending state, if this continues for a long time, check the status of PVC and DataVolume manually.") - } - return reconcile.Result{}, nil } diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go index 4d64a7bd6..46c62aa79 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go @@ -227,14 +227,6 @@ func (ds ObjectRefVirtualImageDVCR) Sync(ctx context.Context, vd *virtv2.Virtual if err = setPhaseConditionForPVCProvisioningDisk(ctx, dv, vd, pvc, sc, cb, ds.diskService); err != nil { return reconcile.Result{}, err } - - if pvc.Status.Phase == "Pending" { - cb. - Status(metav1.ConditionFalse). - Reason(vdcondition.Provisioning). - Message("") - } - return reconcile.Result{}, nil } diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go index 66a036065..3992ea5b4 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go @@ -230,13 +230,6 @@ func (ds ObjectRefVirtualImagePVC) Sync(ctx context.Context, vd *virtv2.VirtualD return reconcile.Result{}, err } - if pvc.Status.Phase == "Pending" { - cb. - Status(metav1.ConditionFalse). - Reason(vdcondition.Provisioning). - Message("PVC in pending state, if this continues for a long time, check the status of PVC and DataVolume manually.") - } - return reconcile.Result{}, nil } diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go index 3ac862f35..b171f3286 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go @@ -312,14 +312,6 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) ( if err = setPhaseConditionForPVCProvisioningDisk(ctx, dv, vd, pvc, sc, cb, ds.diskService); err != nil { return reconcile.Result{}, err } - - if pvc.Status.Phase == "Pending" { - cb. - Status(metav1.ConditionFalse). - Reason(vdcondition.Provisioning). - Message("PVC in pending state, if this continues for a long time, check the status of PVC and DataVolume manually.") - } - return reconcile.Result{}, nil } diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go index d169a643e..76bbf64ad 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go @@ -343,14 +343,6 @@ func (ds UploadDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (re if err = setPhaseConditionForPVCProvisioningDisk(ctx, dv, vd, pvc, sc, cb, ds.diskService); err != nil { return reconcile.Result{}, err } - - if pvc.Status.Phase == "Pending" { - cb. - Status(metav1.ConditionFalse). - Reason(vdcondition.Provisioning). - Message("PVC in pending state, if this continues for a long time, check the status of PVC and DataVolume manually.") - } - return reconcile.Result{}, nil } From e567584266f90f5ee4c4b7f0b5b89884b1d5bcf0 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Thu, 19 Dec 2024 16:28:25 +0300 Subject: [PATCH 05/23] get back empty lines) Signed-off-by: Valeriy Khorunzhin --- .../pkg/controller/vd/internal/source/http.go | 1 + .../pkg/controller/vd/internal/source/object_ref_cvi.go | 1 + .../pkg/controller/vd/internal/source/object_ref_vi_dvcr.go | 1 + 3 files changed, 3 insertions(+) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go index 631e9d90e..5422068ca 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go @@ -315,6 +315,7 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (reco if err = setPhaseConditionForPVCProvisioningDisk(ctx, dv, vd, pvc, sc, cb, ds.diskService); err != nil { return reconcile.Result{}, err } + return reconcile.Result{}, nil } diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go index c0c9f4a53..931296f5c 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go @@ -228,6 +228,7 @@ func (ds ObjectRefClusterVirtualImage) Sync(ctx context.Context, vd *virtv2.Virt if err = setPhaseConditionForPVCProvisioningDisk(ctx, dv, vd, pvc, sc, cb, ds.diskService); err != nil { return reconcile.Result{}, err } + return reconcile.Result{}, nil } diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go index 46c62aa79..dedb752a4 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go @@ -227,6 +227,7 @@ func (ds ObjectRefVirtualImageDVCR) Sync(ctx context.Context, vd *virtv2.Virtual if err = setPhaseConditionForPVCProvisioningDisk(ctx, dv, vd, pvc, sc, cb, ds.diskService); err != nil { return reconcile.Result{}, err } + return reconcile.Result{}, nil } From 59fbb6eb3e1820250c12217d1c65a1cb1dd68d21 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Fri, 27 Dec 2024 16:36:00 +0300 Subject: [PATCH 06/23] quouta exceeded for prime and scratch in dv cdi patch Signed-off-by: Valeriy Khorunzhin --- ...prime-and-scratch-pvc-quota-exceeded.patch | 244 ++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch diff --git a/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch b/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch new file mode 100644 index 000000000..c71521494 --- /dev/null +++ b/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch @@ -0,0 +1,244 @@ +diff --git a/pkg/controller/datavolume/controller-base.go b/pkg/controller/datavolume/controller-base.go +index acd09cb94..b26d6efb6 100644 +--- a/pkg/controller/datavolume/controller-base.go ++++ b/pkg/controller/datavolume/controller-base.go +@@ -55,6 +55,7 @@ import ( + cloneMetrics "kubevirt.io/containerized-data-importer/pkg/monitoring/metrics/cdi-cloner" + metrics "kubevirt.io/containerized-data-importer/pkg/monitoring/metrics/cdi-controller" + importMetrics "kubevirt.io/containerized-data-importer/pkg/monitoring/metrics/cdi-importer" ++ datavolume_patched "kubevirt.io/containerized-data-importer/pkg/patchesv" + "kubevirt.io/containerized-data-importer/pkg/token" + "kubevirt.io/containerized-data-importer/pkg/util" + ) +@@ -1035,6 +1036,24 @@ func (r *ReconcilerBase) updateConditions(dataVolume *cdiv1.DataVolume, pvc *cor + dataVolume.Status.Conditions = updateBoundCondition(dataVolume.Status.Conditions, pvc, message, reason) + dataVolume.Status.Conditions = UpdateReadyCondition(dataVolume.Status.Conditions, readyStatus, message, reason) + dataVolume.Status.Conditions = updateRunningCondition(dataVolume.Status.Conditions, anno) ++ pvcPrimeCreatedCondition := FindConditionByType(datavolume_patched.DataVolumePrimeConditionCreated, dataVolume.Status.Conditions) ++ if pvcPrimeCreatedCondition == nil { ++ dataVolume.Status.Conditions = append(dataVolume.Status.Conditions, cdiv1.DataVolumeCondition{ ++ Type: datavolume_patched.DataVolumePrimeConditionCreated, ++ Status: corev1.ConditionFalse, ++ Reason: "NotCreated", ++ Message: "", ++ }) ++ } ++ pvcScratchCreatedCondition := FindConditionByType(datavolume_patched.DataVolumeScratchConditionCreated, dataVolume.Status.Conditions) ++ if pvcScratchCreatedCondition == nil { ++ dataVolume.Status.Conditions = append(dataVolume.Status.Conditions, cdiv1.DataVolumeCondition{ ++ Type: datavolume_patched.DataVolumeScratchConditionCreated, ++ Status: corev1.ConditionFalse, ++ Reason: "NotCreated", ++ Message: "", ++ }) ++ } + } + + func (r *ReconcilerBase) emitConditionEvent(dataVolume *cdiv1.DataVolume, originalCond []cdiv1.DataVolumeCondition) { +diff --git a/pkg/controller/import-controller.go b/pkg/controller/import-controller.go +index 49f1ff898..4f7cfd2c6 100644 +--- a/pkg/controller/import-controller.go ++++ b/pkg/controller/import-controller.go +@@ -34,6 +34,7 @@ import ( + "kubevirt.io/containerized-data-importer/pkg/common" + cc "kubevirt.io/containerized-data-importer/pkg/controller/common" + featuregates "kubevirt.io/containerized-data-importer/pkg/feature-gates" ++ datavolume_patched "kubevirt.io/containerized-data-importer/pkg/patchesv" + "kubevirt.io/containerized-data-importer/pkg/util" + "kubevirt.io/containerized-data-importer/pkg/util/naming" + sdkapi "kubevirt.io/controller-lifecycle-operator-sdk/api" +@@ -753,8 +754,16 @@ func (r *ImportReconciler) createScratchPvcForPod(pvc *corev1.PersistentVolumeCl + // Scratch PVC doesn't exist yet, create it. Determine which storage class to use. + _, err = createScratchPersistentVolumeClaim(r.client, pvc, pod, scratchPVCName, storageClassName, r.installerLabels, r.recorder) + if err != nil { ++ reason := "ErrCreating" ++ if strings.Contains(err.Error(), "exceeded quota") { ++ reason = "ErrExceededQuota" ++ } ++ datavolume_patched.UpdateDVScratchCondition(r.client, pvc, corev1.ConditionFalse, fmt.Sprintf("Err creating scratch pvc: %q", err.Error()), reason) + return err + } ++ ++ datavolume_patched.UpdateDVScratchCondition(r.client, pvc, corev1.ConditionTrue, "", "ScratchConditionCreated") ++ + anno[cc.AnnBoundCondition] = "false" + anno[cc.AnnBoundConditionMessage] = "Creating scratch space" + anno[cc.AnnBoundConditionReason] = creatingScratch +diff --git a/pkg/controller/populators/populator-base.go b/pkg/controller/populators/populator-base.go +index 6c6fd8f8a..4043ff5eb 100644 +--- a/pkg/controller/populators/populator-base.go ++++ b/pkg/controller/populators/populator-base.go +@@ -18,7 +18,9 @@ package populators + + import ( + "context" ++ "fmt" + "reflect" ++ "strings" + + "github.com/go-logr/logr" + +@@ -40,6 +42,7 @@ import ( + "kubevirt.io/containerized-data-importer/pkg/common" + cc "kubevirt.io/containerized-data-importer/pkg/controller/common" + featuregates "kubevirt.io/containerized-data-importer/pkg/feature-gates" ++ datavolume_patched "kubevirt.io/containerized-data-importer/pkg/patchesv" + "kubevirt.io/containerized-data-importer/pkg/util" + ) + +@@ -182,6 +185,11 @@ func (r *ReconcilerBase) createPVCPrime(pvc *corev1.PersistentVolumeClaim, sourc + annotations[cc.AnnPodRetainAfterCompletion] = pvc.Annotations[cc.AnnPodRetainAfterCompletion] + } + ++ dvUid, ok := pvc.Annotations[cc.AnnCreatedForDataVolume] ++ if ok { ++ annotations[datavolume_patched.AnnPrimeForDataVolume] = dvUid ++ } ++ + // Assemble PVC' spec + pvcPrime := &corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ +@@ -213,9 +221,17 @@ func (r *ReconcilerBase) createPVCPrime(pvc *corev1.PersistentVolumeClaim, sourc + } + + if err := r.client.Create(context.TODO(), pvcPrime); err != nil { ++ reason := "ErrCreating" ++ if strings.Contains(err.Error(), "exceeded quota") { ++ reason = "ErrExceededQuota" ++ } ++ datavolume_patched.UpdateDVPrimeCondition(r.client, pvc, corev1.ConditionFalse, fmt.Sprintf("Err creating prime pvc: %q", err.Error()), reason) + return nil, err + } + r.recorder.Eventf(pvc, corev1.EventTypeNormal, createdPVCPrimeSuccessfully, messageCreatedPVCPrimeSuccessfully) ++ ++ datavolume_patched.UpdateDVPrimeCondition(r.client, pvc, corev1.ConditionTrue, "", "PrimeConditionCreated") ++ + return pvcPrime, nil + } + +diff --git a/pkg/controller/upload-controller.go b/pkg/controller/upload-controller.go +index 4c153257a..9c586ebda 100644 +--- a/pkg/controller/upload-controller.go ++++ b/pkg/controller/upload-controller.go +@@ -51,6 +51,7 @@ import ( + cc "kubevirt.io/containerized-data-importer/pkg/controller/common" + featuregates "kubevirt.io/containerized-data-importer/pkg/feature-gates" + "kubevirt.io/containerized-data-importer/pkg/operator" ++ datavolume_patched "kubevirt.io/containerized-data-importer/pkg/patchesv" + "kubevirt.io/containerized-data-importer/pkg/util" + "kubevirt.io/containerized-data-importer/pkg/util/cert/fetcher" + "kubevirt.io/containerized-data-importer/pkg/util/cert/generator" +@@ -473,8 +474,14 @@ func (r *UploadReconciler) getOrCreateScratchPvc(pvc *corev1.PersistentVolumeCla + // Scratch PVC doesn't exist yet, create it. + scratchPvc, err = createScratchPersistentVolumeClaim(r.client, pvc, pod, name, storageClassName, map[string]string{}, r.recorder) + if err != nil { ++ reason := "ErrCreating" ++ if strings.Contains(err.Error(), "exceeded quota") { ++ reason = "ErrExceededQuota" ++ } ++ datavolume_patched.UpdateDVScratchCondition(r.client, pvc, corev1.ConditionFalse, fmt.Sprintf("Err creating scratch pvc: %q", err.Error()), reason) + return nil, err + } ++ datavolume_patched.UpdateDVPrimeCondition(r.client, pvc, corev1.ConditionTrue, "", "PrimeConditionCreated") + } else { + if !metav1.IsControlledBy(scratchPvc, pod) { + return nil, errors.Errorf("%s scratch PVC not controlled by pod %s", scratchPvc.Name, pod.Name) +diff --git a/pkg/patchesv/patched_condition_type.go b/pkg/patchesv/patched_condition_type.go +new file mode 100644 +index 000000000..ec614eb93 +--- /dev/null ++++ b/pkg/patchesv/patched_condition_type.go +@@ -0,0 +1,93 @@ ++package datavolume_patched ++ ++import ( ++ "context" ++ ++ corev1 "k8s.io/api/core/v1" ++ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ++ cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" ++ "kubevirt.io/containerized-data-importer/pkg/controller/common" ++ "sigs.k8s.io/controller-runtime/pkg/client" ++) ++ ++const ( ++ DataVolumePrimeConditionCreated cdiv1.DataVolumeConditionType = "PrimePVCCreated" ++ DataVolumeScratchConditionCreated cdiv1.DataVolumeConditionType = "ScratchPVCCreated" ++ ++ AnnPrimeForDataVolume = common.AnnAPIGroup + "/primeForDataVolume" ++) ++ ++func FindConditionByType(conditionType cdiv1.DataVolumeConditionType, conditions []cdiv1.DataVolumeCondition) *cdiv1.DataVolumeCondition { ++ for i, condition := range conditions { ++ if condition.Type == conditionType { ++ return &conditions[i] ++ } ++ } ++ return nil ++} ++ ++func updateCondition(conditions []cdiv1.DataVolumeCondition, conditionType cdiv1.DataVolumeConditionType, status corev1.ConditionStatus, message, reason string) []cdiv1.DataVolumeCondition { ++ condition := FindConditionByType(conditionType, conditions) ++ if condition == nil { ++ conditions = append(conditions, cdiv1.DataVolumeCondition{ ++ Type: conditionType, ++ }) ++ condition = FindConditionByType(conditionType, conditions) ++ } ++ if condition.Status != status { ++ condition.LastTransitionTime = metav1.Now() ++ condition.Message = message ++ condition.Reason = reason ++ condition.LastHeartbeatTime = condition.LastTransitionTime ++ } else if condition.Message != message || condition.Reason != reason { ++ condition.Message = message ++ condition.Reason = reason ++ condition.LastHeartbeatTime = metav1.Now() ++ } ++ condition.Status = status ++ return conditions ++} ++ ++func getDVByPVC(clientObject client.Client, pvc *corev1.PersistentVolumeClaim, ann string) *cdiv1.DataVolume { ++ uid, ok := pvc.Annotations[ann] ++ if !ok { ++ return nil ++ } ++ ++ var dvList cdiv1.DataVolumeList ++ ++ err := clientObject.List(context.TODO(), &dvList, client.InNamespace(pvc.Namespace)) ++ if err != nil { ++ return nil ++ } ++ ++ if len(dvList.Items) > 0 { ++ for _, dv := range dvList.Items { ++ if string(dv.UID) == uid { ++ return &dv ++ } ++ } ++ } ++ ++ return nil ++} ++ ++func UpdateDVPrimeCondition(clientObject client.Client, pvc *corev1.PersistentVolumeClaim, status corev1.ConditionStatus, message, reason string) { ++ dv := getDVByPVC(clientObject, pvc, common.AnnCreatedForDataVolume) ++ if dv == nil { ++ return ++ } ++ ++ dv.Status.Conditions = updateCondition(dv.Status.Conditions, DataVolumePrimeConditionCreated, status, message, reason) ++ _ = clientObject.Status().Update(context.TODO(), dv) ++} ++ ++func UpdateDVScratchCondition(clientObject client.Client, pvc *corev1.PersistentVolumeClaim, status corev1.ConditionStatus, message, reason string) { ++ dv := getDVByPVC(clientObject, pvc, AnnPrimeForDataVolume) ++ if dv == nil { ++ return ++ } ++ ++ dv.Status.Conditions = updateCondition(dv.Status.Conditions, DataVolumeScratchConditionCreated, status, message, reason) ++ _ = clientObject.Status().Update(context.TODO(), dv) ++} From 2019aa9341cc996f846a2832f0b415f1fdaccfd3 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Sun, 29 Dec 2024 03:27:04 +0300 Subject: [PATCH 07/23] patch Signed-off-by: Valeriy Khorunzhin --- ...prime-and-scratch-pvc-quota-exceeded.patch | 49 ++++++++++++++++--- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch b/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch index c71521494..acf000d0c 100644 --- a/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch +++ b/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch @@ -36,7 +36,7 @@ index acd09cb94..b26d6efb6 100644 func (r *ReconcilerBase) emitConditionEvent(dataVolume *cdiv1.DataVolume, originalCond []cdiv1.DataVolumeCondition) { diff --git a/pkg/controller/import-controller.go b/pkg/controller/import-controller.go -index 49f1ff898..4f7cfd2c6 100644 +index 49f1ff898..8c5664fed 100644 --- a/pkg/controller/import-controller.go +++ b/pkg/controller/import-controller.go @@ -34,6 +34,7 @@ import ( @@ -47,7 +47,7 @@ index 49f1ff898..4f7cfd2c6 100644 "kubevirt.io/containerized-data-importer/pkg/util" "kubevirt.io/containerized-data-importer/pkg/util/naming" sdkapi "kubevirt.io/controller-lifecycle-operator-sdk/api" -@@ -753,8 +754,16 @@ func (r *ImportReconciler) createScratchPvcForPod(pvc *corev1.PersistentVolumeCl +@@ -753,12 +754,21 @@ func (r *ImportReconciler) createScratchPvcForPod(pvc *corev1.PersistentVolumeCl // Scratch PVC doesn't exist yet, create it. Determine which storage class to use. _, err = createScratchPersistentVolumeClaim(r.client, pvc, pod, scratchPVCName, storageClassName, r.installerLabels, r.recorder) if err != nil { @@ -59,13 +59,39 @@ index 49f1ff898..4f7cfd2c6 100644 return err } + -+ datavolume_patched.UpdateDVScratchCondition(r.client, pvc, corev1.ConditionTrue, "", "ScratchConditionCreated") ++ datavolume_patched.UpdateDVScratchCondition(r.client, pvc, corev1.ConditionTrue, "", "ScratchPVCCreated") + anno[cc.AnnBoundCondition] = "false" anno[cc.AnnBoundConditionMessage] = "Creating scratch space" anno[cc.AnnBoundConditionReason] = creatingScratch + } else { ++ datavolume_patched.UpdateDVScratchCondition(r.client, pvc, corev1.ConditionTrue, "", "ScratchPVCCreated") + if scratchPvc.DeletionTimestamp != nil { + // Delete the pod since we are in a deadlock situation now. The scratch PVC from the previous import is not gone + // yet but terminating, and the new pod is still being created and the scratch PVC now has a finalizer on it. +diff --git a/pkg/controller/populators/forklift-populator.go b/pkg/controller/populators/forklift-populator.go +index 9565ebb93..09d7e9135 100644 +--- a/pkg/controller/populators/forklift-populator.go ++++ b/pkg/controller/populators/forklift-populator.go +@@ -27,6 +27,7 @@ import ( + featuregates "kubevirt.io/containerized-data-importer/pkg/feature-gates" + openstackMetric "kubevirt.io/containerized-data-importer/pkg/monitoring/metrics/openstack-populator" + ovirtMetric "kubevirt.io/containerized-data-importer/pkg/monitoring/metrics/ovirt-populator" ++ datavolume_patched "kubevirt.io/containerized-data-importer/pkg/patchesv" + ) + + const ( +@@ -257,6 +258,8 @@ func (r *ForkliftPopulatorReconciler) reconcileCommon(pvc *corev1.PersistentVolu + r.recorder.Eventf(pvc, corev1.EventTypeWarning, errCreatingPVCPrime, err.Error()) + return nil, err + } ++ } else { ++ datavolume_patched.UpdateDVPrimeCondition(r.client, pvc, corev1.ConditionTrue, "", "PrimePVCCreated") + } + + return nil, nil diff --git a/pkg/controller/populators/populator-base.go b/pkg/controller/populators/populator-base.go -index 6c6fd8f8a..4043ff5eb 100644 +index 6c6fd8f8a..56037bccd 100644 --- a/pkg/controller/populators/populator-base.go +++ b/pkg/controller/populators/populator-base.go @@ -18,7 +18,9 @@ package populators @@ -111,13 +137,22 @@ index 6c6fd8f8a..4043ff5eb 100644 } r.recorder.Eventf(pvc, corev1.EventTypeNormal, createdPVCPrimeSuccessfully, messageCreatedPVCPrimeSuccessfully) + -+ datavolume_patched.UpdateDVPrimeCondition(r.client, pvc, corev1.ConditionTrue, "", "PrimeConditionCreated") ++ datavolume_patched.UpdateDVPrimeCondition(r.client, pvc, corev1.ConditionTrue, "", "PrimePVCCreated") + return pvcPrime, nil } +@@ -342,6 +358,8 @@ func (r *ReconcilerBase) reconcileCommon(pvc *corev1.PersistentVolumeClaim, popu + r.recorder.Eventf(pvc, corev1.EventTypeWarning, errCreatingPVCPrime, err.Error()) + return nil, err + } ++ } else { ++ datavolume_patched.UpdateDVPrimeCondition(r.client, pvc, corev1.ConditionTrue, "", "PrimePVCCreated") + } + + return nil, nil diff --git a/pkg/controller/upload-controller.go b/pkg/controller/upload-controller.go -index 4c153257a..9c586ebda 100644 +index 4c153257a..c3b9d38ee 100644 --- a/pkg/controller/upload-controller.go +++ b/pkg/controller/upload-controller.go @@ -51,6 +51,7 @@ import ( @@ -139,7 +174,7 @@ index 4c153257a..9c586ebda 100644 + datavolume_patched.UpdateDVScratchCondition(r.client, pvc, corev1.ConditionFalse, fmt.Sprintf("Err creating scratch pvc: %q", err.Error()), reason) return nil, err } -+ datavolume_patched.UpdateDVPrimeCondition(r.client, pvc, corev1.ConditionTrue, "", "PrimeConditionCreated") ++ datavolume_patched.UpdateDVScratchCondition(r.client, pvc, corev1.ConditionTrue, "", "ScratchPVCCreated") } else { if !metav1.IsControlledBy(scratchPvc, pod) { return nil, errors.Errorf("%s scratch PVC not controlled by pod %s", scratchPvc.Name, pod.Name) From 60a73b9201762d8c89268097945034bd1d5cd259 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Sun, 29 Dec 2024 09:34:52 +0300 Subject: [PATCH 08/23] use new conditions Signed-off-by: Valeriy Khorunzhin --- .../controller/vd/internal/source/sources.go | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go index 2850a0688..34d4f2e34 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go @@ -421,6 +421,8 @@ const ( DVBoundConditionType string = "Bound" DVRunningConditionType string = "Running" DVReadyConditionType string = "Ready" + DVPrimePVCCreatedType string = "PrimePVCCreated" + DVScratchPVCCreatedType string = "ScratchPVCCreated" DVErrExceededQuotaReason string = "ErrExceededQuota" ) @@ -444,6 +446,16 @@ func checkIfQuotaExceeded(dv *cdiv1.DataVolume) (bool, string) { return false, "" } + primeCreatedCondition, ok := getDVCondition(dv, DVPrimePVCCreatedType) + if !ok { + return false, "" + } + + scratchCreatedCondition, ok := getDVCondition(dv, DVScratchPVCCreatedType) + if !ok { + return false, "" + } + if boundCondition.Reason == DVErrExceededQuotaReason { return true, service.CapitalizeFirstLetter(boundCondition.Message) } @@ -456,6 +468,14 @@ func checkIfQuotaExceeded(dv *cdiv1.DataVolume) (bool, string) { return true, service.CapitalizeFirstLetter(runningCondition.Message) } + if primeCreatedCondition.Reason == DVErrExceededQuotaReason { + return true, service.CapitalizeFirstLetter(primeCreatedCondition.Message) + } + + if scratchCreatedCondition.Reason == DVErrExceededQuotaReason { + return true, service.CapitalizeFirstLetter(scratchCreatedCondition.Message) + } + return false, "" } From 3f7d6fefb6e81f173247594a26739ff518cc3d5a Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Thu, 9 Jan 2025 11:00:08 +0300 Subject: [PATCH 09/23] fix cdi patch Signed-off-by: Valeriy Khorunzhin --- ...prime-and-scratch-pvc-quota-exceeded.patch | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch b/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch index acf000d0c..90c2062fb 100644 --- a/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch +++ b/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch @@ -1,5 +1,5 @@ diff --git a/pkg/controller/datavolume/controller-base.go b/pkg/controller/datavolume/controller-base.go -index acd09cb94..b26d6efb6 100644 +index acd09cb94..0751de9c3 100644 --- a/pkg/controller/datavolume/controller-base.go +++ b/pkg/controller/datavolume/controller-base.go @@ -55,6 +55,7 @@ import ( @@ -10,7 +10,7 @@ index acd09cb94..b26d6efb6 100644 "kubevirt.io/containerized-data-importer/pkg/token" "kubevirt.io/containerized-data-importer/pkg/util" ) -@@ -1035,6 +1036,24 @@ func (r *ReconcilerBase) updateConditions(dataVolume *cdiv1.DataVolume, pvc *cor +@@ -1035,6 +1036,31 @@ func (r *ReconcilerBase) updateConditions(dataVolume *cdiv1.DataVolume, pvc *cor dataVolume.Status.Conditions = updateBoundCondition(dataVolume.Status.Conditions, pvc, message, reason) dataVolume.Status.Conditions = UpdateReadyCondition(dataVolume.Status.Conditions, readyStatus, message, reason) dataVolume.Status.Conditions = updateRunningCondition(dataVolume.Status.Conditions, anno) @@ -31,6 +31,13 @@ index acd09cb94..b26d6efb6 100644 + Reason: "NotCreated", + Message: "", + }) ++ } ++ ++ runningCondition := FindConditionByType(cdiv1.DataVolumeRunning, dataVolume.Status.Conditions) ++ ++ if runningCondition != nil && runningCondition.Status == corev1.ConditionTrue { ++ datavolume_patched.UpdateCondition(dataVolume.Status.Conditions, datavolume_patched.DataVolumePrimeConditionCreated, corev1.ConditionTrue, "", "PrimePVCCreated") ++ datavolume_patched.UpdateCondition(dataVolume.Status.Conditions, datavolume_patched.DataVolumeScratchConditionCreated, corev1.ConditionTrue, "", "ScratchPVCCreated") + } } @@ -180,7 +187,7 @@ index 4c153257a..c3b9d38ee 100644 return nil, errors.Errorf("%s scratch PVC not controlled by pod %s", scratchPvc.Name, pod.Name) diff --git a/pkg/patchesv/patched_condition_type.go b/pkg/patchesv/patched_condition_type.go new file mode 100644 -index 000000000..ec614eb93 +index 000000000..58642e568 --- /dev/null +++ b/pkg/patchesv/patched_condition_type.go @@ -0,0 +1,93 @@ @@ -212,7 +219,7 @@ index 000000000..ec614eb93 + return nil +} + -+func updateCondition(conditions []cdiv1.DataVolumeCondition, conditionType cdiv1.DataVolumeConditionType, status corev1.ConditionStatus, message, reason string) []cdiv1.DataVolumeCondition { ++func UpdateCondition(conditions []cdiv1.DataVolumeCondition, conditionType cdiv1.DataVolumeConditionType, status corev1.ConditionStatus, message, reason string) []cdiv1.DataVolumeCondition { + condition := FindConditionByType(conditionType, conditions) + if condition == nil { + conditions = append(conditions, cdiv1.DataVolumeCondition{ @@ -264,7 +271,7 @@ index 000000000..ec614eb93 + return + } + -+ dv.Status.Conditions = updateCondition(dv.Status.Conditions, DataVolumePrimeConditionCreated, status, message, reason) ++ dv.Status.Conditions = UpdateCondition(dv.Status.Conditions, DataVolumePrimeConditionCreated, status, message, reason) + _ = clientObject.Status().Update(context.TODO(), dv) +} + @@ -274,6 +281,6 @@ index 000000000..ec614eb93 + return + } + -+ dv.Status.Conditions = updateCondition(dv.Status.Conditions, DataVolumeScratchConditionCreated, status, message, reason) ++ dv.Status.Conditions = UpdateCondition(dv.Status.Conditions, DataVolumeScratchConditionCreated, status, message, reason) + _ = clientObject.Status().Update(context.TODO(), dv) +} From 502a25a7a7c86f52e8c6d6c05d96f3378fad86b8 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Fri, 10 Jan 2025 17:13:39 +0300 Subject: [PATCH 10/23] patch Signed-off-by: Valeriy Khorunzhin --- ...prime-and-scratch-pvc-quota-exceeded.patch | 286 ------------------ 1 file changed, 286 deletions(-) diff --git a/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch b/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch index 90c2062fb..e69de29bb 100644 --- a/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch +++ b/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch @@ -1,286 +0,0 @@ -diff --git a/pkg/controller/datavolume/controller-base.go b/pkg/controller/datavolume/controller-base.go -index acd09cb94..0751de9c3 100644 ---- a/pkg/controller/datavolume/controller-base.go -+++ b/pkg/controller/datavolume/controller-base.go -@@ -55,6 +55,7 @@ import ( - cloneMetrics "kubevirt.io/containerized-data-importer/pkg/monitoring/metrics/cdi-cloner" - metrics "kubevirt.io/containerized-data-importer/pkg/monitoring/metrics/cdi-controller" - importMetrics "kubevirt.io/containerized-data-importer/pkg/monitoring/metrics/cdi-importer" -+ datavolume_patched "kubevirt.io/containerized-data-importer/pkg/patchesv" - "kubevirt.io/containerized-data-importer/pkg/token" - "kubevirt.io/containerized-data-importer/pkg/util" - ) -@@ -1035,6 +1036,31 @@ func (r *ReconcilerBase) updateConditions(dataVolume *cdiv1.DataVolume, pvc *cor - dataVolume.Status.Conditions = updateBoundCondition(dataVolume.Status.Conditions, pvc, message, reason) - dataVolume.Status.Conditions = UpdateReadyCondition(dataVolume.Status.Conditions, readyStatus, message, reason) - dataVolume.Status.Conditions = updateRunningCondition(dataVolume.Status.Conditions, anno) -+ pvcPrimeCreatedCondition := FindConditionByType(datavolume_patched.DataVolumePrimeConditionCreated, dataVolume.Status.Conditions) -+ if pvcPrimeCreatedCondition == nil { -+ dataVolume.Status.Conditions = append(dataVolume.Status.Conditions, cdiv1.DataVolumeCondition{ -+ Type: datavolume_patched.DataVolumePrimeConditionCreated, -+ Status: corev1.ConditionFalse, -+ Reason: "NotCreated", -+ Message: "", -+ }) -+ } -+ pvcScratchCreatedCondition := FindConditionByType(datavolume_patched.DataVolumeScratchConditionCreated, dataVolume.Status.Conditions) -+ if pvcScratchCreatedCondition == nil { -+ dataVolume.Status.Conditions = append(dataVolume.Status.Conditions, cdiv1.DataVolumeCondition{ -+ Type: datavolume_patched.DataVolumeScratchConditionCreated, -+ Status: corev1.ConditionFalse, -+ Reason: "NotCreated", -+ Message: "", -+ }) -+ } -+ -+ runningCondition := FindConditionByType(cdiv1.DataVolumeRunning, dataVolume.Status.Conditions) -+ -+ if runningCondition != nil && runningCondition.Status == corev1.ConditionTrue { -+ datavolume_patched.UpdateCondition(dataVolume.Status.Conditions, datavolume_patched.DataVolumePrimeConditionCreated, corev1.ConditionTrue, "", "PrimePVCCreated") -+ datavolume_patched.UpdateCondition(dataVolume.Status.Conditions, datavolume_patched.DataVolumeScratchConditionCreated, corev1.ConditionTrue, "", "ScratchPVCCreated") -+ } - } - - func (r *ReconcilerBase) emitConditionEvent(dataVolume *cdiv1.DataVolume, originalCond []cdiv1.DataVolumeCondition) { -diff --git a/pkg/controller/import-controller.go b/pkg/controller/import-controller.go -index 49f1ff898..8c5664fed 100644 ---- a/pkg/controller/import-controller.go -+++ b/pkg/controller/import-controller.go -@@ -34,6 +34,7 @@ import ( - "kubevirt.io/containerized-data-importer/pkg/common" - cc "kubevirt.io/containerized-data-importer/pkg/controller/common" - featuregates "kubevirt.io/containerized-data-importer/pkg/feature-gates" -+ datavolume_patched "kubevirt.io/containerized-data-importer/pkg/patchesv" - "kubevirt.io/containerized-data-importer/pkg/util" - "kubevirt.io/containerized-data-importer/pkg/util/naming" - sdkapi "kubevirt.io/controller-lifecycle-operator-sdk/api" -@@ -753,12 +754,21 @@ func (r *ImportReconciler) createScratchPvcForPod(pvc *corev1.PersistentVolumeCl - // Scratch PVC doesn't exist yet, create it. Determine which storage class to use. - _, err = createScratchPersistentVolumeClaim(r.client, pvc, pod, scratchPVCName, storageClassName, r.installerLabels, r.recorder) - if err != nil { -+ reason := "ErrCreating" -+ if strings.Contains(err.Error(), "exceeded quota") { -+ reason = "ErrExceededQuota" -+ } -+ datavolume_patched.UpdateDVScratchCondition(r.client, pvc, corev1.ConditionFalse, fmt.Sprintf("Err creating scratch pvc: %q", err.Error()), reason) - return err - } -+ -+ datavolume_patched.UpdateDVScratchCondition(r.client, pvc, corev1.ConditionTrue, "", "ScratchPVCCreated") -+ - anno[cc.AnnBoundCondition] = "false" - anno[cc.AnnBoundConditionMessage] = "Creating scratch space" - anno[cc.AnnBoundConditionReason] = creatingScratch - } else { -+ datavolume_patched.UpdateDVScratchCondition(r.client, pvc, corev1.ConditionTrue, "", "ScratchPVCCreated") - if scratchPvc.DeletionTimestamp != nil { - // Delete the pod since we are in a deadlock situation now. The scratch PVC from the previous import is not gone - // yet but terminating, and the new pod is still being created and the scratch PVC now has a finalizer on it. -diff --git a/pkg/controller/populators/forklift-populator.go b/pkg/controller/populators/forklift-populator.go -index 9565ebb93..09d7e9135 100644 ---- a/pkg/controller/populators/forklift-populator.go -+++ b/pkg/controller/populators/forklift-populator.go -@@ -27,6 +27,7 @@ import ( - featuregates "kubevirt.io/containerized-data-importer/pkg/feature-gates" - openstackMetric "kubevirt.io/containerized-data-importer/pkg/monitoring/metrics/openstack-populator" - ovirtMetric "kubevirt.io/containerized-data-importer/pkg/monitoring/metrics/ovirt-populator" -+ datavolume_patched "kubevirt.io/containerized-data-importer/pkg/patchesv" - ) - - const ( -@@ -257,6 +258,8 @@ func (r *ForkliftPopulatorReconciler) reconcileCommon(pvc *corev1.PersistentVolu - r.recorder.Eventf(pvc, corev1.EventTypeWarning, errCreatingPVCPrime, err.Error()) - return nil, err - } -+ } else { -+ datavolume_patched.UpdateDVPrimeCondition(r.client, pvc, corev1.ConditionTrue, "", "PrimePVCCreated") - } - - return nil, nil -diff --git a/pkg/controller/populators/populator-base.go b/pkg/controller/populators/populator-base.go -index 6c6fd8f8a..56037bccd 100644 ---- a/pkg/controller/populators/populator-base.go -+++ b/pkg/controller/populators/populator-base.go -@@ -18,7 +18,9 @@ package populators - - import ( - "context" -+ "fmt" - "reflect" -+ "strings" - - "github.com/go-logr/logr" - -@@ -40,6 +42,7 @@ import ( - "kubevirt.io/containerized-data-importer/pkg/common" - cc "kubevirt.io/containerized-data-importer/pkg/controller/common" - featuregates "kubevirt.io/containerized-data-importer/pkg/feature-gates" -+ datavolume_patched "kubevirt.io/containerized-data-importer/pkg/patchesv" - "kubevirt.io/containerized-data-importer/pkg/util" - ) - -@@ -182,6 +185,11 @@ func (r *ReconcilerBase) createPVCPrime(pvc *corev1.PersistentVolumeClaim, sourc - annotations[cc.AnnPodRetainAfterCompletion] = pvc.Annotations[cc.AnnPodRetainAfterCompletion] - } - -+ dvUid, ok := pvc.Annotations[cc.AnnCreatedForDataVolume] -+ if ok { -+ annotations[datavolume_patched.AnnPrimeForDataVolume] = dvUid -+ } -+ - // Assemble PVC' spec - pvcPrime := &corev1.PersistentVolumeClaim{ - ObjectMeta: metav1.ObjectMeta{ -@@ -213,9 +221,17 @@ func (r *ReconcilerBase) createPVCPrime(pvc *corev1.PersistentVolumeClaim, sourc - } - - if err := r.client.Create(context.TODO(), pvcPrime); err != nil { -+ reason := "ErrCreating" -+ if strings.Contains(err.Error(), "exceeded quota") { -+ reason = "ErrExceededQuota" -+ } -+ datavolume_patched.UpdateDVPrimeCondition(r.client, pvc, corev1.ConditionFalse, fmt.Sprintf("Err creating prime pvc: %q", err.Error()), reason) - return nil, err - } - r.recorder.Eventf(pvc, corev1.EventTypeNormal, createdPVCPrimeSuccessfully, messageCreatedPVCPrimeSuccessfully) -+ -+ datavolume_patched.UpdateDVPrimeCondition(r.client, pvc, corev1.ConditionTrue, "", "PrimePVCCreated") -+ - return pvcPrime, nil - } - -@@ -342,6 +358,8 @@ func (r *ReconcilerBase) reconcileCommon(pvc *corev1.PersistentVolumeClaim, popu - r.recorder.Eventf(pvc, corev1.EventTypeWarning, errCreatingPVCPrime, err.Error()) - return nil, err - } -+ } else { -+ datavolume_patched.UpdateDVPrimeCondition(r.client, pvc, corev1.ConditionTrue, "", "PrimePVCCreated") - } - - return nil, nil -diff --git a/pkg/controller/upload-controller.go b/pkg/controller/upload-controller.go -index 4c153257a..c3b9d38ee 100644 ---- a/pkg/controller/upload-controller.go -+++ b/pkg/controller/upload-controller.go -@@ -51,6 +51,7 @@ import ( - cc "kubevirt.io/containerized-data-importer/pkg/controller/common" - featuregates "kubevirt.io/containerized-data-importer/pkg/feature-gates" - "kubevirt.io/containerized-data-importer/pkg/operator" -+ datavolume_patched "kubevirt.io/containerized-data-importer/pkg/patchesv" - "kubevirt.io/containerized-data-importer/pkg/util" - "kubevirt.io/containerized-data-importer/pkg/util/cert/fetcher" - "kubevirt.io/containerized-data-importer/pkg/util/cert/generator" -@@ -473,8 +474,14 @@ func (r *UploadReconciler) getOrCreateScratchPvc(pvc *corev1.PersistentVolumeCla - // Scratch PVC doesn't exist yet, create it. - scratchPvc, err = createScratchPersistentVolumeClaim(r.client, pvc, pod, name, storageClassName, map[string]string{}, r.recorder) - if err != nil { -+ reason := "ErrCreating" -+ if strings.Contains(err.Error(), "exceeded quota") { -+ reason = "ErrExceededQuota" -+ } -+ datavolume_patched.UpdateDVScratchCondition(r.client, pvc, corev1.ConditionFalse, fmt.Sprintf("Err creating scratch pvc: %q", err.Error()), reason) - return nil, err - } -+ datavolume_patched.UpdateDVScratchCondition(r.client, pvc, corev1.ConditionTrue, "", "ScratchPVCCreated") - } else { - if !metav1.IsControlledBy(scratchPvc, pod) { - return nil, errors.Errorf("%s scratch PVC not controlled by pod %s", scratchPvc.Name, pod.Name) -diff --git a/pkg/patchesv/patched_condition_type.go b/pkg/patchesv/patched_condition_type.go -new file mode 100644 -index 000000000..58642e568 ---- /dev/null -+++ b/pkg/patchesv/patched_condition_type.go -@@ -0,0 +1,93 @@ -+package datavolume_patched -+ -+import ( -+ "context" -+ -+ corev1 "k8s.io/api/core/v1" -+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -+ cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" -+ "kubevirt.io/containerized-data-importer/pkg/controller/common" -+ "sigs.k8s.io/controller-runtime/pkg/client" -+) -+ -+const ( -+ DataVolumePrimeConditionCreated cdiv1.DataVolumeConditionType = "PrimePVCCreated" -+ DataVolumeScratchConditionCreated cdiv1.DataVolumeConditionType = "ScratchPVCCreated" -+ -+ AnnPrimeForDataVolume = common.AnnAPIGroup + "/primeForDataVolume" -+) -+ -+func FindConditionByType(conditionType cdiv1.DataVolumeConditionType, conditions []cdiv1.DataVolumeCondition) *cdiv1.DataVolumeCondition { -+ for i, condition := range conditions { -+ if condition.Type == conditionType { -+ return &conditions[i] -+ } -+ } -+ return nil -+} -+ -+func UpdateCondition(conditions []cdiv1.DataVolumeCondition, conditionType cdiv1.DataVolumeConditionType, status corev1.ConditionStatus, message, reason string) []cdiv1.DataVolumeCondition { -+ condition := FindConditionByType(conditionType, conditions) -+ if condition == nil { -+ conditions = append(conditions, cdiv1.DataVolumeCondition{ -+ Type: conditionType, -+ }) -+ condition = FindConditionByType(conditionType, conditions) -+ } -+ if condition.Status != status { -+ condition.LastTransitionTime = metav1.Now() -+ condition.Message = message -+ condition.Reason = reason -+ condition.LastHeartbeatTime = condition.LastTransitionTime -+ } else if condition.Message != message || condition.Reason != reason { -+ condition.Message = message -+ condition.Reason = reason -+ condition.LastHeartbeatTime = metav1.Now() -+ } -+ condition.Status = status -+ return conditions -+} -+ -+func getDVByPVC(clientObject client.Client, pvc *corev1.PersistentVolumeClaim, ann string) *cdiv1.DataVolume { -+ uid, ok := pvc.Annotations[ann] -+ if !ok { -+ return nil -+ } -+ -+ var dvList cdiv1.DataVolumeList -+ -+ err := clientObject.List(context.TODO(), &dvList, client.InNamespace(pvc.Namespace)) -+ if err != nil { -+ return nil -+ } -+ -+ if len(dvList.Items) > 0 { -+ for _, dv := range dvList.Items { -+ if string(dv.UID) == uid { -+ return &dv -+ } -+ } -+ } -+ -+ return nil -+} -+ -+func UpdateDVPrimeCondition(clientObject client.Client, pvc *corev1.PersistentVolumeClaim, status corev1.ConditionStatus, message, reason string) { -+ dv := getDVByPVC(clientObject, pvc, common.AnnCreatedForDataVolume) -+ if dv == nil { -+ return -+ } -+ -+ dv.Status.Conditions = UpdateCondition(dv.Status.Conditions, DataVolumePrimeConditionCreated, status, message, reason) -+ _ = clientObject.Status().Update(context.TODO(), dv) -+} -+ -+func UpdateDVScratchCondition(clientObject client.Client, pvc *corev1.PersistentVolumeClaim, status corev1.ConditionStatus, message, reason string) { -+ dv := getDVByPVC(clientObject, pvc, AnnPrimeForDataVolume) -+ if dv == nil { -+ return -+ } -+ -+ dv.Status.Conditions = UpdateCondition(dv.Status.Conditions, DataVolumeScratchConditionCreated, status, message, reason) -+ _ = clientObject.Status().Update(context.TODO(), dv) -+} From 7d9d63e012b9f031f597d6b5eedd94e4fc925750 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Fri, 10 Jan 2025 17:49:17 +0300 Subject: [PATCH 11/23] fix cdi patch Signed-off-by: Valeriy Khorunzhin --- ...prime-and-scratch-pvc-quota-exceeded.patch | 234 ++++++++++++++++++ 1 file changed, 234 insertions(+) diff --git a/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch b/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch index e69de29bb..ed34e8319 100644 --- a/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch +++ b/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch @@ -0,0 +1,234 @@ +diff --git a/pkg/controller/datavolume/controller-base.go b/pkg/controller/datavolume/controller-base.go +index acd09cb94..b856d5e38 100644 +--- a/pkg/controller/datavolume/controller-base.go ++++ b/pkg/controller/datavolume/controller-base.go +@@ -55,6 +55,7 @@ import ( + cloneMetrics "kubevirt.io/containerized-data-importer/pkg/monitoring/metrics/cdi-cloner" + metrics "kubevirt.io/containerized-data-importer/pkg/monitoring/metrics/cdi-controller" + importMetrics "kubevirt.io/containerized-data-importer/pkg/monitoring/metrics/cdi-importer" ++ patchedDV "kubevirt.io/containerized-data-importer/pkg/patcheddatavolume" + "kubevirt.io/containerized-data-importer/pkg/token" + "kubevirt.io/containerized-data-importer/pkg/util" + ) +@@ -1035,6 +1036,24 @@ func (r *ReconcilerBase) updateConditions(dataVolume *cdiv1.DataVolume, pvc *cor + dataVolume.Status.Conditions = updateBoundCondition(dataVolume.Status.Conditions, pvc, message, reason) + dataVolume.Status.Conditions = UpdateReadyCondition(dataVolume.Status.Conditions, readyStatus, message, reason) + dataVolume.Status.Conditions = updateRunningCondition(dataVolume.Status.Conditions, anno) ++ patchedDV.CreateDVQuotaIsNotExceededConditionIfNotExists(&dataVolume.Status.Conditions) ++ ++ readyCondition := FindConditionByType(cdiv1.DataVolumeReady, dataVolume.Status.Conditions) ++ boundCondition := FindConditionByType(cdiv1.DataVolumeBound, dataVolume.Status.Conditions) ++ runningCondition := FindConditionByType(cdiv1.DataVolumeRunning, dataVolume.Status.Conditions) ++ ++ switch { ++ case readyCondition != nil && readyCondition.Reason == cc.ErrExceededQuota: ++ dataVolume.Status.Conditions = patchedDV.UpdateDVQuotaNotExceededCondition(dataVolume.Status.Conditions, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", readyCondition.Message), patchedDV.QuotaExceededReason) ++ case boundCondition != nil && boundCondition.Reason == cc.ErrExceededQuota: ++ dataVolume.Status.Conditions = patchedDV.UpdateDVQuotaNotExceededCondition(dataVolume.Status.Conditions, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", readyCondition.Message), patchedDV.QuotaExceededReason) ++ case runningCondition != nil: ++ if runningCondition.Reason == cc.ErrExceededQuota { ++ dataVolume.Status.Conditions = patchedDV.UpdateDVQuotaNotExceededCondition(dataVolume.Status.Conditions, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", readyCondition.Message), patchedDV.QuotaExceededReason) ++ } else if runningCondition.Status == corev1.ConditionTrue { ++ dataVolume.Status.Conditions = patchedDV.UpdateDVQuotaNotExceededCondition(dataVolume.Status.Conditions, corev1.ConditionTrue, "", patchedDV.QuotaNotExceededReason) ++ } ++ } + } + + func (r *ReconcilerBase) emitConditionEvent(dataVolume *cdiv1.DataVolume, originalCond []cdiv1.DataVolumeCondition) { +diff --git a/pkg/controller/import-controller.go b/pkg/controller/import-controller.go +index 49f1ff898..4ce5c085e 100644 +--- a/pkg/controller/import-controller.go ++++ b/pkg/controller/import-controller.go +@@ -34,6 +34,7 @@ import ( + "kubevirt.io/containerized-data-importer/pkg/common" + cc "kubevirt.io/containerized-data-importer/pkg/controller/common" + featuregates "kubevirt.io/containerized-data-importer/pkg/feature-gates" ++ patchedDV "kubevirt.io/containerized-data-importer/pkg/patcheddatavolume" + "kubevirt.io/containerized-data-importer/pkg/util" + "kubevirt.io/containerized-data-importer/pkg/util/naming" + sdkapi "kubevirt.io/controller-lifecycle-operator-sdk/api" +@@ -753,6 +754,9 @@ func (r *ImportReconciler) createScratchPvcForPod(pvc *corev1.PersistentVolumeCl + // Scratch PVC doesn't exist yet, create it. Determine which storage class to use. + _, err = createScratchPersistentVolumeClaim(r.client, pvc, pod, scratchPVCName, storageClassName, r.installerLabels, r.recorder) + if err != nil { ++ if strings.Contains(err.Error(), "exceeded quota") { ++ patchedDV.UpdateDVQuotaNotExceededConditionByPVC(r.client, pvc, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", err.Error()), patchedDV.QuotaExceededReason) ++ } + return err + } + anno[cc.AnnBoundCondition] = "false" +diff --git a/pkg/controller/populators/populator-base.go b/pkg/controller/populators/populator-base.go +index 6c6fd8f8a..9df58c3fd 100644 +--- a/pkg/controller/populators/populator-base.go ++++ b/pkg/controller/populators/populator-base.go +@@ -18,7 +18,9 @@ package populators + + import ( + "context" ++ "fmt" + "reflect" ++ "strings" + + "github.com/go-logr/logr" + +@@ -40,6 +42,7 @@ import ( + "kubevirt.io/containerized-data-importer/pkg/common" + cc "kubevirt.io/containerized-data-importer/pkg/controller/common" + featuregates "kubevirt.io/containerized-data-importer/pkg/feature-gates" ++ patchedDV "kubevirt.io/containerized-data-importer/pkg/patcheddatavolume" + "kubevirt.io/containerized-data-importer/pkg/util" + ) + +@@ -182,6 +185,11 @@ func (r *ReconcilerBase) createPVCPrime(pvc *corev1.PersistentVolumeClaim, sourc + annotations[cc.AnnPodRetainAfterCompletion] = pvc.Annotations[cc.AnnPodRetainAfterCompletion] + } + ++ dvUid, ok := pvc.Annotations[cc.AnnCreatedForDataVolume] ++ if ok { ++ annotations[cc.AnnCreatedForDataVolume] = dvUid ++ } ++ + // Assemble PVC' spec + pvcPrime := &corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ +@@ -213,6 +221,9 @@ func (r *ReconcilerBase) createPVCPrime(pvc *corev1.PersistentVolumeClaim, sourc + } + + if err := r.client.Create(context.TODO(), pvcPrime); err != nil { ++ if strings.Contains(err.Error(), "exceeded quota") { ++ patchedDV.UpdateDVQuotaNotExceededConditionByPVC(r.client, pvc, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", err.Error()), patchedDV.QuotaExceededReason) ++ } + return nil, err + } + r.recorder.Eventf(pvc, corev1.EventTypeNormal, createdPVCPrimeSuccessfully, messageCreatedPVCPrimeSuccessfully) +diff --git a/pkg/controller/upload-controller.go b/pkg/controller/upload-controller.go +index 4c153257a..aaf4f8198 100644 +--- a/pkg/controller/upload-controller.go ++++ b/pkg/controller/upload-controller.go +@@ -51,6 +51,7 @@ import ( + cc "kubevirt.io/containerized-data-importer/pkg/controller/common" + featuregates "kubevirt.io/containerized-data-importer/pkg/feature-gates" + "kubevirt.io/containerized-data-importer/pkg/operator" ++ patchedDV "kubevirt.io/containerized-data-importer/pkg/patcheddatavolume" + "kubevirt.io/containerized-data-importer/pkg/util" + "kubevirt.io/containerized-data-importer/pkg/util/cert/fetcher" + "kubevirt.io/containerized-data-importer/pkg/util/cert/generator" +@@ -473,6 +474,9 @@ func (r *UploadReconciler) getOrCreateScratchPvc(pvc *corev1.PersistentVolumeCla + // Scratch PVC doesn't exist yet, create it. + scratchPvc, err = createScratchPersistentVolumeClaim(r.client, pvc, pod, name, storageClassName, map[string]string{}, r.recorder) + if err != nil { ++ if strings.Contains(err.Error(), "exceeded quota") { ++ patchedDV.UpdateDVQuotaNotExceededConditionByPVC(r.client, pvc, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", err.Error()), patchedDV.QuotaExceededReason) ++ } + return nil, err + } + } else { +diff --git a/pkg/patcheddatavolume/patched_datavolume.go b/pkg/patcheddatavolume/patched_datavolume.go +new file mode 100644 +index 000000000..3f0b5e605 +--- /dev/null ++++ b/pkg/patcheddatavolume/patched_datavolume.go +@@ -0,0 +1,103 @@ ++package patcheddatavolume ++ ++import ( ++ "context" ++ ++ corev1 "k8s.io/api/core/v1" ++ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ++ cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" ++ "kubevirt.io/containerized-data-importer/pkg/controller/common" ++ "sigs.k8s.io/controller-runtime/pkg/client" ++) ++ ++const ( ++ QoutaNotExceededConditionType cdiv1.DataVolumeConditionType = "QuotaNotExceeded" ++ ++ QuotaNotExceededReason string = "QuotaNotExceeded" ++ QuotaExceededReason string = "QuotaExceeded" ++) ++ ++func FindConditionByType(conditionType cdiv1.DataVolumeConditionType, conditions []cdiv1.DataVolumeCondition) *cdiv1.DataVolumeCondition { ++ for i, condition := range conditions { ++ if condition.Type == conditionType { ++ return &conditions[i] ++ } ++ } ++ return nil ++} ++ ++func updateCondition(conditions []cdiv1.DataVolumeCondition, conditionType cdiv1.DataVolumeConditionType, status corev1.ConditionStatus, message, reason string) []cdiv1.DataVolumeCondition { ++ condition := FindConditionByType(conditionType, conditions) ++ if condition == nil { ++ conditions = append(conditions, cdiv1.DataVolumeCondition{ ++ Type: conditionType, ++ }) ++ condition = FindConditionByType(conditionType, conditions) ++ } ++ if condition.Status != status { ++ condition.LastTransitionTime = metav1.Now() ++ condition.Message = message ++ condition.Reason = reason ++ condition.LastHeartbeatTime = condition.LastTransitionTime ++ } else if condition.Message != message || condition.Reason != reason { ++ condition.Message = message ++ condition.Reason = reason ++ condition.LastHeartbeatTime = metav1.Now() ++ } ++ condition.Status = status ++ return conditions ++} ++ ++func getDVByPVC(clientObject client.Client, pvc *corev1.PersistentVolumeClaim, ann string) *cdiv1.DataVolume { ++ uid, ok := pvc.Annotations[ann] ++ if !ok { ++ return nil ++ } ++ ++ var dvList cdiv1.DataVolumeList ++ ++ err := clientObject.List(context.TODO(), &dvList, client.InNamespace(pvc.Namespace)) ++ if err != nil { ++ return nil ++ } ++ ++ if len(dvList.Items) > 0 { ++ for _, dv := range dvList.Items { ++ if string(dv.UID) == uid { ++ return &dv ++ } ++ } ++ } ++ ++ return nil ++} ++ ++func UpdateDVQuotaNotExceededCondition(conditions []cdiv1.DataVolumeCondition, status corev1.ConditionStatus, message, reason string) []cdiv1.DataVolumeCondition { ++ return updateCondition(conditions, QoutaNotExceededConditionType, status, message, reason) ++} ++ ++func UpdateDVQuotaNotExceededConditionByPVC(clientObject client.Client, pvc *corev1.PersistentVolumeClaim, status corev1.ConditionStatus, message, reason string) { ++ dv := getDVByPVC(clientObject, pvc, common.AnnCreatedForDataVolume) ++ if dv == nil { ++ return ++ } ++ ++ dv.Status.Conditions = updateCondition(dv.Status.Conditions, QoutaNotExceededConditionType, status, message, reason) ++ _ = clientObject.Status().Update(context.TODO(), dv) ++} ++ ++func CreateDVQuotaIsNotExceededConditionIfNotExists(conditions *[]cdiv1.DataVolumeCondition) { ++ if conditions == nil { ++ return ++ } ++ ++ condition := FindConditionByType(QoutaNotExceededConditionType, *conditions) ++ if condition == nil { ++ *conditions = append(*conditions, cdiv1.DataVolumeCondition{ ++ Type: QoutaNotExceededConditionType, ++ Status: corev1.ConditionTrue, ++ Reason: QuotaNotExceededReason, ++ Message: "", ++ }) ++ } ++} From 6a05ec8967812dcf8a7dbe35f5047d643429e9af Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Fri, 10 Jan 2025 19:16:43 +0300 Subject: [PATCH 12/23] controller after new dv condition api Signed-off-by: Valeriy Khorunzhin --- .../controller/vd/internal/source/blank.go | 9 +- .../pkg/controller/vd/internal/source/http.go | 9 +- .../vd/internal/source/object_ref_cvi.go | 9 +- .../vd/internal/source/object_ref_vi_dvcr.go | 9 +- .../vd/internal/source/object_ref_vi_pvc.go | 9 +- .../controller/vd/internal/source/registry.go | 9 +- .../controller/vd/internal/source/sources.go | 84 +++++-------------- .../controller/vd/internal/source/upload.go | 9 +- 8 files changed, 62 insertions(+), 85 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go index b2d55aabf..fd3ac667b 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go @@ -84,7 +84,10 @@ func (ds BlankDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (rec return reconcile.Result{}, err } - quotaExceeded, quotaExceededMessage := checkIfQuotaExceeded(dv) + var quotaNotExceededCondition *metav1.Condition + if dv != nil { + quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) + } switch { case isDiskProvisioningFinished(condition): @@ -141,11 +144,11 @@ func (ds BlankDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (rec Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil - case quotaExceeded: + case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: cb. Status(metav1.ConditionFalse). Reason(vdcondition.QuotaExceeded). - Message(quotaExceededMessage) + Message(quotaNotExceededCondition.Message) return reconcile.Result{}, nil case pvc == nil: vd.Status.Phase = virtv2.DiskProvisioning diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go index 5422068ca..69b78fa1e 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go @@ -106,7 +106,10 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (reco return reconcile.Result{}, err } - quotaExceeded, quotaExceededMessage := checkIfQuotaExceeded(dv) + var quotaNotExceededCondition *metav1.Condition + if dv != nil { + quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) + } switch { case isDiskProvisioningFinished(condition): @@ -259,11 +262,11 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (reco Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil - case quotaExceeded: + case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: cb. Status(metav1.ConditionFalse). Reason(vdcondition.QuotaExceeded). - Message(quotaExceededMessage) + Message(quotaNotExceededCondition.Message) return reconcile.Result{}, nil case pvc == nil: vd.Status.Phase = virtv2.DiskProvisioning diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go index 931296f5c..1782011d4 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go @@ -103,7 +103,10 @@ func (ds ObjectRefClusterVirtualImage) Sync(ctx context.Context, vd *virtv2.Virt return reconcile.Result{}, err } - quotaExceeded, quotaExceededMessage := checkIfQuotaExceeded(dv) + var quotaNotExceededCondition *metav1.Condition + if dv != nil { + quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) + } switch { case isDiskProvisioningFinished(condition): @@ -174,11 +177,11 @@ func (ds ObjectRefClusterVirtualImage) Sync(ctx context.Context, vd *virtv2.Virt Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil - case quotaExceeded: + case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: cb. Status(metav1.ConditionFalse). Reason(vdcondition.QuotaExceeded). - Message(quotaExceededMessage) + Message(quotaNotExceededCondition.Message) return reconcile.Result{}, nil case pvc == nil: vd.Status.Phase = virtv2.DiskProvisioning diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go index dedb752a4..171ba151f 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go @@ -102,7 +102,10 @@ func (ds ObjectRefVirtualImageDVCR) Sync(ctx context.Context, vd *virtv2.Virtual return reconcile.Result{}, err } - quotaExceeded, quotaExceededMessage := checkIfQuotaExceeded(dv) + var quotaNotExceededCondition *metav1.Condition + if dv != nil { + quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) + } switch { case isDiskProvisioningFinished(condition): @@ -173,11 +176,11 @@ func (ds ObjectRefVirtualImageDVCR) Sync(ctx context.Context, vd *virtv2.Virtual Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil - case quotaExceeded: + case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: cb. Status(metav1.ConditionFalse). Reason(vdcondition.QuotaExceeded). - Message(quotaExceededMessage) + Message(quotaNotExceededCondition.Message) return reconcile.Result{}, nil case pvc == nil: vd.Status.Phase = virtv2.DiskProvisioning diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go index 3992ea5b4..f35bf8130 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go @@ -98,7 +98,10 @@ func (ds ObjectRefVirtualImagePVC) Sync(ctx context.Context, vd *virtv2.VirtualD return reconcile.Result{}, err } - quotaExceeded, quotaExceededMessage := checkIfQuotaExceeded(dv) + var quotaNotExceededCondition *metav1.Condition + if dv != nil { + quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) + } switch { case isDiskProvisioningFinished(condition): @@ -174,11 +177,11 @@ func (ds ObjectRefVirtualImagePVC) Sync(ctx context.Context, vd *virtv2.VirtualD Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil - case quotaExceeded: + case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: cb. Status(metav1.ConditionFalse). Reason(vdcondition.QuotaExceeded). - Message(quotaExceededMessage) + Message(quotaNotExceededCondition.Message) return reconcile.Result{}, nil case pvc == nil: vd.Status.Phase = virtv2.DiskProvisioning diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go index b171f3286..54a7fa28f 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go @@ -107,7 +107,10 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) ( return reconcile.Result{}, err } - quotaExceeded, quotaExceededMessage := checkIfQuotaExceeded(dv) + var quotaNotExceededCondition *metav1.Condition + if dv != nil { + quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) + } switch { case isDiskProvisioningFinished(condition): @@ -257,11 +260,11 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) ( Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil - case quotaExceeded: + case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: cb. Status(metav1.ConditionFalse). Reason(vdcondition.QuotaExceeded). - Message(quotaExceededMessage) + Message(quotaNotExceededCondition.Message) return reconcile.Result{}, nil case pvc == nil: vd.Status.Phase = virtv2.DiskProvisioning diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go index 34d4f2e34..1d6277bf7 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go @@ -418,73 +418,29 @@ func setPhaseConditionToFailed(cb *conditions.ConditionBuilder, phase *virtv2.Di } const ( - DVBoundConditionType string = "Bound" - DVRunningConditionType string = "Running" - DVReadyConditionType string = "Ready" - DVPrimePVCCreatedType string = "PrimePVCCreated" - DVScratchPVCCreatedType string = "ScratchPVCCreated" - DVErrExceededQuotaReason string = "ErrExceededQuota" + DVQoutaNotExceededConditionType string = "QuotaNotExceeded" ) -func checkIfQuotaExceeded(dv *cdiv1.DataVolume) (bool, string) { - if dv == nil { - return false, "" - } - - boundCondition, ok := getDVCondition(dv, DVBoundConditionType) - if !ok { - return false, "" - } - - readyDVCondition, ok := getDVCondition(dv, DVReadyConditionType) - if !ok { - return false, "" - } - - runningCondition, ok := getDVCondition(dv, DVRunningConditionType) - if !ok { - return false, "" - } - - primeCreatedCondition, ok := getDVCondition(dv, DVPrimePVCCreatedType) - if !ok { - return false, "" - } - - scratchCreatedCondition, ok := getDVCondition(dv, DVScratchPVCCreatedType) - if !ok { - return false, "" - } - - if boundCondition.Reason == DVErrExceededQuotaReason { - return true, service.CapitalizeFirstLetter(boundCondition.Message) - } - - if readyDVCondition.Reason == DVErrExceededQuotaReason { - return true, service.CapitalizeFirstLetter(readyDVCondition.Message) - } - - if runningCondition.Reason == DVErrExceededQuotaReason { - return true, service.CapitalizeFirstLetter(runningCondition.Message) - } - - if primeCreatedCondition.Reason == DVErrExceededQuotaReason { - return true, service.CapitalizeFirstLetter(primeCreatedCondition.Message) - } - - if scratchCreatedCondition.Reason == DVErrExceededQuotaReason { - return true, service.CapitalizeFirstLetter(scratchCreatedCondition.Message) - } - - return false, "" -} - -func getDVCondition(dv *cdiv1.DataVolume, conditionType string) (*cdiv1.DataVolumeCondition, bool) { - for _, cond := range dv.Status.Conditions { - if string(cond.Type) == conditionType { - return &cond, true +func getDVNotExceededCondition(conditions []cdiv1.DataVolumeCondition) *metav1.Condition { + for _, condition := range conditions { + if string(condition.Type) == DVQoutaNotExceededConditionType { + returned := &metav1.Condition{ + Type: DVQoutaNotExceededConditionType, + Reason: condition.Reason, + Message: condition.Message, + LastTransitionTime: condition.LastTransitionTime, + } + switch condition.Status { + case corev1.ConditionTrue: + returned.Status = metav1.ConditionTrue + case corev1.ConditionFalse: + returned.Status = metav1.ConditionFalse + case corev1.ConditionUnknown: + returned.Status = metav1.ConditionUnknown + } + return returned } } - return nil, false + return nil } diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go index 76bbf64ad..28e9c17a6 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go @@ -114,7 +114,10 @@ func (ds UploadDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (re return reconcile.Result{}, err } - quotaExceeded, quotaExceededMessage := checkIfQuotaExceeded(dv) + var quotaNotExceededCondition *metav1.Condition + if dv != nil { + quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) + } switch { case isDiskProvisioningFinished(condition): @@ -286,11 +289,11 @@ func (ds UploadDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (re Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil - case quotaExceeded: + case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: cb. Status(metav1.ConditionFalse). Reason(vdcondition.QuotaExceeded). - Message(quotaExceededMessage) + Message(quotaNotExceededCondition.Message) return reconcile.Result{}, nil case pvc == nil: vd.Status.Phase = virtv2.DiskProvisioning From b74fcb3f6ac6bba1bf0643e7d4c0f699d9f5cf53 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Fri, 10 Jan 2025 19:32:00 +0300 Subject: [PATCH 13/23] refactor Signed-off-by: Valeriy Khorunzhin --- ...2-show-prime-and-scratch-pvc-quota-exceeded.patch | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch b/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch index ed34e8319..b0fec7207 100644 --- a/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch +++ b/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch @@ -125,10 +125,10 @@ index 4c153257a..aaf4f8198 100644 } else { diff --git a/pkg/patcheddatavolume/patched_datavolume.go b/pkg/patcheddatavolume/patched_datavolume.go new file mode 100644 -index 000000000..3f0b5e605 +index 000000000..19573973a --- /dev/null +++ b/pkg/patcheddatavolume/patched_datavolume.go -@@ -0,0 +1,103 @@ +@@ -0,0 +1,101 @@ +package patcheddatavolume + +import ( @@ -192,11 +192,9 @@ index 000000000..3f0b5e605 + return nil + } + -+ if len(dvList.Items) > 0 { -+ for _, dv := range dvList.Items { -+ if string(dv.UID) == uid { -+ return &dv -+ } ++ for _, dv := range dvList.Items { ++ if string(dv.UID) == uid { ++ return &dv + } + } + From 9eb48572560216cb8126d5d096c2d3e4c9199afa Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Mon, 13 Jan 2025 18:07:02 +0300 Subject: [PATCH 14/23] update phase if quota exceeded Signed-off-by: Valeriy Khorunzhin --- .../pkg/controller/vd/internal/source/blank.go | 1 + .../pkg/controller/vd/internal/source/http.go | 1 + .../pkg/controller/vd/internal/source/object_ref_cvi.go | 1 + .../pkg/controller/vd/internal/source/object_ref_vi_dvcr.go | 1 + .../pkg/controller/vd/internal/source/object_ref_vi_pvc.go | 1 + .../pkg/controller/vd/internal/source/registry.go | 1 + .../pkg/controller/vd/internal/source/upload.go | 1 + 7 files changed, 7 insertions(+) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go index fd3ac667b..be04f432a 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go @@ -145,6 +145,7 @@ func (ds BlankDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (rec return reconcile.Result{Requeue: true}, nil case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: + vd.Status.Phase = virtv2.DiskPending cb. Status(metav1.ConditionFalse). Reason(vdcondition.QuotaExceeded). diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go index 69b78fa1e..687dc1a0a 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go @@ -263,6 +263,7 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (reco return reconcile.Result{Requeue: true}, nil case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: + vd.Status.Phase = virtv2.DiskPending cb. Status(metav1.ConditionFalse). Reason(vdcondition.QuotaExceeded). diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go index 1782011d4..cfa5e70f2 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go @@ -178,6 +178,7 @@ func (ds ObjectRefClusterVirtualImage) Sync(ctx context.Context, vd *virtv2.Virt return reconcile.Result{Requeue: true}, nil case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: + vd.Status.Phase = virtv2.DiskPending cb. Status(metav1.ConditionFalse). Reason(vdcondition.QuotaExceeded). diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go index 171ba151f..f7871769a 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go @@ -177,6 +177,7 @@ func (ds ObjectRefVirtualImageDVCR) Sync(ctx context.Context, vd *virtv2.Virtual return reconcile.Result{Requeue: true}, nil case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: + vd.Status.Phase = virtv2.DiskPending cb. Status(metav1.ConditionFalse). Reason(vdcondition.QuotaExceeded). diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go index f35bf8130..70410c0ff 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go @@ -178,6 +178,7 @@ func (ds ObjectRefVirtualImagePVC) Sync(ctx context.Context, vd *virtv2.VirtualD return reconcile.Result{Requeue: true}, nil case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: + vd.Status.Phase = virtv2.DiskPending cb. Status(metav1.ConditionFalse). Reason(vdcondition.QuotaExceeded). diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go index 54a7fa28f..bc7a6d767 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go @@ -261,6 +261,7 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) ( return reconcile.Result{Requeue: true}, nil case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: + vd.Status.Phase = virtv2.DiskPending cb. Status(metav1.ConditionFalse). Reason(vdcondition.QuotaExceeded). diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go index 28e9c17a6..2cec47387 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go @@ -290,6 +290,7 @@ func (ds UploadDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (re return reconcile.Result{Requeue: true}, nil case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: + vd.Status.Phase = virtv2.DiskPending cb. Status(metav1.ConditionFalse). Reason(vdcondition.QuotaExceeded). From 034068583f44b3c45de97f98be319c36ce6a8e35 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Mon, 13 Jan 2025 18:23:59 +0300 Subject: [PATCH 15/23] add patch note for cdi patch and rename it Signed-off-by: Valeriy Khorunzhin --- ... 022-add-datavolume-quouta-not-exceeded-condition.patch} | 0 images/cdi-artifact/patches/README.md | 6 ++++++ 2 files changed, 6 insertions(+) rename images/cdi-artifact/patches/{022-show-prime-and-scratch-pvc-quota-exceeded.patch => 022-add-datavolume-quouta-not-exceeded-condition.patch} (100%) diff --git a/images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch b/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch similarity index 100% rename from images/cdi-artifact/patches/022-show-prime-and-scratch-pvc-quota-exceeded.patch rename to images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch diff --git a/images/cdi-artifact/patches/README.md b/images/cdi-artifact/patches/README.md index 75a24a088..039360cb3 100644 --- a/images/cdi-artifact/patches/README.md +++ b/images/cdi-artifact/patches/README.md @@ -91,3 +91,9 @@ Add annotation to manage provisioner tolerations to avoid unschedulable error. When cloning from PVC to PVC, it's necessary to select a cloning strategy. By default, the cloning strategy `snapshot` is selected. However, `replicated.csi.storage.deckhouse.io` and `local.csi.storage.deckhouse.io` can create snapshots only when using LVM Thin. To avoid errors, for LVM Thick, it's necessary to use `copy` cloning strategy (`csi-clone` is also unavailable since the CSI itself creates a snapshot when using `csi-clone`). + +#### `022-add-datavolume-quouta-not-exceeded-condition.patch` + +A new condition, QuotaNotExceeded, has been added to the DataVolume resource to indicate that the project's quotas have not been exceeded. + +This patch includes an architectural assumption where the condition of the DataVolume resource is modified by an external controller. In the future, CDI usage is planned to be discontinued, making this assumption non-disruptive. From b4a34540850457d3d65e460acb177b3e414a0b0f Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Mon, 13 Jan 2025 19:05:37 +0300 Subject: [PATCH 16/23] refactoring cdi patch Signed-off-by: Valeriy Khorunzhin --- .../022-add-datavolume-quouta-not-exceeded-condition.patch | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch b/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch index b0fec7207..7cbbacd2e 100644 --- a/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch +++ b/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch @@ -125,7 +125,7 @@ index 4c153257a..aaf4f8198 100644 } else { diff --git a/pkg/patcheddatavolume/patched_datavolume.go b/pkg/patcheddatavolume/patched_datavolume.go new file mode 100644 -index 000000000..19573973a +index 000000000..7b00253e5 --- /dev/null +++ b/pkg/patcheddatavolume/patched_datavolume.go @@ -0,0 +1,101 @@ @@ -163,7 +163,7 @@ index 000000000..19573973a + conditions = append(conditions, cdiv1.DataVolumeCondition{ + Type: conditionType, + }) -+ condition = FindConditionByType(conditionType, conditions) ++ condition = &conditions[len(conditions)-1] + } + if condition.Status != status { + condition.LastTransitionTime = metav1.Now() From 611b424ab79fb9a4d3d0b1b627479cca0157a702 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Tue, 14 Jan 2025 18:06:49 +0300 Subject: [PATCH 17/23] refactor cdi patch Signed-off-by: Valeriy Khorunzhin --- ...volume-quouta-not-exceeded-condition.patch | 106 +++++++++--------- 1 file changed, 54 insertions(+), 52 deletions(-) diff --git a/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch b/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch index 7cbbacd2e..039e8823a 100644 --- a/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch +++ b/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch @@ -1,5 +1,5 @@ diff --git a/pkg/controller/datavolume/controller-base.go b/pkg/controller/datavolume/controller-base.go -index acd09cb94..b856d5e38 100644 +index acd09cb94..2fb859150 100644 --- a/pkg/controller/datavolume/controller-base.go +++ b/pkg/controller/datavolume/controller-base.go @@ -55,6 +55,7 @@ import ( @@ -10,28 +10,11 @@ index acd09cb94..b856d5e38 100644 "kubevirt.io/containerized-data-importer/pkg/token" "kubevirt.io/containerized-data-importer/pkg/util" ) -@@ -1035,6 +1036,24 @@ func (r *ReconcilerBase) updateConditions(dataVolume *cdiv1.DataVolume, pvc *cor +@@ -1035,6 +1036,7 @@ func (r *ReconcilerBase) updateConditions(dataVolume *cdiv1.DataVolume, pvc *cor dataVolume.Status.Conditions = updateBoundCondition(dataVolume.Status.Conditions, pvc, message, reason) dataVolume.Status.Conditions = UpdateReadyCondition(dataVolume.Status.Conditions, readyStatus, message, reason) dataVolume.Status.Conditions = updateRunningCondition(dataVolume.Status.Conditions, anno) -+ patchedDV.CreateDVQuotaIsNotExceededConditionIfNotExists(&dataVolume.Status.Conditions) -+ -+ readyCondition := FindConditionByType(cdiv1.DataVolumeReady, dataVolume.Status.Conditions) -+ boundCondition := FindConditionByType(cdiv1.DataVolumeBound, dataVolume.Status.Conditions) -+ runningCondition := FindConditionByType(cdiv1.DataVolumeRunning, dataVolume.Status.Conditions) -+ -+ switch { -+ case readyCondition != nil && readyCondition.Reason == cc.ErrExceededQuota: -+ dataVolume.Status.Conditions = patchedDV.UpdateDVQuotaNotExceededCondition(dataVolume.Status.Conditions, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", readyCondition.Message), patchedDV.QuotaExceededReason) -+ case boundCondition != nil && boundCondition.Reason == cc.ErrExceededQuota: -+ dataVolume.Status.Conditions = patchedDV.UpdateDVQuotaNotExceededCondition(dataVolume.Status.Conditions, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", readyCondition.Message), patchedDV.QuotaExceededReason) -+ case runningCondition != nil: -+ if runningCondition.Reason == cc.ErrExceededQuota { -+ dataVolume.Status.Conditions = patchedDV.UpdateDVQuotaNotExceededCondition(dataVolume.Status.Conditions, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", readyCondition.Message), patchedDV.QuotaExceededReason) -+ } else if runningCondition.Status == corev1.ConditionTrue { -+ dataVolume.Status.Conditions = patchedDV.UpdateDVQuotaNotExceededCondition(dataVolume.Status.Conditions, corev1.ConditionTrue, "", patchedDV.QuotaNotExceededReason) -+ } -+ } ++ dataVolume.Status.Conditions = patchedDV.UpdateDVQuotaNotExceededCondition(dataVolume.Status.Conditions) } func (r *ReconcilerBase) emitConditionEvent(dataVolume *cdiv1.DataVolume, originalCond []cdiv1.DataVolumeCondition) { @@ -125,14 +108,15 @@ index 4c153257a..aaf4f8198 100644 } else { diff --git a/pkg/patcheddatavolume/patched_datavolume.go b/pkg/patcheddatavolume/patched_datavolume.go new file mode 100644 -index 000000000..7b00253e5 +index 000000000..54b62b4cb --- /dev/null +++ b/pkg/patcheddatavolume/patched_datavolume.go -@@ -0,0 +1,101 @@ +@@ -0,0 +1,120 @@ +package patcheddatavolume + +import ( + "context" ++ "fmt" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -157,6 +141,54 @@ index 000000000..7b00253e5 + return nil +} + ++func UpdateDVQuotaNotExceededCondition(conditions []cdiv1.DataVolumeCondition) []cdiv1.DataVolumeCondition { ++ CreateDVQuotaIsNotExceededConditionIfNotExists(&conditions) ++ readyCondition := FindConditionByType(cdiv1.DataVolumeReady, conditions) ++ boundCondition := FindConditionByType(cdiv1.DataVolumeBound, conditions) ++ runningCondition := FindConditionByType(cdiv1.DataVolumeRunning, conditions) ++ ++ switch { ++ case readyCondition != nil && readyCondition.Reason == common.ErrExceededQuota: ++ conditions = updateCondition(conditions, QoutaNotExceededConditionType, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", readyCondition.Message), QuotaExceededReason) ++ case boundCondition != nil && boundCondition.Reason == common.ErrExceededQuota: ++ conditions = updateCondition(conditions, QoutaNotExceededConditionType, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", readyCondition.Message), QuotaExceededReason) ++ case runningCondition != nil: ++ if runningCondition.Reason == common.ErrExceededQuota { ++ conditions = updateCondition(conditions, QoutaNotExceededConditionType, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", readyCondition.Message), QuotaExceededReason) ++ } else if runningCondition.Status == corev1.ConditionTrue { ++ conditions = updateCondition(conditions, QoutaNotExceededConditionType, corev1.ConditionTrue, "", QuotaNotExceededReason) ++ } ++ } ++ ++ return conditions ++} ++ ++func UpdateDVQuotaNotExceededConditionByPVC(clientObject client.Client, pvc *corev1.PersistentVolumeClaim, status corev1.ConditionStatus, message, reason string) { ++ dv := getDVByPVC(clientObject, pvc, common.AnnCreatedForDataVolume) ++ if dv == nil { ++ return ++ } ++ ++ dv.Status.Conditions = updateCondition(dv.Status.Conditions, QoutaNotExceededConditionType, status, message, reason) ++ _ = clientObject.Status().Update(context.TODO(), dv) ++} ++ ++func CreateDVQuotaIsNotExceededConditionIfNotExists(conditions *[]cdiv1.DataVolumeCondition) { ++ if conditions == nil { ++ return ++ } ++ ++ condition := FindConditionByType(QoutaNotExceededConditionType, *conditions) ++ if condition == nil { ++ *conditions = append(*conditions, cdiv1.DataVolumeCondition{ ++ Type: QoutaNotExceededConditionType, ++ Status: corev1.ConditionTrue, ++ Reason: QuotaNotExceededReason, ++ Message: "", ++ }) ++ } ++} ++ +func updateCondition(conditions []cdiv1.DataVolumeCondition, conditionType cdiv1.DataVolumeConditionType, status corev1.ConditionStatus, message, reason string) []cdiv1.DataVolumeCondition { + condition := FindConditionByType(conditionType, conditions) + if condition == nil { @@ -200,33 +232,3 @@ index 000000000..7b00253e5 + + return nil +} -+ -+func UpdateDVQuotaNotExceededCondition(conditions []cdiv1.DataVolumeCondition, status corev1.ConditionStatus, message, reason string) []cdiv1.DataVolumeCondition { -+ return updateCondition(conditions, QoutaNotExceededConditionType, status, message, reason) -+} -+ -+func UpdateDVQuotaNotExceededConditionByPVC(clientObject client.Client, pvc *corev1.PersistentVolumeClaim, status corev1.ConditionStatus, message, reason string) { -+ dv := getDVByPVC(clientObject, pvc, common.AnnCreatedForDataVolume) -+ if dv == nil { -+ return -+ } -+ -+ dv.Status.Conditions = updateCondition(dv.Status.Conditions, QoutaNotExceededConditionType, status, message, reason) -+ _ = clientObject.Status().Update(context.TODO(), dv) -+} -+ -+func CreateDVQuotaIsNotExceededConditionIfNotExists(conditions *[]cdiv1.DataVolumeCondition) { -+ if conditions == nil { -+ return -+ } -+ -+ condition := FindConditionByType(QoutaNotExceededConditionType, *conditions) -+ if condition == nil { -+ *conditions = append(*conditions, cdiv1.DataVolumeCondition{ -+ Type: QoutaNotExceededConditionType, -+ Status: corev1.ConditionTrue, -+ Reason: QuotaNotExceededReason, -+ Message: "", -+ }) -+ } -+} From 9e612e21ff92267ef5c731b0b15745af9c7eb23a Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Tue, 14 Jan 2025 18:39:13 +0300 Subject: [PATCH 18/23] fix cdi patch Signed-off-by: Valeriy Khorunzhin --- ...volume-quouta-not-exceeded-condition.patch | 35 ++++++++++++------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch b/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch index 039e8823a..8a45a4129 100644 --- a/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch +++ b/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch @@ -19,7 +19,7 @@ index acd09cb94..2fb859150 100644 func (r *ReconcilerBase) emitConditionEvent(dataVolume *cdiv1.DataVolume, originalCond []cdiv1.DataVolumeCondition) { diff --git a/pkg/controller/import-controller.go b/pkg/controller/import-controller.go -index 49f1ff898..4ce5c085e 100644 +index 49f1ff898..972f8ab5f 100644 --- a/pkg/controller/import-controller.go +++ b/pkg/controller/import-controller.go @@ -34,6 +34,7 @@ import ( @@ -30,18 +30,21 @@ index 49f1ff898..4ce5c085e 100644 "kubevirt.io/containerized-data-importer/pkg/util" "kubevirt.io/containerized-data-importer/pkg/util/naming" sdkapi "kubevirt.io/controller-lifecycle-operator-sdk/api" -@@ -753,6 +754,9 @@ func (r *ImportReconciler) createScratchPvcForPod(pvc *corev1.PersistentVolumeCl +@@ -753,6 +754,12 @@ func (r *ImportReconciler) createScratchPvcForPod(pvc *corev1.PersistentVolumeCl // Scratch PVC doesn't exist yet, create it. Determine which storage class to use. _, err = createScratchPersistentVolumeClaim(r.client, pvc, pod, scratchPVCName, storageClassName, r.installerLabels, r.recorder) if err != nil { + if strings.Contains(err.Error(), "exceeded quota") { -+ patchedDV.UpdateDVQuotaNotExceededConditionByPVC(r.client, pvc, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", err.Error()), patchedDV.QuotaExceededReason) ++ innerErr := patchedDV.UpdateDVQuotaNotExceededConditionByPVC(r.client, pvc, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", err.Error()), patchedDV.QuotaExceededReason) ++ if innerErr != nil { ++ return innerErr ++ } + } return err } anno[cc.AnnBoundCondition] = "false" diff --git a/pkg/controller/populators/populator-base.go b/pkg/controller/populators/populator-base.go -index 6c6fd8f8a..9df58c3fd 100644 +index 6c6fd8f8a..8fcda592c 100644 --- a/pkg/controller/populators/populator-base.go +++ b/pkg/controller/populators/populator-base.go @@ -18,7 +18,9 @@ package populators @@ -74,18 +77,21 @@ index 6c6fd8f8a..9df58c3fd 100644 // Assemble PVC' spec pvcPrime := &corev1.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ -@@ -213,6 +221,9 @@ func (r *ReconcilerBase) createPVCPrime(pvc *corev1.PersistentVolumeClaim, sourc +@@ -213,6 +221,12 @@ func (r *ReconcilerBase) createPVCPrime(pvc *corev1.PersistentVolumeClaim, sourc } if err := r.client.Create(context.TODO(), pvcPrime); err != nil { + if strings.Contains(err.Error(), "exceeded quota") { -+ patchedDV.UpdateDVQuotaNotExceededConditionByPVC(r.client, pvc, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", err.Error()), patchedDV.QuotaExceededReason) ++ innerErr := patchedDV.UpdateDVQuotaNotExceededConditionByPVC(r.client, pvc, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", err.Error()), patchedDV.QuotaExceededReason) ++ if innerErr != nil { ++ return nil, innerErr ++ } + } return nil, err } r.recorder.Eventf(pvc, corev1.EventTypeNormal, createdPVCPrimeSuccessfully, messageCreatedPVCPrimeSuccessfully) diff --git a/pkg/controller/upload-controller.go b/pkg/controller/upload-controller.go -index 4c153257a..aaf4f8198 100644 +index 4c153257a..e21e40312 100644 --- a/pkg/controller/upload-controller.go +++ b/pkg/controller/upload-controller.go @@ -51,6 +51,7 @@ import ( @@ -96,19 +102,22 @@ index 4c153257a..aaf4f8198 100644 "kubevirt.io/containerized-data-importer/pkg/util" "kubevirt.io/containerized-data-importer/pkg/util/cert/fetcher" "kubevirt.io/containerized-data-importer/pkg/util/cert/generator" -@@ -473,6 +474,9 @@ func (r *UploadReconciler) getOrCreateScratchPvc(pvc *corev1.PersistentVolumeCla +@@ -473,6 +474,12 @@ func (r *UploadReconciler) getOrCreateScratchPvc(pvc *corev1.PersistentVolumeCla // Scratch PVC doesn't exist yet, create it. scratchPvc, err = createScratchPersistentVolumeClaim(r.client, pvc, pod, name, storageClassName, map[string]string{}, r.recorder) if err != nil { + if strings.Contains(err.Error(), "exceeded quota") { -+ patchedDV.UpdateDVQuotaNotExceededConditionByPVC(r.client, pvc, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", err.Error()), patchedDV.QuotaExceededReason) ++ innerErr := patchedDV.UpdateDVQuotaNotExceededConditionByPVC(r.client, pvc, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", err.Error()), patchedDV.QuotaExceededReason) ++ if innerErr != nil { ++ return nil, innerErr ++ } + } return nil, err } } else { diff --git a/pkg/patcheddatavolume/patched_datavolume.go b/pkg/patcheddatavolume/patched_datavolume.go new file mode 100644 -index 000000000..54b62b4cb +index 000000000..28ce3c406 --- /dev/null +++ b/pkg/patcheddatavolume/patched_datavolume.go @@ -0,0 +1,120 @@ @@ -163,14 +172,14 @@ index 000000000..54b62b4cb + return conditions +} + -+func UpdateDVQuotaNotExceededConditionByPVC(clientObject client.Client, pvc *corev1.PersistentVolumeClaim, status corev1.ConditionStatus, message, reason string) { ++func UpdateDVQuotaNotExceededConditionByPVC(clientObject client.Client, pvc *corev1.PersistentVolumeClaim, status corev1.ConditionStatus, message, reason string) error { + dv := getDVByPVC(clientObject, pvc, common.AnnCreatedForDataVolume) + if dv == nil { -+ return ++ return nil + } + + dv.Status.Conditions = updateCondition(dv.Status.Conditions, QoutaNotExceededConditionType, status, message, reason) -+ _ = clientObject.Status().Update(context.TODO(), dv) ++ return clientObject.Status().Update(context.TODO(), dv) +} + +func CreateDVQuotaIsNotExceededConditionIfNotExists(conditions *[]cdiv1.DataVolumeCondition) { From 7e91c4ec4d9287b0d26e725371c98baa8c72323e Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Tue, 14 Jan 2025 18:57:35 +0300 Subject: [PATCH 19/23] patch err experiment Signed-off-by: Valeriy Khorunzhin --- ...-datavolume-quouta-not-exceeded-condition.patch | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch b/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch index 8a45a4129..3d6d5a284 100644 --- a/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch +++ b/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch @@ -117,14 +117,15 @@ index 4c153257a..e21e40312 100644 } else { diff --git a/pkg/patcheddatavolume/patched_datavolume.go b/pkg/patcheddatavolume/patched_datavolume.go new file mode 100644 -index 000000000..28ce3c406 +index 000000000..d931db11d --- /dev/null +++ b/pkg/patcheddatavolume/patched_datavolume.go -@@ -0,0 +1,120 @@ +@@ -0,0 +1,126 @@ +package patcheddatavolume + +import ( + "context" ++ "errors" + "fmt" + + corev1 "k8s.io/api/core/v1" @@ -160,10 +161,10 @@ index 000000000..28ce3c406 + case readyCondition != nil && readyCondition.Reason == common.ErrExceededQuota: + conditions = updateCondition(conditions, QoutaNotExceededConditionType, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", readyCondition.Message), QuotaExceededReason) + case boundCondition != nil && boundCondition.Reason == common.ErrExceededQuota: -+ conditions = updateCondition(conditions, QoutaNotExceededConditionType, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", readyCondition.Message), QuotaExceededReason) ++ conditions = updateCondition(conditions, QoutaNotExceededConditionType, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", boundCondition.Message), QuotaExceededReason) + case runningCondition != nil: + if runningCondition.Reason == common.ErrExceededQuota { -+ conditions = updateCondition(conditions, QoutaNotExceededConditionType, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", readyCondition.Message), QuotaExceededReason) ++ conditions = updateCondition(conditions, QoutaNotExceededConditionType, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", runningCondition.Message), QuotaExceededReason) + } else if runningCondition.Status == corev1.ConditionTrue { + conditions = updateCondition(conditions, QoutaNotExceededConditionType, corev1.ConditionTrue, "", QuotaNotExceededReason) + } @@ -173,6 +174,11 @@ index 000000000..28ce3c406 +} + +func UpdateDVQuotaNotExceededConditionByPVC(clientObject client.Client, pvc *corev1.PersistentVolumeClaim, status corev1.ConditionStatus, message, reason string) error { ++ fmt.Println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<") ++ fmt.Println("Error from UpdateDVQuotaNotExceededConditionByPVC") ++ fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>") ++ return errors.New("errrrrrrr") ++ + dv := getDVByPVC(clientObject, pvc, common.AnnCreatedForDataVolume) + if dv == nil { + return nil From 62cdf6fa32c62e4d95745edfda79b656251f19ae Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Tue, 14 Jan 2025 19:24:40 +0300 Subject: [PATCH 20/23] patch cdi Signed-off-by: Valeriy Khorunzhin --- ...-add-datavolume-quouta-not-exceeded-condition.patch | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch b/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch index 3d6d5a284..f3a913bc3 100644 --- a/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch +++ b/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch @@ -117,15 +117,14 @@ index 4c153257a..e21e40312 100644 } else { diff --git a/pkg/patcheddatavolume/patched_datavolume.go b/pkg/patcheddatavolume/patched_datavolume.go new file mode 100644 -index 000000000..d931db11d +index 000000000..7f5112e87 --- /dev/null +++ b/pkg/patcheddatavolume/patched_datavolume.go -@@ -0,0 +1,126 @@ +@@ -0,0 +1,120 @@ +package patcheddatavolume + +import ( + "context" -+ "errors" + "fmt" + + corev1 "k8s.io/api/core/v1" @@ -174,11 +173,6 @@ index 000000000..d931db11d +} + +func UpdateDVQuotaNotExceededConditionByPVC(clientObject client.Client, pvc *corev1.PersistentVolumeClaim, status corev1.ConditionStatus, message, reason string) error { -+ fmt.Println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<") -+ fmt.Println("Error from UpdateDVQuotaNotExceededConditionByPVC") -+ fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>") -+ return errors.New("errrrrrrr") -+ + dv := getDVByPVC(clientObject, pvc, common.AnnCreatedForDataVolume) + if dv == nil { + return nil From 56b3a01f637f58fad1225cb99ae993e4eac32d57 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Tue, 14 Jan 2025 19:29:20 +0300 Subject: [PATCH 21/23] refactor Signed-off-by: Valeriy Khorunzhin --- .../pkg/controller/vd/internal/source/blank.go | 5 +++-- .../pkg/controller/vd/internal/source/http.go | 4 ++-- .../vd/internal/source/object_ref_cvi.go | 4 ++-- .../vd/internal/source/object_ref_vi_dvcr.go | 4 ++-- .../vd/internal/source/object_ref_vi_pvc.go | 4 ++-- .../controller/vd/internal/source/registry.go | 4 ++-- .../controller/vd/internal/source/sources.go | 18 ++---------------- .../controller/vd/internal/source/upload.go | 4 ++-- 8 files changed, 17 insertions(+), 30 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go index be04f432a..4b8107dcd 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1" @@ -84,7 +85,7 @@ func (ds BlankDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (rec return reconcile.Result{}, err } - var quotaNotExceededCondition *metav1.Condition + var quotaNotExceededCondition *cdiv1.DataVolumeCondition if dv != nil { quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) } @@ -144,7 +145,7 @@ func (ds BlankDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (rec Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil - case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: + case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == corev1.ConditionFalse: vd.Status.Phase = virtv2.DiskPending cb. Status(metav1.ConditionFalse). diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go index 687dc1a0a..21a55146a 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go @@ -106,7 +106,7 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (reco return reconcile.Result{}, err } - var quotaNotExceededCondition *metav1.Condition + var quotaNotExceededCondition *cdiv1.DataVolumeCondition if dv != nil { quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) } @@ -262,7 +262,7 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (reco Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil - case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: + case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == corev1.ConditionFalse: vd.Status.Phase = virtv2.DiskPending cb. Status(metav1.ConditionFalse). diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go index cfa5e70f2..d07e58b80 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go @@ -103,7 +103,7 @@ func (ds ObjectRefClusterVirtualImage) Sync(ctx context.Context, vd *virtv2.Virt return reconcile.Result{}, err } - var quotaNotExceededCondition *metav1.Condition + var quotaNotExceededCondition *cdiv1.DataVolumeCondition if dv != nil { quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) } @@ -177,7 +177,7 @@ func (ds ObjectRefClusterVirtualImage) Sync(ctx context.Context, vd *virtv2.Virt Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil - case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: + case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == corev1.ConditionFalse: vd.Status.Phase = virtv2.DiskPending cb. Status(metav1.ConditionFalse). diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go index f7871769a..f1b5f1047 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go @@ -102,7 +102,7 @@ func (ds ObjectRefVirtualImageDVCR) Sync(ctx context.Context, vd *virtv2.Virtual return reconcile.Result{}, err } - var quotaNotExceededCondition *metav1.Condition + var quotaNotExceededCondition *cdiv1.DataVolumeCondition if dv != nil { quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) } @@ -176,7 +176,7 @@ func (ds ObjectRefVirtualImageDVCR) Sync(ctx context.Context, vd *virtv2.Virtual Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil - case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: + case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == corev1.ConditionFalse: vd.Status.Phase = virtv2.DiskPending cb. Status(metav1.ConditionFalse). diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go index 70410c0ff..789910947 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go @@ -98,7 +98,7 @@ func (ds ObjectRefVirtualImagePVC) Sync(ctx context.Context, vd *virtv2.VirtualD return reconcile.Result{}, err } - var quotaNotExceededCondition *metav1.Condition + var quotaNotExceededCondition *cdiv1.DataVolumeCondition if dv != nil { quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) } @@ -177,7 +177,7 @@ func (ds ObjectRefVirtualImagePVC) Sync(ctx context.Context, vd *virtv2.VirtualD Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil - case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: + case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == corev1.ConditionFalse: vd.Status.Phase = virtv2.DiskPending cb. Status(metav1.ConditionFalse). diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go index bc7a6d767..e19f3a889 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go @@ -107,7 +107,7 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) ( return reconcile.Result{}, err } - var quotaNotExceededCondition *metav1.Condition + var quotaNotExceededCondition *cdiv1.DataVolumeCondition if dv != nil { quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) } @@ -260,7 +260,7 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) ( Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil - case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: + case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == corev1.ConditionFalse: vd.Status.Phase = virtv2.DiskPending cb. Status(metav1.ConditionFalse). diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go index 1d6277bf7..5ffe202ad 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go @@ -421,24 +421,10 @@ const ( DVQoutaNotExceededConditionType string = "QuotaNotExceeded" ) -func getDVNotExceededCondition(conditions []cdiv1.DataVolumeCondition) *metav1.Condition { +func getDVNotExceededCondition(conditions []cdiv1.DataVolumeCondition) *cdiv1.DataVolumeCondition { for _, condition := range conditions { if string(condition.Type) == DVQoutaNotExceededConditionType { - returned := &metav1.Condition{ - Type: DVQoutaNotExceededConditionType, - Reason: condition.Reason, - Message: condition.Message, - LastTransitionTime: condition.LastTransitionTime, - } - switch condition.Status { - case corev1.ConditionTrue: - returned.Status = metav1.ConditionTrue - case corev1.ConditionFalse: - returned.Status = metav1.ConditionFalse - case corev1.ConditionUnknown: - returned.Status = metav1.ConditionUnknown - } - return returned + return &condition } } diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go index 2cec47387..cfdfe1d16 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go @@ -114,7 +114,7 @@ func (ds UploadDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (re return reconcile.Result{}, err } - var quotaNotExceededCondition *metav1.Condition + var quotaNotExceededCondition *cdiv1.DataVolumeCondition if dv != nil { quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) } @@ -289,7 +289,7 @@ func (ds UploadDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (re Message("PVC Provisioner not found: create the new one.") return reconcile.Result{Requeue: true}, nil - case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == metav1.ConditionFalse: + case quotaNotExceededCondition != nil && quotaNotExceededCondition.Status == corev1.ConditionFalse: vd.Status.Phase = virtv2.DiskPending cb. Status(metav1.ConditionFalse). From acb52b6a61655f2283672bcbb804dbecbd20c686 Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Tue, 14 Jan 2025 20:10:14 +0300 Subject: [PATCH 22/23] refactoring Signed-off-by: Valeriy Khorunzhin --- .../controller/vd/internal/source/blank.go | 2 +- .../pkg/controller/vd/internal/source/http.go | 9 ++++----- .../vd/internal/source/object_ref_cvi.go | 7 +++---- .../vd/internal/source/object_ref_vi_dvcr.go | 7 +++---- .../vd/internal/source/object_ref_vi_pvc.go | 7 +++---- .../controller/vd/internal/source/registry.go | 9 ++++----- .../controller/vd/internal/source/sources.go | 20 ++++--------------- .../controller/vd/internal/source/upload.go | 9 ++++----- 8 files changed, 26 insertions(+), 44 deletions(-) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go index 4b8107dcd..01ee17d80 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/blank.go @@ -87,7 +87,7 @@ func (ds BlankDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (rec var quotaNotExceededCondition *cdiv1.DataVolumeCondition if dv != nil { - quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) + quotaNotExceededCondition = service.GetDataVolumeCondition(DVQoutaNotExceededConditionType, dv.Status.Conditions) } switch { diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go index 21a55146a..667096095 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/http.go @@ -42,7 +42,6 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/dvcr" "github.com/deckhouse/virtualization-controller/pkg/eventrecord" "github.com/deckhouse/virtualization-controller/pkg/logger" - "github.com/deckhouse/virtualization/api/core/v1alpha2" virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2" "github.com/deckhouse/virtualization/api/core/v1alpha2/vdcondition" ) @@ -108,7 +107,7 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (reco var quotaNotExceededCondition *cdiv1.DataVolumeCondition if dv != nil { - quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) + quotaNotExceededCondition = service.GetDataVolumeCondition(DVQoutaNotExceededConditionType, dv.Status.Conditions) } switch { @@ -141,7 +140,7 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (reco ds.recorder.Event( vd, corev1.EventTypeNormal, - v1alpha2.ReasonDataSourceSyncStarted, + virtv2.ReasonDataSourceSyncStarted, "The HTTP DataSource import to DVCR has started", ) @@ -200,7 +199,7 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (reco ds.recorder.Event( vd, corev1.EventTypeNormal, - v1alpha2.ReasonDataSourceSyncStarted, + virtv2.ReasonDataSourceSyncStarted, "The HTTP DataSource import to PVC has started", ) @@ -282,7 +281,7 @@ func (ds HTTPDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (reco ds.recorder.Event( vd, corev1.EventTypeNormal, - v1alpha2.ReasonDataSourceSyncCompleted, + virtv2.ReasonDataSourceSyncCompleted, "The HTTP DataSource import has completed", ) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go index d07e58b80..2cb9dbc47 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_cvi.go @@ -39,7 +39,6 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/controller/supplements" "github.com/deckhouse/virtualization-controller/pkg/eventrecord" "github.com/deckhouse/virtualization-controller/pkg/logger" - "github.com/deckhouse/virtualization/api/core/v1alpha2" virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2" "github.com/deckhouse/virtualization/api/core/v1alpha2/vdcondition" ) @@ -105,7 +104,7 @@ func (ds ObjectRefClusterVirtualImage) Sync(ctx context.Context, vd *virtv2.Virt var quotaNotExceededCondition *cdiv1.DataVolumeCondition if dv != nil { - quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) + quotaNotExceededCondition = service.GetDataVolumeCondition(DVQoutaNotExceededConditionType, dv.Status.Conditions) } switch { @@ -132,7 +131,7 @@ func (ds ObjectRefClusterVirtualImage) Sync(ctx context.Context, vd *virtv2.Virt ds.recorder.Event( vd, corev1.EventTypeNormal, - v1alpha2.ReasonDataSourceSyncStarted, + virtv2.ReasonDataSourceSyncStarted, "The ObjectRef DataSource import to PVC has started", ) @@ -196,7 +195,7 @@ func (ds ObjectRefClusterVirtualImage) Sync(ctx context.Context, vd *virtv2.Virt ds.recorder.Event( vd, corev1.EventTypeNormal, - v1alpha2.ReasonDataSourceSyncCompleted, + virtv2.ReasonDataSourceSyncCompleted, "The ObjectRef DataSource import has completed", ) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go index f1b5f1047..a9434eb7b 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_dvcr.go @@ -39,7 +39,6 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/controller/supplements" "github.com/deckhouse/virtualization-controller/pkg/eventrecord" "github.com/deckhouse/virtualization-controller/pkg/logger" - "github.com/deckhouse/virtualization/api/core/v1alpha2" virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2" "github.com/deckhouse/virtualization/api/core/v1alpha2/vdcondition" ) @@ -104,7 +103,7 @@ func (ds ObjectRefVirtualImageDVCR) Sync(ctx context.Context, vd *virtv2.Virtual var quotaNotExceededCondition *cdiv1.DataVolumeCondition if dv != nil { - quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) + quotaNotExceededCondition = service.GetDataVolumeCondition(DVQoutaNotExceededConditionType, dv.Status.Conditions) } switch { @@ -131,7 +130,7 @@ func (ds ObjectRefVirtualImageDVCR) Sync(ctx context.Context, vd *virtv2.Virtual ds.recorder.Event( vd, corev1.EventTypeNormal, - v1alpha2.ReasonDataSourceSyncStarted, + virtv2.ReasonDataSourceSyncStarted, "The ObjectRef DataSource import to DVCR has started", ) @@ -195,7 +194,7 @@ func (ds ObjectRefVirtualImageDVCR) Sync(ctx context.Context, vd *virtv2.Virtual ds.recorder.Event( vd, corev1.EventTypeNormal, - v1alpha2.ReasonDataSourceSyncCompleted, + virtv2.ReasonDataSourceSyncCompleted, "The ObjectRef DataSource import has completed", ) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go index 789910947..d2087b8f6 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/object_ref_vi_pvc.go @@ -38,7 +38,6 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/controller/supplements" "github.com/deckhouse/virtualization-controller/pkg/eventrecord" "github.com/deckhouse/virtualization-controller/pkg/logger" - "github.com/deckhouse/virtualization/api/core/v1alpha2" virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2" "github.com/deckhouse/virtualization/api/core/v1alpha2/vdcondition" ) @@ -100,7 +99,7 @@ func (ds ObjectRefVirtualImagePVC) Sync(ctx context.Context, vd *virtv2.VirtualD var quotaNotExceededCondition *cdiv1.DataVolumeCondition if dv != nil { - quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) + quotaNotExceededCondition = service.GetDataVolumeCondition(DVQoutaNotExceededConditionType, dv.Status.Conditions) } switch { @@ -127,7 +126,7 @@ func (ds ObjectRefVirtualImagePVC) Sync(ctx context.Context, vd *virtv2.VirtualD ds.recorder.Event( vd, corev1.EventTypeNormal, - v1alpha2.ReasonDataSourceSyncStarted, + virtv2.ReasonDataSourceSyncStarted, "The ObjectRef DataSource import to PVC has started", ) @@ -196,7 +195,7 @@ func (ds ObjectRefVirtualImagePVC) Sync(ctx context.Context, vd *virtv2.VirtualD ds.recorder.Event( vd, corev1.EventTypeNormal, - v1alpha2.ReasonDataSourceSyncCompleted, + virtv2.ReasonDataSourceSyncCompleted, "The ObjectRef DataSource import has completed", ) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go index e19f3a889..042af3b5e 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/registry.go @@ -43,7 +43,6 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/dvcr" "github.com/deckhouse/virtualization-controller/pkg/eventrecord" "github.com/deckhouse/virtualization-controller/pkg/logger" - "github.com/deckhouse/virtualization/api/core/v1alpha2" virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2" "github.com/deckhouse/virtualization/api/core/v1alpha2/vdcondition" ) @@ -109,7 +108,7 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) ( var quotaNotExceededCondition *cdiv1.DataVolumeCondition if dv != nil { - quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) + quotaNotExceededCondition = service.GetDataVolumeCondition(DVQoutaNotExceededConditionType, dv.Status.Conditions) } switch { @@ -142,7 +141,7 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) ( ds.recorder.Event( vd, corev1.EventTypeNormal, - v1alpha2.ReasonDataSourceSyncStarted, + virtv2.ReasonDataSourceSyncStarted, "The Registry DataSource import to DVCR has started", ) @@ -200,7 +199,7 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) ( ds.recorder.Event( vd, corev1.EventTypeNormal, - v1alpha2.ReasonDataSourceSyncStarted, + virtv2.ReasonDataSourceSyncStarted, "The Registry DataSource import to PVC has started", ) @@ -280,7 +279,7 @@ func (ds RegistryDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) ( ds.recorder.Event( vd, corev1.EventTypeNormal, - v1alpha2.ReasonDataSourceSyncCompleted, + virtv2.ReasonDataSourceSyncCompleted, "The Registry DataSource import has completed", ) diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go index 5ffe202ad..a00fa38e8 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/sources.go @@ -334,11 +334,9 @@ func setPhaseConditionFromProvisioningError( _, err = cleaner.CleanUp(ctx, supgen) if err != nil { - if err != nil { - err = errors.Join(provisioningErr, err) - setPhaseConditionToFailed(cb, &vd.Status.Phase, err) - return err - } + err = errors.Join(provisioningErr, err) + setPhaseConditionToFailed(cb, &vd.Status.Phase, err) + return err } cb. @@ -418,15 +416,5 @@ func setPhaseConditionToFailed(cb *conditions.ConditionBuilder, phase *virtv2.Di } const ( - DVQoutaNotExceededConditionType string = "QuotaNotExceeded" + DVQoutaNotExceededConditionType cdiv1.DataVolumeConditionType = "QuotaNotExceeded" ) - -func getDVNotExceededCondition(conditions []cdiv1.DataVolumeCondition) *cdiv1.DataVolumeCondition { - for _, condition := range conditions { - if string(condition.Type) == DVQoutaNotExceededConditionType { - return &condition - } - } - - return nil -} diff --git a/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go b/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go index cfdfe1d16..c94c8030a 100644 --- a/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go +++ b/images/virtualization-artifact/pkg/controller/vd/internal/source/upload.go @@ -42,7 +42,6 @@ import ( "github.com/deckhouse/virtualization-controller/pkg/dvcr" "github.com/deckhouse/virtualization-controller/pkg/eventrecord" "github.com/deckhouse/virtualization-controller/pkg/logger" - "github.com/deckhouse/virtualization/api/core/v1alpha2" virtv2 "github.com/deckhouse/virtualization/api/core/v1alpha2" "github.com/deckhouse/virtualization/api/core/v1alpha2/vdcondition" ) @@ -116,7 +115,7 @@ func (ds UploadDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (re var quotaNotExceededCondition *cdiv1.DataVolumeCondition if dv != nil { - quotaNotExceededCondition = getDVNotExceededCondition(dv.Status.Conditions) + quotaNotExceededCondition = service.GetDataVolumeCondition(DVQoutaNotExceededConditionType, dv.Status.Conditions) } switch { @@ -149,7 +148,7 @@ func (ds UploadDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (re ds.recorder.Event( vd, corev1.EventTypeNormal, - v1alpha2.ReasonDataSourceSyncStarted, + virtv2.ReasonDataSourceSyncStarted, "The Upload DataSource import to DVCR has started", ) @@ -234,7 +233,7 @@ func (ds UploadDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (re ds.recorder.Event( vd, corev1.EventTypeNormal, - v1alpha2.ReasonDataSourceSyncStarted, + virtv2.ReasonDataSourceSyncStarted, "The Upload DataSource import to PVC has started", ) @@ -309,7 +308,7 @@ func (ds UploadDataSource) Sync(ctx context.Context, vd *virtv2.VirtualDisk) (re ds.recorder.Event( vd, corev1.EventTypeNormal, - v1alpha2.ReasonDataSourceSyncCompleted, + virtv2.ReasonDataSourceSyncCompleted, "The Upload DataSource import has completed", ) From 6a3e8aab52deacb85721b95ba0bb0cb99dd7a74f Mon Sep 17 00:00:00 2001 From: Valeriy Khorunzhin Date: Wed, 15 Jan 2025 02:45:00 +0300 Subject: [PATCH 23/23] patch for tmp-pvc Signed-off-by: Valeriy Khorunzhin --- ...-add-datavolume-quouta-not-exceeded-condition.patch | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch b/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch index f3a913bc3..1717de3d2 100644 --- a/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch +++ b/images/cdi-artifact/patches/022-add-datavolume-quouta-not-exceeded-condition.patch @@ -117,15 +117,16 @@ index 4c153257a..e21e40312 100644 } else { diff --git a/pkg/patcheddatavolume/patched_datavolume.go b/pkg/patcheddatavolume/patched_datavolume.go new file mode 100644 -index 000000000..7f5112e87 +index 000000000..29fc38c97 --- /dev/null +++ b/pkg/patcheddatavolume/patched_datavolume.go -@@ -0,0 +1,120 @@ +@@ -0,0 +1,124 @@ +package patcheddatavolume + +import ( + "context" + "fmt" ++ "strings" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -139,6 +140,8 @@ index 000000000..7f5112e87 + + QuotaNotExceededReason string = "QuotaNotExceeded" + QuotaExceededReason string = "QuotaExceeded" ++ ++ RunningConditionErrorReason string = "Error" +) + +func FindConditionByType(conditionType cdiv1.DataVolumeConditionType, conditions []cdiv1.DataVolumeCondition) *cdiv1.DataVolumeCondition { @@ -162,7 +165,8 @@ index 000000000..7f5112e87 + case boundCondition != nil && boundCondition.Reason == common.ErrExceededQuota: + conditions = updateCondition(conditions, QoutaNotExceededConditionType, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", boundCondition.Message), QuotaExceededReason) + case runningCondition != nil: -+ if runningCondition.Reason == common.ErrExceededQuota { ++ if runningCondition.Reason == common.ErrExceededQuota || ++ runningCondition.Reason == RunningConditionErrorReason && strings.Contains(runningCondition.Message, "exceeded quota") { + conditions = updateCondition(conditions, QoutaNotExceededConditionType, corev1.ConditionFalse, fmt.Sprintf("Exceeded quota: %q", runningCondition.Message), QuotaExceededReason) + } else if runningCondition.Status == corev1.ConditionTrue { + conditions = updateCondition(conditions, QoutaNotExceededConditionType, corev1.ConditionTrue, "", QuotaNotExceededReason)