@@ -21,6 +21,7 @@ import (
21
21
"testing"
22
22
"time"
23
23
24
+ kftrainingv1 "github.com/kubeflow/training-operator/pkg/apis/kubeflow.org/v1"
24
25
. "github.com/onsi/gomega"
25
26
awv1beta2 "github.com/project-codeflare/appwrapper/api/v1beta2"
26
27
. "github.com/project-codeflare/codeflare-common/support"
@@ -35,26 +36,30 @@ import (
35
36
"k8s.io/apimachinery/pkg/types"
36
37
"k8s.io/client-go/kubernetes/scheme"
37
38
kueuev1beta1 "sigs.k8s.io/kueue/apis/kueue/v1beta1"
39
+ testingpytorchjob "sigs.k8s.io/kueue/pkg/util/testingjobs/pytorchjob"
38
40
testingraycluster "sigs.k8s.io/kueue/pkg/util/testingjobs/raycluster"
39
41
)
40
42
41
43
// Note: This test must run on an OCP v4.17 or later cluster.
42
44
// The Validating Admission Policy feature gate is GA and enabled by default from OCP v4.17 (k8s v1.30)
43
45
44
46
var (
45
- ns * corev1.Namespace
46
- nsNoLabel * corev1.Namespace
47
- rf * kueuev1beta1.ResourceFlavor
48
- cq * kueuev1beta1.ClusterQueue
49
- lq * kueuev1beta1.LocalQueue
50
- rc * rayv1.RayCluster
51
- aw * awv1beta2.AppWrapper
52
- vapb * vapv1.ValidatingAdmissionPolicyBinding
53
- vapbCopy * vapv1.ValidatingAdmissionPolicyBinding
54
- awWithLQName = "aw-with-lq"
55
- awNoLQName = "aw-no-lq"
56
- rcWithLQName = "rc-with-lq"
57
- rcNoLQName = "rc-no-lq"
47
+ ns * corev1.Namespace
48
+ nsNoLabel * corev1.Namespace
49
+ rf * kueuev1beta1.ResourceFlavor
50
+ cq * kueuev1beta1.ClusterQueue
51
+ lq * kueuev1beta1.LocalQueue
52
+ rc * rayv1.RayCluster
53
+ aw * awv1beta2.AppWrapper
54
+ pyt * kftrainingv1.PyTorchJob
55
+ vapb * vapv1.ValidatingAdmissionPolicyBinding
56
+ vapbCopy * vapv1.ValidatingAdmissionPolicyBinding
57
+ awWithLQName = "aw-with-lq"
58
+ awNoLQName = "aw-no-lq"
59
+ rcWithLQName = "rc-with-lq"
60
+ rcNoLQName = "rc-no-lq"
61
+ pytWithLQName = "pyt-with-lq"
62
+ pytNoLQName = "pyt-no-lq"
58
63
)
59
64
60
65
const (
@@ -156,6 +161,18 @@ func TestValidatingAdmissionPolicy(t *testing.T) {
156
161
defer test .Client ().Dynamic ().Resource (awv1beta2 .GroupVersion .WithResource ("appwrappers" )).Namespace (ns .Name ).Delete (test .Ctx (), aw .Name , metav1.DeleteOptions {})
157
162
})
158
163
})
164
+ t .Run ("PyTorchJob Tests" , func (t * testing.T ) {
165
+ t .Run ("PyTorchJob should be admitted with the 'kueue.x-k8s.io/queue-name' label set" , func (t * testing.T ) {
166
+ err = createPyTorchJob (test , ns .Name , withLQ )
167
+ test .Expect (err ).ToNot (HaveOccurred ())
168
+ defer test .Client ().Kubeflow ().KubeflowV1 ().PyTorchJobs (ns .Name ).Delete (test .Ctx (), pyt .Name , metav1.DeleteOptions {})
169
+ })
170
+ t .Run ("PyTorchJob should not be admitted without the 'kueue.x-k8s.io/queue-name' label set" , func (t * testing.T ) {
171
+ err = createPyTorchJob (test , ns .Name , noLQ )
172
+ test .Expect (err ).ToNot (BeNil ())
173
+ defer test .Client ().Kubeflow ().KubeflowV1 ().PyTorchJobs (ns .Name ).Delete (test .Ctx (), pyt .Name , metav1.DeleteOptions {})
174
+ })
175
+ })
159
176
})
160
177
161
178
/**************************************************************************
@@ -196,6 +213,18 @@ func TestValidatingAdmissionPolicy(t *testing.T) {
196
213
defer test .Client ().Dynamic ().Resource (awv1beta2 .GroupVersion .WithResource ("appwrappers" )).Namespace (ns .Name ).Delete (test .Ctx (), aw .Name , metav1.DeleteOptions {})
197
214
})
198
215
})
216
+ t .Run ("PyTorchJob Tests" , func (t * testing.T ) {
217
+ t .Run ("PyTorchJob should be admitted with the 'kueue.x-k8s.io/queue-name' label set" , func (t * testing.T ) {
218
+ err = createPyTorchJob (test , ns .Name , withLQ )
219
+ test .Expect (err ).ToNot (HaveOccurred ())
220
+ defer test .Client ().Kubeflow ().KubeflowV1 ().PyTorchJobs (ns .Name ).Delete (test .Ctx (), pyt .Name , metav1.DeleteOptions {})
221
+ })
222
+ t .Run ("PyTorchJob should be admitted without the 'kueue.x-k8s.io/queue-name' label set" , func (t * testing.T ) {
223
+ err = createPyTorchJob (test , ns .Name , noLQ )
224
+ test .Expect (err ).ToNot (HaveOccurred ())
225
+ defer test .Client ().Kubeflow ().KubeflowV1 ().PyTorchJobs (ns .Name ).Delete (test .Ctx (), pyt .Name , metav1.DeleteOptions {})
226
+ })
227
+ })
199
228
})
200
229
201
230
/**************************************************************************
@@ -271,6 +300,28 @@ func TestValidatingAdmissionPolicy(t *testing.T) {
271
300
defer test .Client ().Dynamic ().Resource (awv1beta2 .GroupVersion .WithResource ("appwrappers" )).Namespace (nsNoLabel .Name ).Delete (test .Ctx (), aw .Name , metav1.DeleteOptions {})
272
301
})
273
302
})
303
+ t .Run ("PyTorchJob Tests" , func (t * testing.T ) {
304
+ t .Run ("PyTorchJob should be admitted with the 'kueue.x-k8s.io/queue-name' label in a labeled namespace" , func (t * testing.T ) {
305
+ err = createPyTorchJob (test , ns .Name , withLQ )
306
+ test .Expect (err ).ToNot (HaveOccurred ())
307
+ defer test .Client ().Kubeflow ().KubeflowV1 ().PyTorchJobs (ns .Name ).Delete (test .Ctx (), pyt .Name , metav1.DeleteOptions {})
308
+ })
309
+ t .Run ("PyTorchJob should not be admitted without the 'kueue.x-k8s.io/queue-name' label in a labeled namespace" , func (t * testing.T ) {
310
+ err = createPyTorchJob (test , ns .Name , noLQ )
311
+ test .Expect (err ).ToNot (BeNil ())
312
+ defer test .Client ().Kubeflow ().KubeflowV1 ().PyTorchJobs (ns .Name ).Delete (test .Ctx (), pyt .Name , metav1.DeleteOptions {})
313
+ })
314
+ t .Run ("PyTorchJob should be admitted with the 'kueue.x-k8s.io/queue-name' label in any other namespace" , func (t * testing.T ) {
315
+ err = createPyTorchJob (test , nsNoLabel .Name , withLQ )
316
+ test .Expect (err ).ToNot (HaveOccurred ())
317
+ defer test .Client ().Kubeflow ().KubeflowV1 ().PyTorchJobs (ns .Name ).Delete (test .Ctx (), pyt .Name , metav1.DeleteOptions {})
318
+ })
319
+ t .Run ("PyTorchJob should be admitted without the 'kueue.x-k8s.io/queue-name' label in any other namespace" , func (t * testing.T ) {
320
+ err = createPyTorchJob (test , nsNoLabel .Name , noLQ )
321
+ test .Expect (err ).ToNot (HaveOccurred ())
322
+ defer test .Client ().Kubeflow ().KubeflowV1 ().PyTorchJobs (ns .Name ).Delete (test .Ctx (), pyt .Name , metav1.DeleteOptions {})
323
+ })
324
+ })
274
325
})
275
326
}
276
327
@@ -315,3 +366,13 @@ func createAppWrapper(test Test, namespaceName string, localQueue bool) error {
315
366
_ , err := test .Client ().Dynamic ().Resource (awv1beta2 .GroupVersion .WithResource ("appwrappers" )).Namespace (namespaceName ).Create (test .Ctx (), & unstructured.Unstructured {Object : awMap }, metav1.CreateOptions {})
316
367
return err
317
368
}
369
+
370
+ func createPyTorchJob (test Test , namespaceName string , localQueue bool ) error {
371
+ if localQueue {
372
+ pyt = testingpytorchjob .MakePyTorchJob (uniqueSuffix (pytWithLQName ), namespaceName ).Queue (lq .Name ).Obj ()
373
+ } else {
374
+ pyt = testingpytorchjob .MakePyTorchJob (uniqueSuffix (pytNoLQName ), namespaceName ).Obj ()
375
+ }
376
+ _ , err := test .Client ().Kubeflow ().KubeflowV1 ().PyTorchJobs (namespaceName ).Create (test .Ctx (), pyt , metav1.CreateOptions {})
377
+ return err
378
+ }
0 commit comments