github.com/kubewharf/katalyst-core@v0.5.3/pkg/scheduler/plugins/noderesourcetopology/reserve_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 noderesourcetopology
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  
    23  	"github.com/stretchr/testify/assert"
    24  	v1 "k8s.io/api/core/v1"
    25  	"k8s.io/apimachinery/pkg/api/resource"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/kubernetes/pkg/scheduler/apis/config"
    28  	"k8s.io/kubernetes/pkg/scheduler/framework"
    29  	"k8s.io/kubernetes/pkg/scheduler/framework/runtime"
    30  
    31  	"github.com/kubewharf/katalyst-api/pkg/apis/node/v1alpha1"
    32  	"github.com/kubewharf/katalyst-api/pkg/consts"
    33  	"github.com/kubewharf/katalyst-core/pkg/config/generic"
    34  	"github.com/kubewharf/katalyst-core/pkg/scheduler/cache"
    35  	"github.com/kubewharf/katalyst-core/pkg/scheduler/util"
    36  )
    37  
    38  func makeTestReserveNode() (*v1alpha1.CustomNodeResource, string) {
    39  	return &v1alpha1.CustomNodeResource{
    40  		ObjectMeta: metav1.ObjectMeta{Name: "node-2numa-8c16g"},
    41  		Status: v1alpha1.CustomNodeResourceStatus{
    42  			TopologyPolicy: v1alpha1.TopologyPolicySingleNUMANodeContainerLevel,
    43  			TopologyZone: []*v1alpha1.TopologyZone{
    44  				{
    45  					Name: "0",
    46  					Type: v1alpha1.TopologyTypeSocket,
    47  					Children: []*v1alpha1.TopologyZone{
    48  						{
    49  							Name: "0",
    50  							Type: v1alpha1.TopologyTypeNuma,
    51  							Resources: v1alpha1.Resources{
    52  								Capacity: &v1.ResourceList{
    53  									v1.ResourceCPU:    resource.MustParse("4"),
    54  									v1.ResourceMemory: resource.MustParse("8Gi"),
    55  									"Gpu":             resource.MustParse("4"),
    56  								},
    57  								Allocatable: &v1.ResourceList{
    58  									v1.ResourceCPU:    resource.MustParse("4"),
    59  									v1.ResourceMemory: resource.MustParse("8Gi"),
    60  									"Gpu":             resource.MustParse("4"),
    61  								},
    62  							},
    63  						},
    64  						{
    65  							Name: "1",
    66  							Type: v1alpha1.TopologyTypeNuma,
    67  							Resources: v1alpha1.Resources{
    68  								Capacity: &v1.ResourceList{
    69  									v1.ResourceCPU:    resource.MustParse("4"),
    70  									v1.ResourceMemory: resource.MustParse("8Gi"),
    71  									"Gpu":             resource.MustParse("4"),
    72  								},
    73  								Allocatable: &v1.ResourceList{
    74  									v1.ResourceCPU:    resource.MustParse("4"),
    75  									v1.ResourceMemory: resource.MustParse("8Gi"),
    76  									"Gpu":             resource.MustParse("4"),
    77  								},
    78  							},
    79  						},
    80  					},
    81  				},
    82  			},
    83  		},
    84  	}, "node-2numa-8c16g"
    85  }
    86  
    87  func TestReserve(t *testing.T) {
    88  	type testCase struct {
    89  		name            string
    90  		policy          v1alpha1.TopologyPolicy
    91  		alignedResource []string
    92  		pod             *v1.Pod
    93  	}
    94  
    95  	testCases := []testCase{
    96  		{
    97  			name:            "dedicated + exclusive + single numa",
    98  			policy:          v1alpha1.TopologyPolicySingleNUMANodeContainerLevel,
    99  			alignedResource: []string{"cpu", "memory"},
   100  			pod: makePodByResourceList(&v1.ResourceList{
   101  				v1.ResourceCPU:    resource.MustParse("2"),
   102  				v1.ResourceMemory: resource.MustParse("4Gi"),
   103  			}, map[string]string{
   104  				consts.PodAnnotationQoSLevelKey:          consts.PodAnnotationQoSLevelDedicatedCores,
   105  				consts.PodAnnotationMemoryEnhancementKey: `{"numa_binding":"true","numa_exclusive":"true"}`,
   106  			}),
   107  		},
   108  	}
   109  
   110  	c := cache.GetCache()
   111  	util.SetQoSConfig(generic.NewQoSConfiguration())
   112  	for _, tc := range testCases {
   113  		cnr, nodeName := makeTestReserveNode()
   114  		c.AddOrUpdateCNR(cnr)
   115  
   116  		f, err := runtime.NewFramework(nil, nil,
   117  			runtime.WithSnapshotSharedLister(newTestSharedLister(nil, nil)))
   118  		assert.NoError(t, err)
   119  		tm, err := MakeTestTm(MakeTestArgs(config.MostAllocated, tc.alignedResource, "dynamic"), f)
   120  		assert.NoError(t, err)
   121  
   122  		n := &v1.Node{}
   123  		n.SetName(nodeName)
   124  		nodeInfo := framework.NewNodeInfo()
   125  		nodeInfo.SetNode(n)
   126  
   127  		// pod can be allocated on node
   128  		status := tm.(*TopologyMatch).Filter(context.TODO(), nil, tc.pod, nodeInfo)
   129  		assert.Nil(t, status)
   130  
   131  		tm.(*TopologyMatch).Reserve(context.TODO(), nil, tc.pod, nodeName)
   132  
   133  		// pod can not be allocated after reserve
   134  		status = tm.(*TopologyMatch).Filter(context.TODO(), nil, tc.pod, nodeInfo)
   135  		assert.Equal(t, 2, int(status.Code()))
   136  
   137  		tm.(*TopologyMatch).Unreserve(context.TODO(), nil, tc.pod, nodeName)
   138  
   139  		// pod can be allocatd again
   140  		status = tm.(*TopologyMatch).Filter(context.TODO(), nil, tc.pod, nodeInfo)
   141  		assert.Nil(t, status)
   142  	}
   143  }