Merge pull request #23280 from pweil-/limitrange-supportsfunc

Auto commit by PR queue bot
This commit is contained in:
k8s-merge-robot 2016-03-22 22:00:47 -07:00
commit 6441e1fc33
3 changed files with 68 additions and 35 deletions

View File

@ -43,16 +43,16 @@ const (
func init() {
admission.RegisterPlugin("LimitRanger", func(client clientset.Interface, config io.Reader) (admission.Interface, error) {
return NewLimitRanger(client, Limit)
return NewLimitRanger(client, &DefaultLimitRangerActions{})
})
}
// limitRanger enforces usage limits on a per resource basis in the namespace
type limitRanger struct {
*admission.Handler
client clientset.Interface
limitFunc LimitFunc
indexer cache.Indexer
client clientset.Interface
actions LimitRangerActions
indexer cache.Indexer
// 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.
@ -68,14 +68,7 @@ type liveLookupEntry struct {
// Admit admits resources into cluster that do not violate any defined LimitRange in the namespace
func (l *limitRanger) Admit(a admission.Attributes) (err error) {
// Ignore all calls to subresources
if a.GetSubresource() != "" {
return nil
}
// ignore all calls that do not deal with pod resources since that is all this supports now.
if a.GetKind() != api.Kind("Pod") {
if !l.actions.SupportsAttributes(a) {
return nil
}
@ -130,7 +123,12 @@ func (l *limitRanger) Admit(a admission.Attributes) (err error) {
// ensure it meets each prescribed min/max
for i := range items {
limitRange := items[i].(*api.LimitRange)
err = l.limitFunc(limitRange, a.GetResource().Resource, a.GetObject())
if !l.actions.SupportsLimit(limitRange) {
continue
}
err = l.actions.Limit(limitRange, a.GetResource().Resource, a.GetObject())
if err != nil {
return admission.NewForbidden(a, err)
}
@ -139,7 +137,7 @@ func (l *limitRanger) Admit(a admission.Attributes) (err error) {
}
// NewLimitRanger returns an object that enforces limits based on the supplied limit function
func NewLimitRanger(client clientset.Interface, limitFunc LimitFunc) (admission.Interface, error) {
func NewLimitRanger(client clientset.Interface, actions LimitRangerActions) (admission.Interface, error) {
liveLookupCache, err := lru.New(10000)
if err != nil {
return nil, err
@ -155,10 +153,15 @@ func NewLimitRanger(client clientset.Interface, limitFunc LimitFunc) (admission.
}
indexer, reflector := cache.NewNamespaceKeyedIndexerAndReflector(lw, &api.LimitRange{}, 0)
reflector.Run()
if actions == nil {
actions = &DefaultLimitRangerActions{}
}
return &limitRanger{
Handler: admission.NewHandler(admission.Create, admission.Update),
client: client,
limitFunc: limitFunc,
actions: actions,
indexer: indexer,
liveLookupCache: liveLookupCache,
liveTTL: time.Duration(30 * time.Second),
@ -181,17 +184,6 @@ func Max(a int64, b int64) int64 {
return b
}
// Limit enforces resource requirements of incoming resources against enumerated constraints
// on the LimitRange. It may modify the incoming object to apply default resource requirements
// if not specified, and enumerated on the LimitRange
func Limit(limitRange *api.LimitRange, resourceName string, obj runtime.Object) error {
switch resourceName {
case "pods":
return PodLimitFunc(limitRange, obj.(*api.Pod))
}
return nil
}
// defaultContainerResourceRequirements returns the default requirements for a container
// the requirement.Limits are taken from the LimitRange defaults (if specified)
// the requirement.Requests are taken from the LimitRange default request (if specified)
@ -383,6 +375,38 @@ func sum(inputs []api.ResourceList) api.ResourceList {
return result
}
// DefaultLimitRangerActions is the default implementatation of LimitRangerActions.
type DefaultLimitRangerActions struct{}
// ensure DefaultLimitRangerActions implements the LimitRangerActions interface.
var _ LimitRangerActions = &DefaultLimitRangerActions{}
// Limit enforces resource requirements of incoming resources against enumerated constraints
// on the LimitRange. It may modify the incoming object to apply default resource requirements
// if not specified, and enumerated on the LimitRange
func (d *DefaultLimitRangerActions) Limit(limitRange *api.LimitRange, resourceName string, obj runtime.Object) error {
switch resourceName {
case "pods":
return PodLimitFunc(limitRange, obj.(*api.Pod))
}
return nil
}
// SupportsAttributes ignores all calls that do not deal with pod resources since that is
// all this supports now. Also ignores any call that has a subresource defined.
func (d *DefaultLimitRangerActions) SupportsAttributes(a admission.Attributes) bool {
if a.GetSubresource() != "" {
return false
}
return a.GetKind() == api.Kind("Pod")
}
// SupportsLimit always returns true.
func (d *DefaultLimitRangerActions) SupportsLimit(limitRange *api.LimitRange) bool {
return true
}
// PodLimitFunc enforces resource requirements enumerated by the pod against
// the specified LimitRange. The pod may be modified to apply default resource
// requirements if not specified, and enumerated on the LimitRange

View File

@ -435,10 +435,10 @@ func TestLimitRangerIgnoresSubresource(t *testing.T) {
client := fake.NewSimpleClientset()
indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{"namespace": cache.MetaNamespaceIndexFunc})
handler := &limitRanger{
Handler: admission.NewHandler(admission.Create, admission.Update),
client: client,
limitFunc: Limit,
indexer: indexer,
Handler: admission.NewHandler(admission.Create, admission.Update),
client: client,
actions: &DefaultLimitRangerActions{},
indexer: indexer,
}
limitRange := validLimitRangeNoDefaults()
@ -468,7 +468,7 @@ func TestLimitRangerCacheMisses(t *testing.T) {
handler := &limitRanger{
Handler: admission.NewHandler(admission.Create, admission.Update),
client: client,
limitFunc: Limit,
actions: &DefaultLimitRangerActions{},
indexer: indexer,
liveLookupCache: liveLookupCache,
}
@ -502,7 +502,7 @@ func TestLimitRangerCacheAndLRUMisses(t *testing.T) {
handler := &limitRanger{
Handler: admission.NewHandler(admission.Create, admission.Update),
client: client,
limitFunc: Limit,
actions: &DefaultLimitRangerActions{},
indexer: indexer,
liveLookupCache: liveLookupCache,
}
@ -532,7 +532,7 @@ func TestLimitRangerCacheAndLRUExpiredMisses(t *testing.T) {
handler := &limitRanger{
Handler: admission.NewHandler(admission.Create, admission.Update),
client: client,
limitFunc: Limit,
actions: &DefaultLimitRangerActions{},
indexer: indexer,
liveLookupCache: liveLookupCache,
}

View File

@ -17,9 +17,18 @@ limitations under the License.
package limitranger
import (
"k8s.io/kubernetes/pkg/admission"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/runtime"
)
// LimitFunc is a pluggable function to enforce limits on the object
type LimitFunc func(limitRange *api.LimitRange, kind string, obj runtime.Object) error
type LimitRangerActions interface {
// Limit is a pluggable function to enforce limits on the object.
Limit(limitRange *api.LimitRange, kind string, obj runtime.Object) error
// SupportsAttributes is a pluggable function to allow overridding what resources the limitranger
// supports.
SupportsAttributes(attr admission.Attributes) bool
// SupportsLimit is a pluggable function to allow ignoring limits that should not be applied
// for any reason.
SupportsLimit(limitRange *api.LimitRange) bool
}