diff --git a/cmd/kube-apiserver/app/server.go b/cmd/kube-apiserver/app/server.go index a018365f5ff..e2724931db3 100644 --- a/cmd/kube-apiserver/app/server.go +++ b/cmd/kube-apiserver/app/server.go @@ -506,11 +506,9 @@ func BuildAdmissionPluginInitializer(s *options.ServerRunOptions, client interna // TODO: use a dynamic restmapper. See https://github.com/kubernetes/kubernetes/pull/42615. restMapper := legacyscheme.Registry.RESTMapper() - // NOTE: we do not provide informers to the quota registry because admission level decisions - // do not require us to open watches for all items tracked by quota. - quotaRegistry := quotainstall.NewRegistry(nil, nil) + quotaConfiguration := quotainstall.NewQuotaConfigurationForAdmission() - pluginInitializer := kubeapiserveradmission.NewPluginInitializer(client, sharedInformers, cloudConfig, restMapper, quotaRegistry, webhookAuthWrapper, serviceResolver) + pluginInitializer := kubeapiserveradmission.NewPluginInitializer(client, sharedInformers, cloudConfig, restMapper, quotaConfiguration, webhookAuthWrapper, serviceResolver) return pluginInitializer, nil } diff --git a/pkg/kubeapiserver/admission/initializer.go b/pkg/kubeapiserver/admission/initializer.go index 551c2314b5e..b7696916001 100644 --- a/pkg/kubeapiserver/admission/initializer.go +++ b/pkg/kubeapiserver/admission/initializer.go @@ -53,9 +53,9 @@ type WantsRESTMapper interface { SetRESTMapper(meta.RESTMapper) } -// WantsQuotaRegistry defines a function which sets quota registry for admission plugins that need it. -type WantsQuotaRegistry interface { - SetQuotaRegistry(quota.Registry) +// WantsQuotaConfiguration defines a function which sets quota configuration for admission plugins that need it. +type WantsQuotaConfiguration interface { + SetQuotaConfiguration(quota.Configuration) admission.Validator } @@ -85,7 +85,7 @@ type PluginInitializer struct { authorizer authorizer.Authorizer cloudConfig []byte restMapper meta.RESTMapper - quotaRegistry quota.Registry + quotaConfiguration quota.Configuration serviceResolver webhook.ServiceResolver authenticationInfoResolverWrapper webhook.AuthenticationInfoResolverWrapper } @@ -100,7 +100,7 @@ func NewPluginInitializer( sharedInformers informers.SharedInformerFactory, cloudConfig []byte, restMapper meta.RESTMapper, - quotaRegistry quota.Registry, + quotaConfiguration quota.Configuration, authenticationInfoResolverWrapper webhook.AuthenticationInfoResolverWrapper, serviceResolver webhook.ServiceResolver, ) *PluginInitializer { @@ -109,7 +109,7 @@ func NewPluginInitializer( informers: sharedInformers, cloudConfig: cloudConfig, restMapper: restMapper, - quotaRegistry: quotaRegistry, + quotaConfiguration: quotaConfiguration, authenticationInfoResolverWrapper: authenticationInfoResolverWrapper, serviceResolver: serviceResolver, } @@ -134,8 +134,8 @@ func (i *PluginInitializer) Initialize(plugin admission.Interface) { wants.SetRESTMapper(i.restMapper) } - if wants, ok := plugin.(WantsQuotaRegistry); ok { - wants.SetQuotaRegistry(i.quotaRegistry) + if wants, ok := plugin.(WantsQuotaConfiguration); ok { + wants.SetQuotaConfiguration(i.quotaConfiguration) } if wants, ok := plugin.(WantsServiceResolver); ok { diff --git a/plugin/pkg/admission/resourcequota/BUILD b/plugin/pkg/admission/resourcequota/BUILD index c2c0e0f4724..b54f99e2a4b 100644 --- a/plugin/pkg/admission/resourcequota/BUILD +++ b/plugin/pkg/admission/resourcequota/BUILD @@ -23,6 +23,7 @@ go_library( "//pkg/client/listers/core/internalversion:go_default_library", "//pkg/kubeapiserver/admission:go_default_library", "//pkg/quota:go_default_library", + "//pkg/quota/generic:go_default_library", "//pkg/util/reflector/prometheus:go_default_library", "//pkg/util/workqueue/prometheus:go_default_library", "//plugin/pkg/admission/resourcequota/apis/resourcequota:go_default_library", @@ -58,14 +59,11 @@ go_test( "//pkg/client/clientset_generated/internalclientset/fake:go_default_library", "//pkg/client/informers/informers_generated/internalversion:go_default_library", "//pkg/controller:go_default_library", - "//pkg/quota:go_default_library", - "//pkg/quota/generic:go_default_library", "//pkg/quota/install:go_default_library", "//plugin/pkg/admission/resourcequota/apis/resourcequota:go_default_library", "//vendor/github.com/hashicorp/golang-lru:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/apiserver/pkg/admission:go_default_library", "//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library", diff --git a/plugin/pkg/admission/resourcequota/admission.go b/plugin/pkg/admission/resourcequota/admission.go index cfb97af50b8..a6885a22949 100644 --- a/plugin/pkg/admission/resourcequota/admission.go +++ b/plugin/pkg/admission/resourcequota/admission.go @@ -53,16 +53,16 @@ func Register(plugins *admission.Plugins) { // quotaAdmission implements an admission controller that can enforce quota constraints type quotaAdmission struct { *admission.Handler - config *resourcequotaapi.Configuration - stopCh <-chan struct{} - registry quota.Registry - numEvaluators int - quotaAccessor *quotaAccessor - evaluator Evaluator + config *resourcequotaapi.Configuration + stopCh <-chan struct{} + quotaConfiguration quota.Configuration + numEvaluators int + quotaAccessor *quotaAccessor + evaluator Evaluator } var _ = kubeapiserveradmission.WantsInternalKubeClientSet("aAdmission{}) -var _ = kubeapiserveradmission.WantsQuotaRegistry("aAdmission{}) +var _ = kubeapiserveradmission.WantsQuotaConfiguration("aAdmission{}) type liveLookupEntry struct { expiry time.Time @@ -95,9 +95,9 @@ func (a *quotaAdmission) SetInternalKubeInformerFactory(f informers.SharedInform a.quotaAccessor.lister = f.Core().InternalVersion().ResourceQuotas().Lister() } -func (a *quotaAdmission) SetQuotaRegistry(r quota.Registry) { - a.registry = r - a.evaluator = NewQuotaEvaluator(a.quotaAccessor, a.registry, nil, a.config, a.numEvaluators, a.stopCh) +func (a *quotaAdmission) SetQuotaConfiguration(c quota.Configuration) { + a.quotaConfiguration = c + a.evaluator = NewQuotaEvaluator(a.quotaAccessor, a.quotaConfiguration, nil, a.config, a.numEvaluators, a.stopCh) } // Validate ensures an authorizer is set. @@ -111,8 +111,8 @@ func (a *quotaAdmission) Validate() error { if a.quotaAccessor.lister == nil { return fmt.Errorf("missing quotaAccessor.lister") } - if a.registry == nil { - return fmt.Errorf("missing registry") + if a.quotaConfiguration == nil { + return fmt.Errorf("missing quotaConfiguration") } if a.evaluator == nil { return fmt.Errorf("missing evaluator") @@ -126,5 +126,9 @@ func (a *quotaAdmission) Admit(attr admission.Attributes) (err error) { if attr.GetSubresource() != "" { return nil } + // ignore all operations that are not namespaced + if attr.GetNamespace() == "" { + return nil + } return a.evaluator.Evaluate(attr) } diff --git a/plugin/pkg/admission/resourcequota/admission_test.go b/plugin/pkg/admission/resourcequota/admission_test.go index 0d197c12381..671cda4cf45 100644 --- a/plugin/pkg/admission/resourcequota/admission_test.go +++ b/plugin/pkg/admission/resourcequota/admission_test.go @@ -26,7 +26,6 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apiserver/pkg/admission" utilfeature "k8s.io/apiserver/pkg/util/feature" @@ -36,8 +35,6 @@ import ( "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion" "k8s.io/kubernetes/pkg/controller" - "k8s.io/kubernetes/pkg/quota" - "k8s.io/kubernetes/pkg/quota/generic" "k8s.io/kubernetes/pkg/quota/install" resourcequotaapi "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota" ) @@ -135,7 +132,8 @@ func TestAdmissionIgnoresDelete(t *testing.T) { quotaAccessor.client = kubeClient quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister() config := &resourcequotaapi.Configuration{} - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), @@ -170,7 +168,8 @@ func TestAdmissionIgnoresSubresources(t *testing.T) { quotaAccessor.client = kubeClient quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister() config := &resourcequotaapi.Configuration{} - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), @@ -214,7 +213,8 @@ func TestAdmitBelowQuotaLimit(t *testing.T) { quotaAccessor.client = kubeClient quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister() config := &resourcequotaapi.Configuration{} - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), @@ -297,7 +297,8 @@ func TestAdmitHandlesOldObjects(t *testing.T) { quotaAccessor.client = kubeClient quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister() config := &resourcequotaapi.Configuration{} - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), @@ -403,7 +404,8 @@ func TestAdmitHandlesNegativePVCUpdates(t *testing.T) { quotaAccessor.client = kubeClient quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister() config := &resourcequotaapi.Configuration{} - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), @@ -469,7 +471,8 @@ func TestAdmitHandlesPVCUpdates(t *testing.T) { quotaAccessor.client = kubeClient quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister() config := &resourcequotaapi.Configuration{} - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), @@ -567,7 +570,8 @@ func TestAdmitHandlesCreatingUpdates(t *testing.T) { quotaAccessor.client = kubeClient quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister() config := &resourcequotaapi.Configuration{} - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), @@ -661,7 +665,8 @@ func TestAdmitExceedQuotaLimit(t *testing.T) { quotaAccessor.client = kubeClient quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister() config := &resourcequotaapi.Configuration{} - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), @@ -705,7 +710,8 @@ func TestAdmitEnforceQuotaConstraints(t *testing.T) { quotaAccessor.client = kubeClient quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister() config := &resourcequotaapi.Configuration{} - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), @@ -759,7 +765,8 @@ func TestAdmitPodInNamespaceWithoutQuota(t *testing.T) { quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister() quotaAccessor.liveLookupCache = liveLookupCache config := &resourcequotaapi.Configuration{} - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), @@ -825,7 +832,8 @@ func TestAdmitBelowTerminatingQuotaLimit(t *testing.T) { quotaAccessor.client = kubeClient quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister() config := &resourcequotaapi.Configuration{} - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), @@ -930,7 +938,8 @@ func TestAdmitBelowBestEffortQuotaLimit(t *testing.T) { quotaAccessor.client = kubeClient quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister() config := &resourcequotaapi.Configuration{} - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), @@ -1022,7 +1031,8 @@ func TestAdmitBestEffortQuotaLimitIgnoresBurstable(t *testing.T) { quotaAccessor.client = kubeClient quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister() config := &resourcequotaapi.Configuration{} - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), @@ -1098,17 +1108,6 @@ func TestAdmissionSetsMissingNamespace(t *testing.T) { }, } - // create a dummy evaluator so we can trigger quota - podEvaluator := &generic.ObjectCountEvaluator{ - AllowCreateOnUpdate: false, - InternalGroupKind: api.Kind("Pod"), - ResourceName: api.ResourcePods, - } - registry := &generic.GenericRegistry{ - InternalEvaluators: map[schema.GroupKind]quota.Evaluator{ - podEvaluator.GroupKind(): podEvaluator, - }, - } stopCh := make(chan struct{}) defer close(stopCh) @@ -1118,8 +1117,8 @@ func TestAdmissionSetsMissingNamespace(t *testing.T) { quotaAccessor.client = kubeClient quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister() config := &resourcequotaapi.Configuration{} - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) - evaluator.(*quotaEvaluator).registry = registry + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), @@ -1164,7 +1163,8 @@ func TestAdmitRejectsNegativeUsage(t *testing.T) { quotaAccessor.client = kubeClient quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister() config := &resourcequotaapi.Configuration{} - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), @@ -1210,7 +1210,8 @@ func TestAdmitWhenUnrelatedResourceExceedsQuota(t *testing.T) { quotaAccessor.client = kubeClient quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister() config := &resourcequotaapi.Configuration{} - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), @@ -1246,7 +1247,8 @@ func TestAdmitLimitedResourceNoQuota(t *testing.T) { }, }, } - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), @@ -1279,7 +1281,8 @@ func TestAdmitLimitedResourceNoQuotaIgnoresNonMatchingResources(t *testing.T) { }, }, } - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), @@ -1325,7 +1328,8 @@ func TestAdmitLimitedResourceWithQuota(t *testing.T) { }, }, } - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), @@ -1383,7 +1387,8 @@ func TestAdmitLimitedResourceWithMultipleQuota(t *testing.T) { }, }, } - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), @@ -1431,7 +1436,8 @@ func TestAdmitLimitedResourceWithQuotaThatDoesNotCover(t *testing.T) { }, }, } - evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh) + quotaConfiguration := install.NewQuotaConfigurationForAdmission() + evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh) handler := "aAdmission{ Handler: admission.NewHandler(admission.Create, admission.Update), diff --git a/plugin/pkg/admission/resourcequota/controller.go b/plugin/pkg/admission/resourcequota/controller.go index 3650f2d39ea..ca0dd50e97c 100644 --- a/plugin/pkg/admission/resourcequota/controller.go +++ b/plugin/pkg/admission/resourcequota/controller.go @@ -34,6 +34,7 @@ import ( "k8s.io/client-go/util/workqueue" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/quota" + "k8s.io/kubernetes/pkg/quota/generic" _ "k8s.io/kubernetes/pkg/util/reflector/prometheus" // for reflector metric registration _ "k8s.io/kubernetes/pkg/util/workqueue/prometheus" // for workqueue metric registration resourcequotaapi "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota" @@ -51,6 +52,9 @@ type quotaEvaluator struct { // lockAcquisitionFunc acquires any required locks and returns a cleanup method to defer lockAcquisitionFunc func([]api.ResourceQuota) func() + // how quota was configured + quotaConfiguration quota.Configuration + // registry that knows how to measure usage for objects registry quota.Registry @@ -106,16 +110,18 @@ func newAdmissionWaiter(a admission.Attributes) *admissionWaiter { // NewQuotaEvaluator 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 NewQuotaEvaluator(quotaAccessor QuotaAccessor, registry quota.Registry, lockAcquisitionFunc func([]api.ResourceQuota) func(), config *resourcequotaapi.Configuration, workers int, stopCh <-chan struct{}) Evaluator { +func NewQuotaEvaluator(quotaAccessor QuotaAccessor, quotaConfiguration quota.Configuration, lockAcquisitionFunc func([]api.ResourceQuota) func(), config *resourcequotaapi.Configuration, workers int, stopCh <-chan struct{}) Evaluator { // if we get a nil config, just create an empty default. if config == nil { config = &resourcequotaapi.Configuration{} } + return "aEvaluator{ quotaAccessor: quotaAccessor, lockAcquisitionFunc: lockAcquisitionFunc, - registry: registry, + quotaConfiguration: quotaConfiguration, + registry: generic.NewRegistry(quotaConfiguration.Evaluators()), queue: workqueue.NewNamed("admission_quota_controller"), work: map[string][]*admissionWaiter{}, @@ -365,9 +371,8 @@ func limitedByDefault(usage api.ResourceList, limitedResources []resourcequotaap // that capture what the usage would be if the request succeeded. It return an error if there is insufficient quota to satisfy the request func (e *quotaEvaluator) checkRequest(quotas []api.ResourceQuota, a admission.Attributes) ([]api.ResourceQuota, error) { namespace := a.GetNamespace() - evaluators := e.registry.Evaluators() - evaluator, found := evaluators[a.GetKind().GroupKind()] - if !found { + evaluator := e.registry.Get(a.GetResource().GroupResource()) + if evaluator == nil { return quotas, nil } @@ -516,18 +521,27 @@ func (e *quotaEvaluator) Evaluate(a admission.Attributes) error { go e.run() }) - // if we do not know how to evaluate use for this kind, just ignore - evaluators := e.registry.Evaluators() - evaluator, found := evaluators[a.GetKind().GroupKind()] - if !found { + // is this resource ignored? + gvr := a.GetResource() + gr := gvr.GroupResource() + if _, ok := e.quotaConfiguration.IgnoredResources()[gr]; ok { return nil } + + // if we do not know how to evaluate use for this resource, create an evaluator + evaluator := e.registry.Get(gr) + if evaluator == nil { + // create an object count evaluator if no evaluator previously registered + // note, we do not need aggregate usage here, so we pass a nil infomer func + evaluator = generic.NewObjectCountEvaluator(false, gr, nil, "") + e.registry.Add(evaluator) + glog.Infof("quota admission added evaluator for: %s", gr) + } // for this kind, check if the operation could mutate any quota resources // if no resources tracked by quota are impacted, then just return if !evaluator.Handles(a) { return nil } - waiter := newAdmissionWaiter(a) e.addWork(waiter)