k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/e2e/upgrades/node/sysctl.go (about) 1 /* 2 Copyright 2017 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 node 18 19 import ( 20 "context" 21 "fmt" 22 23 "github.com/onsi/ginkgo/v2" 24 "github.com/onsi/gomega" 25 26 v1 "k8s.io/api/core/v1" 27 apierrors "k8s.io/apimachinery/pkg/api/errors" 28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 "k8s.io/apimachinery/pkg/util/uuid" 30 "k8s.io/kubernetes/pkg/kubelet/sysctl" 31 32 "k8s.io/kubernetes/test/e2e/framework" 33 e2epod "k8s.io/kubernetes/test/e2e/framework/pod" 34 e2eoutput "k8s.io/kubernetes/test/e2e/framework/pod/output" 35 "k8s.io/kubernetes/test/e2e/upgrades" 36 imageutils "k8s.io/kubernetes/test/utils/image" 37 ) 38 39 // SysctlUpgradeTest tests that a pod with sysctls runs before and after an upgrade. During 40 // a master upgrade, the exact pod is expected to stay running. A pod with unsafe sysctls is 41 // expected to keep failing before and after the upgrade. 42 type SysctlUpgradeTest struct { 43 validPod *v1.Pod 44 invalidPod *v1.Pod 45 } 46 47 // Setup creates two pods: one with safe sysctls, one with unsafe sysctls. It checks that the former 48 // launched and the later is rejected. 49 func (t *SysctlUpgradeTest) Setup(ctx context.Context, f *framework.Framework) { 50 t.validPod = t.verifySafeSysctlWork(ctx, f) 51 t.invalidPod = t.verifyUnsafeSysctlsAreRejected(ctx, f) 52 } 53 54 // Test waits for the upgrade to complete, and then verifies that a 55 // pod can still consume the ConfigMap. 56 func (t *SysctlUpgradeTest) Test(ctx context.Context, f *framework.Framework, done <-chan struct{}, upgrade upgrades.UpgradeType) { 57 <-done 58 switch upgrade { 59 case upgrades.MasterUpgrade, upgrades.ClusterUpgrade: 60 ginkgo.By("Checking the safe sysctl pod keeps running on master upgrade") 61 pod, err := f.ClientSet.CoreV1().Pods(t.validPod.Namespace).Get(ctx, t.validPod.Name, metav1.GetOptions{}) 62 framework.ExpectNoError(err) 63 gomega.Expect(pod.Status.Phase).To(gomega.Equal(v1.PodRunning)) 64 } 65 66 ginkgo.By("Checking the old unsafe sysctl pod was not suddenly started during an upgrade") 67 pod, err := f.ClientSet.CoreV1().Pods(t.invalidPod.Namespace).Get(ctx, t.invalidPod.Name, metav1.GetOptions{}) 68 if err != nil && !apierrors.IsNotFound(err) { 69 framework.ExpectNoError(err) 70 } 71 if err == nil { 72 gomega.Expect(pod.Status.Phase).NotTo(gomega.Equal(v1.PodRunning)) 73 } 74 75 t.verifySafeSysctlWork(ctx, f) 76 t.verifyUnsafeSysctlsAreRejected(ctx, f) 77 } 78 79 // Teardown cleans up any remaining resources. 80 func (t *SysctlUpgradeTest) Teardown(ctx context.Context, f *framework.Framework) { 81 // rely on the namespace deletion to clean up everything 82 } 83 84 func (t *SysctlUpgradeTest) verifySafeSysctlWork(ctx context.Context, f *framework.Framework) *v1.Pod { 85 ginkgo.By("Creating a pod with safe sysctls") 86 safeSysctl := "net.ipv4.ip_local_port_range" 87 safeSysctlValue := "1024 1042" 88 sysctlTestPod("valid-sysctls", map[string]string{safeSysctl: safeSysctlValue}) 89 validPod := e2epod.NewPodClient(f).Create(ctx, t.validPod) 90 91 ginkgo.By("Making sure the valid pod launches") 92 _, err := e2epod.NewPodClient(f).WaitForErrorEventOrSuccess(ctx, t.validPod) 93 framework.ExpectNoError(err) 94 e2eoutput.TestContainerOutput(ctx, f, "pod with safe sysctl launched", t.validPod, 0, []string{fmt.Sprintf("%s = %s", safeSysctl, safeSysctlValue)}) 95 96 return validPod 97 } 98 99 func (t *SysctlUpgradeTest) verifyUnsafeSysctlsAreRejected(ctx context.Context, f *framework.Framework) *v1.Pod { 100 ginkgo.By("Creating a pod with unsafe sysctls") 101 invalidPod := sysctlTestPod("valid-sysctls-"+string(uuid.NewUUID()), map[string]string{ 102 "fs.mount-max": "1000000", 103 }) 104 invalidPod = e2epod.NewPodClient(f).Create(ctx, invalidPod) 105 106 ginkgo.By("Making sure the invalid pod failed") 107 ev, err := e2epod.NewPodClient(f).WaitForErrorEventOrSuccess(ctx, invalidPod) 108 framework.ExpectNoError(err) 109 gomega.Expect(ev.Reason).To(gomega.Equal(sysctl.ForbiddenReason)) 110 111 return invalidPod 112 } 113 114 func sysctlTestPod(name string, sysctls map[string]string) *v1.Pod { 115 sysctlList := []v1.Sysctl{} 116 keys := []string{} 117 for k, v := range sysctls { 118 sysctlList = append(sysctlList, v1.Sysctl{Name: k, Value: v}) 119 keys = append(keys, k) 120 } 121 return &v1.Pod{ 122 ObjectMeta: metav1.ObjectMeta{ 123 Name: name, 124 }, 125 Spec: v1.PodSpec{ 126 Containers: []v1.Container{ 127 { 128 Name: "test-container", 129 Image: imageutils.GetE2EImage(imageutils.BusyBox), 130 Command: append([]string{"/bin/sysctl"}, keys...), 131 }, 132 }, 133 RestartPolicy: v1.RestartPolicyNever, 134 SecurityContext: &v1.PodSecurityContext{ 135 Sysctls: sysctlList, 136 }, 137 }, 138 } 139 }