@@ -38,7 +38,6 @@ import (
3838 appsv1 "k8s.io/api/apps/v1"
3939 v1 "k8s.io/api/core/v1"
4040 resourceapi "k8s.io/api/resource/v1alpha3"
41- apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
4241 apierrors "k8s.io/apimachinery/pkg/api/errors"
4342 "k8s.io/apimachinery/pkg/api/meta"
4443 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -99,6 +98,7 @@ func NewNodes(f *framework.Framework, minNodes, maxNodes int) *Nodes {
9998 for _ , node := range nodeList .Items {
10099 nodes .NodeNames = append (nodes .NodeNames , node .Name )
101100 }
101+ sort .Strings (nodes .NodeNames )
102102 framework .Logf ("testing on nodes %v" , nodes .NodeNames )
103103
104104 // Watch claims in the namespace. This is useful for monitoring a test
@@ -153,7 +153,7 @@ func validateClaim(claim *resourceapi.ResourceClaim) {
153153// NewDriver sets up controller (as client of the cluster) and
154154// kubelet plugin (via proxy) before the test runs. It cleans
155155// up after the test.
156- func NewDriver (f * framework.Framework , nodes * Nodes , configureResources func () app.Resources ) * Driver {
156+ func NewDriver (f * framework.Framework , nodes * Nodes , configureResources func () app.Resources , devicesPerNode ... map [ string ] map [resourceapi. QualifiedName ]resourceapi. DeviceAttribute ) * Driver {
157157 d := & Driver {
158158 f : f ,
159159 fail : map [MethodInstance ]bool {},
@@ -169,7 +169,7 @@ func NewDriver(f *framework.Framework, nodes *Nodes, configureResources func() a
169169 resources .Nodes = nodes .NodeNames
170170 }
171171 ginkgo .DeferCleanup (d .IsGone ) // Register first so it gets called last.
172- d .SetUp (nodes , resources )
172+ d .SetUp (nodes , resources , devicesPerNode ... )
173173 ginkgo .DeferCleanup (d .TearDown )
174174 })
175175 return d
@@ -195,13 +195,8 @@ type Driver struct {
195195 // In addition, there is one entry for a fictional node.
196196 Nodes map [string ]KubeletPlugin
197197
198- parameterMode parameterMode
199- parameterAPIGroup string
200- parameterAPIVersion string
201- claimParameterAPIKind string
202- classParameterAPIKind string
203-
204- NodeV1alpha3 bool
198+ parameterMode parameterMode // empty == parameterModeStructured
199+ NodeV1alpha3 bool
205200
206201 mutex sync.Mutex
207202 fail map [MethodInstance ]bool
@@ -216,12 +211,11 @@ type KubeletPlugin struct {
216211type parameterMode string
217212
218213const (
219- parameterModeConfigMap parameterMode = "configmap" // ConfigMap parameters, control plane controller.
220- parameterModeStructured parameterMode = "structured" // No ConfigMaps, directly create and reference in-tree parameter objects.
221- parameterModeTranslated parameterMode = "translated" // Reference ConfigMaps in claim and class, generate in-tree parameter objects.
214+ parameterModeClassicDRA parameterMode = "classic" // control plane controller
215+ parameterModeStructured parameterMode = "structured" // allocation through scheduler
222216)
223217
224- func (d * Driver ) SetUp (nodes * Nodes , resources app.Resources ) {
218+ func (d * Driver ) SetUp (nodes * Nodes , resources app.Resources , devicesPerNode ... map [ string ] map [resourceapi. QualifiedName ]resourceapi. DeviceAttribute ) {
225219 ginkgo .By (fmt .Sprintf ("deploying driver on nodes %v" , nodes .NodeNames ))
226220 d .Nodes = make (map [string ]KubeletPlugin )
227221 d .Name = d .f .UniqueName + d .NameSuffix + ".k8s.io"
@@ -236,40 +230,75 @@ func (d *Driver) SetUp(nodes *Nodes, resources app.Resources) {
236230 d .ctx = ctx
237231 d .cleanup = append (d .cleanup , cancel )
238232
233+ if d .parameterMode == "" {
234+ d .parameterMode = parameterModeStructured
235+ }
236+
239237 switch d .parameterMode {
240- case "" , parameterModeConfigMap :
238+ case parameterModeClassicDRA :
241239 // The controller is easy: we simply connect to the API server.
242240 d .Controller = app .NewController (d .f .ClientSet , resources )
243241 d .wg .Add (1 )
244242 go func () {
245243 defer d .wg .Done ()
246244 d .Controller .Run (d .ctx , 5 /* workers */ )
247245 }()
246+ case parameterModeStructured :
247+ if ! resources .NodeLocal {
248+ // Publish one resource pool with "network-attached" devices.
249+ slice := & resourceapi.ResourceSlice {
250+ ObjectMeta : metav1.ObjectMeta {
251+ Name : d .Name , // globally unique
252+ },
253+ Spec : resourceapi.ResourceSliceSpec {
254+ Driver : d .Name ,
255+ Pool : resourceapi.ResourcePool {
256+ Name : "network" ,
257+ Generation : 1 ,
258+ ResourceSliceCount : 1 ,
259+ },
260+ NodeSelector : & v1.NodeSelector {
261+ NodeSelectorTerms : []v1.NodeSelectorTerm {{
262+ MatchFields : []v1.NodeSelectorRequirement {{
263+ Key : "metadata.name" ,
264+ Operator : v1 .NodeSelectorOpIn ,
265+ Values : nodes .NodeNames ,
266+ }},
267+ }},
268+ },
269+ },
270+ }
271+ maxAllocations := resources .MaxAllocations
272+ if maxAllocations <= 0 {
273+ // Cannot be empty, otherwise nothing runs.
274+ maxAllocations = 10
275+ }
276+ for i := 0 ; i < maxAllocations ; i ++ {
277+ slice .Spec .Devices = append (slice .Spec .Devices , resourceapi.Device {
278+ Name : fmt .Sprintf ("device-%d" , i ),
279+ Basic : & resourceapi.BasicDevice {},
280+ })
281+ }
282+
283+ _ , err := d .f .ClientSet .ResourceV1alpha3 ().ResourceSlices ().Create (ctx , slice , metav1.CreateOptions {})
284+ framework .ExpectNoError (err )
285+ ginkgo .DeferCleanup (func (ctx context.Context ) {
286+ framework .ExpectNoError (d .f .ClientSet .ResourceV1alpha3 ().ResourceSlices ().Delete (ctx , slice .Name , metav1.DeleteOptions {}))
287+ })
288+ }
248289 }
249290
250291 manifests := []string {
251292 // The code below matches the content of this manifest (ports,
252293 // container names, etc.).
253294 "test/e2e/testing-manifests/dra/dra-test-driver-proxy.yaml" ,
254295 }
255- if d .parameterMode == "" {
256- d .parameterMode = parameterModeConfigMap
257- }
258- var numResourceInstances = - 1 // disabled
259- if d .parameterMode != parameterModeConfigMap {
260- numResourceInstances = resources .MaxAllocations
296+ var numDevices = - 1 // disabled
297+ if d .parameterMode != parameterModeClassicDRA && resources .NodeLocal {
298+ numDevices = resources .MaxAllocations
261299 }
262300 switch d .parameterMode {
263- case parameterModeConfigMap , parameterModeTranslated :
264- d .parameterAPIGroup = ""
265- d .parameterAPIVersion = "v1"
266- d .claimParameterAPIKind = "ConfigMap"
267- d .classParameterAPIKind = "ConfigMap"
268- case parameterModeStructured :
269- d .parameterAPIGroup = "resource.k8s.io"
270- d .parameterAPIVersion = "v1alpha3"
271- d .claimParameterAPIKind = "ResourceClaimParameters"
272- d .classParameterAPIKind = "ResourceClassParameters"
301+ case parameterModeClassicDRA , parameterModeStructured :
273302 default :
274303 framework .Failf ("unknown test driver parameter mode: %s" , d .parameterMode )
275304 }
@@ -314,10 +343,6 @@ func (d *Driver) SetUp(nodes *Nodes, resources app.Resources) {
314343 item .Spec .Template .Spec .Volumes [2 ].HostPath .Path = path .Join (framework .TestContext .KubeletRootDir , "plugins_registry" )
315344 item .Spec .Template .Spec .Containers [0 ].Args = append (item .Spec .Template .Spec .Containers [0 ].Args , "--endpoint=/plugins_registry/" + d .Name + "-reg.sock" )
316345 item .Spec .Template .Spec .Containers [1 ].Args = append (item .Spec .Template .Spec .Containers [1 ].Args , "--endpoint=/dra/" + d .Name + ".sock" )
317- case * apiextensionsv1.CustomResourceDefinition :
318- item .Name = strings .ReplaceAll (item .Name , "dra.e2e.example.com" , d .parameterAPIGroup )
319- item .Spec .Group = d .parameterAPIGroup
320-
321346 }
322347 return nil
323348 }, manifests ... )
@@ -336,9 +361,12 @@ func (d *Driver) SetUp(nodes *Nodes, resources app.Resources) {
336361 pods , err := d .f .ClientSet .CoreV1 ().Pods (d .f .Namespace .Name ).List (ctx , metav1.ListOptions {LabelSelector : selector .String ()})
337362 framework .ExpectNoError (err , "list proxy pods" )
338363 gomega .Expect (numNodes ).To (gomega .Equal (int32 (len (pods .Items ))), "number of proxy pods" )
364+ sort .Slice (pods .Items , func (i , j int ) bool {
365+ return pods .Items [i ].Spec .NodeName < pods .Items [j ].Spec .NodeName
366+ })
339367
340368 // Run registrar and plugin for each of the pods.
341- for _ , pod := range pods .Items {
369+ for i , pod := range pods .Items {
342370 // Need a local variable, not the loop variable, for the anonymous
343371 // callback functions below.
344372 pod := pod
@@ -361,18 +389,23 @@ func (d *Driver) SetUp(nodes *Nodes, resources app.Resources) {
361389
362390 logger := klog .LoggerWithValues (klog .LoggerWithName (klog .Background (), "kubelet plugin" ), "node" , pod .Spec .NodeName , "pod" , klog .KObj (& pod ))
363391 loggerCtx := klog .NewContext (ctx , logger )
364- plugin , err := app .StartPlugin (loggerCtx , "/cdi" , d .Name , driverClient , nodename ,
365- app.FileOperations {
366- Create : func (name string , content []byte ) error {
367- klog .Background ().Info ("creating CDI file" , "node" , nodename , "filename" , name , "content" , string (content ))
368- return d .createFile (& pod , name , content )
369- },
370- Remove : func (name string ) error {
371- klog .Background ().Info ("deleting CDI file" , "node" , nodename , "filename" , name )
372- return d .removeFile (& pod , name )
373- },
374- NumResourceInstances : numResourceInstances ,
392+ fileOps := app.FileOperations {
393+ Create : func (name string , content []byte ) error {
394+ klog .Background ().Info ("creating CDI file" , "node" , nodename , "filename" , name , "content" , string (content ))
395+ return d .createFile (& pod , name , content )
375396 },
397+ Remove : func (name string ) error {
398+ klog .Background ().Info ("deleting CDI file" , "node" , nodename , "filename" , name )
399+ return d .removeFile (& pod , name )
400+ },
401+ }
402+ if i < len (devicesPerNode ) {
403+ fileOps .Devices = devicesPerNode [i ]
404+ fileOps .NumDevices = - 1
405+ } else {
406+ fileOps .NumDevices = numDevices
407+ }
408+ plugin , err := app .StartPlugin (loggerCtx , "/cdi" , d .Name , driverClient , nodename , fileOps ,
376409 kubeletplugin .GRPCVerbosity (0 ),
377410 kubeletplugin .GRPCInterceptor (func (ctx context.Context , req interface {}, info * grpc.UnaryServerInfo , handler grpc.UnaryHandler ) (resp interface {}, err error ) {
378411 return d .interceptor (nodename , ctx , req , info , handler )
@@ -527,7 +560,7 @@ func (d *Driver) TearDown() {
527560
528561func (d * Driver ) IsGone (ctx context.Context ) {
529562 gomega .Eventually (ctx , func (ctx context.Context ) ([]resourceapi.ResourceSlice , error ) {
530- slices , err := d .f .ClientSet .ResourceV1alpha3 ().ResourceSlices ().List (ctx , metav1.ListOptions {FieldSelector : "driverName =" + d .Name })
563+ slices , err := d .f .ClientSet .ResourceV1alpha3 ().ResourceSlices ().List (ctx , metav1.ListOptions {FieldSelector : resourceapi . ResourceSliceSelectorDriver + " =" + d .Name })
531564 if err != nil {
532565 return nil , err
533566 }
0 commit comments