Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: for testing #2145

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ require (
github.com/opencontainers/runc v1.1.13
github.com/opencontainers/selinux v1.11.0
github.com/openshift-eng/openshift-tests-extension v0.0.0-20241028125658-76ee2532d0bf
github.com/openshift/api v0.0.0-20241001152557-e415140e5d5f
github.com/openshift/api v0.0.0-20241101202457-04eb3fd119d2
github.com/openshift/apiserver-library-go v0.0.0-20241001175710-6064b62894a6
github.com/openshift/client-go v0.0.0-20241001162912-da6d55e4611f
github.com/openshift/library-go v0.0.0-20241107160307-0064ad7bd060
github.com/openshift/library-go v0.0.0-20241122090744-c450187f381d
github.com/pkg/errors v0.9.1
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2
github.com/prometheus/client_golang v1.19.1
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -500,17 +500,17 @@ github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaL
github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
github.com/openshift-eng/openshift-tests-extension v0.0.0-20241028125658-76ee2532d0bf h1:WY0VzsbhiQQNcS8Y9AXuiqqY8YHljePp1QhrIrue4+c=
github.com/openshift-eng/openshift-tests-extension v0.0.0-20241028125658-76ee2532d0bf/go.mod h1:1OhaNsaU9vuy/dlYZLEve7bgE2Ed+yTV5VSbYvGXt4s=
github.com/openshift/api v0.0.0-20241001152557-e415140e5d5f h1:ya1OmyZm3LIIxI3U9VE9Nyx3ehCHgBwxyFUPflYPWls=
github.com/openshift/api v0.0.0-20241001152557-e415140e5d5f/go.mod h1:Shkl4HanLwDiiBzakv+con/aMGnVE2MAGvoKp5oyYUo=
github.com/openshift/api v0.0.0-20241101202457-04eb3fd119d2 h1:CguNy+2KzhJ3a3i7e4Bgm/ByfQpSSSPYmF9NLZskoUs=
github.com/openshift/api v0.0.0-20241101202457-04eb3fd119d2/go.mod h1:Shkl4HanLwDiiBzakv+con/aMGnVE2MAGvoKp5oyYUo=
github.com/openshift/apiserver-library-go v0.0.0-20241001175710-6064b62894a6 h1:Wban+ggY6sbg611SQSOeavUeug2cRJGz0rEeXxTxIH0=
github.com/openshift/apiserver-library-go v0.0.0-20241001175710-6064b62894a6/go.mod h1:9Anrq7+DZmmw1Brchx4zmh26hAZbe6Dv7bGXRclnhYI=
github.com/openshift/build-machinery-go v0.0.0-20240613134303-8359781da660/go.mod h1:8jcm8UPtg2mCAsxfqKil1xrmRMI3a+XU2TZ9fF8A7TE=
github.com/openshift/client-go v0.0.0-20241001162912-da6d55e4611f h1:FRc0bVNWprihWS0GqQWzb3dY4dkCwpOP3mDw5NwSoR4=
github.com/openshift/client-go v0.0.0-20241001162912-da6d55e4611f/go.mod h1:KiZi2mJRH1TOJ3FtBDYS6YvUL30s/iIXaGSUrSa36mo=
github.com/openshift/google-cadvisor v0.49.0-openshift-4.17-2 h1:ls1C5cvJbA5CbOwbA4Nx/W+tRvXgKDc9XT81bg3sxCA=
github.com/openshift/google-cadvisor v0.49.0-openshift-4.17-2/go.mod h1:s6Fqwb2KiWG6leCegVhw4KW40tf9f7m+SF1aXiE8Wsk=
github.com/openshift/library-go v0.0.0-20241107160307-0064ad7bd060 h1:jiDC7d8d+jmjv2WfiMY0+Uf55q11MGyYkGGqXnfqWTU=
github.com/openshift/library-go v0.0.0-20241107160307-0064ad7bd060/go.mod h1:9B1MYPoLtP9tqjWxcbUNVpwxy68zOH/3EIP6c31dAM0=
github.com/openshift/library-go v0.0.0-20241122090744-c450187f381d h1:cxEFBp0kZlqTrwnOTg5aCWaGt60A4xiovQKpSdWg25M=
github.com/openshift/library-go v0.0.0-20241122090744-c450187f381d/go.mod h1:l/3SegTa9x+ry2J213bh7+DBofXOOvdrqU4JC9ktJa0=
github.com/openshift/onsi-ginkgo/v2 v2.6.1-0.20241008152707-25bf9f14db44 h1:dKUAGq29JBk2oRn955gnnz3sG/UhlkUKh1ISleLiews=
github.com/openshift/onsi-ginkgo/v2 v2.6.1-0.20241008152707-25bf9f14db44/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
Expand Down
52 changes: 52 additions & 0 deletions go.work.sum

Large diffs are not rendered by default.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,25 @@ package node

import (
"context"
"errors"
"fmt"
"io"

configv1 "github.com/openshift/api/config/v1"
nodelib "github.com/openshift/library-go/pkg/apiserver/node"

openshiftfeatures "github.com/openshift/api/features"
"k8s.io/apimachinery/pkg/api/validation"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/apiserver/pkg/admission"

configv1 "github.com/openshift/api/config/v1"
"k8s.io/apiserver/pkg/admission/initializer"
"k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/informers"
corev1listers "k8s.io/client-go/listers/core/v1"
"k8s.io/component-base/featuregate"
"k8s.io/kubernetes/openshift-kube-apiserver/admission/customresourcevalidation"
)

Expand All @@ -25,18 +34,28 @@ var rejectionScenarios = []struct {
{fromProfile: configv1.LowUpdateSlowReaction, toProfile: configv1.DefaultUpdateDefaultReaction},
}

const PluginName = "config.openshift.io/RestrictExtremeWorkerLatencyProfile"
const PluginName = "config.openshift.io/ValidateConfigNodeV1"

// Register registers a plugin
func Register(plugins *admission.Plugins) {
plugins.Register(PluginName, func(config io.Reader) (admission.Interface, error) {
return customresourcevalidation.NewValidator(
ret := &validateCustomResourceWithNodeLister{}
delegate, err := customresourcevalidation.NewValidator(
map[schema.GroupResource]bool{
configv1.Resource("nodes"): true,
},
map[schema.GroupVersionKind]customresourcevalidation.ObjectValidator{
configv1.GroupVersion.WithKind("Node"): configNodeV1{},
configv1.GroupVersion.WithKind("Node"): &configNodeV1{
nodeLister: ret.getNodeLister,
waitForReady: ret.getWaitForReady,
minimumKubeletVersionEnabled: feature.DefaultMutableFeatureGate.Enabled(featuregate.Feature(openshiftfeatures.FeatureGateMinimumKubeletVersion)),
},
})
if err != nil {
return nil, err
}
ret.ValidationInterface = delegate
return ret, nil
})
}

Expand All @@ -57,7 +76,13 @@ func toConfigNodeV1(uncastObj runtime.Object) (*configv1.Node, field.ErrorList)
return obj, nil
}

type configNodeV1 struct{}
type configNodeV1 struct {
admission.ValidationInterface

nodeLister func() corev1listers.NodeLister
waitForReady func() func() bool
minimumKubeletVersionEnabled bool
}

func validateConfigNodeForExtremeLatencyProfile(obj, oldObj *configv1.Node) *field.Error {
fromProfile := oldObj.Spec.WorkerLatencyProfile
Expand All @@ -78,18 +103,21 @@ func validateConfigNodeForExtremeLatencyProfile(obj, oldObj *configv1.Node) *fie
return nil
}

func (configNodeV1) ValidateCreate(_ context.Context, uncastObj runtime.Object) field.ErrorList {
func (c *configNodeV1) ValidateCreate(_ context.Context, uncastObj runtime.Object) field.ErrorList {
obj, allErrs := toConfigNodeV1(uncastObj)
if len(allErrs) > 0 {
return allErrs
}

allErrs = append(allErrs, validation.ValidateObjectMeta(&obj.ObjectMeta, false, customresourcevalidation.RequireNameCluster, field.NewPath("metadata"))...)
if err := c.validateMinimumKubeletVersion(obj); err != nil {
allErrs = append(allErrs, err)
}

return allErrs
}

func (configNodeV1) ValidateUpdate(_ context.Context, uncastObj runtime.Object, uncastOldObj runtime.Object) field.ErrorList {
func (c *configNodeV1) ValidateUpdate(_ context.Context, uncastObj runtime.Object, uncastOldObj runtime.Object) field.ErrorList {
obj, allErrs := toConfigNodeV1(uncastObj)
if len(allErrs) > 0 {
return allErrs
Expand All @@ -103,11 +131,36 @@ func (configNodeV1) ValidateUpdate(_ context.Context, uncastObj runtime.Object,
if err := validateConfigNodeForExtremeLatencyProfile(obj, oldObj); err != nil {
allErrs = append(allErrs, err)
}
if err := c.validateMinimumKubeletVersion(obj); err != nil {
allErrs = append(allErrs, err)
}

return allErrs
}
func (c *configNodeV1) validateMinimumKubeletVersion(obj *configv1.Node) *field.Error {
if !c.minimumKubeletVersionEnabled {
return nil
}
fieldPath := field.NewPath("spec", "minimumKubeletVersion")
if !c.waitForReady()() {
return field.InternalError(fieldPath, fmt.Errorf("caches not synchronized, cannot validate minimumKubeletVersion"))
}

func (configNodeV1) ValidateStatusUpdate(_ context.Context, uncastObj runtime.Object, uncastOldObj runtime.Object) field.ErrorList {
nodes, err := c.nodeLister().List(labels.Everything())
if err != nil {
return field.Forbidden(fieldPath, fmt.Sprintf("Getting nodes to compare minimum version %v", err.Error()))
}

if err := nodelib.ValidateMinimumKubeletVersion(nodes, obj.Spec.MinimumKubeletVersion); err != nil {
if errors.Is(err, nodelib.ErrKubeletOutdated) {
return field.Forbidden(fieldPath, err.Error())
}
return field.Invalid(fieldPath, obj.Spec.MinimumKubeletVersion, err.Error())
}
return nil
}

func (*configNodeV1) ValidateStatusUpdate(_ context.Context, uncastObj runtime.Object, uncastOldObj runtime.Object) field.ErrorList {
obj, errs := toConfigNodeV1(uncastObj)
if len(errs) > 0 {
return errs
Expand All @@ -122,3 +175,34 @@ func (configNodeV1) ValidateStatusUpdate(_ context.Context, uncastObj runtime.Ob

return errs
}

type validateCustomResourceWithNodeLister struct {
nodeLister corev1listers.NodeLister

handler admission.Handler
admission.ValidationInterface
}

var _ = initializer.WantsExternalKubeInformerFactory(&validateCustomResourceWithNodeLister{})

func (c *validateCustomResourceWithNodeLister) SetExternalKubeInformerFactory(kubeInformers informers.SharedInformerFactory) {
nodeInformer := kubeInformers.Core().V1().Nodes()
c.nodeLister = nodeInformer.Lister()
c.handler.SetReadyFunc(nodeInformer.Informer().HasSynced)
}

func (c *validateCustomResourceWithNodeLister) ValidateInitialization() error {
if c.nodeLister == nil {
return fmt.Errorf("%s needs a nodes", PluginName)
}

return nil
}

func (c *validateCustomResourceWithNodeLister) getNodeLister() corev1listers.NodeLister {
return c.nodeLister
}

func (c *validateCustomResourceWithNodeLister) getWaitForReady() func() bool {
return c.handler.WaitForReady
}
Loading