From f8211d7e447cc6c29139ebf3422f0752278d6da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Tyczy=C5=84ski?= Date: Wed, 18 May 2022 19:30:23 +0200 Subject: [PATCH] Fix ResourceQuota admission shutdown --- plugin/pkg/admission/gc/gc_admission_test.go | 2 +- .../admission/limitranger/admission_test.go | 2 +- .../namespace/autoprovision/admission_test.go | 2 +- .../namespace/exists/admission_test.go | 2 +- .../podnodeselector/admission_test.go | 2 +- .../admission_test.go | 2 +- .../admission/resourcequota/admission_test.go | 15 +++-- .../pkg/admission/initializer/initializer.go | 10 +++- .../admission/initializer/initializer_test.go | 35 +++++++++++- .../pkg/admission/initializer/interfaces.go | 8 +++ .../namespace/lifecycle/admission_test.go | 2 +- .../plugin/resourcequota/admission.go | 28 +++++++-- .../plugin/resourcequota/admission_test.go | 12 ++++ .../apiserver/pkg/server/options/admission.go | 5 +- test/integration/quota/quota_test.go | 57 +++++++++++++------ 15 files changed, 143 insertions(+), 41 deletions(-) diff --git a/plugin/pkg/admission/gc/gc_admission_test.go b/plugin/pkg/admission/gc/gc_admission_test.go index 30a174efb10..d5a30caa005 100644 --- a/plugin/pkg/admission/gc/gc_admission_test.go +++ b/plugin/pkg/admission/gc/gc_admission_test.go @@ -115,7 +115,7 @@ func newGCPermissionsEnforcement() (*gcPermissionsEnforcement, error) { whiteList: whiteList, } - genericPluginInitializer := initializer.New(nil, nil, fakeAuthorizer{}, nil) + genericPluginInitializer := initializer.New(nil, nil, fakeAuthorizer{}, nil, nil) fakeDiscoveryClient := &fakediscovery.FakeDiscovery{Fake: &coretesting.Fake{}} fakeDiscoveryClient.Resources = []*metav1.APIResourceList{ { diff --git a/plugin/pkg/admission/limitranger/admission_test.go b/plugin/pkg/admission/limitranger/admission_test.go index 9fd6699b2a9..4e5879d713e 100644 --- a/plugin/pkg/admission/limitranger/admission_test.go +++ b/plugin/pkg/admission/limitranger/admission_test.go @@ -790,7 +790,7 @@ func newHandlerForTest(c clientset.Interface) (*LimitRanger, informers.SharedInf if err != nil { return nil, f, err } - pluginInitializer := genericadmissioninitializer.New(c, f, nil, nil) + pluginInitializer := genericadmissioninitializer.New(c, f, nil, nil, nil) pluginInitializer.Initialize(handler) err = admission.ValidateInitialization(handler) return handler, f, err diff --git a/plugin/pkg/admission/namespace/autoprovision/admission_test.go b/plugin/pkg/admission/namespace/autoprovision/admission_test.go index 9f32c7c764f..7b1991acdf4 100644 --- a/plugin/pkg/admission/namespace/autoprovision/admission_test.go +++ b/plugin/pkg/admission/namespace/autoprovision/admission_test.go @@ -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, f, nil, nil) + pluginInitializer := genericadmissioninitializer.New(c, f, nil, nil, nil) pluginInitializer.Initialize(handler) err := admission.ValidateInitialization(handler) return handler, f, err diff --git a/plugin/pkg/admission/namespace/exists/admission_test.go b/plugin/pkg/admission/namespace/exists/admission_test.go index 02a799b447d..03500e77433 100644 --- a/plugin/pkg/admission/namespace/exists/admission_test.go +++ b/plugin/pkg/admission/namespace/exists/admission_test.go @@ -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, f, nil, nil) + pluginInitializer := genericadmissioninitializer.New(c, f, nil, nil, nil) pluginInitializer.Initialize(handler) err := admission.ValidateInitialization(handler) return handler, f, err diff --git a/plugin/pkg/admission/podnodeselector/admission_test.go b/plugin/pkg/admission/podnodeselector/admission_test.go index 86cc3c0a2c5..ab2f5404a87 100644 --- a/plugin/pkg/admission/podnodeselector/admission_test.go +++ b/plugin/pkg/admission/podnodeselector/admission_test.go @@ -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, f, nil, nil) + pluginInitializer := genericadmissioninitializer.New(c, f, nil, nil, nil) pluginInitializer.Initialize(handler) err := admission.ValidateInitialization(handler) return handler, f, err diff --git a/plugin/pkg/admission/podtolerationrestriction/admission_test.go b/plugin/pkg/admission/podtolerationrestriction/admission_test.go index f8d19916de0..ae440e23486 100644 --- a/plugin/pkg/admission/podtolerationrestriction/admission_test.go +++ b/plugin/pkg/admission/podtolerationrestriction/admission_test.go @@ -356,7 +356,7 @@ func newHandlerForTest(c kubernetes.Interface) (*Plugin, informers.SharedInforme return nil, nil, err } handler := NewPodTolerationsPlugin(pluginConfig) - pluginInitializer := genericadmissioninitializer.New(c, f, nil, nil) + pluginInitializer := genericadmissioninitializer.New(c, f, nil, nil, nil) pluginInitializer.Initialize(handler) err = admission.ValidateInitialization(handler) return handler, f, err diff --git a/plugin/pkg/admission/resourcequota/admission_test.go b/plugin/pkg/admission/resourcequota/admission_test.go index 1313b955641..1089ba14cf6 100644 --- a/plugin/pkg/admission/resourcequota/admission_test.go +++ b/plugin/pkg/admission/resourcequota/admission_test.go @@ -28,6 +28,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apiserver/pkg/admission" + genericadmissioninitializer "k8s.io/apiserver/pkg/admission/initializer" "k8s.io/apiserver/pkg/admission/plugin/resourcequota" resourcequotaapi "k8s.io/apiserver/pkg/admission/plugin/resourcequota/apis/resourcequota" "k8s.io/client-go/informers" @@ -36,6 +37,7 @@ import ( testcore "k8s.io/client-go/testing" "k8s.io/client-go/tools/cache" api "k8s.io/kubernetes/pkg/apis/core" + kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" "k8s.io/kubernetes/pkg/quota/v1/install" ) @@ -99,15 +101,18 @@ func createHandlerWithConfig(kubeClient kubernetes.Interface, informerFactory in } quotaConfiguration := install.NewQuotaConfigurationForAdmission() - handler, err := resourcequota.NewResourceQuota(config, 5, stopCh) + handler, err := resourcequota.NewResourceQuota(config, 5) if err != nil { return nil, err } - handler.SetExternalKubeClientSet(kubeClient) - handler.SetExternalKubeInformerFactory(informerFactory) - handler.SetQuotaConfiguration(quotaConfiguration) - return handler, nil + initializers := admission.PluginInitializers{ + genericadmissioninitializer.New(kubeClient, informerFactory, nil, nil, stopCh), + kubeapiserveradmission.NewPluginInitializer(nil, nil, quotaConfiguration), + } + initializers.Initialize(handler) + + return handler, admission.ValidateInitialization(handler) } // TestAdmissionIgnoresDelete verifies that the admission controller ignores delete operations diff --git a/staging/src/k8s.io/apiserver/pkg/admission/initializer/initializer.go b/staging/src/k8s.io/apiserver/pkg/admission/initializer/initializer.go index 613baf8efaf..2d9bae550ad 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/initializer/initializer.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/initializer/initializer.go @@ -29,6 +29,7 @@ type pluginInitializer struct { externalInformers informers.SharedInformerFactory authorizer authorizer.Authorizer featureGates featuregate.FeatureGate + stopCh <-chan struct{} } // New creates an instance of admission plugins initializer. @@ -39,19 +40,26 @@ func New( extInformers informers.SharedInformerFactory, authz authorizer.Authorizer, featureGates featuregate.FeatureGate, + stopCh <-chan struct{}, ) pluginInitializer { return pluginInitializer{ externalClient: extClientset, externalInformers: extInformers, authorizer: authz, featureGates: featureGates, + stopCh: stopCh, } } // Initialize checks the initialization interfaces implemented by a plugin // and provide the appropriate initialization data func (i pluginInitializer) Initialize(plugin admission.Interface) { - // First tell the plugin about enabled features, so it can decide whether to start informers or not + // First tell the plugin about drained notification, so it can pass it to further initializations. + if wants, ok := plugin.(WantsDrainedNotification); ok { + wants.SetDrainedNotification(i.stopCh) + } + + // Second tell the plugin about enabled features, so it can decide whether to start informers or not if wants, ok := plugin.(WantsFeatures); ok { wants.InspectFeatureGates(i.featureGates) } diff --git a/staging/src/k8s.io/apiserver/pkg/admission/initializer/initializer_test.go b/staging/src/k8s.io/apiserver/pkg/admission/initializer/initializer_test.go index 8fa9eeadde4..a2849bbce18 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/initializer/initializer_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/initializer/initializer_test.go @@ -32,7 +32,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, &TestAuthorizer{}, nil) + target := initializer.New(nil, nil, &TestAuthorizer{}, nil, nil) wantAuthorizerAdmission := &WantAuthorizerAdmission{} target.Initialize(wantAuthorizerAdmission) if wantAuthorizerAdmission.auth == nil { @@ -44,7 +44,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, &TestAuthorizer{}, nil) + target := initializer.New(cs, nil, &TestAuthorizer{}, nil, nil) wantExternalKubeClientSet := &WantExternalKubeClientSet{} target.Initialize(wantExternalKubeClientSet) if wantExternalKubeClientSet.cs != cs { @@ -57,7 +57,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, sf, &TestAuthorizer{}, nil) + target := initializer.New(cs, sf, &TestAuthorizer{}, nil, nil) wantExternalKubeInformerFactory := &WantExternalKubeInformerFactory{} target.Initialize(wantExternalKubeInformerFactory) if wantExternalKubeInformerFactory.sf != sf { @@ -65,6 +65,18 @@ func TestWantsExternalKubeInformerFactory(t *testing.T) { } } +// TestWantsShutdownSignal ensures that the shutdown signal is injected +// when the WantsShutdownSignal interface is implemented by a plugin. +func TestWantsShutdownNotification(t *testing.T) { + stopCh := make(chan struct{}) + target := initializer.New(nil, nil, &TestAuthorizer{}, nil, stopCh) + wantDrainedNotification := &WantDrainedNotification{} + target.Initialize(wantDrainedNotification) + if wantDrainedNotification.stopCh == nil { + t.Errorf("expected stopCh to be initialized but found nil") + } +} + // WantExternalKubeInformerFactory is a test stub that fulfills the WantsExternalKubeInformerFactory interface type WantExternalKubeInformerFactory struct { sf informers.SharedInformerFactory @@ -114,6 +126,23 @@ func (self *WantAuthorizerAdmission) ValidateInitialization() error { retur var _ admission.Interface = &WantAuthorizerAdmission{} var _ initializer.WantsAuthorizer = &WantAuthorizerAdmission{} +// WantDrainedNotification is a test stub that filfills the WantsDrainedNotification interface. +type WantDrainedNotification struct { + stopCh <-chan struct{} +} + +func (self *WantDrainedNotification) SetDrainedNotification(stopCh <-chan struct{}) { + self.stopCh = stopCh +} +func (self *WantDrainedNotification) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error { + return nil +} +func (self *WantDrainedNotification) Handles(o admission.Operation) bool { return false } +func (self *WantDrainedNotification) ValidateInitialization() error { return nil } + +var _ admission.Interface = &WantDrainedNotification{} +var _ initializer.WantsDrainedNotification = &WantDrainedNotification{} + // TestAuthorizer is a test stub that fulfills the WantsAuthorizer interface. type TestAuthorizer struct{} diff --git a/staging/src/k8s.io/apiserver/pkg/admission/initializer/interfaces.go b/staging/src/k8s.io/apiserver/pkg/admission/initializer/interfaces.go index 86a6df1c2c4..191c090556d 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/initializer/interfaces.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/initializer/interfaces.go @@ -49,6 +49,14 @@ type WantsQuotaConfiguration interface { admission.InitializationValidator } +// WantsDrainedNotification defines a function which sets the notification of where the apiserver +// has already been drained for admission plugins that need it. +// After receiving that notification, Admit/Validate calls won't be called anymore. +type WantsDrainedNotification interface { + SetDrainedNotification(<-chan struct{}) + admission.InitializationValidator +} + // WantsFeatureGate defines a function which passes the featureGates for inspection by an admission plugin. // Admission plugins should not hold a reference to the featureGates. Instead, they should query a particular one // and assign it to a simple bool in the admission plugin struct. diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go index e0131538db1..c29bacf0ea4 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/namespace/lifecycle/admission_test.go @@ -53,7 +53,7 @@ func newHandlerForTestWithClock(c clientset.Interface, cacheClock clock.Clock) ( if err != nil { return nil, f, err } - pluginInitializer := kubeadmission.New(c, f, nil, nil) + pluginInitializer := kubeadmission.New(c, f, nil, nil, nil) pluginInitializer.Initialize(handler) err = admission.ValidateInitialization(handler) return handler, f, err diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/resourcequota/admission.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/resourcequota/admission.go index 76049950904..25c266479db 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/resourcequota/admission.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/resourcequota/admission.go @@ -37,7 +37,10 @@ import ( // PluginName is a string with the name of the plugin const PluginName = "ResourceQuota" -var namespaceGVK = v1.SchemeGroupVersion.WithKind("Namespace").GroupKind() +var ( + namespaceGVK = v1.SchemeGroupVersion.WithKind("Namespace").GroupKind() + stopChUnconfiguredErr = fmt.Errorf("quota configuration configured between stop channel") +) // Register registers a plugin func Register(plugins *admission.Plugins) { @@ -54,7 +57,7 @@ func Register(plugins *admission.Plugins) { return nil, errs.ToAggregate() } } - return NewResourceQuota(configuration, 5, make(chan struct{})) + return NewResourceQuota(configuration, 5) }) } @@ -67,12 +70,14 @@ type QuotaAdmission struct { numEvaluators int quotaAccessor *quotaAccessor evaluator Evaluator + initializationErr error } var _ admission.ValidationInterface = &QuotaAdmission{} var _ = genericadmissioninitializer.WantsExternalKubeInformerFactory(&QuotaAdmission{}) var _ = genericadmissioninitializer.WantsExternalKubeClientSet(&QuotaAdmission{}) var _ = genericadmissioninitializer.WantsQuotaConfiguration(&QuotaAdmission{}) +var _ = genericadmissioninitializer.WantsDrainedNotification(&QuotaAdmission{}) type liveLookupEntry struct { expiry time.Time @@ -82,7 +87,7 @@ type liveLookupEntry struct { // NewResourceQuota configures an admission controller that can enforce quota constraints // using the provided registry. The registry must have the capability to handle group/kinds that // are persisted by the server this admission controller is intercepting -func NewResourceQuota(config *resourcequotaapi.Configuration, numEvaluators int, stopCh <-chan struct{}) (*QuotaAdmission, error) { +func NewResourceQuota(config *resourcequotaapi.Configuration, numEvaluators int) (*QuotaAdmission, error) { quotaAccessor, err := newQuotaAccessor() if err != nil { return nil, err @@ -90,13 +95,18 @@ func NewResourceQuota(config *resourcequotaapi.Configuration, numEvaluators int, return &QuotaAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), - stopCh: stopCh, + stopCh: nil, numEvaluators: numEvaluators, config: config, quotaAccessor: quotaAccessor, }, nil } +// SetDrainedNotification sets the stop channel into QuotaAdmission. +func (a *QuotaAdmission) SetDrainedNotification(stopCh <-chan struct{}) { + a.stopCh = stopCh +} + // SetExternalKubeClientSet registers the client into QuotaAdmission func (a *QuotaAdmission) SetExternalKubeClientSet(client kubernetes.Interface) { a.quotaAccessor.client = client @@ -110,11 +120,21 @@ func (a *QuotaAdmission) SetExternalKubeInformerFactory(f informers.SharedInform // SetQuotaConfiguration assigns and initializes configuration and evaluator for QuotaAdmission func (a *QuotaAdmission) SetQuotaConfiguration(c quota.Configuration) { a.quotaConfiguration = c + if a.stopCh == nil { + a.initializationErr = stopChUnconfiguredErr + return + } a.evaluator = NewQuotaEvaluator(a.quotaAccessor, a.quotaConfiguration.IgnoredResources(), generic.NewRegistry(a.quotaConfiguration.Evaluators()), nil, a.config, a.numEvaluators, a.stopCh) } // ValidateInitialization ensures an authorizer is set. func (a *QuotaAdmission) ValidateInitialization() error { + if a.initializationErr != nil { + return a.initializationErr + } + if a.stopCh == nil { + return fmt.Errorf("missing stopCh") + } if a.quotaAccessor == nil { return fmt.Errorf("missing quotaAccessor") } diff --git a/staging/src/k8s.io/apiserver/pkg/admission/plugin/resourcequota/admission_test.go b/staging/src/k8s.io/apiserver/pkg/admission/plugin/resourcequota/admission_test.go index 04f12af8094..efe323a079f 100644 --- a/staging/src/k8s.io/apiserver/pkg/admission/plugin/resourcequota/admission_test.go +++ b/staging/src/k8s.io/apiserver/pkg/admission/plugin/resourcequota/admission_test.go @@ -26,6 +26,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/admission" v1 "k8s.io/apiserver/pkg/admission/plugin/resourcequota/apis/resourcequota/v1" + "k8s.io/apiserver/pkg/quota/v1/generic" ) func TestPrettyPrint(t *testing.T) { @@ -161,3 +162,14 @@ func TestExcludedOperations(t *testing.T) { } } } + +func TestInitializationOrder(t *testing.T) { + a := &QuotaAdmission{} + + qca := generic.NewConfiguration(nil, nil) + a.SetQuotaConfiguration(qca) + + if err := a.ValidateInitialization(); err != stopChUnconfiguredErr { + t.Errorf("unexpected error: %v", err) + } +} diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/admission.go b/staging/src/k8s.io/apiserver/pkg/server/options/admission.go index 765e2ad2b65..2d77e68979c 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/admission.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/admission.go @@ -143,9 +143,8 @@ func (a *AdmissionOptions) ApplyTo( if err != nil { return err } - genericInitializer := initializer.New(clientset, informers, c.Authorization.Authorizer, features) - initializersChain := admission.PluginInitializers{} - pluginInitializers = append(pluginInitializers, genericInitializer) + genericInitializer := initializer.New(clientset, informers, c.Authorization.Authorizer, features, c.DrainedNotify()) + initializersChain := admission.PluginInitializers{genericInitializer} initializersChain = append(initializersChain, pluginInitializers...) admissionChain, err := a.Plugins.NewFromPlugins(pluginNames, pluginsConfigProvider, initializersChain, a.Decorators) diff --git a/test/integration/quota/quota_test.go b/test/integration/quota/quota_test.go index e8bb3dad27e..382e3d2c643 100644 --- a/test/integration/quota/quota_test.go +++ b/test/integration/quota/quota_test.go @@ -35,6 +35,8 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/watch" + "k8s.io/apiserver/pkg/admission" + genericadmissioninitializer "k8s.io/apiserver/pkg/admission/initializer" "k8s.io/apiserver/pkg/admission/plugin/resourcequota" resourcequotaapi "k8s.io/apiserver/pkg/admission/plugin/resourcequota/apis/resourcequota" "k8s.io/apiserver/pkg/quota/v1/generic" @@ -45,6 +47,7 @@ import ( "k8s.io/kubernetes/pkg/controller" replicationcontroller "k8s.io/kubernetes/pkg/controller/replication" resourcequotacontroller "k8s.io/kubernetes/pkg/controller/resourcequota" + kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission" quotainstall "k8s.io/kubernetes/pkg/quota/v1/install" "k8s.io/kubernetes/test/integration/framework" ) @@ -68,21 +71,27 @@ func TestQuota(t *testing.T) { })) admissionCh := make(chan struct{}) + defer close(admissionCh) clientset := clientset.NewForConfigOrDie(&restclient.Config{QPS: -1, Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Group: "", Version: "v1"}}}) config := &resourcequotaapi.Configuration{} - admission, err := resourcequota.NewResourceQuota(config, 5, admissionCh) + admissionControl, err := resourcequota.NewResourceQuota(config, 5) if err != nil { t.Fatalf("unexpected error: %v", err) } - admission.SetExternalKubeClientSet(clientset) internalInformers := informers.NewSharedInformerFactory(clientset, controller.NoResyncPeriodFunc()) - admission.SetExternalKubeInformerFactory(internalInformers) qca := quotainstall.NewQuotaConfigurationForAdmission() - admission.SetQuotaConfiguration(qca) - defer close(admissionCh) + + initializers := admission.PluginInitializers{ + genericadmissioninitializer.New(clientset, internalInformers, nil, nil, admissionCh), + kubeapiserveradmission.NewPluginInitializer(nil, nil, qca), + } + initializers.Initialize(admissionControl) + if err := admission.ValidateInitialization(admissionControl); err != nil { + t.Fatalf("couldn't initialize resource quota: %v", err) + } controlPlaneConfig := framework.NewIntegrationTestControlPlaneConfig() - controlPlaneConfig.GenericConfig.AdmissionControl = admission + controlPlaneConfig.GenericConfig.AdmissionControl = admissionControl _, _, closeFn := framework.RunAnAPIServerUsingServer(controlPlaneConfig, s, h) defer closeFn() @@ -291,6 +300,7 @@ func TestQuotaLimitedResourceDenial(t *testing.T) { })) admissionCh := make(chan struct{}) + defer close(admissionCh) clientset := clientset.NewForConfigOrDie(&restclient.Config{QPS: -1, Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Group: "", Version: "v1"}}}) // stop creation of a pod resource unless there is a quota @@ -303,18 +313,23 @@ func TestQuotaLimitedResourceDenial(t *testing.T) { }, } qca := quotainstall.NewQuotaConfigurationForAdmission() - admission, err := resourcequota.NewResourceQuota(config, 5, admissionCh) + admissionControl, err := resourcequota.NewResourceQuota(config, 5) if err != nil { t.Fatalf("unexpected error: %v", err) } - admission.SetExternalKubeClientSet(clientset) externalInformers := informers.NewSharedInformerFactory(clientset, controller.NoResyncPeriodFunc()) - admission.SetExternalKubeInformerFactory(externalInformers) - admission.SetQuotaConfiguration(qca) - defer close(admissionCh) + + initializers := admission.PluginInitializers{ + genericadmissioninitializer.New(clientset, externalInformers, nil, nil, admissionCh), + kubeapiserveradmission.NewPluginInitializer(nil, nil, qca), + } + initializers.Initialize(admissionControl) + if err := admission.ValidateInitialization(admissionControl); err != nil { + t.Fatalf("couldn't initialize resource quota: %v", err) + } controlPlaneConfig := framework.NewIntegrationTestControlPlaneConfig() - controlPlaneConfig.GenericConfig.AdmissionControl = admission + controlPlaneConfig.GenericConfig.AdmissionControl = admissionControl _, _, closeFn := framework.RunAnAPIServerUsingServer(controlPlaneConfig, s, h) defer closeFn() @@ -419,6 +434,7 @@ func TestQuotaLimitService(t *testing.T) { })) admissionCh := make(chan struct{}) + defer close(admissionCh) clientset := clientset.NewForConfigOrDie(&restclient.Config{QPS: -1, Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Group: "", Version: "v1"}}}) // stop creation of a pod resource unless there is a quota @@ -431,18 +447,23 @@ func TestQuotaLimitService(t *testing.T) { }, } qca := quotainstall.NewQuotaConfigurationForAdmission() - admission, err := resourcequota.NewResourceQuota(config, 5, admissionCh) + admissionControl, err := resourcequota.NewResourceQuota(config, 5) if err != nil { t.Fatalf("unexpected error: %v", err) } - admission.SetExternalKubeClientSet(clientset) externalInformers := informers.NewSharedInformerFactory(clientset, controller.NoResyncPeriodFunc()) - admission.SetExternalKubeInformerFactory(externalInformers) - admission.SetQuotaConfiguration(qca) - defer close(admissionCh) + + initializers := admission.PluginInitializers{ + genericadmissioninitializer.New(clientset, externalInformers, nil, nil, admissionCh), + kubeapiserveradmission.NewPluginInitializer(nil, nil, qca), + } + initializers.Initialize(admissionControl) + if err := admission.ValidateInitialization(admissionControl); err != nil { + t.Fatalf("couldn't initialize resource quota: %v", err) + } controlPlaneConfig := framework.NewIntegrationTestControlPlaneConfig() - controlPlaneConfig.GenericConfig.AdmissionControl = admission + controlPlaneConfig.GenericConfig.AdmissionControl = admissionControl _, _, closeFn := framework.RunAnAPIServerUsingServer(controlPlaneConfig, s, h) defer closeFn()