Plumb effective version into admission initializer

Kubernetes-commit: 55419eca7a203e6f251fa632686bd4f534bf12e8
This commit is contained in:
Jordan Liggitt 2025-07-28 16:48:28 -04:00 committed by Kubernetes Publisher
parent bf8cdb9718
commit c8c846aeb1
7 changed files with 28 additions and 7 deletions

View File

@ -23,6 +23,7 @@ import (
"k8s.io/client-go/dynamic"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/component-base/compatibility"
"k8s.io/component-base/featuregate"
)
@ -32,6 +33,7 @@ type pluginInitializer struct {
externalInformers informers.SharedInformerFactory
authorizer authorizer.Authorizer
featureGates featuregate.FeatureGate
effectiveVersion compatibility.EffectiveVersion
stopCh <-chan struct{}
restMapper meta.RESTMapper
}
@ -45,6 +47,7 @@ func New(
extInformers informers.SharedInformerFactory,
authz authorizer.Authorizer,
featureGates featuregate.FeatureGate,
effectiveVersion compatibility.EffectiveVersion,
stopCh <-chan struct{},
restMapper meta.RESTMapper,
) pluginInitializer {
@ -54,6 +57,7 @@ func New(
externalInformers: extInformers,
authorizer: authz,
featureGates: featureGates,
effectiveVersion: effectiveVersion,
stopCh: stopCh,
restMapper: restMapper,
}
@ -68,6 +72,9 @@ func (i pluginInitializer) Initialize(plugin admission.Interface) {
}
// Second tell the plugin about enabled features, so it can decide whether to start informers or not
if wants, ok := plugin.(WantsEffectiveVersion); ok {
wants.InspectEffectiveVersion(i.effectiveVersion)
}
if wants, ok := plugin.(WantsFeatures); ok {
wants.InspectFeatureGates(i.featureGates)
}

View File

@ -34,7 +34,7 @@ import (
// TestWantsAuthorizer ensures that the authorizer is injected
// when the WantsAuthorizer interface is implemented by a plugin.
func TestWantsAuthorizer(t *testing.T) {
target := initializer.New(nil, nil, nil, &TestAuthorizer{}, nil, nil, nil)
target := initializer.New(nil, nil, nil, &TestAuthorizer{}, nil, nil, nil, nil)
wantAuthorizerAdmission := &WantAuthorizerAdmission{}
target.Initialize(wantAuthorizerAdmission)
if wantAuthorizerAdmission.auth == nil {
@ -46,7 +46,7 @@ func TestWantsAuthorizer(t *testing.T) {
// when the WantsExternalKubeClientSet interface is implemented by a plugin.
func TestWantsExternalKubeClientSet(t *testing.T) {
cs := &fake.Clientset{}
target := initializer.New(cs, nil, nil, &TestAuthorizer{}, nil, nil, nil)
target := initializer.New(cs, nil, nil, &TestAuthorizer{}, nil, nil, nil, nil)
wantExternalKubeClientSet := &WantExternalKubeClientSet{}
target.Initialize(wantExternalKubeClientSet)
if wantExternalKubeClientSet.cs != cs {
@ -59,7 +59,7 @@ func TestWantsExternalKubeClientSet(t *testing.T) {
func TestWantsExternalKubeInformerFactory(t *testing.T) {
cs := &fake.Clientset{}
sf := informers.NewSharedInformerFactory(cs, time.Duration(1)*time.Second)
target := initializer.New(cs, nil, sf, &TestAuthorizer{}, nil, nil, nil)
target := initializer.New(cs, nil, sf, &TestAuthorizer{}, nil, nil, nil, nil)
wantExternalKubeInformerFactory := &WantExternalKubeInformerFactory{}
target.Initialize(wantExternalKubeInformerFactory)
if wantExternalKubeInformerFactory.sf != sf {
@ -71,7 +71,7 @@ func TestWantsExternalKubeInformerFactory(t *testing.T) {
// when the WantsShutdownSignal interface is implemented by a plugin.
func TestWantsShutdownNotification(t *testing.T) {
stopCh := make(chan struct{})
target := initializer.New(nil, nil, nil, &TestAuthorizer{}, nil, stopCh, nil)
target := initializer.New(nil, nil, nil, &TestAuthorizer{}, nil, nil, stopCh, nil)
wantDrainedNotification := &WantDrainedNotification{}
target.Initialize(wantDrainedNotification)
if wantDrainedNotification.stopCh == nil {
@ -153,7 +153,7 @@ func (t *TestAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes)
}
func TestRESTMapperAdmissionPlugin(t *testing.T) {
initializer := initializer.New(nil, nil, nil, &TestAuthorizer{}, nil, nil, &doNothingRESTMapper{})
initializer := initializer.New(nil, nil, nil, &TestAuthorizer{}, nil, nil, nil, &doNothingRESTMapper{})
wantsRESTMapperAdmission := &WantsRESTMapperAdmissionPlugin{}
initializer.Initialize(wantsRESTMapperAdmission)

View File

@ -26,6 +26,7 @@ import (
"k8s.io/client-go/dynamic"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/component-base/compatibility"
"k8s.io/component-base/featuregate"
)
@ -73,6 +74,12 @@ type WantsFeatures interface {
admission.InitializationValidator
}
// WantsEffectiveVersion defines a function which passes the effective version for inspection by an admission plugin.
type WantsEffectiveVersion interface {
InspectEffectiveVersion(compatibility.EffectiveVersion)
admission.InitializationValidator
}
type WantsDynamicClient interface {
SetDynamicClient(dynamic.Interface)
admission.InitializationValidator

View File

@ -24,6 +24,7 @@ import (
"time"
"github.com/google/go-cmp/cmp"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -53,7 +54,7 @@ func newHandlerForTestWithClock(c clientset.Interface, cacheClock clock.Clock) (
if err != nil {
return nil, f, err
}
pluginInitializer := kubeadmission.New(c, nil, f, nil, nil, nil, nil)
pluginInitializer := kubeadmission.New(c, nil, f, nil, nil, nil, nil, nil)
pluginInitializer.Initialize(handler)
err = admission.ValidateInitialization(handler)
return handler, f, err

View File

@ -45,6 +45,7 @@ import (
"k8s.io/apiserver/pkg/admission"
"k8s.io/apiserver/pkg/admission/initializer"
"k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/util/compatibility"
)
// Logger allows t.Testing and b.Testing to be passed to PolicyTestContext
@ -203,6 +204,7 @@ func NewPolicyTestContext[P, B runtime.Object, E Evaluator](
plugin.SetEnabled(true)
featureGate := featuregate.NewFeatureGate()
effectiveVersion := compatibility.DefaultBuildEffectiveVersion()
testContext, testCancel := context.WithCancel(context.Background())
genericInitializer := initializer.New(
nativeClient,
@ -210,6 +212,7 @@ func NewPolicyTestContext[P, B runtime.Object, E Evaluator](
fakeInformerFactory,
fakeAuthorizer{},
featureGate,
effectiveVersion,
testContext.Done(),
fakeRestMapper,
)

View File

@ -44,6 +44,7 @@ import (
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/restmapper"
"k8s.io/component-base/compatibility"
"k8s.io/component-base/featuregate"
)
@ -130,6 +131,7 @@ func (a *AdmissionOptions) ApplyTo(
kubeClient kubernetes.Interface,
dynamicClient dynamic.Interface,
features featuregate.FeatureGate,
effectiveVersion compatibility.EffectiveVersion,
pluginInitializers ...admission.PluginInitializer,
) error {
if a == nil {
@ -154,7 +156,7 @@ func (a *AdmissionOptions) ApplyTo(
discoveryClient := cacheddiscovery.NewMemCacheClient(kubeClient.Discovery())
discoveryRESTMapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient)
genericInitializer := initializer.New(kubeClient, dynamicClient, informers, c.Authorization.Authorizer, features,
c.DrainedNotify(), discoveryRESTMapper)
effectiveVersion, c.DrainedNotify(), discoveryRESTMapper)
initializersChain := admission.PluginInitializers{genericInitializer}
initializersChain = append(initializersChain, pluginInitializers...)

View File

@ -141,6 +141,7 @@ func (o *RecommendedOptions) ApplyTo(config *server.RecommendedConfig) error {
return err
}
if err := o.Admission.ApplyTo(&config.Config, config.SharedInformerFactory, kubeClient, dynamicClient, o.FeatureGate,
config.EffectiveVersion,
initializers...); err != nil {
return err
}