update admission control to properly indicate resource

pull/6/head
deads2k 2015-01-30 08:16:46 -05:00
parent 8a2fe9bd2b
commit 889c4cc755
6 changed files with 27 additions and 27 deletions

View File

@ -22,15 +22,15 @@ import (
type attributesRecord struct { type attributesRecord struct {
namespace string namespace string
kind string resource string
operation string operation string
object runtime.Object object runtime.Object
} }
func NewAttributesRecord(object runtime.Object, namespace, kind, operation string) Attributes { func NewAttributesRecord(object runtime.Object, namespace, resource, operation string) Attributes {
return &attributesRecord{ return &attributesRecord{
namespace: namespace, namespace: namespace,
kind: kind, resource: resource,
operation: operation, operation: operation,
object: object, object: object,
} }
@ -40,8 +40,8 @@ func (record *attributesRecord) GetNamespace() string {
return record.namespace return record.namespace
} }
func (record *attributesRecord) GetKind() string { func (record *attributesRecord) GetResource() string {
return record.kind return record.resource
} }
func (record *attributesRecord) GetOperation() string { func (record *attributesRecord) GetOperation() string {

View File

@ -24,7 +24,7 @@ import (
// that is used to make an admission decision. // that is used to make an admission decision.
type Attributes interface { type Attributes interface {
GetNamespace() string GetNamespace() string
GetKind() string GetResource() string
GetOperation() string GetOperation() string
GetObject() runtime.Object GetObject() runtime.Object
} }

View File

@ -36,7 +36,7 @@ func init() {
type alwaysDeny struct{} type alwaysDeny struct{}
func (alwaysDeny) Admit(a admission.Attributes) (err error) { func (alwaysDeny) Admit(a admission.Attributes) (err error) {
return apierrors.NewForbidden(a.GetKind(), "", errors.New("Admission control is denying all modifications")) return apierrors.NewForbidden(a.GetResource(), "", errors.New("Admission control is denying all modifications"))
} }
func NewAlwaysDeny() admission.Interface { func NewAlwaysDeny() admission.Interface {

View File

@ -58,7 +58,7 @@ func (l *limitRanger) Admit(a admission.Attributes) (err error) {
// ensure it meets each prescribed min/max // ensure it meets each prescribed min/max
for i := range items.Items { for i := range items.Items {
limitRange := &items.Items[i] limitRange := &items.Items[i]
err = l.limitFunc(limitRange, a.GetKind(), a.GetObject()) err = l.limitFunc(limitRange, a.GetResource(), a.GetObject())
if err != nil { if err != nil {
return err return err
} }
@ -86,8 +86,8 @@ func Max(a int64, b int64) int64 {
} }
// PodLimitFunc enforces that a pod spec does not exceed any limits specified on the supplied limit range // PodLimitFunc enforces that a pod spec does not exceed any limits specified on the supplied limit range
func PodLimitFunc(limitRange *api.LimitRange, kind string, obj runtime.Object) error { func PodLimitFunc(limitRange *api.LimitRange, resourceName string, obj runtime.Object) error {
if kind != "pods" { if resourceName != "pods" {
return nil return nil
} }
@ -161,11 +161,11 @@ func PodLimitFunc(limitRange *api.LimitRange, kind string, obj runtime.Object) e
switch minOrMax { switch minOrMax {
case "Min": case "Min":
if observed < enforced { if observed < enforced {
return apierrors.NewForbidden(kind, pod.Name, err) return apierrors.NewForbidden(resourceName, pod.Name, err)
} }
case "Max": case "Max":
if observed > enforced { if observed > enforced {
return apierrors.NewForbidden(kind, pod.Name, err) return apierrors.NewForbidden(resourceName, pod.Name, err)
} }
} }
} }

View File

@ -47,7 +47,7 @@ func (resourceDefaults) Admit(a admission.Attributes) (err error) {
} }
// we only care about pods // we only care about pods
if a.GetKind() != "pods" { if a.GetResource() != "pods" {
return nil return nil
} }

View File

@ -44,7 +44,7 @@ func NewResourceQuota(client client.Interface) admission.Interface {
return &quota{client: client} return &quota{client: client}
} }
var kindToResourceName = map[string]api.ResourceName{ var resourceToResourceName = map[string]api.ResourceName{
"pods": api.ResourcePods, "pods": api.ResourcePods,
"services": api.ResourceServices, "services": api.ResourceServices,
"replicationControllers": api.ResourceReplicationControllers, "replicationControllers": api.ResourceReplicationControllers,
@ -57,7 +57,7 @@ func (q *quota) Admit(a admission.Attributes) (err error) {
} }
obj := a.GetObject() obj := a.GetObject()
kind := a.GetKind() resource := a.GetResource()
name := "Unknown" name := "Unknown"
if obj != nil { if obj != nil {
name, _ = meta.NewAccessor().Name(obj) name, _ = meta.NewAccessor().Name(obj)
@ -65,7 +65,7 @@ func (q *quota) Admit(a admission.Attributes) (err error) {
list, err := q.client.ResourceQuotas(a.GetNamespace()).List(labels.Everything()) list, err := q.client.ResourceQuotas(a.GetNamespace()).List(labels.Everything())
if err != nil { if err != nil {
return apierrors.NewForbidden(a.GetKind(), name, fmt.Errorf("Unable to %s %s at this time because there was an error enforcing quota", a.GetOperation(), kind)) return apierrors.NewForbidden(a.GetResource(), name, fmt.Errorf("Unable to %s %s at this time because there was an error enforcing quota", a.GetOperation(), resource))
} }
if len(list.Items) == 0 { if len(list.Items) == 0 {
@ -90,7 +90,7 @@ func (q *quota) Admit(a admission.Attributes) (err error) {
usage.Status = quota.Status usage.Status = quota.Status
err = q.client.ResourceQuotaUsages(usage.Namespace).Create(&usage) err = q.client.ResourceQuotaUsages(usage.Namespace).Create(&usage)
if err != nil { if err != nil {
return apierrors.NewForbidden(a.GetKind(), name, fmt.Errorf("Unable to %s %s at this time because there was an error enforcing quota", a.GetOperation(), a.GetKind())) return apierrors.NewForbidden(a.GetResource(), name, fmt.Errorf("Unable to %s %s at this time because there was an error enforcing quota", a.GetOperation(), a.GetResource()))
} }
} }
} }
@ -102,7 +102,7 @@ func (q *quota) Admit(a admission.Attributes) (err error) {
// Return an error if the operation should not pass admission control // Return an error if the operation should not pass admission control
func IncrementUsage(a admission.Attributes, status *api.ResourceQuotaStatus, client client.Interface) (bool, error) { func IncrementUsage(a admission.Attributes, status *api.ResourceQuotaStatus, client client.Interface) (bool, error) {
obj := a.GetObject() obj := a.GetObject()
kind := a.GetKind() resourceName := a.GetResource()
name := "Unknown" name := "Unknown"
if obj != nil { if obj != nil {
name, _ = meta.NewAccessor().Name(obj) name, _ = meta.NewAccessor().Name(obj)
@ -114,15 +114,15 @@ func IncrementUsage(a admission.Attributes, status *api.ResourceQuotaStatus, cli
} }
// handle max counts for each kind of resource (pods, services, replicationControllers, etc.) // handle max counts for each kind of resource (pods, services, replicationControllers, etc.)
if a.GetOperation() == "CREATE" { if a.GetOperation() == "CREATE" {
resourceName := kindToResourceName[a.GetKind()] resourceName := resourceToResourceName[a.GetResource()]
hard, hardFound := status.Hard[resourceName] hard, hardFound := status.Hard[resourceName]
if hardFound { if hardFound {
used, usedFound := status.Used[resourceName] used, usedFound := status.Used[resourceName]
if !usedFound { if !usedFound {
return false, apierrors.NewForbidden(kind, name, fmt.Errorf("Quota usage stats are not yet known, unable to admit resource until an accurate count is completed.")) return false, apierrors.NewForbidden(a.GetResource(), name, fmt.Errorf("Quota usage stats are not yet known, unable to admit resource until an accurate count is completed."))
} }
if used.Value() >= hard.Value() { if used.Value() >= hard.Value() {
return false, apierrors.NewForbidden(kind, name, fmt.Errorf("Limited to %s %s", hard.String(), kind)) return false, apierrors.NewForbidden(a.GetResource(), name, fmt.Errorf("Limited to %s %s", hard.String(), a.GetResource()))
} else { } else {
status.Used[resourceName] = *resource.NewQuantity(used.Value()+int64(1), resource.DecimalSI) status.Used[resourceName] = *resource.NewQuantity(used.Value()+int64(1), resource.DecimalSI)
dirty = true dirty = true
@ -130,7 +130,7 @@ func IncrementUsage(a admission.Attributes, status *api.ResourceQuotaStatus, cli
} }
} }
// handle memory/cpu constraints, and any diff of usage based on memory/cpu on updates // handle memory/cpu constraints, and any diff of usage based on memory/cpu on updates
if a.GetKind() == "pods" && (set[api.ResourceMemory] || set[api.ResourceCPU]) { if a.GetResource() == "pods" && (set[api.ResourceMemory] || set[api.ResourceCPU]) {
pod := obj.(*api.Pod) pod := obj.(*api.Pod)
deltaCPU := resourcequota.PodCPU(pod) deltaCPU := resourcequota.PodCPU(pod)
deltaMemory := resourcequota.PodMemory(pod) deltaMemory := resourcequota.PodMemory(pod)
@ -138,7 +138,7 @@ func IncrementUsage(a admission.Attributes, status *api.ResourceQuotaStatus, cli
if a.GetOperation() == "UPDATE" { if a.GetOperation() == "UPDATE" {
oldPod, err := client.Pods(a.GetNamespace()).Get(pod.Name) oldPod, err := client.Pods(a.GetNamespace()).Get(pod.Name)
if err != nil { if err != nil {
return false, apierrors.NewForbidden(kind, name, err) return false, apierrors.NewForbidden(resourceName, name, err)
} }
oldCPU := resourcequota.PodCPU(oldPod) oldCPU := resourcequota.PodCPU(oldPod)
oldMemory := resourcequota.PodMemory(oldPod) oldMemory := resourcequota.PodMemory(oldPod)
@ -150,10 +150,10 @@ func IncrementUsage(a admission.Attributes, status *api.ResourceQuotaStatus, cli
if hardMemFound { if hardMemFound {
used, usedFound := status.Used[api.ResourceMemory] used, usedFound := status.Used[api.ResourceMemory]
if !usedFound { if !usedFound {
return false, apierrors.NewForbidden(kind, name, fmt.Errorf("Quota usage stats are not yet known, unable to admit resource until an accurate count is completed.")) return false, apierrors.NewForbidden(resourceName, name, fmt.Errorf("Quota usage stats are not yet known, unable to admit resource until an accurate count is completed."))
} }
if used.Value()+deltaMemory.Value() > hardMem.Value() { if used.Value()+deltaMemory.Value() > hardMem.Value() {
return false, apierrors.NewForbidden(kind, name, fmt.Errorf("Limited to %s memory", hardMem.String())) return false, apierrors.NewForbidden(resourceName, name, fmt.Errorf("Limited to %s memory", hardMem.String()))
} else { } else {
status.Used[api.ResourceMemory] = *resource.NewQuantity(used.Value()+deltaMemory.Value(), resource.DecimalSI) status.Used[api.ResourceMemory] = *resource.NewQuantity(used.Value()+deltaMemory.Value(), resource.DecimalSI)
dirty = true dirty = true
@ -163,10 +163,10 @@ func IncrementUsage(a admission.Attributes, status *api.ResourceQuotaStatus, cli
if hardCPUFound { if hardCPUFound {
used, usedFound := status.Used[api.ResourceCPU] used, usedFound := status.Used[api.ResourceCPU]
if !usedFound { if !usedFound {
return false, apierrors.NewForbidden(kind, name, fmt.Errorf("Quota usage stats are not yet known, unable to admit resource until an accurate count is completed.")) return false, apierrors.NewForbidden(resourceName, name, fmt.Errorf("Quota usage stats are not yet known, unable to admit resource until an accurate count is completed."))
} }
if used.MilliValue()+deltaCPU.MilliValue() > hardCPU.MilliValue() { if used.MilliValue()+deltaCPU.MilliValue() > hardCPU.MilliValue() {
return false, apierrors.NewForbidden(kind, name, fmt.Errorf("Limited to %s CPU", hardCPU.String())) return false, apierrors.NewForbidden(resourceName, name, fmt.Errorf("Limited to %s CPU", hardCPU.String()))
} else { } else {
status.Used[api.ResourceCPU] = *resource.NewMilliQuantity(used.MilliValue()+deltaCPU.MilliValue(), resource.DecimalSI) status.Used[api.ResourceCPU] = *resource.NewMilliQuantity(used.MilliValue()+deltaCPU.MilliValue(), resource.DecimalSI)
dirty = true dirty = true