sigs.k8s.io/kueue@v0.6.2/pkg/util/admissioncheck/admissioncheck.go (about)

     1  /*
     2  Copyright 2023 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package admissioncheck
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  
    24  	"k8s.io/apimachinery/pkg/runtime/schema"
    25  	"k8s.io/apimachinery/pkg/types"
    26  	"sigs.k8s.io/controller-runtime/pkg/client"
    27  	"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
    28  
    29  	kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1"
    30  )
    31  
    32  var (
    33  	ErrNilParametersRef = errors.New("missing parameters reference")
    34  	ErrBadParametersRef = errors.New("bad parameters reference")
    35  )
    36  
    37  type objAsPtr[T any] interface {
    38  	client.Object
    39  	*T
    40  }
    41  
    42  type ConfigHelper[PtrT objAsPtr[T], T any] struct {
    43  	gk     schema.GroupKind
    44  	client client.Client
    45  }
    46  
    47  func NewConfigHelper[PtrT objAsPtr[T], T any](c client.Client) (*ConfigHelper[PtrT, T], error) {
    48  	helper := ConfigHelper[PtrT, T]{
    49  		client: c,
    50  	}
    51  
    52  	gvk, err := apiutil.GVKForObject(helper.newConfigPtr(), c.Scheme())
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	helper.gk = gvk.GroupKind()
    58  	return &helper, nil
    59  }
    60  
    61  func (ch *ConfigHelper[PtrT, T]) newConfigPtr() PtrT {
    62  	return PtrT(new(T))
    63  }
    64  
    65  // isValidConfigReference - checks if the provided reference is addressing an object specific to this helper.
    66  func (ch *ConfigHelper[PtrT, T]) isValidConfigReference(ref *kueue.AdmissionCheckParametersReference) (bool, error) {
    67  	return refValidForGK(ref, ch.gk)
    68  }
    69  
    70  // ConfigByName - get the config identified by its name
    71  func (ch *ConfigHelper[PtrT, T]) ConfigByName(ctx context.Context, name string) (PtrT, error) {
    72  	configPtr := ch.newConfigPtr()
    73  	if err := ch.client.Get(ctx, types.NamespacedName{Name: name}, configPtr); err != nil {
    74  		return nil, err
    75  	}
    76  	return configPtr, nil
    77  }
    78  
    79  // ConfigFromRef - get the config identified by ref if valid.
    80  func (ch *ConfigHelper[PtrT, T]) ConfigFromRef(ctx context.Context, ref *kueue.AdmissionCheckParametersReference) (PtrT, error) {
    81  	if isValid, err := ch.isValidConfigReference(ref); !isValid {
    82  		return nil, err
    83  	}
    84  	return ch.ConfigByName(ctx, ref.Name)
    85  }
    86  
    87  // ConfigForAdmissionCheck - get the configuration of the admission check identified by its name if it uses the
    88  // helpers configuration type.
    89  func (ch *ConfigHelper[PtrT, T]) ConfigForAdmissionCheck(ctx context.Context, checkName string) (PtrT, error) {
    90  	ac := &kueue.AdmissionCheck{}
    91  	if err := ch.client.Get(ctx, types.NamespacedName{Name: checkName}, ac); err != nil {
    92  		return nil, err
    93  	}
    94  
    95  	return ch.ConfigFromRef(ctx, ac.Spec.Parameters)
    96  }
    97  
    98  func refValidForGK(ref *kueue.AdmissionCheckParametersReference, gk schema.GroupKind) (bool, error) {
    99  	if ref == nil {
   100  		return false, ErrNilParametersRef
   101  	}
   102  
   103  	if len(ref.Name) == 0 {
   104  		return false, fmt.Errorf("empty name: %w", ErrBadParametersRef)
   105  	}
   106  	if gk.Group != ref.APIGroup {
   107  		return false, fmt.Errorf("wrong group %q, expecting %q: %w", ref.APIGroup, gk.Group, ErrBadParametersRef)
   108  	}
   109  
   110  	if gk.Kind != ref.Kind {
   111  		return false, fmt.Errorf("wrong kind %q, expecting %q: %w", ref.Kind, gk.Kind, ErrBadParametersRef)
   112  	}
   113  	return true, nil
   114  }
   115  
   116  func IndexerByConfigFunction(ControllerName string, gvk schema.GroupVersionKind) client.IndexerFunc {
   117  	gk := gvk.GroupKind()
   118  	return func(obj client.Object) []string {
   119  		ac, isAc := obj.(*kueue.AdmissionCheck)
   120  		if !isAc || ac == nil || ac.Spec.ControllerName != ControllerName {
   121  			return nil
   122  		}
   123  		if isvalid, _ := refValidForGK(ac.Spec.Parameters, gk); !isvalid {
   124  			return nil
   125  		}
   126  		return []string{ac.Spec.Parameters.Name}
   127  	}
   128  }
   129  
   130  // FilterForController - returns a list of check names controlled by ControllerName.
   131  func FilterForController(ctx context.Context, c client.Client, states []kueue.AdmissionCheckState, ControllerName string) ([]string, error) {
   132  	var retActive []string
   133  	for _, state := range states {
   134  		ac := &kueue.AdmissionCheck{}
   135  
   136  		if err := c.Get(ctx, types.NamespacedName{Name: state.Name}, ac); client.IgnoreNotFound(err) != nil {
   137  			return nil, err
   138  		} else if err == nil && ac.Spec.ControllerName == ControllerName {
   139  			retActive = append(retActive, ac.Name)
   140  		}
   141  	}
   142  	return retActive, nil
   143  }