Skip to content

Commit

Permalink
feat(metrics): provide metrics for tenant quotas
Browse files Browse the repository at this point in the history
Signed-off-by: Lukas Boettcher <[email protected]>
  • Loading branch information
lukasboettcher committed May 24, 2024
1 parent 0571e41 commit 7f4d55f
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 0 deletions.
50 changes: 50 additions & 0 deletions controllers/tenant/cleanup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2020-2023 Project Capsule Authors.
// SPDX-License-Identifier: Apache-2.0

package tenant

import (
"context"

"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
"github.com/projectcapsule/capsule/pkg/metrics"
)

func (r *Manager) handleMetricsCleanup(ctx context.Context, tenant *capsulev1beta2.Tenant) (err error) {
metricsFinalizer := "capsule.clastix.io/metrics-cleanup"

// examine DeletionTimestamp to determine if object is under deletion
if tenant.ObjectMeta.DeletionTimestamp.IsZero() { //nolint:nestif
// The object is not being deleted, so if it does not have our finalizer,
// then lets add the finalizer and update the object. This is equivalent
// to registering our finalizer.
if !controllerutil.ContainsFinalizer(tenant, metricsFinalizer) {
controllerutil.AddFinalizer(tenant, metricsFinalizer)

if err := r.Update(ctx, tenant); err != nil {
return err
}
}
} else {
// The object is being deleted
if controllerutil.ContainsFinalizer(tenant, metricsFinalizer) {
// our finalizer is present, so handle the removal of the metrics
r.Log.Info("Removing ResourceQuota metrics because Tenant " + tenant.Name + " is being deleted")

// remove all metrics of the deleted tenant
metrics.TenantResourceUsage.DeletePartialMatch(map[string]string{"tenant": tenant.Name})
metrics.TenantResourceLimit.DeletePartialMatch(map[string]string{"tenant": tenant.Name})

// remove our finalizer from the list and update it.
controllerutil.RemoveFinalizer(tenant, metricsFinalizer)

if err := r.Update(ctx, tenant); err != nil {
return err
}
}
}

return nil
}
9 changes: 9 additions & 0 deletions controllers/tenant/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,15 @@ func (r Manager) Reconcile(ctx context.Context, request ctrl.Request) (result ct
return
}

// Handle cleanup of metrics if the tenant was deleted
r.Log.Info("Setting up metrics cleanup")

if err = r.handleMetricsCleanup(ctx, instance); err != nil {
r.Log.Error(err, "Cannot setup metrics cleanup")

return
}

r.Log.Info("Tenant reconciling completed")

return ctrl.Result{}, err
Expand Down
26 changes: 26 additions & 0 deletions controllers/tenant/resourcequotas.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (

capsulev1beta2 "github.com/projectcapsule/capsule/api/v1beta2"
"github.com/projectcapsule/capsule/pkg/api"
"github.com/projectcapsule/capsule/pkg/metrics"
"github.com/projectcapsule/capsule/pkg/utils"
)

Expand Down Expand Up @@ -51,6 +52,18 @@ func (r *Manager) syncResourceQuotas(ctx context.Context, tenant *capsulev1beta2
if typeLabel, err = utils.GetTypeLabel(&corev1.ResourceQuota{}); err != nil {
return err
}

// Remove prior metrics, to avoid cleaning up for metrics of deleted ResourceQuotas
metrics.TenantResourceUsage.DeletePartialMatch(map[string]string{"tenant": tenant.Name})
metrics.TenantResourceLimit.DeletePartialMatch(map[string]string{"tenant": tenant.Name})

// Expose the namespace quota and usage as metrics for the tenant
metrics.TenantResourceUsage.WithLabelValues(tenant.Name, "namespaces", "").Set(float64(tenant.Status.Size))

if tenant.Spec.NamespaceOptions != nil && tenant.Spec.NamespaceOptions.Quota != nil {
metrics.TenantResourceLimit.WithLabelValues(tenant.Name, "namespaces", "").Set(float64(*tenant.Spec.NamespaceOptions.Quota))
}

//nolint:nestif
if tenant.Spec.ResourceQuota.Scope == api.ResourceQuotaScopeTenant {
group := new(errgroup.Group)
Expand Down Expand Up @@ -102,6 +115,19 @@ func (r *Manager) syncResourceQuotas(ctx context.Context, tenant *capsulev1beta2

r.Log.Info("Computed " + name.String() + " quota for the whole Tenant is " + quantity.String())

// Expose usage and limit metrics for the resource (name) of the ResourceQuota (index)
metrics.TenantResourceUsage.WithLabelValues(
tenant.Name,
name.String(),
strconv.Itoa(index),
).Set(float64(quantity.MilliValue()) / 1000)

metrics.TenantResourceLimit.WithLabelValues(
tenant.Name,
name.String(),
strconv.Itoa(index),
).Set(float64(hardQuota.MilliValue()) / 1000)

switch quantity.Cmp(resourceQuota.Hard[name]) {
case 0:
// The Tenant is matching exactly the Quota:
Expand Down
30 changes: 30 additions & 0 deletions pkg/metrics/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2020-2023 Project Capsule Authors.
// SPDX-License-Identifier: Apache-2.0

package metrics

import (
"github.com/prometheus/client_golang/prometheus"
"sigs.k8s.io/controller-runtime/pkg/metrics"
)

var (
metricsPrefix = "capsule_"

TenantResourceUsage = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: metricsPrefix + "tenant_resource_usage",
Help: "Current resource usage for a given resource in a tenant",
}, []string{"tenant", "resource", "resourcequotaindex"})

TenantResourceLimit = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: metricsPrefix + "tenant_resource_limit",
Help: "Current resource limit for a given resource in a tenant",
}, []string{"tenant", "resource", "resourcequotaindex"})
)

func init() {
metrics.Registry.MustRegister(
TenantResourceUsage,
TenantResourceLimit,
)
}

0 comments on commit 7f4d55f

Please sign in to comment.