Skip to content

Commit 555efba

Browse files
authored
Merge pull request kubernetes#128123 from felipeagger/feat/add-updatepodsandbox-cri-method
[FG:InPlacePodVerticalScaling] Add UpdatePodSandboxResources CRI method
2 parents 18e5a4d + 41e3efd commit 555efba

18 files changed

+2008
-510
lines changed

pkg/kubelet/kuberuntime/helpers.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"k8s.io/apimachinery/pkg/types"
2929
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
3030
"k8s.io/klog/v2"
31+
"k8s.io/kubernetes/pkg/kubelet/cm"
3132
kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
3233
"k8s.io/kubernetes/pkg/security/apparmor"
3334
)
@@ -337,3 +338,86 @@ func getAppArmorProfile(pod *v1.Pod, container *v1.Container) (*runtimeapi.Secur
337338

338339
return securityProfile, deprecatedProfile, nil
339340
}
341+
342+
func mergeResourceConfig(source, update *cm.ResourceConfig) *cm.ResourceConfig {
343+
if source == nil {
344+
return update
345+
}
346+
if update == nil {
347+
return source
348+
}
349+
350+
merged := *source
351+
352+
if update.Memory != nil {
353+
merged.Memory = update.Memory
354+
}
355+
if update.CPUSet.Size() > 0 {
356+
merged.CPUSet = update.CPUSet
357+
}
358+
if update.CPUShares != nil {
359+
merged.CPUShares = update.CPUShares
360+
}
361+
if update.CPUQuota != nil {
362+
merged.CPUQuota = update.CPUQuota
363+
}
364+
if update.CPUPeriod != nil {
365+
merged.CPUPeriod = update.CPUPeriod
366+
}
367+
if update.PidsLimit != nil {
368+
merged.PidsLimit = update.PidsLimit
369+
}
370+
371+
if update.HugePageLimit != nil {
372+
if merged.HugePageLimit == nil {
373+
merged.HugePageLimit = make(map[int64]int64)
374+
}
375+
for k, v := range update.HugePageLimit {
376+
merged.HugePageLimit[k] = v
377+
}
378+
}
379+
380+
if update.Unified != nil {
381+
if merged.Unified == nil {
382+
merged.Unified = make(map[string]string)
383+
}
384+
for k, v := range update.Unified {
385+
merged.Unified[k] = v
386+
}
387+
}
388+
389+
return &merged
390+
}
391+
392+
func convertResourceConfigToLinuxContainerResources(rc *cm.ResourceConfig) *runtimeapi.LinuxContainerResources {
393+
if rc == nil {
394+
return nil
395+
}
396+
397+
lcr := &runtimeapi.LinuxContainerResources{}
398+
399+
if rc.CPUPeriod != nil {
400+
lcr.CpuPeriod = int64(*rc.CPUPeriod)
401+
}
402+
if rc.CPUQuota != nil {
403+
lcr.CpuQuota = *rc.CPUQuota
404+
}
405+
if rc.CPUShares != nil {
406+
lcr.CpuShares = int64(*rc.CPUShares)
407+
}
408+
if rc.Memory != nil {
409+
lcr.MemoryLimitInBytes = *rc.Memory
410+
}
411+
if rc.CPUSet.Size() > 0 {
412+
lcr.CpusetCpus = rc.CPUSet.String()
413+
}
414+
415+
if rc.Unified != nil {
416+
lcr.Unified = make(map[string]string, len(rc.Unified))
417+
for k, v := range rc.Unified {
418+
lcr.Unified[k] = v
419+
}
420+
}
421+
422+
return lcr
423+
}

pkg/kubelet/kuberuntime/helpers_linux.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,10 @@ limitations under the License.
2020
package kuberuntime
2121

2222
import (
23-
"k8s.io/kubernetes/pkg/kubelet/cm"
2423
"math"
24+
25+
v1 "k8s.io/api/core/v1"
26+
"k8s.io/kubernetes/pkg/kubelet/cm"
2527
)
2628

2729
const (
@@ -77,3 +79,40 @@ func quotaToMilliCPU(quota int64, period int64) int64 {
7779
}
7880
return (quota * milliCPUToCPU) / period
7981
}
82+
83+
func subtractOverheadFromResourceConfig(resCfg *cm.ResourceConfig, pod *v1.Pod) *cm.ResourceConfig {
84+
if resCfg == nil {
85+
return nil
86+
}
87+
88+
rc := *resCfg
89+
90+
if pod.Spec.Overhead != nil {
91+
if cpu, found := pod.Spec.Overhead[v1.ResourceCPU]; found {
92+
if rc.CPUPeriod != nil {
93+
cpuPeriod := int64(*rc.CPUPeriod)
94+
cpuQuota := *rc.CPUQuota - cm.MilliCPUToQuota(cpu.MilliValue(), cpuPeriod)
95+
rc.CPUQuota = &cpuQuota
96+
}
97+
98+
if rc.CPUShares != nil {
99+
totalCPUMilli := sharesToMilliCPU(int64(*rc.CPUShares))
100+
cpuShares := cm.MilliCPUToShares(totalCPUMilli - cpu.MilliValue())
101+
rc.CPUShares = &cpuShares
102+
}
103+
}
104+
105+
if memory, found := pod.Spec.Overhead[v1.ResourceMemory]; found {
106+
if rc.Memory != nil {
107+
currMemory := *rc.Memory
108+
109+
if mem, ok := memory.AsInt64(); ok {
110+
currMemory -= mem
111+
}
112+
113+
rc.Memory = &currMemory
114+
}
115+
}
116+
}
117+
return &rc
118+
}

pkg/kubelet/kuberuntime/helpers_linux_test.go

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/stretchr/testify/require"
2525

2626
v1 "k8s.io/api/core/v1"
27+
"k8s.io/apimachinery/pkg/api/resource"
2728
utilfeature "k8s.io/apiserver/pkg/util/feature"
2829
featuregatetesting "k8s.io/component-base/featuregate/testing"
2930
runtimeapi "k8s.io/cri-api/pkg/apis/runtime/v1"
@@ -494,3 +495,230 @@ func TestQuotaToMilliCPU(t *testing.T) {
494495
})
495496
}
496497
}
498+
499+
func TestSubtractOverheadFromResourceConfig(t *testing.T) {
500+
podCPUMilli := resource.MustParse("200m")
501+
podMemory := resource.MustParse("256Mi")
502+
podOverheadCPUMilli := resource.MustParse("100m")
503+
podOverheadMemory := resource.MustParse("64Mi")
504+
505+
resCfg := &cm.ResourceConfig{
506+
Memory: int64Ptr(335544320),
507+
CPUShares: uint64Ptr(306),
508+
CPUPeriod: uint64Ptr(100000),
509+
CPUQuota: int64Ptr(30000),
510+
}
511+
512+
for _, tc := range []struct {
513+
name string
514+
cfgInput *cm.ResourceConfig
515+
pod *v1.Pod
516+
expected *cm.ResourceConfig
517+
}{
518+
{
519+
name: "withoutOverhead",
520+
cfgInput: resCfg,
521+
pod: &v1.Pod{
522+
Spec: v1.PodSpec{
523+
Containers: []v1.Container{
524+
{
525+
Name: "foo",
526+
Resources: v1.ResourceRequirements{
527+
Requests: v1.ResourceList{
528+
v1.ResourceCPU: podCPUMilli,
529+
},
530+
Limits: v1.ResourceList{
531+
v1.ResourceCPU: podCPUMilli,
532+
v1.ResourceMemory: podMemory,
533+
},
534+
},
535+
},
536+
},
537+
},
538+
},
539+
expected: &cm.ResourceConfig{
540+
Memory: int64Ptr(335544320),
541+
CPUShares: uint64Ptr(306),
542+
CPUPeriod: uint64Ptr(100000),
543+
CPUQuota: int64Ptr(30000),
544+
},
545+
},
546+
{
547+
name: "withoutCPUOverhead",
548+
cfgInput: resCfg,
549+
pod: &v1.Pod{
550+
Spec: v1.PodSpec{
551+
Containers: []v1.Container{
552+
{
553+
Name: "foo",
554+
Resources: v1.ResourceRequirements{
555+
Requests: v1.ResourceList{
556+
v1.ResourceCPU: podCPUMilli,
557+
},
558+
Limits: v1.ResourceList{
559+
v1.ResourceCPU: podCPUMilli,
560+
v1.ResourceMemory: podMemory,
561+
},
562+
},
563+
},
564+
},
565+
Overhead: v1.ResourceList{
566+
v1.ResourceMemory: podOverheadMemory,
567+
},
568+
},
569+
},
570+
expected: &cm.ResourceConfig{
571+
Memory: int64Ptr(268435456),
572+
CPUShares: uint64Ptr(306),
573+
CPUPeriod: uint64Ptr(100000),
574+
CPUQuota: int64Ptr(30000),
575+
},
576+
},
577+
{
578+
name: "withoutMemoryOverhead",
579+
cfgInput: resCfg,
580+
pod: &v1.Pod{
581+
Spec: v1.PodSpec{
582+
Containers: []v1.Container{
583+
{
584+
Name: "foo",
585+
Resources: v1.ResourceRequirements{
586+
Requests: v1.ResourceList{
587+
v1.ResourceCPU: podCPUMilli,
588+
},
589+
Limits: v1.ResourceList{
590+
v1.ResourceCPU: podCPUMilli,
591+
v1.ResourceMemory: podMemory,
592+
},
593+
},
594+
},
595+
},
596+
Overhead: v1.ResourceList{
597+
v1.ResourceCPU: podOverheadCPUMilli,
598+
},
599+
},
600+
},
601+
expected: &cm.ResourceConfig{
602+
Memory: int64Ptr(335544320),
603+
CPUShares: uint64Ptr(203),
604+
CPUPeriod: uint64Ptr(100000),
605+
CPUQuota: int64Ptr(20000),
606+
},
607+
},
608+
{
609+
name: "withoutCPUPeriod",
610+
cfgInput: &cm.ResourceConfig{
611+
Memory: int64Ptr(335544320),
612+
CPUShares: uint64Ptr(306),
613+
},
614+
pod: &v1.Pod{
615+
Spec: v1.PodSpec{
616+
Containers: []v1.Container{
617+
{
618+
Name: "foo",
619+
Resources: v1.ResourceRequirements{
620+
Requests: v1.ResourceList{
621+
v1.ResourceCPU: podCPUMilli,
622+
},
623+
Limits: v1.ResourceList{
624+
v1.ResourceCPU: podCPUMilli,
625+
v1.ResourceMemory: podMemory,
626+
},
627+
},
628+
},
629+
},
630+
Overhead: v1.ResourceList{
631+
v1.ResourceCPU: podOverheadCPUMilli,
632+
},
633+
},
634+
},
635+
expected: &cm.ResourceConfig{
636+
Memory: int64Ptr(335544320),
637+
CPUShares: uint64Ptr(203),
638+
},
639+
},
640+
{
641+
name: "withoutCPUShares",
642+
cfgInput: &cm.ResourceConfig{
643+
Memory: int64Ptr(335544320),
644+
CPUPeriod: uint64Ptr(100000),
645+
CPUQuota: int64Ptr(30000),
646+
},
647+
pod: &v1.Pod{
648+
Spec: v1.PodSpec{
649+
Containers: []v1.Container{
650+
{
651+
Name: "foo",
652+
Resources: v1.ResourceRequirements{
653+
Requests: v1.ResourceList{
654+
v1.ResourceCPU: podCPUMilli,
655+
},
656+
Limits: v1.ResourceList{
657+
v1.ResourceCPU: podCPUMilli,
658+
v1.ResourceMemory: podMemory,
659+
},
660+
},
661+
},
662+
},
663+
Overhead: v1.ResourceList{
664+
v1.ResourceCPU: podOverheadCPUMilli,
665+
},
666+
},
667+
},
668+
expected: &cm.ResourceConfig{
669+
Memory: int64Ptr(335544320),
670+
CPUPeriod: uint64Ptr(100000),
671+
CPUQuota: int64Ptr(20000),
672+
},
673+
},
674+
{
675+
name: "withOverhead",
676+
cfgInput: resCfg,
677+
pod: &v1.Pod{
678+
Spec: v1.PodSpec{
679+
Containers: []v1.Container{
680+
{
681+
Name: "foo",
682+
Resources: v1.ResourceRequirements{
683+
Requests: v1.ResourceList{
684+
v1.ResourceCPU: podCPUMilli,
685+
},
686+
Limits: v1.ResourceList{
687+
v1.ResourceCPU: podCPUMilli,
688+
v1.ResourceMemory: podMemory,
689+
},
690+
},
691+
},
692+
},
693+
Overhead: v1.ResourceList{
694+
v1.ResourceCPU: podOverheadCPUMilli,
695+
v1.ResourceMemory: podOverheadMemory,
696+
},
697+
},
698+
},
699+
expected: &cm.ResourceConfig{
700+
Memory: int64Ptr(268435456),
701+
CPUShares: uint64Ptr(203),
702+
CPUPeriod: uint64Ptr(100000),
703+
CPUQuota: int64Ptr(20000),
704+
},
705+
},
706+
} {
707+
t.Run(tc.name, func(t *testing.T) {
708+
gotCfg := subtractOverheadFromResourceConfig(tc.cfgInput, tc.pod)
709+
710+
if tc.expected.CPUPeriod != nil && *gotCfg.CPUPeriod != *tc.expected.CPUPeriod {
711+
t.Errorf("Test %s: expected CPUPeriod %v, but got %v", tc.name, *tc.expected.CPUPeriod, *gotCfg.CPUPeriod)
712+
}
713+
if tc.expected.CPUQuota != nil && *gotCfg.CPUQuota != *tc.expected.CPUQuota {
714+
t.Errorf("Test %s: expected CPUQuota %v, but got %v", tc.name, *tc.expected.CPUQuota, *gotCfg.CPUQuota)
715+
}
716+
if tc.expected.CPUShares != nil && *gotCfg.CPUShares != *tc.expected.CPUShares {
717+
t.Errorf("Test %s: expected CPUShares %v, but got %v", tc.name, *tc.expected.CPUShares, *gotCfg.CPUShares)
718+
}
719+
if tc.expected.Memory != nil && *gotCfg.Memory != *tc.expected.Memory {
720+
t.Errorf("Test %s: expected Memory %v, but got %v", tc.name, *tc.expected.Memory, *gotCfg.Memory)
721+
}
722+
})
723+
}
724+
}

0 commit comments

Comments
 (0)