Skip to content

Commit 0b62bfb

Browse files
committed
DRA e2e: adapt to v1alpha3 API
1 parent 877829a commit 0b62bfb

File tree

10 files changed

+1054
-868
lines changed

10 files changed

+1054
-868
lines changed

test/e2e/dra/deploy.go

Lines changed: 81 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -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 {
216211
type parameterMode string
217212

218213
const (
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

528561
func (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

Comments
 (0)