From 5e1a817a78b5ea6c16ab25e1c04c7cfd02f88fce Mon Sep 17 00:00:00 2001 From: Sebastian Widmer Date: Thu, 4 Jan 2024 13:39:41 +0100 Subject: [PATCH] Remove token validity metric on delete of CRD (#16) --- controllers/emergencyaccount_controller.go | 20 +++++++++++++++++ .../emergencyaccount_controller_test.go | 22 ++++++++++++++++++- controllers/metrics.go | 4 ++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/controllers/emergencyaccount_controller.go b/controllers/emergencyaccount_controller.go index 392ab4d..8244724 100644 --- a/controllers/emergencyaccount_controller.go +++ b/controllers/emergencyaccount_controller.go @@ -23,6 +23,8 @@ import ( "github.com/appuio/emergency-credentials-controller/controllers/stores" ) +const EmergencyAccountFinalizer = "emergencyaccounts.cluster.appuio.io/finalizer" + type Clock interface { Now() time.Time } @@ -60,6 +62,24 @@ func (r *EmergencyAccountReconciler) Reconcile(ctx context.Context, req ctrl.Req return ctrl.Result{}, fmt.Errorf("unable to get EmergencyAccount resource: %w", err) } + if instance.DeletionTimestamp != nil { + l.Info("EmergencyAccount resource is being deleted") + deleteVerifiedTokensValidUntil(instance.Name) + if controllerutil.RemoveFinalizer(instance, EmergencyAccountFinalizer) { + if err := r.Update(ctx, instance); err != nil { + return ctrl.Result{}, fmt.Errorf("unable to remove finalizer: %w", err) + } + } + return ctrl.Result{}, nil + } + + if controllerutil.AddFinalizer(instance, EmergencyAccountFinalizer) { + if err := r.Update(ctx, instance); err != nil { + return ctrl.Result{}, fmt.Errorf("unable to add finalizer: %w", err) + } + return ctrl.Result{}, nil + } + sa, err := r.reconcileSA(ctx, instance) if err != nil { return ctrl.Result{}, fmt.Errorf("unable to reconcile ServiceAccount: %w", err) diff --git a/controllers/emergencyaccount_controller_test.go b/controllers/emergencyaccount_controller_test.go index 78b8d68..72913fa 100644 --- a/controllers/emergencyaccount_controller_test.go +++ b/controllers/emergencyaccount_controller_test.go @@ -7,6 +7,7 @@ import ( "time" "github.com/go-logr/logr/testr" + "github.com/prometheus/client_golang/prometheus/testutil" "github.com/stretchr/testify/require" authenticationv1 "k8s.io/api/authentication/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -16,6 +17,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/controller-runtime/pkg/client/interceptor" "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/metrics" "sigs.k8s.io/controller-runtime/pkg/reconcile" emcv1beta1 "github.com/appuio/emergency-credentials-controller/api/v1beta1" @@ -55,11 +57,18 @@ func Test_EmergencyAccountReconciler_Reconcile(t *testing.T) { Clock: clock, } - // Create token + // Create finalizer _, err := subject.Reconcile(ctx, reconcile.Request{NamespacedName: client.ObjectKeyFromObject(ea)}) require.NoError(t, err) require.NoError(t, c.Get(ctx, client.ObjectKeyFromObject(ea), ea)) t.Logf("status %+v", ea.Status) + require.Len(t, ea.Finalizers, 1, "finalizer should be created") + + // Create token + _, err = subject.Reconcile(ctx, reconcile.Request{NamespacedName: client.ObjectKeyFromObject(ea)}) + require.NoError(t, err) + require.NoError(t, c.Get(ctx, client.ObjectKeyFromObject(ea), ea)) + t.Logf("status %+v", ea.Status) require.Len(t, ea.Status.Tokens, 1, "token should be created") require.WithinDuration(t, clock.Now(), ea.Status.LastTokenCreationTimestamp.Time, 0, "last token creation timestamp should be set") lastTimestamp := ea.Status.LastTokenCreationTimestamp.Time @@ -97,6 +106,17 @@ func Test_EmergencyAccountReconciler_Reconcile(t *testing.T) { require.NoError(t, c.Get(ctx, client.ObjectKeyFromObject(ea), ea)) t.Logf("status %+v", ea.Status) require.Len(t, ea.Status.Tokens, 3, "should add a new token") + + // Finalizer should be removed and no metric left + require.NoError(t, c.Delete(ctx, ea)) + deleted := &emcv1beta1.EmergencyAccount{} + _, err = subject.Reconcile(ctx, reconcile.Request{NamespacedName: client.ObjectKeyFromObject(ea)}) + require.NoError(t, err) + require.Error(t, c.Get(ctx, client.ObjectKeyFromObject(ea), deleted)) + require.Len(t, deleted.Finalizers, 0, "finalizer should be removed") + ml, err := testutil.GatherAndCount(metrics.Registry, MetricsNamespace+"_verified_tokens_valid_until_seconds") + require.NoError(t, err) + require.Equal(t, 0, ml, "metric should be removed") } type fakeClientControl struct { diff --git a/controllers/metrics.go b/controllers/metrics.go index be6956a..d8f9fa4 100644 --- a/controllers/metrics.go +++ b/controllers/metrics.go @@ -18,6 +18,10 @@ var ( ) ) +func deleteVerifiedTokensValidUntil(emergencyAccount string) { + verifiedTokensValidUntil.Delete(prometheus.Labels{"emergency_account": emergencyAccount}) +} + func init() { metrics.Registry.MustRegister(verifiedTokensValidUntil) }