mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 13:37:30 +00:00
use informers for quota evaluation of core resources where possible
This commit is contained in:
parent
c9ab810803
commit
bbd291faa7
@ -17,21 +17,22 @@ limitations under the License.
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/client-go/informers"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
"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/quota/generic"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewConfigMapEvaluator returns an evaluator that can evaluate configMaps
|
// listConfigMapsByNamespaceFuncUsingClient returns a configMap listing function based on the provided client.
|
||||||
func NewConfigMapEvaluator(kubeClient clientset.Interface) quota.Evaluator {
|
func listConfigMapsByNamespaceFuncUsingClient(kubeClient clientset.Interface) generic.ListFuncByNamespace {
|
||||||
return &generic.ObjectCountEvaluator{
|
// TODO: ideally, we could pass dynamic client pool down into this code, and have one way of doing this.
|
||||||
AllowCreateOnUpdate: false,
|
// unfortunately, dynamic client works with Unstructured objects, and when we calculate Usage, we require
|
||||||
InternalGroupKind: api.Kind("ConfigMap"),
|
// structured objects.
|
||||||
ResourceName: api.ResourceConfigMaps,
|
return func(namespace string, options metav1.ListOptions) ([]runtime.Object, error) {
|
||||||
ListFuncByNamespace: func(namespace string, options metav1.ListOptions) ([]runtime.Object, error) {
|
|
||||||
itemList, err := kubeClient.Core().ConfigMaps(namespace).List(options)
|
itemList, err := kubeClient.Core().ConfigMaps(namespace).List(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -41,6 +42,20 @@ func NewConfigMapEvaluator(kubeClient clientset.Interface) quota.Evaluator {
|
|||||||
results = append(results, &itemList.Items[i])
|
results = append(results, &itemList.Items[i])
|
||||||
}
|
}
|
||||||
return results, nil
|
return results, nil
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewConfigMapEvaluator returns an evaluator that can evaluate configMaps
|
||||||
|
// if the specified shared informer factory is not nil, evaluator may use it to support listing functions.
|
||||||
|
func NewConfigMapEvaluator(kubeClient clientset.Interface, f informers.SharedInformerFactory) quota.Evaluator {
|
||||||
|
listFuncByNamespace := listConfigMapsByNamespaceFuncUsingClient(kubeClient)
|
||||||
|
if f != nil {
|
||||||
|
listFuncByNamespace = generic.ListResourceUsingInformerFunc(f, v1.SchemeGroupVersion.WithResource("configmaps"))
|
||||||
|
}
|
||||||
|
return &generic.ObjectCountEvaluator{
|
||||||
|
AllowCreateOnUpdate: false,
|
||||||
|
InternalGroupKind: api.Kind("ConfigMap"),
|
||||||
|
ResourceName: api.ResourceConfigMaps,
|
||||||
|
ListFuncByNamespace: listFuncByNamespace,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,11 +28,11 @@ import (
|
|||||||
// If an informer factory is provided, evaluators will use them.
|
// If an informer factory is provided, evaluators will use them.
|
||||||
func NewRegistry(kubeClient clientset.Interface, f informers.SharedInformerFactory) quota.Registry {
|
func NewRegistry(kubeClient clientset.Interface, f informers.SharedInformerFactory) quota.Registry {
|
||||||
pod := NewPodEvaluator(kubeClient, f)
|
pod := NewPodEvaluator(kubeClient, f)
|
||||||
service := NewServiceEvaluator(kubeClient)
|
service := NewServiceEvaluator(kubeClient, f)
|
||||||
replicationController := NewReplicationControllerEvaluator(kubeClient)
|
replicationController := NewReplicationControllerEvaluator(kubeClient, f)
|
||||||
resourceQuota := NewResourceQuotaEvaluator(kubeClient)
|
resourceQuota := NewResourceQuotaEvaluator(kubeClient, f)
|
||||||
secret := NewSecretEvaluator(kubeClient)
|
secret := NewSecretEvaluator(kubeClient, f)
|
||||||
configMap := NewConfigMapEvaluator(kubeClient)
|
configMap := NewConfigMapEvaluator(kubeClient, f)
|
||||||
persistentVolumeClaim := NewPersistentVolumeClaimEvaluator(kubeClient, f)
|
persistentVolumeClaim := NewPersistentVolumeClaimEvaluator(kubeClient, f)
|
||||||
return &generic.GenericRegistry{
|
return &generic.GenericRegistry{
|
||||||
InternalEvaluators: map[schema.GroupKind]quota.Evaluator{
|
InternalEvaluators: map[schema.GroupKind]quota.Evaluator{
|
||||||
|
@ -17,21 +17,22 @@ limitations under the License.
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/client-go/informers"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
"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/quota/generic"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewReplicationControllerEvaluator returns an evaluator that can evaluate replication controllers
|
// listReplicationControllersByNamespaceFuncUsingClient returns a replicationController listing function based on the provided client.
|
||||||
func NewReplicationControllerEvaluator(kubeClient clientset.Interface) quota.Evaluator {
|
func listReplicationControllersByNamespaceFuncUsingClient(kubeClient clientset.Interface) generic.ListFuncByNamespace {
|
||||||
return &generic.ObjectCountEvaluator{
|
// TODO: ideally, we could pass dynamic client pool down into this code, and have one way of doing this.
|
||||||
AllowCreateOnUpdate: false,
|
// unfortunately, dynamic client works with Unstructured objects, and when we calculate Usage, we require
|
||||||
InternalGroupKind: api.Kind("ReplicationController"),
|
// structured objects.
|
||||||
ResourceName: api.ResourceReplicationControllers,
|
return func(namespace string, options metav1.ListOptions) ([]runtime.Object, error) {
|
||||||
ListFuncByNamespace: func(namespace string, options metav1.ListOptions) ([]runtime.Object, error) {
|
|
||||||
itemList, err := kubeClient.Core().ReplicationControllers(namespace).List(options)
|
itemList, err := kubeClient.Core().ReplicationControllers(namespace).List(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -41,6 +42,20 @@ func NewReplicationControllerEvaluator(kubeClient clientset.Interface) quota.Eva
|
|||||||
results = append(results, &itemList.Items[i])
|
results = append(results, &itemList.Items[i])
|
||||||
}
|
}
|
||||||
return results, nil
|
return results, nil
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewReplicationControllerEvaluator returns an evaluator that can evaluate replicationControllers
|
||||||
|
// if the specified shared informer factory is not nil, evaluator may use it to support listing functions.
|
||||||
|
func NewReplicationControllerEvaluator(kubeClient clientset.Interface, f informers.SharedInformerFactory) quota.Evaluator {
|
||||||
|
listFuncByNamespace := listReplicationControllersByNamespaceFuncUsingClient(kubeClient)
|
||||||
|
if f != nil {
|
||||||
|
listFuncByNamespace = generic.ListResourceUsingInformerFunc(f, v1.SchemeGroupVersion.WithResource("replicationcontrollers"))
|
||||||
|
}
|
||||||
|
return &generic.ObjectCountEvaluator{
|
||||||
|
AllowCreateOnUpdate: false,
|
||||||
|
InternalGroupKind: api.Kind("ReplicationController"),
|
||||||
|
ResourceName: api.ResourceReplicationControllers,
|
||||||
|
ListFuncByNamespace: listFuncByNamespace,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,21 +17,22 @@ limitations under the License.
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/client-go/informers"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
"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/quota/generic"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewResourceQuotaEvaluator returns an evaluator that can evaluate resource quotas
|
// listResourceQuotasByNamespaceFuncUsingClient returns a resourceQuota listing function based on the provided client.
|
||||||
func NewResourceQuotaEvaluator(kubeClient clientset.Interface) quota.Evaluator {
|
func listResourceQuotasByNamespaceFuncUsingClient(kubeClient clientset.Interface) generic.ListFuncByNamespace {
|
||||||
return &generic.ObjectCountEvaluator{
|
// TODO: ideally, we could pass dynamic client pool down into this code, and have one way of doing this.
|
||||||
AllowCreateOnUpdate: false,
|
// unfortunately, dynamic client works with Unstructured objects, and when we calculate Usage, we require
|
||||||
InternalGroupKind: api.Kind("ResourceQuota"),
|
// structured objects.
|
||||||
ResourceName: api.ResourceQuotas,
|
return func(namespace string, options metav1.ListOptions) ([]runtime.Object, error) {
|
||||||
ListFuncByNamespace: func(namespace string, options metav1.ListOptions) ([]runtime.Object, error) {
|
|
||||||
itemList, err := kubeClient.Core().ResourceQuotas(namespace).List(options)
|
itemList, err := kubeClient.Core().ResourceQuotas(namespace).List(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -41,6 +42,20 @@ func NewResourceQuotaEvaluator(kubeClient clientset.Interface) quota.Evaluator {
|
|||||||
results = append(results, &itemList.Items[i])
|
results = append(results, &itemList.Items[i])
|
||||||
}
|
}
|
||||||
return results, nil
|
return results, nil
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewResourceQuotaEvaluator returns an evaluator that can evaluate resourceQuotas
|
||||||
|
// if the specified shared informer factory is not nil, evaluator may use it to support listing functions.
|
||||||
|
func NewResourceQuotaEvaluator(kubeClient clientset.Interface, f informers.SharedInformerFactory) quota.Evaluator {
|
||||||
|
listFuncByNamespace := listResourceQuotasByNamespaceFuncUsingClient(kubeClient)
|
||||||
|
if f != nil {
|
||||||
|
listFuncByNamespace = generic.ListResourceUsingInformerFunc(f, v1.SchemeGroupVersion.WithResource("resourcequotas"))
|
||||||
|
}
|
||||||
|
return &generic.ObjectCountEvaluator{
|
||||||
|
AllowCreateOnUpdate: false,
|
||||||
|
InternalGroupKind: api.Kind("ResourceQuota"),
|
||||||
|
ResourceName: api.ResourceQuotas,
|
||||||
|
ListFuncByNamespace: listFuncByNamespace,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,21 +17,22 @@ limitations under the License.
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/client-go/informers"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
"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/quota/generic"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewSecretEvaluator returns an evaluator that can evaluate secrets
|
// listSecretsByNamespaceFuncUsingClient returns a secret listing function based on the provided client.
|
||||||
func NewSecretEvaluator(kubeClient clientset.Interface) quota.Evaluator {
|
func listSecretsByNamespaceFuncUsingClient(kubeClient clientset.Interface) generic.ListFuncByNamespace {
|
||||||
return &generic.ObjectCountEvaluator{
|
// TODO: ideally, we could pass dynamic client pool down into this code, and have one way of doing this.
|
||||||
AllowCreateOnUpdate: false,
|
// unfortunately, dynamic client works with Unstructured objects, and when we calculate Usage, we require
|
||||||
InternalGroupKind: api.Kind("Secret"),
|
// structured objects.
|
||||||
ResourceName: api.ResourceSecrets,
|
return func(namespace string, options metav1.ListOptions) ([]runtime.Object, error) {
|
||||||
ListFuncByNamespace: func(namespace string, options metav1.ListOptions) ([]runtime.Object, error) {
|
|
||||||
itemList, err := kubeClient.Core().Secrets(namespace).List(options)
|
itemList, err := kubeClient.Core().Secrets(namespace).List(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -41,6 +42,20 @@ func NewSecretEvaluator(kubeClient clientset.Interface) quota.Evaluator {
|
|||||||
results = append(results, &itemList.Items[i])
|
results = append(results, &itemList.Items[i])
|
||||||
}
|
}
|
||||||
return results, nil
|
return results, nil
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSecretEvaluator returns an evaluator that can evaluate secrets
|
||||||
|
// if the specified shared informer factory is not nil, evaluator may use it to support listing functions.
|
||||||
|
func NewSecretEvaluator(kubeClient clientset.Interface, f informers.SharedInformerFactory) quota.Evaluator {
|
||||||
|
listFuncByNamespace := listSecretsByNamespaceFuncUsingClient(kubeClient)
|
||||||
|
if f != nil {
|
||||||
|
listFuncByNamespace = generic.ListResourceUsingInformerFunc(f, v1.SchemeGroupVersion.WithResource("secrets"))
|
||||||
|
}
|
||||||
|
return &generic.ObjectCountEvaluator{
|
||||||
|
AllowCreateOnUpdate: false,
|
||||||
|
InternalGroupKind: api.Kind("Secret"),
|
||||||
|
ResourceName: api.ResourceSecrets,
|
||||||
|
ListFuncByNamespace: listFuncByNamespace,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"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"
|
||||||
|
"k8s.io/client-go/informers"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
k8s_api_v1 "k8s.io/kubernetes/pkg/api/v1"
|
k8s_api_v1 "k8s.io/kubernetes/pkg/api/v1"
|
||||||
@ -41,10 +42,12 @@ var serviceResources = []api.ResourceName{
|
|||||||
api.ResourceServicesLoadBalancers,
|
api.ResourceServicesLoadBalancers,
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewServiceEvaluator returns an evaluator that can evaluate service quotas
|
// listServicesByNamespaceFuncUsingClient returns a service listing function based on the provided client.
|
||||||
func NewServiceEvaluator(kubeClient clientset.Interface) quota.Evaluator {
|
func listServicesByNamespaceFuncUsingClient(kubeClient clientset.Interface) generic.ListFuncByNamespace {
|
||||||
return &serviceEvaluator{
|
// TODO: ideally, we could pass dynamic client pool down into this code, and have one way of doing this.
|
||||||
listFuncByNamespace: func(namespace string, options metav1.ListOptions) ([]runtime.Object, error) {
|
// unfortunately, dynamic client works with Unstructured objects, and when we calculate Usage, we require
|
||||||
|
// structured objects.
|
||||||
|
return func(namespace string, options metav1.ListOptions) ([]runtime.Object, error) {
|
||||||
itemList, err := kubeClient.Core().Services(namespace).List(options)
|
itemList, err := kubeClient.Core().Services(namespace).List(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -54,7 +57,18 @@ func NewServiceEvaluator(kubeClient clientset.Interface) quota.Evaluator {
|
|||||||
results = append(results, &itemList.Items[i])
|
results = append(results, &itemList.Items[i])
|
||||||
}
|
}
|
||||||
return results, nil
|
return results, nil
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServiceEvaluator returns an evaluator that can evaluate services
|
||||||
|
// if the specified shared informer factory is not nil, evaluator may use it to support listing functions.
|
||||||
|
func NewServiceEvaluator(kubeClient clientset.Interface, f informers.SharedInformerFactory) quota.Evaluator {
|
||||||
|
listFuncByNamespace := listServicesByNamespaceFuncUsingClient(kubeClient)
|
||||||
|
if f != nil {
|
||||||
|
listFuncByNamespace = generic.ListResourceUsingInformerFunc(f, v1.SchemeGroupVersion.WithResource("services"))
|
||||||
|
}
|
||||||
|
return &serviceEvaluator{
|
||||||
|
listFuncByNamespace: listFuncByNamespace,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,7 +139,7 @@ func toInternalServiceOrError(obj runtime.Object) (*api.Service, error) {
|
|||||||
return svc, nil
|
return svc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Usage knows how to measure usage associated with pods
|
// Usage knows how to measure usage associated with services
|
||||||
func (p *serviceEvaluator) Usage(item runtime.Object) (api.ResourceList, error) {
|
func (p *serviceEvaluator) Usage(item runtime.Object) (api.ResourceList, error) {
|
||||||
result := api.ResourceList{}
|
result := api.ResourceList{}
|
||||||
svc, err := toInternalServiceOrError(item)
|
svc, err := toInternalServiceOrError(item)
|
||||||
|
@ -27,7 +27,7 @@ import (
|
|||||||
|
|
||||||
func TestServiceEvaluatorMatchesResources(t *testing.T) {
|
func TestServiceEvaluatorMatchesResources(t *testing.T) {
|
||||||
kubeClient := fake.NewSimpleClientset()
|
kubeClient := fake.NewSimpleClientset()
|
||||||
evaluator := NewServiceEvaluator(kubeClient)
|
evaluator := NewServiceEvaluator(kubeClient, nil)
|
||||||
// we give a lot of resources
|
// we give a lot of resources
|
||||||
input := []api.ResourceName{
|
input := []api.ResourceName{
|
||||||
api.ResourceConfigMaps,
|
api.ResourceConfigMaps,
|
||||||
@ -50,7 +50,7 @@ func TestServiceEvaluatorMatchesResources(t *testing.T) {
|
|||||||
|
|
||||||
func TestServiceEvaluatorUsage(t *testing.T) {
|
func TestServiceEvaluatorUsage(t *testing.T) {
|
||||||
kubeClient := fake.NewSimpleClientset()
|
kubeClient := fake.NewSimpleClientset()
|
||||||
evaluator := NewServiceEvaluator(kubeClient)
|
evaluator := NewServiceEvaluator(kubeClient, nil)
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
service *api.Service
|
service *api.Service
|
||||||
usage api.ResourceList
|
usage api.ResourceList
|
||||||
@ -199,7 +199,7 @@ func TestServiceConstraintsFunc(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
kubeClient := fake.NewSimpleClientset()
|
kubeClient := fake.NewSimpleClientset()
|
||||||
evaluator := NewServiceEvaluator(kubeClient)
|
evaluator := NewServiceEvaluator(kubeClient, nil)
|
||||||
for testName, test := range testCases {
|
for testName, test := range testCases {
|
||||||
err := evaluator.Constraints(test.required, test.service)
|
err := evaluator.Constraints(test.required, test.service)
|
||||||
switch {
|
switch {
|
||||||
|
Loading…
Reference in New Issue
Block a user