From acfed1da3ef05240bc9894c6db291100b3df8683 Mon Sep 17 00:00:00 2001 From: An Tran Date: Mon, 24 Nov 2025 15:17:54 +1000 Subject: [PATCH 1/2] Move deletion to the end of the sync --- .../backend_threescale_reconciler.go | 82 +++++++++---------- controllers/capabilities/methods.go | 32 ++++---- controllers/capabilities/metrics.go | 34 ++++---- 3 files changed, 74 insertions(+), 74 deletions(-) diff --git a/controllers/capabilities/backend_threescale_reconciler.go b/controllers/capabilities/backend_threescale_reconciler.go index 75b86b0be..e85902b47 100644 --- a/controllers/capabilities/backend_threescale_reconciler.go +++ b/controllers/capabilities/backend_threescale_reconciler.go @@ -137,26 +137,6 @@ func (t *BackendThreescaleReconciler) syncMethods(_ interface{}) error { existingMap[systemName] = existing.Element } - // - // Deleted existing and not desired - // - notDesiredExistingKeys := helper.ArrayStringDifference(existingKeys, desiredKeys) - notDesiredMap := map[string]threescaleapi.MethodItem{} - for _, systemName := range notDesiredExistingKeys { - // key is expected to exist - // notDesiredExistingKeys is a subset of the existingMap key set - notDesiredMap[systemName] = existingMap[systemName] - } - err = t.deleteNotDesiredMethodsFrom3scale(notDesiredMap) - if err != nil { - return fmt.Errorf("error sync backend methods [%s]: %w", t.backendResource.Spec.SystemName, err) - } - - err = t.deleteExternalMetricReferences(notDesiredExistingKeys) - if err != nil { - return fmt.Errorf("error sync backend methods [%s]: %w", t.backendResource.Spec.SystemName, err) - } - // // Reconcile existing and changed // @@ -189,6 +169,26 @@ func (t *BackendThreescaleReconciler) syncMethods(_ interface{}) error { return fmt.Errorf("error sync backend methods [%s]: %w", t.backendResource.Spec.SystemName, err) } + // + // Deleted existing and not desired + // + notDesiredExistingKeys := helper.ArrayStringDifference(existingKeys, desiredKeys) + notDesiredMap := map[string]threescaleapi.MethodItem{} + for _, systemName := range notDesiredExistingKeys { + // key is expected to exist + // notDesiredExistingKeys is a subset of the existingMap key set + notDesiredMap[systemName] = existingMap[systemName] + } + err = t.deleteNotDesiredMethodsFrom3scale(notDesiredMap) + if err != nil { + return fmt.Errorf("error sync backend methods [%s]: %w", t.backendResource.Spec.SystemName, err) + } + + err = t.deleteExternalMetricReferences(notDesiredExistingKeys) + if err != nil { + return fmt.Errorf("error sync backend methods [%s]: %w", t.backendResource.Spec.SystemName, err) + } + return nil } @@ -344,27 +344,6 @@ func (t *BackendThreescaleReconciler) syncMetrics(_ interface{}) error { existingMap[systemName] = existing.Element } - // - // Deleted existing and not desired metrics - // - - notDesiredExistingKeys := helper.ArrayStringDifference(existingKeys, desiredKeys) - notDesiredMap := map[string]threescaleapi.MetricItem{} - for _, systemName := range notDesiredExistingKeys { - // key is expected to exist - // notDesiredExistingKeys is a subset of the existingMap key set - notDesiredMap[systemName] = existingMap[systemName] - } - err = t.deleteNotDesiredMetricsFrom3scale(notDesiredMap) - if err != nil { - return fmt.Errorf("error sync backend metrics [%s]: %w", t.backendResource.Spec.SystemName, err) - } - - err = t.deleteExternalMetricReferences(notDesiredExistingKeys) - if err != nil { - return fmt.Errorf("error sync backend metrics [%s]: %w", t.backendResource.Spec.SystemName, err) - } - // // Reconcile existing and changed metrics // @@ -399,6 +378,27 @@ func (t *BackendThreescaleReconciler) syncMetrics(_ interface{}) error { return fmt.Errorf("error sync backend metrics [%s]: %w", t.backendResource.Spec.SystemName, err) } + // + // Deleted existing and not desired metrics + // + + notDesiredExistingKeys := helper.ArrayStringDifference(existingKeys, desiredKeys) + notDesiredMap := map[string]threescaleapi.MetricItem{} + for _, systemName := range notDesiredExistingKeys { + // key is expected to exist + // notDesiredExistingKeys is a subset of the existingMap key set + notDesiredMap[systemName] = existingMap[systemName] + } + err = t.deleteNotDesiredMetricsFrom3scale(notDesiredMap) + if err != nil { + return fmt.Errorf("error sync backend metrics [%s]: %w", t.backendResource.Spec.SystemName, err) + } + + err = t.deleteExternalMetricReferences(notDesiredExistingKeys) + if err != nil { + return fmt.Errorf("error sync backend metrics [%s]: %w", t.backendResource.Spec.SystemName, err) + } + return nil } diff --git a/controllers/capabilities/methods.go b/controllers/capabilities/methods.go index 17d870e36..cf5ad2820 100644 --- a/controllers/capabilities/methods.go +++ b/controllers/capabilities/methods.go @@ -33,22 +33,6 @@ func (t *ProductThreescaleReconciler) syncMethods(_ interface{}) error { existingMap[systemName] = existing.Element } - // - // Deleted existing and not desired - // - notDesiredExistingKeys := helper.ArrayStringDifference(existingKeys, desiredKeys) - t.logger.V(1).Info("syncMethods", "notDesiredExistingKeys", notDesiredExistingKeys) - notDesiredMap := map[string]threescaleapi.MethodItem{} - for _, systemName := range notDesiredExistingKeys { - // key is expected to exist - // notDesiredExistingKeys is a subset of the existingMap key set - notDesiredMap[systemName] = existingMap[systemName] - } - err = t.processNotDesiredMethods(notDesiredMap) - if err != nil { - return fmt.Errorf("error sync product methods [%s]: %w", t.resource.Spec.SystemName, err) - } - // // Reconcile existing and changed // @@ -83,6 +67,22 @@ func (t *ProductThreescaleReconciler) syncMethods(_ interface{}) error { return fmt.Errorf("error sync product methods [%s]: %w", t.resource.Spec.SystemName, err) } + // + // Deleted existing and not desired + // + notDesiredExistingKeys := helper.ArrayStringDifference(existingKeys, desiredKeys) + t.logger.V(1).Info("syncMethods", "notDesiredExistingKeys", notDesiredExistingKeys) + notDesiredMap := map[string]threescaleapi.MethodItem{} + for _, systemName := range notDesiredExistingKeys { + // key is expected to exist + // notDesiredExistingKeys is a subset of the existingMap key set + notDesiredMap[systemName] = existingMap[systemName] + } + err = t.processNotDesiredMethods(notDesiredMap) + if err != nil { + return fmt.Errorf("error sync product methods [%s]: %w", t.resource.Spec.SystemName, err) + } + return nil } diff --git a/controllers/capabilities/metrics.go b/controllers/capabilities/metrics.go index d8f6f841c..69d8a9312 100644 --- a/controllers/capabilities/metrics.go +++ b/controllers/capabilities/metrics.go @@ -33,23 +33,6 @@ func (t *ProductThreescaleReconciler) syncMetrics(_ interface{}) error { existingMap[systemName] = existing.Element } - // - // Deleted existing and not desired metrics - // - - notDesiredExistingKeys := helper.ArrayStringDifference(existingKeys, desiredKeys) - t.logger.V(1).Info("syncMetrics", "notDesiredExistingKeys", notDesiredExistingKeys) - notDesiredMap := map[string]threescaleapi.MetricItem{} - for _, systemName := range notDesiredExistingKeys { - // key is expected to exist - // notDesiredExistingKeys is a subset of the existingMap key set - notDesiredMap[systemName] = existingMap[systemName] - } - err = t.processNotDesiredMetrics(notDesiredMap) - if err != nil { - return fmt.Errorf("error sync product metrics [%s]: %w", t.resource.Spec.SystemName, err) - } - // // Reconcile existing and changed metrics // @@ -86,6 +69,23 @@ func (t *ProductThreescaleReconciler) syncMetrics(_ interface{}) error { return fmt.Errorf("error sync product metrics [%s]: %w", t.resource.Spec.SystemName, err) } + // + // Deleted existing and not desired metrics + // + + notDesiredExistingKeys := helper.ArrayStringDifference(existingKeys, desiredKeys) + t.logger.V(1).Info("syncMetrics", "notDesiredExistingKeys", notDesiredExistingKeys) + notDesiredMap := map[string]threescaleapi.MetricItem{} + for _, systemName := range notDesiredExistingKeys { + // key is expected to exist + // notDesiredExistingKeys is a subset of the existingMap key set + notDesiredMap[systemName] = existingMap[systemName] + } + err = t.processNotDesiredMetrics(notDesiredMap) + if err != nil { + return fmt.Errorf("error sync product metrics [%s]: %w", t.resource.Spec.SystemName, err) + } + return nil } From 452ef371927a5ecb459daccd29e839c95888ddc4 Mon Sep 17 00:00:00 2001 From: An Tran Date: Mon, 24 Nov 2025 17:03:04 +1000 Subject: [PATCH 2/2] Allow Product/Backend promotion with active method/metric deletion error --- .../application_status_reconciler_test.go | 7 +- .../proxyconfigpromote_controller.go | 5 +- .../proxyconfigpromote_controller_test.go | 149 +++++++++++------- pkg/controller/helper/backend_list.go | 28 ++-- pkg/helper/errors.go | 6 + pkg/helper/task_runner.go | 2 +- 6 files changed, 117 insertions(+), 80 deletions(-) diff --git a/controllers/capabilities/application_status_reconciler_test.go b/controllers/capabilities/application_status_reconciler_test.go index 14ce24c73..41064bf7e 100644 --- a/controllers/capabilities/application_status_reconciler_test.go +++ b/controllers/capabilities/application_status_reconciler_test.go @@ -13,6 +13,7 @@ import ( v1 "github.com/openshift/api/config/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/reconcile" ) @@ -217,7 +218,7 @@ func getApplicationProductCR() (CR *capabilitiesv1beta1.Product) { }, }, Status: capabilitiesv1beta1.ProductStatus{ - ID: create(3), + ID: ptr.To(int64(3)), ProviderAccountHost: "some string", ObservedGeneration: 1, Conditions: common.Conditions{common.Condition{ @@ -265,7 +266,7 @@ func getApplicationProductList() (productList *capabilitiesv1beta1.ProductList) }, }, Status: capabilitiesv1beta1.ProductStatus{ - ID: create(3), + ID: ptr.To(int64(3)), ProviderAccountHost: "some string", ObservedGeneration: 1, Conditions: nil, @@ -310,7 +311,7 @@ func getApplicationDeveloperAccount() (CR *capabilitiesv1beta1.DeveloperAccount) }, }, Status: capabilitiesv1beta1.DeveloperAccountStatus{ - ID: create(3), + ID: ptr.To(int64(3)), ProviderAccountHost: "some string", Conditions: common.Conditions{ common.Condition{ diff --git a/controllers/capabilities/proxyconfigpromote_controller.go b/controllers/capabilities/proxyconfigpromote_controller.go index 0d302475a..672110e32 100644 --- a/controllers/capabilities/proxyconfigpromote_controller.go +++ b/controllers/capabilities/proxyconfigpromote_controller.go @@ -144,7 +144,10 @@ func (r *ProxyConfigPromoteReconciler) proxyConfigPromoteReconciler(proxyConfigP var currentStagingVersion int // Only proceed with proxyConfigPromote if status of the product is marked as "Completed" - if product.Status.Conditions.IsTrueFor(capabilitiesv1beta1.ProductSyncedConditionType) { + // OR the status is marked with ErrReferencedMethodIsBeingDeleted + failedCond := product.Status.Conditions.GetCondition(capabilitiesv1beta1.ProductFailedConditionType) + if product.Status.Conditions.IsTrueFor(capabilitiesv1beta1.ProductSyncedConditionType) || + (failedCond != nil && failedCond.IsTrue() && failedCond.Message == helper.ErrReferencedMethodIsBeingDeleted.Error()) { productID := product.Status.ID productIDInt64 := *productID productIDStr := strconv.Itoa(int(productIDInt64)) diff --git a/controllers/capabilities/proxyconfigpromote_controller_test.go b/controllers/capabilities/proxyconfigpromote_controller_test.go index 0bb595aff..8c596ca3d 100644 --- a/controllers/capabilities/proxyconfigpromote_controller_test.go +++ b/controllers/capabilities/proxyconfigpromote_controller_test.go @@ -12,18 +12,14 @@ import ( capabilitiesv1beta1 "github.com/3scale/3scale-operator/apis/capabilities/v1beta1" "github.com/3scale/3scale-operator/pkg/apispkg/common" - "github.com/3scale/3scale-operator/pkg/reconcilers" + "github.com/3scale/3scale-operator/pkg/helper" "github.com/3scale/3scale-porta-go-client/client" - "github.com/go-logr/logr" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/utils/ptr" logf "sigs.k8s.io/controller-runtime/pkg/log" ) -func create(x int64) *int64 { - return &x -} - type RoundTripFunc func(req *http.Request) *http.Response func (f RoundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) { @@ -53,11 +49,6 @@ func getProviderAccount() (Secret *v1.Secret) { return Secret } -func newTrue() *bool { - b := true - return &b -} - func getProxyConfigPromoteCRStaging() (CR *capabilitiesv1beta1.ProxyConfigPromote) { CR = &capabilitiesv1beta1.ProxyConfigPromote{ ObjectMeta: metav1.ObjectMeta{ @@ -79,7 +70,7 @@ func getProxyConfigPromoteCRProduction() (CR *capabilitiesv1beta1.ProxyConfigPro }, Spec: capabilitiesv1beta1.ProxyConfigPromoteSpec{ ProductCRName: "test", - Production: newTrue(), + Production: ptr.To(true), }, } return CR @@ -102,7 +93,7 @@ func getProductList() (productList *capabilitiesv1beta1.ProductList) { Description: "test", }, Status: capabilitiesv1beta1.ProductStatus{ - ID: create(3), + ID: ptr.To(int64(3)), ProviderAccountHost: "some string", ObservedGeneration: 1, Conditions: nil, @@ -126,7 +117,7 @@ func getProductCR() (CR *capabilitiesv1beta1.Product) { Description: "test", }, Status: capabilitiesv1beta1.ProductStatus{ - ID: create(3), + ID: ptr.To(int64(3)), ProviderAccountHost: "some string", ObservedGeneration: 1, Conditions: common.Conditions{common.Condition{ @@ -210,7 +201,7 @@ func emptyMockHttpClient() *http.Client { func responseBody(class interface{}) (responseBodyBytes []byte) { responseBodyBytes, err := json.Marshal(class) if err != nil { - fmt.Println("json marshal error", "err") + fmt.Println("json marshal error", err) } return responseBodyBytes } @@ -311,32 +302,23 @@ func TestProxyConfigPromoteReconciler_proxyConfigPromoteReconciler(t *testing.T) // new adminportal ap, _ := client.NewAdminPortalFromStr("https://3scale-admin.test.3scale.net") - type fields struct { - BaseReconciler *reconcilers.BaseReconciler - } type args struct { - proxyConfigPromote *capabilitiesv1beta1.ProxyConfigPromote - reqLogger logr.Logger - threescaleAPIClient *client.ThreeScaleClient - product *capabilitiesv1beta1.Product + proxyConfigPromote *capabilitiesv1beta1.ProxyConfigPromote + httpClient *http.Client + product *capabilitiesv1beta1.Product } tests := []struct { name string - fields fields args args want *ProxyConfigPromoteStatusReconciler wantErr bool }{ { name: "Test promotion to Staging Completed", - fields: fields{ - BaseReconciler: getBaseReconciler(), - }, args: args{ - proxyConfigPromote: getProxyConfigPromoteCRStaging(), - reqLogger: logf.Log.WithName("test reqlogger"), - threescaleAPIClient: client.NewThreeScale(ap, "test", mockHttpClient(proxyJson, productList, proxyConfigElementSandbox, failedProxyConfigElementProduction)), - product: getProductCR(), + proxyConfigPromote: getProxyConfigPromoteCRStaging(), + httpClient: mockHttpClient(proxyJson, productList, proxyConfigElementSandbox, failedProxyConfigElementProduction), + product: getProductCR(), }, want: &ProxyConfigPromoteStatusReconciler{ BaseReconciler: getBaseReconciler(), @@ -351,14 +333,10 @@ func TestProxyConfigPromoteReconciler_proxyConfigPromoteReconciler(t *testing.T) }, { name: "Test promotion to Staging not Completed", - fields: fields{ - BaseReconciler: getBaseReconciler(), - }, args: args{ - proxyConfigPromote: getProxyConfigPromoteCRStaging(), - reqLogger: logf.Log.WithName("test reqlogger"), - threescaleAPIClient: client.NewThreeScale(ap, "test", mockHttpClient(proxyJson, productList, proxyConfigElementSandbox, failedProxyConfigElementProduction)), - product: getProductCR(), + proxyConfigPromote: getProxyConfigPromoteCRStaging(), + httpClient: mockHttpClient(proxyJson, productList, proxyConfigElementSandbox, failedProxyConfigElementProduction), + product: getProductCR(), }, want: &ProxyConfigPromoteStatusReconciler{ BaseReconciler: getBaseReconciler(), @@ -373,14 +351,10 @@ func TestProxyConfigPromoteReconciler_proxyConfigPromoteReconciler(t *testing.T) }, { name: "Test empty staging environment response", - fields: fields{ - BaseReconciler: getBaseReconciler(), - }, args: args{ - proxyConfigPromote: getProxyConfigPromoteCRStaging(), - reqLogger: logf.Log.WithName("test reqlogger"), - threescaleAPIClient: client.NewThreeScale(ap, "test", emptyMockHttpClient()), - product: getProductCR(), + proxyConfigPromote: getProxyConfigPromoteCRStaging(), + httpClient: emptyMockHttpClient(), + product: getProductCR(), }, want: &ProxyConfigPromoteStatusReconciler{ BaseReconciler: getBaseReconciler(), @@ -395,14 +369,10 @@ func TestProxyConfigPromoteReconciler_proxyConfigPromoteReconciler(t *testing.T) }, { name: "Test promotion to Production Completed", - fields: fields{ - BaseReconciler: getBaseReconciler(), - }, args: args{ - proxyConfigPromote: getProxyConfigPromoteCRProduction(), - reqLogger: logf.Log.WithName("test reqlogger"), - threescaleAPIClient: client.NewThreeScale(ap, "test", mockHttpClient(proxyJson, productList, proxyConfigElementSandbox, proxyConfigElementProduction)), - product: getProductCR(), + proxyConfigPromote: getProxyConfigPromoteCRProduction(), + httpClient: mockHttpClient(proxyJson, productList, proxyConfigElementSandbox, proxyConfigElementProduction), + product: getProductCR(), }, want: &ProxyConfigPromoteStatusReconciler{ BaseReconciler: getBaseReconciler(), @@ -416,25 +386,82 @@ func TestProxyConfigPromoteReconciler_proxyConfigPromoteReconciler(t *testing.T) wantErr: false, }, { - name: "Test promotion to Production Failed", - fields: fields{ - BaseReconciler: getBaseReconciler(), - }, + name: "Test promotion with Product in Failed status", args: args{ - proxyConfigPromote: getProxyConfigPromoteCRProduction(), - reqLogger: logf.Log.WithName("test reqlogger"), - threescaleAPIClient: client.NewThreeScale(ap, "test", mockHttpClient(proxyJson, productList, failedProxyConfigElementSandbox, failedProxyConfigElementProduction)), - product: getProductCR(), + proxyConfigPromote: getProxyConfigPromoteCRProduction(), + httpClient: mockHttpClient(proxyJson, productList, failedProxyConfigElementSandbox, failedProxyConfigElementProduction), + product: &capabilitiesv1beta1.Product{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "test", + }, + Spec: capabilitiesv1beta1.ProductSpec{ + Name: "test", + SystemName: "test", + Description: "test", + }, + Status: capabilitiesv1beta1.ProductStatus{ + ID: ptr.To(int64(3)), + ProviderAccountHost: "some string", + ObservedGeneration: 1, + Conditions: common.Conditions{common.Condition{ + Type: capabilitiesv1beta1.ProductFailedConditionType, + Status: v1.ConditionTrue, + }}, + }, + }, }, wantErr: true, }, + { + name: "Allow promote Product with Failed and ErrReferencedMethodIsBeingDeleted message ", + args: args{ + proxyConfigPromote: getProxyConfigPromoteCRProduction(), + httpClient: mockHttpClient(proxyJson, productList, proxyConfigElementSandbox, proxyConfigElementProduction), + product: &capabilitiesv1beta1.Product{ + TypeMeta: metav1.TypeMeta{}, + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Namespace: "test", + }, + Spec: capabilitiesv1beta1.ProductSpec{ + Name: "test", + SystemName: "test", + Description: "test", + }, + Status: capabilitiesv1beta1.ProductStatus{ + ID: ptr.To(int64(3)), + ProviderAccountHost: "some string", + ObservedGeneration: 1, + Conditions: common.Conditions{common.Condition{ + Type: capabilitiesv1beta1.ProductFailedConditionType, + Message: helper.ErrReferencedMethodIsBeingDeleted.Error(), + Status: v1.ConditionTrue, + }}, + }, + }, + }, + want: &ProxyConfigPromoteStatusReconciler{ + BaseReconciler: getBaseReconciler(), + resource: getProxyConfigPromoteCRProduction(), + productID: "3", + latestProductionVersion: 1, + latestStagingVersion: 1, + reconcileError: nil, + logger: logf.Log.WithValues("Status Reconciler", "test"), + }, + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := &ProxyConfigPromoteReconciler{ - BaseReconciler: tt.fields.BaseReconciler, + BaseReconciler: getBaseReconciler(), } - got, err := r.proxyConfigPromoteReconciler(tt.args.proxyConfigPromote, tt.args.reqLogger, tt.args.threescaleAPIClient, tt.args.product) + reqLogger := logf.Log.WithName("test reqlogger") + threescaleAPIClient := client.NewThreeScale(ap, "test", tt.args.httpClient) + got, err := r.proxyConfigPromoteReconciler(tt.args.proxyConfigPromote, reqLogger, threescaleAPIClient, tt.args.product) if (err != nil) && tt.wantErr { t.Logf("proxyConfigPromoteReconciler(), wantErr %v", tt.wantErr) return diff --git a/pkg/controller/helper/backend_list.go b/pkg/controller/helper/backend_list.go index 006624113..ef943848a 100644 --- a/pkg/controller/helper/backend_list.go +++ b/pkg/controller/helper/backend_list.go @@ -5,6 +5,7 @@ import ( "fmt" capabilitiesv1beta1 "github.com/3scale/3scale-operator/apis/capabilities/v1beta1" + "github.com/3scale/3scale-operator/pkg/helper" "github.com/go-logr/logr" "sigs.k8s.io/controller-runtime/pkg/client" @@ -26,22 +27,21 @@ func BackendList(ns string, cl client.Client, providerAccountURLStr string, logg logger.V(1).Info("Backend resources", "total", len(backendList.Items)) validBackends := make([]capabilitiesv1beta1.Backend, 0) - for idx := range backendList.Items { + for idx, backend := range backendList.Items { // Filter by synchronized - if !backendList.Items[idx].IsSynced() { - continue + failedCond := backend.Status.Conditions.GetCondition(capabilitiesv1beta1.BackendFailedConditionType) + if backend.IsSynced() || (failedCond != nil && failedCond.IsTrue() && failedCond.Message == helper.ErrReferencedMethodIsBeingDeleted.Error()) { + backendProviderAccount, err := LookupProviderAccount(cl, ns, backendList.Items[idx].Spec.ProviderAccountRef, logger) + if err != nil { + return nil, fmt.Errorf("BackendList: %w", err) + } + + // Filter by provider account + if providerAccountURLStr != backendProviderAccount.AdminURLStr { + continue + } + validBackends = append(validBackends, backendList.Items[idx]) } - - backendProviderAccount, err := LookupProviderAccount(cl, ns, backendList.Items[idx].Spec.ProviderAccountRef, logger) - if err != nil { - return nil, fmt.Errorf("BackendList: %w", err) - } - - // Filter by provider account - if providerAccountURLStr != backendProviderAccount.AdminURLStr { - continue - } - validBackends = append(validBackends, backendList.Items[idx]) } logger.V(1).Info("Backend valid resources", "total", len(validBackends)) diff --git a/pkg/helper/errors.go b/pkg/helper/errors.go index d152b67df..d87d53953 100644 --- a/pkg/helper/errors.go +++ b/pkg/helper/errors.go @@ -1,9 +1,15 @@ package helper import ( + "errors" + "k8s.io/apimachinery/pkg/util/validation/field" ) +// ErrReferencedMethodIsBeingDeleted is an error type that is returned when +// an active Metric entity references in Product or Backend which is being deleted. +var ErrReferencedMethodIsBeingDeleted = errors.New("method is used by the latest gateway configuration, it will be removed from 3scale only once the promotion without the mapping rule that uses the deleted method is done") + type FieldTypeError int const ( diff --git a/pkg/helper/task_runner.go b/pkg/helper/task_runner.go index b65ce8d28..38f2c9f87 100644 --- a/pkg/helper/task_runner.go +++ b/pkg/helper/task_runner.go @@ -51,7 +51,7 @@ func (t *taskRunnerImpl) Run() error { t.logger.V(1).Info("Measure", task.Name, elapsed) } if reqerr { - return fmt.Errorf("method is used by the latest gateway configuration, it will be removed from 3scale only once the promotion without the mapping rule that uses the deleted method is done") + return ErrReferencedMethodIsBeingDeleted } return nil }