k8s.io/kubernetes@v1.29.3/test/e2e_node/system_node_critical_test.go (about) 1 /* 2 Copyright 2019 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package e2enode 18 19 import ( 20 "context" 21 "fmt" 22 "os" 23 "time" 24 25 v1 "k8s.io/api/core/v1" 26 "k8s.io/apimachinery/pkg/api/resource" 27 "k8s.io/apimachinery/pkg/util/uuid" 28 kubeapi "k8s.io/kubernetes/pkg/apis/core" 29 kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config" 30 evictionapi "k8s.io/kubernetes/pkg/kubelet/eviction/api" 31 "k8s.io/kubernetes/test/e2e/framework" 32 "k8s.io/kubernetes/test/e2e/nodefeature" 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("SystemNodeCriticalPod", framework.WithSlow(), framework.WithSerial(), framework.WithDisruptive(), nodefeature.SystemNodeCriticalPod, func() { 40 f := framework.NewDefaultFramework("system-node-critical-pod-test") 41 f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged 42 // this test only manipulates pods in kube-system 43 f.SkipNamespaceCreation = true 44 45 ginkgo.AfterEach(func() { 46 if framework.TestContext.PrepullImages { 47 // The test may cause the prepulled images to be evicted, 48 // prepull those images again to ensure this test not affect following tests. 49 PrePullAllImages() 50 } 51 }) 52 53 ginkgo.Context("when create a system-node-critical pod", func() { 54 tempSetCurrentKubeletConfig(f, func(ctx context.Context, initialConfig *kubeletconfig.KubeletConfiguration) { 55 diskConsumed := resource.MustParse("200Mi") 56 summary := eventuallyGetSummary(ctx) 57 availableBytes := *(summary.Node.Fs.AvailableBytes) 58 initialConfig.EvictionHard = map[string]string{string(evictionapi.SignalNodeFsAvailable): fmt.Sprintf("%d", availableBytes-uint64(diskConsumed.Value()))} 59 initialConfig.EvictionMinimumReclaim = map[string]string{} 60 }) 61 62 // Place the remainder of the test within a context so that the kubelet config is set before and after the test. 63 ginkgo.Context("", func() { 64 var staticPodName, mirrorPodName, podPath string 65 ns := kubeapi.NamespaceSystem 66 67 ginkgo.BeforeEach(func(ctx context.Context) { 68 ginkgo.By("create a static system-node-critical pod") 69 staticPodName = "static-disk-hog-" + string(uuid.NewUUID()) 70 mirrorPodName = staticPodName + "-" + framework.TestContext.NodeName 71 podPath = kubeletCfg.StaticPodPath 72 // define a static pod consuming disk gradually 73 // the upper limit is 1024 (iterations) * 10485760 bytes (10MB) = 10GB 74 err := createStaticSystemNodeCriticalPod( 75 podPath, staticPodName, ns, busyboxImage, v1.RestartPolicyNever, 1024, 76 "dd if=/dev/urandom of=file${i} bs=10485760 count=1 2>/dev/null; sleep .1;", 77 ) 78 gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) 79 80 ginkgo.By("wait for the mirror pod to be running") 81 gomega.Eventually(ctx, func(ctx context.Context) error { 82 return checkMirrorPodRunning(ctx, f.ClientSet, mirrorPodName, ns) 83 }, time.Minute, time.Second*2).Should(gomega.Succeed()) 84 }) 85 86 ginkgo.It("should not be evicted upon DiskPressure", func(ctx context.Context) { 87 ginkgo.By("wait for the node to have DiskPressure condition") 88 gomega.Eventually(ctx, func(ctx context.Context) error { 89 if hasNodeCondition(ctx, f, v1.NodeDiskPressure) { 90 return nil 91 } 92 msg := fmt.Sprintf("NodeCondition: %s not encountered yet", v1.NodeDiskPressure) 93 framework.Logf(msg) 94 return fmt.Errorf(msg) 95 }, time.Minute*2, time.Second*4).Should(gomega.Succeed()) 96 97 ginkgo.By("check if it's running all the time") 98 gomega.Consistently(ctx, func(ctx context.Context) error { 99 err := checkMirrorPodRunning(ctx, f.ClientSet, mirrorPodName, ns) 100 if err == nil { 101 framework.Logf("mirror pod %q is running", mirrorPodName) 102 } else { 103 framework.Logf(err.Error()) 104 } 105 return err 106 }, time.Minute*8, time.Second*4).ShouldNot(gomega.HaveOccurred()) 107 }) 108 ginkgo.AfterEach(func(ctx context.Context) { 109 defer func() { 110 if framework.TestContext.PrepullImages { 111 // The test may cause the prepulled images to be evicted, 112 // prepull those images again to ensure this test not affect following tests. 113 PrePullAllImages() 114 } 115 }() 116 ginkgo.By("delete the static pod") 117 err := deleteStaticPod(podPath, staticPodName, ns) 118 gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) 119 120 ginkgo.By("wait for the mirror pod to disappear") 121 gomega.Eventually(ctx, func(ctx context.Context) error { 122 return checkMirrorPodDisappear(ctx, f.ClientSet, mirrorPodName, ns) 123 }, time.Minute, time.Second*2).Should(gomega.Succeed()) 124 125 ginkgo.By("making sure that node no longer has DiskPressure") 126 gomega.Eventually(ctx, func(ctx context.Context) error { 127 if hasNodeCondition(ctx, f, v1.NodeDiskPressure) { 128 return fmt.Errorf("Conditions haven't returned to normal, node still has DiskPressure") 129 } 130 return nil 131 }, pressureDisappearTimeout, evictionPollInterval).Should(gomega.Succeed()) 132 }) 133 }) 134 }) 135 }) 136 137 func createStaticSystemNodeCriticalPod(dir, name, namespace, image string, restart v1.RestartPolicy, 138 iterations int, command string) error { 139 template := ` 140 apiVersion: v1 141 kind: Pod 142 metadata: 143 name: %s 144 namespace: %s 145 spec: 146 priorityClassName: system-node-critical 147 containers: 148 - name: %s 149 image: %s 150 command: ["sh", "-c", "i=0; while [ $i -lt %d ]; do %s i=$(($i+1)); done; while true; do sleep 5; done"] 151 restartPolicy: %s 152 ` 153 file := staticPodPath(dir, name, namespace) 154 podYaml := fmt.Sprintf(template, name, namespace, name, image, iterations, command, string(restart)) 155 156 f, err := os.OpenFile(file, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0666) 157 if err != nil { 158 return err 159 } 160 defer f.Close() 161 162 _, err = f.WriteString(podYaml) 163 return err 164 }