@@ -19,14 +19,40 @@ package ctrl
1919import (
2020 datav1alpha1 "github.com/fluid-cloudnative/fluid/api/v1alpha1"
2121 "github.com/fluid-cloudnative/fluid/pkg/common"
22+ "github.com/fluid-cloudnative/fluid/pkg/types/cacheworkerset"
2223 "github.com/fluid-cloudnative/fluid/pkg/utils"
24+ openkruise "github.com/openkruise/kruise/apis/apps/v1beta1"
2325
24- appsv1 "k8s.io/api/apps/v1"
2526 corev1 "k8s.io/api/core/v1"
2627 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2728)
2829
29- func (e * Helper ) checkWorkerAffinity (workers * appsv1.StatefulSet ) (found bool ) {
30+ func (e * Helper ) checkWorkerAffinity (workers * cacheworkerset.CacheWorkerSet ) (found bool ) {
31+
32+ if workers .GetAffinity () == nil {
33+ return
34+ }
35+
36+ if workers .GetNodeAffinity () == nil {
37+ return
38+ }
39+
40+ if len (workers .GetNodeAffinityPreferredDuringSchedulingIgnoredDuringExecution ()) == 0 {
41+ return
42+ }
43+
44+ for _ , preferred := range workers .GetNodeAffinityPreferredDuringSchedulingIgnoredDuringExecution () {
45+ for _ , term := range preferred .Preference .MatchExpressions {
46+ if term .Key == e .runtimeInfo .GetFuseLabelName () {
47+ found = true
48+ return
49+ }
50+ }
51+ }
52+
53+ return
54+ }
55+ func (e * Helper ) checkWorkerAffinityForAts (workers * openkruise.StatefulSet ) (found bool ) {
3056
3157 if workers .Spec .Template .Spec .Affinity == nil {
3258 return
@@ -52,12 +78,14 @@ func (e *Helper) checkWorkerAffinity(workers *appsv1.StatefulSet) (found bool) {
5278 return
5379}
5480
55- // BuildWorkersAffinity builds workers affinity if it doesn't have
56- func (e * Helper ) BuildWorkersAffinity (workers * appsv1.StatefulSet ) (workersToUpdate * appsv1.StatefulSet , err error ) {
57- // TODO: for now, runtime affinity can't be set by user, so we can assume the affinity is nil in the first time.
58- // We need to enhance it in future
59- workersToUpdate = workers .DeepCopy ()
60- if e .checkWorkerAffinity (workersToUpdate ) {
81+ func (e * Helper ) BuildCacheWorkersAffinity (workers * cacheworkerset.CacheWorkerSet ) (workersToUpdate * cacheworkerset.CacheWorkerSet , err error ) {
82+ returnV , err := e .BuildWorkersAffinity (workers )
83+ return returnV , err
84+ }
85+
86+ func (e * Helper ) BuildWorkersAffinityForAsts (workers * openkruise.StatefulSet ) (workersToUpdate * openkruise.StatefulSet , err error ) {
87+
88+ if e .checkWorkerAffinityForAts (workersToUpdate ) {
6189 return
6290 }
6391 var (
@@ -168,3 +196,145 @@ func (e *Helper) BuildWorkersAffinity(workers *appsv1.StatefulSet) (workersToUpd
168196
169197 return
170198}
199+
200+ // BuildWorkersAffinity builds workers affinity if it doesn't have
201+ func (e * Helper ) BuildWorkersAffinity (workers * cacheworkerset.CacheWorkerSet ) (workersToUpdate * cacheworkerset.CacheWorkerSet , err error ) {
202+ // TODO: for now, runtime affinity can't be set by user, so we can assume the affinity is nil in the first time.
203+ // We need to enhance it in future
204+
205+ if e .checkWorkerAffinity (workersToUpdate ) {
206+ return
207+ }
208+ var (
209+ name = e .runtimeInfo .GetName ()
210+ namespace = e .runtimeInfo .GetNamespace ()
211+ )
212+
213+ if workersToUpdate .GetAffinity () == nil {
214+ affinity := & corev1.Affinity {}
215+ workersToUpdate .SetAffinity (affinity )
216+ dataset , err := utils .GetDataset (e .client , name , namespace )
217+ if err != nil {
218+ return workersToUpdate , err
219+ }
220+ // 1. Set pod anti affinity(required) for same dataset (Current using port conflict for scheduling, no need to do)
221+
222+ // 2. Set pod anti affinity for the different dataset
223+ if dataset .IsExclusiveMode () {
224+ podAntiAffinity := & corev1.PodAntiAffinity {
225+ RequiredDuringSchedulingIgnoredDuringExecution : []corev1.PodAffinityTerm {
226+ {
227+ LabelSelector : & metav1.LabelSelector {
228+ MatchExpressions : []metav1.LabelSelectorRequirement {
229+ {
230+ Key : "fluid.io/dataset" ,
231+ Operator : metav1 .LabelSelectorOpExists ,
232+ },
233+ },
234+ },
235+ TopologyKey : "kubernetes.io/hostname" ,
236+ },
237+ },
238+ }
239+ workersToUpdate .SetPodAntiAffinity (podAntiAffinity )
240+
241+ } else {
242+ podAntiAffinity := & corev1.PodAntiAffinity {
243+ PreferredDuringSchedulingIgnoredDuringExecution : []corev1.WeightedPodAffinityTerm {
244+ {
245+ // The default weight is 50
246+ Weight : 50 ,
247+ PodAffinityTerm : corev1.PodAffinityTerm {
248+ LabelSelector : & metav1.LabelSelector {
249+ MatchExpressions : []metav1.LabelSelectorRequirement {
250+ {
251+ Key : "fluid.io/dataset" ,
252+ Operator : metav1 .LabelSelectorOpExists ,
253+ },
254+ },
255+ },
256+ TopologyKey : "kubernetes.io/hostname" ,
257+ },
258+ },
259+ },
260+
261+ RequiredDuringSchedulingIgnoredDuringExecution : []corev1.PodAffinityTerm {
262+ {
263+ LabelSelector : & metav1.LabelSelector {
264+ MatchExpressions : []metav1.LabelSelectorRequirement {
265+ {
266+ Key : "fluid.io/dataset-placement" ,
267+ Operator : metav1 .LabelSelectorOpIn ,
268+ Values : []string {string (datav1alpha1 .ExclusiveMode )},
269+ },
270+ },
271+ },
272+ TopologyKey : "kubernetes.io/hostname" ,
273+ },
274+ },
275+ }
276+ workersToUpdate .SetPodAntiAffinity (podAntiAffinity )
277+
278+ // TODO: remove this when EFC is ready for spread-first scheduling policy
279+ // Currently EFC prefers binpack-first scheduling policy to spread-first scheduling policy. Set PreferredDuringSchedulingIgnoredDuringExecution to empty
280+ // to avoid using spread-first scheduling policy
281+ if e .runtimeInfo .GetRuntimeType () == common .EFCRuntime {
282+ preferredDuringSchedulingIgnoredDuringExecution := []corev1.WeightedPodAffinityTerm {}
283+ workersToUpdate .SetPodAntiAffinityPreferredDuringSchedulingIgnoredDuringExecution (preferredDuringSchedulingIgnoredDuringExecution )
284+
285+ }
286+ }
287+
288+ // 3. Prefer to locate on the node which already has fuse on it
289+ if workersToUpdate .GetNodeAffinity () == nil {
290+ NodeAffinity := & corev1.NodeAffinity {}
291+ workersToUpdate .SetNodeAffinity (NodeAffinity )
292+
293+ }
294+
295+ if len (workersToUpdate .GetNodeAffinityPreferredDuringSchedulingIgnoredDuringExecution ()) == 0 {
296+
297+ PreferredDuringSchedulingIgnoredDuringExecution := []corev1.PreferredSchedulingTerm {}
298+ workersToUpdate .SetNodeAffinityPreferredDuringSchedulingIgnoredDuringExecution (PreferredDuringSchedulingIgnoredDuringExecution )
299+
300+ }
301+
302+ //workersToUpdate.Spec.Template.Spec.Affinity.NodeAffinity.PreferredDuringSchedulingIgnoredDuringExecution =
303+ // append(workersToUpdate.Spec.Template.Spec.Affinity.NodeAffinity.PreferredDuringSchedulingIgnoredDuringExecution,
304+ // corev1.PreferredSchedulingTerm{
305+ // Weight: 100,
306+ // Preference: corev1.NodeSelectorTerm{
307+ // MatchExpressions: []corev1.NodeSelectorRequirement{
308+ // {
309+ // Key: e.runtimeInfo.GetFuseLabelName(),
310+ // Operator: corev1.NodeSelectorOpIn,
311+ // Values: []string{"true"},
312+ // },
313+ // },
314+ // },
315+ // })
316+ PreferredDuringSchedulingIgnoredDuringExecution := corev1.PreferredSchedulingTerm {
317+ Weight : 100 ,
318+ Preference : corev1.NodeSelectorTerm {
319+ MatchExpressions : []corev1.NodeSelectorRequirement {
320+ {
321+ Key : e .runtimeInfo .GetFuseLabelName (),
322+ Operator : corev1 .NodeSelectorOpIn ,
323+ Values : []string {"true" },
324+ },
325+ },
326+ },
327+ }
328+ workersToUpdate .AppendNodeAffinityPreferredDuringSchedulingIgnoredDuringExecution (PreferredDuringSchedulingIgnoredDuringExecution )
329+
330+ // 3. set node affinity if possible
331+ if dataset .Spec .NodeAffinity != nil {
332+ if dataset .Spec .NodeAffinity .Required != nil {
333+ workersToUpdate .SetNodeAffinityRequired (dataset .Spec .NodeAffinity .Required )
334+
335+ }
336+ }
337+ }
338+
339+ return
340+ }
0 commit comments