@@ -22,13 +22,14 @@ import (
2222 autoscalingv2 "k8s.io/api/autoscaling/v2"
2323 corev1 "k8s.io/api/core/v1"
2424 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25- "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil "
25+ "sigs.k8s.io/controller-runtime/pkg/client "
2626 "sigs.k8s.io/controller-runtime/pkg/log"
2727)
2828
2929const (
3030 defaultHPACPUUtilization int32 = 80
3131 defaultHPAMinReplicas int32 = 1
32+ fieldManager = "feast-operator"
3233)
3334
3435// getDesiredReplicas returns the replica count the operator should set on the
@@ -49,73 +50,82 @@ func (feast *FeastServices) getDesiredReplicas() *int32 {
4950}
5051
5152// createOrDeleteHPA reconciles the HorizontalPodAutoscaler for the FeatureStore
52- // deployment. If autoscaling is not configured, any existing HPA is deleted.
53+ // deployment using Server-Side Apply. If autoscaling is not configured, any
54+ // existing HPA is deleted.
5355func (feast * FeastServices ) createOrDeleteHPA () error {
5456 cr := feast .Handler .FeatureStore
55- hpa := feast .initHPA ()
5657
5758 scaling := cr .Status .Applied .Services .Scaling
5859 if scaling == nil || scaling .Autoscaling == nil {
60+ hpa := & autoscalingv2.HorizontalPodAutoscaler {
61+ ObjectMeta : feast .GetObjectMeta (),
62+ }
63+ hpa .SetGroupVersionKind (autoscalingv2 .SchemeGroupVersion .WithKind ("HorizontalPodAutoscaler" ))
5964 return feast .Handler .DeleteOwnedFeastObj (hpa )
6065 }
6166
67+ hpa := feast .buildHPA ()
6268 logger := log .FromContext (feast .Handler .Context )
63- if op , err := controllerutil .CreateOrUpdate (feast .Handler .Context , feast .Handler .Client , hpa , controllerutil .MutateFn (func () error {
64- return feast .setHPA (hpa )
65- })); err != nil {
69+ if err := feast .Handler .Client .Patch (feast .Handler .Context , hpa ,
70+ client .Apply , client .FieldOwner (fieldManager ), client .ForceOwnership ); err != nil {
6671 return err
67- } else if op == controllerutil .OperationResultCreated || op == controllerutil .OperationResultUpdated {
68- logger .Info ("Successfully reconciled" , "HorizontalPodAutoscaler" , hpa .Name , "operation" , op )
6972 }
73+ logger .Info ("Successfully applied" , "HorizontalPodAutoscaler" , hpa .Name )
7074
7175 return nil
7276}
7377
74- func (feast * FeastServices ) initHPA () * autoscalingv2.HorizontalPodAutoscaler {
75- hpa := & autoscalingv2.HorizontalPodAutoscaler {
76- ObjectMeta : feast .GetObjectMeta (),
77- }
78- hpa .SetGroupVersionKind (autoscalingv2 .SchemeGroupVersion .WithKind ("HorizontalPodAutoscaler" ))
79- return hpa
80- }
81-
82- func (feast * FeastServices ) setHPA (hpa * autoscalingv2.HorizontalPodAutoscaler ) error {
78+ // buildHPA constructs the fully desired HPA state for Server-Side Apply.
79+ func (feast * FeastServices ) buildHPA () * autoscalingv2.HorizontalPodAutoscaler {
8380 cr := feast .Handler .FeatureStore
84- scaling := cr .Status .Applied .Services .Scaling
85- if scaling == nil || scaling .Autoscaling == nil {
86- return nil
87- }
88- autoscaling := scaling .Autoscaling
89-
90- hpa .Labels = feast .getLabels ()
81+ autoscaling := cr .Status .Applied .Services .Scaling .Autoscaling
9182
9283 deploy := feast .initFeastDeploy ()
9384 minReplicas := defaultHPAMinReplicas
9485 if autoscaling .MinReplicas != nil {
9586 minReplicas = * autoscaling .MinReplicas
9687 }
9788
98- hpa .Spec = autoscalingv2.HorizontalPodAutoscalerSpec {
99- ScaleTargetRef : autoscalingv2.CrossVersionObjectReference {
100- APIVersion : "apps/v1" ,
101- Kind : "Deployment" ,
102- Name : deploy .Name ,
103- },
104- MinReplicas : & minReplicas ,
105- MaxReplicas : autoscaling .MaxReplicas ,
106- }
107-
89+ metrics := defaultHPAMetrics ()
10890 if len (autoscaling .Metrics ) > 0 {
109- hpa .Spec .Metrics = autoscaling .Metrics
110- } else {
111- hpa .Spec .Metrics = defaultHPAMetrics ()
91+ metrics = autoscaling .Metrics
11292 }
11393
114- if autoscaling .Behavior != nil {
115- hpa .Spec .Behavior = autoscaling .Behavior
94+ isController := true
95+ hpa := & autoscalingv2.HorizontalPodAutoscaler {
96+ TypeMeta : metav1.TypeMeta {
97+ APIVersion : autoscalingv2 .SchemeGroupVersion .String (),
98+ Kind : "HorizontalPodAutoscaler" ,
99+ },
100+ ObjectMeta : metav1.ObjectMeta {
101+ Name : feast .GetObjectMeta ().Name ,
102+ Namespace : feast .GetObjectMeta ().Namespace ,
103+ Labels : feast .getLabels (),
104+ OwnerReferences : []metav1.OwnerReference {
105+ {
106+ APIVersion : feastdevv1 .GroupVersion .String (),
107+ Kind : "FeatureStore" ,
108+ Name : cr .Name ,
109+ UID : cr .UID ,
110+ Controller : & isController ,
111+ BlockOwnerDeletion : & isController ,
112+ },
113+ },
114+ },
115+ Spec : autoscalingv2.HorizontalPodAutoscalerSpec {
116+ ScaleTargetRef : autoscalingv2.CrossVersionObjectReference {
117+ APIVersion : appsv1 .SchemeGroupVersion .String (),
118+ Kind : "Deployment" ,
119+ Name : deploy .Name ,
120+ },
121+ MinReplicas : & minReplicas ,
122+ MaxReplicas : autoscaling .MaxReplicas ,
123+ Metrics : metrics ,
124+ Behavior : autoscaling .Behavior ,
125+ },
116126 }
117127
118- return controllerutil . SetControllerReference ( cr , hpa , feast . Handler . Scheme )
128+ return hpa
119129}
120130
121131func defaultHPAMetrics () []autoscalingv2.MetricSpec {
0 commit comments