1
0
mirror of https://github.com/kubernetes-sigs/descheduler.git synced 2026-01-26 05:14:13 +01:00

feat(eviction): add annotations to eviction requests for observability

Although eviction requests (policy/v1) are not persisted long term,
their API still implements the full metav1.ObjectMeta struct. While
name and namespace refer to the pod being evicted, eviction requests
can still carry annotations.

This change adds annotations to descheduler-initiated evictions,
including the requester, reason, and the strategy or plugin that
triggered them.

While these details are already logged by the descheduler, exposing them
as annotations allows external webhooks or controllers to provide
clearer context about each eviction request, both for tracking and
prioritization purposes.

Signed-off-by: Simone Tiraboschi <stirabos@redhat.com>
This commit is contained in:
Simone Tiraboschi
2025-10-10 16:36:13 +02:00
parent 07b1c4e681
commit 3a608a590a
2 changed files with 19 additions and 4 deletions

View File

@@ -42,6 +42,12 @@ import (
"sigs.k8s.io/descheduler/pkg/tracing"
)
const (
deschedulerGlobalName = "sigs.k8s.io/descheduler"
reasonAnnotationKey = "reason"
requestedByAnnotationKey = "requested-by"
)
var (
assumedEvictionRequestTimeoutSeconds uint = 10 * 60 // 10 minutes
evictionRequestsCacheResyncPeriod time.Duration = 10 * time.Minute
@@ -522,7 +528,7 @@ func (pe *PodEvictor) EvictPod(ctx context.Context, pod *v1.Pod, opts EvictOptio
return err
}
ignore, err := pe.evictPod(ctx, pod)
ignore, err := pe.evictPod(ctx, pod, opts)
if err != nil {
// err is used only for logging purposes
span.AddEvent("Eviction Failed", trace.WithAttributes(attribute.String("node", pod.Spec.NodeName), attribute.String("err", err.Error())))
@@ -569,7 +575,7 @@ func (pe *PodEvictor) EvictPod(ctx context.Context, pod *v1.Pod, opts EvictOptio
}
// return (ignore, err)
func (pe *PodEvictor) evictPod(ctx context.Context, pod *v1.Pod) (bool, error) {
func (pe *PodEvictor) evictPod(ctx context.Context, pod *v1.Pod, opts EvictOptions) (bool, error) {
deleteOptions := &metav1.DeleteOptions{
GracePeriodSeconds: pe.gracePeriodSeconds,
}
@@ -582,6 +588,10 @@ func (pe *PodEvictor) evictPod(ctx context.Context, pod *v1.Pod) (bool, error) {
ObjectMeta: metav1.ObjectMeta{
Name: pod.Name,
Namespace: pod.Namespace,
Annotations: map[string]string{
"reason": fmt.Sprintf("triggered by %v/%v: %v", opts.ProfileName, opts.StrategyName, opts.Reason),
"requested-by": deschedulerGlobalName,
},
},
DeleteOptions: deleteOptions,
}

View File

@@ -20,6 +20,7 @@ import (
"context"
"fmt"
"reflect"
"strings"
"testing"
"time"
@@ -114,7 +115,7 @@ func TestEvictPod(t *testing.T) {
t.Fatalf("Unexpected error when creating a pod evictor: %v", err)
}
_, got := podEvictor.evictPod(ctx, test.evictedPod)
_, got := podEvictor.evictPod(ctx, test.evictedPod, EvictOptions{})
if got != test.wantErr {
t.Errorf("Test error for Desc: %s. Expected %v pod eviction to be %v, got %v", test.description, test.evictedPod.Name, test.wantErr, got)
}
@@ -418,7 +419,11 @@ func TestEvictionRequestsCacheCleanup(t *testing.T) {
}
if eviction, matched := createAct.Object.(*policy.Eviction); matched {
podName := eviction.GetName()
if podName == "p1" || podName == "p2" {
annotations := eviction.GetAnnotations()
if (podName == "p1" || podName == "p2") && annotations[requestedByAnnotationKey] == deschedulerGlobalName && strings.HasPrefix(
annotations[reasonAnnotationKey],
"triggered by",
) {
return true, nil, &apierrors.StatusError{
ErrStatus: metav1.Status{
Reason: metav1.StatusReasonTooManyRequests,