Skip to content

Commit dfc8444

Browse files
committed
add metrics for logical clusters count
On-behalf-of: @SAP [email protected] Signed-off-by: Karol Szwaj <[email protected]>
1 parent 384a53c commit dfc8444

File tree

3 files changed

+83
-8
lines changed

3 files changed

+83
-8
lines changed

pkg/reconciler/tenancy/logicalcluster/logicalcluster_controller.go

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,15 @@ import (
2020
"context"
2121
"encoding/json"
2222
"fmt"
23+
"sync"
2324
"time"
2425

26+
kcpcache "github.com/kcp-dev/apimachinery/v2/pkg/cache"
27+
kcprbacinformers "github.com/kcp-dev/client-go/informers/rbac/v1"
28+
kcpkubernetesclientset "github.com/kcp-dev/client-go/kubernetes"
29+
kcprbaclisters "github.com/kcp-dev/client-go/listers/rbac/v1"
30+
kcpmetrics "github.com/kcp-dev/kcp/pkg/server/metrics"
31+
"github.com/kcp-dev/logicalcluster/v3"
2532
authenticationv1 "k8s.io/api/authentication/v1"
2633
rbacv1 "k8s.io/api/rbac/v1"
2734
"k8s.io/apimachinery/pkg/api/equality"
@@ -33,11 +40,6 @@ import (
3340
"k8s.io/client-go/util/workqueue"
3441
"k8s.io/klog/v2"
3542

36-
kcpcache "github.com/kcp-dev/apimachinery/v2/pkg/cache"
37-
kcprbacinformers "github.com/kcp-dev/client-go/informers/rbac/v1"
38-
kcpkubernetesclientset "github.com/kcp-dev/client-go/kubernetes"
39-
kcprbaclisters "github.com/kcp-dev/client-go/listers/rbac/v1"
40-
4143
"github.com/kcp-dev/kcp/pkg/logging"
4244
"github.com/kcp-dev/kcp/pkg/reconciler/events"
4345
corev1alpha1 "github.com/kcp-dev/kcp/sdk/apis/core/v1alpha1"
@@ -58,6 +60,7 @@ func NewController(
5860
kubeClusterClient kcpkubernetesclientset.ClusterInterface,
5961
logicalClusterInformer corev1alpha1informers.LogicalClusterClusterInformer,
6062
clusterRoleBindingInformer kcprbacinformers.ClusterRoleBindingClusterInformer,
63+
shardName string,
6164
) *Controller {
6265
c := &Controller{
6366
queue: workqueue.NewTypedRateLimitingQueueWithConfig(
@@ -69,6 +72,8 @@ func NewController(
6972
kubeClusterClient: kubeClusterClient,
7073
logicalClusterLister: logicalClusterInformer.Lister(),
7174
clusterRoleBindingLister: clusterRoleBindingInformer.Lister(),
75+
shardName: shardName,
76+
countedClusters: make(map[string]bool),
7277
}
7378

7479
_, _ = logicalClusterInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
@@ -104,6 +109,9 @@ type Controller struct {
104109
logicalClusterLister corev1alpha1listers.LogicalClusterClusterLister
105110

106111
clusterRoleBindingLister kcprbaclisters.ClusterRoleBindingClusterLister
112+
mu sync.Mutex
113+
countedClusters map[string]bool
114+
shardName string
107115
}
108116

109117
func (c *Controller) enqueue(obj interface{}) {
@@ -186,11 +194,18 @@ func (c *Controller) process(ctx context.Context, key string) error {
186194

187195
logicalCluster, err := c.logicalClusterLister.Cluster(clusterName).Get(corev1alpha1.LogicalClusterName)
188196
if err != nil {
189-
if !apierrors.IsNotFound(err) {
197+
if apierrors.IsNotFound(err) {
198+
c.mu.Lock()
199+
if c.countedClusters[clusterName.String()] {
200+
delete(c.countedClusters, clusterName.String())
201+
kcpmetrics.DecrementLogicalClusterCount(c.shardName)
202+
logger.V(4).Info("LogicalCluster deleted, decremented metrics", "cluster", clusterName)
203+
}
204+
c.mu.Unlock()
205+
} else {
190206
logger.Error(err, "failed to get LogicalCluster from lister", "cluster", clusterName)
191207
}
192-
193-
return nil // nothing we can do here
208+
return nil
194209
}
195210

196211
logger = logging.WithObject(logger, logicalCluster)
@@ -201,6 +216,18 @@ func (c *Controller) process(ctx context.Context, key string) error {
201216
return nil
202217
}
203218

219+
c.mu.Lock()
220+
clusterKey := string(logicalcluster.From(logicalCluster))
221+
alreadyCounted := c.countedClusters[clusterKey]
222+
if logicalCluster.Status.Phase == corev1alpha1.LogicalClusterPhaseReady && !alreadyCounted {
223+
c.countedClusters[clusterKey] = true
224+
kcpmetrics.IncrementLogicalClusterCount(c.shardName)
225+
} else if logicalCluster.Status.Phase != corev1alpha1.LogicalClusterPhaseReady && alreadyCounted {
226+
delete(c.countedClusters, clusterKey)
227+
kcpmetrics.DecrementLogicalClusterCount(c.shardName)
228+
}
229+
c.mu.Unlock()
230+
204231
// need to create ClusterRoleBinding for owner.
205232
ownerAnnotation := logicalCluster.Annotations[tenancyv1alpha1.ExperimentalWorkspaceOwnerAnnotationKey]
206233
// some older installations of kcp might have produced an annotation with empty value, so we should

pkg/server/controllers.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ func (s *Server) installTenancyLogicalClusterController(ctx context.Context, con
435435
kubeClusterClient,
436436
s.KcpSharedInformerFactory.Core().V1alpha1().LogicalClusters(),
437437
s.KubeSharedInformerFactory.Rbac().V1().ClusterRoleBindings(),
438+
s.Options.Extra.ShardName,
438439
)
439440

440441
return s.registerController(&controllerWrapper{

pkg/server/metrics/metrics.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
Copyright 2025 The KCP Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package metrics
18+
19+
import (
20+
"k8s.io/component-base/metrics"
21+
"k8s.io/component-base/metrics/legacyregistry"
22+
)
23+
24+
var (
25+
logicalClusterCount = metrics.NewGaugeVec(
26+
&metrics.GaugeOpts{
27+
Name: "kcp_logicalcluster_count",
28+
Help: "Number of logical clusters currently running on this shard.",
29+
StabilityLevel: metrics.ALPHA,
30+
},
31+
[]string{"shard"},
32+
)
33+
)
34+
35+
func init() {
36+
legacyregistry.MustRegister(logicalClusterCount)
37+
}
38+
39+
// IncrementLogicalClusterCount increments the count for the given shard
40+
func IncrementLogicalClusterCount(shardName string) {
41+
logicalClusterCount.WithLabelValues(shardName).Inc()
42+
}
43+
44+
// DecrementLogicalClusterCount decrements the count for the given shard
45+
func DecrementLogicalClusterCount(shardName string) {
46+
logicalClusterCount.WithLabelValues(shardName).Dec()
47+
}

0 commit comments

Comments
 (0)