Skip to content

Commit 6c0da9a

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

File tree

7 files changed

+207
-104
lines changed

7 files changed

+207
-104
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: 158 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -19,88 +19,28 @@ 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"
40+
k8sscheme "k8s.io/client-go/kubernetes/scheme"
3041
)
3142

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-
}
43+
var packagePath string
10444

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

0 commit comments

Comments
 (0)