mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 12:15:52 +00:00
externalize limitrange
This commit is contained in:
parent
444373b404
commit
61ba80cbac
@ -15,10 +15,7 @@ go_library(
|
|||||||
importpath = "k8s.io/kubernetes/plugin/pkg/admission/limitranger",
|
importpath = "k8s.io/kubernetes/plugin/pkg/admission/limitranger",
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/apis/core:go_default_library",
|
"//pkg/apis/core:go_default_library",
|
||||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
"//staging/src/k8s.io/api/core/v1: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",
|
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
@ -26,6 +23,10 @@ go_library(
|
|||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/admission/initializer:go_default_library",
|
||||||
|
"//staging/src/k8s.io/client-go/informers:go_default_library",
|
||||||
|
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||||
|
"//staging/src/k8s.io/client-go/listers/core/v1:go_default_library",
|
||||||
"//vendor/github.com/hashicorp/golang-lru:go_default_library",
|
"//vendor/github.com/hashicorp/golang-lru:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@ -36,16 +37,18 @@ go_test(
|
|||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/apis/core:go_default_library",
|
"//pkg/apis/core:go_default_library",
|
||||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
"//pkg/apis/core/v1:go_default_library",
|
||||||
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
|
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||||
"//pkg/client/informers/informers_generated/internalversion:go_default_library",
|
|
||||||
"//pkg/kubeapiserver/admission:go_default_library",
|
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||||
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
|
"//staging/src/k8s.io/apiserver/pkg/admission:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apiserver/pkg/admission/initializer:go_default_library",
|
||||||
|
"//staging/src/k8s.io/client-go/informers:go_default_library",
|
||||||
|
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||||
|
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/testing:go_default_library",
|
"//staging/src/k8s.io/client-go/testing:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -23,8 +23,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
"github.com/hashicorp/golang-lru"
|
||||||
|
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
@ -32,11 +33,11 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
|
genericadmissioninitailizer "k8s.io/apiserver/pkg/admission/initializer"
|
||||||
|
"k8s.io/client-go/informers"
|
||||||
|
"k8s.io/client-go/kubernetes"
|
||||||
|
corev1listers "k8s.io/client-go/listers/core/v1"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
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"
|
|
||||||
corelisters "k8s.io/kubernetes/pkg/client/listers/core/internalversion"
|
|
||||||
kubeapiserveradmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -55,9 +56,9 @@ func Register(plugins *admission.Plugins) {
|
|||||||
// LimitRanger enforces usage limits on a per resource basis in the namespace
|
// LimitRanger enforces usage limits on a per resource basis in the namespace
|
||||||
type LimitRanger struct {
|
type LimitRanger struct {
|
||||||
*admission.Handler
|
*admission.Handler
|
||||||
client internalclientset.Interface
|
client kubernetes.Interface
|
||||||
actions LimitRangerActions
|
actions LimitRangerActions
|
||||||
lister corelisters.LimitRangeLister
|
lister corev1listers.LimitRangeLister
|
||||||
|
|
||||||
// liveLookups holds the last few live lookups we've done to help ammortize cost on repeated lookup failures.
|
// 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.
|
// This let's us handle the case of latent caches, by looking up actual results for a namespace on cache miss/no results.
|
||||||
@ -68,19 +69,25 @@ type LimitRanger struct {
|
|||||||
|
|
||||||
var _ admission.MutationInterface = &LimitRanger{}
|
var _ admission.MutationInterface = &LimitRanger{}
|
||||||
var _ admission.ValidationInterface = &LimitRanger{}
|
var _ admission.ValidationInterface = &LimitRanger{}
|
||||||
var _ kubeapiserveradmission.WantsInternalKubeInformerFactory = &LimitRanger{}
|
|
||||||
|
var _ genericadmissioninitailizer.WantsExternalKubeInformerFactory = &LimitRanger{}
|
||||||
|
var _ genericadmissioninitailizer.WantsExternalKubeClientSet = &LimitRanger{}
|
||||||
|
|
||||||
type liveLookupEntry struct {
|
type liveLookupEntry struct {
|
||||||
expiry time.Time
|
expiry time.Time
|
||||||
items []*api.LimitRange
|
items []*corev1.LimitRange
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LimitRanger) SetInternalKubeInformerFactory(f informers.SharedInformerFactory) {
|
func (l *LimitRanger) SetExternalKubeInformerFactory(f informers.SharedInformerFactory) {
|
||||||
limitRangeInformer := f.Core().InternalVersion().LimitRanges()
|
limitRangeInformer := f.Core().V1().LimitRanges()
|
||||||
l.SetReadyFunc(limitRangeInformer.Informer().HasSynced)
|
l.SetReadyFunc(limitRangeInformer.Informer().HasSynced)
|
||||||
l.lister = limitRangeInformer.Lister()
|
l.lister = limitRangeInformer.Lister()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *LimitRanger) SetExternalKubeClientSet(client kubernetes.Interface) {
|
||||||
|
a.client = client
|
||||||
|
}
|
||||||
|
|
||||||
func (l *LimitRanger) ValidateInitialization() error {
|
func (l *LimitRanger) ValidateInitialization() error {
|
||||||
if l.lister == nil {
|
if l.lister == nil {
|
||||||
return fmt.Errorf("missing limitRange lister")
|
return fmt.Errorf("missing limitRange lister")
|
||||||
@ -101,20 +108,11 @@ func (l *LimitRanger) Validate(a admission.Attributes) (err error) {
|
|||||||
return l.runLimitFunc(a, l.actions.ValidateLimit)
|
return l.runLimitFunc(a, l.actions.ValidateLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LimitRanger) runLimitFunc(a admission.Attributes, limitFn func(limitRange *api.LimitRange, kind string, obj runtime.Object) error) (err error) {
|
func (l *LimitRanger) runLimitFunc(a admission.Attributes, limitFn func(limitRange *corev1.LimitRange, kind string, obj runtime.Object) error) (err error) {
|
||||||
if !l.actions.SupportsAttributes(a) {
|
if !l.actions.SupportsAttributes(a) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
obj := a.GetObject()
|
|
||||||
name := "Unknown"
|
|
||||||
if obj != nil {
|
|
||||||
name, _ = meta.NewAccessor().Name(obj)
|
|
||||||
if len(name) == 0 {
|
|
||||||
name, _ = meta.NewAccessor().GenerateName(obj)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ignore all objects marked for deletion
|
// ignore all objects marked for deletion
|
||||||
oldObj := a.GetOldObject()
|
oldObj := a.GetOldObject()
|
||||||
if oldObj != nil {
|
if oldObj != nil {
|
||||||
@ -148,7 +146,7 @@ func (l *LimitRanger) runLimitFunc(a admission.Attributes, limitFn func(limitRan
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *LimitRanger) GetLimitRanges(a admission.Attributes) ([]*api.LimitRange, error) {
|
func (l *LimitRanger) GetLimitRanges(a admission.Attributes) ([]*corev1.LimitRange, error) {
|
||||||
items, err := l.lister.LimitRanges(a.GetNamespace()).List(labels.Everything())
|
items, err := l.lister.LimitRanges(a.GetNamespace()).List(labels.Everything())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, admission.NewForbidden(a, fmt.Errorf("unable to %s %v at this time because there was an error enforcing limit ranges", a.GetOperation(), a.GetResource()))
|
return nil, admission.NewForbidden(a, fmt.Errorf("unable to %s %v at this time because there was an error enforcing limit ranges", a.GetOperation(), a.GetResource()))
|
||||||
@ -163,7 +161,7 @@ func (l *LimitRanger) GetLimitRanges(a admission.Attributes) ([]*api.LimitRange,
|
|||||||
// If there is already in-flight List() for a given namespace, we should wait until
|
// 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
|
// it is finished and cache is updated instead of doing the same, also to avoid
|
||||||
// throttling - see #22422 for details.
|
// throttling - see #22422 for details.
|
||||||
liveList, err := l.client.Core().LimitRanges(a.GetNamespace()).List(metav1.ListOptions{})
|
liveList, err := l.client.CoreV1().LimitRanges(a.GetNamespace()).List(metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, admission.NewForbidden(a, err)
|
return nil, admission.NewForbidden(a, err)
|
||||||
}
|
}
|
||||||
@ -204,31 +202,24 @@ func NewLimitRanger(actions LimitRangerActions) (*LimitRanger, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = kubeapiserveradmission.WantsInternalKubeInformerFactory(&LimitRanger{})
|
|
||||||
var _ = kubeapiserveradmission.WantsInternalKubeClientSet(&LimitRanger{})
|
|
||||||
|
|
||||||
func (a *LimitRanger) SetInternalKubeClientSet(client internalclientset.Interface) {
|
|
||||||
a.client = client
|
|
||||||
}
|
|
||||||
|
|
||||||
// defaultContainerResourceRequirements returns the default requirements for a container
|
// defaultContainerResourceRequirements returns the default requirements for a container
|
||||||
// the requirement.Limits are taken from the LimitRange defaults (if specified)
|
// the requirement.Limits are taken from the LimitRange defaults (if specified)
|
||||||
// the requirement.Requests are taken from the LimitRange default request (if specified)
|
// the requirement.Requests are taken from the LimitRange default request (if specified)
|
||||||
func defaultContainerResourceRequirements(limitRange *api.LimitRange) api.ResourceRequirements {
|
func defaultContainerResourceRequirements(limitRange *corev1.LimitRange) api.ResourceRequirements {
|
||||||
requirements := api.ResourceRequirements{}
|
requirements := api.ResourceRequirements{}
|
||||||
requirements.Requests = api.ResourceList{}
|
requirements.Requests = api.ResourceList{}
|
||||||
requirements.Limits = api.ResourceList{}
|
requirements.Limits = api.ResourceList{}
|
||||||
|
|
||||||
for i := range limitRange.Spec.Limits {
|
for i := range limitRange.Spec.Limits {
|
||||||
limit := limitRange.Spec.Limits[i]
|
limit := limitRange.Spec.Limits[i]
|
||||||
if limit.Type == api.LimitTypeContainer {
|
if limit.Type == corev1.LimitTypeContainer {
|
||||||
for k, v := range limit.DefaultRequest {
|
for k, v := range limit.DefaultRequest {
|
||||||
value := v.Copy()
|
value := v.Copy()
|
||||||
requirements.Requests[k] = *value
|
requirements.Requests[api.ResourceName(k)] = *value
|
||||||
}
|
}
|
||||||
for k, v := range limit.Default {
|
for k, v := range limit.Default {
|
||||||
value := v.Copy()
|
value := v.Copy()
|
||||||
requirements.Limits[k] = *value
|
requirements.Limits[api.ResourceName(k)] = *value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -309,9 +300,9 @@ func requestLimitEnforcedValues(requestQuantity, limitQuantity, enforcedQuantity
|
|||||||
}
|
}
|
||||||
|
|
||||||
// minConstraint enforces the min constraint over the specified resource
|
// minConstraint enforces the min constraint over the specified resource
|
||||||
func minConstraint(limitType api.LimitType, resourceName api.ResourceName, enforced resource.Quantity, request api.ResourceList, limit api.ResourceList) error {
|
func minConstraint(limitType string, resourceName string, enforced resource.Quantity, request api.ResourceList, limit api.ResourceList) error {
|
||||||
req, reqExists := request[resourceName]
|
req, reqExists := request[api.ResourceName(resourceName)]
|
||||||
lim, limExists := limit[resourceName]
|
lim, limExists := limit[api.ResourceName(resourceName)]
|
||||||
observedReqValue, observedLimValue, enforcedValue := requestLimitEnforcedValues(req, lim, enforced)
|
observedReqValue, observedLimValue, enforcedValue := requestLimitEnforcedValues(req, lim, enforced)
|
||||||
|
|
||||||
if !reqExists {
|
if !reqExists {
|
||||||
@ -328,8 +319,8 @@ func minConstraint(limitType api.LimitType, resourceName api.ResourceName, enfor
|
|||||||
|
|
||||||
// maxRequestConstraint enforces the max constraint over the specified resource
|
// maxRequestConstraint enforces the max constraint over the specified resource
|
||||||
// use when specify LimitType resource doesn't recognize limit values
|
// use when specify LimitType resource doesn't recognize limit values
|
||||||
func maxRequestConstraint(limitType api.LimitType, resourceName api.ResourceName, enforced resource.Quantity, request api.ResourceList) error {
|
func maxRequestConstraint(limitType string, resourceName string, enforced resource.Quantity, request api.ResourceList) error {
|
||||||
req, reqExists := request[resourceName]
|
req, reqExists := request[api.ResourceName(resourceName)]
|
||||||
observedReqValue, _, enforcedValue := requestLimitEnforcedValues(req, resource.Quantity{}, enforced)
|
observedReqValue, _, enforcedValue := requestLimitEnforcedValues(req, resource.Quantity{}, enforced)
|
||||||
|
|
||||||
if !reqExists {
|
if !reqExists {
|
||||||
@ -342,9 +333,9 @@ func maxRequestConstraint(limitType api.LimitType, resourceName api.ResourceName
|
|||||||
}
|
}
|
||||||
|
|
||||||
// maxConstraint enforces the max constraint over the specified resource
|
// maxConstraint enforces the max constraint over the specified resource
|
||||||
func maxConstraint(limitType api.LimitType, resourceName api.ResourceName, enforced resource.Quantity, request api.ResourceList, limit api.ResourceList) error {
|
func maxConstraint(limitType string, resourceName string, enforced resource.Quantity, request api.ResourceList, limit api.ResourceList) error {
|
||||||
req, reqExists := request[resourceName]
|
req, reqExists := request[api.ResourceName(resourceName)]
|
||||||
lim, limExists := limit[resourceName]
|
lim, limExists := limit[api.ResourceName(resourceName)]
|
||||||
observedReqValue, observedLimValue, enforcedValue := requestLimitEnforcedValues(req, lim, enforced)
|
observedReqValue, observedLimValue, enforcedValue := requestLimitEnforcedValues(req, lim, enforced)
|
||||||
|
|
||||||
if !limExists {
|
if !limExists {
|
||||||
@ -360,9 +351,9 @@ func maxConstraint(limitType api.LimitType, resourceName api.ResourceName, enfor
|
|||||||
}
|
}
|
||||||
|
|
||||||
// limitRequestRatioConstraint enforces the limit to request ratio over the specified resource
|
// limitRequestRatioConstraint enforces the limit to request ratio over the specified resource
|
||||||
func limitRequestRatioConstraint(limitType api.LimitType, resourceName api.ResourceName, enforced resource.Quantity, request api.ResourceList, limit api.ResourceList) error {
|
func limitRequestRatioConstraint(limitType string, resourceName string, enforced resource.Quantity, request api.ResourceList, limit api.ResourceList) error {
|
||||||
req, reqExists := request[resourceName]
|
req, reqExists := request[api.ResourceName(resourceName)]
|
||||||
lim, limExists := limit[resourceName]
|
lim, limExists := limit[api.ResourceName(resourceName)]
|
||||||
observedReqValue, observedLimValue, _ := requestLimitEnforcedValues(req, lim, enforced)
|
observedReqValue, observedLimValue, _ := requestLimitEnforcedValues(req, lim, enforced)
|
||||||
|
|
||||||
if !reqExists || (observedReqValue == int64(0)) {
|
if !reqExists || (observedReqValue == int64(0)) {
|
||||||
@ -435,7 +426,7 @@ var _ LimitRangerActions = &DefaultLimitRangerActions{}
|
|||||||
// Limit enforces resource requirements of incoming resources against enumerated constraints
|
// Limit enforces resource requirements of incoming resources against enumerated constraints
|
||||||
// on the LimitRange. It may modify the incoming object to apply default resource requirements
|
// on the LimitRange. It may modify the incoming object to apply default resource requirements
|
||||||
// if not specified, and enumerated on the LimitRange
|
// if not specified, and enumerated on the LimitRange
|
||||||
func (d *DefaultLimitRangerActions) MutateLimit(limitRange *api.LimitRange, resourceName string, obj runtime.Object) error {
|
func (d *DefaultLimitRangerActions) MutateLimit(limitRange *corev1.LimitRange, resourceName string, obj runtime.Object) error {
|
||||||
switch resourceName {
|
switch resourceName {
|
||||||
case "pods":
|
case "pods":
|
||||||
return PodMutateLimitFunc(limitRange, obj.(*api.Pod))
|
return PodMutateLimitFunc(limitRange, obj.(*api.Pod))
|
||||||
@ -446,7 +437,7 @@ func (d *DefaultLimitRangerActions) MutateLimit(limitRange *api.LimitRange, reso
|
|||||||
// Limit enforces resource requirements of incoming resources against enumerated constraints
|
// Limit enforces resource requirements of incoming resources against enumerated constraints
|
||||||
// on the LimitRange. It may modify the incoming object to apply default resource requirements
|
// on the LimitRange. It may modify the incoming object to apply default resource requirements
|
||||||
// if not specified, and enumerated on the LimitRange
|
// if not specified, and enumerated on the LimitRange
|
||||||
func (d *DefaultLimitRangerActions) ValidateLimit(limitRange *api.LimitRange, resourceName string, obj runtime.Object) error {
|
func (d *DefaultLimitRangerActions) ValidateLimit(limitRange *corev1.LimitRange, resourceName string, obj runtime.Object) error {
|
||||||
switch resourceName {
|
switch resourceName {
|
||||||
case "pods":
|
case "pods":
|
||||||
return PodValidateLimitFunc(limitRange, obj.(*api.Pod))
|
return PodValidateLimitFunc(limitRange, obj.(*api.Pod))
|
||||||
@ -467,7 +458,7 @@ func (d *DefaultLimitRangerActions) SupportsAttributes(a admission.Attributes) b
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SupportsLimit always returns true.
|
// SupportsLimit always returns true.
|
||||||
func (d *DefaultLimitRangerActions) SupportsLimit(limitRange *api.LimitRange) bool {
|
func (d *DefaultLimitRangerActions) SupportsLimit(limitRange *corev1.LimitRange) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -475,22 +466,22 @@ func (d *DefaultLimitRangerActions) SupportsLimit(limitRange *api.LimitRange) bo
|
|||||||
// Users request storage via pvc.Spec.Resources.Requests. Min/Max is enforced by an admin with LimitRange.
|
// Users request storage via pvc.Spec.Resources.Requests. Min/Max is enforced by an admin with LimitRange.
|
||||||
// Claims will not be modified with default values because storage is a required part of pvc.Spec.
|
// Claims will not be modified with default values because storage is a required part of pvc.Spec.
|
||||||
// All storage enforced values *only* apply to pvc.Spec.Resources.Requests.
|
// All storage enforced values *only* apply to pvc.Spec.Resources.Requests.
|
||||||
func PersistentVolumeClaimValidateLimitFunc(limitRange *api.LimitRange, pvc *api.PersistentVolumeClaim) error {
|
func PersistentVolumeClaimValidateLimitFunc(limitRange *corev1.LimitRange, pvc *api.PersistentVolumeClaim) error {
|
||||||
var errs []error
|
var errs []error
|
||||||
for i := range limitRange.Spec.Limits {
|
for i := range limitRange.Spec.Limits {
|
||||||
limit := limitRange.Spec.Limits[i]
|
limit := limitRange.Spec.Limits[i]
|
||||||
limitType := limit.Type
|
limitType := limit.Type
|
||||||
if limitType == api.LimitTypePersistentVolumeClaim {
|
if limitType == corev1.LimitTypePersistentVolumeClaim {
|
||||||
for k, v := range limit.Min {
|
for k, v := range limit.Min {
|
||||||
// normal usage of minConstraint. pvc.Spec.Resources.Limits is not recognized as user input
|
// normal usage of minConstraint. pvc.Spec.Resources.Limits is not recognized as user input
|
||||||
if err := minConstraint(limitType, k, v, pvc.Spec.Resources.Requests, api.ResourceList{}); err != nil {
|
if err := minConstraint(string(limitType), string(k), v, pvc.Spec.Resources.Requests, api.ResourceList{}); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for k, v := range limit.Max {
|
for k, v := range limit.Max {
|
||||||
// We want to enforce the max of the LimitRange against what
|
// We want to enforce the max of the LimitRange against what
|
||||||
// the user requested.
|
// the user requested.
|
||||||
if err := maxRequestConstraint(limitType, k, v, pvc.Spec.Resources.Requests); err != nil {
|
if err := maxRequestConstraint(string(limitType), string(k), v, pvc.Spec.Resources.Requests); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -502,7 +493,7 @@ func PersistentVolumeClaimValidateLimitFunc(limitRange *api.LimitRange, pvc *api
|
|||||||
// PodMutateLimitFunc sets resource requirements enumerated by the pod against
|
// PodMutateLimitFunc sets resource requirements enumerated by the pod against
|
||||||
// the specified LimitRange. The pod may be modified to apply default resource
|
// the specified LimitRange. The pod may be modified to apply default resource
|
||||||
// requirements if not specified, and enumerated on the LimitRange
|
// requirements if not specified, and enumerated on the LimitRange
|
||||||
func PodMutateLimitFunc(limitRange *api.LimitRange, pod *api.Pod) error {
|
func PodMutateLimitFunc(limitRange *corev1.LimitRange, pod *api.Pod) error {
|
||||||
defaultResources := defaultContainerResourceRequirements(limitRange)
|
defaultResources := defaultContainerResourceRequirements(limitRange)
|
||||||
mergePodResourceRequirements(pod, &defaultResources)
|
mergePodResourceRequirements(pod, &defaultResources)
|
||||||
return nil
|
return nil
|
||||||
@ -510,28 +501,28 @@ func PodMutateLimitFunc(limitRange *api.LimitRange, pod *api.Pod) error {
|
|||||||
|
|
||||||
// PodValidateLimitFunc enforces resource requirements enumerated by the pod against
|
// PodValidateLimitFunc enforces resource requirements enumerated by the pod against
|
||||||
// the specified LimitRange.
|
// the specified LimitRange.
|
||||||
func PodValidateLimitFunc(limitRange *api.LimitRange, pod *api.Pod) error {
|
func PodValidateLimitFunc(limitRange *corev1.LimitRange, pod *api.Pod) error {
|
||||||
var errs []error
|
var errs []error
|
||||||
|
|
||||||
for i := range limitRange.Spec.Limits {
|
for i := range limitRange.Spec.Limits {
|
||||||
limit := limitRange.Spec.Limits[i]
|
limit := limitRange.Spec.Limits[i]
|
||||||
limitType := limit.Type
|
limitType := limit.Type
|
||||||
// enforce container limits
|
// enforce container limits
|
||||||
if limitType == api.LimitTypeContainer {
|
if limitType == corev1.LimitTypeContainer {
|
||||||
for j := range pod.Spec.Containers {
|
for j := range pod.Spec.Containers {
|
||||||
container := &pod.Spec.Containers[j]
|
container := &pod.Spec.Containers[j]
|
||||||
for k, v := range limit.Min {
|
for k, v := range limit.Min {
|
||||||
if err := minConstraint(limitType, k, v, container.Resources.Requests, container.Resources.Limits); err != nil {
|
if err := minConstraint(string(limitType), string(k), v, container.Resources.Requests, container.Resources.Limits); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for k, v := range limit.Max {
|
for k, v := range limit.Max {
|
||||||
if err := maxConstraint(limitType, k, v, container.Resources.Requests, container.Resources.Limits); err != nil {
|
if err := maxConstraint(string(limitType), string(k), v, container.Resources.Requests, container.Resources.Limits); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for k, v := range limit.MaxLimitRequestRatio {
|
for k, v := range limit.MaxLimitRequestRatio {
|
||||||
if err := limitRequestRatioConstraint(limitType, k, v, container.Resources.Requests, container.Resources.Limits); err != nil {
|
if err := limitRequestRatioConstraint(string(limitType), string(k), v, container.Resources.Requests, container.Resources.Limits); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -539,17 +530,17 @@ func PodValidateLimitFunc(limitRange *api.LimitRange, pod *api.Pod) error {
|
|||||||
for j := range pod.Spec.InitContainers {
|
for j := range pod.Spec.InitContainers {
|
||||||
container := &pod.Spec.InitContainers[j]
|
container := &pod.Spec.InitContainers[j]
|
||||||
for k, v := range limit.Min {
|
for k, v := range limit.Min {
|
||||||
if err := minConstraint(limitType, k, v, container.Resources.Requests, container.Resources.Limits); err != nil {
|
if err := minConstraint(string(limitType), string(k), v, container.Resources.Requests, container.Resources.Limits); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for k, v := range limit.Max {
|
for k, v := range limit.Max {
|
||||||
if err := maxConstraint(limitType, k, v, container.Resources.Requests, container.Resources.Limits); err != nil {
|
if err := maxConstraint(string(limitType), string(k), v, container.Resources.Requests, container.Resources.Limits); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for k, v := range limit.MaxLimitRequestRatio {
|
for k, v := range limit.MaxLimitRequestRatio {
|
||||||
if err := limitRequestRatioConstraint(limitType, k, v, container.Resources.Requests, container.Resources.Limits); err != nil {
|
if err := limitRequestRatioConstraint(string(limitType), string(k), v, container.Resources.Requests, container.Resources.Limits); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -557,7 +548,7 @@ func PodValidateLimitFunc(limitRange *api.LimitRange, pod *api.Pod) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// enforce pod limits on init containers
|
// enforce pod limits on init containers
|
||||||
if limitType == api.LimitTypePod {
|
if limitType == corev1.LimitTypePod {
|
||||||
containerRequests, containerLimits := []api.ResourceList{}, []api.ResourceList{}
|
containerRequests, containerLimits := []api.ResourceList{}, []api.ResourceList{}
|
||||||
for j := range pod.Spec.Containers {
|
for j := range pod.Spec.Containers {
|
||||||
container := &pod.Spec.Containers[j]
|
container := &pod.Spec.Containers[j]
|
||||||
@ -589,17 +580,17 @@ func PodValidateLimitFunc(limitRange *api.LimitRange, pod *api.Pod) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for k, v := range limit.Min {
|
for k, v := range limit.Min {
|
||||||
if err := minConstraint(limitType, k, v, podRequests, podLimits); err != nil {
|
if err := minConstraint(string(limitType), string(k), v, podRequests, podLimits); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for k, v := range limit.Max {
|
for k, v := range limit.Max {
|
||||||
if err := maxConstraint(limitType, k, v, podRequests, podLimits); err != nil {
|
if err := maxConstraint(string(limitType), string(k), v, podRequests, podLimits); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for k, v := range limit.MaxLimitRequestRatio {
|
for k, v := range limit.MaxLimitRequestRatio {
|
||||||
if err := limitRequestRatioConstraint(limitType, k, v, podRequests, podLimits); err != nil {
|
if err := limitRequestRatioConstraint(string(limitType), string(k), v, podRequests, podLimits); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,18 +22,20 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
|
genericadmissioninitializer "k8s.io/apiserver/pkg/admission/initializer"
|
||||||
|
"k8s.io/client-go/informers"
|
||||||
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
core "k8s.io/client-go/testing"
|
core "k8s.io/client-go/testing"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
"k8s.io/kubernetes/pkg/apis/core/v1"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
|
|
||||||
informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion"
|
|
||||||
kubeadmission "k8s.io/kubernetes/pkg/kubeapiserver/admission"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func getComputeResourceList(cpu, memory string) api.ResourceList {
|
func getComputeResourceList(cpu, memory string) api.ResourceList {
|
||||||
@ -63,8 +65,8 @@ func getResourceRequirements(requests, limits api.ResourceList) api.ResourceRequ
|
|||||||
}
|
}
|
||||||
|
|
||||||
// createLimitRange creates a limit range with the specified data
|
// createLimitRange creates a limit range with the specified data
|
||||||
func createLimitRange(limitType api.LimitType, min, max, defaultLimit, defaultRequest, maxLimitRequestRatio api.ResourceList) api.LimitRange {
|
func createLimitRange(limitType api.LimitType, min, max, defaultLimit, defaultRequest, maxLimitRequestRatio api.ResourceList) corev1.LimitRange {
|
||||||
return api.LimitRange{
|
internalLimitRage := api.LimitRange{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "abc",
|
Name: "abc",
|
||||||
Namespace: "test",
|
Namespace: "test",
|
||||||
@ -82,10 +84,13 @@ func createLimitRange(limitType api.LimitType, min, max, defaultLimit, defaultRe
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
externalLimitRange := corev1.LimitRange{}
|
||||||
|
v1.Convert_core_LimitRange_To_v1_LimitRange(&internalLimitRage, &externalLimitRange, nil)
|
||||||
|
return externalLimitRange
|
||||||
}
|
}
|
||||||
|
|
||||||
func validLimitRange() api.LimitRange {
|
func validLimitRange() corev1.LimitRange {
|
||||||
return api.LimitRange{
|
internalLimitRange := api.LimitRange{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "abc",
|
Name: "abc",
|
||||||
Namespace: "test",
|
Namespace: "test",
|
||||||
@ -107,10 +112,13 @@ func validLimitRange() api.LimitRange {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
externalLimitRange := corev1.LimitRange{}
|
||||||
|
v1.Convert_core_LimitRange_To_v1_LimitRange(&internalLimitRange, &externalLimitRange, nil)
|
||||||
|
return externalLimitRange
|
||||||
}
|
}
|
||||||
|
|
||||||
func validLimitRangeNoDefaults() api.LimitRange {
|
func validLimitRangeNoDefaults() corev1.LimitRange {
|
||||||
return api.LimitRange{
|
internalLimitRange := api.LimitRange{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "abc",
|
Name: "abc",
|
||||||
Namespace: "test",
|
Namespace: "test",
|
||||||
@ -130,6 +138,9 @@ func validLimitRangeNoDefaults() api.LimitRange {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
externalLimitRange := corev1.LimitRange{}
|
||||||
|
v1.Convert_core_LimitRange_To_v1_LimitRange(&internalLimitRange, &externalLimitRange, nil)
|
||||||
|
return externalLimitRange
|
||||||
}
|
}
|
||||||
|
|
||||||
func validPod(name string, numContainers int, resources api.ResourceRequirements) api.Pod {
|
func validPod(name string, numContainers int, resources api.ResourceRequirements) api.Pod {
|
||||||
@ -255,7 +266,7 @@ func TestMergePodResourceRequirements(t *testing.T) {
|
|||||||
func TestPodLimitFunc(t *testing.T) {
|
func TestPodLimitFunc(t *testing.T) {
|
||||||
type testCase struct {
|
type testCase struct {
|
||||||
pod api.Pod
|
pod api.Pod
|
||||||
limitRange api.LimitRange
|
limitRange corev1.LimitRange
|
||||||
}
|
}
|
||||||
|
|
||||||
successCases := []testCase{
|
successCases := []testCase{
|
||||||
@ -686,7 +697,7 @@ func TestPodLimitFuncApplyDefault(t *testing.T) {
|
|||||||
|
|
||||||
func TestLimitRangerIgnoresSubresource(t *testing.T) {
|
func TestLimitRangerIgnoresSubresource(t *testing.T) {
|
||||||
limitRange := validLimitRangeNoDefaults()
|
limitRange := validLimitRangeNoDefaults()
|
||||||
mockClient := newMockClientForTest([]api.LimitRange{limitRange})
|
mockClient := newMockClientForTest([]corev1.LimitRange{limitRange})
|
||||||
handler, informerFactory, err := newHandlerForTest(mockClient)
|
handler, informerFactory, err := newHandlerForTest(mockClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error initializing handler: %v", err)
|
t.Errorf("unexpected error initializing handler: %v", err)
|
||||||
@ -712,7 +723,7 @@ func TestLimitRangerIgnoresSubresource(t *testing.T) {
|
|||||||
|
|
||||||
func TestLimitRangerAdmitPod(t *testing.T) {
|
func TestLimitRangerAdmitPod(t *testing.T) {
|
||||||
limitRange := validLimitRangeNoDefaults()
|
limitRange := validLimitRangeNoDefaults()
|
||||||
mockClient := newMockClientForTest([]api.LimitRange{limitRange})
|
mockClient := newMockClientForTest([]corev1.LimitRange{limitRange})
|
||||||
handler, informerFactory, err := newHandlerForTest(mockClient)
|
handler, informerFactory, err := newHandlerForTest(mockClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("unexpected error initializing handler: %v", err)
|
t.Errorf("unexpected error initializing handler: %v", err)
|
||||||
@ -745,10 +756,10 @@ func TestLimitRangerAdmitPod(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// newMockClientForTest creates a mock client that returns a client configured for the specified list of limit ranges
|
// newMockClientForTest creates a mock client that returns a client configured for the specified list of limit ranges
|
||||||
func newMockClientForTest(limitRanges []api.LimitRange) *fake.Clientset {
|
func newMockClientForTest(limitRanges []corev1.LimitRange) *fake.Clientset {
|
||||||
mockClient := &fake.Clientset{}
|
mockClient := &fake.Clientset{}
|
||||||
mockClient.AddReactor("list", "limitranges", func(action core.Action) (bool, runtime.Object, error) {
|
mockClient.AddReactor("list", "limitranges", func(action core.Action) (bool, runtime.Object, error) {
|
||||||
limitRangeList := &api.LimitRangeList{
|
limitRangeList := &corev1.LimitRangeList{
|
||||||
ListMeta: metav1.ListMeta{
|
ListMeta: metav1.ListMeta{
|
||||||
ResourceVersion: fmt.Sprintf("%d", len(limitRanges)),
|
ResourceVersion: fmt.Sprintf("%d", len(limitRanges)),
|
||||||
},
|
},
|
||||||
@ -769,7 +780,7 @@ func newHandlerForTest(c clientset.Interface) (*LimitRanger, informers.SharedInf
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, f, err
|
return nil, f, err
|
||||||
}
|
}
|
||||||
pluginInitializer := kubeadmission.NewPluginInitializer(c, f, nil, nil, nil)
|
pluginInitializer := genericadmissioninitializer.New(c, f, nil, nil)
|
||||||
pluginInitializer.Initialize(handler)
|
pluginInitializer.Initialize(handler)
|
||||||
err = admission.ValidateInitialization(handler)
|
err = admission.ValidateInitialization(handler)
|
||||||
return handler, f, err
|
return handler, f, err
|
||||||
@ -788,7 +799,7 @@ func validPersistentVolumeClaim(name string, resources api.ResourceRequirements)
|
|||||||
func TestPersistentVolumeClaimLimitFunc(t *testing.T) {
|
func TestPersistentVolumeClaimLimitFunc(t *testing.T) {
|
||||||
type testCase struct {
|
type testCase struct {
|
||||||
pvc api.PersistentVolumeClaim
|
pvc api.PersistentVolumeClaim
|
||||||
limitRange api.LimitRange
|
limitRange corev1.LimitRange
|
||||||
}
|
}
|
||||||
|
|
||||||
successCases := []testCase{
|
successCases := []testCase{
|
||||||
|
@ -17,20 +17,20 @@ limitations under the License.
|
|||||||
package limitranger
|
package limitranger
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type LimitRangerActions interface {
|
type LimitRangerActions interface {
|
||||||
// MutateLimit is a pluggable function to set limits on the object.
|
// MutateLimit is a pluggable function to set limits on the object.
|
||||||
MutateLimit(limitRange *api.LimitRange, kind string, obj runtime.Object) error
|
MutateLimit(limitRange *corev1.LimitRange, kind string, obj runtime.Object) error
|
||||||
// ValidateLimits is a pluggable function to enforce limits on the object.
|
// ValidateLimits is a pluggable function to enforce limits on the object.
|
||||||
ValidateLimit(limitRange *api.LimitRange, kind string, obj runtime.Object) error
|
ValidateLimit(limitRange *corev1.LimitRange, kind string, obj runtime.Object) error
|
||||||
// SupportsAttributes is a pluggable function to allow overridding what resources the limitranger
|
// SupportsAttributes is a pluggable function to allow overridding what resources the limitranger
|
||||||
// supports.
|
// supports.
|
||||||
SupportsAttributes(attr admission.Attributes) bool
|
SupportsAttributes(attr admission.Attributes) bool
|
||||||
// SupportsLimit is a pluggable function to allow ignoring limits that should not be applied
|
// SupportsLimit is a pluggable function to allow ignoring limits that should not be applied
|
||||||
// for any reason.
|
// for any reason.
|
||||||
SupportsLimit(limitRange *api.LimitRange) bool
|
SupportsLimit(limitRange *corev1.LimitRange) bool
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user