1
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
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
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
178 func newRuntimeClass(namespace, name string) *nodev1.RuntimeClass {
179 uniqueName := fmt.Sprintf("%s-%s", namespace, name)
180 return runtimeclasstest.NewRuntimeClass(uniqueName, e2eruntimeclass.PreconfiguredRuntimeClassHandler)
181 }
182
View as plain text