@@ -19,88 +19,27 @@ 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"
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