From 1981c985b17853c3db3d19a30ffdfdedc3627c67 Mon Sep 17 00:00:00 2001 From: Ed Bartosh Date: Tue, 15 Jul 2025 15:01:49 +0300 Subject: [PATCH] e2e: DRA: support test and public options Refactor StartPlugin and related test helpers to accept a variadic list of options of any type, allowing both public and test-specific options to be passed. --- test/e2e/dra/test-driver/app/kubeletplugin.go | 30 +++++++++++++++---- test/e2e/dra/test-driver/app/options.go | 24 +++++++++++++++ test/e2e_node/dra_test.go | 12 ++++---- 3 files changed, 54 insertions(+), 12 deletions(-) create mode 100644 test/e2e/dra/test-driver/app/options.go diff --git a/test/e2e/dra/test-driver/app/kubeletplugin.go b/test/e2e/dra/test-driver/app/kubeletplugin.go index ba2ebc1ad94..7f137a14462 100644 --- a/test/e2e/dra/test-driver/app/kubeletplugin.go +++ b/test/e2e/dra/test-driver/app/kubeletplugin.go @@ -128,7 +128,7 @@ type FileOperations struct { } // StartPlugin sets up the servers that are necessary for a DRA kubelet plugin. -func StartPlugin(ctx context.Context, cdiDir, driverName string, kubeClient kubernetes.Interface, nodeName string, fileOps FileOperations, opts ...kubeletplugin.Option) (*ExamplePlugin, error) { +func StartPlugin(ctx context.Context, cdiDir, driverName string, kubeClient kubernetes.Interface, nodeName string, fileOps FileOperations, opts ...any) (*ExamplePlugin, error) { logger := klog.FromContext(ctx) if fileOps.Create == nil { @@ -144,6 +144,27 @@ func StartPlugin(ctx context.Context, cdiDir, driverName string, kubeClient kube return nil } } + + publicOpts := []kubeletplugin.Option{ + kubeletplugin.DriverName(driverName), + kubeletplugin.NodeName(nodeName), + kubeletplugin.KubeClient(kubeClient), + } + + testOpts := &options{} + for _, opt := range opts { + switch typedOpt := opt.(type) { + case TestOption: + if err := typedOpt(testOpts); err != nil { + return nil, fmt.Errorf("apply test option: %w", err) + } + case kubeletplugin.Option: + publicOpts = append(publicOpts, typedOpt) + default: + return nil, fmt.Errorf("unexpected option type %T", opt) + } + } + ex := &ExamplePlugin{ stopCh: ctx.Done(), logger: logger, @@ -155,14 +176,11 @@ func StartPlugin(ctx context.Context, cdiDir, driverName string, kubeClient kube prepared: make(map[ClaimID][]kubeletplugin.Device), } - opts = append(opts, - kubeletplugin.DriverName(driverName), - kubeletplugin.NodeName(nodeName), - kubeletplugin.KubeClient(kubeClient), + publicOpts = append(publicOpts, kubeletplugin.GRPCInterceptor(ex.recordGRPCCall), kubeletplugin.GRPCStreamInterceptor(ex.recordGRPCStream), ) - d, err := kubeletplugin.Start(ctx, ex, opts...) + d, err := kubeletplugin.Start(ctx, ex, publicOpts...) if err != nil { return nil, fmt.Errorf("start kubelet plugin: %w", err) } diff --git a/test/e2e/dra/test-driver/app/options.go b/test/e2e/dra/test-driver/app/options.go new file mode 100644 index 00000000000..cab0613c2be --- /dev/null +++ b/test/e2e/dra/test-driver/app/options.go @@ -0,0 +1,24 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package app + +type options struct { +} + +// TestOption implements the functional options pattern +// dedicated for usage in testing code. +type TestOption func(o *options) error diff --git a/test/e2e_node/dra_test.go b/test/e2e_node/dra_test.go index bf7c28f127d..35eb6d2db3f 100644 --- a/test/e2e_node/dra_test.go +++ b/test/e2e_node/dra_test.go @@ -381,7 +381,7 @@ var _ = framework.SIGDescribe("node")(framework.WithLabel("DRA"), feature.Dynami }).WithTimeout(retryTestTimeout).Should(gomega.Equal(calls)) }) - functionalListenAfterRegistration := func(ctx context.Context, datadir string, opts ...kubeletplugin.Option) { + functionalListenAfterRegistration := func(ctx context.Context, datadir string, opts ...any) { nodeName := getNodeName(ctx, f) ginkgo.By("start DRA registrar") @@ -413,7 +413,7 @@ var _ = framework.SIGDescribe("node")(framework.WithLabel("DRA"), feature.Dynami ), ) - functionalAfterServiceReconnect := func(ctx context.Context, datadir string, opts ...kubeletplugin.Option) { + functionalAfterServiceReconnect := func(ctx context.Context, datadir string, opts ...any) { nodeName := getNodeName(ctx, f) ginkgo.By("start DRA registrar") @@ -674,7 +674,7 @@ var _ = framework.SIGDescribe("node")(framework.WithLabel("DRA"), feature.Dynami gomega.Consistently(ctx, listResources(f.ClientSet)).WithTimeout(5*time.Second).Should(gomega.BeEmpty(), "ResourceSlices with no plugin") }) - removedIfPluginStopsAfterRegistration := func(ctx context.Context, datadir string, opts ...kubeletplugin.Option) { + removedIfPluginStopsAfterRegistration := func(ctx context.Context, datadir string, opts ...any) { nodeName := getNodeName(ctx, f) ginkgo.By("start DRA registrar") @@ -726,7 +726,7 @@ var _ = framework.SIGDescribe("node")(framework.WithLabel("DRA"), feature.Dynami gomega.Consistently(ctx, listResources(f.ClientSet)).WithTimeout(5*time.Second).Should(gomega.BeEmpty(), "ResourceSlices without plugin") }) - testRemoveIfRestartsQuickly := func(ctx context.Context, datadir string, opts ...kubeletplugin.Option) { + testRemoveIfRestartsQuickly := func(ctx context.Context, datadir string, opts ...any) { nodeName := getNodeName(ctx, f) ginkgo.By("start DRA registrar") @@ -824,7 +824,7 @@ func newKubeletPlugin(ctx context.Context, clientSet kubernetes.Interface, nodeN } // newRegistrar starts a registrar for the specified DRA driver, without the DRA gRPC service. -func newRegistrar(ctx context.Context, clientSet kubernetes.Interface, nodeName, driverName string, opts ...kubeletplugin.Option) *testdriver.ExamplePlugin { +func newRegistrar(ctx context.Context, clientSet kubernetes.Interface, nodeName, driverName string, opts ...any) *testdriver.ExamplePlugin { ginkgo.By("start only Kubelet plugin registrar") logger := klog.LoggerWithValues(klog.LoggerWithName(klog.Background(), "kubelet plugin registrar "+driverName)) ctx = klog.NewContext(ctx, logger) @@ -857,7 +857,7 @@ func newRegistrar(ctx context.Context, clientSet kubernetes.Interface, nodeName, // // Returns: // - A pointer to the started ExamplePlugin instance. -func newDRAService(ctx context.Context, clientSet kubernetes.Interface, nodeName, driverName, datadir string, opts ...kubeletplugin.Option) *testdriver.ExamplePlugin { +func newDRAService(ctx context.Context, clientSet kubernetes.Interface, nodeName, driverName, datadir string, opts ...any) *testdriver.ExamplePlugin { ginkgo.By("start only Kubelet plugin") logger := klog.LoggerWithValues(klog.LoggerWithName(klog.Background(), "kubelet plugin "+driverName), "node", nodeName) ctx = klog.NewContext(ctx, logger)