From 1633cdde05c45dc673c50edfda7dd82dc1997717 Mon Sep 17 00:00:00 2001 From: NickrenREN Date: Fri, 15 Sep 2017 12:05:16 +0800 Subject: [PATCH] Add limitrange e2e test for LocalStorageCapacityIsolation feature --- test/e2e/framework/BUILD | 2 + test/e2e/framework/util.go | 8 ++ test/e2e/scheduling/limit_range.go | 131 +++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+) diff --git a/test/e2e/framework/BUILD b/test/e2e/framework/BUILD index ec302bce8e6..8de2b0eddc3 100644 --- a/test/e2e/framework/BUILD +++ b/test/e2e/framework/BUILD @@ -57,6 +57,7 @@ go_library( "//pkg/controller:go_default_library", "//pkg/controller/deployment/util:go_default_library", "//pkg/controller/node:go_default_library", + "//pkg/features:go_default_library", "//pkg/kubectl:go_default_library", "//pkg/kubelet/apis/kubeletconfig:go_default_library", "//pkg/kubelet/apis/stats/v1alpha1:go_default_library", @@ -128,6 +129,7 @@ go_library( "//vendor/k8s.io/apimachinery/pkg/version:go_default_library", "//vendor/k8s.io/apimachinery/pkg/watch:go_default_library", "//vendor/k8s.io/apiserver/pkg/authentication/serviceaccount:go_default_library", + "//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library", "//vendor/k8s.io/client-go/discovery:go_default_library", "//vendor/k8s.io/client-go/dynamic:go_default_library", "//vendor/k8s.io/client-go/informers:go_default_library", diff --git a/test/e2e/framework/util.go b/test/e2e/framework/util.go index cd91fb964f5..7b8d5b314d8 100644 --- a/test/e2e/framework/util.go +++ b/test/e2e/framework/util.go @@ -73,6 +73,7 @@ import ( "k8s.io/client-go/tools/clientcmd" clientcmdapi "k8s.io/client-go/tools/clientcmd/api" + utilfeature "k8s.io/apiserver/pkg/util/feature" clientset "k8s.io/client-go/kubernetes" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/legacyscheme" @@ -86,6 +87,7 @@ import ( gcecloud "k8s.io/kubernetes/pkg/cloudprovider/providers/gce" "k8s.io/kubernetes/pkg/controller" nodectlr "k8s.io/kubernetes/pkg/controller/node" + "k8s.io/kubernetes/pkg/features" "k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubelet/util/format" "k8s.io/kubernetes/pkg/master/ports" @@ -318,6 +320,12 @@ func SkipIfProviderIs(unsupportedProviders ...string) { } } +func SkipUnlessLocalEphemeralStorageEnabled() { + if !utilfeature.DefaultFeatureGate.Enabled(features.LocalStorageCapacityIsolation) { + Skipf("Only supported when %v feature is enabled", features.LocalStorageCapacityIsolation) + } +} + func SkipUnlessSSHKeyPresent() { if _, err := GetSigner(TestContext.Provider); err != nil { Skipf("No SSH Key for provider %s: '%v'", TestContext.Provider, err) diff --git a/test/e2e/scheduling/limit_range.go b/test/e2e/scheduling/limit_range.go index 267acb072f0..31de3ab9d87 100644 --- a/test/e2e/scheduling/limit_range.go +++ b/test/e2e/scheduling/limit_range.go @@ -108,6 +108,137 @@ var _ = SIGDescribe("LimitRange", func() { }) +var _ = framework.KubeDescribe("LimitRange", func() { + f := framework.NewDefaultFramework("limitrange") + + BeforeEach(func() { + // only run the tests when LocalStorageCapacityIsolation feature is enabled + framework.SkipUnlessLocalEphemeralStorageEnabled() + }) + + It("should create a LimitRange with default ephemeral storage and ensure pod has the default applied.", func() { + By("Creating a LimitRange") + + min := getEphemeralStorageResourceList("100Mi") + max := getEphemeralStorageResourceList("500Mi") + defaultLimit := getEphemeralStorageResourceList("500Mi") + defaultRequest := getEphemeralStorageResourceList("200Mi") + maxLimitRequestRatio := v1.ResourceList{} + limitRange := newLimitRange("limit-range", v1.LimitTypeContainer, + min, max, + defaultLimit, defaultRequest, + maxLimitRequestRatio) + limitRange, err := f.ClientSet.CoreV1().LimitRanges(f.Namespace.Name).Create(limitRange) + Expect(err).NotTo(HaveOccurred()) + + defer func() { + By("Removing limitrange") + err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(limitRange.Name, nil) + Expect(err).NotTo(HaveOccurred()) + }() + + By("Fetching the LimitRange to ensure it has proper values") + limitRange, err = f.ClientSet.CoreV1().LimitRanges(f.Namespace.Name).Get(limitRange.Name, metav1.GetOptions{}) + expected := v1.ResourceRequirements{Requests: defaultRequest, Limits: defaultLimit} + actual := v1.ResourceRequirements{Requests: limitRange.Spec.Limits[0].DefaultRequest, Limits: limitRange.Spec.Limits[0].Default} + err = equalResourceRequirement(expected, actual) + Expect(err).NotTo(HaveOccurred()) + + By("Creating a Pod with no resource requirements") + pod := f.NewTestPod("pod-no-resources", v1.ResourceList{}, v1.ResourceList{}) + pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod) + Expect(err).NotTo(HaveOccurred()) + + defer func() { + By("Removing pod") + err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(pod.Name, nil) + Expect(err).NotTo(HaveOccurred()) + }() + + By("Ensuring Pod has resource requirements applied from LimitRange") + pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Get(pod.Name, metav1.GetOptions{}) + Expect(err).NotTo(HaveOccurred()) + for i := range pod.Spec.Containers { + err = equalResourceRequirement(expected, pod.Spec.Containers[i].Resources) + if err != nil { + // Print the pod to help in debugging. + framework.Logf("Pod %+v does not have the expected requirements", pod) + Expect(err).NotTo(HaveOccurred()) + } + } + + By("Creating a Pod with request") + pod = f.NewTestPod("pod-partial-resources", getEphemeralStorageResourceList("150m"), v1.ResourceList{}) + pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod) + Expect(err).NotTo(HaveOccurred()) + + defer func() { + By("Removing pod") + err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(pod.Name, nil) + Expect(err).NotTo(HaveOccurred()) + }() + + By("Ensuring Pod has merged resource requirements applied from LimitRange") + pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Get(pod.Name, metav1.GetOptions{}) + Expect(err).NotTo(HaveOccurred()) + // If you specify a Request, and no Limit, the Limit will be set to default limit + expected = v1.ResourceRequirements{Requests: getEphemeralStorageResourceList("150Mi"), Limits: defaultLimit} + for i := range pod.Spec.Containers { + err = equalResourceRequirement(expected, pod.Spec.Containers[i].Resources) + if err != nil { + // Print the pod to help in debugging. + framework.Logf("Pod %+v does not have the expected requirements", pod) + Expect(err).NotTo(HaveOccurred()) + } + } + + By("Creating a Pod with limit") + pod = f.NewTestPod("pod-partial-resources", v1.ResourceList{}, getEphemeralStorageResourceList("300m")) + pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod) + Expect(err).NotTo(HaveOccurred()) + + defer func() { + By("Removing pod") + err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(pod.Name, nil) + Expect(err).NotTo(HaveOccurred()) + }() + + By("Ensuring Pod has merged resource requirements applied from LimitRange") + pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Get(pod.Name, metav1.GetOptions{}) + Expect(err).NotTo(HaveOccurred()) + // If you specify a Limit, and no Request, the Limit will default to the Request + // This means that the LimitRange.DefaultRequest will ONLY take affect if a container.resources.limit is not supplied + expected = v1.ResourceRequirements{Requests: getEphemeralStorageResourceList("300Mi"), Limits: getEphemeralStorageResourceList("300Mi")} + for i := range pod.Spec.Containers { + err = equalResourceRequirement(expected, pod.Spec.Containers[i].Resources) + if err != nil { + // Print the pod to help in debugging. + framework.Logf("Pod %+v does not have the expected requirements", pod) + Expect(err).NotTo(HaveOccurred()) + } + } + + By("Failing to create a Pod with less than min resources") + pod = f.NewTestPod(podName, getEphemeralStorageResourceList("50Mi"), v1.ResourceList{}) + pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod) + Expect(err).To(HaveOccurred()) + + By("Failing to create a Pod with more than max resources") + pod = f.NewTestPod(podName, getEphemeralStorageResourceList("600Mi"), v1.ResourceList{}) + pod, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod) + Expect(err).To(HaveOccurred()) + }) + +}) + +func getEphemeralStorageResourceList(ephemeralStorage string) v1.ResourceList { + res := v1.ResourceList{} + if ephemeralStorage != "" { + res[v1.ResourceEphemeralStorage] = resource.MustParse(ephemeralStorage) + } + return res +} + func equalResourceRequirement(expected v1.ResourceRequirements, actual v1.ResourceRequirements) error { framework.Logf("Verifying requests: expected %v with actual %v", expected.Requests, actual.Requests) err := equalResourceList(expected.Requests, actual.Requests)