Skip to content

Commit 4937906

Browse files
[no-relnote] E2E Create test objects from file
Signed-off-by: Carlos Eduardo Arango Gutierrez <[email protected]>
1 parent 047d5f4 commit 4937906

File tree

4 files changed

+114
-53
lines changed

4 files changed

+114
-53
lines changed

tests/e2e/data/job-1.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
apiVersion: batch/v1
2+
kind: Job
3+
metadata:
4+
name: j-e2e-1
5+
labels:
6+
app.nvidia.com: k8s-device-plugin-test-app
7+
spec:
8+
template:
9+
metadata:
10+
name: gpu-pod
11+
spec:
12+
restartPolicy: Never
13+
containers:
14+
- name: cuda-container
15+
image: nvcr.io/nvidia/k8s/cuda-sample:nbody-cuda11.7.1-ubuntu18.04
16+
args:
17+
- "--benchmark"
18+
- "--numbodies=10000"
19+
resources:
20+
limits:
21+
nvidia.com/gpu: "1"
22+
tolerations:
23+
- key: "nvidia.com/gpu"
24+
operator: "Exists"
25+
effect: "NoSchedule"

tests/e2e/device-plugin_test.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,15 +133,12 @@ var _ = Describe("GPU Device Plugin", Ordered, func() {
133133
})
134134
It("it should run GPU jobs", func(ctx context.Context) {
135135
By("Creating a GPU job")
136-
job := newGPUJob(testNamespace.Name)
137-
job.Namespace = testNamespace.Name
138-
139-
_, err := clientSet.BatchV1().Jobs(testNamespace.Name).Create(ctx, job, metav1.CreateOptions{})
136+
job, err := CreateOrUpdateJobsFromFile(ctx, clientSet, "job-1.yaml", testNamespace.Name)
140137
Expect(err).NotTo(HaveOccurred())
141138

142139
By("Waiting for job to complete")
143140
Eventually(func() error {
144-
job, err := clientSet.BatchV1().Jobs(testNamespace.Name).Get(ctx, job.Name, metav1.GetOptions{})
141+
job, err := clientSet.BatchV1().Jobs(testNamespace.Name).Get(ctx, job[0], metav1.GetOptions{})
145142
if err != nil {
146143
return err
147144
}

tests/e2e/e2e_test.go

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"log"
2424
"os"
2525
"path/filepath"
26-
"runtime"
2726
"strconv"
2827
"testing"
2928
"time"
@@ -34,11 +33,9 @@ import (
3433
. "github.com/onsi/ginkgo/v2"
3534
. "github.com/onsi/gomega"
3635

37-
batchv1 "k8s.io/api/batch/v1"
3836
corev1 "k8s.io/api/core/v1"
3937
extclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
4038
apierrors "k8s.io/apimachinery/pkg/api/errors"
41-
"k8s.io/apimachinery/pkg/api/resource"
4239
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
4340
"k8s.io/apimachinery/pkg/util/rand"
4441
"k8s.io/apimachinery/pkg/util/wait"
@@ -56,7 +53,6 @@ const (
5653
)
5754

5855
var (
59-
packagePath string
6056
Kubeconfig string
6157
Timeout time.Duration
6258
HelmChart string
@@ -186,9 +182,6 @@ func getTestEnv() {
186182
defer GinkgoRecover()
187183
var err error
188184

189-
_, thisFile, _, _ := runtime.Caller(0)
190-
packagePath = filepath.Dir(thisFile)
191-
192185
Kubeconfig = os.Getenv("KUBECONFIG")
193186
Expect(Kubeconfig).NotTo(BeEmpty(), "KUBECONFIG must be set")
194187

@@ -284,44 +277,3 @@ func CreateTestingNS(baseName string, c clientset.Interface, labels map[string]s
284277

285278
return got, nil
286279
}
287-
288-
func newGPUJob(namespace string) *batchv1.Job {
289-
return &batchv1.Job{
290-
ObjectMeta: metav1.ObjectMeta{
291-
Name: "gpu-job",
292-
Namespace: namespace,
293-
Labels: map[string]string{
294-
"app.nvidia.com": "k8s-device-plugin-test-app",
295-
},
296-
},
297-
Spec: batchv1.JobSpec{
298-
Template: corev1.PodTemplateSpec{
299-
ObjectMeta: metav1.ObjectMeta{
300-
Name: "gpu-pod",
301-
},
302-
Spec: corev1.PodSpec{
303-
RestartPolicy: corev1.RestartPolicyNever,
304-
Containers: []corev1.Container{
305-
{
306-
Name: "cuda-container",
307-
Image: "nvcr.io/nvidia/k8s/cuda-sample:nbody-cuda11.7.1-ubuntu18.04",
308-
Args: []string{"--benchmark", "--numbodies=10000"},
309-
Resources: corev1.ResourceRequirements{
310-
Limits: corev1.ResourceList{
311-
"nvidia.com/gpu": resource.MustParse("1"),
312-
},
313-
},
314-
},
315-
},
316-
Tolerations: []corev1.Toleration{
317-
{
318-
Key: "nvidia.com/gpu",
319-
Operator: corev1.TolerationOpExists,
320-
Effect: corev1.TaintEffectNoSchedule,
321-
},
322-
},
323-
},
324-
},
325-
},
326-
}
327-
}

tests/e2e/utils.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,32 @@
1818
package e2e
1919

2020
import (
21+
"bytes"
2122
"context"
2223
"fmt"
2324
"math/rand"
25+
"os"
26+
"path/filepath"
2427
"regexp"
28+
"runtime"
2529
"strconv"
2630
"strings"
2731
"time"
2832

2933
. "github.com/onsi/gomega"
3034
gomegatypes "github.com/onsi/gomega/types"
3135

36+
batchv1 "k8s.io/api/batch/v1"
3237
corev1 "k8s.io/api/core/v1"
38+
apierrors "k8s.io/apimachinery/pkg/api/errors"
3339
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
40+
apiruntime "k8s.io/apimachinery/pkg/runtime"
3441
clientset "k8s.io/client-go/kubernetes"
42+
k8sscheme "k8s.io/client-go/kubernetes/scheme"
3543
)
3644

45+
var packagePath string
46+
3747
type k8sLabels map[string]string
3848

3949
// eventuallyNonControlPlaneNodes is a helper for asserting node properties
@@ -254,3 +264,80 @@ func getNode(nodes []corev1.Node, nodeName string) corev1.Node {
254264
}
255265
return corev1.Node{}
256266
}
267+
268+
// CreateOrUpdateJobsFromFile creates or updates jobs from a file
269+
func CreateOrUpdateJobsFromFile(ctx context.Context, cli clientset.Interface, filename, namespace string) ([]string, error) {
270+
jobs, err := newJobFromfile(filepath.Join(packagePath, "data", filename))
271+
if err != nil {
272+
return nil, fmt.Errorf("failed to create Job from file: %w", err)
273+
}
274+
275+
names := make([]string, len(jobs))
276+
for i, job := range jobs {
277+
job.Namespace = namespace
278+
279+
names[i] = job.Name
280+
281+
// create or update the job
282+
_, err := cli.BatchV1().Jobs(namespace).Get(ctx, job.Name, metav1.GetOptions{})
283+
if err != nil {
284+
if apierrors.IsNotFound(err) {
285+
_, err = cli.BatchV1().Jobs(namespace).Create(ctx, job, metav1.CreateOptions{})
286+
if err != nil {
287+
return nil, fmt.Errorf("failed to create Job %s: %w", job.Name, err)
288+
}
289+
} else {
290+
return nil, fmt.Errorf("failed to get Job %s: %w", job.Name, err)
291+
}
292+
}
293+
}
294+
295+
return names, nil
296+
}
297+
298+
func newJobFromfile(path string) ([]*batchv1.Job, error) {
299+
objs, err := apiObjsFromFile(path, k8sscheme.Codecs.UniversalDeserializer())
300+
if err != nil {
301+
return nil, err
302+
}
303+
304+
jobs := make([]*batchv1.Job, len(objs))
305+
306+
for i, obj := range objs {
307+
var ok bool
308+
jobs[i], ok = obj.(*batchv1.Job)
309+
if !ok {
310+
return nil, fmt.Errorf("unexpected type %t when reading %q", obj, path)
311+
}
312+
}
313+
314+
return jobs, nil
315+
}
316+
func apiObjsFromFile(path string, decoder apiruntime.Decoder) ([]apiruntime.Object, error) {
317+
data, err := os.ReadFile(path)
318+
if err != nil {
319+
return nil, err
320+
}
321+
322+
// TODO: find out a nicer way to decode multiple api objects from a single
323+
// file (K8s must have that somewhere)
324+
split := bytes.Split(data, []byte("---"))
325+
objs := []apiruntime.Object{}
326+
327+
for _, slice := range split {
328+
if len(slice) == 0 {
329+
continue
330+
}
331+
obj, _, err := decoder.Decode(slice, nil, nil)
332+
if err != nil {
333+
return nil, err
334+
}
335+
objs = append(objs, obj)
336+
}
337+
return objs, err
338+
}
339+
340+
func init() {
341+
_, thisFile, _, _ := runtime.Caller(0)
342+
packagePath = filepath.Dir(thisFile)
343+
}

0 commit comments

Comments
 (0)