Return the active leases from ActiveLeases

The lease counter needs to hand over more than a number to its
consumers, so it needs the leases themselves. Let ActiveLeases return
the active controller leases and let the callers count them. Split out
the selection of controller leases and the activity check, so that the
lease counter can observe leases that aren't active, too.

Signed-off-by: Tom Wieczorek <twieczorek@mirantis.com>
This commit is contained in:
Tom Wieczorek committed 2026-10-22 13:59:49 +02:00
1 parent a41e1a93a8
commit 505e84183c
5 files changed
+42 -20

No files matched your search

@@ -121,10 +121,11 @@ func (c *ClusterInfoCollector) CollectData(ctx context.Context) (*ClusterInfo, e
}
// Collect control plane node count
ci.ControlPlaneNodesCount, err = leasecounter.ActiveLeases(ctx, c.client)
activeLeases, err := leasecounter.ActiveLeases(ctx, c.client)
if err != nil {
return ci, fmt.Errorf("can't collect control plane nodes count: %w", err)
}
ci.ControlPlaneNodesCount = uint(len(activeLeases))
return ci, nil
}
@@ -111,12 +111,12 @@ func (c *Component) runLeaseCounter(ctx context.Context, clients kubernetes.Inte
c.log.Debug("Counting active controller leases")
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
numActiveLeases, err := ActiveLeases(ctx, clients)
activeLeases, err := ActiveLeases(ctx, clients)
if err != nil {
c.log.WithError(err).Error("Failed to count controller lease holders")
return
}
c.UpdateControllerCount(numActiveLeases)
c.UpdateControllerCount(uint(len(activeLeases)))
}, 10*time.Second)
}
+32 -12
View File
@@ -9,26 +9,46 @@ import (
kubeutil "github.com/k0sproject/k0s/pkg/kubernetes"
coordinationv1 "k8s.io/api/coordination/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
)
// Counts the active controller leases.
func ActiveLeases(ctx context.Context, kubeClient kubernetes.Interface) (count uint, _ error) {
leases, err := kubeClient.CoordinationV1().Leases(corev1.NamespaceNodeLease).List(ctx, metav1.ListOptions{})
// Returns the active controller leases.
func ActiveLeases(ctx context.Context, kubeClient kubernetes.Interface) (activeLeases []coordinationv1.Lease, _ error) {
allLeases, err := controllerLeases(ctx, kubeClient)
if err != nil {
return 0, err
return nil, err
}
for _, l := range leases.Items {
switch {
// FIXME: Remove the name prefix check in k0s 1.38+.
case l.Labels[leaseTypeLabel] != leaseTypeLabelValueController && !strings.HasPrefix(l.Name, "k0s-ctrl-"):
case l.Spec.HolderIdentity == nil || *l.Spec.HolderIdentity == "":
case kubeutil.IsValidLease(l):
count++
for _, l := range allLeases {
if isActive(&l) {
activeLeases = append(activeLeases, l)
}
}
return count, nil
return
}
// Returns all controller leases, active or not.
func controllerLeases(ctx context.Context, kubeClient kubernetes.Interface) (leases []coordinationv1.Lease, _ error) {
allLeases, err := kubeClient.CoordinationV1().Leases(corev1.NamespaceNodeLease).List(ctx, metav1.ListOptions{})
if err != nil {
return nil, err
}
for _, l := range allLeases.Items {
// FIXME: Remove the name prefix check in k0s 1.38+.
if l.Labels[leaseTypeLabel] == leaseTypeLabelValueController || strings.HasPrefix(l.Name, "k0s-ctrl-") {
leases = append(leases, l)
}
}
return
}
// Indicates if the lease is held and hasn't expired.
func isActive(l *coordinationv1.Lease) bool {
return l.Spec.HolderIdentity != nil && *l.Spec.HolderIdentity != "" && kubeutil.IsValidLease(*l)
}
@@ -22,7 +22,7 @@ func TestActiveLeases(t *testing.T) {
for _, tt := range []struct {
name string
expected uint
expected int
leases []runtime.Object
}{
{
@@ -34,7 +34,7 @@ func TestActiveLeases(t *testing.T) {
1, []runtime.Object{makeLease(withoutControllerLabel, withName("k0s-ctrl-foo"))},
},
{
"returns zero when there are no leases",
"returns no leases when there are none",
0, nil,
},
{
@@ -73,9 +73,9 @@ func TestActiveLeases(t *testing.T) {
} {
t.Run(tt.name, func(t *testing.T) {
c := fake.NewSimpleClientset(tt.leases...)
count, err := ActiveLeases(t.Context(), c)
leases, err := ActiveLeases(t.Context(), c)
assert.NoError(t, err)
assert.Equal(t, tt.expected, count)
assert.Len(t, leases, tt.expected)
})
}
}
+2 -1
View File
@@ -68,10 +68,11 @@ func (c *Component) collectTelemetry(ctx context.Context, clients kubernetes.Int
data.WorkerData = wds
data.MEMTotal = sums.memTotal
data.CPUTotal = sums.cpuTotal
data.ControlPlaneNodesCount, err = leasecounter.ActiveLeases(ctx, clients)
activeLeases, err := leasecounter.ActiveLeases(ctx, clients)
if err != nil {
return data, fmt.Errorf("can't collect control plane nodes count: %w", err)
}
data.ControlPlaneNodesCount = uint(len(activeLeases))
return data, nil
}