mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-28 14:07:14 +00:00
Update admission control framework for quota
This commit is contained in:
parent
7f88e91892
commit
5b4ca14307
@ -506,11 +506,9 @@ func BuildAdmissionPluginInitializer(s *options.ServerRunOptions, client interna
|
|||||||
// TODO: use a dynamic restmapper. See https://github.com/kubernetes/kubernetes/pull/42615.
|
// TODO: use a dynamic restmapper. See https://github.com/kubernetes/kubernetes/pull/42615.
|
||||||
restMapper := legacyscheme.Registry.RESTMapper()
|
restMapper := legacyscheme.Registry.RESTMapper()
|
||||||
|
|
||||||
// NOTE: we do not provide informers to the quota registry because admission level decisions
|
quotaConfiguration := quotainstall.NewQuotaConfigurationForAdmission()
|
||||||
// do not require us to open watches for all items tracked by quota.
|
|
||||||
quotaRegistry := quotainstall.NewRegistry(nil, nil)
|
|
||||||
|
|
||||||
pluginInitializer := kubeapiserveradmission.NewPluginInitializer(client, sharedInformers, cloudConfig, restMapper, quotaRegistry, webhookAuthWrapper, serviceResolver)
|
pluginInitializer := kubeapiserveradmission.NewPluginInitializer(client, sharedInformers, cloudConfig, restMapper, quotaConfiguration, webhookAuthWrapper, serviceResolver)
|
||||||
|
|
||||||
return pluginInitializer, nil
|
return pluginInitializer, nil
|
||||||
}
|
}
|
||||||
|
@ -53,9 +53,9 @@ type WantsRESTMapper interface {
|
|||||||
SetRESTMapper(meta.RESTMapper)
|
SetRESTMapper(meta.RESTMapper)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WantsQuotaRegistry defines a function which sets quota registry for admission plugins that need it.
|
// WantsQuotaConfiguration defines a function which sets quota configuration for admission plugins that need it.
|
||||||
type WantsQuotaRegistry interface {
|
type WantsQuotaConfiguration interface {
|
||||||
SetQuotaRegistry(quota.Registry)
|
SetQuotaConfiguration(quota.Configuration)
|
||||||
admission.Validator
|
admission.Validator
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ type PluginInitializer struct {
|
|||||||
authorizer authorizer.Authorizer
|
authorizer authorizer.Authorizer
|
||||||
cloudConfig []byte
|
cloudConfig []byte
|
||||||
restMapper meta.RESTMapper
|
restMapper meta.RESTMapper
|
||||||
quotaRegistry quota.Registry
|
quotaConfiguration quota.Configuration
|
||||||
serviceResolver webhook.ServiceResolver
|
serviceResolver webhook.ServiceResolver
|
||||||
authenticationInfoResolverWrapper webhook.AuthenticationInfoResolverWrapper
|
authenticationInfoResolverWrapper webhook.AuthenticationInfoResolverWrapper
|
||||||
}
|
}
|
||||||
@ -100,7 +100,7 @@ func NewPluginInitializer(
|
|||||||
sharedInformers informers.SharedInformerFactory,
|
sharedInformers informers.SharedInformerFactory,
|
||||||
cloudConfig []byte,
|
cloudConfig []byte,
|
||||||
restMapper meta.RESTMapper,
|
restMapper meta.RESTMapper,
|
||||||
quotaRegistry quota.Registry,
|
quotaConfiguration quota.Configuration,
|
||||||
authenticationInfoResolverWrapper webhook.AuthenticationInfoResolverWrapper,
|
authenticationInfoResolverWrapper webhook.AuthenticationInfoResolverWrapper,
|
||||||
serviceResolver webhook.ServiceResolver,
|
serviceResolver webhook.ServiceResolver,
|
||||||
) *PluginInitializer {
|
) *PluginInitializer {
|
||||||
@ -109,7 +109,7 @@ func NewPluginInitializer(
|
|||||||
informers: sharedInformers,
|
informers: sharedInformers,
|
||||||
cloudConfig: cloudConfig,
|
cloudConfig: cloudConfig,
|
||||||
restMapper: restMapper,
|
restMapper: restMapper,
|
||||||
quotaRegistry: quotaRegistry,
|
quotaConfiguration: quotaConfiguration,
|
||||||
authenticationInfoResolverWrapper: authenticationInfoResolverWrapper,
|
authenticationInfoResolverWrapper: authenticationInfoResolverWrapper,
|
||||||
serviceResolver: serviceResolver,
|
serviceResolver: serviceResolver,
|
||||||
}
|
}
|
||||||
@ -134,8 +134,8 @@ func (i *PluginInitializer) Initialize(plugin admission.Interface) {
|
|||||||
wants.SetRESTMapper(i.restMapper)
|
wants.SetRESTMapper(i.restMapper)
|
||||||
}
|
}
|
||||||
|
|
||||||
if wants, ok := plugin.(WantsQuotaRegistry); ok {
|
if wants, ok := plugin.(WantsQuotaConfiguration); ok {
|
||||||
wants.SetQuotaRegistry(i.quotaRegistry)
|
wants.SetQuotaConfiguration(i.quotaConfiguration)
|
||||||
}
|
}
|
||||||
|
|
||||||
if wants, ok := plugin.(WantsServiceResolver); ok {
|
if wants, ok := plugin.(WantsServiceResolver); ok {
|
||||||
|
@ -23,6 +23,7 @@ go_library(
|
|||||||
"//pkg/client/listers/core/internalversion:go_default_library",
|
"//pkg/client/listers/core/internalversion:go_default_library",
|
||||||
"//pkg/kubeapiserver/admission:go_default_library",
|
"//pkg/kubeapiserver/admission:go_default_library",
|
||||||
"//pkg/quota:go_default_library",
|
"//pkg/quota:go_default_library",
|
||||||
|
"//pkg/quota/generic:go_default_library",
|
||||||
"//pkg/util/reflector/prometheus:go_default_library",
|
"//pkg/util/reflector/prometheus:go_default_library",
|
||||||
"//pkg/util/workqueue/prometheus:go_default_library",
|
"//pkg/util/workqueue/prometheus:go_default_library",
|
||||||
"//plugin/pkg/admission/resourcequota/apis/resourcequota: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/clientset_generated/internalclientset/fake:go_default_library",
|
||||||
"//pkg/client/informers/informers_generated/internalversion:go_default_library",
|
"//pkg/client/informers/informers_generated/internalversion:go_default_library",
|
||||||
"//pkg/controller: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",
|
"//pkg/quota/install:go_default_library",
|
||||||
"//plugin/pkg/admission/resourcequota/apis/resourcequota:go_default_library",
|
"//plugin/pkg/admission/resourcequota/apis/resourcequota:go_default_library",
|
||||||
"//vendor/github.com/hashicorp/golang-lru: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/api/resource:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1: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/apimachinery/pkg/util/sets:go_default_library",
|
||||||
"//vendor/k8s.io/apiserver/pkg/admission:go_default_library",
|
"//vendor/k8s.io/apiserver/pkg/admission:go_default_library",
|
||||||
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
"//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||||
|
@ -53,16 +53,16 @@ func Register(plugins *admission.Plugins) {
|
|||||||
// quotaAdmission implements an admission controller that can enforce quota constraints
|
// quotaAdmission implements an admission controller that can enforce quota constraints
|
||||||
type quotaAdmission struct {
|
type quotaAdmission struct {
|
||||||
*admission.Handler
|
*admission.Handler
|
||||||
config *resourcequotaapi.Configuration
|
config *resourcequotaapi.Configuration
|
||||||
stopCh <-chan struct{}
|
stopCh <-chan struct{}
|
||||||
registry quota.Registry
|
quotaConfiguration quota.Configuration
|
||||||
numEvaluators int
|
numEvaluators int
|
||||||
quotaAccessor *quotaAccessor
|
quotaAccessor *quotaAccessor
|
||||||
evaluator Evaluator
|
evaluator Evaluator
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = kubeapiserveradmission.WantsInternalKubeClientSet("aAdmission{})
|
var _ = kubeapiserveradmission.WantsInternalKubeClientSet("aAdmission{})
|
||||||
var _ = kubeapiserveradmission.WantsQuotaRegistry("aAdmission{})
|
var _ = kubeapiserveradmission.WantsQuotaConfiguration("aAdmission{})
|
||||||
|
|
||||||
type liveLookupEntry struct {
|
type liveLookupEntry struct {
|
||||||
expiry time.Time
|
expiry time.Time
|
||||||
@ -95,9 +95,9 @@ func (a *quotaAdmission) SetInternalKubeInformerFactory(f informers.SharedInform
|
|||||||
a.quotaAccessor.lister = f.Core().InternalVersion().ResourceQuotas().Lister()
|
a.quotaAccessor.lister = f.Core().InternalVersion().ResourceQuotas().Lister()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *quotaAdmission) SetQuotaRegistry(r quota.Registry) {
|
func (a *quotaAdmission) SetQuotaConfiguration(c quota.Configuration) {
|
||||||
a.registry = r
|
a.quotaConfiguration = c
|
||||||
a.evaluator = NewQuotaEvaluator(a.quotaAccessor, a.registry, nil, a.config, a.numEvaluators, a.stopCh)
|
a.evaluator = NewQuotaEvaluator(a.quotaAccessor, a.quotaConfiguration, nil, a.config, a.numEvaluators, a.stopCh)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate ensures an authorizer is set.
|
// Validate ensures an authorizer is set.
|
||||||
@ -111,8 +111,8 @@ func (a *quotaAdmission) Validate() error {
|
|||||||
if a.quotaAccessor.lister == nil {
|
if a.quotaAccessor.lister == nil {
|
||||||
return fmt.Errorf("missing quotaAccessor.lister")
|
return fmt.Errorf("missing quotaAccessor.lister")
|
||||||
}
|
}
|
||||||
if a.registry == nil {
|
if a.quotaConfiguration == nil {
|
||||||
return fmt.Errorf("missing registry")
|
return fmt.Errorf("missing quotaConfiguration")
|
||||||
}
|
}
|
||||||
if a.evaluator == nil {
|
if a.evaluator == nil {
|
||||||
return fmt.Errorf("missing evaluator")
|
return fmt.Errorf("missing evaluator")
|
||||||
@ -126,5 +126,9 @@ func (a *quotaAdmission) Admit(attr admission.Attributes) (err error) {
|
|||||||
if attr.GetSubresource() != "" {
|
if attr.GetSubresource() != "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
// ignore all operations that are not namespaced
|
||||||
|
if attr.GetNamespace() == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return a.evaluator.Evaluate(attr)
|
return a.evaluator.Evaluate(attr)
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,6 @@ import (
|
|||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
@ -36,8 +35,6 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
|
||||||
informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
|
informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
|
||||||
"k8s.io/kubernetes/pkg/controller"
|
"k8s.io/kubernetes/pkg/controller"
|
||||||
"k8s.io/kubernetes/pkg/quota"
|
|
||||||
"k8s.io/kubernetes/pkg/quota/generic"
|
|
||||||
"k8s.io/kubernetes/pkg/quota/install"
|
"k8s.io/kubernetes/pkg/quota/install"
|
||||||
resourcequotaapi "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota"
|
resourcequotaapi "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota"
|
||||||
)
|
)
|
||||||
@ -135,7 +132,8 @@ func TestAdmissionIgnoresDelete(t *testing.T) {
|
|||||||
quotaAccessor.client = kubeClient
|
quotaAccessor.client = kubeClient
|
||||||
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
||||||
config := &resourcequotaapi.Configuration{}
|
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 := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
Handler: admission.NewHandler(admission.Create, admission.Update),
|
||||||
@ -170,7 +168,8 @@ func TestAdmissionIgnoresSubresources(t *testing.T) {
|
|||||||
quotaAccessor.client = kubeClient
|
quotaAccessor.client = kubeClient
|
||||||
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
||||||
config := &resourcequotaapi.Configuration{}
|
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 := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
Handler: admission.NewHandler(admission.Create, admission.Update),
|
||||||
@ -214,7 +213,8 @@ func TestAdmitBelowQuotaLimit(t *testing.T) {
|
|||||||
quotaAccessor.client = kubeClient
|
quotaAccessor.client = kubeClient
|
||||||
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
||||||
config := &resourcequotaapi.Configuration{}
|
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 := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
Handler: admission.NewHandler(admission.Create, admission.Update),
|
||||||
@ -297,7 +297,8 @@ func TestAdmitHandlesOldObjects(t *testing.T) {
|
|||||||
quotaAccessor.client = kubeClient
|
quotaAccessor.client = kubeClient
|
||||||
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
||||||
config := &resourcequotaapi.Configuration{}
|
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 := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
Handler: admission.NewHandler(admission.Create, admission.Update),
|
||||||
@ -403,7 +404,8 @@ func TestAdmitHandlesNegativePVCUpdates(t *testing.T) {
|
|||||||
quotaAccessor.client = kubeClient
|
quotaAccessor.client = kubeClient
|
||||||
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
||||||
config := &resourcequotaapi.Configuration{}
|
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 := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
Handler: admission.NewHandler(admission.Create, admission.Update),
|
||||||
@ -469,7 +471,8 @@ func TestAdmitHandlesPVCUpdates(t *testing.T) {
|
|||||||
quotaAccessor.client = kubeClient
|
quotaAccessor.client = kubeClient
|
||||||
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
||||||
config := &resourcequotaapi.Configuration{}
|
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 := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
Handler: admission.NewHandler(admission.Create, admission.Update),
|
||||||
@ -567,7 +570,8 @@ func TestAdmitHandlesCreatingUpdates(t *testing.T) {
|
|||||||
quotaAccessor.client = kubeClient
|
quotaAccessor.client = kubeClient
|
||||||
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
||||||
config := &resourcequotaapi.Configuration{}
|
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 := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
Handler: admission.NewHandler(admission.Create, admission.Update),
|
||||||
@ -661,7 +665,8 @@ func TestAdmitExceedQuotaLimit(t *testing.T) {
|
|||||||
quotaAccessor.client = kubeClient
|
quotaAccessor.client = kubeClient
|
||||||
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
||||||
config := &resourcequotaapi.Configuration{}
|
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 := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
Handler: admission.NewHandler(admission.Create, admission.Update),
|
||||||
@ -705,7 +710,8 @@ func TestAdmitEnforceQuotaConstraints(t *testing.T) {
|
|||||||
quotaAccessor.client = kubeClient
|
quotaAccessor.client = kubeClient
|
||||||
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
||||||
config := &resourcequotaapi.Configuration{}
|
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 := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
Handler: admission.NewHandler(admission.Create, admission.Update),
|
||||||
@ -759,7 +765,8 @@ func TestAdmitPodInNamespaceWithoutQuota(t *testing.T) {
|
|||||||
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
||||||
quotaAccessor.liveLookupCache = liveLookupCache
|
quotaAccessor.liveLookupCache = liveLookupCache
|
||||||
config := &resourcequotaapi.Configuration{}
|
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 := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
Handler: admission.NewHandler(admission.Create, admission.Update),
|
||||||
@ -825,7 +832,8 @@ func TestAdmitBelowTerminatingQuotaLimit(t *testing.T) {
|
|||||||
quotaAccessor.client = kubeClient
|
quotaAccessor.client = kubeClient
|
||||||
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
||||||
config := &resourcequotaapi.Configuration{}
|
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 := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
Handler: admission.NewHandler(admission.Create, admission.Update),
|
||||||
@ -930,7 +938,8 @@ func TestAdmitBelowBestEffortQuotaLimit(t *testing.T) {
|
|||||||
quotaAccessor.client = kubeClient
|
quotaAccessor.client = kubeClient
|
||||||
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
||||||
config := &resourcequotaapi.Configuration{}
|
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 := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
Handler: admission.NewHandler(admission.Create, admission.Update),
|
||||||
@ -1022,7 +1031,8 @@ func TestAdmitBestEffortQuotaLimitIgnoresBurstable(t *testing.T) {
|
|||||||
quotaAccessor.client = kubeClient
|
quotaAccessor.client = kubeClient
|
||||||
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
||||||
config := &resourcequotaapi.Configuration{}
|
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 := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
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{})
|
stopCh := make(chan struct{})
|
||||||
defer close(stopCh)
|
defer close(stopCh)
|
||||||
|
|
||||||
@ -1118,8 +1117,8 @@ func TestAdmissionSetsMissingNamespace(t *testing.T) {
|
|||||||
quotaAccessor.client = kubeClient
|
quotaAccessor.client = kubeClient
|
||||||
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
||||||
config := &resourcequotaapi.Configuration{}
|
config := &resourcequotaapi.Configuration{}
|
||||||
evaluator := NewQuotaEvaluator(quotaAccessor, install.NewRegistry(nil, nil), nil, config, 5, stopCh)
|
quotaConfiguration := install.NewQuotaConfigurationForAdmission()
|
||||||
evaluator.(*quotaEvaluator).registry = registry
|
evaluator := NewQuotaEvaluator(quotaAccessor, quotaConfiguration, nil, config, 5, stopCh)
|
||||||
|
|
||||||
handler := "aAdmission{
|
handler := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
Handler: admission.NewHandler(admission.Create, admission.Update),
|
||||||
@ -1164,7 +1163,8 @@ func TestAdmitRejectsNegativeUsage(t *testing.T) {
|
|||||||
quotaAccessor.client = kubeClient
|
quotaAccessor.client = kubeClient
|
||||||
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
||||||
config := &resourcequotaapi.Configuration{}
|
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 := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
Handler: admission.NewHandler(admission.Create, admission.Update),
|
||||||
@ -1210,7 +1210,8 @@ func TestAdmitWhenUnrelatedResourceExceedsQuota(t *testing.T) {
|
|||||||
quotaAccessor.client = kubeClient
|
quotaAccessor.client = kubeClient
|
||||||
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
quotaAccessor.lister = informerFactory.Core().InternalVersion().ResourceQuotas().Lister()
|
||||||
config := &resourcequotaapi.Configuration{}
|
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 := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
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 := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
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 := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
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 := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
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 := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
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 := "aAdmission{
|
||||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
Handler: admission.NewHandler(admission.Create, admission.Update),
|
||||||
|
@ -34,6 +34,7 @@ import (
|
|||||||
"k8s.io/client-go/util/workqueue"
|
"k8s.io/client-go/util/workqueue"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/quota"
|
"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/reflector/prometheus" // for reflector metric registration
|
||||||
_ "k8s.io/kubernetes/pkg/util/workqueue/prometheus" // for workqueue metric registration
|
_ "k8s.io/kubernetes/pkg/util/workqueue/prometheus" // for workqueue metric registration
|
||||||
resourcequotaapi "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota"
|
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 acquires any required locks and returns a cleanup method to defer
|
||||||
lockAcquisitionFunc func([]api.ResourceQuota) func()
|
lockAcquisitionFunc func([]api.ResourceQuota) func()
|
||||||
|
|
||||||
|
// how quota was configured
|
||||||
|
quotaConfiguration quota.Configuration
|
||||||
|
|
||||||
// registry that knows how to measure usage for objects
|
// registry that knows how to measure usage for objects
|
||||||
registry quota.Registry
|
registry quota.Registry
|
||||||
|
|
||||||
@ -106,16 +110,18 @@ func newAdmissionWaiter(a admission.Attributes) *admissionWaiter {
|
|||||||
// NewQuotaEvaluator configures an admission controller that can enforce quota constraints
|
// 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
|
// 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
|
// 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 we get a nil config, just create an empty default.
|
||||||
if config == nil {
|
if config == nil {
|
||||||
config = &resourcequotaapi.Configuration{}
|
config = &resourcequotaapi.Configuration{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "aEvaluator{
|
return "aEvaluator{
|
||||||
quotaAccessor: quotaAccessor,
|
quotaAccessor: quotaAccessor,
|
||||||
lockAcquisitionFunc: lockAcquisitionFunc,
|
lockAcquisitionFunc: lockAcquisitionFunc,
|
||||||
|
|
||||||
registry: registry,
|
quotaConfiguration: quotaConfiguration,
|
||||||
|
registry: generic.NewRegistry(quotaConfiguration.Evaluators()),
|
||||||
|
|
||||||
queue: workqueue.NewNamed("admission_quota_controller"),
|
queue: workqueue.NewNamed("admission_quota_controller"),
|
||||||
work: map[string][]*admissionWaiter{},
|
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
|
// 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) {
|
func (e *quotaEvaluator) checkRequest(quotas []api.ResourceQuota, a admission.Attributes) ([]api.ResourceQuota, error) {
|
||||||
namespace := a.GetNamespace()
|
namespace := a.GetNamespace()
|
||||||
evaluators := e.registry.Evaluators()
|
evaluator := e.registry.Get(a.GetResource().GroupResource())
|
||||||
evaluator, found := evaluators[a.GetKind().GroupKind()]
|
if evaluator == nil {
|
||||||
if !found {
|
|
||||||
return quotas, nil
|
return quotas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,18 +521,27 @@ func (e *quotaEvaluator) Evaluate(a admission.Attributes) error {
|
|||||||
go e.run()
|
go e.run()
|
||||||
})
|
})
|
||||||
|
|
||||||
// if we do not know how to evaluate use for this kind, just ignore
|
// is this resource ignored?
|
||||||
evaluators := e.registry.Evaluators()
|
gvr := a.GetResource()
|
||||||
evaluator, found := evaluators[a.GetKind().GroupKind()]
|
gr := gvr.GroupResource()
|
||||||
if !found {
|
if _, ok := e.quotaConfiguration.IgnoredResources()[gr]; ok {
|
||||||
return nil
|
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
|
// for this kind, check if the operation could mutate any quota resources
|
||||||
// if no resources tracked by quota are impacted, then just return
|
// if no resources tracked by quota are impacted, then just return
|
||||||
if !evaluator.Handles(a) {
|
if !evaluator.Handles(a) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
waiter := newAdmissionWaiter(a)
|
waiter := newAdmissionWaiter(a)
|
||||||
|
|
||||||
e.addWork(waiter)
|
e.addWork(waiter)
|
||||||
|
Loading…
Reference in New Issue
Block a user