Initial commit
This commit is contained in:
122
internal/controller/hpa.go
Normal file
122
internal/controller/hpa.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
|
||||
gomaprojv1beta1 "github.com/jkaninda/goma-operator/api/v1beta1"
|
||||
autoscalingv2 "k8s.io/api/autoscaling/v2"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
// createHpa creates HPA
|
||||
func createHpa(r GatewayReconciler, ctx context.Context, req ctrl.Request, gateway *gomaprojv1beta1.Gateway) error {
|
||||
logger := log.FromContext(ctx)
|
||||
var metrics []autoscalingv2.MetricSpec
|
||||
targetCPUUtilizationPercentage := gateway.Spec.AutoScaling.TargetCPUUtilizationPercentage
|
||||
targetMemoryUtilizationPercentage := gateway.Spec.AutoScaling.TargetMemoryUtilizationPercentage
|
||||
// Add CPU metric if targetCPUUtilizationPercentage is set
|
||||
if targetCPUUtilizationPercentage != 0 {
|
||||
metrics = append(metrics, autoscalingv2.MetricSpec{
|
||||
Type: autoscalingv2.ResourceMetricSourceType,
|
||||
Resource: &autoscalingv2.ResourceMetricSource{
|
||||
Name: "cpu",
|
||||
Target: autoscalingv2.MetricTarget{
|
||||
Type: autoscalingv2.UtilizationMetricType,
|
||||
AverageUtilization: int32Ptr(targetCPUUtilizationPercentage),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
// Add Memory metric if targetMemoryUtilizationPercentage is set
|
||||
if targetMemoryUtilizationPercentage != 0 {
|
||||
metrics = append(metrics, autoscalingv2.MetricSpec{
|
||||
Type: autoscalingv2.ResourceMetricSourceType,
|
||||
Resource: &autoscalingv2.ResourceMetricSource{
|
||||
Name: "memory",
|
||||
Target: autoscalingv2.MetricTarget{
|
||||
Type: autoscalingv2.UtilizationMetricType,
|
||||
AverageUtilization: int32Ptr(targetMemoryUtilizationPercentage),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
// Create HPA
|
||||
hpa := &autoscalingv2.HorizontalPodAutoscaler{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: req.Name,
|
||||
Namespace: req.Namespace,
|
||||
},
|
||||
Spec: autoscalingv2.HorizontalPodAutoscalerSpec{
|
||||
MinReplicas: int32Ptr(gateway.Spec.AutoScaling.MinReplicas),
|
||||
MaxReplicas: gateway.Spec.AutoScaling.MaxReplicas,
|
||||
Metrics: metrics,
|
||||
ScaleTargetRef: autoscalingv2.CrossVersionObjectReference{
|
||||
APIVersion: "apps/v1",
|
||||
Kind: "Deployment",
|
||||
Name: req.Name,
|
||||
},
|
||||
},
|
||||
}
|
||||
// Check if the hpa already exists
|
||||
var existHpa autoscalingv2.HorizontalPodAutoscaler
|
||||
err := r.Get(ctx, types.NamespacedName{Name: req.Name, Namespace: req.Namespace}, &existHpa)
|
||||
if err != nil && client.IgnoreNotFound(err) != nil {
|
||||
logger.Error(err, "Failed to get HorizontalPodAutoscaler")
|
||||
return err
|
||||
}
|
||||
if err != nil && client.IgnoreNotFound(err) == nil {
|
||||
// Create the HPA if it doesn't exist
|
||||
if err = controllerutil.SetControllerReference(gateway, hpa, r.Scheme); err != nil {
|
||||
logger.Error(err, "Failed to set controller reference")
|
||||
return err
|
||||
}
|
||||
if err = r.Create(ctx, hpa); err != nil {
|
||||
logger.Error(err, "Failed to create HorizontalPodAutoscaler")
|
||||
return err
|
||||
}
|
||||
logger.Info("Created HorizontalPodAutoscaler", "HorizontalPodAutoscaler.Name", hpa.Name)
|
||||
} else {
|
||||
// Update the Deployment if the spec has changed
|
||||
if !equalHpaSpec(existHpa, *hpa) {
|
||||
existHpa.Spec = hpa.Spec
|
||||
if err = r.Update(ctx, &existHpa); err != nil {
|
||||
logger.Error(err, "Failed to update Deployment")
|
||||
return err
|
||||
}
|
||||
logger.Info("Updated HorizontalPodAutoscaler", "HorizontalPodAutoscaler.Name", hpa.Name)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Helper function to compare Deployment specs
|
||||
func equalHpaSpec(existing, desired autoscalingv2.HorizontalPodAutoscaler) bool {
|
||||
// A deep equality check or field-by-field comparison would be more accurate
|
||||
if existing.Spec.MinReplicas != desired.Spec.MinReplicas {
|
||||
return false
|
||||
}
|
||||
if existing.Spec.MaxReplicas != desired.Spec.MaxReplicas {
|
||||
return false
|
||||
}
|
||||
if existing.Spec.Metrics[0].Resource.Target.AverageUtilization != desired.Spec.Metrics[0].Resource.Target.AverageUtilization {
|
||||
return false
|
||||
}
|
||||
if existing.Spec.Metrics[1].Resource.Target.AverageUtilization != desired.Spec.Metrics[1].Resource.Target.AverageUtilization {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
func ConvertRawExtensionToStruct(raw runtime.RawExtension, out interface{}) error {
|
||||
// Unmarshal the raw JSON into the provided struct
|
||||
if err := json.Unmarshal(raw.Raw, out); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user