mirror of
https://github.com/k3s-io/kubernetes.git
synced 2026-07-17 11:28:58 +00:00
Merge pull request #136759 from pravk03/ndf-guaranteedQos-fix
Remove `GuaranteedQoSPodCPUResize` declared feature
This commit is contained in:
@@ -36,11 +36,9 @@ func (a FeatureGateAdapter) Enabled(key string) bool {
|
||||
|
||||
// discoverNodeDeclaredFeatures determines the final set of node features to be declared by using the discovery library.
|
||||
func (kl *Kubelet) discoverNodeDeclaredFeatures() []string {
|
||||
staticConfig := nodedeclaredfeatures.StaticConfiguration{
|
||||
CPUManagerPolicy: kl.containerManager.GetNodeConfig().CPUManagerPolicy,
|
||||
}
|
||||
|
||||
adaptedFG := FeatureGateAdapter{FeatureGate: utilfeature.DefaultFeatureGate}
|
||||
// Add fields from node configuration fields as needed by registered features.
|
||||
staticConfig := nodedeclaredfeatures.StaticConfiguration{}
|
||||
cfg := &nodedeclaredfeatures.NodeConfiguration{
|
||||
FeatureGates: adaptedFG,
|
||||
StaticConfig: staticConfig,
|
||||
|
||||
@@ -21,73 +21,82 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
ndflib "k8s.io/component-helpers/nodedeclaredfeatures"
|
||||
ndffeatures "k8s.io/component-helpers/nodedeclaredfeatures/features"
|
||||
ndf "k8s.io/component-helpers/nodedeclaredfeatures"
|
||||
ndftesting "k8s.io/component-helpers/nodedeclaredfeatures/testing"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
"k8s.io/kubernetes/pkg/kubelet/cm"
|
||||
)
|
||||
|
||||
func TestGuaranteedPodExclusiveCPUsFeatureDiscovery(t *testing.T) {
|
||||
func TestDeclaredFeatureDiscovery(t *testing.T) {
|
||||
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.NodeDeclaredFeatures, true)
|
||||
|
||||
podLevelResourcesIPPRFeatureGate := features.InPlacePodLevelResourcesVerticalScaling
|
||||
featureMaxVersion := version.MustParseSemantic("v1.36.0")
|
||||
createMockFeature := func(t *testing.T, name string, cfg *ndf.NodeConfiguration) *ndftesting.MockFeature {
|
||||
mockFeature := ndftesting.NewMockFeature(t)
|
||||
mockFeature.SetName(name)
|
||||
mockFeature.SetMaxVersion(featureMaxVersion)
|
||||
mockFeature.SetDiscover(func(*ndf.NodeConfiguration) bool { return cfg.FeatureGates.Enabled(name) })
|
||||
return mockFeature
|
||||
}
|
||||
|
||||
testcases := []struct {
|
||||
name string
|
||||
cpuManagerPolicy string
|
||||
inplacePodResizeExclusiveCPUsEnable bool
|
||||
expectedFeature string
|
||||
expectFeature bool
|
||||
name string
|
||||
podLevelResourcesIPPREnabled bool
|
||||
featureDiscovered bool
|
||||
kubeletVersion *version.Version
|
||||
}{
|
||||
{
|
||||
name: "feature enabled with static cpu manager policy",
|
||||
cpuManagerPolicy: "static",
|
||||
inplacePodResizeExclusiveCPUsEnable: true,
|
||||
expectedFeature: "GuaranteedQoSPodCPUResize",
|
||||
expectFeature: true,
|
||||
name: "feature gate enabled, feature discovered",
|
||||
podLevelResourcesIPPREnabled: true,
|
||||
featureDiscovered: true,
|
||||
kubeletVersion: featureMaxVersion.SubtractMinor(1),
|
||||
},
|
||||
{
|
||||
name: "feature enabled with none cpu manager policy",
|
||||
cpuManagerPolicy: "none",
|
||||
inplacePodResizeExclusiveCPUsEnable: true,
|
||||
expectedFeature: "GuaranteedQoSPodCPUResize",
|
||||
expectFeature: true,
|
||||
name: "feature gate enabled, feature not discovered as kubelet version higher than max version",
|
||||
podLevelResourcesIPPREnabled: true,
|
||||
featureDiscovered: false,
|
||||
kubeletVersion: featureMaxVersion.AddMinor(1),
|
||||
},
|
||||
{
|
||||
name: "feature disabled with static cpu manager policy",
|
||||
cpuManagerPolicy: "static",
|
||||
inplacePodResizeExclusiveCPUsEnable: false,
|
||||
expectedFeature: "GuaranteedQoSPodCPUResize",
|
||||
expectFeature: false,
|
||||
},
|
||||
{
|
||||
name: "feature disabled with none cpu manager policy",
|
||||
cpuManagerPolicy: "none",
|
||||
inplacePodResizeExclusiveCPUsEnable: false,
|
||||
expectedFeature: "GuaranteedQoSPodCPUResize",
|
||||
expectFeature: true,
|
||||
name: "feature disabled and not discovered",
|
||||
podLevelResourcesIPPREnabled: false,
|
||||
featureDiscovered: false,
|
||||
kubeletVersion: featureMaxVersion.SubtractMinor(1),
|
||||
},
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.InPlacePodVerticalScalingExclusiveCPUs, tc.inplacePodResizeExclusiveCPUsEnable)
|
||||
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, podLevelResourcesIPPRFeatureGate, tc.podLevelResourcesIPPREnabled)
|
||||
|
||||
cfg := &ndf.NodeConfiguration{
|
||||
FeatureGates: FeatureGateAdapter{
|
||||
FeatureGate: utilfeature.DefaultFeatureGate,
|
||||
},
|
||||
Version: tc.kubeletVersion,
|
||||
}
|
||||
registeredFeatures := []ndf.Feature{
|
||||
createMockFeature(t, string(podLevelResourcesIPPRFeatureGate), cfg),
|
||||
}
|
||||
|
||||
testKubelet := newTestKubelet(t, false /* controllerAttachDetachEnabled */)
|
||||
defer testKubelet.Cleanup()
|
||||
kubelet := testKubelet.kubelet
|
||||
fakeCM := cm.NewFakeContainerManagerWithNodeConfig(cm.NodeConfig{
|
||||
CPUManagerPolicy: tc.cpuManagerPolicy,
|
||||
})
|
||||
fakeCM := cm.NewFakeContainerManagerWithNodeConfig(cm.NodeConfig{})
|
||||
kubelet.containerManager = fakeCM
|
||||
framework, err := ndflib.New(ndffeatures.AllFeatures)
|
||||
framework, err := ndf.New(registeredFeatures)
|
||||
require.NoError(t, err)
|
||||
kubelet.nodeDeclaredFeaturesFramework = framework
|
||||
kubelet.version = tc.kubeletVersion
|
||||
|
||||
features := kubelet.discoverNodeDeclaredFeatures()
|
||||
if tc.expectFeature {
|
||||
assert.Contains(t, features, tc.expectedFeature)
|
||||
if tc.featureDiscovered {
|
||||
assert.Contains(t, features, string(podLevelResourcesIPPRFeatureGate))
|
||||
} else {
|
||||
assert.NotContains(t, features, tc.expectedFeature)
|
||||
assert.NotContains(t, features, string(podLevelResourcesIPPRFeatureGate))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
Copyright 2025 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package inplacepodresize
|
||||
|
||||
import (
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
"k8s.io/component-helpers/nodedeclaredfeatures"
|
||||
)
|
||||
|
||||
// Ensure the feature struct implements the unified Feature interface.
|
||||
var _ nodedeclaredfeatures.Feature = &guaranteedQoSPodCPUResizeFeature{}
|
||||
|
||||
const (
|
||||
// IPPRExclusiveCPUsFeatureGate is the feature gate for IPPRExclusiveCPUsFeatureGate.
|
||||
IPPRExclusiveCPUsFeatureGate = "InPlacePodVerticalScalingExclusiveCPUs"
|
||||
// CPUManagerPolicyStatic is the value for the static CPUManagerPolicy.
|
||||
CPUManagerPolicyStatic = "static"
|
||||
// CPUManagerPolicyNone is the value for the none CPUManagerPolicy.
|
||||
CPUManagerPolicyNone = "none"
|
||||
// GuaranteedQoSPodCPUResize is a declared feature that indicates a node supports in-place pod resize for guaranteed QoS pods with exclusive CPUs.
|
||||
GuaranteedQoSPodCPUResize = "GuaranteedQoSPodCPUResize"
|
||||
)
|
||||
|
||||
// GuaranteedQoSPodCPUResizeFeature is the implementation of the `GuaranteedQoSPodCPUResize` feature.
|
||||
var GuaranteedQoSPodCPUResizeFeature = &guaranteedQoSPodCPUResizeFeature{}
|
||||
|
||||
type guaranteedQoSPodCPUResizeFeature struct{}
|
||||
|
||||
func (f *guaranteedQoSPodCPUResizeFeature) Name() string {
|
||||
return GuaranteedQoSPodCPUResize
|
||||
}
|
||||
|
||||
func (f *guaranteedQoSPodCPUResizeFeature) Discover(cfg *nodedeclaredfeatures.NodeConfiguration) bool {
|
||||
featureGateEnabled := cfg.FeatureGates.Enabled(IPPRExclusiveCPUsFeatureGate)
|
||||
cpuManagerPolicy := cfg.StaticConfig.CPUManagerPolicy
|
||||
if (featureGateEnabled && cpuManagerPolicy == CPUManagerPolicyStatic) || (cpuManagerPolicy == CPUManagerPolicyNone) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (f *guaranteedQoSPodCPUResizeFeature) InferForScheduling(podInfo *nodedeclaredfeatures.PodInfo) bool {
|
||||
// This feature is only relevant for pod updates (resizes).
|
||||
return false
|
||||
}
|
||||
|
||||
func (f *guaranteedQoSPodCPUResizeFeature) InferForUpdate(oldPodInfo, newPodInfo *nodedeclaredfeatures.PodInfo) bool {
|
||||
// Since this is an update, the QOS class must already be se ans must be the same for old and new pod spec.
|
||||
if oldPodInfo.Status != nil && oldPodInfo.Status.QOSClass != v1.PodQOSGuaranteed {
|
||||
return false
|
||||
}
|
||||
|
||||
oldPodSpec := oldPodInfo.Spec
|
||||
newPodSpec := newPodInfo.Spec
|
||||
|
||||
// Check if CPU request is changing for any container.
|
||||
for i := range oldPodSpec.Containers {
|
||||
oldCPU := oldPodSpec.Containers[i].Resources.Requests.Cpu()
|
||||
newCPU := newPodSpec.Containers[i].Resources.Requests.Cpu()
|
||||
if oldCPU != nil && newCPU != nil && !oldCPU.Equal(*newCPU) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (f *guaranteedQoSPodCPUResizeFeature) MaxVersion() *version.Version {
|
||||
return nil
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
Copyright 2025 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package inplacepodresize
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/component-helpers/nodedeclaredfeatures"
|
||||
test "k8s.io/component-helpers/nodedeclaredfeatures/testing"
|
||||
)
|
||||
|
||||
func TestGuaranteedQoSPodCPUResizeFeature_Discover(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
cpuManagerPolicy string
|
||||
gateEnabled bool
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "feature gate enabled, static policy",
|
||||
cpuManagerPolicy: CPUManagerPolicyStatic,
|
||||
gateEnabled: true,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "feature gate disabled, static policy",
|
||||
cpuManagerPolicy: CPUManagerPolicyStatic,
|
||||
gateEnabled: false,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "none policy",
|
||||
cpuManagerPolicy: CPUManagerPolicyNone,
|
||||
gateEnabled: true,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "feature gate missing",
|
||||
cpuManagerPolicy: CPUManagerPolicyStatic,
|
||||
gateEnabled: false, // Effectively disabled if not found
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
feature := &guaranteedQoSPodCPUResizeFeature{}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
mockFG := test.NewMockFeatureGate(t)
|
||||
mockFG.SetEnabled(IPPRExclusiveCPUsFeatureGate, tc.gateEnabled)
|
||||
|
||||
config := &nodedeclaredfeatures.NodeConfiguration{
|
||||
FeatureGates: mockFG,
|
||||
StaticConfig: nodedeclaredfeatures.StaticConfiguration{CPUManagerPolicy: tc.cpuManagerPolicy},
|
||||
}
|
||||
enabled := feature.Discover(config)
|
||||
if tc.expected != enabled {
|
||||
t.Fatalf("expected %v, got %v", tc.expected, enabled)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGuaranteedQoSPodCPUResizeFeature_InferForScheduling(t *testing.T) {
|
||||
feature := &guaranteedQoSPodCPUResizeFeature{}
|
||||
if feature.InferForScheduling(&nodedeclaredfeatures.PodInfo{Spec: &v1.PodSpec{}, Status: &v1.PodStatus{}}) {
|
||||
t.Fatalf("InferForScheduling should always be false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGuaranteedQoSPodCPUResizeFeature_InferFromUpdate(t *testing.T) {
|
||||
basePod := func() *v1.Pod {
|
||||
return &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{Name: "test-pod"},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "c1",
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{v1.ResourceCPU: resource.MustParse("1")},
|
||||
Limits: v1.ResourceList{v1.ResourceCPU: resource.MustParse("1")},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: v1.PodStatus{
|
||||
QOSClass: v1.PodQOSGuaranteed,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
oldPod *v1.Pod
|
||||
newPod *v1.Pod
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "not guaranteed QOS",
|
||||
oldPod: func() *v1.Pod { p := basePod(); p.Status.QOSClass = v1.PodQOSBurstable; return p }(),
|
||||
newPod: func() *v1.Pod { p := basePod(); p.Status.QOSClass = v1.PodQOSBurstable; return p }(),
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "no CPU request change",
|
||||
oldPod: basePod(),
|
||||
newPod: basePod(),
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "CPU request changed",
|
||||
oldPod: basePod(),
|
||||
newPod: func() *v1.Pod {
|
||||
p := basePod()
|
||||
p.Spec.Containers[0].Resources.Requests[v1.ResourceCPU] = resource.MustParse("2")
|
||||
return p
|
||||
}(),
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "CPU limit changed, but not request",
|
||||
oldPod: basePod(),
|
||||
newPod: func() *v1.Pod {
|
||||
p := basePod()
|
||||
p.Spec.Containers[0].Resources.Limits[v1.ResourceCPU] = resource.MustParse("2")
|
||||
return p
|
||||
}(),
|
||||
expected: false, // Only request changes matter for this feature
|
||||
},
|
||||
}
|
||||
|
||||
feature := &guaranteedQoSPodCPUResizeFeature{}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
oldPodInfo := &nodedeclaredfeatures.PodInfo{Spec: &tc.oldPod.Spec, Status: &tc.oldPod.Status}
|
||||
newPodInfo := &nodedeclaredfeatures.PodInfo{Spec: &tc.newPod.Spec, Status: &tc.newPod.Status}
|
||||
if want, got := tc.expected, feature.InferForUpdate(oldPodInfo, newPodInfo); want != got {
|
||||
t.Fatalf("want=%v,got=%v", want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,5 @@ import (
|
||||
// discovery and inference logic.
|
||||
var AllFeatures = []nodedeclaredfeatures.Feature{
|
||||
restartallcontainers.Feature,
|
||||
inplacepodresize.GuaranteedQoSPodCPUResizeFeature,
|
||||
inplacepodresize.PodLevelResourcesResizeFeature,
|
||||
}
|
||||
|
||||
@@ -84,9 +84,9 @@ func TestDiscoverNodeFeatures(t *testing.T) {
|
||||
maxVersion: featureMaxVersion,
|
||||
},
|
||||
&mockFeature{
|
||||
name: "FeatureBWithStaticConfig",
|
||||
name: "FeatureB",
|
||||
discover: func(cfg *NodeConfiguration) bool {
|
||||
return cfg.FeatureGates.Enabled("feature-b") && cfg.StaticConfig.CPUManagerPolicy == "static"
|
||||
return cfg.FeatureGates.Enabled("feature-b")
|
||||
},
|
||||
maxVersion: featureMaxVersion,
|
||||
},
|
||||
@@ -114,18 +114,16 @@ func TestDiscoverNodeFeatures(t *testing.T) {
|
||||
string("feature-a"): true,
|
||||
string("feature-b"): true,
|
||||
}),
|
||||
StaticConfig: StaticConfiguration{CPUManagerPolicy: "static"},
|
||||
},
|
||||
expected: []string{"FeatureA", "FeatureBWithStaticConfig"}, // Should be sorted
|
||||
expected: []string{"FeatureA", "FeatureB"}, // Should be sorted
|
||||
},
|
||||
{
|
||||
name: "no features enabled",
|
||||
config: &NodeConfiguration{
|
||||
FeatureGates: newMockFeatureGate(map[string]bool{
|
||||
string("feature-a"): false,
|
||||
string("feature-b"): true,
|
||||
string("feature-b"): false,
|
||||
}),
|
||||
StaticConfig: StaticConfiguration{CPUManagerPolicy: "none"},
|
||||
},
|
||||
expected: []string{},
|
||||
},
|
||||
|
||||
@@ -62,10 +62,9 @@ type FeatureGate interface {
|
||||
Enabled(key string) bool
|
||||
}
|
||||
|
||||
// StaticConfiguration provides a view of a node's static configuration.
|
||||
// StaticConfiguration provides a view of a node's static configuration required for feature discovery.
|
||||
type StaticConfiguration struct {
|
||||
// Kubelet's CPU Manager policy
|
||||
CPUManagerPolicy string
|
||||
// Add configuration fields here as required by registered features.
|
||||
}
|
||||
|
||||
// NodeConfiguration provides a generic view of a node's static configuration.
|
||||
|
||||
@@ -1503,8 +1503,9 @@ func TestRelaxedDNSSearchValidation(t *testing.T) {
|
||||
|
||||
func TestNodeDeclaredFeatureAdmission(t *testing.T) {
|
||||
featuregatetesting.SetFeatureGatesDuringTest(t, utilfeature.DefaultFeatureGate, featuregatetesting.FeatureOverrides{
|
||||
features.NodeDeclaredFeatures: true,
|
||||
features.InPlacePodVerticalScaling: true,
|
||||
features.NodeDeclaredFeatures: true,
|
||||
features.PodLevelResources: true,
|
||||
features.InPlacePodLevelResourcesVerticalScaling: true,
|
||||
})
|
||||
server := kubeapiservertesting.StartTestServerOrDie(t, nil, framework.DefaultTestServerFlags(), framework.SharedEtcd())
|
||||
defer server.TearDownFn()
|
||||
@@ -1519,30 +1520,20 @@ func TestNodeDeclaredFeatureAdmission(t *testing.T) {
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
NodeName: nodeName,
|
||||
Resources: &v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{v1.ResourceCPU: resource.MustParse("1"), v1.ResourceMemory: resource.MustParse("1Gi")},
|
||||
Limits: v1.ResourceList{v1.ResourceCPU: resource.MustParse("1"), v1.ResourceMemory: resource.MustParse("1Gi")},
|
||||
},
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Name: "test-container",
|
||||
Image: "fakeimage",
|
||||
Resources: v1.ResourceRequirements{
|
||||
Requests: v1.ResourceList{v1.ResourceCPU: resource.MustParse("1"), v1.ResourceMemory: resource.MustParse("1Gi")},
|
||||
Limits: v1.ResourceList{v1.ResourceCPU: resource.MustParse("1"), v1.ResourceMemory: resource.MustParse("1Gi")},
|
||||
},
|
||||
},
|
||||
},
|
||||
RestartPolicy: v1.RestartPolicyAlways,
|
||||
},
|
||||
Status: v1.PodStatus{
|
||||
Phase: v1.PodRunning,
|
||||
ContainerStatuses: []v1.ContainerStatus{
|
||||
{
|
||||
Name: "test-container",
|
||||
Ready: true,
|
||||
AllocatedResources: v1.ResourceList{
|
||||
v1.ResourceCPU: resource.MustParse("1"),
|
||||
v1.ResourceMemory: resource.MustParse("1Gi"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1558,19 +1549,19 @@ func TestNodeDeclaredFeatureAdmission(t *testing.T) {
|
||||
nodeDeclaredFeatures: []string{"SomeOtherFeature"},
|
||||
nodeVersion: "1.35.0",
|
||||
podUpdateFn: func(pod *v1.Pod) {
|
||||
pod.Spec.Containers[0].Resources.Requests[v1.ResourceCPU] = resource.MustParse("2")
|
||||
pod.Spec.Containers[0].Resources.Limits[v1.ResourceCPU] = resource.MustParse("2")
|
||||
pod.Spec.Resources.Requests[v1.ResourceCPU] = resource.MustParse("2")
|
||||
pod.Spec.Resources.Limits[v1.ResourceCPU] = resource.MustParse("2")
|
||||
},
|
||||
expectError: "pod update requires features GuaranteedQoSPodCPUResize which are not available on node",
|
||||
expectError: "pod update requires features InPlacePodLevelResourcesVerticalScaling which are not available on node",
|
||||
},
|
||||
|
||||
{
|
||||
name: "admission succeeds when required feature is declared on node",
|
||||
nodeDeclaredFeatures: []string{ipprfeature.GuaranteedQoSPodCPUResize},
|
||||
nodeDeclaredFeatures: []string{ipprfeature.PodLevelResourcesResizeFeature.Name()},
|
||||
nodeVersion: "1.35.0",
|
||||
podUpdateFn: func(pod *v1.Pod) {
|
||||
pod.Spec.Containers[0].Resources.Requests[v1.ResourceCPU] = resource.MustParse("2")
|
||||
pod.Spec.Containers[0].Resources.Limits[v1.ResourceCPU] = resource.MustParse("2")
|
||||
pod.Spec.Resources.Requests[v1.ResourceCPU] = resource.MustParse("2")
|
||||
pod.Spec.Resources.Limits[v1.ResourceCPU] = resource.MustParse("2")
|
||||
},
|
||||
expectError: "",
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user