sigs.k8s.io/kueue@v0.6.2/test/integration/controller/jobs/pod/pod_webhook_test.go (about) 1 /* 2 Copyright 2023 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 pod 18 19 import ( 20 "github.com/onsi/ginkgo/v2" 21 "github.com/onsi/gomega" 22 corev1 "k8s.io/api/core/v1" 23 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 "k8s.io/apimachinery/pkg/types" 25 "k8s.io/client-go/discovery" 26 27 configapi "sigs.k8s.io/kueue/apis/config/v1beta1" 28 "sigs.k8s.io/kueue/pkg/controller/jobframework" 29 "sigs.k8s.io/kueue/pkg/util/kubeversion" 30 testingpod "sigs.k8s.io/kueue/pkg/util/testingjobs/pod" 31 "sigs.k8s.io/kueue/test/integration/framework" 32 "sigs.k8s.io/kueue/test/util" 33 ) 34 35 var _ = ginkgo.Describe("Pod Webhook", func() { 36 var ns *corev1.Namespace 37 38 ginkgo.When("with manageJobsWithoutQueueName disabled", ginkgo.Ordered, ginkgo.ContinueOnFailure, func() { 39 ginkgo.BeforeAll(func() { 40 fwk = &framework.Framework{ 41 CRDPath: crdPath, 42 WebhookPath: webhookPath, 43 } 44 cfg = fwk.Init() 45 46 discoveryClient, err := discovery.NewDiscoveryClientForConfig(cfg) 47 gomega.Expect(err).NotTo(gomega.HaveOccurred()) 48 serverVersionFetcher = kubeversion.NewServerVersionFetcher(discoveryClient) 49 err = serverVersionFetcher.FetchServerVersion() 50 gomega.Expect(err).NotTo(gomega.HaveOccurred()) 51 52 ctx, k8sClient = fwk.RunManager(cfg, managerSetup( 53 jobframework.WithManageJobsWithoutQueueName(false), 54 jobframework.WithKubeServerVersion(serverVersionFetcher), 55 jobframework.WithIntegrationOptions(corev1.SchemeGroupVersion.WithKind("Pod").String(), &configapi.PodIntegrationOptions{ 56 PodSelector: &metav1.LabelSelector{}, 57 NamespaceSelector: &metav1.LabelSelector{ 58 MatchExpressions: []metav1.LabelSelectorRequirement{ 59 { 60 Key: "kubernetes.io/metadata.name", 61 Operator: metav1.LabelSelectorOpNotIn, 62 Values: []string{"kube-system", "kueue-system"}, 63 }, 64 }, 65 }, 66 }), 67 )) 68 }) 69 ginkgo.BeforeEach(func() { 70 ns = &corev1.Namespace{ 71 ObjectMeta: metav1.ObjectMeta{ 72 GenerateName: "pod-", 73 }, 74 } 75 gomega.Expect(k8sClient.Create(ctx, ns)).To(gomega.Succeed()) 76 }) 77 78 ginkgo.AfterEach(func() { 79 gomega.Expect(util.DeleteNamespace(ctx, k8sClient, ns)).To(gomega.Succeed()) 80 }) 81 ginkgo.AfterAll(func() { 82 fwk.Teardown() 83 }) 84 85 ginkgo.When("The queue-name label is set", func() { 86 var ( 87 pod *corev1.Pod 88 lookupKey types.NamespacedName 89 ) 90 91 ginkgo.BeforeEach(func() { 92 pod = testingpod.MakePod("pod-with-queue-name", ns.Name).Queue("user-queue").Obj() 93 lookupKey = types.NamespacedName{Name: pod.Name, Namespace: pod.Namespace} 94 }) 95 96 ginkgo.It("Should inject scheduling gate, 'managed' label and finalizer into created pod", func() { 97 gomega.Expect(k8sClient.Create(ctx, pod)).Should(gomega.Succeed()) 98 99 createdPod := &corev1.Pod{} 100 gomega.Eventually(func() error { 101 return k8sClient.Get(ctx, lookupKey, createdPod) 102 }, util.Timeout, util.Interval).Should(gomega.Succeed()) 103 104 gomega.Expect(createdPod.Spec.SchedulingGates).To( 105 gomega.ContainElement(corev1.PodSchedulingGate{Name: "kueue.x-k8s.io/admission"}), 106 "Pod should have scheduling gate", 107 ) 108 109 gomega.Expect(createdPod.Labels).To( 110 gomega.HaveKeyWithValue("kueue.x-k8s.io/managed", "true"), 111 "Pod should have the label", 112 ) 113 114 gomega.Expect(createdPod.Finalizers).To(gomega.ContainElement("kueue.x-k8s.io/managed"), 115 "Pod should have finalizer set") 116 }) 117 118 ginkgo.It("Should skip a Pod created in the forbidden 'kube-system' namespace", func() { 119 pod.Namespace = "kube-system" 120 gomega.Expect(k8sClient.Create(ctx, pod)).Should(gomega.Succeed()) 121 122 lookupKey := types.NamespacedName{Name: pod.Name, Namespace: "kube-system"} 123 createdPod := &corev1.Pod{} 124 gomega.Eventually(func() error { 125 return k8sClient.Get(ctx, lookupKey, createdPod) 126 }, util.Timeout, util.Interval).Should(gomega.Succeed()) 127 128 gomega.Expect(createdPod.Spec.SchedulingGates).NotTo( 129 gomega.ContainElement(corev1.PodSchedulingGate{Name: "kueue.x-k8s.io/admission"}), 130 "Pod shouldn't have scheduling gate", 131 ) 132 133 gomega.Expect(createdPod.Labels).NotTo( 134 gomega.HaveKeyWithValue("kueue.x-k8s.io/managed", "true"), 135 "Pod shouldn't have the label", 136 ) 137 138 gomega.Expect(createdPod.Finalizers).NotTo(gomega.ContainElement("kueue.x-k8s.io/managed"), 139 "Pod shouldn't have finalizer set") 140 }) 141 }) 142 143 ginkgo.When("The queue-name label is not set", func() { 144 var ( 145 pod *corev1.Pod 146 lookupKey types.NamespacedName 147 ) 148 149 ginkgo.BeforeEach(func() { 150 pod = testingpod.MakePod("pod-with-queue-name", ns.Name).Obj() 151 lookupKey = types.NamespacedName{Name: pod.Name, Namespace: pod.Namespace} 152 }) 153 154 ginkgo.It("Should not inject scheduling gate, 'managed' label and finalizer into created pod", func() { 155 gomega.Expect(k8sClient.Create(ctx, pod)).Should(gomega.Succeed()) 156 157 createdPod := &corev1.Pod{} 158 gomega.Eventually(func() error { 159 return k8sClient.Get(ctx, lookupKey, createdPod) 160 }, util.Timeout, util.Interval).Should(gomega.Succeed()) 161 162 gomega.Expect(createdPod.Spec.SchedulingGates).NotTo( 163 gomega.ContainElement(corev1.PodSchedulingGate{Name: "kueue.x-k8s.io/admission"}), 164 "Pod shouldn't have scheduling gate", 165 ) 166 167 gomega.Expect(createdPod.Labels).NotTo( 168 gomega.HaveKeyWithValue("kueue.x-k8s.io/managed", "true"), 169 "Pod shouldn't have the label", 170 ) 171 172 gomega.Expect(createdPod.Finalizers).NotTo(gomega.ContainElement("kueue.x-k8s.io/managed"), 173 "Pod shouldn't have finalizer set") 174 }) 175 }) 176 }) 177 178 ginkgo.When("with manageJobsWithoutQueueName enabled", ginkgo.Ordered, ginkgo.ContinueOnFailure, func() { 179 ginkgo.BeforeAll(func() { 180 fwk = &framework.Framework{ 181 CRDPath: crdPath, 182 WebhookPath: webhookPath, 183 } 184 cfg = fwk.Init() 185 186 discoveryClient, err := discovery.NewDiscoveryClientForConfig(cfg) 187 gomega.Expect(err).NotTo(gomega.HaveOccurred()) 188 serverVersionFetcher = kubeversion.NewServerVersionFetcher(discoveryClient) 189 err = serverVersionFetcher.FetchServerVersion() 190 gomega.Expect(err).NotTo(gomega.HaveOccurred()) 191 192 ctx, k8sClient = fwk.RunManager(cfg, managerSetup( 193 jobframework.WithManageJobsWithoutQueueName(true), 194 jobframework.WithKubeServerVersion(serverVersionFetcher), 195 jobframework.WithIntegrationOptions(corev1.SchemeGroupVersion.WithKind("Pod").String(), &configapi.PodIntegrationOptions{ 196 PodSelector: &metav1.LabelSelector{}, 197 NamespaceSelector: &metav1.LabelSelector{ 198 MatchExpressions: []metav1.LabelSelectorRequirement{ 199 { 200 Key: "kubernetes.io/metadata.name", 201 Operator: metav1.LabelSelectorOpNotIn, 202 Values: []string{"kube-system", "kueue-system"}, 203 }, 204 }, 205 }, 206 }), 207 )) 208 }) 209 ginkgo.BeforeEach(func() { 210 ns = &corev1.Namespace{ 211 ObjectMeta: metav1.ObjectMeta{ 212 GenerateName: "pod-", 213 }, 214 } 215 gomega.Expect(k8sClient.Create(ctx, ns)).To(gomega.Succeed()) 216 }) 217 218 ginkgo.AfterEach(func() { 219 gomega.Expect(util.DeleteNamespace(ctx, k8sClient, ns)).To(gomega.Succeed()) 220 }) 221 ginkgo.AfterAll(func() { 222 fwk.Teardown() 223 }) 224 225 ginkgo.When("The queue-name label is not set", func() { 226 var pod *corev1.Pod 227 228 ginkgo.BeforeEach(func() { 229 pod = testingpod.MakePod("pod-integration", ns.Name).Obj() 230 }) 231 232 ginkgo.It("Should inject scheduling gate, 'managed' label and finalizer into created pod", func() { 233 gomega.Expect(k8sClient.Create(ctx, pod)).Should(gomega.Succeed()) 234 235 lookupKey := types.NamespacedName{Name: pod.Name, Namespace: pod.Namespace} 236 createdPod := &corev1.Pod{} 237 gomega.Eventually(func() error { 238 return k8sClient.Get(ctx, lookupKey, createdPod) 239 }, util.Timeout, util.Interval).Should(gomega.Succeed()) 240 241 gomega.Expect(createdPod.Spec.SchedulingGates).To( 242 gomega.ContainElement(corev1.PodSchedulingGate{Name: "kueue.x-k8s.io/admission"}), 243 "Pod should have scheduling gate", 244 ) 245 246 gomega.Expect(createdPod.Labels).To( 247 gomega.HaveKeyWithValue("kueue.x-k8s.io/managed", "true"), 248 "Pod should have the label", 249 ) 250 251 gomega.Expect(createdPod.Finalizers).To(gomega.ContainElement("kueue.x-k8s.io/managed"), 252 "Pod should have finalizer set") 253 }) 254 255 ginkgo.It("Should skip a Pod created in the forbidden 'kube-system' namespace", func() { 256 pod.Namespace = "kube-system" 257 gomega.Expect(k8sClient.Create(ctx, pod)).Should(gomega.Succeed()) 258 259 lookupKey := types.NamespacedName{Name: pod.Name, Namespace: "kube-system"} 260 createdPod := &corev1.Pod{} 261 gomega.Eventually(func() error { 262 return k8sClient.Get(ctx, lookupKey, createdPod) 263 }, util.Timeout, util.Interval).Should(gomega.Succeed()) 264 265 gomega.Expect(createdPod.Spec.SchedulingGates).NotTo( 266 gomega.ContainElement(corev1.PodSchedulingGate{Name: "kueue.x-k8s.io/admission"}), 267 "Pod shouldn't have scheduling gate", 268 ) 269 270 gomega.Expect(createdPod.Labels).NotTo( 271 gomega.HaveKeyWithValue("kueue.x-k8s.io/managed", "true"), 272 "Pod shouldn't have the label", 273 ) 274 275 gomega.Expect(createdPod.Finalizers).NotTo(gomega.ContainElement("kueue.x-k8s.io/managed"), 276 "Pod shouldn't have finalizer set") 277 }) 278 }) 279 }) 280 })