123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858 |
- /*
- Copyright 2014 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package limitranger
- import (
- "fmt"
- "strconv"
- "testing"
- "time"
- corev1 "k8s.io/api/core/v1"
- apiequality "k8s.io/apimachinery/pkg/api/equality"
- "k8s.io/apimachinery/pkg/api/resource"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/util/wait"
- "k8s.io/apiserver/pkg/admission"
- genericadmissioninitializer "k8s.io/apiserver/pkg/admission/initializer"
- admissiontesting "k8s.io/apiserver/pkg/admission/testing"
- "k8s.io/client-go/informers"
- clientset "k8s.io/client-go/kubernetes"
- "k8s.io/client-go/kubernetes/fake"
- core "k8s.io/client-go/testing"
- api "k8s.io/kubernetes/pkg/apis/core"
- v1 "k8s.io/kubernetes/pkg/apis/core/v1"
- )
- func getComputeResourceList(cpu, memory string) api.ResourceList {
- res := api.ResourceList{}
- if cpu != "" {
- res[api.ResourceCPU] = resource.MustParse(cpu)
- }
- if memory != "" {
- res[api.ResourceMemory] = resource.MustParse(memory)
- }
- return res
- }
- func getStorageResourceList(storage string) api.ResourceList {
- res := api.ResourceList{}
- if storage != "" {
- res[api.ResourceStorage] = resource.MustParse(storage)
- }
- return res
- }
- func getResourceRequirements(requests, limits api.ResourceList) api.ResourceRequirements {
- res := api.ResourceRequirements{}
- res.Requests = requests
- res.Limits = limits
- return res
- }
- // createLimitRange creates a limit range with the specified data
- func createLimitRange(limitType api.LimitType, min, max, defaultLimit, defaultRequest, maxLimitRequestRatio api.ResourceList) corev1.LimitRange {
- internalLimitRage := api.LimitRange{
- ObjectMeta: metav1.ObjectMeta{
- Name: "abc",
- Namespace: "test",
- },
- Spec: api.LimitRangeSpec{
- Limits: []api.LimitRangeItem{
- {
- Type: limitType,
- Min: min,
- Max: max,
- Default: defaultLimit,
- DefaultRequest: defaultRequest,
- MaxLimitRequestRatio: maxLimitRequestRatio,
- },
- },
- },
- }
- externalLimitRange := corev1.LimitRange{}
- v1.Convert_core_LimitRange_To_v1_LimitRange(&internalLimitRage, &externalLimitRange, nil)
- return externalLimitRange
- }
- func validLimitRange() corev1.LimitRange {
- internalLimitRange := api.LimitRange{
- ObjectMeta: metav1.ObjectMeta{
- Name: "abc",
- Namespace: "test",
- },
- Spec: api.LimitRangeSpec{
- Limits: []api.LimitRangeItem{
- {
- Type: api.LimitTypePod,
- Max: getComputeResourceList("200m", "4Gi"),
- Min: getComputeResourceList("50m", "2Mi"),
- },
- {
- Type: api.LimitTypeContainer,
- Max: getComputeResourceList("100m", "2Gi"),
- Min: getComputeResourceList("25m", "1Mi"),
- Default: getComputeResourceList("75m", "10Mi"),
- DefaultRequest: getComputeResourceList("50m", "5Mi"),
- },
- },
- },
- }
- externalLimitRange := corev1.LimitRange{}
- v1.Convert_core_LimitRange_To_v1_LimitRange(&internalLimitRange, &externalLimitRange, nil)
- return externalLimitRange
- }
- func validLimitRangeNoDefaults() corev1.LimitRange {
- internalLimitRange := api.LimitRange{
- ObjectMeta: metav1.ObjectMeta{
- Name: "abc",
- Namespace: "test",
- },
- Spec: api.LimitRangeSpec{
- Limits: []api.LimitRangeItem{
- {
- Type: api.LimitTypePod,
- Max: getComputeResourceList("200m", "4Gi"),
- Min: getComputeResourceList("50m", "2Mi"),
- },
- {
- Type: api.LimitTypeContainer,
- Max: getComputeResourceList("100m", "2Gi"),
- Min: getComputeResourceList("25m", "1Mi"),
- },
- },
- },
- }
- 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 {
- pod := api.Pod{
- ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: "test"},
- Spec: api.PodSpec{},
- }
- pod.Spec.Containers = make([]api.Container, 0, numContainers)
- for i := 0; i < numContainers; i++ {
- pod.Spec.Containers = append(pod.Spec.Containers, api.Container{
- Image: "foo:V" + strconv.Itoa(i),
- Resources: resources,
- Name: "foo-" + strconv.Itoa(i),
- })
- }
- return pod
- }
- func validPodInit(pod api.Pod, resources ...api.ResourceRequirements) api.Pod {
- for i := 0; i < len(resources); i++ {
- pod.Spec.InitContainers = append(pod.Spec.InitContainers, api.Container{
- Image: "foo:V" + strconv.Itoa(i),
- Resources: resources[i],
- Name: "foo-" + strconv.Itoa(i),
- })
- }
- return pod
- }
- func TestDefaultContainerResourceRequirements(t *testing.T) {
- limitRange := validLimitRange()
- expected := api.ResourceRequirements{
- Requests: getComputeResourceList("50m", "5Mi"),
- Limits: getComputeResourceList("75m", "10Mi"),
- }
- actual := defaultContainerResourceRequirements(&limitRange)
- if !apiequality.Semantic.DeepEqual(expected, actual) {
- t.Errorf("actual.Limits != expected.Limits; %v != %v", actual.Limits, expected.Limits)
- t.Errorf("actual.Requests != expected.Requests; %v != %v", actual.Requests, expected.Requests)
- t.Errorf("expected != actual; %v != %v", expected, actual)
- }
- }
- func verifyAnnotation(t *testing.T, pod *api.Pod, expected string) {
- a, ok := pod.ObjectMeta.Annotations[limitRangerAnnotation]
- if !ok {
- t.Errorf("No annotation but expected %v", expected)
- }
- if a != expected {
- t.Errorf("Wrong annotation set by Limit Ranger: got %v, expected %v", a, expected)
- }
- }
- func expectNoAnnotation(t *testing.T, pod *api.Pod) {
- if a, ok := pod.ObjectMeta.Annotations[limitRangerAnnotation]; ok {
- t.Errorf("Expected no annotation but got %v", a)
- }
- }
- func TestMergePodResourceRequirements(t *testing.T) {
- limitRange := validLimitRange()
- // pod with no resources enumerated should get each resource from default request
- expected := getResourceRequirements(getComputeResourceList("", ""), getComputeResourceList("", ""))
- pod := validPod("empty-resources", 1, expected)
- defaultRequirements := defaultContainerResourceRequirements(&limitRange)
- mergePodResourceRequirements(&pod, &defaultRequirements)
- for i := range pod.Spec.Containers {
- actual := pod.Spec.Containers[i].Resources
- if !apiequality.Semantic.DeepEqual(expected, actual) {
- t.Errorf("pod %v, expected != actual; %v != %v", pod.Name, expected, actual)
- }
- }
- verifyAnnotation(t, &pod, "LimitRanger plugin set: cpu, memory request for container foo-0; cpu, memory limit for container foo-0")
- // pod with some resources enumerated should only merge empty
- input := getResourceRequirements(getComputeResourceList("", "512Mi"), getComputeResourceList("", ""))
- pod = validPodInit(validPod("limit-memory", 1, input), input)
- expected = api.ResourceRequirements{
- Requests: api.ResourceList{
- api.ResourceCPU: defaultRequirements.Requests[api.ResourceCPU],
- api.ResourceMemory: resource.MustParse("512Mi"),
- },
- Limits: defaultRequirements.Limits,
- }
- mergePodResourceRequirements(&pod, &defaultRequirements)
- for i := range pod.Spec.Containers {
- actual := pod.Spec.Containers[i].Resources
- if !apiequality.Semantic.DeepEqual(expected, actual) {
- t.Errorf("pod %v, expected != actual; %v != %v", pod.Name, expected, actual)
- }
- }
- for i := range pod.Spec.InitContainers {
- actual := pod.Spec.InitContainers[i].Resources
- if !apiequality.Semantic.DeepEqual(expected, actual) {
- t.Errorf("pod %v, expected != actual; %v != %v", pod.Name, expected, actual)
- }
- }
- verifyAnnotation(t, &pod, "LimitRanger plugin set: cpu request for container foo-0; cpu, memory limit for container foo-0")
- // pod with all resources enumerated should not merge anything
- input = getResourceRequirements(getComputeResourceList("100m", "512Mi"), getComputeResourceList("200m", "1G"))
- initInputs := []api.ResourceRequirements{getResourceRequirements(getComputeResourceList("200m", "1G"), getComputeResourceList("400m", "2G"))}
- pod = validPodInit(validPod("limit-memory", 1, input), initInputs...)
- expected = input
- mergePodResourceRequirements(&pod, &defaultRequirements)
- for i := range pod.Spec.Containers {
- actual := pod.Spec.Containers[i].Resources
- if !apiequality.Semantic.DeepEqual(expected, actual) {
- t.Errorf("pod %v, expected != actual; %v != %v", pod.Name, expected, actual)
- }
- }
- for i := range pod.Spec.InitContainers {
- actual := pod.Spec.InitContainers[i].Resources
- if !apiequality.Semantic.DeepEqual(initInputs[i], actual) {
- t.Errorf("pod %v, expected != actual; %v != %v", pod.Name, initInputs[i], actual)
- }
- }
- expectNoAnnotation(t, &pod)
- }
- func TestPodLimitFunc(t *testing.T) {
- type testCase struct {
- pod api.Pod
- limitRange corev1.LimitRange
- }
- successCases := []testCase{
- {
- pod: validPod("ctr-min-cpu-request", 1, getResourceRequirements(getComputeResourceList("100m", ""), getComputeResourceList("", ""))),
- limitRange: createLimitRange(api.LimitTypeContainer, getComputeResourceList("50m", ""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-min-cpu-request-limit", 1, getResourceRequirements(getComputeResourceList("100m", ""), getComputeResourceList("200m", ""))),
- limitRange: createLimitRange(api.LimitTypeContainer, getComputeResourceList("50m", ""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-min-memory-request", 1, getResourceRequirements(getComputeResourceList("", "60Mi"), getComputeResourceList("", ""))),
- limitRange: createLimitRange(api.LimitTypeContainer, getComputeResourceList("", "50Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-min-memory-request-limit", 1, getResourceRequirements(getComputeResourceList("", "60Mi"), getComputeResourceList("", "100Mi"))),
- limitRange: createLimitRange(api.LimitTypeContainer, getComputeResourceList("", "50Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-max-cpu-request-limit", 1, getResourceRequirements(getComputeResourceList("500m", ""), getComputeResourceList("1", ""))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, getComputeResourceList("2", ""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-max-cpu-limit", 1, getResourceRequirements(getComputeResourceList("", ""), getComputeResourceList("1", ""))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, getComputeResourceList("2", ""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-max-mem-request-limit", 1, getResourceRequirements(getComputeResourceList("", "250Mi"), getComputeResourceList("", "500Mi"))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, getComputeResourceList("", "1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-max-cpu-ratio", 1, getResourceRequirements(getComputeResourceList("500m", ""), getComputeResourceList("750m", ""))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, getComputeResourceList("1.5", "")),
- },
- {
- pod: validPod("ctr-max-mem-limit", 1, getResourceRequirements(getComputeResourceList("", ""), getComputeResourceList("", "500Mi"))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, getComputeResourceList("", "1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-min-cpu-request", 2, getResourceRequirements(getComputeResourceList("75m", ""), getComputeResourceList("", ""))),
- limitRange: createLimitRange(api.LimitTypePod, getComputeResourceList("100m", ""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-min-cpu-request-limit", 2, getResourceRequirements(getComputeResourceList("75m", ""), getComputeResourceList("200m", ""))),
- limitRange: createLimitRange(api.LimitTypePod, getComputeResourceList("100m", ""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-min-memory-request", 2, getResourceRequirements(getComputeResourceList("", "60Mi"), getComputeResourceList("", ""))),
- limitRange: createLimitRange(api.LimitTypePod, getComputeResourceList("", "100Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-min-memory-request-limit", 2, getResourceRequirements(getComputeResourceList("", "60Mi"), getComputeResourceList("", "100Mi"))),
- limitRange: createLimitRange(api.LimitTypePod, getComputeResourceList("", "100Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPodInit(
- validPod("pod-init-min-memory-request", 2, getResourceRequirements(getComputeResourceList("", "60Mi"), getComputeResourceList("", ""))),
- getResourceRequirements(getComputeResourceList("", "100Mi"), getComputeResourceList("", "")),
- ),
- limitRange: createLimitRange(api.LimitTypePod, getComputeResourceList("", "100Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPodInit(
- validPod("pod-init-min-memory-request-limit", 2, getResourceRequirements(getComputeResourceList("", "60Mi"), getComputeResourceList("", "100Mi"))),
- getResourceRequirements(getComputeResourceList("", "80Mi"), getComputeResourceList("", "100Mi")),
- ),
- limitRange: createLimitRange(api.LimitTypePod, getComputeResourceList("", "100Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-max-cpu-request-limit", 2, getResourceRequirements(getComputeResourceList("500m", ""), getComputeResourceList("1", ""))),
- limitRange: createLimitRange(api.LimitTypePod, api.ResourceList{}, getComputeResourceList("2", ""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-max-cpu-limit", 2, getResourceRequirements(getComputeResourceList("", ""), getComputeResourceList("1", ""))),
- limitRange: createLimitRange(api.LimitTypePod, api.ResourceList{}, getComputeResourceList("2", ""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPodInit(
- validPod("pod-init-max-cpu-request-limit", 2, getResourceRequirements(getComputeResourceList("500m", ""), getComputeResourceList("1", ""))),
- getResourceRequirements(getComputeResourceList("1", ""), getComputeResourceList("2", "")),
- getResourceRequirements(getComputeResourceList("1", ""), getComputeResourceList("1", "")),
- ),
- limitRange: createLimitRange(api.LimitTypePod, api.ResourceList{}, getComputeResourceList("2", ""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPodInit(
- validPod("pod-init-max-cpu-limit", 2, getResourceRequirements(getComputeResourceList("", ""), getComputeResourceList("1", ""))),
- getResourceRequirements(getComputeResourceList("", ""), getComputeResourceList("2", "")),
- getResourceRequirements(getComputeResourceList("", ""), getComputeResourceList("2", "")),
- ),
- limitRange: createLimitRange(api.LimitTypePod, api.ResourceList{}, getComputeResourceList("2", ""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-max-mem-request-limit", 2, getResourceRequirements(getComputeResourceList("", "250Mi"), getComputeResourceList("", "500Mi"))),
- limitRange: createLimitRange(api.LimitTypePod, api.ResourceList{}, getComputeResourceList("", "1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-max-mem-limit", 2, getResourceRequirements(getComputeResourceList("", ""), getComputeResourceList("", "500Mi"))),
- limitRange: createLimitRange(api.LimitTypePod, api.ResourceList{}, getComputeResourceList("", "1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-max-mem-ratio", 3, getResourceRequirements(getComputeResourceList("", "300Mi"), getComputeResourceList("", "450Mi"))),
- limitRange: createLimitRange(api.LimitTypePod, api.ResourceList{}, getComputeResourceList("", "2Gi"), api.ResourceList{}, api.ResourceList{}, getComputeResourceList("", "1.5")),
- },
- {
- pod: validPod("ctr-1-min-local-ephemeral-storage-request", 1, getResourceRequirements(getLocalStorageResourceList("60Mi"), getLocalStorageResourceList(""))),
- limitRange: createLimitRange(api.LimitTypeContainer, getLocalStorageResourceList("50Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-1-min-local-ephemeral-storage-request-limit", 1, getResourceRequirements(getLocalStorageResourceList("60Mi"), getLocalStorageResourceList("100Mi"))),
- limitRange: createLimitRange(api.LimitTypeContainer, getLocalStorageResourceList("50Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-1-max-local-ephemeral-storage-request-limit", 1, getResourceRequirements(getLocalStorageResourceList("250Mi"), getLocalStorageResourceList("500Mi"))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, getLocalStorageResourceList("1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-1-max-local-ephemeral-storage-limit", 1, getResourceRequirements(getLocalStorageResourceList(""), getLocalStorageResourceList("500Mi"))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, getLocalStorageResourceList("1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-2-min-local-ephemeral-storage-request", 2, getResourceRequirements(getLocalStorageResourceList("60Mi"), getLocalStorageResourceList(""))),
- limitRange: createLimitRange(api.LimitTypeContainer, getLocalStorageResourceList("50Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-2-min-local-ephemeral-storage-request-limit", 2, getResourceRequirements(getLocalStorageResourceList("60Mi"), getLocalStorageResourceList("100Mi"))),
- limitRange: createLimitRange(api.LimitTypeContainer, getLocalStorageResourceList("50Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-2-max-local-ephemeral-storage-request-limit", 2, getResourceRequirements(getLocalStorageResourceList("250Mi"), getLocalStorageResourceList("500Mi"))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, getLocalStorageResourceList("600Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-2-max-local-ephemeral-storage-limit", 2, getResourceRequirements(getLocalStorageResourceList(""), getLocalStorageResourceList("500Mi"))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, getLocalStorageResourceList("600Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-min-local-ephemeral-storage-request", 2, getResourceRequirements(getLocalStorageResourceList("60Mi"), getLocalStorageResourceList(""))),
- limitRange: createLimitRange(api.LimitTypePod, getLocalStorageResourceList("100Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-min-local-ephemeral-storage-request-limit", 2, getResourceRequirements(getLocalStorageResourceList("60Mi"), getLocalStorageResourceList("100Mi"))),
- limitRange: createLimitRange(api.LimitTypePod, getLocalStorageResourceList("100Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPodInit(
- validPod("pod-init-min-local-ephemeral-storage-request", 2, getResourceRequirements(getLocalStorageResourceList("60Mi"), getLocalStorageResourceList(""))),
- getResourceRequirements(getLocalStorageResourceList("100Mi"), getLocalStorageResourceList("")),
- ),
- limitRange: createLimitRange(api.LimitTypePod, getLocalStorageResourceList("100Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPodInit(
- validPod("pod-init-min-local-ephemeral-storage-request-limit", 2, getResourceRequirements(getLocalStorageResourceList("60Mi"), getLocalStorageResourceList("100Mi"))),
- getResourceRequirements(getLocalStorageResourceList("80Mi"), getLocalStorageResourceList("100Mi")),
- ),
- limitRange: createLimitRange(api.LimitTypePod, getLocalStorageResourceList("100Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-max-local-ephemeral-storage-request-limit", 2, getResourceRequirements(getLocalStorageResourceList("250Mi"), getLocalStorageResourceList("500Mi"))),
- limitRange: createLimitRange(api.LimitTypePod, api.ResourceList{}, getLocalStorageResourceList("1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-max-local-ephemeral-storage-limit", 2, getResourceRequirements(getLocalStorageResourceList(""), getLocalStorageResourceList("500Mi"))),
- limitRange: createLimitRange(api.LimitTypePod, api.ResourceList{}, getLocalStorageResourceList("1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-max-local-ephemeral-storage-ratio", 3, getResourceRequirements(getLocalStorageResourceList("300Mi"), getLocalStorageResourceList("450Mi"))),
- limitRange: createLimitRange(api.LimitTypePod, api.ResourceList{}, getLocalStorageResourceList("2Gi"), api.ResourceList{}, api.ResourceList{}, getLocalStorageResourceList("1.5")),
- },
- }
- for i := range successCases {
- test := successCases[i]
- err := PodMutateLimitFunc(&test.limitRange, &test.pod)
- if err != nil {
- t.Errorf("Unexpected error for pod: %s, %v", test.pod.Name, err)
- }
- err = PodValidateLimitFunc(&test.limitRange, &test.pod)
- if err != nil {
- t.Errorf("Unexpected error for pod: %s, %v", test.pod.Name, err)
- }
- }
- errorCases := []testCase{
- {
- pod: validPod("ctr-min-cpu-request", 1, getResourceRequirements(getComputeResourceList("40m", ""), getComputeResourceList("", ""))),
- limitRange: createLimitRange(api.LimitTypeContainer, getComputeResourceList("50m", ""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-min-cpu-request-limit", 1, getResourceRequirements(getComputeResourceList("40m", ""), getComputeResourceList("200m", ""))),
- limitRange: createLimitRange(api.LimitTypeContainer, getComputeResourceList("50m", ""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-min-cpu-no-request-limit", 1, getResourceRequirements(getComputeResourceList("", ""), getComputeResourceList("", ""))),
- limitRange: createLimitRange(api.LimitTypeContainer, getComputeResourceList("50m", ""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-min-memory-request", 1, getResourceRequirements(getComputeResourceList("", "40Mi"), getComputeResourceList("", ""))),
- limitRange: createLimitRange(api.LimitTypeContainer, getComputeResourceList("", "50Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-min-memory-request-limit", 1, getResourceRequirements(getComputeResourceList("", "40Mi"), getComputeResourceList("", "100Mi"))),
- limitRange: createLimitRange(api.LimitTypeContainer, getComputeResourceList("", "50Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-min-memory-no-request-limit", 1, getResourceRequirements(getComputeResourceList("", ""), getComputeResourceList("", ""))),
- limitRange: createLimitRange(api.LimitTypeContainer, getComputeResourceList("", "50Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-max-cpu-request-limit", 1, getResourceRequirements(getComputeResourceList("500m", ""), getComputeResourceList("2500m", ""))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, getComputeResourceList("2", ""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-max-cpu-limit", 1, getResourceRequirements(getComputeResourceList("", ""), getComputeResourceList("2500m", ""))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, getComputeResourceList("2", ""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-max-cpu-no-request-limit", 1, getResourceRequirements(getComputeResourceList("", ""), getComputeResourceList("", ""))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, getComputeResourceList("2", ""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-max-cpu-ratio", 1, getResourceRequirements(getComputeResourceList("1250m", ""), getComputeResourceList("2500m", ""))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, getComputeResourceList("1", "")),
- },
- {
- pod: validPod("ctr-max-mem-request-limit", 1, getResourceRequirements(getComputeResourceList("", "250Mi"), getComputeResourceList("", "2Gi"))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, getComputeResourceList("", "1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-max-mem-limit", 1, getResourceRequirements(getComputeResourceList("", ""), getComputeResourceList("", "2Gi"))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, getComputeResourceList("", "1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-max-mem-no-request-limit", 1, getResourceRequirements(getComputeResourceList("", ""), getComputeResourceList("", ""))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, getComputeResourceList("", "1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-min-cpu-request", 1, getResourceRequirements(getComputeResourceList("75m", ""), getComputeResourceList("", ""))),
- limitRange: createLimitRange(api.LimitTypePod, getComputeResourceList("100m", ""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-min-cpu-request-limit", 1, getResourceRequirements(getComputeResourceList("75m", ""), getComputeResourceList("200m", ""))),
- limitRange: createLimitRange(api.LimitTypePod, getComputeResourceList("100m", ""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-min-memory-request", 1, getResourceRequirements(getComputeResourceList("", "60Mi"), getComputeResourceList("", ""))),
- limitRange: createLimitRange(api.LimitTypePod, getComputeResourceList("", "100Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-min-memory-request-limit", 1, getResourceRequirements(getComputeResourceList("", "60Mi"), getComputeResourceList("", "100Mi"))),
- limitRange: createLimitRange(api.LimitTypePod, getComputeResourceList("", "100Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-max-cpu-request-limit", 3, getResourceRequirements(getComputeResourceList("500m", ""), getComputeResourceList("1", ""))),
- limitRange: createLimitRange(api.LimitTypePod, api.ResourceList{}, getComputeResourceList("2", ""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-max-cpu-limit", 3, getResourceRequirements(getComputeResourceList("", ""), getComputeResourceList("1", ""))),
- limitRange: createLimitRange(api.LimitTypePod, api.ResourceList{}, getComputeResourceList("2", ""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-max-mem-request-limit", 3, getResourceRequirements(getComputeResourceList("", "250Mi"), getComputeResourceList("", "500Mi"))),
- limitRange: createLimitRange(api.LimitTypePod, api.ResourceList{}, getComputeResourceList("", "1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-max-mem-limit", 3, getResourceRequirements(getComputeResourceList("", ""), getComputeResourceList("", "500Mi"))),
- limitRange: createLimitRange(api.LimitTypePod, api.ResourceList{}, getComputeResourceList("", "1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPodInit(
- validPod("pod-init-max-mem-limit", 1, getResourceRequirements(getComputeResourceList("", ""), getComputeResourceList("", "500Mi"))),
- getResourceRequirements(getComputeResourceList("", ""), getComputeResourceList("", "1.5Gi")),
- ),
- limitRange: createLimitRange(api.LimitTypePod, api.ResourceList{}, getComputeResourceList("", "1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-max-mem-ratio", 3, getResourceRequirements(getComputeResourceList("", "250Mi"), getComputeResourceList("", "500Mi"))),
- limitRange: createLimitRange(api.LimitTypePod, api.ResourceList{}, getComputeResourceList("", "2Gi"), api.ResourceList{}, api.ResourceList{}, getComputeResourceList("", "1.5")),
- },
- {
- pod: validPod("ctr-1-min-local-ephemeral-storage-request", 1, getResourceRequirements(getLocalStorageResourceList("40Mi"), getLocalStorageResourceList(""))),
- limitRange: createLimitRange(api.LimitTypeContainer, getLocalStorageResourceList("50Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-1-min-local-ephemeral-storage-request-limit", 1, getResourceRequirements(getLocalStorageResourceList("40Mi"), getLocalStorageResourceList("100Mi"))),
- limitRange: createLimitRange(api.LimitTypeContainer, getLocalStorageResourceList("50Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-1-min-local-ephemeral-storage-no-request-limit", 1, getResourceRequirements(getLocalStorageResourceList(""), getLocalStorageResourceList(""))),
- limitRange: createLimitRange(api.LimitTypeContainer, getLocalStorageResourceList("50Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-1-max-local-ephemeral-storage-request-limit", 1, getResourceRequirements(getLocalStorageResourceList("250Mi"), getLocalStorageResourceList("2Gi"))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, getLocalStorageResourceList("1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-1-max-local-ephemeral-storage-limit", 1, getResourceRequirements(getLocalStorageResourceList(""), getLocalStorageResourceList("2Gi"))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, getLocalStorageResourceList("1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-1-max-local-ephemeral-storage-no-request-limit", 1, getResourceRequirements(getLocalStorageResourceList(""), getLocalStorageResourceList(""))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, getLocalStorageResourceList("1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-2-min-local-ephemeral-storage-request", 2, getResourceRequirements(getLocalStorageResourceList("40Mi"), getLocalStorageResourceList(""))),
- limitRange: createLimitRange(api.LimitTypeContainer, getLocalStorageResourceList("50Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-2-min-local-ephemeral-storage-request-limit", 2, getResourceRequirements(getLocalStorageResourceList("40Mi"), getLocalStorageResourceList("100Mi"))),
- limitRange: createLimitRange(api.LimitTypeContainer, getLocalStorageResourceList("50Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-2-min-local-ephemeral-storage-no-request-limit", 2, getResourceRequirements(getLocalStorageResourceList(""), getLocalStorageResourceList(""))),
- limitRange: createLimitRange(api.LimitTypeContainer, getLocalStorageResourceList("50Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-2-max-local-ephemeral-storage-request-limit", 2, getResourceRequirements(getLocalStorageResourceList("250Mi"), getLocalStorageResourceList("2Gi"))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, getLocalStorageResourceList("1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-2-max-local-ephemeral-storage-limit", 2, getResourceRequirements(getLocalStorageResourceList(""), getLocalStorageResourceList("2Gi"))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, getLocalStorageResourceList("1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("ctr-2-max-local-ephemeral-storage-no-request-limit", 2, getResourceRequirements(getLocalStorageResourceList(""), getLocalStorageResourceList(""))),
- limitRange: createLimitRange(api.LimitTypeContainer, api.ResourceList{}, getLocalStorageResourceList("1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-min-local-ephemeral-storage-request", 1, getResourceRequirements(getLocalStorageResourceList("60Mi"), getLocalStorageResourceList(""))),
- limitRange: createLimitRange(api.LimitTypePod, getLocalStorageResourceList("100Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-min-local-ephemeral-storage-request-limit", 1, getResourceRequirements(getLocalStorageResourceList("60Mi"), getLocalStorageResourceList("100Mi"))),
- limitRange: createLimitRange(api.LimitTypePod, getLocalStorageResourceList("100Mi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-max-local-ephemeral-storage-request-limit", 3, getResourceRequirements(getLocalStorageResourceList("250Mi"), getLocalStorageResourceList("500Mi"))),
- limitRange: createLimitRange(api.LimitTypePod, api.ResourceList{}, getLocalStorageResourceList("1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-max-local-ephemeral-storage-limit", 3, getResourceRequirements(getLocalStorageResourceList(""), getLocalStorageResourceList("500Mi"))),
- limitRange: createLimitRange(api.LimitTypePod, api.ResourceList{}, getLocalStorageResourceList("1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPodInit(
- validPod("pod-init-max-local-ephemeral-storage-limit", 1, getResourceRequirements(getLocalStorageResourceList(""), getLocalStorageResourceList("500Mi"))),
- getResourceRequirements(getLocalStorageResourceList(""), getLocalStorageResourceList("1.5Gi")),
- ),
- limitRange: createLimitRange(api.LimitTypePod, api.ResourceList{}, getLocalStorageResourceList("1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pod: validPod("pod-max-local-ephemeral-storage-ratio", 3, getResourceRequirements(getLocalStorageResourceList("250Mi"), getLocalStorageResourceList("500Mi"))),
- limitRange: createLimitRange(api.LimitTypePod, api.ResourceList{}, getLocalStorageResourceList("2Gi"), api.ResourceList{}, api.ResourceList{}, getLocalStorageResourceList("1.5")),
- },
- }
- for i := range errorCases {
- test := errorCases[i]
- err := PodMutateLimitFunc(&test.limitRange, &test.pod)
- if err != nil {
- t.Errorf("Unexpected error for pod: %s, %v", test.pod.Name, err)
- }
- err = PodValidateLimitFunc(&test.limitRange, &test.pod)
- if err == nil {
- t.Errorf("Expected error for pod: %s", test.pod.Name)
- }
- }
- }
- func getLocalStorageResourceList(ephemeralStorage string) api.ResourceList {
- res := api.ResourceList{}
- if ephemeralStorage != "" {
- res[api.ResourceEphemeralStorage] = resource.MustParse(ephemeralStorage)
- }
- return res
- }
- func TestPodLimitFuncApplyDefault(t *testing.T) {
- limitRange := validLimitRange()
- testPod := validPodInit(validPod("foo", 1, getResourceRequirements(api.ResourceList{}, api.ResourceList{})), getResourceRequirements(api.ResourceList{}, api.ResourceList{}))
- err := PodMutateLimitFunc(&limitRange, &testPod)
- if err != nil {
- t.Errorf("Unexpected error for valid pod: %s, %v", testPod.Name, err)
- }
- for i := range testPod.Spec.Containers {
- container := testPod.Spec.Containers[i]
- limitMemory := container.Resources.Limits.Memory().String()
- limitCPU := container.Resources.Limits.Cpu().String()
- requestMemory := container.Resources.Requests.Memory().String()
- requestCPU := container.Resources.Requests.Cpu().String()
- if limitMemory != "10Mi" {
- t.Errorf("Unexpected limit memory value %s", limitMemory)
- }
- if limitCPU != "75m" {
- t.Errorf("Unexpected limit cpu value %s", limitCPU)
- }
- if requestMemory != "5Mi" {
- t.Errorf("Unexpected request memory value %s", requestMemory)
- }
- if requestCPU != "50m" {
- t.Errorf("Unexpected request cpu value %s", requestCPU)
- }
- }
- for i := range testPod.Spec.InitContainers {
- container := testPod.Spec.InitContainers[i]
- limitMemory := container.Resources.Limits.Memory().String()
- limitCPU := container.Resources.Limits.Cpu().String()
- requestMemory := container.Resources.Requests.Memory().String()
- requestCPU := container.Resources.Requests.Cpu().String()
- if limitMemory != "10Mi" {
- t.Errorf("Unexpected limit memory value %s", limitMemory)
- }
- if limitCPU != "75m" {
- t.Errorf("Unexpected limit cpu value %s", limitCPU)
- }
- if requestMemory != "5Mi" {
- t.Errorf("Unexpected request memory value %s", requestMemory)
- }
- if requestCPU != "50m" {
- t.Errorf("Unexpected request cpu value %s", requestCPU)
- }
- }
- }
- func TestLimitRangerIgnoresSubresource(t *testing.T) {
- limitRange := validLimitRangeNoDefaults()
- mockClient := newMockClientForTest([]corev1.LimitRange{limitRange})
- handler, informerFactory, err := newHandlerForTest(mockClient)
- if err != nil {
- t.Errorf("unexpected error initializing handler: %v", err)
- }
- informerFactory.Start(wait.NeverStop)
- testPod := validPod("testPod", 1, api.ResourceRequirements{})
- err = admissiontesting.WithReinvocationTesting(t, handler).Admit(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil)
- if err != nil {
- t.Fatal(err)
- }
- err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil)
- if err == nil {
- t.Errorf("Expected an error since the pod did not specify resource limits in its create call")
- }
- err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, &metav1.UpdateOptions{}, false, nil), nil)
- if err != nil {
- t.Errorf("Expected not to call limitranger actions on pod updates")
- }
- err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "status", admission.Update, &metav1.UpdateOptions{}, false, nil), nil)
- if err != nil {
- t.Errorf("Should have ignored calls to any subresource of pod %v", err)
- }
- }
- func TestLimitRangerAdmitPod(t *testing.T) {
- limitRange := validLimitRangeNoDefaults()
- mockClient := newMockClientForTest([]corev1.LimitRange{limitRange})
- handler, informerFactory, err := newHandlerForTest(mockClient)
- if err != nil {
- t.Errorf("unexpected error initializing handler: %v", err)
- }
- informerFactory.Start(wait.NeverStop)
- testPod := validPod("testPod", 1, api.ResourceRequirements{})
- err = admissiontesting.WithReinvocationTesting(t, handler).Admit(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil)
- if err != nil {
- t.Fatal(err)
- }
- err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil), nil)
- if err == nil {
- t.Errorf("Expected an error since the pod did not specify resource limits in its create call")
- }
- err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "", admission.Update, &metav1.UpdateOptions{}, false, nil), nil)
- if err != nil {
- t.Errorf("Expected not to call limitranger actions on pod updates")
- }
- err = handler.Validate(admission.NewAttributesRecord(&testPod, nil, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "testPod", api.Resource("pods").WithVersion("version"), "status", admission.Update, &metav1.UpdateOptions{}, false, nil), nil)
- if err != nil {
- t.Errorf("Should have ignored calls to any subresource of pod %v", err)
- }
- // a pod that is undergoing termination should never be blocked
- terminatingPod := validPod("terminatingPod", 1, api.ResourceRequirements{})
- now := metav1.Now()
- terminatingPod.DeletionTimestamp = &now
- err = handler.Validate(admission.NewAttributesRecord(&terminatingPod, &terminatingPod, api.Kind("Pod").WithVersion("version"), limitRange.Namespace, "terminatingPod", api.Resource("pods").WithVersion("version"), "", admission.Update, &metav1.UpdateOptions{}, false, nil), nil)
- if err != nil {
- t.Errorf("LimitRange should ignore a pod marked for termination")
- }
- }
- // newMockClientForTest creates a mock client that returns a client configured for the specified list of limit ranges
- func newMockClientForTest(limitRanges []corev1.LimitRange) *fake.Clientset {
- mockClient := &fake.Clientset{}
- mockClient.AddReactor("list", "limitranges", func(action core.Action) (bool, runtime.Object, error) {
- limitRangeList := &corev1.LimitRangeList{
- ListMeta: metav1.ListMeta{
- ResourceVersion: fmt.Sprintf("%d", len(limitRanges)),
- },
- }
- for index, value := range limitRanges {
- value.ResourceVersion = fmt.Sprintf("%d", index)
- limitRangeList.Items = append(limitRangeList.Items, value)
- }
- return true, limitRangeList, nil
- })
- return mockClient
- }
- // newHandlerForTest returns a handler configured for testing.
- func newHandlerForTest(c clientset.Interface) (*LimitRanger, informers.SharedInformerFactory, error) {
- f := informers.NewSharedInformerFactory(c, 5*time.Minute)
- handler, err := NewLimitRanger(&DefaultLimitRangerActions{})
- if err != nil {
- return nil, f, err
- }
- pluginInitializer := genericadmissioninitializer.New(c, f, nil)
- pluginInitializer.Initialize(handler)
- err = admission.ValidateInitialization(handler)
- return handler, f, err
- }
- func validPersistentVolumeClaim(name string, resources api.ResourceRequirements) api.PersistentVolumeClaim {
- pvc := api.PersistentVolumeClaim{
- ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: "test"},
- Spec: api.PersistentVolumeClaimSpec{
- Resources: resources,
- },
- }
- return pvc
- }
- func TestPersistentVolumeClaimLimitFunc(t *testing.T) {
- type testCase struct {
- pvc api.PersistentVolumeClaim
- limitRange corev1.LimitRange
- }
- successCases := []testCase{
- {
- pvc: validPersistentVolumeClaim("pvc-is-min-storage-request", getResourceRequirements(getStorageResourceList("1Gi"), getStorageResourceList(""))),
- limitRange: createLimitRange(api.LimitTypePersistentVolumeClaim, getStorageResourceList("1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pvc: validPersistentVolumeClaim("pvc-is-max-storage-request", getResourceRequirements(getStorageResourceList("1Gi"), getStorageResourceList(""))),
- limitRange: createLimitRange(api.LimitTypePersistentVolumeClaim, api.ResourceList{}, getStorageResourceList("1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pvc: validPersistentVolumeClaim("pvc-no-minmax-storage-request", getResourceRequirements(getStorageResourceList("100Gi"), getStorageResourceList(""))),
- limitRange: createLimitRange(api.LimitTypePersistentVolumeClaim, getStorageResourceList(""), getStorageResourceList(""), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pvc: validPersistentVolumeClaim("pvc-within-minmax-storage-request", getResourceRequirements(getStorageResourceList("5Gi"), getStorageResourceList(""))),
- limitRange: createLimitRange(api.LimitTypePersistentVolumeClaim, getStorageResourceList("1Gi"), getStorageResourceList("10Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- }
- for i := range successCases {
- test := successCases[i]
- err := PersistentVolumeClaimValidateLimitFunc(&test.limitRange, &test.pvc)
- if err != nil {
- t.Errorf("Unexpected error for pvc: %s, %v", test.pvc.Name, err)
- }
- }
- errorCases := []testCase{
- {
- pvc: validPersistentVolumeClaim("pvc-below-min-storage-request", getResourceRequirements(getStorageResourceList("500Mi"), getStorageResourceList(""))),
- limitRange: createLimitRange(api.LimitTypePersistentVolumeClaim, getStorageResourceList("1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- {
- pvc: validPersistentVolumeClaim("pvc-exceeds-max-storage-request", getResourceRequirements(getStorageResourceList("100Gi"), getStorageResourceList(""))),
- limitRange: createLimitRange(api.LimitTypePersistentVolumeClaim, getStorageResourceList("1Gi"), getStorageResourceList("1Gi"), api.ResourceList{}, api.ResourceList{}, api.ResourceList{}),
- },
- }
- for i := range errorCases {
- test := errorCases[i]
- err := PersistentVolumeClaimValidateLimitFunc(&test.limitRange, &test.pvc)
- if err == nil {
- t.Errorf("Expected error for pvc: %s", test.pvc.Name)
- }
- }
- }
|