DRA: Update controller for Prioritized Alternatives in Device Requests

This commit is contained in:
Morten Torkildsen 2025-02-28 19:32:59 +00:00
parent 2229a78dfe
commit 36d8a44b9c
4 changed files with 60 additions and 29 deletions

View File

@ -408,7 +408,10 @@ func newResourceClaimControllerDescriptor() *ControllerDescriptor {
func startResourceClaimController(ctx context.Context, controllerContext ControllerContext, controllerName string) (controller.Interface, bool, error) {
ephemeralController, err := resourceclaim.NewController(
klog.FromContext(ctx),
utilfeature.DefaultFeatureGate.Enabled(features.DRAAdminAccess),
resourceclaim.Features{
AdminAccess: utilfeature.DefaultFeatureGate.Enabled(features.DRAAdminAccess),
PrioritizedList: utilfeature.DefaultFeatureGate.Enabled(features.DRAPrioritizedList),
},
controllerContext.ClientBuilder.ClientOrDie("resource-claim-controller"),
controllerContext.InformerFactory.Core().V1().Pods(),
controllerContext.InformerFactory.Resource().V1beta1().ResourceClaims(),

View File

@ -71,8 +71,8 @@ const (
// Controller creates ResourceClaims for ResourceClaimTemplates in a pod spec.
type Controller struct {
// adminAccessEnabled matches the DRAAdminAccess feature gate state.
adminAccessEnabled bool
// features defines the feature gates that are enabled.
features Features
// kubeClient is the kube API client used to communicate with the API
// server.
@ -118,25 +118,31 @@ const (
podKeyPrefix = "pod:"
)
// Features defines which features should be enabled in the controller.
type Features struct {
AdminAccess bool
PrioritizedList bool
}
// NewController creates a ResourceClaim controller.
func NewController(
logger klog.Logger,
adminAccessEnabled bool,
features Features,
kubeClient clientset.Interface,
podInformer v1informers.PodInformer,
claimInformer resourceinformers.ResourceClaimInformer,
templateInformer resourceinformers.ResourceClaimTemplateInformer) (*Controller, error) {
ec := &Controller{
adminAccessEnabled: adminAccessEnabled,
kubeClient: kubeClient,
podLister: podInformer.Lister(),
podIndexer: podInformer.Informer().GetIndexer(),
podSynced: podInformer.Informer().HasSynced,
claimLister: claimInformer.Lister(),
claimsSynced: claimInformer.Informer().HasSynced,
templateLister: templateInformer.Lister(),
templatesSynced: templateInformer.Informer().HasSynced,
features: features,
kubeClient: kubeClient,
podLister: podInformer.Lister(),
podIndexer: podInformer.Informer().GetIndexer(),
podSynced: podInformer.Informer().HasSynced,
claimLister: claimInformer.Lister(),
claimsSynced: claimInformer.Informer().HasSynced,
templateLister: templateInformer.Lister(),
templatesSynced: templateInformer.Informer().HasSynced,
queue: workqueue.NewTypedRateLimitingQueueWithConfig(
workqueue.DefaultTypedControllerRateLimiter[string](),
workqueue.TypedRateLimitingQueueConfig[string]{Name: "resource_claim"},
@ -617,10 +623,14 @@ func (ec *Controller) handleClaim(ctx context.Context, pod *v1.Pod, podClaim v1.
return fmt.Errorf("resource claim template %q: %v", *templateName, err)
}
if !ec.adminAccessEnabled && needsAdminAccess(template) {
if !ec.features.AdminAccess && needsAdminAccess(template) {
return errors.New("admin access is requested, but the feature is disabled")
}
if !ec.features.PrioritizedList && hasPrioritizedList(template) {
return errors.New("template includes a prioritized list of subrequests, but the feature is disabled")
}
// Create the ResourceClaim with pod as owner, with a generated name that uses
// <pod>-<claim name> as base.
isTrue := true
@ -688,6 +698,15 @@ func needsAdminAccess(claimTemplate *resourceapi.ResourceClaimTemplate) bool {
return false
}
func hasPrioritizedList(claimTemplate *resourceapi.ResourceClaimTemplate) bool {
for _, request := range claimTemplate.Spec.Spec.Devices.Requests {
if len(request.FirstAvailable) > 0 {
return true
}
}
return false
}
// findPodResourceClaim looks for an existing ResourceClaim with the right
// annotation (ties it to the pod claim) and the right ownership (ties it to
// the pod).

View File

@ -82,18 +82,19 @@ var (
func TestSyncHandler(t *testing.T) {
tests := []struct {
name string
key string
adminAccessEnabled bool
claims []*resourceapi.ResourceClaim
claimsInCache []*resourceapi.ResourceClaim
pods []*v1.Pod
podsLater []*v1.Pod
templates []*resourceapi.ResourceClaimTemplate
expectedClaims []resourceapi.ResourceClaim
expectedStatuses map[string][]v1.PodResourceClaimStatus
expectedError bool
expectedMetrics expectedMetrics
name string
key string
adminAccessEnabled bool
prioritizedListEnabled bool
claims []*resourceapi.ResourceClaim
claimsInCache []*resourceapi.ResourceClaim
pods []*v1.Pod
podsLater []*v1.Pod
templates []*resourceapi.ResourceClaimTemplate
expectedClaims []resourceapi.ResourceClaim
expectedStatuses map[string][]v1.PodResourceClaimStatus
expectedError bool
expectedMetrics expectedMetrics
}{
{
name: "create",
@ -390,7 +391,11 @@ func TestSyncHandler(t *testing.T) {
claimInformer := informerFactory.Resource().V1beta1().ResourceClaims()
templateInformer := informerFactory.Resource().V1beta1().ResourceClaimTemplates()
ec, err := NewController(tCtx.Logger(), tc.adminAccessEnabled, fakeKubeClient, podInformer, claimInformer, templateInformer)
features := Features{
AdminAccess: tc.adminAccessEnabled,
PrioritizedList: tc.prioritizedListEnabled,
}
ec, err := NewController(tCtx.Logger(), features, fakeKubeClient, podInformer, claimInformer, templateInformer)
if err != nil {
t.Fatalf("error creating ephemeral controller : %v", err)
}
@ -465,7 +470,7 @@ func TestResourceClaimEventHandler(t *testing.T) {
templateInformer := informerFactory.Resource().V1beta1().ResourceClaimTemplates()
claimClient := fakeKubeClient.ResourceV1beta1().ResourceClaims(testNamespace)
_, err := NewController(tCtx.Logger(), false /* admin access */, fakeKubeClient, podInformer, claimInformer, templateInformer)
_, err := NewController(tCtx.Logger(), Features{}, fakeKubeClient, podInformer, claimInformer, templateInformer)
tCtx.ExpectNoError(err, "creating ephemeral controller")
informerFactory.Start(tCtx.Done())

View File

@ -132,7 +132,11 @@ func CreateResourceClaimController(ctx context.Context, tb ktesting.TB, clientSe
podInformer := informerFactory.Core().V1().Pods()
claimInformer := informerFactory.Resource().V1beta1().ResourceClaims()
claimTemplateInformer := informerFactory.Resource().V1beta1().ResourceClaimTemplates()
claimController, err := resourceclaim.NewController(klog.FromContext(ctx), true /* admin access */, clientSet, podInformer, claimInformer, claimTemplateInformer)
features := resourceclaim.Features{
AdminAccess: true,
PrioritizedList: true,
}
claimController, err := resourceclaim.NewController(klog.FromContext(ctx), features, clientSet, podInformer, claimInformer, claimTemplateInformer)
if err != nil {
tb.Fatalf("Error creating claim controller: %v", err)
}