github.com/kubewharf/katalyst-core@v0.5.3/pkg/scheduler/plugins/nodeovercommitment/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 nodeovercommitment
    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  	v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/kubernetes/pkg/scheduler/framework"
    28  
    29  	"github.com/kubewharf/katalyst-api/pkg/apis/node/v1alpha1"
    30  	"github.com/kubewharf/katalyst-core/pkg/scheduler/plugins/nodeovercommitment/cache"
    31  )
    32  
    33  func TestPreFilter(t *testing.T) {
    34  	t.Parallel()
    35  
    36  	testCases := []struct {
    37  		name                string
    38  		pod                 *v1.Pod
    39  		expectCPU           int64
    40  		expectGuaranteedCPU int
    41  	}{
    42  		{
    43  			name: "burstable pod",
    44  			pod: &v1.Pod{
    45  				Spec: v1.PodSpec{
    46  					Containers: []v1.Container{
    47  						{
    48  							Resources: v1.ResourceRequirements{
    49  								Limits: map[v1.ResourceName]resource.Quantity{
    50  									v1.ResourceCPU:    resource.MustParse("4"),
    51  									v1.ResourceMemory: resource.MustParse("8Gi"),
    52  								},
    53  								Requests: map[v1.ResourceName]resource.Quantity{
    54  									v1.ResourceCPU:    resource.MustParse("2"),
    55  									v1.ResourceMemory: resource.MustParse("4Gi"),
    56  								},
    57  							},
    58  						},
    59  					},
    60  				},
    61  			},
    62  			expectCPU:           2000,
    63  			expectGuaranteedCPU: 0,
    64  		},
    65  		{
    66  			name: "guaranteed pod",
    67  			pod: &v1.Pod{
    68  				Spec: v1.PodSpec{
    69  					Containers: []v1.Container{
    70  						{
    71  							Resources: v1.ResourceRequirements{
    72  								Limits: map[v1.ResourceName]resource.Quantity{
    73  									v1.ResourceCPU:    resource.MustParse("4"),
    74  									v1.ResourceMemory: resource.MustParse("8Gi"),
    75  								},
    76  								Requests: map[v1.ResourceName]resource.Quantity{
    77  									v1.ResourceCPU:    resource.MustParse("4"),
    78  									v1.ResourceMemory: resource.MustParse("8Gi"),
    79  								},
    80  							},
    81  						},
    82  					},
    83  				},
    84  			},
    85  			expectCPU:           0,
    86  			expectGuaranteedCPU: 4,
    87  		},
    88  		{
    89  			name: "guaranteed pod with init container",
    90  			pod: &v1.Pod{
    91  				Spec: v1.PodSpec{
    92  					InitContainers: []v1.Container{
    93  						{
    94  							Resources: v1.ResourceRequirements{
    95  								Limits: map[v1.ResourceName]resource.Quantity{
    96  									v1.ResourceCPU:    resource.MustParse("4"),
    97  									v1.ResourceMemory: resource.MustParse("8Gi"),
    98  								},
    99  								Requests: map[v1.ResourceName]resource.Quantity{
   100  									v1.ResourceCPU:    resource.MustParse("4"),
   101  									v1.ResourceMemory: resource.MustParse("8Gi"),
   102  								},
   103  							},
   104  						},
   105  					},
   106  					Containers: []v1.Container{
   107  						{
   108  							Resources: v1.ResourceRequirements{
   109  								Limits: map[v1.ResourceName]resource.Quantity{
   110  									v1.ResourceCPU:    resource.MustParse("2"),
   111  									v1.ResourceMemory: resource.MustParse("8Gi"),
   112  								},
   113  								Requests: map[v1.ResourceName]resource.Quantity{
   114  									v1.ResourceCPU:    resource.MustParse("2"),
   115  									v1.ResourceMemory: resource.MustParse("8Gi"),
   116  								},
   117  							},
   118  						},
   119  					},
   120  				},
   121  			},
   122  			expectCPU:           0,
   123  			expectGuaranteedCPU: 4,
   124  		},
   125  	}
   126  
   127  	for _, tc := range testCases {
   128  		t.Run(tc.name, func(t *testing.T) {
   129  			n := &NodeOvercommitment{}
   130  			cs := framework.NewCycleState()
   131  			res, stat := n.PreFilter(context.TODO(), cs, tc.pod)
   132  			assert.Nil(t, res)
   133  			assert.Nil(t, stat)
   134  
   135  			fs, err := getPreFilterState(cs)
   136  			assert.NoError(t, err)
   137  			assert.Equal(t, tc.expectGuaranteedCPU, fs.GuaranteedCPUs)
   138  			assert.Equal(t, tc.expectCPU, fs.MilliCPU)
   139  		})
   140  	}
   141  }
   142  
   143  func TestFilter(t *testing.T) {
   144  	t.Parallel()
   145  
   146  	testCases := []struct {
   147  		name      string
   148  		node      *v1.Node
   149  		cnrs      []*v1alpha1.CustomNodeResource
   150  		existPods []*v1.Pod
   151  		pod       *v1.Pod
   152  		requested *framework.Resource
   153  		expectRes *framework.Status
   154  	}{
   155  		{
   156  			name: "node cpumanager off",
   157  			node: &v1.Node{
   158  				ObjectMeta: v12.ObjectMeta{
   159  					Name: "node1",
   160  					Annotations: map[string]string{
   161  						"katalyst.kubewharf.io/cpu_overcommit_ratio":     "2.0",
   162  						"katalyst.kubewharf.io/memory_overcommit_ratio":  "1.0",
   163  						"katalyst.kubewharf.io/original_allocatable_cpu": "16000",
   164  					},
   165  				},
   166  				Status: v1.NodeStatus{
   167  					Allocatable: map[v1.ResourceName]resource.Quantity{
   168  						v1.ResourceCPU:    resource.MustParse("32"),
   169  						v1.ResourceMemory: resource.MustParse("32Gi"),
   170  					},
   171  				},
   172  			},
   173  			cnrs: []*v1alpha1.CustomNodeResource{
   174  				{
   175  					ObjectMeta: v12.ObjectMeta{
   176  						Name: "node1",
   177  						Annotations: map[string]string{
   178  							"katalyst.kubewharf.io/overcommit_cpu_manager":    "none",
   179  							"katalyst.kubewharf.io/overcommit_memory_manager": "None",
   180  							"katalyst.kubewharf.io/guaranteed_cpus":           "0",
   181  						},
   182  					},
   183  				},
   184  			},
   185  			existPods: []*v1.Pod{},
   186  			requested: &framework.Resource{
   187  				MilliCPU: 24000,
   188  			},
   189  			pod: &v1.Pod{
   190  				ObjectMeta: v12.ObjectMeta{
   191  					Name: "pod1",
   192  				},
   193  				Spec: v1.PodSpec{
   194  					Containers: []v1.Container{
   195  						{
   196  							Name: "testContainer",
   197  							Resources: v1.ResourceRequirements{
   198  								Requests: map[v1.ResourceName]resource.Quantity{
   199  									v1.ResourceCPU:    resource.MustParse("4"),
   200  									v1.ResourceMemory: resource.MustParse("8Gi"),
   201  								},
   202  							},
   203  						},
   204  					},
   205  				},
   206  			},
   207  			expectRes: nil,
   208  		},
   209  		{
   210  			name: "node cpumanager on",
   211  			node: &v1.Node{
   212  				ObjectMeta: v12.ObjectMeta{
   213  					Name: "node1",
   214  					Annotations: map[string]string{
   215  						"katalyst.kubewharf.io/cpu_overcommit_ratio":     "2.0",
   216  						"katalyst.kubewharf.io/memory_overcommit_ratio":  "1.0",
   217  						"katalyst.kubewharf.io/original_allocatable_cpu": "16000",
   218  					},
   219  				},
   220  				Status: v1.NodeStatus{
   221  					Allocatable: map[v1.ResourceName]resource.Quantity{
   222  						v1.ResourceCPU:    resource.MustParse("32"),
   223  						v1.ResourceMemory: resource.MustParse("32Gi"),
   224  					},
   225  				},
   226  			},
   227  			cnrs: []*v1alpha1.CustomNodeResource{
   228  				{
   229  					ObjectMeta: v12.ObjectMeta{
   230  						Name: "node1",
   231  						Annotations: map[string]string{
   232  							"katalyst.kubewharf.io/overcommit_cpu_manager":    "static",
   233  							"katalyst.kubewharf.io/overcommit_memory_manager": "None",
   234  							"katalyst.kubewharf.io/guaranteed_cpus":           "4",
   235  						},
   236  					},
   237  				},
   238  			},
   239  			requested: &framework.Resource{
   240  				MilliCPU: 24000,
   241  			},
   242  			existPods: []*v1.Pod{
   243  				{
   244  					ObjectMeta: v12.ObjectMeta{
   245  						Name: "pod01",
   246  						UID:  "pod01",
   247  					},
   248  					Spec: v1.PodSpec{
   249  						NodeName: "node1",
   250  						Containers: []v1.Container{
   251  							{
   252  								Name: "testContainer",
   253  								Resources: v1.ResourceRequirements{
   254  									Requests: map[v1.ResourceName]resource.Quantity{
   255  										v1.ResourceCPU:    resource.MustParse("4"),
   256  										v1.ResourceMemory: resource.MustParse("8Gi"),
   257  									},
   258  									Limits: map[v1.ResourceName]resource.Quantity{
   259  										v1.ResourceCPU:    resource.MustParse("4"),
   260  										v1.ResourceMemory: resource.MustParse("8Gi"),
   261  									},
   262  								},
   263  							},
   264  						},
   265  					},
   266  				},
   267  			},
   268  			pod: &v1.Pod{
   269  				ObjectMeta: v12.ObjectMeta{
   270  					Name: "pod1",
   271  				},
   272  				Spec: v1.PodSpec{
   273  					Containers: []v1.Container{
   274  						{
   275  							Name: "testContainer",
   276  							Resources: v1.ResourceRequirements{
   277  								Requests: map[v1.ResourceName]resource.Quantity{
   278  									v1.ResourceCPU:    resource.MustParse("4"),
   279  									v1.ResourceMemory: resource.MustParse("8Gi"),
   280  								},
   281  							},
   282  						},
   283  					},
   284  				},
   285  			},
   286  			expectRes: nil,
   287  		},
   288  		{
   289  			name: "node cpumanager on with recommend",
   290  			node: &v1.Node{
   291  				ObjectMeta: v12.ObjectMeta{
   292  					Name: "node1",
   293  					Annotations: map[string]string{
   294  						"katalyst.kubewharf.io/cpu_overcommit_ratio":           "3.0",
   295  						"katalyst.kubewharf.io/memory_overcommit_ratio":        "1.0",
   296  						"katalyst.kubewharf.io/recommend_cpu_overcommit_ratio": "2.0",
   297  						"katalyst.kubewharf.io/original_allocatable_cpu":       "16000",
   298  					},
   299  				},
   300  				Status: v1.NodeStatus{
   301  					Allocatable: map[v1.ResourceName]resource.Quantity{
   302  						v1.ResourceCPU:    resource.MustParse("32"),
   303  						v1.ResourceMemory: resource.MustParse("32Gi"),
   304  					},
   305  				},
   306  			},
   307  			cnrs: []*v1alpha1.CustomNodeResource{
   308  				{
   309  					ObjectMeta: v12.ObjectMeta{
   310  						Name: "node1",
   311  						Annotations: map[string]string{
   312  							"katalyst.kubewharf.io/overcommit_cpu_manager":    "static",
   313  							"katalyst.kubewharf.io/overcommit_memory_manager": "None",
   314  							"katalyst.kubewharf.io/guaranteed_cpus":           "4",
   315  						},
   316  					},
   317  				},
   318  			},
   319  			requested: &framework.Resource{
   320  				MilliCPU: 24000,
   321  			},
   322  			existPods: []*v1.Pod{
   323  				{
   324  					ObjectMeta: v12.ObjectMeta{
   325  						Name: "pod01",
   326  						UID:  "pod01",
   327  					},
   328  					Spec: v1.PodSpec{
   329  						NodeName: "node1",
   330  						Containers: []v1.Container{
   331  							{
   332  								Name: "testContainer",
   333  								Resources: v1.ResourceRequirements{
   334  									Requests: map[v1.ResourceName]resource.Quantity{
   335  										v1.ResourceCPU:    resource.MustParse("4"),
   336  										v1.ResourceMemory: resource.MustParse("8Gi"),
   337  									},
   338  									Limits: map[v1.ResourceName]resource.Quantity{
   339  										v1.ResourceCPU:    resource.MustParse("4"),
   340  										v1.ResourceMemory: resource.MustParse("8Gi"),
   341  									},
   342  								},
   343  							},
   344  						},
   345  					},
   346  				},
   347  			},
   348  			pod: &v1.Pod{
   349  				ObjectMeta: v12.ObjectMeta{
   350  					Name: "pod1",
   351  				},
   352  				Spec: v1.PodSpec{
   353  					Containers: []v1.Container{
   354  						{
   355  							Name: "testContainer",
   356  							Resources: v1.ResourceRequirements{
   357  								Requests: map[v1.ResourceName]resource.Quantity{
   358  									v1.ResourceCPU:    resource.MustParse("4"),
   359  									v1.ResourceMemory: resource.MustParse("8Gi"),
   360  								},
   361  							},
   362  						},
   363  					},
   364  				},
   365  			},
   366  			expectRes: nil,
   367  		},
   368  		{
   369  			name: "node cpumanager on 2",
   370  			node: &v1.Node{
   371  				ObjectMeta: v12.ObjectMeta{
   372  					Name: "node1",
   373  					Annotations: map[string]string{
   374  						"katalyst.kubewharf.io/cpu_overcommit_ratio":     "2.0",
   375  						"katalyst.kubewharf.io/memory_overcommit_ratio":  "1.0",
   376  						"katalyst.kubewharf.io/original_allocatable_cpu": "16000m",
   377  					},
   378  				},
   379  				Status: v1.NodeStatus{
   380  					Allocatable: map[v1.ResourceName]resource.Quantity{
   381  						v1.ResourceCPU:    resource.MustParse("32"),
   382  						v1.ResourceMemory: resource.MustParse("32Gi"),
   383  					},
   384  				},
   385  			},
   386  			cnrs: []*v1alpha1.CustomNodeResource{
   387  				{
   388  					ObjectMeta: v12.ObjectMeta{
   389  						Name: "node1",
   390  						Annotations: map[string]string{
   391  							"katalyst.kubewharf.io/overcommit_cpu_manager":    "static",
   392  							"katalyst.kubewharf.io/overcommit_memory_manager": "None",
   393  							"katalyst.kubewharf.io/guaranteed_cpus":           "8",
   394  						},
   395  					},
   396  				},
   397  			},
   398  			requested: &framework.Resource{
   399  				MilliCPU: 24000,
   400  			},
   401  			existPods: []*v1.Pod{
   402  				{
   403  					ObjectMeta: v12.ObjectMeta{
   404  						Name: "pod01",
   405  						UID:  "pod01",
   406  					},
   407  					Spec: v1.PodSpec{
   408  						NodeName: "node1",
   409  						Containers: []v1.Container{
   410  							{
   411  								Name: "testContainer",
   412  								Resources: v1.ResourceRequirements{
   413  									Requests: map[v1.ResourceName]resource.Quantity{
   414  										v1.ResourceCPU:    resource.MustParse("8"),
   415  										v1.ResourceMemory: resource.MustParse("8Gi"),
   416  									},
   417  									Limits: map[v1.ResourceName]resource.Quantity{
   418  										v1.ResourceCPU:    resource.MustParse("8"),
   419  										v1.ResourceMemory: resource.MustParse("8Gi"),
   420  									},
   421  								},
   422  							},
   423  						},
   424  					},
   425  				},
   426  			},
   427  			pod: &v1.Pod{
   428  				ObjectMeta: v12.ObjectMeta{
   429  					Name: "pod1",
   430  				},
   431  				Spec: v1.PodSpec{
   432  					Containers: []v1.Container{
   433  						{
   434  							Name: "testContainer",
   435  							Resources: v1.ResourceRequirements{
   436  								Requests: map[v1.ResourceName]resource.Quantity{
   437  									v1.ResourceCPU:    resource.MustParse("4"),
   438  									v1.ResourceMemory: resource.MustParse("8Gi"),
   439  								},
   440  							},
   441  						},
   442  					},
   443  				},
   444  			},
   445  			expectRes: framework.NewStatus(framework.Unschedulable),
   446  		},
   447  		{
   448  			name: "node cpumanager on 3",
   449  			node: &v1.Node{
   450  				ObjectMeta: v12.ObjectMeta{
   451  					Name: "node1",
   452  					Annotations: map[string]string{
   453  						"katalyst.kubewharf.io/cpu_overcommit_ratio":     "2.0",
   454  						"katalyst.kubewharf.io/memory_overcommit_ratio":  "1.0",
   455  						"katalyst.kubewharf.io/original_allocatable_cpu": "16000m",
   456  					},
   457  				},
   458  				Status: v1.NodeStatus{
   459  					Allocatable: map[v1.ResourceName]resource.Quantity{
   460  						v1.ResourceCPU:    resource.MustParse("32"),
   461  						v1.ResourceMemory: resource.MustParse("32Gi"),
   462  					},
   463  				},
   464  			},
   465  			cnrs: []*v1alpha1.CustomNodeResource{
   466  				{
   467  					ObjectMeta: v12.ObjectMeta{
   468  						Name: "node1",
   469  						Annotations: map[string]string{
   470  							"katalyst.kubewharf.io/overcommit_cpu_manager":    "static",
   471  							"katalyst.kubewharf.io/overcommit_memory_manager": "None",
   472  							"katalyst.kubewharf.io/guaranteed_cpus":           "4",
   473  						},
   474  					},
   475  				},
   476  			},
   477  			requested: &framework.Resource{
   478  				MilliCPU: 24000,
   479  			},
   480  			existPods: []*v1.Pod{
   481  				{
   482  					ObjectMeta: v12.ObjectMeta{
   483  						Name: "pod01",
   484  						UID:  "pod01",
   485  					},
   486  					Spec: v1.PodSpec{
   487  						NodeName: "node1",
   488  						Containers: []v1.Container{
   489  							{
   490  								Name: "testContainer",
   491  								Resources: v1.ResourceRequirements{
   492  									Requests: map[v1.ResourceName]resource.Quantity{
   493  										v1.ResourceCPU:    resource.MustParse("4"),
   494  										v1.ResourceMemory: resource.MustParse("8Gi"),
   495  									},
   496  									Limits: map[v1.ResourceName]resource.Quantity{
   497  										v1.ResourceCPU:    resource.MustParse("4"),
   498  										v1.ResourceMemory: resource.MustParse("8Gi"),
   499  									},
   500  								},
   501  							},
   502  						},
   503  					},
   504  				},
   505  			},
   506  			pod: &v1.Pod{
   507  				ObjectMeta: v12.ObjectMeta{
   508  					Name: "pod1",
   509  				},
   510  				Spec: v1.PodSpec{
   511  					Containers: []v1.Container{
   512  						{
   513  							Name: "testContainer",
   514  							Resources: v1.ResourceRequirements{
   515  								Requests: map[v1.ResourceName]resource.Quantity{
   516  									v1.ResourceCPU:    resource.MustParse("4"),
   517  									v1.ResourceMemory: resource.MustParse("8Gi"),
   518  								},
   519  								Limits: map[v1.ResourceName]resource.Quantity{
   520  									v1.ResourceCPU:    resource.MustParse("4"),
   521  									v1.ResourceMemory: resource.MustParse("8Gi"),
   522  								},
   523  							},
   524  						},
   525  					},
   526  				},
   527  			},
   528  			expectRes: framework.NewStatus(framework.Unschedulable),
   529  		},
   530  		{
   531  			name: "node memorymanager on, overcommit not allowed",
   532  			node: &v1.Node{
   533  				ObjectMeta: v12.ObjectMeta{
   534  					Name: "node1",
   535  					Annotations: map[string]string{
   536  						"katalyst.kubewharf.io/cpu_overcommit_ratio":     "2.0",
   537  						"katalyst.kubewharf.io/memory_overcommit_ratio":  "1.5",
   538  						"katalyst.kubewharf.io/original_allocatable_cpu": "16000",
   539  					},
   540  				},
   541  				Status: v1.NodeStatus{
   542  					Allocatable: map[v1.ResourceName]resource.Quantity{
   543  						v1.ResourceCPU:    resource.MustParse("32"),
   544  						v1.ResourceMemory: resource.MustParse("32Gi"),
   545  					},
   546  				},
   547  			},
   548  			cnrs: []*v1alpha1.CustomNodeResource{
   549  				{
   550  					ObjectMeta: v12.ObjectMeta{
   551  						Name: "node1",
   552  						Annotations: map[string]string{
   553  							"katalyst.kubewharf.io/overcommit_cpu_manager":    "none",
   554  							"katalyst.kubewharf.io/overcommit_memory_manager": "Static",
   555  							"katalyst.kubewharf.io/guaranteed_cpus":           "0",
   556  						},
   557  					},
   558  				},
   559  			},
   560  			requested: &framework.Resource{
   561  				MilliCPU: 0,
   562  			},
   563  			existPods: []*v1.Pod{},
   564  			pod: &v1.Pod{
   565  				ObjectMeta: v12.ObjectMeta{
   566  					Name: "pod1",
   567  				},
   568  				Spec: v1.PodSpec{
   569  					Containers: []v1.Container{
   570  						{
   571  							Name: "testContainer",
   572  							Resources: v1.ResourceRequirements{
   573  								Requests: map[v1.ResourceName]resource.Quantity{
   574  									v1.ResourceCPU:    resource.MustParse("4"),
   575  									v1.ResourceMemory: resource.MustParse("8Gi"),
   576  								},
   577  							},
   578  						},
   579  					},
   580  				},
   581  			},
   582  			expectRes: framework.NewStatus(framework.Unschedulable),
   583  		},
   584  	}
   585  
   586  	for _, tc := range testCases {
   587  		t.Run(tc.name, func(t *testing.T) {
   588  			cnrs := tc.cnrs
   589  			for _, cnr := range cnrs {
   590  				cache.GetCache().AddOrUpdateCNR(cnr)
   591  			}
   592  			for _, pod := range tc.existPods {
   593  				cache.GetCache().AddPod(pod)
   594  			}
   595  			defer func() {
   596  				for _, cnr := range cnrs {
   597  					cache.GetCache().RemoveCNR(cnr)
   598  				}
   599  			}()
   600  
   601  			nodeInfo := framework.NewNodeInfo()
   602  			nodeInfo.SetNode(tc.node)
   603  			nodeInfo.Requested = tc.requested
   604  
   605  			n := &NodeOvercommitment{}
   606  			cs := framework.NewCycleState()
   607  			res, stat := n.PreFilter(context.TODO(), cs, tc.pod)
   608  			assert.Nil(t, res)
   609  			assert.Nil(t, stat)
   610  
   611  			status := n.Filter(context.TODO(), cs, tc.pod, nodeInfo)
   612  			assert.Equal(t, tc.expectRes.Code(), status.Code())
   613  		})
   614  	}
   615  }