Skip to content

Commit

Permalink
Add DisruptionTarget condition when preempting for critical pod
Browse files Browse the repository at this point in the history
Manually modified the commit to expect Failed phase instead of Succeeded.
This is expected in 1.26 as the code in preemption.go sets it to Failed.
In 1.27 the phase is determined by `getPhase` kubelet_pods.go based
on the completed containers.
  • Loading branch information
mimowo committed May 29, 2023
1 parent 4dfe380 commit b935de6
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 0 deletions.
11 changes: 11 additions & 0 deletions pkg/kubelet/preemption/preemption.go
Expand Up @@ -21,10 +21,13 @@ import (
"math"

v1 "k8s.io/api/core/v1"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/tools/record"
"k8s.io/klog/v2"
podutil "k8s.io/kubernetes/pkg/api/v1/pod"
"k8s.io/kubernetes/pkg/api/v1/resource"
v1qos "k8s.io/kubernetes/pkg/apis/core/v1/helper/qos"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/kubelet/events"
"k8s.io/kubernetes/pkg/kubelet/eviction"
"k8s.io/kubernetes/pkg/kubelet/lifecycle"
Expand Down Expand Up @@ -103,6 +106,14 @@ func (c *CriticalPodAdmissionHandler) evictPodsToFreeRequests(admitPod *v1.Pod,
status.Phase = v1.PodFailed
status.Reason = events.PreemptContainer
status.Message = message
if utilfeature.DefaultFeatureGate.Enabled(features.PodDisruptionConditions) {
podutil.UpdatePodCondition(status, &v1.PodCondition{
Type: v1.DisruptionTarget,
Status: v1.ConditionTrue,
Reason: v1.PodReasonTerminationByKubelet,
Message: "Pod was preempted by Kubelet to accommodate a critical pod.",
})
}
})
if err != nil {
klog.ErrorS(err, "Failed to evict pod", "pod", klog.KObj(pod))
Expand Down
44 changes: 44 additions & 0 deletions test/e2e_node/critical_pod_test.go
Expand Up @@ -23,6 +23,7 @@ import (
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/klog/v2"
kubeapi "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/scheduling"
kubelettypes "k8s.io/kubernetes/pkg/kubelet/types"
Expand Down Expand Up @@ -87,6 +88,49 @@ var _ = SIGDescribe("CriticalPod [Serial] [Disruptive] [NodeFeature:CriticalPod]
}
}
})

ginkgo.It("should add DisruptionTarget condition to the preempted pod [NodeFeature:PodDisruptionConditions]", func() {
// because adminssion Priority enable, If the priority class is not found, the Pod is rejected.
node := getNodeName(f)
nonCriticalGuaranteed := getTestPod(false, guaranteedPodName, v1.ResourceRequirements{
Requests: v1.ResourceList{
v1.ResourceCPU: resource.MustParse("100m"),
v1.ResourceMemory: resource.MustParse("100Mi"),
},
Limits: v1.ResourceList{
v1.ResourceCPU: resource.MustParse("100m"),
v1.ResourceMemory: resource.MustParse("100Mi"),
},
}, node)

criticalPod := getTestPod(true, criticalPodName, v1.ResourceRequirements{
// request the entire resource capacity of the node, so that
// admitting this pod requires the other pod to be preempted
Requests: getNodeCPUAndMemoryCapacity(f),
}, node)
criticalPod.Namespace = kubeapi.NamespaceSystem

ginkgo.By(fmt.Sprintf("create the non-critical pod %q", klog.KObj(nonCriticalGuaranteed)))
e2epod.NewPodClient(f).CreateSync(nonCriticalGuaranteed)

ginkgo.By(fmt.Sprintf("create the critical pod %q", klog.KObj(criticalPod)))
e2epod.PodClientNS(f, kubeapi.NamespaceSystem).Create(criticalPod)

ginkgo.By(fmt.Sprintf("await for the critical pod %q to be ready", klog.KObj(criticalPod)))
err := e2epod.WaitForPodNameRunningInNamespace(f.ClientSet, criticalPod.Name, kubeapi.NamespaceSystem)
framework.ExpectNoError(err, "Failed to await for the pod to be running: %q", klog.KObj(criticalPod))

// Check that non-critical pods other than the besteffort have been evicted
updatedPodList, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).List(context.TODO(), metav1.ListOptions{})
framework.ExpectNoError(err)
for _, p := range updatedPodList.Items {
ginkgo.By(fmt.Sprintf("verify that the non-critical pod %q is preempted and has the DisruptionTarget condition", klog.KObj(&p)))
framework.ExpectEqual(p.Status.Phase, v1.PodFailed, fmt.Sprintf("pod: %v should be preempted with status: %#v", p.Name, p.Status))
if condition := e2epod.FindPodConditionByType(&p.Status, v1.DisruptionTarget); condition == nil {
framework.Failf("pod %q should have the condition: %q, pod status: %v", klog.KObj(&p), v1.DisruptionTarget, p.Status)
}
}
})
ginkgo.AfterEach(func() {
// Delete Pods
e2epod.NewPodClient(f).DeleteSync(guaranteedPodName, metav1.DeleteOptions{}, e2epod.DefaultPodDeletionTimeout)
Expand Down

0 comments on commit b935de6

Please sign in to comment.