mirror of https://github.com/k3s-io/k3s
pod constraints func for quota validates resources
parent
7e7465e2d4
commit
8b8a22b143
|
@ -23,12 +23,14 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/admission"
|
"k8s.io/kubernetes/pkg/admission"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/api/resource"
|
"k8s.io/kubernetes/pkg/api/resource"
|
||||||
|
"k8s.io/kubernetes/pkg/api/validation"
|
||||||
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/qos/util"
|
"k8s.io/kubernetes/pkg/kubelet/qos/util"
|
||||||
"k8s.io/kubernetes/pkg/quota"
|
"k8s.io/kubernetes/pkg/quota"
|
||||||
"k8s.io/kubernetes/pkg/quota/generic"
|
"k8s.io/kubernetes/pkg/quota/generic"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
"k8s.io/kubernetes/pkg/util/sets"
|
"k8s.io/kubernetes/pkg/util/sets"
|
||||||
|
"k8s.io/kubernetes/pkg/util/validation/field"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewPodEvaluator returns an evaluator that can evaluate pods
|
// NewPodEvaluator returns an evaluator that can evaluate pods
|
||||||
|
@ -64,12 +66,26 @@ func NewPodEvaluator(kubeClient clientset.Interface) quota.Evaluator {
|
||||||
}
|
}
|
||||||
|
|
||||||
// PodConstraintsFunc verifies that all required resources are present on the pod
|
// PodConstraintsFunc verifies that all required resources are present on the pod
|
||||||
|
// In addition, it validates that the resources are valid (i.e. requests < limits)
|
||||||
func PodConstraintsFunc(required []api.ResourceName, object runtime.Object) error {
|
func PodConstraintsFunc(required []api.ResourceName, object runtime.Object) error {
|
||||||
pod, ok := object.(*api.Pod)
|
pod, ok := object.(*api.Pod)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("Unexpected input object %v", object)
|
return fmt.Errorf("Unexpected input object %v", object)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pod level resources are often set during admission control
|
||||||
|
// As a consequence, we want to verify that resources are valid prior
|
||||||
|
// to ever charging quota prematurely in case they are not.
|
||||||
|
allErrs := field.ErrorList{}
|
||||||
|
fldPath := field.NewPath("spec").Child("containers")
|
||||||
|
for i, ctr := range pod.Spec.Containers {
|
||||||
|
idxPath := fldPath.Index(i)
|
||||||
|
allErrs = append(allErrs, validation.ValidateResourceRequirements(&ctr.Resources, idxPath.Child("resources"))...)
|
||||||
|
}
|
||||||
|
if len(allErrs) > 0 {
|
||||||
|
return allErrs.ToAggregate()
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: fix this when we have pod level cgroups
|
// TODO: fix this when we have pod level cgroups
|
||||||
// since we do not yet pod level requests/limits, we need to ensure each
|
// since we do not yet pod level requests/limits, we need to ensure each
|
||||||
// container makes an explict request or limit for a quota tracked resource
|
// container makes an explict request or limit for a quota tracked resource
|
||||||
|
|
|
@ -314,11 +314,18 @@ func TestAdmitEnforceQuotaConstraints(t *testing.T) {
|
||||||
evaluator: evaluator,
|
evaluator: evaluator,
|
||||||
}
|
}
|
||||||
indexer.Add(resourceQuota)
|
indexer.Add(resourceQuota)
|
||||||
|
// verify all values are specified as required on the quota
|
||||||
newPod := validPod("not-allowed-pod", 1, getResourceRequirements(getResourceList("100m", "2Gi"), getResourceList("200m", "")))
|
newPod := validPod("not-allowed-pod", 1, getResourceRequirements(getResourceList("100m", "2Gi"), getResourceList("200m", "")))
|
||||||
err := handler.Admit(admission.NewAttributesRecord(newPod, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
err := handler.Admit(admission.NewAttributesRecord(newPod, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected an error because the pod does not specify a memory limit")
|
t.Errorf("Expected an error because the pod does not specify a memory limit")
|
||||||
}
|
}
|
||||||
|
// verify the requests and limits are actually valid (in this case, we fail because the limits < requests)
|
||||||
|
newPod = validPod("not-allowed-pod", 1, getResourceRequirements(getResourceList("200m", "2Gi"), getResourceList("100m", "1Gi")))
|
||||||
|
err = handler.Admit(admission.NewAttributesRecord(newPod, api.Kind("Pod").WithVersion("version"), newPod.Namespace, newPod.Name, api.Resource("pods").WithVersion("version"), "", admission.Create, nil))
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Expected an error because the pod does not specify a memory limit")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestAdmitPodInNamespaceWithoutQuota ensures that if a namespace has no quota, that a pod can get in
|
// TestAdmitPodInNamespaceWithoutQuota ensures that if a namespace has no quota, that a pod can get in
|
||||||
|
|
Loading…
Reference in New Issue