@@ -19,88 +19,28 @@ package e2e
1919
2020import (
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