@@ -30,6 +30,7 @@ import (
30
30
kresource "k8s.io/apimachinery/pkg/api/resource"
31
31
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32
32
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
33
+ "k8s.io/utils/ptr"
33
34
"sigs.k8s.io/controller-runtime/pkg/client"
34
35
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
35
36
"sigs.k8s.io/controller-runtime/pkg/log"
@@ -108,7 +109,7 @@ func hasResourceRequest(spec map[string]interface{}, resource string) bool {
108
109
return false
109
110
}
110
111
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 {
112
113
if _ , ok := spec ["affinity" ]; ! ok {
113
114
spec ["affinity" ] = map [string ]interface {}{}
114
115
}
@@ -123,44 +124,64 @@ func addNodeSelectorsToAffinity(spec map[string]interface{}, exprsToAdd []v1.Nod
123
124
if ! ok {
124
125
return fmt .Errorf ("spec.affinity.nodeAffinity is not a map" )
125
126
}
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 {})
142
132
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" )
144
134
}
145
- if _ , ok := selTerm [ "matchExpressions " ]; ! ok {
146
- selTerm [ "matchExpressions " ] = []interface {}{}
135
+ if _ , ok := nodeSelector [ "nodeSelectorTerms " ]; ! ok {
136
+ nodeSelector [ "nodeSelectorTerms " ] = []interface {}{map [ string ] interface {}{} }
147
137
}
148
- matchExpressions , ok := selTerm [ "matchExpressions " ].([]interface {})
138
+ existingTerms , ok := nodeSelector [ "nodeSelectorTerms " ].([]interface {})
149
139
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" )
151
141
}
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 )
156
146
}
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 {}{}
160
149
}
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 {}{}
162
170
}
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
164
185
}
165
186
166
187
return nil
@@ -291,20 +312,35 @@ func (r *AppWrapperReconciler) createComponent(ctx context.Context, aw *workload
291
312
}
292
313
293
314
if r .Config .Autopilot != nil && r .Config .Autopilot .InjectAntiAffinities {
294
- toAdd := map [string ][]string {}
315
+ toAddRequired := map [string ][]string {}
316
+ toAddPreferred := map [string ][]string {}
295
317
for resource , taints := range r .Config .Autopilot .ResourceTaints {
296
318
if hasResourceRequest (spec , resource ) {
297
319
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
+ }
299
325
}
300
326
}
301
327
}
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 {
303
338
matchExpressions := []v1.NodeSelectorRequirement {}
304
- for k , v := range toAdd {
339
+ for k , v := range toAddPreferred {
305
340
matchExpressions = append (matchExpressions , v1.NodeSelectorRequirement {Operator : v1 .NodeSelectorOpNotIn , Key : k , Values : v })
306
341
}
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 {
308
344
log .FromContext (ctx ).Error (err , "failed to inject Autopilot affinities" )
309
345
}
310
346
}
@@ -315,6 +351,8 @@ func (r *AppWrapperReconciler) createComponent(ctx context.Context, aw *workload
315
351
return err , true
316
352
}
317
353
354
+ log .FromContext (ctx ).Info ("After injection" , "obj" , obj )
355
+
318
356
orig := copyForStatusPatch (aw )
319
357
if meta .FindStatusCondition (aw .Status .ComponentStatus [componentIdx ].Conditions , string (workloadv1beta2 .ResourcesDeployed )) == nil {
320
358
aw .Status .ComponentStatus [componentIdx ].Name = obj .GetName ()
0 commit comments