Skip to content

Commit 5405d11

Browse files
Create test objects from file
Signed-off-by: Carlos Eduardo Arango Gutierrez <[email protected]>
1 parent e10c693 commit 5405d11

File tree

6 files changed

+205
-103
lines changed

6 files changed

+205
-103
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
apiVersion: resource.nvidia.com/v1beta1
2+
kind: ComputeDomain
3+
metadata:
4+
name: cd-e2e-1
5+
spec:
6+
numNodes: 1
7+
channel:
8+
resourceClaimTemplate:
9+
name: cd-e2e-1

tests/e2e/data/pod-1.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
apiVersion: v1
2+
kind: Pod
3+
metadata:
4+
name: pod-e2e-1
5+
labels:
6+
app.nvidia.com: k8s-dra-driver-gpu-test-app
7+
spec:
8+
containers:
9+
- name: ctr
10+
image: ubuntu:22.04
11+
command: ["bash", "-c"]
12+
args: ["nvidia-smi -L; trap 'exit 0' TERM; sleep 9999 & wait"]
13+
resources:
14+
claims:
15+
- name: cd-e2e-1
16+
- name: rct-e2e-1
17+
resourceClaims:
18+
- name: cd-e2e-1
19+
resourceClaimTemplateName: cd-e2e-1
20+
- name: rct-e2e-1
21+
resourceClaimTemplateName: rct-e2e-1
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
apiVersion: resource.k8s.io/v1beta1
2+
kind: ResourceClaimTemplate
3+
metadata:
4+
name: rct-e2e-1
5+
spec:
6+
spec:
7+
devices:
8+
requests:
9+
- name: gpu
10+
deviceClassName: gpu.nvidia.com

tests/e2e/e2e_test.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import (
2424
"log"
2525
"os"
2626
"path/filepath"
27-
"runtime"
2827
"strconv"
2928
"testing"
3029
"time"
@@ -93,7 +92,6 @@ var (
9392
diagnosticsCollector *diagnostics.Diagnostic
9493
CollectLogsFrom string
9594
LogArtifactDir string
96-
packagePath string
9795
)
9896

9997
func TestMain(t *testing.T) {
@@ -203,9 +201,6 @@ func getTestEnv() {
203201
defer GinkgoRecover()
204202
var err error
205203

206-
_, thisFile, _, _ := runtime.Caller(0)
207-
packagePath = filepath.Dir(thisFile)
208-
209204
Kubeconfig = os.Getenv("KUBECONFIG")
210205
Expect(Kubeconfig).NotTo(BeEmpty(), "KUBECONFIG must be set")
211206

tests/e2e/k8s-dra-gpu-driver_test.go

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -124,21 +124,17 @@ var _ = Describe("K8S DRA GPU Driver", Ordered, func() {
124124
When("running a pod that consumes a computeDomain", func() {
125125
It("should be successful", func(ctx context.Context) {
126126
By("Creating the resource claim template")
127-
rct := newGpuResourceClaimTemplate("test-resourceclaim1", testNamespace.Name)
128-
_, err := clientSet.ResourceV1beta1().ResourceClaimTemplates(testNamespace.Name).
129-
Create(ctx, rct, metav1.CreateOptions{})
127+
rct, err := CreateOrUpdateResourceClaimTemplatesFromFile(ctx, clientSet, "resourceclaimtemplate-1.yaml", testNamespace.Name)
130128
Expect(err).NotTo(HaveOccurred())
131129

132130
By("Creating the computeDomain")
133-
cd := newComputeDomain("test-computedomain1", testNamespace.Name)
134-
_, err = resourceClient.ResourceV1beta1().ComputeDomains(testNamespace.Name).
135-
Create(ctx, cd, metav1.CreateOptions{})
131+
cd, err := CreateOrUpdateComputeDomainsFromFile(ctx, resourceClient, "computedomain-1.yaml", testNamespace.Name)
136132
Expect(err).NotTo(HaveOccurred())
137133

138134
By("Verifying that expected resource claim templates exist")
139135
expectedTemplates := []string{
140-
rct.Name,
141-
cd.Spec.Channel.ResourceClaimTemplate.Name,
136+
rct[0],
137+
cd[0],
142138
}
143139
for _, tmplName := range expectedTemplates {
144140
Eventually(func() error {
@@ -161,26 +157,12 @@ var _ = Describe("K8S DRA GPU Driver", Ordered, func() {
161157
}, 5*time.Minute, 10*time.Second).Should(BeTrue())
162158

163159
By("Creating the test pod")
164-
pod := createPod(testNamespace.Name, "test-pod1")
165-
pod.Spec.Containers[0].Command = []string{"bash", "-c"}
166-
pod.Spec.Containers[0].Args = []string{"nvidia-smi -L; trap 'exit 0' TERM; sleep 9999 & wait"}
167-
pod.Spec.Containers[0].Resources.Claims = []v1Core.ResourceClaim{
168-
{Name: "gpu"},
169-
{Name: "test-channel-0"},
170-
}
171-
pod.Spec.ResourceClaims = []v1Core.PodResourceClaim{
172-
{Name: "gpu", ResourceClaimTemplateName: &rct.Name},
173-
{Name: "test-channel-0", ResourceClaimTemplateName: &cd.Spec.Channel.ResourceClaimTemplate.Name},
174-
}
175-
pod.Spec.Tolerations = []v1Core.Toleration{
176-
{Key: "nvidia.com/gpu", Operator: v1Core.TolerationOpExists, Effect: v1Core.TaintEffectNoSchedule},
177-
}
178-
_, err = clientSet.CoreV1().Pods(testNamespace.Name).Create(ctx, pod, metav1.CreateOptions{})
160+
pod, err := CreateOrUpdatePodsFromFile(ctx, clientSet, "pod-1.yaml", testNamespace.Name)
179161
Expect(err).NotTo(HaveOccurred())
180162

181163
By("Waiting for the test pod to be running")
182164
Eventually(func() (v1Core.PodPhase, error) {
183-
p, err := clientSet.CoreV1().Pods(testNamespace.Name).Get(ctx, pod.Name, metav1.GetOptions{})
165+
p, err := clientSet.CoreV1().Pods(testNamespace.Name).Get(ctx, pod[0], metav1.GetOptions{})
184166
if err != nil {
185167
return "", err
186168
}
@@ -189,14 +171,14 @@ var _ = Describe("K8S DRA GPU Driver", Ordered, func() {
189171

190172
By("Checking the test pod logs")
191173
Eventually(func() bool {
192-
podLogs, err := clientSet.CoreV1().Pods(testNamespace.Name).GetLogs(pod.Name, &v1Core.PodLogOptions{}).DoRaw(ctx)
174+
podLogs, err := clientSet.CoreV1().Pods(testNamespace.Name).GetLogs(pod[0], &v1Core.PodLogOptions{}).DoRaw(ctx)
193175
Expect(err).NotTo(HaveOccurred())
194176
logs := string(podLogs)
195177
return validatePodLogs(logs)
196178
}, 5*time.Minute, 10*time.Second).Should(BeTrue())
197179

198180
By("Deleting the test1 resources")
199-
err = cleanupTestResources(testNamespace.Name, pod.Name, cd.Name, rct.Name)
181+
err = cleanupTestResources(testNamespace.Name, pod[0], cd[0], rct[0])
200182
Expect(err).NotTo(HaveOccurred())
201183
})
202184
})

tests/e2e/utils.go

Lines changed: 157 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -19,88 +19,27 @@ package e2e
1919

2020
import (
2121
"bufio"
22+
"bytes"
23+
"context"
24+
"fmt"
25+
"os"
26+
"path/filepath"
2227
"regexp"
28+
"runtime"
2329
"strings"
2430

2531
"github.com/NVIDIA/k8s-dra-driver-gpu/api/nvidia.com/resource/v1beta1"
32+
computeDomainV1beta1 "github.com/NVIDIA/k8s-dra-driver-gpu/pkg/nvidia.com/clientset/versioned"
33+
"github.com/NVIDIA/k8s-dra-driver-gpu/pkg/nvidia.com/clientset/versioned/scheme"
2634

2735
v1Core "k8s.io/api/core/v1"
2836
k8sV1beta1 "k8s.io/api/resource/v1beta1"
2937
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
38+
apiruntime "k8s.io/apimachinery/pkg/runtime"
39+
clientset "k8s.io/client-go/kubernetes"
3040
)
3141

32-
// newGpuResourceClaimTemplate returns a new ResourceClaimTemplate prepopulated
33-
func newGpuResourceClaimTemplate(name, namespace string) *k8sV1beta1.ResourceClaimTemplate {
34-
return &k8sV1beta1.ResourceClaimTemplate{
35-
TypeMeta: metav1.TypeMeta{
36-
APIVersion: "resource.k8s.io/v1beta1",
37-
Kind: "ResourceClaimTemplate",
38-
},
39-
ObjectMeta: metav1.ObjectMeta{
40-
Name: name,
41-
Namespace: namespace,
42-
},
43-
Spec: k8sV1beta1.ResourceClaimTemplateSpec{
44-
Spec: k8sV1beta1.ResourceClaimSpec{
45-
Devices: k8sV1beta1.DeviceClaim{
46-
Requests: []k8sV1beta1.DeviceRequest{
47-
{
48-
Name: "gpu",
49-
DeviceClassName: "gpu.nvidia.com",
50-
},
51-
},
52-
},
53-
},
54-
},
55-
}
56-
}
57-
58-
// newComputeDomain returns a new ComputeDomain prepopulated
59-
func newComputeDomain(name, namespace string) *v1beta1.ComputeDomain {
60-
return &v1beta1.ComputeDomain{
61-
TypeMeta: metav1.TypeMeta{
62-
APIVersion: "resource.k8s.io/v1beta1",
63-
Kind: "ComputeDomain",
64-
},
65-
ObjectMeta: metav1.ObjectMeta{
66-
Name: name,
67-
Namespace: namespace,
68-
},
69-
Spec: v1beta1.ComputeDomainSpec{
70-
NumNodes: 1,
71-
Channel: &v1beta1.ComputeDomainChannelSpec{
72-
ResourceClaimTemplate: v1beta1.ComputeDomainResourceClaimTemplate{
73-
Name: "test-channel-0",
74-
},
75-
},
76-
},
77-
}
78-
}
79-
80-
// createPod creates a new Pod with the specified name and namespace
81-
func createPod(namespace, podName string) *v1Core.Pod {
82-
// Define a minimal Pod spec.
83-
return &v1Core.Pod{
84-
ObjectMeta: metav1.ObjectMeta{
85-
Name: podName,
86-
Namespace: namespace,
87-
Labels: map[string]string{
88-
"app.nvidia.com": "k8s-dra-driver-gpu-test-app",
89-
},
90-
},
91-
Spec: v1Core.PodSpec{
92-
Containers: []v1Core.Container{
93-
{
94-
Name: "dra-test-container",
95-
Image: "ubuntu:22.04",
96-
Ports: []v1Core.ContainerPort{
97-
{ContainerPort: 80},
98-
},
99-
},
100-
},
101-
},
102-
}
103-
}
42+
var packagePath string
10443

10544
// validatePodLogs checks if each non-empty line in the provided logs
10645
// matches the expected GPU log format:
@@ -128,3 +67,149 @@ func validatePodLogs(logs string) bool {
12867
}
12968
return true
13069
}
70+
71+
func CreateOrUpdateComputeDomainsFromFile(ctx context.Context, cli computeDomainV1beta1.Interface, filename, namespace string) ([]string, error) {
72+
computeDomains, err := newComputeDomainFromFile(filepath.Join(packagePath, "..", "data", filename))
73+
if err != nil {
74+
return nil, fmt.Errorf("failed to create ComputeDomain from file: %w", err)
75+
}
76+
77+
names := make([]string, len(computeDomains))
78+
for i, computeDomain := range computeDomains {
79+
computeDomain.Namespace = namespace
80+
81+
names[i] = computeDomain.Name
82+
83+
_, err := cli.ResourceV1beta1().ComputeDomains(namespace).Create(ctx, computeDomain, metav1.CreateOptions{})
84+
if err != nil {
85+
return nil, fmt.Errorf("failed to create ComputeDomain: %w", err)
86+
}
87+
}
88+
return names, nil
89+
}
90+
91+
func CreateOrUpdateResourceClaimTemplatesFromFile(ctx context.Context, cli clientset.Interface, filename, namespace string) ([]string, error) {
92+
rcts, err := newResourceClaimTemplateFromFile(filepath.Join(packagePath, "..", "data", filename))
93+
if err != nil {
94+
return nil, fmt.Errorf("failed to create ResourceClaimTemplate from file: %w", err)
95+
}
96+
97+
names := make([]string, len(rcts))
98+
for i, rct := range rcts {
99+
rct.Namespace = namespace
100+
101+
names[i] = rct.Name
102+
103+
_, err := cli.ResourceV1beta1().ResourceClaimTemplates(namespace).Create(ctx, rct, metav1.CreateOptions{})
104+
if err != nil {
105+
return nil, fmt.Errorf("failed to create ResourceClaimTemplate: %w", err)
106+
}
107+
}
108+
return names, nil
109+
}
110+
111+
func CreateOrUpdatePodsFromFile(ctx context.Context, cli clientset.Interface, filename, namespace string) ([]string, error) {
112+
pods, err := newPodFromfile(filepath.Join(packagePath, "..", "data", filename))
113+
if err != nil {
114+
return nil, fmt.Errorf("failed to create Pod from file: %w", err)
115+
}
116+
117+
names := make([]string, len(pods))
118+
for i, pod := range pods {
119+
pod.Namespace = namespace
120+
121+
names[i] = pod.Name
122+
123+
_, err := cli.CoreV1().Pods(namespace).Create(ctx, pod, metav1.CreateOptions{})
124+
if err != nil {
125+
return nil, fmt.Errorf("failed to create Pod: %w", err)
126+
}
127+
}
128+
return names, nil
129+
}
130+
131+
func newComputeDomainFromFile(path string) ([]*v1beta1.ComputeDomain, error) {
132+
objs, err := apiObjsFromFile(path, scheme.Codecs.UniversalDeserializer())
133+
if err != nil {
134+
return nil, err
135+
}
136+
137+
crs := make([]*v1beta1.ComputeDomain, len(objs))
138+
139+
for i, obj := range objs {
140+
var ok bool
141+
crs[i], ok = obj.(*v1beta1.ComputeDomain)
142+
if !ok {
143+
return nil, fmt.Errorf("unexpected type %t when reading %q", obj, path)
144+
}
145+
}
146+
147+
return crs, nil
148+
}
149+
150+
func newPodFromfile(path string) ([]*v1Core.Pod, error) {
151+
objs, err := apiObjsFromFile(path, scheme.Codecs.UniversalDeserializer())
152+
if err != nil {
153+
return nil, err
154+
}
155+
156+
pods := make([]*v1Core.Pod, len(objs))
157+
158+
for i, obj := range objs {
159+
var ok bool
160+
pods[i], ok = obj.(*v1Core.Pod)
161+
if !ok {
162+
return nil, fmt.Errorf("unexpected type %t when reading %q", obj, path)
163+
}
164+
}
165+
166+
return pods, nil
167+
}
168+
169+
func newResourceClaimTemplateFromFile(path string) ([]*k8sV1beta1.ResourceClaimTemplate, error) {
170+
objs, err := apiObjsFromFile(path, scheme.Codecs.UniversalDeserializer())
171+
if err != nil {
172+
return nil, err
173+
}
174+
175+
rcts := make([]*k8sV1beta1.ResourceClaimTemplate, len(objs))
176+
177+
for i, obj := range objs {
178+
var ok bool
179+
rcts[i], ok = obj.(*k8sV1beta1.ResourceClaimTemplate)
180+
if !ok {
181+
return nil, fmt.Errorf("unexpected type %t when reading %q", obj, path)
182+
}
183+
}
184+
185+
return rcts, nil
186+
}
187+
188+
func apiObjsFromFile(path string, decoder apiruntime.Decoder) ([]apiruntime.Object, error) {
189+
data, err := os.ReadFile(path)
190+
if err != nil {
191+
return nil, err
192+
}
193+
194+
// TODO: find out a nicer way to decode multiple api objects from a single
195+
// file (K8s must have that somewhere)
196+
split := bytes.Split(data, []byte("---"))
197+
objs := []apiruntime.Object{}
198+
199+
for _, slice := range split {
200+
if len(slice) == 0 {
201+
continue
202+
}
203+
obj, _, err := decoder.Decode(slice, nil, nil)
204+
if err != nil {
205+
return nil, err
206+
}
207+
objs = append(objs, obj)
208+
}
209+
return objs, err
210+
}
211+
212+
func init() {
213+
_, thisFile, _, _ := runtime.Caller(0)
214+
packagePath = filepath.Dir(thisFile)
215+
}

0 commit comments

Comments
 (0)