GA of RuntimeClass feature gate and API

This commit is contained in:
Sergey Kanzhelev
2020-11-11 19:22:32 +00:00
parent 0469db9fe7
commit 06da0e5e74
88 changed files with 4377 additions and 305 deletions

View File

@@ -8,10 +8,10 @@ go_library(
deps = [
"//pkg/apis/core:go_default_library",
"//pkg/apis/node:go_default_library",
"//pkg/apis/node/v1beta1:go_default_library",
"//pkg/apis/node/v1:go_default_library",
"//pkg/features:go_default_library",
"//pkg/util/tolerations:go_default_library",
"//staging/src/k8s.io/api/node/v1beta1:go_default_library",
"//staging/src/k8s.io/api/node/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
@@ -19,8 +19,8 @@ go_library(
"//staging/src/k8s.io/apiserver/pkg/admission/initializer:go_default_library",
"//staging/src/k8s.io/client-go/informers:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/typed/node/v1beta1:go_default_library",
"//staging/src/k8s.io/client-go/listers/node/v1beta1:go_default_library",
"//staging/src/k8s.io/client-go/kubernetes/typed/node/v1:go_default_library",
"//staging/src/k8s.io/client-go/listers/node/v1:go_default_library",
"//staging/src/k8s.io/component-base/featuregate:go_default_library",
],
)
@@ -34,7 +34,7 @@ go_test(
"//pkg/controller:go_default_library",
"//pkg/features:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/node/v1beta1:go_default_library",
"//staging/src/k8s.io/api/node/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",

View File

@@ -17,7 +17,7 @@ limitations under the License.
// Package runtimeclass contains an admission controller for modifying and validating new Pods to
// take RuntimeClass into account. For RuntimeClass definitions which describe an overhead associated
// with running a pod, this admission controller will set the pod.Spec.Overhead field accordingly. This
// field should only be set through this controller, so vaidation will be carried out to ensure the pod's
// field should only be set through this controller, so validation will be carried out to ensure the pod's
// value matches what is defined in the coresponding RuntimeClass.
package runtimeclass
@@ -26,7 +26,7 @@ import (
"fmt"
"io"
v1beta1 "k8s.io/api/node/v1beta1"
nodev1 "k8s.io/api/node/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -34,12 +34,12 @@ import (
genericadmissioninitailizer "k8s.io/apiserver/pkg/admission/initializer"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
nodev1beta1client "k8s.io/client-go/kubernetes/typed/node/v1beta1"
nodev1beta1listers "k8s.io/client-go/listers/node/v1beta1"
nodev1client "k8s.io/client-go/kubernetes/typed/node/v1"
nodev1listers "k8s.io/client-go/listers/node/v1"
"k8s.io/component-base/featuregate"
api "k8s.io/kubernetes/pkg/apis/core"
node "k8s.io/kubernetes/pkg/apis/node"
nodev1beta1 "k8s.io/kubernetes/pkg/apis/node/v1beta1"
apinodev1 "k8s.io/kubernetes/pkg/apis/node/v1"
"k8s.io/kubernetes/pkg/features"
"k8s.io/kubernetes/pkg/util/tolerations"
)
@@ -60,12 +60,11 @@ func Register(plugins *admission.Plugins) {
// not specified, the pod is rejected.
type RuntimeClass struct {
*admission.Handler
runtimeClassLister nodev1beta1listers.RuntimeClassLister
runtimeClassClient nodev1beta1client.RuntimeClassInterface
runtimeClassLister nodev1listers.RuntimeClassLister
runtimeClassClient nodev1client.RuntimeClassInterface
inspectedFeatures bool
runtimeClassEnabled bool
podOverheadEnabled bool
inspectedFeatures bool
podOverheadEnabled bool
}
var _ admission.MutationInterface = &RuntimeClass{}
@@ -76,22 +75,18 @@ var _ genericadmissioninitailizer.WantsExternalKubeClientSet = &RuntimeClass{}
// SetExternalKubeClientSet sets the client for the plugin
func (r *RuntimeClass) SetExternalKubeClientSet(client kubernetes.Interface) {
r.runtimeClassClient = client.NodeV1beta1().RuntimeClasses()
r.runtimeClassClient = client.NodeV1().RuntimeClasses()
}
// InspectFeatureGates allows setting bools without taking a dep on a global variable
func (r *RuntimeClass) InspectFeatureGates(featureGates featuregate.FeatureGate) {
r.runtimeClassEnabled = featureGates.Enabled(features.RuntimeClass)
r.podOverheadEnabled = featureGates.Enabled(features.PodOverhead)
r.inspectedFeatures = true
}
// SetExternalKubeInformerFactory implements the WantsExternalKubeInformerFactory interface.
func (r *RuntimeClass) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
if !r.runtimeClassEnabled {
return
}
runtimeClassInformer := f.Node().V1beta1().RuntimeClasses()
runtimeClassInformer := f.Node().V1().RuntimeClasses()
r.SetReadyFunc(runtimeClassInformer.Informer().HasSynced)
r.runtimeClassLister = runtimeClassInformer.Lister()
}
@@ -101,9 +96,6 @@ func (r *RuntimeClass) ValidateInitialization() error {
if !r.inspectedFeatures {
return fmt.Errorf("InspectFeatureGates was not called")
}
if !r.runtimeClassEnabled {
return nil
}
if r.runtimeClassLister == nil {
return fmt.Errorf("missing RuntimeClass lister")
}
@@ -115,10 +107,6 @@ func (r *RuntimeClass) ValidateInitialization() error {
// Admit makes an admission decision based on the request attributes
func (r *RuntimeClass) Admit(ctx context.Context, attributes admission.Attributes, o admission.ObjectInterfaces) error {
if !r.runtimeClassEnabled {
return nil
}
// Ignore all calls to subresources or resources other than pods.
if shouldIgnore(attributes) {
return nil
@@ -143,10 +131,6 @@ func (r *RuntimeClass) Admit(ctx context.Context, attributes admission.Attribute
// Validate makes sure that pod adhere's to RuntimeClass's definition
func (r *RuntimeClass) Validate(ctx context.Context, attributes admission.Attributes, o admission.ObjectInterfaces) error {
if !r.runtimeClassEnabled {
return nil
}
// Ignore all calls to subresources or resources other than pods.
if shouldIgnore(attributes) {
return nil
@@ -173,7 +157,7 @@ func NewRuntimeClass() *RuntimeClass {
}
// prepareObjects returns pod and runtimeClass types from the given admission attributes
func (r *RuntimeClass) prepareObjects(ctx context.Context, attributes admission.Attributes) (pod *api.Pod, runtimeClass *v1beta1.RuntimeClass, err error) {
func (r *RuntimeClass) prepareObjects(ctx context.Context, attributes admission.Attributes) (pod *api.Pod, runtimeClass *nodev1.RuntimeClass, err error) {
pod, ok := attributes.GetObject().(*api.Pod)
if !ok {
return nil, nil, apierrors.NewBadRequest("Resource was marked with kind Pod but was unable to be converted")
@@ -197,14 +181,14 @@ func (r *RuntimeClass) prepareObjects(ctx context.Context, attributes admission.
return pod, runtimeClass, err
}
func setOverhead(a admission.Attributes, pod *api.Pod, runtimeClass *v1beta1.RuntimeClass) (err error) {
func setOverhead(a admission.Attributes, pod *api.Pod, runtimeClass *nodev1.RuntimeClass) (err error) {
if runtimeClass == nil || runtimeClass.Overhead == nil {
return nil
}
// convert to internal type and assign to pod's Overhead
nodeOverhead := &node.Overhead{}
if err = nodev1beta1.Convert_v1beta1_Overhead_To_node_Overhead(runtimeClass.Overhead, nodeOverhead, nil); err != nil {
if err = apinodev1.Convert_v1_Overhead_To_node_Overhead(runtimeClass.Overhead, nodeOverhead, nil); err != nil {
return err
}
@@ -218,14 +202,14 @@ func setOverhead(a admission.Attributes, pod *api.Pod, runtimeClass *v1beta1.Run
return nil
}
func setScheduling(a admission.Attributes, pod *api.Pod, runtimeClass *v1beta1.RuntimeClass) (err error) {
func setScheduling(a admission.Attributes, pod *api.Pod, runtimeClass *nodev1.RuntimeClass) (err error) {
if runtimeClass == nil || runtimeClass.Scheduling == nil {
return nil
}
// convert to internal type and assign to pod's Scheduling
nodeScheduling := &node.Scheduling{}
if err = nodev1beta1.Convert_v1beta1_Scheduling_To_node_Scheduling(runtimeClass.Scheduling, nodeScheduling, nil); err != nil {
if err = apinodev1.Convert_v1_Scheduling_To_node_Scheduling(runtimeClass.Scheduling, nodeScheduling, nil); err != nil {
return err
}
@@ -250,11 +234,11 @@ func setScheduling(a admission.Attributes, pod *api.Pod, runtimeClass *v1beta1.R
return nil
}
func validateOverhead(a admission.Attributes, pod *api.Pod, runtimeClass *v1beta1.RuntimeClass) (err error) {
func validateOverhead(a admission.Attributes, pod *api.Pod, runtimeClass *nodev1.RuntimeClass) (err error) {
if runtimeClass != nil && runtimeClass.Overhead != nil {
// If the Overhead set doesn't match what is provided in the RuntimeClass definition, reject the pod
nodeOverhead := &node.Overhead{}
if err := nodev1beta1.Convert_v1beta1_Overhead_To_node_Overhead(runtimeClass.Overhead, nodeOverhead, nil); err != nil {
if err := apinodev1.Convert_v1_Overhead_To_node_Overhead(runtimeClass.Overhead, nodeOverhead, nil); err != nil {
return err
}
if !apiequality.Semantic.DeepEqual(nodeOverhead.PodFixed, pod.Spec.Overhead) {

View File

@@ -23,7 +23,7 @@ import (
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/api/core/v1"
"k8s.io/api/node/v1beta1"
nodev1 "k8s.io/api/node/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@@ -86,17 +86,17 @@ func getGuaranteedRequirements() core.ResourceRequirements {
func TestSetOverhead(t *testing.T) {
tests := []struct {
name string
runtimeClass *v1beta1.RuntimeClass
runtimeClass *nodev1.RuntimeClass
pod *core.Pod
expectError bool
expectedPod *core.Pod
}{
{
name: "overhead, no container requirements",
runtimeClass: &v1beta1.RuntimeClass{
runtimeClass: &nodev1.RuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Handler: "bar",
Overhead: &v1beta1.Overhead{
Overhead: &nodev1.Overhead{
PodFixed: corev1.ResourceList{
corev1.ResourceName(corev1.ResourceCPU): resource.MustParse("100m"),
corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("1"),
@@ -109,10 +109,10 @@ func TestSetOverhead(t *testing.T) {
},
{
name: "overhead, guaranteed pod",
runtimeClass: &v1beta1.RuntimeClass{
runtimeClass: &nodev1.RuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Handler: "bar",
Overhead: &v1beta1.Overhead{
Overhead: &nodev1.Overhead{
PodFixed: corev1.ResourceList{
corev1.ResourceName(corev1.ResourceCPU): resource.MustParse("100m"),
corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("1"),
@@ -125,10 +125,10 @@ func TestSetOverhead(t *testing.T) {
},
{
name: "overhead, pod with differing overhead already set",
runtimeClass: &v1beta1.RuntimeClass{
runtimeClass: &nodev1.RuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Handler: "bar",
Overhead: &v1beta1.Overhead{
Overhead: &nodev1.Overhead{
PodFixed: corev1.ResourceList{
corev1.ResourceName(corev1.ResourceCPU): resource.MustParse("10"),
corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("10G"),
@@ -141,10 +141,10 @@ func TestSetOverhead(t *testing.T) {
},
{
name: "overhead, pod with same overhead already set",
runtimeClass: &v1beta1.RuntimeClass{
runtimeClass: &nodev1.RuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Handler: "bar",
Overhead: &v1beta1.Overhead{
Overhead: &nodev1.Overhead{
PodFixed: corev1.ResourceList{
corev1.ResourceName(corev1.ResourceCPU): resource.MustParse("100m"),
corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("1"),
@@ -175,14 +175,14 @@ func TestSetOverhead(t *testing.T) {
func TestSetScheduling(t *testing.T) {
tests := []struct {
name string
runtimeClass *v1beta1.RuntimeClass
runtimeClass *nodev1.RuntimeClass
pod *core.Pod
expectError bool
expectedPod *core.Pod
}{
{
name: "scheduling, nil scheduling",
runtimeClass: &v1beta1.RuntimeClass{
runtimeClass: &nodev1.RuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Handler: "bar",
Scheduling: nil,
@@ -193,10 +193,10 @@ func TestSetScheduling(t *testing.T) {
},
{
name: "scheduling, conflict node selector",
runtimeClass: &v1beta1.RuntimeClass{
runtimeClass: &nodev1.RuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Handler: "bar",
Scheduling: &v1beta1.Scheduling{
Scheduling: &nodev1.Scheduling{
NodeSelector: map[string]string{
"foo": "conflict",
},
@@ -207,10 +207,10 @@ func TestSetScheduling(t *testing.T) {
},
{
name: "scheduling, nil node selector",
runtimeClass: &v1beta1.RuntimeClass{
runtimeClass: &nodev1.RuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Handler: "bar",
Scheduling: &v1beta1.Scheduling{
Scheduling: &nodev1.Scheduling{
NodeSelector: map[string]string{
"foo": "bar",
},
@@ -222,10 +222,10 @@ func TestSetScheduling(t *testing.T) {
},
{
name: "scheduling, node selector with the same key value",
runtimeClass: &v1beta1.RuntimeClass{
runtimeClass: &nodev1.RuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Handler: "bar",
Scheduling: &v1beta1.Scheduling{
Scheduling: &nodev1.Scheduling{
NodeSelector: map[string]string{
"foo": "bar",
},
@@ -237,10 +237,10 @@ func TestSetScheduling(t *testing.T) {
},
{
name: "scheduling, node selector with different key value",
runtimeClass: &v1beta1.RuntimeClass{
runtimeClass: &nodev1.RuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Handler: "bar",
Scheduling: &v1beta1.Scheduling{
Scheduling: &nodev1.Scheduling{
NodeSelector: map[string]string{
"foo": "bar",
"fizz": "buzz",
@@ -253,10 +253,10 @@ func TestSetScheduling(t *testing.T) {
},
{
name: "scheduling, multiple tolerations",
runtimeClass: &v1beta1.RuntimeClass{
runtimeClass: &nodev1.RuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Handler: "bar",
Scheduling: &v1beta1.Scheduling{
Scheduling: &nodev1.Scheduling{
Tolerations: []v1.Toleration{
{
Key: "foo",
@@ -322,18 +322,17 @@ func NewObjectInterfacesForTest() admission.ObjectInterfaces {
return admission.NewObjectInterfacesFromScheme(scheme)
}
func newRuntimeClassForTest(runtimeClassEnabled bool,
func newRuntimeClassForTest(
featureInspection bool,
addLister bool,
listerObject *v1beta1.RuntimeClass,
listerObject *nodev1.RuntimeClass,
addClient bool,
clientObject *v1beta1.RuntimeClass) *RuntimeClass {
clientObject *nodev1.RuntimeClass) *RuntimeClass {
runtimeClass := NewRuntimeClass()
if featureInspection {
relevantFeatures := map[featuregate.Feature]featuregate.FeatureSpec{
features.RuntimeClass: {Default: runtimeClassEnabled},
features.PodOverhead: {Default: false},
features.PodOverhead: {Default: false},
}
fg := featuregate.NewFeatureGate()
fg.Add(relevantFeatures)
@@ -344,7 +343,7 @@ func newRuntimeClassForTest(runtimeClassEnabled bool,
informerFactory := informers.NewSharedInformerFactory(nil, controller.NoResyncPeriodFunc())
runtimeClass.SetExternalKubeInformerFactory(informerFactory)
if listerObject != nil {
informerFactory.Node().V1beta1().RuntimeClasses().Informer().GetStore().Add(listerObject)
informerFactory.Node().V1().RuntimeClasses().Informer().GetStore().Add(listerObject)
}
}
@@ -367,30 +366,25 @@ func TestValidateInitialization(t *testing.T) {
expectError bool
runtimeClass *RuntimeClass
}{
{
name: "runtimeClass disabled, success",
expectError: false,
runtimeClass: newRuntimeClassForTest(false, true, true, nil, true, nil),
},
{
name: "runtimeClass enabled, success",
expectError: false,
runtimeClass: newRuntimeClassForTest(true, true, true, nil, true, nil),
runtimeClass: newRuntimeClassForTest(true, true, nil, true, nil),
},
{
name: "runtimeClass enabled, no feature inspection",
expectError: true,
runtimeClass: newRuntimeClassForTest(true, false, true, nil, true, nil),
runtimeClass: newRuntimeClassForTest(false, true, nil, true, nil),
},
{
name: "runtimeClass enabled, no lister",
expectError: true,
runtimeClass: newRuntimeClassForTest(true, true, false, nil, true, nil),
runtimeClass: newRuntimeClassForTest(true, false, nil, true, nil),
},
{
name: "runtimeClass enabled, no client",
expectError: true,
runtimeClass: newRuntimeClassForTest(true, true, true, nil, false, nil),
runtimeClass: newRuntimeClassForTest(true, true, nil, false, nil),
},
}
@@ -409,7 +403,7 @@ func TestValidateInitialization(t *testing.T) {
func TestAdmit(t *testing.T) {
runtimeClassName := "runtimeClassName"
rc := &v1beta1.RuntimeClass{
rc := &nodev1.RuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: runtimeClassName},
}
@@ -440,17 +434,17 @@ func TestAdmit(t *testing.T) {
{
name: "runtimeClass found by lister",
expectError: false,
runtimeClass: newRuntimeClassForTest(true, true, true, rc, true, nil),
runtimeClass: newRuntimeClassForTest(true, true, rc, true, nil),
},
{
name: "runtimeClass found by client",
expectError: false,
runtimeClass: newRuntimeClassForTest(true, true, true, nil, true, rc),
runtimeClass: newRuntimeClassForTest(true, true, nil, true, rc),
},
{
name: "runtimeClass not found by lister nor client",
expectError: true,
runtimeClass: newRuntimeClassForTest(true, true, true, nil, true, nil),
runtimeClass: newRuntimeClassForTest(true, true, nil, true, nil),
},
}
@@ -469,13 +463,13 @@ func TestAdmit(t *testing.T) {
func TestValidate(t *testing.T) {
tests := []struct {
name string
runtimeClass *v1beta1.RuntimeClass
runtimeClass *nodev1.RuntimeClass
pod *core.Pod
expectError bool
}{
{
name: "No Overhead in RunntimeClass, Overhead set in pod",
runtimeClass: &v1beta1.RuntimeClass{
runtimeClass: &nodev1.RuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Handler: "bar",
},
@@ -484,10 +478,10 @@ func TestValidate(t *testing.T) {
},
{
name: "Non-matching Overheads",
runtimeClass: &v1beta1.RuntimeClass{
runtimeClass: &nodev1.RuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Handler: "bar",
Overhead: &v1beta1.Overhead{
Overhead: &nodev1.Overhead{
PodFixed: corev1.ResourceList{
corev1.ResourceName(corev1.ResourceCPU): resource.MustParse("10"),
corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("10G"),
@@ -499,10 +493,10 @@ func TestValidate(t *testing.T) {
},
{
name: "Matching Overheads",
runtimeClass: &v1beta1.RuntimeClass{
runtimeClass: &nodev1.RuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Handler: "bar",
Overhead: &v1beta1.Overhead{
Overhead: &nodev1.Overhead{
PodFixed: corev1.ResourceList{
corev1.ResourceName(corev1.ResourceCPU): resource.MustParse("100m"),
corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("1"),
@@ -514,7 +508,6 @@ func TestValidate(t *testing.T) {
},
}
rt := NewRuntimeClass()
rt.runtimeClassEnabled = true
rt.podOverheadEnabled = true
o := NewObjectInterfacesForTest()
for _, tc := range tests {
@@ -535,16 +528,16 @@ func TestValidate(t *testing.T) {
func TestValidateOverhead(t *testing.T) {
tests := []struct {
name string
runtimeClass *v1beta1.RuntimeClass
runtimeClass *nodev1.RuntimeClass
pod *core.Pod
expectError bool
}{
{
name: "Overhead part of RuntimeClass, no Overhead defined in pod",
runtimeClass: &v1beta1.RuntimeClass{
runtimeClass: &nodev1.RuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Handler: "bar",
Overhead: &v1beta1.Overhead{
Overhead: &nodev1.Overhead{
PodFixed: corev1.ResourceList{
corev1.ResourceName(corev1.ResourceCPU): resource.MustParse("100m"),
corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("1"),
@@ -556,7 +549,7 @@ func TestValidateOverhead(t *testing.T) {
},
{
name: "No Overhead in RunntimeClass, Overhead set in pod",
runtimeClass: &v1beta1.RuntimeClass{
runtimeClass: &nodev1.RuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Handler: "bar",
},
@@ -571,10 +564,10 @@ func TestValidateOverhead(t *testing.T) {
},
{
name: "Non-matching Overheads",
runtimeClass: &v1beta1.RuntimeClass{
runtimeClass: &nodev1.RuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Handler: "bar",
Overhead: &v1beta1.Overhead{
Overhead: &nodev1.Overhead{
PodFixed: corev1.ResourceList{
corev1.ResourceName(corev1.ResourceCPU): resource.MustParse("10"),
corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("10G"),
@@ -586,10 +579,10 @@ func TestValidateOverhead(t *testing.T) {
},
{
name: "Matching Overheads",
runtimeClass: &v1beta1.RuntimeClass{
runtimeClass: &nodev1.RuntimeClass{
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
Handler: "bar",
Overhead: &v1beta1.Overhead{
Overhead: &nodev1.Overhead{
PodFixed: corev1.ResourceList{
corev1.ResourceName(corev1.ResourceCPU): resource.MustParse("100m"),
corev1.ResourceName(corev1.ResourceMemory): resource.MustParse("1"),

View File

@@ -175,9 +175,7 @@ func NodeRules() []rbacv1.PolicyRule {
}
// RuntimeClass
if utilfeature.DefaultFeatureGate.Enabled(features.RuntimeClass) {
nodePolicyRules = append(nodePolicyRules, rbacv1helpers.NewRule("get", "list", "watch").Groups("node.k8s.io").Resources("runtimeclasses").RuleOrDie())
}
nodePolicyRules = append(nodePolicyRules, rbacv1helpers.NewRule("get", "list", "watch").Groups("node.k8s.io").Resources("runtimeclasses").RuleOrDie())
return nodePolicyRules
}