Plumb effective version into admission initializer

This commit is contained in:
Jordan Liggitt 2025-07-28 16:48:28 -04:00
parent ae5d650460
commit 55419eca7a
No known key found for this signature in database
20 changed files with 47 additions and 20 deletions

View file

@ -40,6 +40,7 @@ import (
"k8s.io/apiserver/pkg/server/egressselector"
"k8s.io/apiserver/pkg/server/filters"
serverstorage "k8s.io/apiserver/pkg/server/storage"
"k8s.io/apiserver/pkg/util/compatibility"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/apiserver/pkg/util/openapi"
utilpeerproxy "k8s.io/apiserver/pkg/util/peerproxy"
@ -47,9 +48,9 @@ import (
clientgoinformers "k8s.io/client-go/informers"
clientgoclientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/util/keyutil"
basecompatibility "k8s.io/component-base/compatibility"
aggregatorapiserver "k8s.io/kube-aggregator/pkg/apiserver"
openapicommon "k8s.io/kube-openapi/pkg/common"
"k8s.io/kubernetes/pkg/api/legacyscheme"
controlplaneadmission "k8s.io/kubernetes/pkg/controlplane/apiserver/admission"
"k8s.io/kubernetes/pkg/controlplane/apiserver/options"
@ -379,6 +380,7 @@ func CreateConfig(
clientgoExternalClient,
dynamicExternalClient,
utilfeature.DefaultFeatureGate,
compatibility.DefaultComponentGlobalsRegistry.EffectiveVersionFor(basecompatibility.DefaultKubeComponent),
append(genericInitializers, additionalInitializers...)...,
)
if err != nil {

View file

@ -21,6 +21,7 @@ import (
"strings"
"github.com/spf13/pflag"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
@ -29,6 +30,7 @@ import (
"k8s.io/apiserver/pkg/server"
genericoptions "k8s.io/apiserver/pkg/server/options"
"k8s.io/client-go/informers"
"k8s.io/component-base/compatibility"
"k8s.io/component-base/featuregate"
)
@ -116,6 +118,7 @@ func (a *AdmissionOptions) ApplyTo(
kubeClient kubernetes.Interface,
dynamicClient dynamic.Interface,
features featuregate.FeatureGate,
effectiveVersion compatibility.EffectiveVersion,
pluginInitializers ...admission.PluginInitializer,
) error {
if a == nil {
@ -127,7 +130,7 @@ func (a *AdmissionOptions) ApplyTo(
a.GenericAdmission.EnablePlugins, a.GenericAdmission.DisablePlugins = computePluginNames(a.PluginNames, a.GenericAdmission.RecommendedPluginOrder)
}
return a.GenericAdmission.ApplyTo(c, informers, kubeClient, dynamicClient, features, pluginInitializers...)
return a.GenericAdmission.ApplyTo(c, informers, kubeClient, dynamicClient, features, effectiveVersion, pluginInitializers...)
}
// explicitly disable all plugins that are not in the enabled list

View file

@ -300,7 +300,7 @@ func TestHandles(t *testing.T) {
// newHandlerForTest returns a handler configured for testing.
func newHandlerForTest() (*Plugin, error) {
handler := NewDefaultTolerationSeconds()
pluginInitializer := initializer.New(nil, nil, nil, nil, nil, nil, nil)
pluginInitializer := initializer.New(nil, nil, nil, nil, nil, nil, nil, nil)
pluginInitializer.Initialize(handler)
return handler, admission.ValidateInitialization(handler)
}

View file

@ -138,7 +138,7 @@ func newGCPermissionsEnforcement() (*gcPermissionsEnforcement, error) {
return nil, fmt.Errorf("unexpected error while constructing resource list from fake discovery client: %v", err)
}
restMapper := restmapper.NewDiscoveryRESTMapper(restMapperRes)
genericPluginInitializer := initializer.New(nil, nil, nil, fakeAuthorizer{}, nil, nil, restMapper)
genericPluginInitializer := initializer.New(nil, nil, nil, fakeAuthorizer{}, nil, nil, nil, restMapper)
pluginInitializer := controlplaneadmission.NewPluginInitializer(nil, nil)
initializersChain := apiserveradmission.PluginInitializers{}
initializersChain = append(initializersChain, genericPluginInitializer)

View file

@ -891,7 +891,7 @@ func newHandlerForTest(c clientset.Interface) (*LimitRanger, informers.SharedInf
if err != nil {
return nil, f, err
}
pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil)
pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil, nil)
pluginInitializer.Initialize(handler)
err = admission.ValidateInitialization(handler)
return handler, f, err

View file

@ -41,7 +41,7 @@ import (
func newHandlerForTest(c clientset.Interface) (admission.MutationInterface, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(c, 5*time.Minute)
handler := NewProvision()
pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil)
pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil, nil)
pluginInitializer.Initialize(handler)
err := admission.ValidateInitialization(handler)
return handler, f, err

View file

@ -39,7 +39,7 @@ import (
func newHandlerForTest(c kubernetes.Interface) (admission.ValidationInterface, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(c, 5*time.Minute)
handler := NewExists()
pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil)
pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil, nil)
pluginInitializer.Initialize(handler)
err := admission.ValidateInitialization(handler)
return handler, f, err

View file

@ -198,7 +198,7 @@ func TestHandles(t *testing.T) {
func newHandlerForTest(c kubernetes.Interface) (*Plugin, informers.SharedInformerFactory, error) {
f := informers.NewSharedInformerFactory(c, 5*time.Minute)
handler := NewPodNodeSelector(nil)
pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil)
pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil, nil)
pluginInitializer.Initialize(handler)
err := admission.ValidateInitialization(handler)
return handler, f, err

View file

@ -23,6 +23,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -355,7 +356,7 @@ func newHandlerForTest(c kubernetes.Interface) (*Plugin, informers.SharedInforme
return nil, nil, err
}
handler := NewPodTolerationsPlugin(pluginConfig)
pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil)
pluginInitializer := genericadmissioninitializer.New(c, nil, f, nil, nil, nil, nil, nil)
pluginInitializer.Initialize(handler)
err = admission.ValidateInitialization(handler)
return handler, f, err

View file

@ -226,7 +226,7 @@ func TestPodTopology(t *testing.T) {
func newHandlerForTest(c kubernetes.Interface) (*Plugin, informers.SharedInformerFactory, error) {
factory := informers.NewSharedInformerFactory(c, 5*time.Minute)
handler := NewPodTopologyPlugin(defaultConfig) // todo: write additional test cases with non-default config.
pluginInitializer := genericadmissioninitializer.New(c, nil, factory, nil, feature.DefaultFeatureGate, nil, nil)
pluginInitializer := genericadmissioninitializer.New(c, nil, factory, nil, feature.DefaultFeatureGate, nil, nil, nil)
pluginInitializer.Initialize(handler)
return handler, factory, admission.ValidateInitialization(handler)
}

View file

@ -118,7 +118,7 @@ func createHandlerWithConfig(kubeClient kubernetes.Interface, informerFactory in
}
initializers := admission.PluginInitializers{
genericadmissioninitializer.New(kubeClient, nil, informerFactory, nil, nil, stopCh, nil),
genericadmissioninitializer.New(kubeClient, nil, informerFactory, nil, nil, nil, stopCh, nil),
controlplaneadmission.NewPluginInitializer(quotaConfiguration, nil),
}
initializers.Initialize(handler)

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
}

View file

@ -110,7 +110,7 @@ func TestAdmission(t *testing.T) {
// newHandlerForTest returns a handler configured for testing.
func newHandlerForTest() (*defaulttolerationseconds.Plugin, error) {
handler := defaulttolerationseconds.NewDefaultTolerationSeconds()
pluginInitializer := initializer.New(nil, nil, nil, nil, nil, nil, nil)
pluginInitializer := initializer.New(nil, nil, nil, nil, nil, nil, nil, nil)
pluginInitializer.Initialize(handler)
return handler, admission.ValidateInitialization(handler)
}

View file

@ -467,7 +467,7 @@ func TestTaintBasedEvictions(t *testing.T) {
// newHandlerForTest returns a handler configured for testing.
func newHandlerForTest() (*defaulttolerationseconds.Plugin, error) {
handler := defaulttolerationseconds.NewDefaultTolerationSeconds()
pluginInitializer := initializer.New(nil, nil, nil, nil, nil, nil, nil)
pluginInitializer := initializer.New(nil, nil, nil, nil, nil, nil, nil, nil)
pluginInitializer.Initialize(handler)
return handler, admission.ValidateInitialization(handler)
}