github.com/kubewharf/katalyst-core@v0.5.3/pkg/agent/evictionmanager/manager_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 evictionmanager 18 19 import ( 20 "context" 21 "testing" 22 "time" 23 24 "github.com/stretchr/testify/assert" 25 v1 "k8s.io/api/core/v1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/util/sets" 28 29 pluginapi "github.com/kubewharf/katalyst-api/pkg/protocol/evictionplugin/v1alpha1" 30 endpointpkg "github.com/kubewharf/katalyst-core/pkg/agent/evictionmanager/endpoint" 31 "github.com/kubewharf/katalyst-core/pkg/client" 32 "github.com/kubewharf/katalyst-core/pkg/config" 33 "github.com/kubewharf/katalyst-core/pkg/config/agent/dynamic/adminqos/eviction" 34 "github.com/kubewharf/katalyst-core/pkg/consts" 35 "github.com/kubewharf/katalyst-core/pkg/metaserver" 36 "github.com/kubewharf/katalyst-core/pkg/metaserver/agent" 37 "github.com/kubewharf/katalyst-core/pkg/metaserver/agent/pod" 38 "github.com/kubewharf/katalyst-core/pkg/metrics" 39 "github.com/kubewharf/katalyst-core/pkg/util/credential" 40 "github.com/kubewharf/katalyst-core/pkg/util/credential/authorization" 41 ) 42 43 var ( 44 evictionManagerSyncPeriod = 10 * time.Second 45 pods = []*v1.Pod{ 46 { 47 ObjectMeta: metav1.ObjectMeta{ 48 Name: "pod-1", 49 UID: "pod-1", 50 }, 51 Status: v1.PodStatus{ 52 Phase: v1.PodRunning, 53 }, 54 }, 55 { 56 ObjectMeta: metav1.ObjectMeta{ 57 Name: "pod-2", 58 UID: "pod-2", 59 }, 60 Status: v1.PodStatus{ 61 Phase: v1.PodRunning, 62 }, 63 }, 64 { 65 ObjectMeta: metav1.ObjectMeta{ 66 Name: "pod-3", 67 UID: "pod-3", 68 }, 69 Status: v1.PodStatus{ 70 Phase: v1.PodRunning, 71 }, 72 }, 73 { 74 ObjectMeta: metav1.ObjectMeta{ 75 Name: "pod-4", 76 UID: "pod-4", 77 }, 78 Status: v1.PodStatus{ 79 Phase: v1.PodRunning, 80 }, 81 }, 82 { 83 ObjectMeta: metav1.ObjectMeta{ 84 Name: "pod-5", 85 UID: "pod-5", 86 }, 87 Status: v1.PodStatus{ 88 Phase: v1.PodRunning, 89 }, 90 }, 91 } 92 ) 93 94 func makeConf() *config.Configuration { 95 conf := config.NewConfiguration() 96 conf.EvictionManagerSyncPeriod = evictionManagerSyncPeriod 97 conf.GetDynamicConfiguration().MemoryPressureEvictionConfiguration.GracePeriod = eviction.DefaultGracePeriod 98 conf.PodKiller = consts.KillerNameEvictionKiller 99 conf.GenericConfiguration.AuthConfiguration.AuthType = credential.AuthTypeInsecure 100 conf.GenericConfiguration.AuthConfiguration.AccessControlType = authorization.AccessControlTypeInsecure 101 102 return conf 103 } 104 105 func makeMetaServer() *metaserver.MetaServer { 106 return &metaserver.MetaServer{ 107 MetaAgent: &agent.MetaAgent{ 108 PodFetcher: &pod.PodFetcherStub{PodList: pods}, 109 }, 110 } 111 } 112 113 type pluginSkeleton struct{} 114 115 func (p *pluginSkeleton) Start() { 116 } 117 118 func (p *pluginSkeleton) Stop() { 119 } 120 121 func (p *pluginSkeleton) IsStopped() bool { 122 return false 123 } 124 125 func (p *pluginSkeleton) StopGracePeriodExpired() bool { 126 return false 127 } 128 129 type plugin1 struct { 130 pluginSkeleton 131 } 132 133 func (p *plugin1) ThresholdMet(_ context.Context) (*pluginapi.ThresholdMetResponse, error) { 134 return &pluginapi.ThresholdMetResponse{ 135 MetType: pluginapi.ThresholdMetType_NOT_MET, 136 }, nil 137 } 138 139 func (p *plugin1) GetTopEvictionPods(_ context.Context, _ *pluginapi.GetTopEvictionPodsRequest) (*pluginapi.GetTopEvictionPodsResponse, error) { 140 return &pluginapi.GetTopEvictionPodsResponse{}, nil 141 } 142 143 func (p *plugin1) GetEvictPods(_ context.Context, _ *pluginapi.GetEvictPodsRequest) (*pluginapi.GetEvictPodsResponse, error) { 144 return &pluginapi.GetEvictPodsResponse{ 145 EvictPods: []*pluginapi.EvictPod{ 146 { 147 Pod: &v1.Pod{ 148 ObjectMeta: metav1.ObjectMeta{ 149 Name: "pod-1", 150 UID: "pod-1", 151 }, 152 Status: v1.PodStatus{ 153 Phase: v1.PodRunning, 154 }, 155 }, 156 ForceEvict: false, 157 }, 158 { 159 Pod: &v1.Pod{ 160 ObjectMeta: metav1.ObjectMeta{ 161 Name: "pod-2", 162 UID: "pod-2", 163 }, 164 Status: v1.PodStatus{ 165 Phase: v1.PodRunning, 166 }, 167 }, 168 ForceEvict: true, 169 }, 170 { 171 Pod: &v1.Pod{ 172 ObjectMeta: metav1.ObjectMeta{ 173 Name: "pod-5", 174 UID: "pod-5", 175 }, 176 Status: v1.PodStatus{ 177 Phase: v1.PodRunning, 178 }, 179 }, 180 ForceEvict: false, 181 }, 182 }, 183 }, nil 184 } 185 186 type plugin2 struct { 187 pluginSkeleton 188 } 189 190 func (p plugin2) ThresholdMet(_ context.Context) (*pluginapi.ThresholdMetResponse, error) { 191 return &pluginapi.ThresholdMetResponse{ 192 MetType: pluginapi.ThresholdMetType_HARD_MET, 193 ThresholdValue: 0.8, 194 ObservedValue: 0.9, 195 ThresholdOperator: pluginapi.ThresholdOperator_GREATER_THAN, 196 EvictionScope: "plugin2_scope", 197 GracePeriodSeconds: -1, 198 Condition: &pluginapi.Condition{ 199 ConditionType: pluginapi.ConditionType_NODE_CONDITION, 200 Effects: []string{"NoSchedule"}, 201 ConditionName: "diskPressure", 202 MetCondition: true, 203 }, 204 }, nil 205 } 206 207 func (p plugin2) GetTopEvictionPods(_ context.Context, _ *pluginapi.GetTopEvictionPodsRequest) (*pluginapi.GetTopEvictionPodsResponse, error) { 208 return &pluginapi.GetTopEvictionPodsResponse{TargetPods: []*v1.Pod{ 209 { 210 ObjectMeta: metav1.ObjectMeta{ 211 Name: "pod-3", 212 UID: "pod-3", 213 }, 214 Status: v1.PodStatus{ 215 Phase: v1.PodRunning, 216 }, 217 }, 218 }}, nil 219 } 220 221 func (p plugin2) GetEvictPods(_ context.Context, _ *pluginapi.GetEvictPodsRequest) (*pluginapi.GetEvictPodsResponse, error) { 222 return &pluginapi.GetEvictPodsResponse{EvictPods: []*pluginapi.EvictPod{}}, nil 223 } 224 225 func makeEvictionManager(t *testing.T) *EvictionManger { 226 mgr, err := NewEvictionManager(&client.GenericClientSet{}, nil, makeMetaServer(), metrics.DummyMetrics{}, makeConf()) 227 assert.NoError(t, err) 228 mgr.endpoints = map[string]endpointpkg.Endpoint{ 229 "plugin1": &plugin1{}, 230 "plugin2": &plugin2{}, 231 } 232 233 return mgr 234 } 235 236 func TestEvictionManger_collectEvictionResult(t *testing.T) { 237 t.Parallel() 238 239 tests := []struct { 240 name string 241 dryrun []string 242 wantSoftEvictPods sets.String 243 wantForceEvictPods sets.String 244 wantConditions sets.String 245 }{ 246 { 247 name: "no dryrun", 248 dryrun: []string{}, 249 wantSoftEvictPods: sets.String{ 250 "pod-1": sets.Empty{}, 251 "pod-5": sets.Empty{}, 252 }, 253 wantForceEvictPods: sets.String{ 254 "pod-2": sets.Empty{}, 255 "pod-3": sets.Empty{}, 256 }, 257 wantConditions: sets.String{ 258 "diskPressure": sets.Empty{}, 259 }, 260 }, 261 { 262 name: "dryrun plugin1", 263 dryrun: []string{"plugin1"}, 264 wantSoftEvictPods: sets.String{}, 265 wantForceEvictPods: sets.String{ 266 "pod-3": sets.Empty{}, 267 }, 268 wantConditions: sets.String{ 269 "diskPressure": sets.Empty{}, 270 }, 271 }, 272 { 273 name: "dryrun plugin2", 274 dryrun: []string{"plugin2"}, 275 wantSoftEvictPods: sets.String{ 276 "pod-1": sets.Empty{}, 277 "pod-5": sets.Empty{}, 278 }, 279 wantForceEvictPods: sets.String{ 280 "pod-2": sets.Empty{}, 281 }, 282 wantConditions: sets.String{}, 283 }, 284 { 285 name: "dryrun plugin1 & plugin2", 286 dryrun: []string{"plugin1", "plugin2"}, 287 wantSoftEvictPods: sets.String{}, 288 wantForceEvictPods: sets.String{}, 289 wantConditions: sets.String{}, 290 }, 291 { 292 name: "dryrun *", 293 dryrun: []string{"*"}, 294 wantSoftEvictPods: sets.String{}, 295 wantForceEvictPods: sets.String{}, 296 wantConditions: sets.String{}, 297 }, 298 } 299 for _, tt := range tests { 300 tt := tt 301 t.Run(tt.name, func(t *testing.T) { 302 t.Parallel() 303 304 mgr := makeEvictionManager(t) 305 mgr.conf.GetDynamicConfiguration().DryRun = tt.dryrun 306 307 collector, _ := mgr.collectEvictionResult(pods) 308 gotForceEvictPods := sets.String{} 309 gotSoftEvictPods := sets.String{} 310 gotConditions := sets.String{} 311 for _, evictPod := range collector.getForceEvictPods() { 312 gotForceEvictPods.Insert(evictPod.Pod.Name) 313 } 314 315 for _, evictPod := range collector.getSoftEvictPods() { 316 gotSoftEvictPods.Insert(evictPod.Pod.Name) 317 } 318 319 for name := range collector.getCurrentConditions() { 320 gotConditions.Insert(name) 321 } 322 assert.Equal(t, tt.wantForceEvictPods, gotForceEvictPods) 323 assert.Equal(t, tt.wantSoftEvictPods, gotSoftEvictPods) 324 assert.Equal(t, tt.wantConditions, gotConditions) 325 }) 326 } 327 }