@@ -20,6 +20,7 @@ import (
2020 "context"
2121 "encoding/json"
2222 "fmt"
23+ "sync"
2324 "time"
2425
2526 authenticationv1 "k8s.io/api/authentication/v1"
@@ -37,9 +38,11 @@ import (
3738 kcprbacinformers "github.com/kcp-dev/client-go/informers/rbac/v1"
3839 kcpkubernetesclientset "github.com/kcp-dev/client-go/kubernetes"
3940 kcprbaclisters "github.com/kcp-dev/client-go/listers/rbac/v1"
41+ "github.com/kcp-dev/logicalcluster/v3"
4042
4143 "github.com/kcp-dev/kcp/pkg/logging"
4244 "github.com/kcp-dev/kcp/pkg/reconciler/events"
45+ kcpmetrics "github.com/kcp-dev/kcp/pkg/server/metrics"
4346 corev1alpha1 "github.com/kcp-dev/kcp/sdk/apis/core/v1alpha1"
4447 tenancyv1alpha1 "github.com/kcp-dev/kcp/sdk/apis/tenancy/v1alpha1"
4548 corev1alpha1informers "github.com/kcp-dev/kcp/sdk/client/informers/externalversions/core/v1alpha1"
@@ -58,6 +61,7 @@ func NewController(
5861 kubeClusterClient kcpkubernetesclientset.ClusterInterface ,
5962 logicalClusterInformer corev1alpha1informers.LogicalClusterClusterInformer ,
6063 clusterRoleBindingInformer kcprbacinformers.ClusterRoleBindingClusterInformer ,
64+ shardName string ,
6165) * Controller {
6266 c := & Controller {
6367 queue : workqueue .NewTypedRateLimitingQueueWithConfig (
@@ -69,26 +73,36 @@ func NewController(
6973 kubeClusterClient : kubeClusterClient ,
7074 logicalClusterLister : logicalClusterInformer .Lister (),
7175 clusterRoleBindingLister : clusterRoleBindingInformer .Lister (),
76+ shardName : shardName ,
77+ countedClusters : make (map [string ]string ),
7278 }
7379
7480 _ , _ = logicalClusterInformer .Informer ().AddEventHandler (cache.ResourceEventHandlerFuncs {
75- AddFunc : func (obj interface {}) { c .enqueue (obj ) },
76- UpdateFunc : func (obj , _ interface {}) { c .enqueue (obj ) },
77- DeleteFunc : func (obj interface {}) { c .enqueue (obj ) },
81+ AddFunc : func (obj any ) {
82+ c .enqueue (obj )
83+ c .handleMetricsOnAdd (obj )
84+ },
85+ UpdateFunc : func (oldObj , newObj any ) {
86+ c .enqueue (newObj )
87+ c .handleMetricsOnUpdate (oldObj , newObj )
88+ },
89+ DeleteFunc : func (obj any ) {
90+ c .enqueue (obj )
91+ c .handleMetricsOnDelete (obj )
92+ },
7893 })
79-
8094 _ , _ = clusterRoleBindingInformer .Informer ().AddEventHandler (events .WithoutSyncs (cache.FilteringResourceEventHandler {
81- FilterFunc : func (obj interface {} ) bool {
95+ FilterFunc : func (obj any ) bool {
8296 crb , ok := obj .(* rbacv1.ClusterRoleBinding )
8397 if ! ok {
8498 return false
8599 }
86100 return crb .Name == workspaceAdminClusterRoleBindingName
87101 },
88102 Handler : cache.ResourceEventHandlerFuncs {
89- AddFunc : func (obj interface {} ) { c .enqueueCRB (obj ) },
90- UpdateFunc : func (obj , _ interface {} ) { c .enqueueCRB (obj ) },
91- DeleteFunc : func (obj interface {} ) { c .enqueueCRB (obj ) },
103+ AddFunc : func (obj any ) { c .enqueueCRB (obj ) },
104+ UpdateFunc : func (obj , _ any ) { c .enqueueCRB (obj ) },
105+ DeleteFunc : func (obj any ) { c .enqueueCRB (obj ) },
92106 },
93107 }))
94108
@@ -104,9 +118,12 @@ type Controller struct {
104118 logicalClusterLister corev1alpha1listers.LogicalClusterClusterLister
105119
106120 clusterRoleBindingLister kcprbaclisters.ClusterRoleBindingClusterLister
121+ mu sync.Mutex
122+ countedClusters map [string ]string
123+ shardName string
107124}
108125
109- func (c * Controller ) enqueue (obj interface {} ) {
126+ func (c * Controller ) enqueue (obj any ) {
110127 key , err := kcpcache .DeletionHandlingMetaClusterNamespaceKeyFunc (obj )
111128 if err != nil {
112129 utilruntime .HandleError (err )
@@ -117,7 +134,7 @@ func (c *Controller) enqueue(obj interface{}) {
117134 c .queue .Add (key )
118135}
119136
120- func (c * Controller ) enqueueCRB (obj interface {} ) {
137+ func (c * Controller ) enqueueCRB (obj any ) {
121138 key , err := kcpcache .DeletionHandlingMetaClusterNamespaceKeyFunc (obj )
122139 if err != nil {
123140 utilruntime .HandleError (err )
@@ -189,7 +206,6 @@ func (c *Controller) process(ctx context.Context, key string) error {
189206 if ! apierrors .IsNotFound (err ) {
190207 logger .Error (err , "failed to get LogicalCluster from lister" , "cluster" , clusterName )
191208 }
192-
193209 return nil // nothing we can do here
194210 }
195211
@@ -252,3 +268,76 @@ func (c *Controller) process(ctx context.Context, key string) error {
252268 _ , err = c .kubeClusterClient .Cluster (clusterName .Path ()).RbacV1 ().ClusterRoleBindings ().Update (ctx , newBinding , metav1.UpdateOptions {})
253269 return err
254270}
271+
272+ func (c * Controller ) handleMetricsOnAdd (obj any ) {
273+ logicalCluster , ok := obj .(* corev1alpha1.LogicalCluster )
274+ if ! ok {
275+ return
276+ }
277+
278+ c .mu .Lock ()
279+ defer c .mu .Unlock ()
280+
281+ clusterKey := string (logicalcluster .From (logicalCluster ))
282+ phase := string (logicalCluster .Status .Phase )
283+ if _ , exists := c .countedClusters [clusterKey ]; ! exists {
284+ c .countedClusters [clusterKey ] = phase
285+ if phase != "" {
286+ kcpmetrics .IncrementLogicalClusterCount (c .shardName , phase )
287+ }
288+ }
289+ }
290+
291+ func (c * Controller ) handleMetricsOnUpdate (oldObj , newObj any ) {
292+ oldLogicalCluster , ok := oldObj .(* corev1alpha1.LogicalCluster )
293+ if ! ok {
294+ return
295+ }
296+
297+ newLogicalCluster , ok := newObj .(* corev1alpha1.LogicalCluster )
298+ if ! ok {
299+ return
300+ }
301+
302+ c .mu .Lock ()
303+ defer c .mu .Unlock ()
304+
305+ clusterKey := string (logicalcluster .From (newLogicalCluster ))
306+ oldPhase := string (oldLogicalCluster .Status .Phase )
307+ newPhase := string (newLogicalCluster .Status .Phase )
308+
309+ if oldPhase != newPhase {
310+ if oldPhase != "" {
311+ kcpmetrics .DecrementLogicalClusterCount (c .shardName , oldPhase )
312+ }
313+ if newPhase != "" {
314+ kcpmetrics .IncrementLogicalClusterCount (c .shardName , newPhase )
315+ }
316+ c .countedClusters [clusterKey ] = newPhase
317+ }
318+ }
319+
320+ func (c * Controller ) handleMetricsOnDelete (obj any ) {
321+ logicalCluster , ok := obj .(* corev1alpha1.LogicalCluster )
322+ if ! ok {
323+ if tombstone , ok := obj .(cache.DeletedFinalStateUnknown ); ok {
324+ logicalCluster , ok = tombstone .Obj .(* corev1alpha1.LogicalCluster )
325+ if ! ok {
326+ return
327+ }
328+ } else {
329+ return
330+ }
331+ }
332+
333+ c .mu .Lock ()
334+ defer c .mu .Unlock ()
335+
336+ clusterKey := string (logicalcluster .From (logicalCluster ))
337+ if phase , exists := c .countedClusters [clusterKey ]; exists {
338+ delete (c .countedClusters , clusterKey )
339+ if phase != "" {
340+ kcpmetrics .DecrementLogicalClusterCount (c .shardName , phase )
341+ }
342+ }
343+ }
0 commit comments