@@ -23,6 +23,7 @@ import (
2323 . "github.com/onsi/gomega"
2424 v1 "k8s.io/api/core/v1"
2525 "k8s.io/apimachinery/pkg/api/meta"
26+ "k8s.io/apimachinery/pkg/api/resource"
2627 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2728 "k8s.io/apimachinery/pkg/types"
2829 "k8s.io/client-go/tools/record"
@@ -63,6 +64,8 @@ var _ = Describe("AppWrapper Controller", func() {
6364 awConfig .FaultTolerance .RetryPausePeriod = 0 * time .Second
6465 awConfig .FaultTolerance .RetryLimit = 0
6566 awConfig .FaultTolerance .SuccessTTL = 0 * time .Second
67+ awConfig .Autopilot .ResourceTaints ["nvidia.com/gpu" ] = append (awConfig .Autopilot .ResourceTaints ["nvidia.com/gpu" ], v1.Taint {Key : "extra" , Value : "test" , Effect : v1 .TaintEffectNoExecute })
68+
6669 awReconciler = & AppWrapperReconciler {
6770 Client : k8sClient ,
6871 Recorder : & record.FakeRecorder {},
@@ -156,6 +159,42 @@ var _ = Describe("AppWrapper Controller", func() {
156159 Expect (finished ).Should (BeFalse ())
157160 }
158161
162+ validateMarkers := func (p * v1.Pod ) {
163+ for k , v := range markerPodSet .Annotations {
164+ Expect (p .Annotations ).Should (HaveKeyWithValue (k , v ))
165+ }
166+ for k , v := range markerPodSet .Labels {
167+ Expect (p .Labels ).Should (HaveKeyWithValue (k , v ))
168+ }
169+ for _ , v := range markerPodSet .Tolerations {
170+ Expect (p .Spec .Tolerations ).Should (ContainElement (v ))
171+ }
172+ for k , v := range markerPodSet .NodeSelector {
173+ Expect (p .Spec .NodeSelector ).Should (HaveKeyWithValue (k , v ))
174+ }
175+ }
176+
177+ validateAutopilot := func (p * v1.Pod ) {
178+ if p .Spec .Containers [0 ].Resources .Requests .Name ("nvidia.com/gpu" , resource .DecimalSI ).IsZero () {
179+ Expect (p .Spec .Affinity ).Should (BeNil ())
180+ } else {
181+ Expect (p .Spec .Affinity .NodeAffinity .RequiredDuringSchedulingIgnoredDuringExecution ).ShouldNot (BeNil ())
182+ Expect (p .Spec .Affinity .NodeAffinity .RequiredDuringSchedulingIgnoredDuringExecution .NodeSelectorTerms ).Should (HaveLen (1 ))
183+ mes := p .Spec .Affinity .NodeAffinity .RequiredDuringSchedulingIgnoredDuringExecution .NodeSelectorTerms [0 ].MatchExpressions
184+ for _ , taint := range awReconciler .Config .Autopilot .ResourceTaints ["nvidia.com/gpu" ] {
185+ found := false
186+ for _ , me := range mes {
187+ if me .Key == taint .Key {
188+ Expect (me .Operator ).Should (Equal (v1 .NodeSelectorOpNotIn ))
189+ Expect (me .Values ).Should (ContainElement (taint .Value ))
190+ found = true
191+ }
192+ }
193+ Expect (found ).Should (BeTrue ())
194+ }
195+ }
196+ }
197+
159198 AfterEach (func () {
160199 By ("Cleanup the AppWrapper and ensure no Pods remain" )
161200 aw := & workloadv1beta2.AppWrapper {}
@@ -318,6 +357,54 @@ var _ = Describe("AppWrapper Controller", func() {
318357 Expect (err ).NotTo (HaveOccurred ())
319358 Expect (podStatus .pending ).Should (Equal (int32 (1 )))
320359 })
360+
361+ It ("Validating PodSet Injection invariants on minimal pods" , func () {
362+ advanceToResuming (pod (100 , 0 , false ), pod (100 , 1 , true ))
363+ beginRunning ()
364+ aw := getAppWrapper (awName )
365+ pods := getPods (aw )
366+ Expect (pods ).Should (HaveLen (2 ))
367+
368+ By ("Validate expected markers and Autopilot anti-affinities were injected" )
369+ for _ , p := range pods {
370+ Expect (p .Labels ).Should (HaveKeyWithValue (AppWrapperLabel , awName .Name ))
371+ validateMarkers (& p )
372+ validateAutopilot (& p )
373+ }
374+ })
375+
376+ It ("Validating PodSet Injection invariants on complex pods" , func () {
377+ advanceToResuming (complexPodYaml (), complexPodYaml ())
378+ beginRunning ()
379+ aw := getAppWrapper (awName )
380+ pods := getPods (aw )
381+ Expect (pods ).Should (HaveLen (2 ))
382+
383+ By ("Validate expected markers and Autopilot anti-affinities were injected" )
384+ for _ , p := range pods {
385+ Expect (p .Labels ).Should (HaveKeyWithValue (AppWrapperLabel , awName .Name ))
386+ validateMarkers (& p )
387+ validateAutopilot (& p )
388+ }
389+
390+ By ("Validate complex pod elements were not removed" )
391+ for _ , p := range pods {
392+ Expect (p .Labels ).Should (HaveKeyWithValue ("myComplexLabel" , "myComplexValue" ))
393+ Expect (p .Annotations ).Should (HaveKeyWithValue ("myComplexAnnotation" , "myComplexValue" ))
394+ Expect (p .Spec .NodeSelector ).Should (HaveKeyWithValue ("myComplexSelector" , "myComplexValue" ))
395+ Expect (p .Spec .Tolerations ).Should (ContainElement (v1.Toleration {Key : "myComplexKey" , Value : "myComplexValue" , Operator : v1 .TolerationOpEqual , Effect : v1 .TaintEffectNoSchedule }))
396+ mes := p .Spec .Affinity .NodeAffinity .RequiredDuringSchedulingIgnoredDuringExecution .NodeSelectorTerms [0 ].MatchExpressions
397+ found := false
398+ for _ , me := range mes {
399+ if me .Key == "kubernetes.io/hostname" {
400+ Expect (me .Operator ).Should (Equal (v1 .NodeSelectorOpNotIn ))
401+ Expect (me .Values ).Should (ContainElement ("badHost1" ))
402+ found = true
403+ }
404+ }
405+ Expect (found ).Should (BeTrue ())
406+ }
407+ })
321408})
322409
323410var _ = Describe ("AppWrapper Annotations" , func () {
@@ -433,5 +520,4 @@ var _ = Describe("AppWrapper Annotations", func() {
433520 Expect (awReconciler .terminalExitCodes (ctx , aw )).Should (Equal ([]int {3 , 10 , 42 }))
434521 Expect (awReconciler .retryableExitCodes (ctx , aw )).Should (Equal ([]int {10 , 20 }))
435522 })
436-
437523})
0 commit comments