1
16
17 package windows
18
19 import (
20 "context"
21
22 "time"
23
24 v1 "k8s.io/api/core/v1"
25 "k8s.io/apimachinery/pkg/api/resource"
26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27 "k8s.io/apimachinery/pkg/util/uuid"
28 "k8s.io/kubernetes/test/e2e/feature"
29 "k8s.io/kubernetes/test/e2e/framework"
30 e2ekubelet "k8s.io/kubernetes/test/e2e/framework/kubelet"
31 e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
32 imageutils "k8s.io/kubernetes/test/utils/image"
33 admissionapi "k8s.io/pod-security-admission/api"
34
35 "github.com/onsi/ginkgo/v2"
36 "github.com/onsi/gomega"
37 )
38
39 var _ = sigDescribe(feature.Windows, "Cpu Resources", framework.WithSerial(), skipUnlessWindows(func() {
40 f := framework.NewDefaultFramework("cpu-resources-test-windows")
41 f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
42
43
44 powershellImage := imageutils.GetConfig(imageutils.BusyBox)
45
46 ginkgo.Context("Container limits", func() {
47 ginkgo.It("should not be exceeded after waiting 2 minutes", func(ctx context.Context) {
48 ginkgo.By("Creating one pod with limit set to '0.5'")
49 podsDecimal := newCPUBurnPods(1, powershellImage, "0.5", "1Gi")
50 e2epod.NewPodClient(f).CreateBatch(ctx, podsDecimal)
51 ginkgo.By("Creating one pod with limit set to '500m'")
52 podsMilli := newCPUBurnPods(1, powershellImage, "500m", "1Gi")
53 e2epod.NewPodClient(f).CreateBatch(ctx, podsMilli)
54 ginkgo.By("Waiting 2 minutes")
55 time.Sleep(2 * time.Minute)
56 ginkgo.By("Ensuring pods are still running")
57 var allPods []*v1.Pod
58 for _, p := range podsDecimal {
59 pod, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Get(
60 ctx,
61 p.Name,
62 metav1.GetOptions{})
63 framework.ExpectNoError(err, "Error retrieving pod")
64 gomega.Expect(pod.Status.Phase).To(gomega.Equal(v1.PodRunning))
65 allPods = append(allPods, pod)
66 }
67 for _, p := range podsMilli {
68 pod, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Get(
69 ctx,
70 p.Name,
71 metav1.GetOptions{})
72 framework.ExpectNoError(err, "Error retrieving pod")
73 gomega.Expect(pod.Status.Phase).To(gomega.Equal(v1.PodRunning))
74 allPods = append(allPods, pod)
75 }
76 ginkgo.By("Ensuring cpu doesn't exceed limit by >5%")
77 for _, p := range allPods {
78 ginkgo.By("Gathering node summary stats")
79 nodeStats, err := e2ekubelet.GetStatsSummary(ctx, f.ClientSet, p.Spec.NodeName)
80 framework.ExpectNoError(err, "Error grabbing node summary stats")
81 found := false
82 cpuUsage := float64(0)
83 for _, pod := range nodeStats.Pods {
84 if pod.PodRef.Name != p.Name || pod.PodRef.Namespace != p.Namespace {
85 continue
86 }
87 cpuUsage = float64(*pod.CPU.UsageNanoCores) * 1e-9
88 found = true
89 break
90 }
91 if !found {
92 framework.Failf("Pod %s/%s not found in the stats summary %+v", p.Namespace, p.Name, allPods)
93 }
94 framework.Logf("Pod %s usage: %v", p.Name, cpuUsage)
95 if cpuUsage <= 0 {
96 framework.Failf("Pod %s/%s reported usage is %v, but it should be greater than 0", p.Namespace, p.Name, cpuUsage)
97 }
98 if cpuUsage >= .5*1.05 {
99 framework.Failf("Pod %s/%s reported usage is %v, but it should not exceed limit by > 5%%", p.Namespace, p.Name, cpuUsage)
100 }
101 }
102 })
103 })
104 }))
105
106
107 func newCPUBurnPods(numPods int, image imageutils.Config, cpuLimit string, memoryLimit string) []*v1.Pod {
108 var pods []*v1.Pod
109
110 memLimitQuantity, err := resource.ParseQuantity(memoryLimit)
111 framework.ExpectNoError(err)
112
113 cpuLimitQuantity, err := resource.ParseQuantity(cpuLimit)
114 framework.ExpectNoError(err)
115
116 for i := 0; i < numPods; i++ {
117
118 podName := "cpulimittest-" + string(uuid.NewUUID())
119 pod := v1.Pod{
120 ObjectMeta: metav1.ObjectMeta{
121 Name: podName,
122 Labels: map[string]string{
123 "name": podName,
124 "testapp": "cpuburn",
125 },
126 },
127 Spec: v1.PodSpec{
128
129 Containers: []v1.Container{
130 {
131 Image: image.GetE2EImage(),
132 Name: podName,
133 Resources: v1.ResourceRequirements{
134 Limits: v1.ResourceList{
135 v1.ResourceMemory: memLimitQuantity,
136 v1.ResourceCPU: cpuLimitQuantity,
137 },
138 },
139 Command: []string{
140 "powershell.exe",
141 "-Command",
142 "foreach ($loopnumber in 1..8) { Start-Job -ScriptBlock { $result = 1; foreach($mm in 1..2147483647){$res1=1;foreach($num in 1..2147483647){$res1=$mm*$num*1340371};$res1} } } ; get-job | wait-job",
143 },
144 },
145 },
146 NodeSelector: map[string]string{
147 "kubernetes.io/os": "windows",
148 },
149 },
150 }
151
152 pods = append(pods, &pod)
153 }
154
155 return pods
156 }
157
View as plain text