@@ -474,6 +474,82 @@ var _ = SIGDescribe("Restart", framework.WithSerial(), framework.WithSlow(), fra
474
474
return checkMirrorPodDisappear (ctx , f .ClientSet , pod .Name , pod .Namespace )
475
475
}, f .Timeouts .PodDelete , f .Timeouts .Poll ).Should (gomega .BeNil ())
476
476
})
477
+ // Regression test for an extended scenario for https://issues.k8s.io/123980
478
+ ginkgo .It ("should evict running pods that do not meet the affinity after the kubelet restart" , func (ctx context.Context ) {
479
+ nodeLabelKey := string (uuid .NewUUID ())
480
+ nodeLabelValueRequired := string (uuid .NewUUID ())
481
+ podName := "affinity-pod" + string (uuid .NewUUID ())
482
+ nodeName := getNodeName (ctx , f )
483
+
484
+ ginkgo .By (fmt .Sprintf ("Adding node label for node (%s) to satisify pod (%s/%s) affinity" , nodeName , f .Namespace .Name , podName ))
485
+ e2enode .AddOrUpdateLabelOnNode (f .ClientSet , nodeName , nodeLabelKey , nodeLabelValueRequired )
486
+ ginkgo .DeferCleanup (func () { e2enode .RemoveLabelOffNode (f .ClientSet , nodeName , nodeLabelKey ) })
487
+
488
+ pod := e2epod .MustMixinRestrictedPodSecurity (& v1.Pod {
489
+ ObjectMeta : metav1.ObjectMeta {
490
+ Name : podName ,
491
+ Namespace : f .Namespace .Name ,
492
+ },
493
+ Spec : v1.PodSpec {
494
+ Affinity : & v1.Affinity {
495
+ NodeAffinity : & v1.NodeAffinity {
496
+ RequiredDuringSchedulingIgnoredDuringExecution : & v1.NodeSelector {
497
+ NodeSelectorTerms : []v1.NodeSelectorTerm {
498
+ {
499
+ MatchExpressions : []v1.NodeSelectorRequirement {
500
+ {
501
+ Key : nodeLabelKey ,
502
+ Operator : v1 .NodeSelectorOpIn ,
503
+ Values : []string {nodeLabelValueRequired },
504
+ },
505
+ },
506
+ },
507
+ },
508
+ },
509
+ },
510
+ },
511
+ Containers : []v1.Container {
512
+ {
513
+ Name : podName ,
514
+ Image : imageutils .GetPauseImageName (),
515
+ },
516
+ },
517
+ },
518
+ })
519
+
520
+ // Create the pod bound to the node. It will start, but will be rejected after kubelet restart.
521
+ ginkgo .By (fmt .Sprintf ("Creating a pod (%s/%s)" , f .Namespace .Name , podName ))
522
+ e2epod .NewPodClient (f ).Create (ctx , pod )
523
+
524
+ ginkgo .By (fmt .Sprintf ("Waiting for the pod (%s/%s) to be running" , f .Namespace .Name , pod .Name ))
525
+ err := e2epod .WaitForPodNameRunningInNamespace (ctx , f .ClientSet , pod .Name , f .Namespace .Name )
526
+ framework .ExpectNoError (err , "Failed to await for the pod to be running: (%v/%v)" , f .Namespace .Name , pod .Name )
527
+
528
+ // Remove node label
529
+ e2enode .RemoveLabelOffNode (f .ClientSet , nodeName , nodeLabelKey )
530
+
531
+ ginkgo .By ("Restart the kubelet" )
532
+ restartKubelet (true )
533
+ gomega .Eventually (ctx , func () bool {
534
+ return kubeletHealthCheck (kubeletHealthCheckURL )
535
+ }, recoverTimeout , f .Timeouts .Poll ).
536
+ Should (gomega .BeTrueBecause ("kubelet should be healthy after restart" ))
537
+
538
+ // Pod should be terminated, maybe not immediately, should allow a few seconds for the kubelet to kill the pod
539
+ // after kubelet restart, pod admission denied, kubelet will reject the pod and kill container.
540
+ gomega .Eventually (ctx , func () bool {
541
+ pod , err = e2epod .NewPodClient (f ).Get (ctx , podName , metav1.GetOptions {})
542
+ framework .ExpectNoError (err )
543
+ // pod is in a final state, the following are the behaviors of pods after kubelet restarted:
544
+ // 1. kubelet `canAdmitPod` reject pod by reason Pod admission denied by nodeAffinity
545
+ // 2. kubelet stop/kill container
546
+ // the final state of the pod is related to the kill container.
547
+ // if an error occurs in the preStop of the container or the exitCode is not 0,
548
+ // the phase is PodFailed. if the exitCode of the StopContainer is 0, the phase is PodSucceeded.
549
+ // in this case, stop and kill container is successful(exitCode 0), the pod phase should be PodSucceeded.
550
+ return pod .Status .Phase == v1 .PodSucceeded
551
+ }, recoverTimeout , f .Timeouts .Poll ).Should (gomega .BeTrueBecause ("Pod %s not terminated: %s" , pod .Name , pod .Status .Phase ))
552
+ })
477
553
})
478
554
479
555
})
0 commit comments