@@ -4,23 +4,19 @@ import (
44 "context"
55 "fmt"
66 "os"
7- "reflect"
87 "strings"
98
9+ apiequality "k8s.io/apimachinery/pkg/api/equality"
1010 apierrors "k8s.io/apimachinery/pkg/api/errors"
1111 "k8s.io/apimachinery/pkg/api/meta"
1212 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1313 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
1414 "k8s.io/apimachinery/pkg/runtime/schema"
15- "k8s.io/client-go/dynamic"
15+ "k8s.io/utils/ptr"
16+ "sigs.k8s.io/controller-runtime/pkg/client"
17+ infextv1alpha2 "sigs.k8s.io/gateway-api-inference-extension/apix/v1alpha2"
1618)
1719
18- var inferenceObjectiveGVR = schema.GroupVersionResource {
19- Group : "inference.networking.x-k8s.io" ,
20- Version : "v1alpha2" ,
21- Resource : "inferenceobjectives" ,
22- }
23-
2420const defaultInferenceObjectiveName = "e2e-default"
2521
2622// EnsureInferenceObjective creates the default InferenceObjective for GIE flow-control
@@ -29,43 +25,32 @@ const defaultInferenceObjectiveName = "e2e-default"
2925//
3026// Returns applied=true if the object exists or was created. If the InferenceObjective API is not
3127// available on the cluster, returns (false, nil).
32- func EnsureInferenceObjective (ctx context.Context , dc dynamic. Interface , namespace , poolName string ) (applied bool , err error ) {
33- return EnsureInferenceObjectiveNamed (ctx , dc , namespace , defaultInferenceObjectiveName , poolName )
28+ func EnsureInferenceObjective (ctx context.Context , crClient client. Client , namespace , poolName string ) (applied bool , err error ) {
29+ return EnsureInferenceObjectiveNamed (ctx , crClient , namespace , defaultInferenceObjectiveName , poolName )
3430}
3531
3632// EnsureInferenceObjectiveNamed creates or updates a named InferenceObjective when the CRD exists.
37- func EnsureInferenceObjectiveNamed (ctx context.Context , dc dynamic.Interface , namespace , objectiveName , poolName string ) (applied bool , err error ) {
38- ri := dc .Resource (inferenceObjectiveGVR ).Namespace (namespace )
39- poolGroup , gErr := resolveInferencePoolGroup (ctx , dc , namespace , poolName )
33+ func EnsureInferenceObjectiveNamed (ctx context.Context , crClient client.Client , namespace , objectiveName , poolName string ) (applied bool , err error ) {
34+ poolGroup , gErr := resolveInferencePoolGroup (ctx , crClient , namespace , poolName )
4035 if gErr != nil {
4136 return false , gErr
4237 }
43- obj := buildInferenceObjective (namespace , objectiveName , poolName , poolGroup )
38+ desired := buildInferenceObjective (namespace , objectiveName , poolName , poolGroup )
4439
45- if _ , cErr := ri .Create (ctx , obj , metav1. CreateOptions {} ); cErr != nil {
40+ if cErr := crClient .Create (ctx , desired ); cErr != nil {
4641 if apierrors .IsAlreadyExists (cErr ) {
47- current , getErr := ri .Get (ctx , objectiveName , metav1.GetOptions {})
42+ key := client.ObjectKey {Namespace : namespace , Name : objectiveName }
43+ current := & infextv1alpha2.InferenceObjective {}
44+ getErr := crClient .Get (ctx , key , current )
4845 if getErr != nil {
4946 return false , fmt .Errorf ("get existing InferenceObjective %s: %w" , objectiveName , getErr )
5047 }
51-
52- currentSpec , _ , specErr := unstructured .NestedMap (current .Object , "spec" )
53- if specErr != nil {
54- return false , fmt .Errorf ("read existing InferenceObjective spec: %w" , specErr )
55- }
56- desiredSpec , _ , desiredErr := unstructured .NestedMap (obj .Object , "spec" )
57- if desiredErr != nil {
58- return false , fmt .Errorf ("read desired InferenceObjective spec: %w" , desiredErr )
59- }
60- if reflect .DeepEqual (currentSpec , desiredSpec ) {
48+ if inferenceObjectiveSpecEqual (current .Spec , desired .Spec ) {
6149 return true , nil
6250 }
63-
64- if setErr := unstructured .SetNestedMap (current .Object , desiredSpec , "spec" ); setErr != nil {
65- return false , fmt .Errorf ("set desired InferenceObjective spec: %w" , setErr )
66- }
67- if _ , uErr := ri .Update (ctx , current , metav1.UpdateOptions {}); uErr != nil {
68- return false , fmt .Errorf ("update InferenceObjective %s: %w" , objectiveName , uErr )
51+ current .Spec = desired .Spec
52+ if upErr := crClient .Update (ctx , current ); upErr != nil {
53+ return false , fmt .Errorf ("update InferenceObjective %s: %w" , objectiveName , upErr )
6954 }
7055 return true , nil
7156 }
@@ -78,40 +63,60 @@ func EnsureInferenceObjectiveNamed(ctx context.Context, dc dynamic.Interface, na
7863}
7964
8065// DeleteInferenceObjective removes the default InferenceObjective if present.
81- func DeleteInferenceObjective (ctx context.Context , dc dynamic. Interface , namespace string ) error {
82- return DeleteInferenceObjectiveNamed (ctx , dc , namespace , defaultInferenceObjectiveName )
66+ func DeleteInferenceObjective (ctx context.Context , crClient client. Client , namespace string ) error {
67+ return DeleteInferenceObjectiveNamed (ctx , crClient , namespace , defaultInferenceObjectiveName )
8368}
8469
8570// DeleteInferenceObjectiveNamed removes a named InferenceObjective if present.
86- func DeleteInferenceObjectiveNamed (ctx context.Context , dc dynamic.Interface , namespace , objectiveName string ) error {
87- err := dc .Resource (inferenceObjectiveGVR ).Namespace (namespace ).Delete (ctx , objectiveName , metav1.DeleteOptions {})
71+ func DeleteInferenceObjectiveNamed (ctx context.Context , crClient client.Client , namespace , objectiveName string ) error {
72+ err := crClient .Delete (ctx , & infextv1alpha2.InferenceObjective {
73+ ObjectMeta : metav1.ObjectMeta {
74+ Name : objectiveName ,
75+ Namespace : namespace ,
76+ },
77+ })
8878 if apierrors .IsNotFound (err ) || inferenceObjectiveAPIMissing (err ) {
8979 return nil
9080 }
9181 return err
9282}
9383
94- func buildInferenceObjective (namespace , objectiveName , poolName , poolGroup string ) * unstructured. Unstructured {
95- return & unstructured. Unstructured {
96- Object : map [ string ] interface {} {
97- "apiVersion" : "inference.networking.x-k8s.io/v1alpha2" ,
98- "kind" : "InferenceObjective" ,
99- "metadata" : map [ string ] interface {}{
100- "name" : objectiveName ,
101- "namespace" : namespace ,
102- } ,
103- "spec" : map [ string ] interface {}{
104- "priority" : int64 ( 0 ),
105- "poolRef" : map [ string ] interface {}{
106- "name" : poolName ,
107- "kind" : "InferencePool" ,
108- "group" : poolGroup ,
109- } ,
84+ func buildInferenceObjective (namespace , objectiveName , poolName , poolGroup string ) * infextv1alpha2. InferenceObjective {
85+ return & infextv1alpha2. InferenceObjective {
86+ TypeMeta : metav1. TypeMeta {
87+ APIVersion : infextv1alpha2 . SchemeGroupVersion . String () ,
88+ Kind : "InferenceObjective" ,
89+ },
90+ ObjectMeta : metav1. ObjectMeta {
91+ Name : objectiveName ,
92+ Namespace : namespace ,
93+ },
94+ Spec : infextv1alpha2. InferenceObjectiveSpec {
95+ Priority : ptr . To ( 0 ),
96+ PoolRef : infextv1alpha2. PoolObjectReference {
97+ Group : infextv1alpha2 . Group ( poolGroup ) ,
98+ Kind : infextv1alpha2 . Kind ( "InferencePool" ) ,
99+ Name : infextv1alpha2 . ObjectName ( poolName ) ,
110100 },
111101 },
112102 }
113103}
114104
105+ // inferenceObjectiveSpecEqual compares spec semantically (priority unset vs 0 matches).
106+ func inferenceObjectiveSpecEqual (a , b infextv1alpha2.InferenceObjectiveSpec ) bool {
107+ return apiequality .Semantic .DeepEqual (
108+ normalizeInferenceObjectiveSpec (a ),
109+ normalizeInferenceObjectiveSpec (b ),
110+ )
111+ }
112+
113+ func normalizeInferenceObjectiveSpec (spec infextv1alpha2.InferenceObjectiveSpec ) infextv1alpha2.InferenceObjectiveSpec {
114+ if spec .Priority == nil {
115+ spec .Priority = ptr .To (0 )
116+ }
117+ return spec
118+ }
119+
115120func inferenceObjectiveAPIMissing (err error ) bool {
116121 if err == nil {
117122 return false
@@ -133,10 +138,10 @@ func inferenceObjectiveAPIMissing(err error) bool {
133138 if details == nil {
134139 return false
135140 }
136- return details .Group == inferenceObjectiveGVR . Group && details .Kind == inferenceObjectiveGVR . Resource
141+ return details .Group == infextv1alpha2 . GroupName && details .Kind == "inferenceobjectives"
137142}
138143
139- func resolveInferencePoolGroup (ctx context.Context , dc dynamic. Interface , namespace , poolName string ) (string , error ) {
144+ func resolveInferencePoolGroup (ctx context.Context , crClient client. Client , namespace , poolName string ) (string , error ) {
140145 if envPoolGroup := os .Getenv ("POOL_GROUP" ); envPoolGroup != "" {
141146 return envPoolGroup , nil
142147 }
@@ -147,7 +152,10 @@ func resolveInferencePoolGroup(ctx context.Context, dc dynamic.Interface, namesp
147152 }
148153
149154 for _ , gvr := range inferencePoolCandidates {
150- _ , err := dc .Resource (gvr ).Namespace (namespace ).Get (ctx , poolName , metav1.GetOptions {})
155+ pool := & unstructured.Unstructured {}
156+ pool .SetAPIVersion (gvr .Group + "/" + gvr .Version )
157+ pool .SetKind ("InferencePool" )
158+ err := crClient .Get (ctx , client.ObjectKey {Namespace : namespace , Name : poolName }, pool )
151159 if err == nil {
152160 return gvr .Group , nil
153161 }
0 commit comments