Files
zeekayandHanzo Dev 7cbe76b386 Go 1.27.1, and the code it can say more simply
Modules declare go 1.27.1 and the build images follow. go fix applied the
modernizers, and int32Ptr went once new(expr) could say it; omitzero is not
applied, since it changes what the JSON says.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-16 19:07:47 -07:00

117 lines
3.4 KiB
Go

package manifests
import (
"fmt"
"maps"
appsv1 "k8s.io/api/apps/v1"
autoscalingv2 "k8s.io/api/autoscaling/v2"
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
policyv1 "k8s.io/api/policy/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)
// MutateFuncFor returns a controllerutil.MutateFn that copies the spec from
// desired into existing while preserving existing metadata fields that the
// API server manages (UID, resourceVersion, etc.). Labels and annotations
// are merged from desired into existing.
func MutateFuncFor(existing, desired client.Object) controllerutil.MutateFn {
return func() error {
// Merge labels and annotations.
existingLabels := existing.GetLabels()
if existingLabels == nil {
existingLabels = make(map[string]string)
}
maps.Copy(existingLabels, desired.GetLabels())
existing.SetLabels(existingLabels)
existingAnnotations := existing.GetAnnotations()
if existingAnnotations == nil {
existingAnnotations = make(map[string]string)
}
maps.Copy(existingAnnotations, desired.GetAnnotations())
existing.SetAnnotations(existingAnnotations)
// Copy spec fields based on concrete type.
switch e := existing.(type) {
case *appsv1.Deployment:
d, ok := desired.(*appsv1.Deployment)
if !ok {
return fmt.Errorf("desired is %T, want *appsv1.Deployment", desired)
}
e.Spec.Replicas = d.Spec.Replicas
e.Spec.MinReadySeconds = d.Spec.MinReadySeconds
e.Spec.Strategy = d.Spec.Strategy
e.Spec.Template = d.Spec.Template
if e.Spec.Selector == nil {
e.Spec.Selector = d.Spec.Selector
}
case *appsv1.StatefulSet:
d, ok := desired.(*appsv1.StatefulSet)
if !ok {
return fmt.Errorf("desired is %T, want *appsv1.StatefulSet", desired)
}
e.Spec.Replicas = d.Spec.Replicas
e.Spec.MinReadySeconds = d.Spec.MinReadySeconds
e.Spec.UpdateStrategy = d.Spec.UpdateStrategy
e.Spec.Template = d.Spec.Template
// Selector and VolumeClaimTemplates are immutable after creation.
if e.Spec.Selector == nil {
e.Spec.Selector = d.Spec.Selector
}
if len(e.Spec.VolumeClaimTemplates) == 0 {
e.Spec.VolumeClaimTemplates = d.Spec.VolumeClaimTemplates
}
case *corev1.Service:
d, ok := desired.(*corev1.Service)
if !ok {
return fmt.Errorf("desired is %T, want *corev1.Service", desired)
}
e.Spec.Ports = d.Spec.Ports
e.Spec.Selector = d.Spec.Selector
e.Spec.Type = d.Spec.Type
if d.Spec.ClusterIP == "None" {
e.Spec.ClusterIP = "None"
}
case *networkingv1.Ingress:
d, ok := desired.(*networkingv1.Ingress)
if !ok {
return fmt.Errorf("desired is %T, want *networkingv1.Ingress", desired)
}
e.Spec = d.Spec
case *policyv1.PodDisruptionBudget:
d, ok := desired.(*policyv1.PodDisruptionBudget)
if !ok {
return fmt.Errorf("desired is %T, want *policyv1.PodDisruptionBudget", desired)
}
e.Spec = d.Spec
case *autoscalingv2.HorizontalPodAutoscaler:
d, ok := desired.(*autoscalingv2.HorizontalPodAutoscaler)
if !ok {
return fmt.Errorf("desired is %T, want *autoscalingv2.HorizontalPodAutoscaler", desired)
}
e.Spec = d.Spec
case *corev1.ConfigMap:
d, ok := desired.(*corev1.ConfigMap)
if !ok {
return fmt.Errorf("desired is %T, want *corev1.ConfigMap", desired)
}
e.Data = d.Data
e.BinaryData = d.BinaryData
default:
return fmt.Errorf("unsupported type for mutation: %T", existing)
}
return nil
}
}