sigs.k8s.io/kueue@v0.6.2/pkg/workload/resources_test.go (about)

     1  /*
     2  Copyright 2023 The Kubernetes Authors.
     3  Licensed under the Apache License, Version 2.0 (the "License");
     4  you may not use this file except in compliance with the License.
     5  You may obtain a copy of the License at
     6  	http://www.apache.org/licenses/LICENSE-2.0
     7  Unless required by applicable law or agreed to in writing, software
     8  distributed under the License is distributed on an "AS IS" BASIS,
     9  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    10  See the License for the specific language governing permissions and
    11  limitations under the License.
    12  */
    13  
    14  package workload
    15  
    16  import (
    17  	"testing"
    18  
    19  	"github.com/google/go-cmp/cmp"
    20  	corev1 "k8s.io/api/core/v1"
    21  	nodev1 "k8s.io/api/node/v1"
    22  	"k8s.io/apimachinery/pkg/api/resource"
    23  
    24  	kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1"
    25  	"sigs.k8s.io/kueue/pkg/controller/core/indexer"
    26  	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
    27  )
    28  
    29  func TestAdjustResources(t *testing.T) {
    30  	cases := map[string]struct {
    31  		runtimeClasses []nodev1.RuntimeClass
    32  		limitranges    []corev1.LimitRange
    33  		wl             *kueue.Workload
    34  		wantWl         *kueue.Workload
    35  	}{
    36  		"Handle runtimeClass with podOverHead": {
    37  			runtimeClasses: []nodev1.RuntimeClass{
    38  				utiltesting.MakeRuntimeClass("runtime-a", "handler-a").
    39  					PodOverhead(corev1.ResourceList{
    40  						corev1.ResourceCPU:    ResourceQuantity(corev1.ResourceCPU, 1),
    41  						corev1.ResourceMemory: ResourceQuantity(corev1.ResourceMemory, 1024),
    42  					}).
    43  					RuntimeClass,
    44  			},
    45  			wl: utiltesting.MakeWorkload("foo", "").
    46  				PodSets(
    47  					*utiltesting.MakePodSet("a", 1).
    48  						RuntimeClass("runtime-a").
    49  						Obj(),
    50  					*utiltesting.MakePodSet("b", 1).
    51  						Obj(),
    52  					*utiltesting.MakePodSet("c", 1).
    53  						RuntimeClass("runtime-a").
    54  						PodOverHead(
    55  							corev1.ResourceList{
    56  								corev1.ResourceCPU:    ResourceQuantity(corev1.ResourceCPU, 2),
    57  								corev1.ResourceMemory: ResourceQuantity(corev1.ResourceMemory, 2048),
    58  							}).
    59  						Obj(),
    60  					*utiltesting.MakePodSet("d", 1).
    61  						RuntimeClass("runtime-d").
    62  						Obj(),
    63  					*utiltesting.MakePodSet("e", 1).
    64  						RuntimeClass("runtime-e").
    65  						PodOverHead(
    66  							corev1.ResourceList{
    67  								corev1.ResourceCPU:    ResourceQuantity(corev1.ResourceCPU, 2),
    68  								corev1.ResourceMemory: ResourceQuantity(corev1.ResourceMemory, 2048),
    69  							}).
    70  						Obj(),
    71  				).
    72  				Obj(),
    73  			wantWl: utiltesting.MakeWorkload("foo", "").
    74  				PodSets(
    75  					*utiltesting.MakePodSet("a", 1).
    76  						RuntimeClass("runtime-a").
    77  						PodOverHead(
    78  							corev1.ResourceList{
    79  								corev1.ResourceCPU:    ResourceQuantity(corev1.ResourceCPU, 1),
    80  								corev1.ResourceMemory: ResourceQuantity(corev1.ResourceMemory, 1024),
    81  							}).
    82  						Obj(),
    83  					*utiltesting.MakePodSet("b", 1).
    84  						Obj(),
    85  					*utiltesting.MakePodSet("c", 1).
    86  						RuntimeClass("runtime-a").
    87  						PodOverHead(
    88  							corev1.ResourceList{
    89  								corev1.ResourceCPU:    ResourceQuantity(corev1.ResourceCPU, 2),
    90  								corev1.ResourceMemory: ResourceQuantity(corev1.ResourceMemory, 2048),
    91  							}).
    92  						Obj(),
    93  					*utiltesting.MakePodSet("d", 1).
    94  						RuntimeClass("runtime-d").
    95  						Obj(),
    96  					*utiltesting.MakePodSet("e", 1).
    97  						RuntimeClass("runtime-e").
    98  						PodOverHead(
    99  							corev1.ResourceList{
   100  								corev1.ResourceCPU:    ResourceQuantity(corev1.ResourceCPU, 2),
   101  								corev1.ResourceMemory: ResourceQuantity(corev1.ResourceMemory, 2048),
   102  							}).
   103  						Obj(),
   104  				).
   105  				Obj(),
   106  		},
   107  		"Handle runtimeClass without podOverHead": {
   108  			runtimeClasses: []nodev1.RuntimeClass{
   109  				utiltesting.MakeRuntimeClass("runtime-a", "handler-a").
   110  					RuntimeClass,
   111  			},
   112  			wl: utiltesting.MakeWorkload("foo", "").
   113  				PodSets(
   114  					*utiltesting.MakePodSet("a", 1).
   115  						RuntimeClass("runtime-a").
   116  						Obj(),
   117  					*utiltesting.MakePodSet("b", 1).
   118  						Obj(),
   119  					*utiltesting.MakePodSet("c", 1).
   120  						RuntimeClass("runtime-a").
   121  						PodOverHead(
   122  							corev1.ResourceList{
   123  								corev1.ResourceCPU:    ResourceQuantity(corev1.ResourceCPU, 1),
   124  								corev1.ResourceMemory: ResourceQuantity(corev1.ResourceMemory, 1024),
   125  							}).
   126  						Obj(),
   127  					*utiltesting.MakePodSet("d", 1).
   128  						RuntimeClass("runtime-d").
   129  						Obj(),
   130  					*utiltesting.MakePodSet("e", 1).
   131  						RuntimeClass("runtime-e").
   132  						PodOverHead(
   133  							corev1.ResourceList{
   134  								corev1.ResourceCPU:    ResourceQuantity(corev1.ResourceCPU, 1),
   135  								corev1.ResourceMemory: ResourceQuantity(corev1.ResourceMemory, 1024),
   136  							}).
   137  						Obj(),
   138  				).
   139  				Obj(),
   140  			wantWl: utiltesting.MakeWorkload("foo", "").
   141  				PodSets(
   142  					*utiltesting.MakePodSet("a", 1).
   143  						RuntimeClass("runtime-a").
   144  						Obj(),
   145  					*utiltesting.MakePodSet("b", 1).
   146  						Obj(),
   147  					*utiltesting.MakePodSet("c", 1).
   148  						RuntimeClass("runtime-a").
   149  						PodOverHead(
   150  							corev1.ResourceList{
   151  								corev1.ResourceCPU:    ResourceQuantity(corev1.ResourceCPU, 1),
   152  								corev1.ResourceMemory: ResourceQuantity(corev1.ResourceMemory, 1024),
   153  							}).
   154  						Obj(),
   155  					*utiltesting.MakePodSet("d", 1).
   156  						RuntimeClass("runtime-d").
   157  						Obj(),
   158  					*utiltesting.MakePodSet("e", 1).
   159  						RuntimeClass("runtime-e").
   160  						PodOverHead(
   161  							corev1.ResourceList{
   162  								corev1.ResourceCPU:    ResourceQuantity(corev1.ResourceCPU, 1),
   163  								corev1.ResourceMemory: ResourceQuantity(corev1.ResourceMemory, 1024),
   164  							}).
   165  						Obj(),
   166  				).
   167  				Obj(),
   168  		},
   169  		"Handle container limit range": {
   170  			limitranges: []corev1.LimitRange{
   171  				utiltesting.MakeLimitRange("foo", "").
   172  					WithType(corev1.LimitTypeContainer).
   173  					WithValue(
   174  						"Default", corev1.ResourceCPU, "4",
   175  					).
   176  					WithValue(
   177  						"DefaultRequest", corev1.ResourceCPU, "3",
   178  					).
   179  					WithValue(
   180  						"Max", corev1.ResourceCPU, "5",
   181  					).
   182  					WithValue(
   183  						"Min", corev1.ResourceCPU, "2",
   184  					).
   185  					LimitRange,
   186  			},
   187  			wl: utiltesting.MakeWorkload("foo", "").
   188  				PodSets(
   189  					*utiltesting.MakePodSet("a", 1).
   190  						InitContainers(corev1.Container{}).
   191  						Obj(),
   192  					*utiltesting.MakePodSet("b", 1).
   193  						InitContainers(corev1.Container{}).
   194  						Limit(corev1.ResourceCPU, "6").
   195  						Obj(),
   196  					*utiltesting.MakePodSet("c", 1).
   197  						InitContainers(corev1.Container{}).
   198  						Request(corev1.ResourceCPU, "1").
   199  						Obj(),
   200  				).
   201  				Obj(),
   202  			wantWl: utiltesting.MakeWorkload("foo", "").
   203  				PodSets(
   204  					*utiltesting.MakePodSet("a", 1).
   205  						Limit(corev1.ResourceCPU, "4").
   206  						Request(corev1.ResourceCPU, "3").
   207  						InitContainers(corev1.Container{
   208  							Resources: corev1.ResourceRequirements{
   209  								Limits: corev1.ResourceList{
   210  									corev1.ResourceCPU: *resource.NewQuantity(4, resource.DecimalSI),
   211  								},
   212  								Requests: corev1.ResourceList{
   213  									corev1.ResourceCPU: *resource.NewQuantity(3, resource.DecimalSI),
   214  								},
   215  							},
   216  						}).
   217  						Obj(),
   218  					*utiltesting.MakePodSet("b", 1).
   219  						Limit(corev1.ResourceCPU, "6").
   220  						Request(corev1.ResourceCPU, "3").
   221  						InitContainers(corev1.Container{
   222  							Resources: corev1.ResourceRequirements{
   223  								Limits: corev1.ResourceList{
   224  									corev1.ResourceCPU: *resource.NewQuantity(4, resource.DecimalSI),
   225  								},
   226  								Requests: corev1.ResourceList{
   227  									corev1.ResourceCPU: *resource.NewQuantity(3, resource.DecimalSI),
   228  								},
   229  							},
   230  						}).
   231  						Obj(),
   232  					*utiltesting.MakePodSet("c", 1).
   233  						Limit(corev1.ResourceCPU, "4").
   234  						Request(corev1.ResourceCPU, "1").
   235  						InitContainers(corev1.Container{
   236  							Resources: corev1.ResourceRequirements{
   237  								Limits: corev1.ResourceList{
   238  									corev1.ResourceCPU: *resource.NewQuantity(4, resource.DecimalSI),
   239  								},
   240  								Requests: corev1.ResourceList{
   241  									corev1.ResourceCPU: *resource.NewQuantity(3, resource.DecimalSI),
   242  								},
   243  							},
   244  						}).
   245  						Obj(),
   246  				).
   247  				Obj(),
   248  		},
   249  		"Handle pod limit range": {
   250  			limitranges: []corev1.LimitRange{
   251  				utiltesting.MakeLimitRange("foo", "").
   252  					WithType(corev1.LimitTypePod).
   253  					WithValue(
   254  						"Default", corev1.ResourceCPU, "4",
   255  					).
   256  					WithValue(
   257  						"DefaultRequest", corev1.ResourceCPU, "3",
   258  					).
   259  					WithValue(
   260  						"Max", corev1.ResourceCPU, "5",
   261  					).
   262  					WithValue(
   263  						"Min", corev1.ResourceCPU, "2",
   264  					).
   265  					LimitRange,
   266  			},
   267  			wl: utiltesting.MakeWorkload("foo", "").
   268  				PodSets(
   269  					*utiltesting.MakePodSet("a", 1).
   270  						Obj(),
   271  					*utiltesting.MakePodSet("b", 1).
   272  						Limit(corev1.ResourceCPU, "6").
   273  						Request(corev1.ResourceCPU, "1").
   274  						Obj(),
   275  				).
   276  				Obj(),
   277  			wantWl: utiltesting.MakeWorkload("foo", "").
   278  				PodSets(
   279  					*utiltesting.MakePodSet("a", 1).
   280  						Obj(),
   281  					*utiltesting.MakePodSet("b", 1).
   282  						Limit(corev1.ResourceCPU, "6").
   283  						Request(corev1.ResourceCPU, "1").
   284  						Obj(),
   285  				).
   286  				Obj(),
   287  		},
   288  		"Handle empty container limit range": {
   289  			limitranges: []corev1.LimitRange{
   290  				utiltesting.MakeLimitRange("foo", "").
   291  					WithType(corev1.LimitTypeContainer).
   292  					LimitRange,
   293  			},
   294  			wl: utiltesting.MakeWorkload("foo", "").
   295  				PodSets(
   296  					*utiltesting.MakePodSet("a", 1).
   297  						Obj(),
   298  					*utiltesting.MakePodSet("b", 1).
   299  						Limit(corev1.ResourceCPU, "6").
   300  						Request(corev1.ResourceCPU, "1").
   301  						Obj(),
   302  				).
   303  				Obj(),
   304  			wantWl: utiltesting.MakeWorkload("foo", "").
   305  				PodSets(
   306  					*utiltesting.MakePodSet("a", 1).
   307  						Obj(),
   308  					*utiltesting.MakePodSet("b", 1).
   309  						Limit(corev1.ResourceCPU, "6").
   310  						Request(corev1.ResourceCPU, "1").
   311  						Obj(),
   312  				).
   313  				Obj(),
   314  		},
   315  		"Apply limits to requests": {
   316  			wl: utiltesting.MakeWorkload("foo", "").
   317  				PodSets(
   318  					*utiltesting.MakePodSet("a", 1).
   319  						Limit(corev1.ResourceCPU, "1").
   320  						Limit(corev1.ResourceMemory, "1Gi").
   321  						InitContainers(corev1.Container{
   322  							Resources: corev1.ResourceRequirements{
   323  								Limits: corev1.ResourceList{
   324  									corev1.ResourceCPU:    *resource.NewQuantity(1, resource.DecimalSI),
   325  									corev1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI),
   326  								},
   327  							},
   328  						}).
   329  						Obj(),
   330  					*utiltesting.MakePodSet("b", 1).
   331  						Request(corev1.ResourceCPU, "2").
   332  						Limit(corev1.ResourceCPU, "3").
   333  						Limit(corev1.ResourceMemory, "1Gi").
   334  						InitContainers(corev1.Container{
   335  							Resources: corev1.ResourceRequirements{
   336  								Limits: corev1.ResourceList{
   337  									corev1.ResourceCPU:    *resource.NewQuantity(3, resource.DecimalSI),
   338  									corev1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI),
   339  								},
   340  								Requests: corev1.ResourceList{
   341  									corev1.ResourceCPU: *resource.NewQuantity(2, resource.DecimalSI),
   342  								},
   343  							},
   344  						}).
   345  						Obj(),
   346  					*utiltesting.MakePodSet("c", 1).
   347  						Request(corev1.ResourceMemory, "1Gi").
   348  						Limit(corev1.ResourceCPU, "1").
   349  						Limit(corev1.ResourceMemory, "3Gi").
   350  						InitContainers(corev1.Container{
   351  							Resources: corev1.ResourceRequirements{
   352  								Limits: corev1.ResourceList{
   353  									corev1.ResourceCPU:    *resource.NewQuantity(1, resource.DecimalSI),
   354  									corev1.ResourceMemory: *resource.NewQuantity(3, resource.BinarySI),
   355  								},
   356  								Requests: corev1.ResourceList{
   357  									corev1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI),
   358  								},
   359  							},
   360  						}).
   361  						Obj(),
   362  					*utiltesting.MakePodSet("d", 1).
   363  						Limit(corev1.ResourceCPU, "1").
   364  						InitContainers(corev1.Container{
   365  							Resources: corev1.ResourceRequirements{
   366  								Limits: corev1.ResourceList{
   367  									corev1.ResourceCPU: *resource.NewQuantity(1, resource.DecimalSI),
   368  								},
   369  							},
   370  						}).
   371  						Obj(),
   372  					*utiltesting.MakePodSet("e", 1).
   373  						Request(corev1.ResourceMemory, "1Gi").
   374  						InitContainers(corev1.Container{
   375  							Resources: corev1.ResourceRequirements{
   376  								Requests: corev1.ResourceList{
   377  									corev1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI),
   378  								},
   379  							},
   380  						}).
   381  						Obj(),
   382  				).
   383  				Obj(),
   384  			wantWl: utiltesting.MakeWorkload("foo", "").
   385  				PodSets(
   386  					*utiltesting.MakePodSet("a", 1).
   387  						Limit(corev1.ResourceCPU, "1").
   388  						Limit(corev1.ResourceMemory, "1Gi").
   389  						Request(corev1.ResourceCPU, "1").
   390  						Request(corev1.ResourceMemory, "1Gi").
   391  						InitContainers(corev1.Container{
   392  							Resources: corev1.ResourceRequirements{
   393  								Limits: corev1.ResourceList{
   394  									corev1.ResourceCPU:    *resource.NewQuantity(1, resource.DecimalSI),
   395  									corev1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI),
   396  								},
   397  								Requests: corev1.ResourceList{
   398  									corev1.ResourceCPU:    *resource.NewQuantity(1, resource.DecimalSI),
   399  									corev1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI),
   400  								},
   401  							},
   402  						}).
   403  						Obj(),
   404  					*utiltesting.MakePodSet("b", 1).
   405  						Limit(corev1.ResourceCPU, "3").
   406  						Limit(corev1.ResourceMemory, "1Gi").
   407  						Request(corev1.ResourceCPU, "2").
   408  						Request(corev1.ResourceMemory, "1Gi").
   409  						InitContainers(corev1.Container{
   410  							Resources: corev1.ResourceRequirements{
   411  								Limits: corev1.ResourceList{
   412  									corev1.ResourceCPU:    *resource.NewQuantity(3, resource.DecimalSI),
   413  									corev1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI),
   414  								},
   415  								Requests: corev1.ResourceList{
   416  									corev1.ResourceCPU:    *resource.NewQuantity(2, resource.DecimalSI),
   417  									corev1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI),
   418  								},
   419  							},
   420  						}).
   421  						Obj(),
   422  					*utiltesting.MakePodSet("c", 1).
   423  						Limit(corev1.ResourceCPU, "1").
   424  						Limit(corev1.ResourceMemory, "3Gi").
   425  						Request(corev1.ResourceCPU, "1").
   426  						Request(corev1.ResourceMemory, "1Gi").
   427  						InitContainers(corev1.Container{
   428  							Resources: corev1.ResourceRequirements{
   429  								Limits: corev1.ResourceList{
   430  									corev1.ResourceCPU:    *resource.NewQuantity(1, resource.DecimalSI),
   431  									corev1.ResourceMemory: *resource.NewQuantity(3, resource.BinarySI),
   432  								},
   433  								Requests: corev1.ResourceList{
   434  									corev1.ResourceCPU:    *resource.NewQuantity(1, resource.DecimalSI),
   435  									corev1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI),
   436  								},
   437  							},
   438  						}).
   439  						Obj(),
   440  					*utiltesting.MakePodSet("d", 1).
   441  						Limit(corev1.ResourceCPU, "1").
   442  						Request(corev1.ResourceCPU, "1").
   443  						InitContainers(corev1.Container{
   444  							Resources: corev1.ResourceRequirements{
   445  								Limits: corev1.ResourceList{
   446  									corev1.ResourceCPU: *resource.NewQuantity(1, resource.DecimalSI),
   447  								},
   448  								Requests: corev1.ResourceList{
   449  									corev1.ResourceCPU: *resource.NewQuantity(1, resource.DecimalSI),
   450  								},
   451  							},
   452  						}).
   453  						Obj(),
   454  					*utiltesting.MakePodSet("e", 1).
   455  						Request(corev1.ResourceMemory, "1Gi").
   456  						InitContainers(corev1.Container{
   457  							Resources: corev1.ResourceRequirements{
   458  								Requests: corev1.ResourceList{
   459  									corev1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI),
   460  								},
   461  							},
   462  						}).
   463  						Obj(),
   464  				).
   465  				Obj(),
   466  		},
   467  	}
   468  	for name, tc := range cases {
   469  		t.Run(name, func(t *testing.T) {
   470  			cl := utiltesting.NewClientBuilder().WithLists(
   471  				&nodev1.RuntimeClassList{Items: tc.runtimeClasses},
   472  				&corev1.LimitRangeList{Items: tc.limitranges},
   473  			).WithIndex(&corev1.LimitRange{}, indexer.LimitRangeHasContainerType, indexer.IndexLimitRangeHasContainerType).
   474  				Build()
   475  			ctx, _ := utiltesting.ContextWithLog(t)
   476  			AdjustResources(ctx, cl, tc.wl)
   477  			if diff := cmp.Diff(tc.wl, tc.wantWl); diff != "" {
   478  				t.Errorf("Unexpected resources after adjusting (-want,+got): %s", diff)
   479  			}
   480  		})
   481  	}
   482  }