mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 12:43:23 +00:00
use informers for quota evaluation of core resources where possible
This commit is contained in:
parent
c9ab810803
commit
bbd291faa7
@ -17,30 +17,45 @@ limitations under the License.
|
||||
package core
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/informers"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/quota"
|
||||
"k8s.io/kubernetes/pkg/quota/generic"
|
||||
)
|
||||
|
||||
// listConfigMapsByNamespaceFuncUsingClient returns a configMap listing function based on the provided client.
|
||||
func listConfigMapsByNamespaceFuncUsingClient(kubeClient clientset.Interface) generic.ListFuncByNamespace {
|
||||
// TODO: ideally, we could pass dynamic client pool down into this code, and have one way of doing this.
|
||||
// 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().ConfigMaps(namespace).List(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results := make([]runtime.Object, 0, len(itemList.Items))
|
||||
for i := range itemList.Items {
|
||||
results = append(results, &itemList.Items[i])
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
}
|
||||
|
||||
// NewConfigMapEvaluator returns an evaluator that can evaluate configMaps
|
||||
func NewConfigMapEvaluator(kubeClient clientset.Interface) quota.Evaluator {
|
||||
// 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: func(namespace string, options metav1.ListOptions) ([]runtime.Object, error) {
|
||||
itemList, err := kubeClient.Core().ConfigMaps(namespace).List(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results := make([]runtime.Object, 0, len(itemList.Items))
|
||||
for i := range itemList.Items {
|
||||
results = append(results, &itemList.Items[i])
|
||||
}
|
||||
return results, nil
|
||||
},
|
||||
ListFuncByNamespace: listFuncByNamespace,
|
||||
}
|
||||
}
|
||||
|
@ -28,11 +28,11 @@ import (
|
||||
// If an informer factory is provided, evaluators will use them.
|
||||
func NewRegistry(kubeClient clientset.Interface, f informers.SharedInformerFactory) quota.Registry {
|
||||
pod := NewPodEvaluator(kubeClient, f)
|
||||
service := NewServiceEvaluator(kubeClient)
|
||||
replicationController := NewReplicationControllerEvaluator(kubeClient)
|
||||
resourceQuota := NewResourceQuotaEvaluator(kubeClient)
|
||||
secret := NewSecretEvaluator(kubeClient)
|
||||
configMap := NewConfigMapEvaluator(kubeClient)
|
||||
service := NewServiceEvaluator(kubeClient, f)
|
||||
replicationController := NewReplicationControllerEvaluator(kubeClient, f)
|
||||
resourceQuota := NewResourceQuotaEvaluator(kubeClient, f)
|
||||
secret := NewSecretEvaluator(kubeClient, f)
|
||||
configMap := NewConfigMapEvaluator(kubeClient, f)
|
||||
persistentVolumeClaim := NewPersistentVolumeClaimEvaluator(kubeClient, f)
|
||||
return &generic.GenericRegistry{
|
||||
InternalEvaluators: map[schema.GroupKind]quota.Evaluator{
|
||||
|
@ -17,30 +17,45 @@ limitations under the License.
|
||||
package core
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/informers"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/quota"
|
||||
"k8s.io/kubernetes/pkg/quota/generic"
|
||||
)
|
||||
|
||||
// NewReplicationControllerEvaluator returns an evaluator that can evaluate replication controllers
|
||||
func NewReplicationControllerEvaluator(kubeClient clientset.Interface) quota.Evaluator {
|
||||
// listReplicationControllersByNamespaceFuncUsingClient returns a replicationController listing function based on the provided client.
|
||||
func listReplicationControllersByNamespaceFuncUsingClient(kubeClient clientset.Interface) generic.ListFuncByNamespace {
|
||||
// TODO: ideally, we could pass dynamic client pool down into this code, and have one way of doing this.
|
||||
// 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().ReplicationControllers(namespace).List(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results := make([]runtime.Object, 0, len(itemList.Items))
|
||||
for i := range itemList.Items {
|
||||
results = append(results, &itemList.Items[i])
|
||||
}
|
||||
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: func(namespace string, options metav1.ListOptions) ([]runtime.Object, error) {
|
||||
itemList, err := kubeClient.Core().ReplicationControllers(namespace).List(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results := make([]runtime.Object, 0, len(itemList.Items))
|
||||
for i := range itemList.Items {
|
||||
results = append(results, &itemList.Items[i])
|
||||
}
|
||||
return results, nil
|
||||
},
|
||||
ListFuncByNamespace: listFuncByNamespace,
|
||||
}
|
||||
}
|
||||
|
@ -17,30 +17,45 @@ limitations under the License.
|
||||
package core
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/informers"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/quota"
|
||||
"k8s.io/kubernetes/pkg/quota/generic"
|
||||
)
|
||||
|
||||
// NewResourceQuotaEvaluator returns an evaluator that can evaluate resource quotas
|
||||
func NewResourceQuotaEvaluator(kubeClient clientset.Interface) quota.Evaluator {
|
||||
// listResourceQuotasByNamespaceFuncUsingClient returns a resourceQuota listing function based on the provided client.
|
||||
func listResourceQuotasByNamespaceFuncUsingClient(kubeClient clientset.Interface) generic.ListFuncByNamespace {
|
||||
// TODO: ideally, we could pass dynamic client pool down into this code, and have one way of doing this.
|
||||
// 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().ResourceQuotas(namespace).List(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results := make([]runtime.Object, 0, len(itemList.Items))
|
||||
for i := range itemList.Items {
|
||||
results = append(results, &itemList.Items[i])
|
||||
}
|
||||
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: func(namespace string, options metav1.ListOptions) ([]runtime.Object, error) {
|
||||
itemList, err := kubeClient.Core().ResourceQuotas(namespace).List(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results := make([]runtime.Object, 0, len(itemList.Items))
|
||||
for i := range itemList.Items {
|
||||
results = append(results, &itemList.Items[i])
|
||||
}
|
||||
return results, nil
|
||||
},
|
||||
ListFuncByNamespace: listFuncByNamespace,
|
||||
}
|
||||
}
|
||||
|
@ -17,30 +17,45 @@ limitations under the License.
|
||||
package core
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/informers"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/quota"
|
||||
"k8s.io/kubernetes/pkg/quota/generic"
|
||||
)
|
||||
|
||||
// listSecretsByNamespaceFuncUsingClient returns a secret listing function based on the provided client.
|
||||
func listSecretsByNamespaceFuncUsingClient(kubeClient clientset.Interface) generic.ListFuncByNamespace {
|
||||
// TODO: ideally, we could pass dynamic client pool down into this code, and have one way of doing this.
|
||||
// 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().Secrets(namespace).List(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results := make([]runtime.Object, 0, len(itemList.Items))
|
||||
for i := range itemList.Items {
|
||||
results = append(results, &itemList.Items[i])
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
}
|
||||
|
||||
// NewSecretEvaluator returns an evaluator that can evaluate secrets
|
||||
func NewSecretEvaluator(kubeClient clientset.Interface) quota.Evaluator {
|
||||
// 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: func(namespace string, options metav1.ListOptions) ([]runtime.Object, error) {
|
||||
itemList, err := kubeClient.Core().Secrets(namespace).List(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results := make([]runtime.Object, 0, len(itemList.Items))
|
||||
for i := range itemList.Items {
|
||||
results = append(results, &itemList.Items[i])
|
||||
}
|
||||
return results, nil
|
||||
},
|
||||
ListFuncByNamespace: listFuncByNamespace,
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
"k8s.io/client-go/informers"
|
||||
clientset "k8s.io/client-go/kubernetes"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
k8s_api_v1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
@ -41,20 +42,33 @@ var serviceResources = []api.ResourceName{
|
||||
api.ResourceServicesLoadBalancers,
|
||||
}
|
||||
|
||||
// NewServiceEvaluator returns an evaluator that can evaluate service quotas
|
||||
func NewServiceEvaluator(kubeClient clientset.Interface) quota.Evaluator {
|
||||
// listServicesByNamespaceFuncUsingClient returns a service listing function based on the provided client.
|
||||
func listServicesByNamespaceFuncUsingClient(kubeClient clientset.Interface) generic.ListFuncByNamespace {
|
||||
// TODO: ideally, we could pass dynamic client pool down into this code, and have one way of doing this.
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results := make([]runtime.Object, 0, len(itemList.Items))
|
||||
for i := range itemList.Items {
|
||||
results = append(results, &itemList.Items[i])
|
||||
}
|
||||
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: func(namespace string, options metav1.ListOptions) ([]runtime.Object, error) {
|
||||
itemList, err := kubeClient.Core().Services(namespace).List(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
results := make([]runtime.Object, 0, len(itemList.Items))
|
||||
for i := range itemList.Items {
|
||||
results = append(results, &itemList.Items[i])
|
||||
}
|
||||
return results, nil
|
||||
},
|
||||
listFuncByNamespace: listFuncByNamespace,
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +139,7 @@ func toInternalServiceOrError(obj runtime.Object) (*api.Service, error) {
|
||||
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) {
|
||||
result := api.ResourceList{}
|
||||
svc, err := toInternalServiceOrError(item)
|
||||
|
@ -27,7 +27,7 @@ import (
|
||||
|
||||
func TestServiceEvaluatorMatchesResources(t *testing.T) {
|
||||
kubeClient := fake.NewSimpleClientset()
|
||||
evaluator := NewServiceEvaluator(kubeClient)
|
||||
evaluator := NewServiceEvaluator(kubeClient, nil)
|
||||
// we give a lot of resources
|
||||
input := []api.ResourceName{
|
||||
api.ResourceConfigMaps,
|
||||
@ -50,7 +50,7 @@ func TestServiceEvaluatorMatchesResources(t *testing.T) {
|
||||
|
||||
func TestServiceEvaluatorUsage(t *testing.T) {
|
||||
kubeClient := fake.NewSimpleClientset()
|
||||
evaluator := NewServiceEvaluator(kubeClient)
|
||||
evaluator := NewServiceEvaluator(kubeClient, nil)
|
||||
testCases := map[string]struct {
|
||||
service *api.Service
|
||||
usage api.ResourceList
|
||||
@ -199,7 +199,7 @@ func TestServiceConstraintsFunc(t *testing.T) {
|
||||
}
|
||||
|
||||
kubeClient := fake.NewSimpleClientset()
|
||||
evaluator := NewServiceEvaluator(kubeClient)
|
||||
evaluator := NewServiceEvaluator(kubeClient, nil)
|
||||
for testName, test := range testCases {
|
||||
err := evaluator.Constraints(test.required, test.service)
|
||||
switch {
|
||||
|
Loading…
Reference in New Issue
Block a user