From 91e64ed897fa68e11ee383483984f65c53c7b804 Mon Sep 17 00:00:00 2001 From: lubedacht <132355999+lubedacht@users.noreply.github.com> Date: Mon, 13 May 2024 17:28:55 +0200 Subject: [PATCH] :sparkles: Allow credentials in multiple clusters (#114) **What is the purpose of this pull request/Why do we need it?** As we would like to allow referencing the same secret in multiple clusters, we need to make sure to not delete it when it is still in use and set the owner references accordingly. **Description of changes:** Updates the finalizer logic to ensure that a finalizer is not removed as long as the secret is referenced by multiple owners. **Special notes for your reviewer:** * An object in Kubernetes can only have one controller reference, but multiple owner references. **Checklist:** - [x] Includes [emojis](https://github.com/kubernetes-sigs/kubebuilder-release-tools?tab=readme-ov-file#kubebuilder-project-versioning) --------- Co-authored-by: Jonas Riedel --- api/v1alpha1/ionoscloudcluster_types.go | 4 ---- internal/controller/util.go | 23 ++++++++++++----------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/api/v1alpha1/ionoscloudcluster_types.go b/api/v1alpha1/ionoscloudcluster_types.go index 103118a1..3709855b 100644 --- a/api/v1alpha1/ionoscloudcluster_types.go +++ b/api/v1alpha1/ionoscloudcluster_types.go @@ -27,10 +27,6 @@ const ( // associated with the IonosCloudCluster before removing it from the API server. ClusterFinalizer = "ionoscloudcluster.infrastructure.cluster.x-k8s.io" - // ClusterCredentialsFinalizer allows cleanup of resources, which are - // associated with the IonosCloudCluster credentials before removing it from the API server. - ClusterCredentialsFinalizer = ClusterFinalizer + "/credentials" - // IonosCloudClusterReady is the condition for the IonosCloudCluster, which indicates that the cluster is ready. IonosCloudClusterReady clusterv1.ConditionType = "ClusterReady" diff --git a/internal/controller/util.go b/internal/controller/util.go index 7a60a22e..4c4aa5f3 100644 --- a/internal/controller/util.go +++ b/internal/controller/util.go @@ -22,6 +22,7 @@ import ( "time" "github.com/go-logr/logr" + "github.com/google/go-cmp/cmp" sdk "github.com/ionos-cloud/sdk-go/v6" corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" @@ -97,30 +98,30 @@ func createServiceFromCluster( return cloud.NewService(ionosClient, log) } -// ensureSecretControlledByCluster ensures that the secrets will contain a finalizer and a controller reference. -// The secret should only be deleted when there are no resources left in the IONOS Cloud environment. +// ensureSecretControlledByCluster ensures that the secrets will contain a cluster-specific finalizer and an owner reference. +// The secret will be deleted automatically with its last owner. func ensureSecretControlledByCluster( ctx context.Context, c client.Client, cluster *infrav1.IonosCloudCluster, secret *corev1.Secret, ) error { - requireUpdate := controllerutil.AddFinalizer(secret, infrav1.ClusterCredentialsFinalizer) + old := secret.DeepCopy() - if !controllerutil.HasControllerReference(secret) { - if err := controllerutil.SetControllerReference(cluster, secret, c.Scheme()); err != nil { - return err - } - requireUpdate = true + finalizerAdded := controllerutil.AddFinalizer(secret, fmt.Sprintf("%s/%s", infrav1.ClusterFinalizer, cluster.GetUID())) + // We want to allow using the secret in multiple clusters. + // Using owner references because Kubernetes only allows us to have one controller reference. + if err := controllerutil.SetOwnerReference(cluster, secret, c.Scheme()); err != nil { + return err } - if requireUpdate { + if finalizerAdded || !cmp.Equal(old.GetOwnerReferences(), secret.GetOwnerReferences()) { return c.Update(ctx, secret) } return nil } -// removeCredentialsFinalizer removes the finalizer from the credential secret. +// removeCredentialsFinalizer removes the cluster-specific finalizer from the credentials secret. func removeCredentialsFinalizer(ctx context.Context, c client.Client, cluster *infrav1.IonosCloudCluster) error { secretKey := client.ObjectKey{ Namespace: cluster.Namespace, @@ -133,6 +134,6 @@ func removeCredentialsFinalizer(ctx context.Context, c client.Client, cluster *i return client.IgnoreNotFound(err) } - controllerutil.RemoveFinalizer(&secret, infrav1.ClusterCredentialsFinalizer) + controllerutil.RemoveFinalizer(&secret, fmt.Sprintf("%s/%s", infrav1.ClusterFinalizer, cluster.GetUID())) return c.Update(ctx, &secret) }