mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 10:53:34 +00:00
vendor files
This commit is contained in:
89
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/BUILD
generated
vendored
Normal file
89
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/BUILD
generated
vendored
Normal file
@ -0,0 +1,89 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"admission.go",
|
||||
"config.go",
|
||||
"controller.go",
|
||||
"doc.go",
|
||||
"resource_access.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/plugin/pkg/admission/resourcequota",
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||
"//pkg/client/informers/informers_generated/internalversion:go_default_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",
|
||||
"//plugin/pkg/admission/resourcequota/apis/resourcequota/install:go_default_library",
|
||||
"//plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1:go_default_library",
|
||||
"//plugin/pkg/admission/resourcequota/apis/resourcequota/validation:go_default_library",
|
||||
"//vendor/github.com/golang/glog:go_default_library",
|
||||
"//vendor/github.com/hashicorp/golang-lru:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apimachinery/announced:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apimachinery/registered:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/admission:go_default_library",
|
||||
"//vendor/k8s.io/apiserver/pkg/storage/etcd:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/workqueue:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["admission_test.go"],
|
||||
importpath = "k8s.io/kubernetes/plugin/pkg/admission/resourcequota",
|
||||
library = ":go_default_library",
|
||||
deps = [
|
||||
"//pkg/apis/core:go_default_library",
|
||||
"//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/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/util/sets: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/client-go/testing:go_default_library",
|
||||
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//plugin/pkg/admission/resourcequota/apis/resourcequota:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
140
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/admission.go
generated
vendored
Normal file
140
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/admission.go
generated
vendored
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package resourcequota
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
|
||||
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
|
||||
"k8s.io/kubernetes/pkg/quota"
|
||||
resourcequotaapi "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota"
|
||||
resourcequotaapiv1alpha1 "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1"
|
||||
"k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/validation"
|
||||
)
|
||||
|
||||
// Register registers a plugin
|
||||
func Register(plugins *admission.Plugins) {
|
||||
plugins.Register("ResourceQuota",
|
||||
func(config io.Reader) (admission.Interface, error) {
|
||||
// load the configuration provided (if any)
|
||||
configuration, err := LoadConfiguration(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// validate the configuration (if any)
|
||||
if configuration != nil {
|
||||
if errs := validation.ValidateConfiguration(configuration); len(errs) != 0 {
|
||||
return nil, errs.ToAggregate()
|
||||
}
|
||||
}
|
||||
return NewResourceQuota(configuration, 5, make(chan struct{}))
|
||||
})
|
||||
|
||||
// add our config types
|
||||
resourcequotaapi.AddToScheme(plugins.ConfigScheme)
|
||||
resourcequotaapiv1alpha1.AddToScheme(plugins.ConfigScheme)
|
||||
}
|
||||
|
||||
// QuotaAdmission implements an admission controller that can enforce quota constraints
|
||||
type QuotaAdmission struct {
|
||||
*admission.Handler
|
||||
config *resourcequotaapi.Configuration
|
||||
stopCh <-chan struct{}
|
||||
quotaConfiguration quota.Configuration
|
||||
numEvaluators int
|
||||
quotaAccessor *quotaAccessor
|
||||
evaluator Evaluator
|
||||
}
|
||||
|
||||
var _ admission.ValidationInterface = &QuotaAdmission{}
|
||||
var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&QuotaAdmission{})
|
||||
var _ = kubeapiserveradmission.WantsQuotaConfiguration(&QuotaAdmission{})
|
||||
|
||||
type liveLookupEntry struct {
|
||||
expiry time.Time
|
||||
items []*api.ResourceQuota
|
||||
}
|
||||
|
||||
// NewResourceQuota configures an admission controller that can enforce quota constraints
|
||||
// using the provided registry. The registry must have the capability to handle group/kinds that
|
||||
// are persisted by the server this admission controller is intercepting
|
||||
func NewResourceQuota(config *resourcequotaapi.Configuration, numEvaluators int, stopCh <-chan struct{}) (*QuotaAdmission, error) {
|
||||
quotaAccessor, err := newQuotaAccessor()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &QuotaAdmission{
|
||||
Handler: admission.NewHandler(admission.Create, admission.Update),
|
||||
stopCh: stopCh,
|
||||
numEvaluators: numEvaluators,
|
||||
config: config,
|
||||
quotaAccessor: quotaAccessor,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (a *QuotaAdmission) SetInternalKubeClientSet(client internalclientset.Interface) {
|
||||
a.quotaAccessor.client = client
|
||||
}
|
||||
|
||||
func (a *QuotaAdmission) SetInternalKubeInformerFactory(f informers.SharedInformerFactory) {
|
||||
a.quotaAccessor.lister = f.Core().InternalVersion().ResourceQuotas().Lister()
|
||||
}
|
||||
|
||||
func (a *QuotaAdmission) SetQuotaConfiguration(c quota.Configuration) {
|
||||
a.quotaConfiguration = c
|
||||
a.evaluator = NewQuotaEvaluator(a.quotaAccessor, a.quotaConfiguration, nil, a.config, a.numEvaluators, a.stopCh)
|
||||
}
|
||||
|
||||
// ValidateInitialization ensures an authorizer is set.
|
||||
func (a *QuotaAdmission) ValidateInitialization() error {
|
||||
if a.quotaAccessor == nil {
|
||||
return fmt.Errorf("missing quotaAccessor")
|
||||
}
|
||||
if a.quotaAccessor.client == nil {
|
||||
return fmt.Errorf("missing quotaAccessor.client")
|
||||
}
|
||||
if a.quotaAccessor.lister == nil {
|
||||
return fmt.Errorf("missing quotaAccessor.lister")
|
||||
}
|
||||
if a.quotaConfiguration == nil {
|
||||
return fmt.Errorf("missing quotaConfiguration")
|
||||
}
|
||||
if a.evaluator == nil {
|
||||
return fmt.Errorf("missing evaluator")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate makes admission decisions while enforcing quota
|
||||
func (a *QuotaAdmission) Validate(attr admission.Attributes) (err error) {
|
||||
// ignore all operations that correspond to sub-resource actions
|
||||
if attr.GetSubresource() != "" {
|
||||
return nil
|
||||
}
|
||||
// ignore all operations that are not namespaced
|
||||
if attr.GetNamespace() == "" {
|
||||
return nil
|
||||
}
|
||||
return a.evaluator.Evaluate(attr)
|
||||
}
|
1452
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/admission_test.go
generated
vendored
Normal file
1452
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/admission_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
40
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/BUILD
generated
vendored
Normal file
40
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/BUILD
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"register.go",
|
||||
"types.go",
|
||||
"zz_generated.deepcopy.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//plugin/pkg/admission/resourcequota/apis/resourcequota/install:all-srcs",
|
||||
"//plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1:all-srcs",
|
||||
"//plugin/pkg/admission/resourcequota/apis/resourcequota/validation:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
)
|
7
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/OWNERS
generated
vendored
Executable file
7
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/OWNERS
generated
vendored
Executable file
@ -0,0 +1,7 @@
|
||||
reviewers:
|
||||
- deads2k
|
||||
- derekwaynecarr
|
||||
approvers:
|
||||
- deads2k
|
||||
- derekwaynecarr
|
||||
- smarterclayton
|
19
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/doc.go
generated
vendored
Normal file
19
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/doc.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package
|
||||
|
||||
package resourcequota // import "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota"
|
32
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/install/BUILD
generated
vendored
Normal file
32
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/install/BUILD
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["install.go"],
|
||||
importpath = "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/install",
|
||||
deps = [
|
||||
"//plugin/pkg/admission/resourcequota/apis/resourcequota:go_default_library",
|
||||
"//plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apimachinery/announced:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apimachinery/registered:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
43
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/install/install.go
generated
vendored
Normal file
43
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/install/install.go
generated
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package install installs the experimental API group, making it available as
|
||||
// an option to all of the API encoding/decoding machinery.
|
||||
package install
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/apimachinery/announced"
|
||||
"k8s.io/apimachinery/pkg/apimachinery/registered"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
resourcequotaapi "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota"
|
||||
resourcequotav1alpha1 "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1"
|
||||
)
|
||||
|
||||
// Install registers the API group and adds types to a scheme
|
||||
func Install(groupFactoryRegistry announced.APIGroupFactoryRegistry, registry *registered.APIRegistrationManager, scheme *runtime.Scheme) {
|
||||
if err := announced.NewGroupMetaFactory(
|
||||
&announced.GroupMetaFactoryArgs{
|
||||
GroupName: resourcequotaapi.GroupName,
|
||||
VersionPreferenceOrder: []string{resourcequotav1alpha1.SchemeGroupVersion.Version},
|
||||
AddInternalObjectsToScheme: resourcequotaapi.AddToScheme,
|
||||
},
|
||||
announced.VersionToSchemeFunc{
|
||||
resourcequotav1alpha1.SchemeGroupVersion.Version: resourcequotav1alpha1.AddToScheme,
|
||||
},
|
||||
).Announce(groupFactoryRegistry).RegisterAndEnable(registry, scheme); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
51
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/register.go
generated
vendored
Normal file
51
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/register.go
generated
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package resourcequota
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
var (
|
||||
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
|
||||
AddToScheme = SchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
// GroupName is the group name use in this package
|
||||
const GroupName = "resourcequota.admission.k8s.io"
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
|
||||
|
||||
// Kind takes an unqualified kind and returns a Group qualified GroupKind
|
||||
func Kind(kind string) schema.GroupKind {
|
||||
return SchemeGroupVersion.WithKind(kind).GroupKind()
|
||||
}
|
||||
|
||||
// Resource takes an unqualified resource and returns a Group qualified GroupResource
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return SchemeGroupVersion.WithResource(resource).GroupResource()
|
||||
}
|
||||
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
// TODO this will get cleaned up with the scheme types are fixed
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&Configuration{},
|
||||
)
|
||||
return nil
|
||||
}
|
57
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/types.go
generated
vendored
Normal file
57
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/types.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package resourcequota
|
||||
|
||||
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Configuration provides configuration for the ResourceQuota admission controller.
|
||||
type Configuration struct {
|
||||
metav1.TypeMeta
|
||||
|
||||
// LimitedResources whose consumption is limited by default.
|
||||
// +optional
|
||||
LimitedResources []LimitedResource
|
||||
}
|
||||
|
||||
// LimitedResource matches a resource whose consumption is limited by default.
|
||||
// To consume the resource, there must exist an associated quota that limits
|
||||
// its consumption.
|
||||
type LimitedResource struct {
|
||||
|
||||
// APIGroup is the name of the APIGroup that contains the limited resource.
|
||||
// +optional
|
||||
APIGroup string `json:"apiGroup,omitempty"`
|
||||
|
||||
// Resource is the name of the resource this rule applies to.
|
||||
// For example, if the administrator wants to limit consumption
|
||||
// of a storage resource associated with persistent volume claims,
|
||||
// the value would be "persistentvolumeclaims".
|
||||
Resource string `json:"resource"`
|
||||
|
||||
// For each intercepted request, the quota system will evaluate
|
||||
// its resource usage. It will iterate through each resource consumed
|
||||
// and if the resource contains any substring in this listing, the
|
||||
// quota system will ensure that there is a covering quota. In the
|
||||
// absence of a covering quota, the quota system will deny the request.
|
||||
// For example, if an administrator wants to globally enforce that
|
||||
// that a quota must exist to consume persistent volume claims associated
|
||||
// with any storage class, the list would include
|
||||
// ".storageclass.storage.k8s.io/requests.storage"
|
||||
MatchContains []string
|
||||
}
|
40
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1/BUILD
generated
vendored
Normal file
40
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1/BUILD
generated
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"defaults.go",
|
||||
"doc.go",
|
||||
"register.go",
|
||||
"types.go",
|
||||
"zz_generated.conversion.go",
|
||||
"zz_generated.deepcopy.go",
|
||||
"zz_generated.defaults.go",
|
||||
],
|
||||
importpath = "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1",
|
||||
deps = [
|
||||
"//plugin/pkg/admission/resourcequota/apis/resourcequota:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/conversion:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
25
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1/defaults.go
generated
vendored
Normal file
25
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1/defaults.go
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import kruntime "k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
func addDefaultingFuncs(scheme *kruntime.Scheme) error {
|
||||
return RegisterDefaults(scheme)
|
||||
}
|
||||
|
||||
func SetDefaults_Configuration(obj *Configuration) {}
|
23
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1/doc.go
generated
vendored
Normal file
23
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1/doc.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// +k8s:deepcopy-gen=package
|
||||
// +k8s:conversion-gen=k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota
|
||||
// +k8s:defaulter-gen=TypeMeta
|
||||
|
||||
// Package v1alpha1 is the v1alpha1 version of the API.
|
||||
// +groupName=resourcequota.admission.k8s.io
|
||||
package v1alpha1 // import "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1"
|
50
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1/register.go
generated
vendored
Normal file
50
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1/register.go
generated
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// GroupName is the group name use in this package
|
||||
const GroupName = "resourcequota.admission.k8s.io"
|
||||
|
||||
// SchemeGroupVersion is group version used to register these objects
|
||||
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha1"}
|
||||
|
||||
var (
|
||||
// TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api.
|
||||
// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
|
||||
SchemeBuilder runtime.SchemeBuilder
|
||||
localSchemeBuilder = &SchemeBuilder
|
||||
AddToScheme = localSchemeBuilder.AddToScheme
|
||||
)
|
||||
|
||||
func init() {
|
||||
// We only register manually written functions here. The registration of the
|
||||
// generated functions takes place in the generated files. The separation
|
||||
// makes the code compile even when the generated files are missing.
|
||||
localSchemeBuilder.Register(addKnownTypes, addDefaultingFuncs)
|
||||
}
|
||||
|
||||
func addKnownTypes(scheme *runtime.Scheme) error {
|
||||
scheme.AddKnownTypes(SchemeGroupVersion,
|
||||
&Configuration{},
|
||||
)
|
||||
return nil
|
||||
}
|
57
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1/types.go
generated
vendored
Normal file
57
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1/types.go
generated
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
||||
|
||||
// Configuration provides configuration for the ResourceQuota admission controller.
|
||||
type Configuration struct {
|
||||
metav1.TypeMeta `json:",inline"`
|
||||
|
||||
// LimitedResources whose consumption is limited by default.
|
||||
// +optional
|
||||
LimitedResources []LimitedResource `json:"limitedResources"`
|
||||
}
|
||||
|
||||
// LimitedResource matches a resource whose consumption is limited by default.
|
||||
// To consume the resource, there must exist an associated quota that limits
|
||||
// its consumption.
|
||||
type LimitedResource struct {
|
||||
|
||||
// APIGroup is the name of the APIGroup that contains the limited resource.
|
||||
// +optional
|
||||
APIGroup string `json:"apiGroup,omitempty"`
|
||||
|
||||
// Resource is the name of the resource this rule applies to.
|
||||
// For example, if the administrator wants to limit consumption
|
||||
// of a storage resource associated with persistent volume claims,
|
||||
// the value would be "persistentvolumeclaims".
|
||||
Resource string `json:"resource"`
|
||||
|
||||
// For each intercepted request, the quota system will evaluate
|
||||
// its resource usage. It will iterate through each resource consumed
|
||||
// and if the resource contains any substring in this listing, the
|
||||
// quota system will ensure that there is a covering quota. In the
|
||||
// absence of a covering quota, the quota system will deny the request.
|
||||
// For example, if an administrator wants to globally enforce that
|
||||
// that a quota must exist to consume persistent volume claims associated
|
||||
// with any storage class, the list would include
|
||||
// ".storageclass.storage.k8s.io/requests.storage"
|
||||
MatchContains []string `json:"matchContains,omitempty"`
|
||||
}
|
87
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1/zz_generated.conversion.go
generated
vendored
Normal file
87
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1/zz_generated.conversion.go
generated
vendored
Normal file
@ -0,0 +1,87 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by conversion-gen. Do not edit it manually!
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
resourcequota "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
func init() {
|
||||
localSchemeBuilder.Register(RegisterConversions)
|
||||
}
|
||||
|
||||
// RegisterConversions adds conversion functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
func RegisterConversions(scheme *runtime.Scheme) error {
|
||||
return scheme.AddGeneratedConversionFuncs(
|
||||
Convert_v1alpha1_Configuration_To_resourcequota_Configuration,
|
||||
Convert_resourcequota_Configuration_To_v1alpha1_Configuration,
|
||||
Convert_v1alpha1_LimitedResource_To_resourcequota_LimitedResource,
|
||||
Convert_resourcequota_LimitedResource_To_v1alpha1_LimitedResource,
|
||||
)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_Configuration_To_resourcequota_Configuration(in *Configuration, out *resourcequota.Configuration, s conversion.Scope) error {
|
||||
out.LimitedResources = *(*[]resourcequota.LimitedResource)(unsafe.Pointer(&in.LimitedResources))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1alpha1_Configuration_To_resourcequota_Configuration is an autogenerated conversion function.
|
||||
func Convert_v1alpha1_Configuration_To_resourcequota_Configuration(in *Configuration, out *resourcequota.Configuration, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_Configuration_To_resourcequota_Configuration(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_resourcequota_Configuration_To_v1alpha1_Configuration(in *resourcequota.Configuration, out *Configuration, s conversion.Scope) error {
|
||||
out.LimitedResources = *(*[]LimitedResource)(unsafe.Pointer(&in.LimitedResources))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_resourcequota_Configuration_To_v1alpha1_Configuration is an autogenerated conversion function.
|
||||
func Convert_resourcequota_Configuration_To_v1alpha1_Configuration(in *resourcequota.Configuration, out *Configuration, s conversion.Scope) error {
|
||||
return autoConvert_resourcequota_Configuration_To_v1alpha1_Configuration(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_v1alpha1_LimitedResource_To_resourcequota_LimitedResource(in *LimitedResource, out *resourcequota.LimitedResource, s conversion.Scope) error {
|
||||
out.APIGroup = in.APIGroup
|
||||
out.Resource = in.Resource
|
||||
out.MatchContains = *(*[]string)(unsafe.Pointer(&in.MatchContains))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_v1alpha1_LimitedResource_To_resourcequota_LimitedResource is an autogenerated conversion function.
|
||||
func Convert_v1alpha1_LimitedResource_To_resourcequota_LimitedResource(in *LimitedResource, out *resourcequota.LimitedResource, s conversion.Scope) error {
|
||||
return autoConvert_v1alpha1_LimitedResource_To_resourcequota_LimitedResource(in, out, s)
|
||||
}
|
||||
|
||||
func autoConvert_resourcequota_LimitedResource_To_v1alpha1_LimitedResource(in *resourcequota.LimitedResource, out *LimitedResource, s conversion.Scope) error {
|
||||
out.APIGroup = in.APIGroup
|
||||
out.Resource = in.Resource
|
||||
out.MatchContains = *(*[]string)(unsafe.Pointer(&in.MatchContains))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert_resourcequota_LimitedResource_To_v1alpha1_LimitedResource is an autogenerated conversion function.
|
||||
func Convert_resourcequota_LimitedResource_To_v1alpha1_LimitedResource(in *resourcequota.LimitedResource, out *LimitedResource, s conversion.Scope) error {
|
||||
return autoConvert_resourcequota_LimitedResource_To_v1alpha1_LimitedResource(in, out, s)
|
||||
}
|
79
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1/zz_generated.deepcopy.go
generated
vendored
Normal file
79
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1/zz_generated.deepcopy.go
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Configuration) DeepCopyInto(out *Configuration) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if in.LimitedResources != nil {
|
||||
in, out := &in.LimitedResources, &out.LimitedResources
|
||||
*out = make([]LimitedResource, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Configuration.
|
||||
func (in *Configuration) DeepCopy() *Configuration {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Configuration)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Configuration) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *LimitedResource) DeepCopyInto(out *LimitedResource) {
|
||||
*out = *in
|
||||
if in.MatchContains != nil {
|
||||
in, out := &in.MatchContains, &out.MatchContains
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LimitedResource.
|
||||
func (in *LimitedResource) DeepCopy() *LimitedResource {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(LimitedResource)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
37
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1/zz_generated.defaults.go
generated
vendored
Normal file
37
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1/zz_generated.defaults.go
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by defaulter-gen. Do not edit it manually!
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// RegisterDefaults adds defaulters functions to the given scheme.
|
||||
// Public to allow building arbitrary schemes.
|
||||
// All generated defaulters are covering - they call all nested defaulters.
|
||||
func RegisterDefaults(scheme *runtime.Scheme) error {
|
||||
scheme.AddTypeDefaultingFunc(&Configuration{}, func(obj interface{}) { SetObjectDefaults_Configuration(obj.(*Configuration)) })
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetObjectDefaults_Configuration(in *Configuration) {
|
||||
SetDefaults_Configuration(in)
|
||||
}
|
38
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/validation/BUILD
generated
vendored
Normal file
38
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/validation/BUILD
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(
|
||||
"@io_bazel_rules_go//go:def.bzl",
|
||||
"go_library",
|
||||
"go_test",
|
||||
)
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["validation.go"],
|
||||
importpath = "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/validation",
|
||||
deps = [
|
||||
"//plugin/pkg/admission/resourcequota/apis/resourcequota:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["validation_test.go"],
|
||||
importpath = "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/validation",
|
||||
library = ":go_default_library",
|
||||
deps = ["//plugin/pkg/admission/resourcequota/apis/resourcequota:go_default_library"],
|
||||
)
|
36
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/validation/validation.go
generated
vendored
Normal file
36
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/validation/validation.go
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package validation
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
|
||||
resourcequotaapi "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota"
|
||||
)
|
||||
|
||||
// ValidateConfiguration validates the configuration.
|
||||
func ValidateConfiguration(config *resourcequotaapi.Configuration) field.ErrorList {
|
||||
allErrs := field.ErrorList{}
|
||||
fldPath := field.NewPath("limitedResources")
|
||||
for i, limitedResource := range config.LimitedResources {
|
||||
idxPath := fldPath.Index(i)
|
||||
if len(limitedResource.Resource) == 0 {
|
||||
allErrs = append(allErrs, field.Required(idxPath.Child("resource"), ""))
|
||||
}
|
||||
}
|
||||
return allErrs
|
||||
}
|
60
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/validation/validation_test.go
generated
vendored
Normal file
60
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/validation/validation_test.go
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package validation
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
resourcequotaapi "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota"
|
||||
)
|
||||
|
||||
func TestValidateConfiguration(t *testing.T) {
|
||||
successCases := []resourcequotaapi.Configuration{
|
||||
{
|
||||
LimitedResources: []resourcequotaapi.LimitedResource{
|
||||
{
|
||||
Resource: "pods",
|
||||
MatchContains: []string{"requests.cpu"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
LimitedResources: []resourcequotaapi.LimitedResource{
|
||||
{
|
||||
Resource: "persistentvolumeclaims",
|
||||
MatchContains: []string{"requests.storage"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for i := range successCases {
|
||||
configuration := successCases[i]
|
||||
if errs := ValidateConfiguration(&configuration); len(errs) != 0 {
|
||||
t.Errorf("expected success: %v", errs)
|
||||
}
|
||||
}
|
||||
errorCases := map[string]resourcequotaapi.Configuration{
|
||||
"missing apiGroupResource": {LimitedResources: []resourcequotaapi.LimitedResource{
|
||||
{MatchContains: []string{"requests.cpu"}},
|
||||
}},
|
||||
}
|
||||
for k, v := range errorCases {
|
||||
if errs := ValidateConfiguration(&v); len(errs) == 0 {
|
||||
t.Errorf("expected failure for %s", k)
|
||||
}
|
||||
}
|
||||
}
|
79
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/zz_generated.deepcopy.go
generated
vendored
Normal file
79
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/zz_generated.deepcopy.go
generated
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
// +build !ignore_autogenerated
|
||||
|
||||
/*
|
||||
Copyright 2018 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
|
||||
|
||||
package resourcequota
|
||||
|
||||
import (
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Configuration) DeepCopyInto(out *Configuration) {
|
||||
*out = *in
|
||||
out.TypeMeta = in.TypeMeta
|
||||
if in.LimitedResources != nil {
|
||||
in, out := &in.LimitedResources, &out.LimitedResources
|
||||
*out = make([]LimitedResource, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Configuration.
|
||||
func (in *Configuration) DeepCopy() *Configuration {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(Configuration)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
||||
func (in *Configuration) DeepCopyObject() runtime.Object {
|
||||
if c := in.DeepCopy(); c != nil {
|
||||
return c
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *LimitedResource) DeepCopyInto(out *LimitedResource) {
|
||||
*out = *in
|
||||
if in.MatchContains != nil {
|
||||
in, out := &in.MatchContains, &out.MatchContains
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LimitedResource.
|
||||
func (in *LimitedResource) DeepCopy() *LimitedResource {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(LimitedResource)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
72
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/config.go
generated
vendored
Normal file
72
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/config.go
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package resourcequota
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apimachinery/announced"
|
||||
"k8s.io/apimachinery/pkg/apimachinery/registered"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
resourcequotaapi "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota"
|
||||
"k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/install"
|
||||
resourcequotav1alpha1 "k8s.io/kubernetes/plugin/pkg/admission/resourcequota/apis/resourcequota/v1alpha1"
|
||||
)
|
||||
|
||||
var (
|
||||
groupFactoryRegistry = make(announced.APIGroupFactoryRegistry)
|
||||
registry = registered.NewOrDie(os.Getenv("KUBE_API_VERSIONS"))
|
||||
scheme = runtime.NewScheme()
|
||||
codecs = serializer.NewCodecFactory(scheme)
|
||||
)
|
||||
|
||||
func init() {
|
||||
install.Install(groupFactoryRegistry, registry, scheme)
|
||||
}
|
||||
|
||||
// LoadConfiguration loads the provided configuration.
|
||||
func LoadConfiguration(config io.Reader) (*resourcequotaapi.Configuration, error) {
|
||||
// if no config is provided, return a default configuration
|
||||
if config == nil {
|
||||
externalConfig := &resourcequotav1alpha1.Configuration{}
|
||||
scheme.Default(externalConfig)
|
||||
internalConfig := &resourcequotaapi.Configuration{}
|
||||
if err := scheme.Convert(externalConfig, internalConfig, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return internalConfig, nil
|
||||
}
|
||||
// we have a config so parse it.
|
||||
data, err := ioutil.ReadAll(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decoder := codecs.UniversalDecoder()
|
||||
decodedObj, err := runtime.Decode(decoder, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resourceQuotaConfiguration, ok := decodedObj.(*resourcequotaapi.Configuration)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected type: %T", decodedObj)
|
||||
}
|
||||
return resourceQuotaConfiguration, nil
|
||||
}
|
647
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/controller.go
generated
vendored
Normal file
647
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/controller.go
generated
vendored
Normal file
@ -0,0 +1,647 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package resourcequota
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
"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"
|
||||
)
|
||||
|
||||
// Evaluator is used to see if quota constraints are satisfied.
|
||||
type Evaluator interface {
|
||||
// Evaluate takes an operation and checks to see if quota constraints are satisfied. It returns an error if they are not.
|
||||
// The default implementation process related operations in chunks when possible.
|
||||
Evaluate(a admission.Attributes) error
|
||||
}
|
||||
|
||||
type quotaEvaluator struct {
|
||||
quotaAccessor QuotaAccessor
|
||||
// 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
|
||||
|
||||
// TODO these are used together to bucket items by namespace and then batch them up for processing.
|
||||
// The technique is valuable for rollup activities to avoid fanout and reduce resource contention.
|
||||
// We could move this into a library if another component needed it.
|
||||
// queue is indexed by namespace, so that we bundle up on a per-namespace basis
|
||||
queue *workqueue.Type
|
||||
workLock sync.Mutex
|
||||
work map[string][]*admissionWaiter
|
||||
dirtyWork map[string][]*admissionWaiter
|
||||
inProgress sets.String
|
||||
|
||||
// controls the run method so that we can cleanly conform to the Evaluator interface
|
||||
workers int
|
||||
stopCh <-chan struct{}
|
||||
init sync.Once
|
||||
|
||||
// lets us know what resources are limited by default
|
||||
config *resourcequotaapi.Configuration
|
||||
}
|
||||
|
||||
type admissionWaiter struct {
|
||||
attributes admission.Attributes
|
||||
finished chan struct{}
|
||||
result error
|
||||
}
|
||||
|
||||
type defaultDeny struct{}
|
||||
|
||||
func (defaultDeny) Error() string {
|
||||
return "DEFAULT DENY"
|
||||
}
|
||||
|
||||
// IsDefaultDeny returns true if the error is defaultDeny
|
||||
func IsDefaultDeny(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
_, ok := err.(defaultDeny)
|
||||
return ok
|
||||
}
|
||||
|
||||
func newAdmissionWaiter(a admission.Attributes) *admissionWaiter {
|
||||
return &admissionWaiter{
|
||||
attributes: a,
|
||||
finished: make(chan struct{}),
|
||||
result: defaultDeny{},
|
||||
}
|
||||
}
|
||||
|
||||
// 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, 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,
|
||||
|
||||
quotaConfiguration: quotaConfiguration,
|
||||
registry: generic.NewRegistry(quotaConfiguration.Evaluators()),
|
||||
|
||||
queue: workqueue.NewNamed("admission_quota_controller"),
|
||||
work: map[string][]*admissionWaiter{},
|
||||
dirtyWork: map[string][]*admissionWaiter{},
|
||||
inProgress: sets.String{},
|
||||
|
||||
workers: workers,
|
||||
stopCh: stopCh,
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
// Run begins watching and syncing.
|
||||
func (e *quotaEvaluator) run() {
|
||||
defer utilruntime.HandleCrash()
|
||||
|
||||
for i := 0; i < e.workers; i++ {
|
||||
go wait.Until(e.doWork, time.Second, e.stopCh)
|
||||
}
|
||||
<-e.stopCh
|
||||
glog.Infof("Shutting down quota evaluator")
|
||||
e.queue.ShutDown()
|
||||
}
|
||||
|
||||
func (e *quotaEvaluator) doWork() {
|
||||
workFunc := func() bool {
|
||||
ns, admissionAttributes, quit := e.getWork()
|
||||
if quit {
|
||||
return true
|
||||
}
|
||||
defer e.completeWork(ns)
|
||||
if len(admissionAttributes) == 0 {
|
||||
return false
|
||||
}
|
||||
e.checkAttributes(ns, admissionAttributes)
|
||||
return false
|
||||
}
|
||||
for {
|
||||
if quit := workFunc(); quit {
|
||||
glog.Infof("quota evaluator worker shutdown")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// checkAttributes iterates evaluates all the waiting admissionAttributes. It will always notify all waiters
|
||||
// before returning. The default is to deny.
|
||||
func (e *quotaEvaluator) checkAttributes(ns string, admissionAttributes []*admissionWaiter) {
|
||||
// notify all on exit
|
||||
defer func() {
|
||||
for _, admissionAttribute := range admissionAttributes {
|
||||
close(admissionAttribute.finished)
|
||||
}
|
||||
}()
|
||||
|
||||
quotas, err := e.quotaAccessor.GetQuotas(ns)
|
||||
if err != nil {
|
||||
for _, admissionAttribute := range admissionAttributes {
|
||||
admissionAttribute.result = err
|
||||
}
|
||||
return
|
||||
}
|
||||
// if limited resources are disabled, we can just return safely when there are no quotas.
|
||||
limitedResourcesDisabled := len(e.config.LimitedResources) == 0
|
||||
if len(quotas) == 0 && limitedResourcesDisabled {
|
||||
for _, admissionAttribute := range admissionAttributes {
|
||||
admissionAttribute.result = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if e.lockAcquisitionFunc != nil {
|
||||
releaseLocks := e.lockAcquisitionFunc(quotas)
|
||||
defer releaseLocks()
|
||||
}
|
||||
|
||||
e.checkQuotas(quotas, admissionAttributes, 3)
|
||||
}
|
||||
|
||||
// checkQuotas checks the admission attributes against the passed quotas. If a quota applies, it will attempt to update it
|
||||
// AFTER it has checked all the admissionAttributes. The method breaks down into phase like this:
|
||||
// 0. make a copy of the quotas to act as a "running" quota so we know what we need to update and can still compare against the
|
||||
// originals
|
||||
// 1. check each admission attribute to see if it fits within *all* the quotas. If it doesn't fit, mark the waiter as failed
|
||||
// and the running quota don't change. If it did fit, check to see if any quota was changed. It there was no quota change
|
||||
// mark the waiter as succeeded. If some quota did change, update the running quotas
|
||||
// 2. If no running quota was changed, return now since no updates are needed.
|
||||
// 3. for each quota that has changed, attempt an update. If all updates succeeded, update all unset waiters to success status and return. If the some
|
||||
// updates failed on conflict errors and we have retries left, re-get the failed quota from our cache for the latest version
|
||||
// and recurse into this method with the subset. It's safe for us to evaluate ONLY the subset, because the other quota
|
||||
// documents for these waiters have already been evaluated. Step 1, will mark all the ones that should already have succeeded.
|
||||
func (e *quotaEvaluator) checkQuotas(quotas []api.ResourceQuota, admissionAttributes []*admissionWaiter, remainingRetries int) {
|
||||
// yet another copy to compare against originals to see if we actually have deltas
|
||||
originalQuotas, err := copyQuotas(quotas)
|
||||
if err != nil {
|
||||
utilruntime.HandleError(err)
|
||||
return
|
||||
}
|
||||
|
||||
atLeastOneChanged := false
|
||||
for i := range admissionAttributes {
|
||||
admissionAttribute := admissionAttributes[i]
|
||||
newQuotas, err := e.checkRequest(quotas, admissionAttribute.attributes)
|
||||
if err != nil {
|
||||
admissionAttribute.result = err
|
||||
continue
|
||||
}
|
||||
|
||||
// if the new quotas are the same as the old quotas, then this particular one doesn't issue any updates
|
||||
// that means that no quota docs applied, so it can get a pass
|
||||
atLeastOneChangeForThisWaiter := false
|
||||
for j := range newQuotas {
|
||||
if !quota.Equals(quotas[j].Status.Used, newQuotas[j].Status.Used) {
|
||||
atLeastOneChanged = true
|
||||
atLeastOneChangeForThisWaiter = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !atLeastOneChangeForThisWaiter {
|
||||
admissionAttribute.result = nil
|
||||
}
|
||||
|
||||
quotas = newQuotas
|
||||
}
|
||||
|
||||
// if none of the requests changed anything, there's no reason to issue an update, just fail them all now
|
||||
if !atLeastOneChanged {
|
||||
return
|
||||
}
|
||||
|
||||
// now go through and try to issue updates. Things get a little weird here:
|
||||
// 1. check to see if the quota changed. If not, skip.
|
||||
// 2. if the quota changed and the update passes, be happy
|
||||
// 3. if the quota changed and the update fails, add the original to a retry list
|
||||
var updatedFailedQuotas []api.ResourceQuota
|
||||
var lastErr error
|
||||
for i := range quotas {
|
||||
newQuota := quotas[i]
|
||||
|
||||
// if this quota didn't have its status changed, skip it
|
||||
if quota.Equals(originalQuotas[i].Status.Used, newQuota.Status.Used) {
|
||||
continue
|
||||
}
|
||||
|
||||
if err := e.quotaAccessor.UpdateQuotaStatus(&newQuota); err != nil {
|
||||
updatedFailedQuotas = append(updatedFailedQuotas, newQuota)
|
||||
lastErr = err
|
||||
}
|
||||
}
|
||||
|
||||
if len(updatedFailedQuotas) == 0 {
|
||||
// all the updates succeeded. At this point, anything with the default deny error was just waiting to
|
||||
// get a successful update, so we can mark and notify
|
||||
for _, admissionAttribute := range admissionAttributes {
|
||||
if IsDefaultDeny(admissionAttribute.result) {
|
||||
admissionAttribute.result = nil
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// at this point, errors are fatal. Update all waiters without status to failed and return
|
||||
if remainingRetries <= 0 {
|
||||
for _, admissionAttribute := range admissionAttributes {
|
||||
if IsDefaultDeny(admissionAttribute.result) {
|
||||
admissionAttribute.result = lastErr
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// this retry logic has the same bug that its possible to be checking against quota in a state that never actually exists where
|
||||
// you've added a new documented, then updated an old one, your resource matches both and you're only checking one
|
||||
// updates for these quota names failed. Get the current quotas in the namespace, compare by name, check to see if the
|
||||
// resource versions have changed. If not, we're going to fall through an fail everything. If they all have, then we can try again
|
||||
newQuotas, err := e.quotaAccessor.GetQuotas(quotas[0].Namespace)
|
||||
if err != nil {
|
||||
// this means that updates failed. Anything with a default deny error has failed and we need to let them know
|
||||
for _, admissionAttribute := range admissionAttributes {
|
||||
if IsDefaultDeny(admissionAttribute.result) {
|
||||
admissionAttribute.result = lastErr
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// this logic goes through our cache to find the new version of all quotas that failed update. If something has been removed
|
||||
// it is skipped on this retry. After all, you removed it.
|
||||
quotasToCheck := []api.ResourceQuota{}
|
||||
for _, newQuota := range newQuotas {
|
||||
for _, oldQuota := range updatedFailedQuotas {
|
||||
if newQuota.Name == oldQuota.Name {
|
||||
quotasToCheck = append(quotasToCheck, newQuota)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
e.checkQuotas(quotasToCheck, admissionAttributes, remainingRetries-1)
|
||||
}
|
||||
|
||||
func copyQuotas(in []api.ResourceQuota) ([]api.ResourceQuota, error) {
|
||||
out := make([]api.ResourceQuota, 0, len(in))
|
||||
for _, quota := range in {
|
||||
out = append(out, *quota.DeepCopy())
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// filterLimitedResourcesByGroupResource filters the input that match the specified groupResource
|
||||
func filterLimitedResourcesByGroupResource(input []resourcequotaapi.LimitedResource, groupResource schema.GroupResource) []resourcequotaapi.LimitedResource {
|
||||
result := []resourcequotaapi.LimitedResource{}
|
||||
for i := range input {
|
||||
limitedResource := input[i]
|
||||
limitedGroupResource := schema.GroupResource{Group: limitedResource.APIGroup, Resource: limitedResource.Resource}
|
||||
if limitedGroupResource == groupResource {
|
||||
result = append(result, limitedResource)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// limitedByDefault determines from the specified usage and limitedResources the set of resources names
|
||||
// that must be present in a covering quota. It returns empty set if it was unable to determine if
|
||||
// a resource was not limited by default.
|
||||
func limitedByDefault(usage api.ResourceList, limitedResources []resourcequotaapi.LimitedResource) []api.ResourceName {
|
||||
result := []api.ResourceName{}
|
||||
for _, limitedResource := range limitedResources {
|
||||
for k, v := range usage {
|
||||
// if a resource is consumed, we need to check if it matches on the limited resource list.
|
||||
if v.Sign() == 1 {
|
||||
// if we get a match, we add it to limited set
|
||||
for _, matchContain := range limitedResource.MatchContains {
|
||||
if strings.Contains(string(k), matchContain) {
|
||||
result = append(result, k)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// checkRequest verifies that the request does not exceed any quota constraint. it returns a copy of quotas not yet persisted
|
||||
// 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()
|
||||
evaluator := e.registry.Get(a.GetResource().GroupResource())
|
||||
if evaluator == nil {
|
||||
return quotas, nil
|
||||
}
|
||||
|
||||
if !evaluator.Handles(a) {
|
||||
return quotas, nil
|
||||
}
|
||||
|
||||
// if we have limited resources enabled for this resource, always calculate usage
|
||||
inputObject := a.GetObject()
|
||||
|
||||
// determine the set of resource names that must exist in a covering quota
|
||||
limitedResourceNames := []api.ResourceName{}
|
||||
limitedResources := filterLimitedResourcesByGroupResource(e.config.LimitedResources, a.GetResource().GroupResource())
|
||||
if len(limitedResources) > 0 {
|
||||
deltaUsage, err := evaluator.Usage(inputObject)
|
||||
if err != nil {
|
||||
return quotas, err
|
||||
}
|
||||
limitedResourceNames = limitedByDefault(deltaUsage, limitedResources)
|
||||
}
|
||||
limitedResourceNamesSet := quota.ToSet(limitedResourceNames)
|
||||
|
||||
// find the set of quotas that are pertinent to this request
|
||||
// reject if we match the quota, but usage is not calculated yet
|
||||
// reject if the input object does not satisfy quota constraints
|
||||
// if there are no pertinent quotas, we can just return
|
||||
interestingQuotaIndexes := []int{}
|
||||
// track the cumulative set of resources that were required across all quotas
|
||||
// this is needed to know if we have satisfied any constraints where consumption
|
||||
// was limited by default.
|
||||
restrictedResourcesSet := sets.String{}
|
||||
for i := range quotas {
|
||||
resourceQuota := quotas[i]
|
||||
match, err := evaluator.Matches(&resourceQuota, inputObject)
|
||||
if err != nil {
|
||||
return quotas, err
|
||||
}
|
||||
if !match {
|
||||
continue
|
||||
}
|
||||
|
||||
hardResources := quota.ResourceNames(resourceQuota.Status.Hard)
|
||||
restrictedResources := evaluator.MatchingResources(hardResources)
|
||||
if err := evaluator.Constraints(restrictedResources, inputObject); err != nil {
|
||||
return nil, admission.NewForbidden(a, fmt.Errorf("failed quota: %s: %v", resourceQuota.Name, err))
|
||||
}
|
||||
if !hasUsageStats(&resourceQuota) {
|
||||
return nil, admission.NewForbidden(a, fmt.Errorf("status unknown for quota: %s", resourceQuota.Name))
|
||||
}
|
||||
interestingQuotaIndexes = append(interestingQuotaIndexes, i)
|
||||
localRestrictedResourcesSet := quota.ToSet(restrictedResources)
|
||||
restrictedResourcesSet.Insert(localRestrictedResourcesSet.List()...)
|
||||
}
|
||||
|
||||
// verify that for every resource that had limited by default consumption
|
||||
// enabled that there was a corresponding quota that covered its use.
|
||||
// if not, we reject the request.
|
||||
hasNoCoveringQuota := limitedResourceNamesSet.Difference(restrictedResourcesSet)
|
||||
if len(hasNoCoveringQuota) > 0 {
|
||||
return quotas, fmt.Errorf("insufficient quota to consume: %v", strings.Join(hasNoCoveringQuota.List(), ","))
|
||||
}
|
||||
|
||||
if len(interestingQuotaIndexes) == 0 {
|
||||
return quotas, nil
|
||||
}
|
||||
|
||||
// Usage of some resources cannot be counted in isolation. For example, when
|
||||
// the resource represents a number of unique references to external
|
||||
// resource. In such a case an evaluator needs to process other objects in
|
||||
// the same namespace which needs to be known.
|
||||
if accessor, err := meta.Accessor(inputObject); namespace != "" && err == nil {
|
||||
if accessor.GetNamespace() == "" {
|
||||
accessor.SetNamespace(namespace)
|
||||
}
|
||||
}
|
||||
// there is at least one quota that definitely matches our object
|
||||
// as a result, we need to measure the usage of this object for quota
|
||||
// on updates, we need to subtract the previous measured usage
|
||||
// if usage shows no change, just return since it has no impact on quota
|
||||
deltaUsage, err := evaluator.Usage(inputObject)
|
||||
if err != nil {
|
||||
return quotas, err
|
||||
}
|
||||
|
||||
// ensure that usage for input object is never negative (this would mean a resource made a negative resource requirement)
|
||||
if negativeUsage := quota.IsNegative(deltaUsage); len(negativeUsage) > 0 {
|
||||
return nil, admission.NewForbidden(a, fmt.Errorf("quota usage is negative for resource(s): %s", prettyPrintResourceNames(negativeUsage)))
|
||||
}
|
||||
|
||||
if admission.Update == a.GetOperation() {
|
||||
prevItem := a.GetOldObject()
|
||||
if prevItem == nil {
|
||||
return nil, admission.NewForbidden(a, fmt.Errorf("unable to get previous usage since prior version of object was not found"))
|
||||
}
|
||||
|
||||
// if we can definitively determine that this is not a case of "create on update",
|
||||
// then charge based on the delta. Otherwise, bill the maximum
|
||||
metadata, err := meta.Accessor(prevItem)
|
||||
if err == nil && len(metadata.GetResourceVersion()) > 0 {
|
||||
prevUsage, innerErr := evaluator.Usage(prevItem)
|
||||
if innerErr != nil {
|
||||
return quotas, innerErr
|
||||
}
|
||||
deltaUsage = quota.SubtractWithNonNegativeResult(deltaUsage, prevUsage)
|
||||
}
|
||||
}
|
||||
|
||||
if quota.IsZero(deltaUsage) {
|
||||
return quotas, nil
|
||||
}
|
||||
|
||||
outQuotas, err := copyQuotas(quotas)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, index := range interestingQuotaIndexes {
|
||||
resourceQuota := outQuotas[index]
|
||||
|
||||
hardResources := quota.ResourceNames(resourceQuota.Status.Hard)
|
||||
requestedUsage := quota.Mask(deltaUsage, hardResources)
|
||||
newUsage := quota.Add(resourceQuota.Status.Used, requestedUsage)
|
||||
maskedNewUsage := quota.Mask(newUsage, quota.ResourceNames(requestedUsage))
|
||||
|
||||
if allowed, exceeded := quota.LessThanOrEqual(maskedNewUsage, resourceQuota.Status.Hard); !allowed {
|
||||
failedRequestedUsage := quota.Mask(requestedUsage, exceeded)
|
||||
failedUsed := quota.Mask(resourceQuota.Status.Used, exceeded)
|
||||
failedHard := quota.Mask(resourceQuota.Status.Hard, exceeded)
|
||||
return nil, admission.NewForbidden(a,
|
||||
fmt.Errorf("exceeded quota: %s, requested: %s, used: %s, limited: %s",
|
||||
resourceQuota.Name,
|
||||
prettyPrint(failedRequestedUsage),
|
||||
prettyPrint(failedUsed),
|
||||
prettyPrint(failedHard)))
|
||||
}
|
||||
|
||||
// update to the new usage number
|
||||
outQuotas[index].Status.Used = newUsage
|
||||
}
|
||||
|
||||
return outQuotas, nil
|
||||
}
|
||||
|
||||
func (e *quotaEvaluator) Evaluate(a admission.Attributes) error {
|
||||
e.init.Do(func() {
|
||||
go e.run()
|
||||
})
|
||||
|
||||
// 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)
|
||||
|
||||
// wait for completion or timeout
|
||||
select {
|
||||
case <-waiter.finished:
|
||||
case <-time.After(10 * time.Second):
|
||||
return fmt.Errorf("timeout")
|
||||
}
|
||||
|
||||
return waiter.result
|
||||
}
|
||||
|
||||
func (e *quotaEvaluator) addWork(a *admissionWaiter) {
|
||||
e.workLock.Lock()
|
||||
defer e.workLock.Unlock()
|
||||
|
||||
ns := a.attributes.GetNamespace()
|
||||
// this Add can trigger a Get BEFORE the work is added to a list, but this is ok because the getWork routine
|
||||
// waits the worklock before retrieving the work to do, so the writes in this method will be observed
|
||||
e.queue.Add(ns)
|
||||
|
||||
if e.inProgress.Has(ns) {
|
||||
e.dirtyWork[ns] = append(e.dirtyWork[ns], a)
|
||||
return
|
||||
}
|
||||
|
||||
e.work[ns] = append(e.work[ns], a)
|
||||
}
|
||||
|
||||
func (e *quotaEvaluator) completeWork(ns string) {
|
||||
e.workLock.Lock()
|
||||
defer e.workLock.Unlock()
|
||||
|
||||
e.queue.Done(ns)
|
||||
e.work[ns] = e.dirtyWork[ns]
|
||||
delete(e.dirtyWork, ns)
|
||||
e.inProgress.Delete(ns)
|
||||
}
|
||||
|
||||
func (e *quotaEvaluator) getWork() (string, []*admissionWaiter, bool) {
|
||||
uncastNS, shutdown := e.queue.Get()
|
||||
if shutdown {
|
||||
return "", []*admissionWaiter{}, shutdown
|
||||
}
|
||||
ns := uncastNS.(string)
|
||||
|
||||
e.workLock.Lock()
|
||||
defer e.workLock.Unlock()
|
||||
// at this point, we know we have a coherent view of e.work. It is entirely possible
|
||||
// that our workqueue has another item requeued to it, but we'll pick it up early. This ok
|
||||
// because the next time will go into our dirty list
|
||||
|
||||
work := e.work[ns]
|
||||
delete(e.work, ns)
|
||||
delete(e.dirtyWork, ns)
|
||||
|
||||
if len(work) != 0 {
|
||||
e.inProgress.Insert(ns)
|
||||
return ns, work, false
|
||||
}
|
||||
|
||||
e.queue.Done(ns)
|
||||
e.inProgress.Delete(ns)
|
||||
return ns, []*admissionWaiter{}, false
|
||||
}
|
||||
|
||||
// prettyPrint formats a resource list for usage in errors
|
||||
// it outputs resources sorted in increasing order
|
||||
func prettyPrint(item api.ResourceList) string {
|
||||
parts := []string{}
|
||||
keys := []string{}
|
||||
for key := range item {
|
||||
keys = append(keys, string(key))
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, key := range keys {
|
||||
value := item[api.ResourceName(key)]
|
||||
constraint := key + "=" + value.String()
|
||||
parts = append(parts, constraint)
|
||||
}
|
||||
return strings.Join(parts, ",")
|
||||
}
|
||||
|
||||
func prettyPrintResourceNames(a []api.ResourceName) string {
|
||||
values := []string{}
|
||||
for _, value := range a {
|
||||
values = append(values, string(value))
|
||||
}
|
||||
sort.Strings(values)
|
||||
return strings.Join(values, ",")
|
||||
}
|
||||
|
||||
// hasUsageStats returns true if for each hard constraint there is a value for its current usage
|
||||
func hasUsageStats(resourceQuota *api.ResourceQuota) bool {
|
||||
for resourceName := range resourceQuota.Status.Hard {
|
||||
if _, found := resourceQuota.Status.Used[resourceName]; !found {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
19
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/doc.go
generated
vendored
Normal file
19
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/doc.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
Copyright 2014 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// resourcequota enforces all incoming requests against any applied quota
|
||||
// in the namespace context of the request
|
||||
package resourcequota // import "k8s.io/kubernetes/plugin/pkg/admission/resourcequota"
|
154
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/resource_access.go
generated
vendored
Normal file
154
vendor/k8s.io/kubernetes/plugin/pkg/admission/resourcequota/resource_access.go
generated
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package resourcequota
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apiserver/pkg/storage/etcd"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||
corelisters "k8s.io/kubernetes/pkg/client/listers/core/internalversion"
|
||||
)
|
||||
|
||||
// QuotaAccessor abstracts the get/set logic from the rest of the Evaluator. This could be a test stub, a straight passthrough,
|
||||
// or most commonly a series of deconflicting caches.
|
||||
type QuotaAccessor interface {
|
||||
// UpdateQuotaStatus is called to persist final status. This method should write to persistent storage.
|
||||
// An error indicates that write didn't complete successfully.
|
||||
UpdateQuotaStatus(newQuota *api.ResourceQuota) error
|
||||
|
||||
// GetQuotas gets all possible quotas for a given namespace
|
||||
GetQuotas(namespace string) ([]api.ResourceQuota, error)
|
||||
}
|
||||
|
||||
type quotaAccessor struct {
|
||||
client clientset.Interface
|
||||
|
||||
// lister can list/get quota objects from a shared informer's cache
|
||||
lister corelisters.ResourceQuotaLister
|
||||
|
||||
// liveLookups holds the last few live lookups we've done to help ammortize cost on repeated lookup failures.
|
||||
// This let's us handle the case of latent caches, by looking up actual results for a namespace on cache miss/no results.
|
||||
// We track the lookup result here so that for repeated requests, we don't look it up very often.
|
||||
liveLookupCache *lru.Cache
|
||||
liveTTL time.Duration
|
||||
// updatedQuotas holds a cache of quotas that we've updated. This is used to pull the "really latest" during back to
|
||||
// back quota evaluations that touch the same quota doc. This only works because we can compare etcd resourceVersions
|
||||
// for the same resource as integers. Before this change: 22 updates with 12 conflicts. after this change: 15 updates with 0 conflicts
|
||||
updatedQuotas *lru.Cache
|
||||
}
|
||||
|
||||
// newQuotaAccessor creates an object that conforms to the QuotaAccessor interface to be used to retrieve quota objects.
|
||||
func newQuotaAccessor() (*quotaAccessor, error) {
|
||||
liveLookupCache, err := lru.New(100)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
updatedCache, err := lru.New(100)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// client and lister will be set when SetInternalKubeClientSet and SetInternalKubeInformerFactory are invoked
|
||||
return "aAccessor{
|
||||
liveLookupCache: liveLookupCache,
|
||||
liveTTL: time.Duration(30 * time.Second),
|
||||
updatedQuotas: updatedCache,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (e *quotaAccessor) UpdateQuotaStatus(newQuota *api.ResourceQuota) error {
|
||||
updatedQuota, err := e.client.Core().ResourceQuotas(newQuota.Namespace).UpdateStatus(newQuota)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
key := newQuota.Namespace + "/" + newQuota.Name
|
||||
e.updatedQuotas.Add(key, updatedQuota)
|
||||
return nil
|
||||
}
|
||||
|
||||
var etcdVersioner = etcd.APIObjectVersioner{}
|
||||
|
||||
// checkCache compares the passed quota against the value in the look-aside cache and returns the newer
|
||||
// if the cache is out of date, it deletes the stale entry. This only works because of etcd resourceVersions
|
||||
// being monotonically increasing integers
|
||||
func (e *quotaAccessor) checkCache(quota *api.ResourceQuota) *api.ResourceQuota {
|
||||
key := quota.Namespace + "/" + quota.Name
|
||||
uncastCachedQuota, ok := e.updatedQuotas.Get(key)
|
||||
if !ok {
|
||||
return quota
|
||||
}
|
||||
cachedQuota := uncastCachedQuota.(*api.ResourceQuota)
|
||||
|
||||
if etcdVersioner.CompareResourceVersion(quota, cachedQuota) >= 0 {
|
||||
e.updatedQuotas.Remove(key)
|
||||
return quota
|
||||
}
|
||||
return cachedQuota
|
||||
}
|
||||
|
||||
func (e *quotaAccessor) GetQuotas(namespace string) ([]api.ResourceQuota, error) {
|
||||
// determine if there are any quotas in this namespace
|
||||
// if there are no quotas, we don't need to do anything
|
||||
items, err := e.lister.ResourceQuotas(namespace).List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error resolving quota: %v", err)
|
||||
}
|
||||
|
||||
// if there are no items held in our indexer, check our live-lookup LRU, if that misses, do the live lookup to prime it.
|
||||
if len(items) == 0 {
|
||||
lruItemObj, ok := e.liveLookupCache.Get(namespace)
|
||||
if !ok || lruItemObj.(liveLookupEntry).expiry.Before(time.Now()) {
|
||||
// TODO: If there are multiple operations at the same time and cache has just expired,
|
||||
// this may cause multiple List operations being issued at the same time.
|
||||
// If there is already in-flight List() for a given namespace, we should wait until
|
||||
// it is finished and cache is updated instead of doing the same, also to avoid
|
||||
// throttling - see #22422 for details.
|
||||
liveList, err := e.client.Core().ResourceQuotas(namespace).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newEntry := liveLookupEntry{expiry: time.Now().Add(e.liveTTL)}
|
||||
for i := range liveList.Items {
|
||||
newEntry.items = append(newEntry.items, &liveList.Items[i])
|
||||
}
|
||||
e.liveLookupCache.Add(namespace, newEntry)
|
||||
lruItemObj = newEntry
|
||||
}
|
||||
lruEntry := lruItemObj.(liveLookupEntry)
|
||||
for i := range lruEntry.items {
|
||||
items = append(items, lruEntry.items[i])
|
||||
}
|
||||
}
|
||||
|
||||
resourceQuotas := []api.ResourceQuota{}
|
||||
for i := range items {
|
||||
quota := items[i]
|
||||
quota = e.checkCache(quota)
|
||||
// always make a copy. We're going to muck around with this and we should never mutate the originals
|
||||
resourceQuotas = append(resourceQuotas, *quota)
|
||||
}
|
||||
|
||||
return resourceQuotas, nil
|
||||
}
|
Reference in New Issue
Block a user