mirror of https://github.com/k3s-io/k3s
update admission control to properly indicate resource
parent
8a2fe9bd2b
commit
889c4cc755
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ func NewResourceQuota(client client.Interface) admission.Interface {
|
||||||
return "a{client: client}
|
return "a{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
|
||||||
|
|
Loading…
Reference in New Issue