k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/e2e/node/runtimeclass.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 node 18 19 import ( 20 "context" 21 "fmt" 22 23 "k8s.io/pod-security-admission/api" 24 25 v1 "k8s.io/api/core/v1" 26 nodev1 "k8s.io/api/node/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 runtimeclasstest "k8s.io/kubernetes/pkg/kubelet/runtimeclass/testing" 31 "k8s.io/kubernetes/test/e2e/framework" 32 e2enode "k8s.io/kubernetes/test/e2e/framework/node" 33 e2eruntimeclass "k8s.io/kubernetes/test/e2e/framework/node/runtimeclass" 34 e2epod "k8s.io/kubernetes/test/e2e/framework/pod" 35 e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper" 36 "k8s.io/kubernetes/test/e2e/scheduling" 37 38 "github.com/onsi/ginkgo/v2" 39 "github.com/onsi/gomega" 40 ) 41 42 var _ = SIGDescribe("RuntimeClass", func() { 43 f := framework.NewDefaultFramework("runtimeclass") 44 f.NamespacePodSecurityLevel = api.LevelPrivileged 45 46 ginkgo.It("should reject a Pod requesting a RuntimeClass with conflicting node selector", func(ctx context.Context) { 47 labelFooName := "foo-" + string(uuid.NewUUID()) 48 49 scheduling := &nodev1.Scheduling{ 50 NodeSelector: map[string]string{ 51 labelFooName: "conflict", 52 }, 53 } 54 55 runtimeClass := newRuntimeClass(f.Namespace.Name, "conflict-runtimeclass") 56 runtimeClass.Scheduling = scheduling 57 rc, err := f.ClientSet.NodeV1().RuntimeClasses().Create(ctx, runtimeClass, metav1.CreateOptions{}) 58 framework.ExpectNoError(err, "failed to create RuntimeClass resource") 59 60 pod := e2eruntimeclass.NewRuntimeClassPod(rc.GetName()) 61 pod.Spec.NodeSelector = map[string]string{ 62 labelFooName: "bar", 63 } 64 _, err = f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(ctx, pod, metav1.CreateOptions{}) 65 if !apierrors.IsForbidden(err) { 66 framework.Failf("expected 'forbidden' as error, got instead: %v", err) 67 } 68 }) 69 70 f.It("should run a Pod requesting a RuntimeClass with scheduling with taints", f.WithSerial(), func(ctx context.Context) { 71 labelFooName := "foo-" + string(uuid.NewUUID()) 72 labelFizzName := "fizz-" + string(uuid.NewUUID()) 73 74 nodeName := scheduling.GetNodeThatCanRunPod(ctx, f) 75 nodeSelector := map[string]string{ 76 labelFooName: "bar", 77 labelFizzName: "buzz", 78 } 79 tolerations := []v1.Toleration{ 80 { 81 Key: labelFooName, 82 Operator: v1.TolerationOpEqual, 83 Value: "bar", 84 Effect: v1.TaintEffectNoSchedule, 85 }, 86 } 87 scheduling := &nodev1.Scheduling{ 88 NodeSelector: nodeSelector, 89 Tolerations: tolerations, 90 } 91 92 ginkgo.By("Trying to apply a label on the found node.") 93 for key, value := range nodeSelector { 94 e2enode.AddOrUpdateLabelOnNode(f.ClientSet, nodeName, key, value) 95 e2enode.ExpectNodeHasLabel(ctx, f.ClientSet, nodeName, key, value) 96 ginkgo.DeferCleanup(e2enode.RemoveLabelOffNode, f.ClientSet, nodeName, key) 97 } 98 99 ginkgo.By("Trying to apply taint on the found node.") 100 taint := v1.Taint{ 101 Key: labelFooName, 102 Value: "bar", 103 Effect: v1.TaintEffectNoSchedule, 104 } 105 e2enode.AddOrUpdateTaintOnNode(ctx, f.ClientSet, nodeName, taint) 106 e2enode.ExpectNodeHasTaint(ctx, f.ClientSet, nodeName, &taint) 107 ginkgo.DeferCleanup(e2enode.RemoveTaintOffNode, f.ClientSet, nodeName, taint) 108 109 ginkgo.By("Trying to create runtimeclass and pod") 110 runtimeClass := newRuntimeClass(f.Namespace.Name, "non-conflict-runtimeclass") 111 runtimeClass.Scheduling = scheduling 112 rc, err := f.ClientSet.NodeV1().RuntimeClasses().Create(ctx, runtimeClass, metav1.CreateOptions{}) 113 framework.ExpectNoError(err, "failed to create RuntimeClass resource") 114 115 pod := e2eruntimeclass.NewRuntimeClassPod(rc.GetName()) 116 pod.Spec.NodeSelector = map[string]string{ 117 labelFooName: "bar", 118 } 119 pod = e2epod.NewPodClient(f).Create(ctx, pod) 120 121 framework.ExpectNoError(e2epod.WaitForPodNotPending(ctx, f.ClientSet, f.Namespace.Name, pod.Name)) 122 123 // check that pod got scheduled on specified node. 124 scheduledPod, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Get(ctx, pod.Name, metav1.GetOptions{}) 125 framework.ExpectNoError(err) 126 gomega.Expect(nodeName).To(gomega.Equal(scheduledPod.Spec.NodeName)) 127 gomega.Expect(nodeSelector).To(gomega.Equal(pod.Spec.NodeSelector)) 128 gomega.Expect(pod.Spec.Tolerations).To(gomega.ContainElement(tolerations[0])) 129 }) 130 131 ginkgo.It("should run a Pod requesting a RuntimeClass with scheduling without taints ", func(ctx context.Context) { 132 if err := e2eruntimeclass.NodeSupportsPreconfiguredRuntimeClassHandler(ctx, f); err != nil { 133 e2eskipper.Skipf("Skipping test as node does not have E2E runtime class handler preconfigured in container runtime config: %v", err) 134 } 135 136 labelFooName := "foo-" + string(uuid.NewUUID()) 137 labelFizzName := "fizz-" + string(uuid.NewUUID()) 138 139 nodeName := scheduling.GetNodeThatCanRunPod(ctx, f) 140 nodeSelector := map[string]string{ 141 labelFooName: "bar", 142 labelFizzName: "buzz", 143 } 144 scheduling := &nodev1.Scheduling{ 145 NodeSelector: nodeSelector, 146 } 147 148 ginkgo.By("Trying to apply a label on the found node.") 149 for key, value := range nodeSelector { 150 e2enode.AddOrUpdateLabelOnNode(f.ClientSet, nodeName, key, value) 151 e2enode.ExpectNodeHasLabel(ctx, f.ClientSet, nodeName, key, value) 152 ginkgo.DeferCleanup(e2enode.RemoveLabelOffNode, f.ClientSet, nodeName, key) 153 } 154 155 ginkgo.By("Trying to create runtimeclass and pod") 156 runtimeClass := newRuntimeClass(f.Namespace.Name, "non-conflict-runtimeclass") 157 runtimeClass.Scheduling = scheduling 158 rc, err := f.ClientSet.NodeV1().RuntimeClasses().Create(ctx, runtimeClass, metav1.CreateOptions{}) 159 framework.ExpectNoError(err, "failed to create RuntimeClass resource") 160 161 pod := e2eruntimeclass.NewRuntimeClassPod(rc.GetName()) 162 pod.Spec.NodeSelector = map[string]string{ 163 labelFooName: "bar", 164 } 165 pod = e2epod.NewPodClient(f).Create(ctx, pod) 166 167 framework.ExpectNoError(e2epod.WaitForPodNotPending(ctx, f.ClientSet, f.Namespace.Name, pod.Name)) 168 169 // check that pod got scheduled on specified node. 170 scheduledPod, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Get(ctx, pod.Name, metav1.GetOptions{}) 171 framework.ExpectNoError(err) 172 gomega.Expect(nodeName).To(gomega.Equal(scheduledPod.Spec.NodeName)) 173 gomega.Expect(nodeSelector).To(gomega.Equal(pod.Spec.NodeSelector)) 174 }) 175 }) 176 177 // newRuntimeClass returns a test runtime class. 178 func newRuntimeClass(namespace, name string) *nodev1.RuntimeClass { 179 uniqueName := fmt.Sprintf("%s-%s", namespace, name) 180 return runtimeclasstest.NewRuntimeClass(uniqueName, e2eruntimeclass.PreconfiguredRuntimeClassHandler) 181 }