diff --git a/CHANGELOG.md b/CHANGELOG.md index 21417f41d..639f2c42b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,14 @@ - [v0.1.1](#v011) - [v0.1.0](#v010) +## Unreleased + +### Fixes + +- Fixes an issue where managed `Gateway`s controller wasn't able to reduce + the created `DataPlane` objects when too many have been created. + [#43](https://github.com/Kong/gateway-operator/pull/43) + ## [v1.2.1] > Release date: 2024-03-19 diff --git a/controllers/gateway/controller.go b/controllers/gateway/controller.go index b4f558413..b5e787cc2 100644 --- a/controllers/gateway/controller.go +++ b/controllers/gateway/controller.go @@ -36,6 +36,7 @@ import ( gatewayutils "github.com/kong/gateway-operator/pkg/utils/gateway" k8sutils "github.com/kong/gateway-operator/pkg/utils/kubernetes" "github.com/kong/gateway-operator/pkg/utils/kubernetes/compare" + k8sreduce "github.com/kong/gateway-operator/pkg/utils/kubernetes/reduce" k8sresources "github.com/kong/gateway-operator/pkg/utils/kubernetes/resources" "github.com/kong/gateway-operator/pkg/vars" ) @@ -382,11 +383,16 @@ func (r *Reconciler) provisionDataPlane( count := len(dataplanes) if count > 1 { - err = fmt.Errorf("data plane deployments found: %d, expected: 1", count) + err = fmt.Errorf("data planes found: %d, expected: 1", count) k8sutils.SetCondition( createDataPlaneCondition(metav1.ConditionFalse, k8sutils.UnableToProvisionReason, err.Error(), gateway.Generation), gatewayConditionsAndListenersAware(gateway), ) + log.Debug(logger, "reducing dataplanes", gateway, "count", count) + rErr := k8sreduce.ReduceDataPlanes(ctx, r.Client, dataplanes) + if rErr != nil { + return nil, fmt.Errorf("failed reducing data planes: %w", rErr) + } return nil, err } if count == 0 { diff --git a/pkg/utils/kubernetes/reduce/filters.go b/pkg/utils/kubernetes/reduce/filters.go index 1bbcd67d6..7a2160c51 100644 --- a/pkg/utils/kubernetes/reduce/filters.go +++ b/pkg/utils/kubernetes/reduce/filters.go @@ -10,6 +10,7 @@ import ( networkingv1 "k8s.io/api/networking/v1" rbacv1 "k8s.io/api/rbac/v1" + operatorv1beta1 "github.com/kong/gateway-operator/apis/v1beta1" "github.com/kong/gateway-operator/pkg/consts" ) @@ -330,3 +331,24 @@ func filterValidatingWebhookConfigurations(webhookConfigurations []admregv1.Vali return append(webhookConfigurations[:best], webhookConfigurations[best+1:]...) } + +// ----------------------------------------------------------------------------- +// Filter functions - DataPlanes +// ----------------------------------------------------------------------------- + +// filterDataPlanes filters out the DataPlanes to be kept and returns all the DataPlanes +// to be deleted. The oldest DataPlane is kept. +func filterDataPlanes(dataplanes []operatorv1beta1.DataPlane) []operatorv1beta1.DataPlane { + if len(dataplanes) < 2 { + return []operatorv1beta1.DataPlane{} + } + + best := 0 + for i, dataplane := range dataplanes { + if dataplane.CreationTimestamp.Before(&dataplanes[best].CreationTimestamp) { + best = i + } + } + + return append(dataplanes[:best], dataplanes[best+1:]...) +} diff --git a/pkg/utils/kubernetes/reduce/reduce.go b/pkg/utils/kubernetes/reduce/reduce.go index ac618c2b5..43ae29f33 100644 --- a/pkg/utils/kubernetes/reduce/reduce.go +++ b/pkg/utils/kubernetes/reduce/reduce.go @@ -12,6 +12,8 @@ import ( networkingv1 "k8s.io/api/networking/v1" rbacv1 "k8s.io/api/rbac/v1" "sigs.k8s.io/controller-runtime/pkg/client" + + operatorv1beta1 "github.com/kong/gateway-operator/apis/v1beta1" ) // PreDeleteHook is a function that can be executed before deleting an object. @@ -176,3 +178,17 @@ func ReduceValidatingWebhookConfigurations(ctx context.Context, k8sClient client } return nil } + +// +kubebuilder:rbac:groups=gateway-operator.konghq.com,resources=dataplanes,verbs=delete + +// ReduceDataPlanes detects the best DataPlane in the set and deletes all the others. +func ReduceDataPlanes(ctx context.Context, k8sClient client.Client, dataplanes []operatorv1beta1.DataPlane) error { + filteredDataPlanes := filterDataPlanes(dataplanes) + for _, dataplane := range filteredDataPlanes { + dataplane := dataplane + if err := k8sClient.Delete(ctx, &dataplane); err != nil { + return err + } + } + return nil +}