@@ -30,6 +30,7 @@ import (
3030 kresource "k8s.io/apimachinery/pkg/api/resource"
3131 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3232 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
33+ "k8s.io/utils/ptr"
3334 "sigs.k8s.io/controller-runtime/pkg/client"
3435 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
3536 "sigs.k8s.io/controller-runtime/pkg/log"
@@ -108,7 +109,7 @@ func hasResourceRequest(spec map[string]interface{}, resource string) bool {
108109 return false
109110}
110111
111- func addNodeSelectorsToAffinity (spec map [string ]interface {}, exprsToAdd []v1.NodeSelectorRequirement ) error {
112+ func addNodeSelectorsToAffinity (spec map [string ]interface {}, exprsToAdd []v1.NodeSelectorRequirement , required bool , weight int32 ) error {
112113 if _ , ok := spec ["affinity" ]; ! ok {
113114 spec ["affinity" ] = map [string ]interface {}{}
114115 }
@@ -123,44 +124,64 @@ func addNodeSelectorsToAffinity(spec map[string]interface{}, exprsToAdd []v1.Nod
123124 if ! ok {
124125 return fmt .Errorf ("spec.affinity.nodeAffinity is not a map" )
125126 }
126- if _ , ok := nodeAffinity ["requiredDuringSchedulingIgnoredDuringExecution" ]; ! ok {
127- nodeAffinity ["requiredDuringSchedulingIgnoredDuringExecution" ] = map [string ]interface {}{}
128- }
129- nodeSelector , ok := nodeAffinity ["requiredDuringSchedulingIgnoredDuringExecution" ].(map [string ]interface {})
130- if ! ok {
131- return fmt .Errorf ("spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution is not a map" )
132- }
133- if _ , ok := nodeSelector ["nodeSelectorTerms" ]; ! ok {
134- nodeSelector ["nodeSelectorTerms" ] = []interface {}{map [string ]interface {}{}}
135- }
136- existingTerms , ok := nodeSelector ["nodeSelectorTerms" ].([]interface {})
137- if ! ok {
138- return fmt .Errorf ("spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms is not an array" )
139- }
140- for idx , term := range existingTerms {
141- selTerm , ok := term .(map [string ]interface {})
127+ if required {
128+ if _ , ok := nodeAffinity ["requiredDuringSchedulingIgnoredDuringExecution" ]; ! ok {
129+ nodeAffinity ["requiredDuringSchedulingIgnoredDuringExecution" ] = map [string ]interface {}{}
130+ }
131+ nodeSelector , ok := nodeAffinity ["requiredDuringSchedulingIgnoredDuringExecution" ].(map [string ]interface {})
142132 if ! ok {
143- return fmt .Errorf ("spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[%v] is not an map" , idx )
133+ return fmt .Errorf ("spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution is not a map" )
144134 }
145- if _ , ok := selTerm [ "matchExpressions " ]; ! ok {
146- selTerm [ "matchExpressions " ] = []interface {}{}
135+ if _ , ok := nodeSelector [ "nodeSelectorTerms " ]; ! ok {
136+ nodeSelector [ "nodeSelectorTerms " ] = []interface {}{map [ string ] interface {}{} }
147137 }
148- matchExpressions , ok := selTerm [ "matchExpressions " ].([]interface {})
138+ existingTerms , ok := nodeSelector [ "nodeSelectorTerms " ].([]interface {})
149139 if ! ok {
150- return fmt .Errorf ("spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[%v].matchExpressions is not an map" , idx )
140+ return fmt .Errorf ("spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms is not an array" )
151141 }
152- for _ , expr := range exprsToAdd {
153- bytes , err := json . Marshal ( expr )
154- if err != nil {
155- return fmt .Errorf ("marshalling selectorTerm %v: %w " , expr , err )
142+ for idx , term := range existingTerms {
143+ selTerm , ok := term .( map [ string ] interface {} )
144+ if ! ok {
145+ return fmt .Errorf ("spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[%v] is not an map " , idx )
156146 }
157- var obj interface {}
158- if err = json .Unmarshal (bytes , & obj ); err != nil {
159- return fmt .Errorf ("unmarshalling selectorTerm %v: %w" , expr , err )
147+ if _ , ok := selTerm ["matchExpressions" ]; ! ok {
148+ selTerm ["matchExpressions" ] = []interface {}{}
160149 }
161- matchExpressions = append (matchExpressions , obj )
150+ matchExpressions , ok := selTerm ["matchExpressions" ].([]interface {})
151+ if ! ok {
152+ return fmt .Errorf ("spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[%v].matchExpressions is not an map" , idx )
153+ }
154+ for _ , expr := range exprsToAdd {
155+ bytes , err := json .Marshal (expr )
156+ if err != nil {
157+ return fmt .Errorf ("marshalling selectorTerm %v: %w" , expr , err )
158+ }
159+ var obj interface {}
160+ if err = json .Unmarshal (bytes , & obj ); err != nil {
161+ return fmt .Errorf ("unmarshalling selectorTerm %v: %w" , expr , err )
162+ }
163+ matchExpressions = append (matchExpressions , obj )
164+ }
165+ selTerm ["matchExpressions" ] = matchExpressions
166+ }
167+ } else {
168+ if _ , ok := nodeAffinity ["preferredDuringSchedulingIgnoredDuringExecution" ]; ! ok {
169+ nodeAffinity ["preferredDuringSchedulingIgnoredDuringExecution" ] = []interface {}{}
162170 }
163- selTerm ["matchExpressions" ] = matchExpressions
171+ terms , ok := nodeAffinity ["preferredDuringSchedulingIgnoredDuringExecution" ].([]interface {})
172+ if ! ok {
173+ return fmt .Errorf ("spec.affinity.nodeAffinity.preferredDuringSchedulingIgnoredDuringExecution is not an array" )
174+ }
175+ bytes , err := json .Marshal (v1.PreferredSchedulingTerm {Weight : weight , Preference : v1.NodeSelectorTerm {MatchExpressions : exprsToAdd }})
176+ if err != nil {
177+ return fmt .Errorf ("marshalling selectorTerms %v: %w" , exprsToAdd , err )
178+ }
179+ var obj interface {}
180+ if err = json .Unmarshal (bytes , & obj ); err != nil {
181+ return fmt .Errorf ("unmarshalling selectorTerms %v: %w" , exprsToAdd , err )
182+ }
183+ terms = append (terms , obj )
184+ nodeAffinity ["preferredDuringSchedulingIgnoredDuringExecution" ] = terms
164185 }
165186
166187 return nil
@@ -291,20 +312,35 @@ func (r *AppWrapperReconciler) createComponent(ctx context.Context, aw *workload
291312 }
292313
293314 if r .Config .Autopilot != nil && r .Config .Autopilot .InjectAntiAffinities {
294- toAdd := map [string ][]string {}
315+ toAddRequired := map [string ][]string {}
316+ toAddPreferred := map [string ][]string {}
295317 for resource , taints := range r .Config .Autopilot .ResourceTaints {
296318 if hasResourceRequest (spec , resource ) {
297319 for _ , taint := range taints {
298- toAdd [taint .Key ] = append (toAdd [taint .Key ], taint .Value )
320+ if taint .Effect == v1 .TaintEffectNoExecute || taint .Effect == v1 .TaintEffectNoSchedule {
321+ toAddRequired [taint .Key ] = append (toAddRequired [taint .Key ], taint .Value )
322+ } else if taint .Effect == v1 .TaintEffectPreferNoSchedule {
323+ toAddPreferred [taint .Key ] = append (toAddPreferred [taint .Key ], taint .Value )
324+ }
299325 }
300326 }
301327 }
302- if len (toAdd ) > 0 {
328+ if len (toAddRequired ) > 0 {
329+ matchExpressions := []v1.NodeSelectorRequirement {}
330+ for k , v := range toAddRequired {
331+ matchExpressions = append (matchExpressions , v1.NodeSelectorRequirement {Operator : v1 .NodeSelectorOpNotIn , Key : k , Values : v })
332+ }
333+ if err := addNodeSelectorsToAffinity (spec , matchExpressions , true , 0 ); err != nil {
334+ log .FromContext (ctx ).Error (err , "failed to inject Autopilot affinities" )
335+ }
336+ }
337+ if len (toAddPreferred ) > 0 {
303338 matchExpressions := []v1.NodeSelectorRequirement {}
304- for k , v := range toAdd {
339+ for k , v := range toAddPreferred {
305340 matchExpressions = append (matchExpressions , v1.NodeSelectorRequirement {Operator : v1 .NodeSelectorOpNotIn , Key : k , Values : v })
306341 }
307- if err := addNodeSelectorsToAffinity (spec , matchExpressions ); err != nil {
342+ weight := ptr .Deref (r .Config .Autopilot .PreferNoScheduleWeight , 1 )
343+ if err := addNodeSelectorsToAffinity (spec , matchExpressions , false , weight ); err != nil {
308344 log .FromContext (ctx ).Error (err , "failed to inject Autopilot affinities" )
309345 }
310346 }
@@ -315,6 +351,8 @@ func (r *AppWrapperReconciler) createComponent(ctx context.Context, aw *workload
315351 return err , true
316352 }
317353
354+ log .FromContext (ctx ).Info ("After injection" , "obj" , obj )
355+
318356 orig := copyForStatusPatch (aw )
319357 if meta .FindStatusCondition (aw .Status .ComponentStatus [componentIdx ].Conditions , string (workloadv1beta2 .ResourcesDeployed )) == nil {
320358 aw .Status .ComponentStatus [componentIdx ].Name = obj .GetName ()
0 commit comments