github.com/kubewharf/katalyst-core@v0.5.3/pkg/scheduler/plugins/qosawarenoderesources/fit_test.go (about) 1 /* 2 Copyright 2022 The Katalyst Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package qosawarenoderesources 18 19 import ( 20 "context" 21 "fmt" 22 "testing" 23 24 "github.com/stretchr/testify/assert" 25 v1 "k8s.io/api/core/v1" 26 "k8s.io/apimachinery/pkg/api/resource" 27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 "k8s.io/apimachinery/pkg/types" 29 kubeschedulerconfig "k8s.io/kubernetes/pkg/scheduler/apis/config" 30 "k8s.io/kubernetes/pkg/scheduler/framework" 31 32 apis "github.com/kubewharf/katalyst-api/pkg/apis/node/v1alpha1" 33 "github.com/kubewharf/katalyst-api/pkg/apis/scheduling/config" 34 "github.com/kubewharf/katalyst-api/pkg/consts" 35 "github.com/kubewharf/katalyst-core/pkg/config/generic" 36 "github.com/kubewharf/katalyst-core/pkg/scheduler/cache" 37 "github.com/kubewharf/katalyst-core/pkg/scheduler/util" 38 "github.com/kubewharf/katalyst-core/pkg/util/native" 39 ) 40 41 var makeFit = func(scoringStrategyType kubeschedulerconfig.ScoringStrategyType) (framework.Plugin, error) { 42 return NewFit(&config.QoSAwareNodeResourcesFitArgs{ 43 ScoringStrategy: &config.ScoringStrategy{ 44 Type: scoringStrategyType, 45 Resources: []kubeschedulerconfig.ResourceSpec{ 46 { 47 Name: fmt.Sprintf("%s", v1.ResourceCPU), 48 Weight: 30, 49 }, 50 { 51 Name: fmt.Sprintf("%s", v1.ResourceMemory), 52 Weight: 70, 53 }, 54 }, 55 ReclaimedResources: []kubeschedulerconfig.ResourceSpec{ 56 { 57 Name: fmt.Sprintf("%s", consts.ReclaimedResourceMilliCPU), 58 Weight: 30, 59 }, 60 { 61 Name: fmt.Sprintf("%s", consts.ReclaimedResourceMemory), 62 Weight: 70, 63 }, 64 }, 65 RequestedToCapacityRatio: &kubeschedulerconfig.RequestedToCapacityRatioParam{ 66 Shape: []kubeschedulerconfig.UtilizationShapePoint{ 67 { 68 Utilization: 10, 69 Score: 3, 70 }, 71 { 72 Utilization: 20, 73 Score: 4, 74 }, 75 { 76 Utilization: 50, 77 Score: 7, 78 }, 79 }, 80 }, 81 ReclaimedRequestedToCapacityRatio: &kubeschedulerconfig.RequestedToCapacityRatioParam{ 82 Shape: []kubeschedulerconfig.UtilizationShapePoint{ 83 { 84 Utilization: 10, 85 Score: 3, 86 }, 87 { 88 Utilization: 20, 89 Score: 4, 90 }, 91 { 92 Utilization: 50, 93 Score: 7, 94 }, 95 }, 96 }, 97 }, 98 }, nil) 99 } 100 101 var makeFitPod = func(uid types.UID, name string, res v1.ResourceList, node string) *v1.Pod { 102 pod := &v1.Pod{ 103 ObjectMeta: metav1.ObjectMeta{ 104 Namespace: "n1", 105 Name: name, 106 UID: uid, 107 Annotations: map[string]string{ 108 consts.PodAnnotationQoSLevelKey: consts.PodAnnotationQoSLevelReclaimedCores, 109 }, 110 }, 111 Spec: v1.PodSpec{ 112 Containers: []v1.Container{ 113 { 114 Name: "c1", 115 Resources: v1.ResourceRequirements{ 116 Limits: res, 117 Requests: res, 118 }, 119 }, 120 }, 121 NodeName: node, 122 }, 123 } 124 return pod 125 } 126 127 var makeFitNode = func(name string, pods []*v1.Pod, res v1.ResourceList) *framework.NodeInfo { 128 ni := framework.NewNodeInfo(pods...) 129 ni.SetNode(&v1.Node{ 130 ObjectMeta: metav1.ObjectMeta{ 131 Name: name, 132 }, 133 Status: v1.NodeStatus{ 134 Allocatable: res, 135 }, 136 }) 137 return ni 138 } 139 140 var makeFitCNR = func(name string, res v1.ResourceList) *apis.CustomNodeResource { 141 cnr := &apis.CustomNodeResource{ 142 ObjectMeta: metav1.ObjectMeta{Name: name}, 143 Status: apis.CustomNodeResourceStatus{ 144 Resources: apis.Resources{ 145 Allocatable: &res, 146 }, 147 }, 148 } 149 return cnr 150 } 151 152 func Test_Fit(t *testing.T) { 153 util.SetQoSConfig(generic.NewQoSConfiguration()) 154 155 f, err := makeFit(kubeschedulerconfig.LeastAllocated) 156 assert.Nil(t, err) 157 fit := f.(*Fit) 158 159 state := framework.NewCycleState() 160 p1 := makeFitPod("p1", "p1", map[v1.ResourceName]resource.Quantity{ 161 consts.ReclaimedResourceMilliCPU: *resource.NewQuantity(2000, resource.DecimalSI), 162 consts.ReclaimedResourceMemory: *resource.NewQuantity(2*1024*0o124*1024, resource.DecimalSI), 163 }, "c1") 164 165 fit.PreFilter(context.Background(), state, p1) 166 data, err := state.Read(preFilterStateKey) 167 assert.Nil(t, err) 168 assert.Equal(t, data, &preFilterState{ 169 QoSResource: native.QoSResource{ 170 ReclaimedMilliCPU: int64(2000), 171 ReclaimedMemory: int64(2 * 1024 * 0o124 * 1024), 172 }, 173 }) 174 175 assert.Nil(t, fit.PreFilterExtensions()) 176 177 e := []framework.ClusterEvent{ 178 {Resource: framework.Pod, ActionType: framework.Delete}, 179 {Resource: framework.Node, ActionType: framework.Add}, 180 } 181 assert.Equal(t, fit.EventsToRegister(), e) 182 assert.Nil(t, fit.ScoreExtensions()) 183 184 fit.Reserve(context.Background(), nil, p1, "c1") 185 node, err := cache.GetCache().GetNodeInfo("c1") 186 assert.Nil(t, err) 187 assert.Equal(t, node.QoSResourcesAllocatable.ReclaimedMilliCPU, int64(0)) 188 assert.Equal(t, node.QoSResourcesAllocatable.ReclaimedMemory, int64(0)) 189 assert.Equal(t, node.QoSResourcesRequested.ReclaimedMilliCPU, int64(2000)) 190 assert.Equal(t, node.QoSResourcesRequested.ReclaimedMemory, int64(2*1024*0o124*1024)) 191 192 fit.Unreserve(context.Background(), nil, p1, "c1") 193 node, err = cache.GetCache().GetNodeInfo("c1") 194 assert.Nil(t, err) 195 assert.Equal(t, node.QoSResourcesAllocatable.ReclaimedMilliCPU, int64(0)) 196 assert.Equal(t, node.QoSResourcesAllocatable.ReclaimedMemory, int64(0)) 197 assert.Equal(t, node.QoSResourcesRequested.ReclaimedMilliCPU, int64(0)) 198 assert.Equal(t, node.QoSResourcesRequested.ReclaimedMemory, int64(0)) 199 } 200 201 func Test_Allocated(t *testing.T) { 202 util.SetQoSConfig(generic.NewQoSConfiguration()) 203 204 f, _ := makeFit(kubeschedulerconfig.LeastAllocated) 205 fit := f.(*Fit) 206 207 state := framework.NewCycleState() 208 p1 := makeFitPod("p1", "p1", map[v1.ResourceName]resource.Quantity{ 209 consts.ReclaimedResourceMilliCPU: *resource.NewQuantity(2000, resource.DecimalSI), 210 consts.ReclaimedResourceMemory: *resource.NewQuantity(2*1024*0o124*1024, resource.DecimalSI), 211 }, "n1") 212 p2 := makeFitPod("p2", "p2", map[v1.ResourceName]resource.Quantity{ 213 consts.ReclaimedResourceMilliCPU: *resource.NewQuantity(3000, resource.DecimalSI), 214 consts.ReclaimedResourceMemory: *resource.NewQuantity(3*1024*0o124*1024, resource.DecimalSI), 215 }, "n1") 216 n1 := makeFitNode("n1", []*v1.Pod{p1, p2}, map[v1.ResourceName]resource.Quantity{ 217 consts.ReclaimedResourceMilliCPU: *resource.NewQuantity(9000, resource.DecimalSI), 218 consts.ReclaimedResourceMemory: *resource.NewQuantity(12*1024*0o124*1024, resource.DecimalSI), 219 }) 220 221 p3 := makeFitPod("p3", "p3", map[v1.ResourceName]resource.Quantity{ 222 consts.ReclaimedResourceMilliCPU: *resource.NewQuantity(3000, resource.DecimalSI), 223 consts.ReclaimedResourceMemory: *resource.NewQuantity(3*1024*0o124*1024, resource.DecimalSI), 224 }, "") 225 fit.PreFilter(context.Background(), state, p3) 226 227 status := fit.Filter(context.Background(), state, p3, n1) 228 t.Logf("%v", status.Reasons()) 229 assert.Equal(t, status.IsSuccess(), false) 230 231 c1 := makeFitCNR("n1", map[v1.ResourceName]resource.Quantity{ 232 consts.ReclaimedResourceMilliCPU: *resource.NewQuantity(9000, resource.DecimalSI), 233 consts.ReclaimedResourceMemory: *resource.NewQuantity(12*1024*0o124*1024, resource.DecimalSI), 234 }) 235 cache.GetCache().AddOrUpdateCNR(c1) 236 status = fit.Filter(context.Background(), state, p3, n1) 237 assert.Equal(t, status.IsSuccess(), true) 238 239 p4 := makeFitPod("p4", "p4", map[v1.ResourceName]resource.Quantity{ 240 consts.ReclaimedResourceMilliCPU: *resource.NewQuantity(3000, resource.DecimalSI), 241 consts.ReclaimedResourceMemory: *resource.NewQuantity(30*1024*0o124*1024, resource.DecimalSI), 242 }, "") 243 fit.PreFilter(context.Background(), state, p4) 244 245 status = fit.Filter(context.Background(), state, p4, n1) 246 t.Logf("%v", status) 247 assert.Equal(t, status.IsSuccess(), false) 248 } 249 250 func Test_FitScore(t *testing.T) { 251 util.SetQoSConfig(generic.NewQoSConfiguration()) 252 253 state := framework.NewCycleState() 254 p1 := makeFitPod("p1", "p1", map[v1.ResourceName]resource.Quantity{ 255 consts.ReclaimedResourceMilliCPU: *resource.NewQuantity(2000, resource.DecimalSI), 256 consts.ReclaimedResourceMemory: *resource.NewQuantity(2*1024*0o124*1024, resource.DecimalSI), 257 }, "n1") 258 _ = cache.GetCache().AddPod(p1) 259 260 p2 := makeFitPod("p2", "p2", map[v1.ResourceName]resource.Quantity{ 261 consts.ReclaimedResourceMilliCPU: *resource.NewQuantity(3000, resource.DecimalSI), 262 consts.ReclaimedResourceMemory: *resource.NewQuantity(3*1024*0o124*1024, resource.DecimalSI), 263 }, "n1") 264 _ = cache.GetCache().AddPod(p2) 265 266 c1 := makeFitCNR("n1", map[v1.ResourceName]resource.Quantity{ 267 consts.ReclaimedResourceMilliCPU: *resource.NewQuantity(9000, resource.DecimalSI), 268 consts.ReclaimedResourceMemory: *resource.NewQuantity(12*1024*0o124*1024, resource.DecimalSI), 269 }) 270 cache.GetCache().AddOrUpdateCNR(c1) 271 272 p3 := makeFitPod("p3", "p3", map[v1.ResourceName]resource.Quantity{ 273 consts.ReclaimedResourceMilliCPU: *resource.NewQuantity(3000, resource.DecimalSI), 274 consts.ReclaimedResourceMemory: *resource.NewQuantity(3*1024*0o124*1024, resource.DecimalSI), 275 }, "") 276 277 leastF, _ := makeFit(kubeschedulerconfig.LeastAllocated) 278 leastFit := leastF.(*Fit) 279 score, _ := leastFit.Score(context.Background(), state, p3, "n1") 280 assert.Equal(t, score, int64(26)) 281 282 mostF, _ := makeFit(kubeschedulerconfig.MostAllocated) 283 mostFit := mostF.(*Fit) 284 score, _ = mostFit.Score(context.Background(), state, p3, "n1") 285 assert.Equal(t, score, int64(72)) 286 287 ratioF, _ := makeFit(kubeschedulerconfig.RequestedToCapacityRatio) 288 ratioFit := ratioF.(*Fit) 289 score, _ = ratioFit.Score(context.Background(), state, p3, "n1") 290 assert.Equal(t, score, int64(70)) 291 }