blob: 45074d44cbec424cb01f9ae266a552683b6cffc4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package util
import (
"github.com/go-logr/logr"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
netv1 "k8s.io/api/networking/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/utils/pointer"
"reflect"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"strconv"
"strings"
)
// CopyLabelsAndAnnotations copies the labels and annotations from one object to another.
// Additional Labels and Annotations in the 'to' object will not be removed.
// Returns true if there are updates required to the object.
func CopyLabelsAndAnnotations(from, to *metav1.ObjectMeta, logger logr.Logger) (requireUpdate bool) {
if len(to.Labels) == 0 && len(from.Labels) > 0 {
to.Labels = make(map[string]string, len(from.Labels))
}
for k, v := range from.Labels {
if to.Labels[k] != v {
requireUpdate = true
logger.Info("Update Label", "label", k, "newValue", v, "oldValue", to.Labels[k])
to.Labels[k] = v
}
}
if len(to.Annotations) == 0 && len(from.Annotations) > 0 {
to.Annotations = make(map[string]string, len(from.Annotations))
}
for k, v := range from.Annotations {
if to.Annotations[k] != v {
requireUpdate = true
logger.Info("Update Annotation", "annotation", k, "newValue", v, "oldValue", to.Annotations[k])
to.Annotations[k] = v
}
}
return requireUpdate
}
func DuplicateLabelsOrAnnotations(from map[string]string) map[string]string {
to := make(map[string]string, len(from))
for k, v := range from {
to[k] = v
}
return to
}
func MergeLabelsOrAnnotations(base, additional map[string]string) map[string]string {
merged := DuplicateLabelsOrAnnotations(base)
for k, v := range additional {
if _, alreadyExists := merged[k]; !alreadyExists {
merged[k] = v
}
}
return merged
}
// DeepEqualWithNils returns a deepEquals call that treats nil and zero-length maps, arrays and slices as the same.
func DeepEqualWithNils(x, y interface{}) bool {
if (x == nil) != (y == nil) {
// Make sure that x is not the nil value
if x == nil {
x = y
}
v := reflect.ValueOf(x)
switch v.Kind() {
case reflect.Array:
case reflect.Map:
case reflect.Slice:
return v.Len() == 0
}
}
return reflect.DeepEqual(x, y)
}
// ContainsString helper function to test string contains
func ContainsString(slice []string, s string) bool {
for _, item := range slice {
if item == s {
return true
}
}
return false
}
// RemoveString helper function to remove string
func RemoveString(slice []string, s string) (result []string) {
for _, item := range slice {
if item == s {
continue
}
result = append(result, item)
}
return
}
// IsPVCOrphan determines whether the given name represents a PVC that is an orphan, or no longer has a pod associated with it.
func IsPVCOrphan(pvcName string, replicas int32) bool {
index := strings.LastIndexAny(pvcName, "-")
if index == -1 {
return false
}
ordinal, err := strconv.Atoi(pvcName[index+1:])
if err != nil {
return false
}
return int32(ordinal) >= replicas
}
// customizeProbe builds the probe logic used for pod liveness, readiness, startup checks
func customizeProbe(initialProbe *corev1.Probe, customProbe corev1.Probe) *corev1.Probe {
if customProbe.InitialDelaySeconds != 0 {
initialProbe.InitialDelaySeconds = customProbe.InitialDelaySeconds
}
if customProbe.TimeoutSeconds != 0 {
initialProbe.TimeoutSeconds = customProbe.TimeoutSeconds
}
if customProbe.SuccessThreshold != 0 {
initialProbe.SuccessThreshold = customProbe.SuccessThreshold
}
if customProbe.FailureThreshold != 0 {
initialProbe.FailureThreshold = customProbe.FailureThreshold
}
if customProbe.PeriodSeconds != 0 {
initialProbe.PeriodSeconds = customProbe.PeriodSeconds
}
if customProbe.Handler.Exec != nil || customProbe.Handler.HTTPGet != nil || customProbe.Handler.TCPSocket != nil {
initialProbe.Handler = customProbe.Handler
}
return initialProbe
}
// CopyConfigMapFields copies the owned fields from one ConfigMap to another
func CopyConfigMapFields(from, to *corev1.ConfigMap, logger logr.Logger) bool {
logger = logger.WithValues("kind", "configMap")
requireUpdate := CopyLabelsAndAnnotations(&from.ObjectMeta, &to.ObjectMeta, logger)
// Don't copy the entire Spec, because we can't overwrite the clusterIp field
if !DeepEqualWithNils(to.Data, from.Data) {
requireUpdate = true
logger.Info("Update required because field changed", "field", "Data", "from", to.Data, "to", from.Data)
}
to.Data = from.Data
return requireUpdate
}
// CopyServiceFields copies the owned fields from one Service to another
func CopyServiceFields(from, to *corev1.Service, logger logr.Logger) bool {
logger = logger.WithValues("kind", "service")
requireUpdate := CopyLabelsAndAnnotations(&from.ObjectMeta, &to.ObjectMeta, logger)
// Don't copy the entire Spec, because we can't overwrite the clusterIp field
if !DeepEqualWithNils(to.Spec.Selector, from.Spec.Selector) {
requireUpdate = true
logger.Info("Update required because field changed", "field", "Spec.Selector", "from", to.Spec.Selector, "to", from.Spec.Selector)
}
to.Spec.Selector = from.Spec.Selector
if !DeepEqualWithNils(to.Spec.Ports, from.Spec.Ports) {
requireUpdate = true
logger.Info("Update required because field changed", "field", "Spec.Ports", "from", to.Spec.Ports, "to", from.Spec.Ports)
}
to.Spec.Ports = from.Spec.Ports
if !DeepEqualWithNils(to.Spec.ExternalName, from.Spec.ExternalName) {
requireUpdate = true
logger.Info("Update required because field changed", "field", "Spec.ExternalName", "from", to.Spec.ExternalName, "to", from.Spec.ExternalName)
}
to.Spec.ExternalName = from.Spec.ExternalName
if !DeepEqualWithNils(to.Spec.PublishNotReadyAddresses, from.Spec.PublishNotReadyAddresses) {
requireUpdate = true
logger.Info("Update required because field changed", "field", "Spec.PublishNotReadyAddresses", "from", to.Spec.PublishNotReadyAddresses, "to", from.Spec.PublishNotReadyAddresses)
}
to.Spec.PublishNotReadyAddresses = from.Spec.PublishNotReadyAddresses
return requireUpdate
}
// CopyIngressFields copies the owned fields from one Ingress to another
func CopyIngressFields(from, to *netv1.Ingress, logger logr.Logger) bool {
logger = logger.WithValues("kind", "ingress")
requireUpdate := CopyLabelsAndAnnotations(&from.ObjectMeta, &to.ObjectMeta, logger)
if len(to.Spec.Rules) != len(from.Spec.Rules) {
requireUpdate = true
logger.Info("Update required because field changed", "field", "Spec.Rules", "from", to.Spec.Rules, "to", from.Spec.Rules)
to.Spec.Rules = from.Spec.Rules
} else {
for i := range from.Spec.Rules {
ruleBase := "Spec.Rules[" + strconv.Itoa(i) + "]."
fromRule := &from.Spec.Rules[i]
toRule := &to.Spec.Rules[i]
if !DeepEqualWithNils(toRule.Host, fromRule.Host) {
requireUpdate = true
logger.Info("Update required because field changed", "field", ruleBase+"Host", "from", toRule.Host, "to", fromRule.Host)
toRule.Host = fromRule.Host
}
if fromRule.HTTP == nil || toRule.HTTP == nil {
requireUpdate = true
logger.Info("Update required because field changed", "field", ruleBase+"HTTP", "from", toRule.HTTP, "to", fromRule.HTTP)
toRule.HTTP = fromRule.HTTP
} else if len(fromRule.HTTP.Paths) != len(toRule.HTTP.Paths) {
requireUpdate = true
logger.Info("Update required because field changed", "field", ruleBase+"HTTP.Paths", "from", toRule.HTTP.Paths, "to", fromRule.HTTP.Paths)
toRule.HTTP.Paths = fromRule.HTTP.Paths
} else {
for j := range fromRule.HTTP.Paths {
pathBase := ruleBase + "HTTP.Paths[" + strconv.Itoa(j) + "]."
fromPath := &fromRule.HTTP.Paths[j]
toPath := &toRule.HTTP.Paths[j]
if toPath.PathType != nil && !DeepEqualWithNils(toPath.PathType, fromPath.PathType) {
requireUpdate = true
logger.Info("Update required because field changed", "field", pathBase+"PathType", "from", toPath.PathType, "to", fromPath.PathType)
toPath.PathType = fromPath.PathType
}
if !DeepEqualWithNils(toPath.Path, fromPath.Path) {
requireUpdate = true
logger.Info("Update required because field changed", "field", pathBase+"Path", "from", toPath.Path, "to", fromPath.Path)
toPath.Path = fromPath.Path
}
if !DeepEqualWithNils(toPath.Backend.ServiceName, fromPath.Backend.ServiceName) {
requireUpdate = true
logger.Info("Update required because field changed", "field", pathBase+"Backend.ServiceName", "from", toPath.Backend.ServiceName, "to", fromPath.Backend.ServiceName)
toPath.Backend.ServiceName = fromPath.Backend.ServiceName
}
if !DeepEqualWithNils(toPath.Backend.ServicePort, fromPath.Backend.ServicePort) {
requireUpdate = true
logger.Info("Update required because field changed", "field", pathBase+"Backend.ServicePort", "from", toPath.Backend.ServicePort, "to", fromPath.Backend.ServicePort)
toPath.Backend.ServicePort = fromPath.Backend.ServicePort
}
if !DeepEqualWithNils(toPath.Backend.Resource, fromPath.Backend.Resource) {
requireUpdate = true
logger.Info("Update required because field changed", "field", pathBase+"Backend.Resource", "from", toPath.Backend.Resource, "to", fromPath.Backend.Resource)
toPath.Backend.Resource = fromPath.Backend.Resource
}
}
}
}
}
if !DeepEqualWithNils(to.Spec.TLS, from.Spec.TLS) {
requireUpdate = true
to.Spec.TLS = from.Spec.TLS
}
return requireUpdate
}
// CopyStatefulSetFields copies the owned fields from one StatefulSet to another
// Returns true if the fields copied from don't match to.
func CopyStatefulSetFields(from, to *appsv1.StatefulSet, logger logr.Logger) bool {
logger = logger.WithValues("kind", "statefulSet")
requireUpdate := CopyLabelsAndAnnotations(&from.ObjectMeta, &to.ObjectMeta, logger)
if !DeepEqualWithNils(to.Spec.Replicas, from.Spec.Replicas) {
requireUpdate = true
logger.Info("Update required because field changed", "field", "Spec.Replicas", "from", to.Spec.Replicas, "to", from.Spec.Replicas)
to.Spec.Replicas = from.Spec.Replicas
}
if !DeepEqualWithNils(to.Spec.UpdateStrategy, from.Spec.UpdateStrategy) {
requireUpdate = true
logger.Info("Update required because field changed", "field", "Spec.UpdateStrategy", "from", to.Spec.UpdateStrategy, "to", from.Spec.UpdateStrategy)
to.Spec.UpdateStrategy = from.Spec.UpdateStrategy
}
/*
Kubernetes does not currently support updates to these fields: Selector and PodManagementPolicy
if !DeepEqualWithNils(to.Spec.Selector, from.Spec.Selector) {
requireUpdate = true
logger.Info("Update required because field changed", "field", "Spec.Selector", "from", to.Spec.Selector, "to", from.Spec.Selector)
to.Spec.Selector = from.Spec.Selector
}
if !DeepEqualWithNils(to.Spec.PodManagementPolicy, from.Spec.PodManagementPolicy) {
requireUpdate = true
logger.Info("Update required because field changed", "field", "Spec.PodManagementPolicy", "from", to.Spec.PodManagementPolicy, "to", from.Spec.PodManagementPolicy)
to.Spec.PodManagementPolicy = from.Spec.PodManagementPolicy
}
*/
/*
Kubernetes does not support modification of VolumeClaimTemplates currently. See:
https://github.com/kubernetes/enhancements/issues/661
if len(from.Spec.VolumeClaimTemplates) > len(to.Spec.VolumeClaimTemplates) {
requireUpdate = true
logger.Info("Update required because field changed", "field", "Spec.VolumeClaimTemplates", "from", to.Spec.VolumeClaimTemplates, "to", from.Spec.VolumeClaimTemplates)
to.Spec.VolumeClaimTemplates = from.Spec.VolumeClaimTemplates
}
for i := range from.Spec.VolumeClaimTemplates {
vctBase := "Spec.VolumeClaimTemplates["+strconv.Itoa(i)+"]."
fromVct := &from.Spec.VolumeClaimTemplates[i]
toVct := &to.Spec.VolumeClaimTemplates[i]
if !DeepEqualWithNils(to.Spec.VolumeClaimTemplates[i].Name, fromVct.Name) {
requireUpdate = true
logger.Info("Update required because field changed", "field", vctBase+"Name", "from", toVct.Name, "to", fromVct.Name)
toVct.Name = fromVct.Name
}
if !DeepEqualWithNils(to.Spec.VolumeClaimTemplates[i].Labels, fromVct.Labels) {
requireUpdate = true
logger.Info("Update required because field changed", "field", vctBase+"Labels", "from", toVct.Labels, "to", fromVct.Labels)
toVct.Labels = fromVct.Labels
}
if !DeepEqualWithNils(to.Spec.VolumeClaimTemplates[i].Annotations, fromVct.Annotations) {
requireUpdate = true
logger.Info("Update required because field changed", "field", vctBase+"Annotations", "from", toVct.Annotations, "to", fromVct.Annotations)
toVct.Annotations = fromVct.Annotations
}
if !DeepEqualWithNils(to.Spec.VolumeClaimTemplates[i].Spec, fromVct.Spec) {
requireUpdate = true
logger.Info("Update required because field changed", "field", vctBase+"Spec", "from", toVct.Spec, "to", fromVct.Spec)
toVct.Spec = fromVct.Spec
}
}
*/
requireUpdate = CopyPodTemplates(&from.Spec.Template, &to.Spec.Template, "Spec.Template.", logger) || requireUpdate
return requireUpdate
}
// CopyDeploymentFields copies the owned fields from one Deployment to another
// Returns true if the fields copied from don't match to.
func CopyDeploymentFields(from, to *appsv1.Deployment, logger logr.Logger) bool {
logger = logger.WithValues("kind", "deployment")
requireUpdate := CopyLabelsAndAnnotations(&from.ObjectMeta, &to.ObjectMeta, logger)
if !DeepEqualWithNils(to.Spec.Replicas, from.Spec.Replicas) {
requireUpdate = true
logger.Info("Update required because field changed", "field", "Spec.Replicas", "from", to.Spec.Replicas, "to", from.Spec.Replicas)
to.Spec.Replicas = from.Spec.Replicas
}
if !DeepEqualWithNils(to.Spec.Selector, from.Spec.Selector) {
requireUpdate = true
logger.Info("Update required because field changed", "field", "Spec.Selector", "from", to.Spec.Selector, "to", from.Spec.Selector)
to.Spec.Selector = from.Spec.Selector
}
requireUpdate = CopyPodTemplates(&from.Spec.Template, &to.Spec.Template, "Spec.Template.", logger) || requireUpdate
return requireUpdate
}
func CopyPodTemplates(from, to *corev1.PodTemplateSpec, basePath string, logger logr.Logger) (requireUpdate bool) {
if basePath == "" {
logger = logger.WithValues("kind", "pod")
}
if !DeepEqualWithNils(to.Labels, from.Labels) {
requireUpdate = true
logger.Info("Update required because field changed", "field", basePath+"Labels", "from", to.Labels, "to", from.Labels)
to.Labels = from.Labels
}
if !DeepEqualWithNils(to.Annotations, from.Annotations) {
requireUpdate = true
logger.Info("Update required because field changed", "field", basePath+"Annotations", "from", to.Annotations, "to", from.Annotations)
to.Annotations = from.Annotations
}
requireUpdate = CopyPodContainers(&from.Spec.Containers, &to.Spec.Containers, basePath+"Spec.Containers", logger) || requireUpdate
requireUpdate = CopyPodContainers(&from.Spec.InitContainers, &to.Spec.InitContainers, basePath+"Spec.InitContainers", logger) || requireUpdate
if !DeepEqualWithNils(to.Spec.HostAliases, from.Spec.HostAliases) {
requireUpdate = true
to.Spec.HostAliases = from.Spec.HostAliases
logger.Info("Update required because field changed", "field", basePath+"Spec.HostAliases", "from", to.Spec.HostAliases, "to", from.Spec.HostAliases)
}
if !DeepEqualWithNils(to.Spec.Volumes, from.Spec.Volumes) {
requireUpdate = true
to.Spec.Volumes = from.Spec.Volumes
logger.Info("Update required because field changed", "field", basePath+"Spec.Volumes", "from", to.Spec.Volumes, "to", from.Spec.Volumes)
}
if !DeepEqualWithNils(to.Spec.ImagePullSecrets, from.Spec.ImagePullSecrets) {
requireUpdate = true
logger.Info("Update required because field changed", "field", basePath+"Spec.ImagePullSecrets", "from", to.Spec.ImagePullSecrets, "to", from.Spec.ImagePullSecrets)
to.Spec.ImagePullSecrets = from.Spec.ImagePullSecrets
}
if !DeepEqualWithNils(to.Spec.Affinity, from.Spec.Affinity) {
requireUpdate = true
logger.Info("Update required because field changed", "field", basePath+"Spec.Affinity", "from", to.Spec.Affinity, "to", from.Spec.Affinity)
to.Spec.Affinity = from.Spec.Affinity
}
if !DeepEqualWithNils(to.Spec.SecurityContext, from.Spec.SecurityContext) {
requireUpdate = true
logger.Info("Update required because field changed", "field", basePath+"Spec.SecurityContext", "from", to.Spec.SecurityContext, "to", from.Spec.SecurityContext)
to.Spec.SecurityContext = from.Spec.SecurityContext
}
if !DeepEqualWithNils(to.Spec.NodeSelector, from.Spec.NodeSelector) {
requireUpdate = true
logger.Info("Update required because field changed", "field", basePath+"Spec.NodeSelector", "from", to.Spec.NodeSelector, "to", from.Spec.NodeSelector)
to.Spec.NodeSelector = from.Spec.NodeSelector
}
if !DeepEqualWithNils(to.Spec.Tolerations, from.Spec.Tolerations) {
requireUpdate = true
logger.Info("Update required because field changed", "field", basePath+"Spec.Tolerations", "from", to.Spec.Tolerations, "to", from.Spec.Tolerations)
to.Spec.Tolerations = from.Spec.Tolerations
}
if !DeepEqualWithNils(to.Spec.PriorityClassName, from.Spec.PriorityClassName) {
requireUpdate = true
logger.Info("Update required because field changed", "field", basePath+"Spec.PriorityClassName", "from", to.Spec.PriorityClassName, "to", from.Spec.PriorityClassName)
to.Spec.PriorityClassName = from.Spec.PriorityClassName
}
if !DeepEqualWithNils(to.Spec.TerminationGracePeriodSeconds, from.Spec.TerminationGracePeriodSeconds) {
requireUpdate = true
logger.Info("Update required because field changed", "field", basePath+"Spec.TerminationGracePeriodSeconds", "from", to.Spec.TerminationGracePeriodSeconds, "to", from.Spec.TerminationGracePeriodSeconds)
to.Spec.TerminationGracePeriodSeconds = from.Spec.TerminationGracePeriodSeconds
}
if !DeepEqualWithNils(to.Spec.ServiceAccountName, from.Spec.ServiceAccountName) {
requireUpdate = true
logger.Info("Update required because field changed", "field", basePath+"Spec.ServiceAccountName", "from", to.Spec.ServiceAccountName, "to", from.Spec.ServiceAccountName)
to.Spec.ServiceAccountName = from.Spec.ServiceAccountName
}
return requireUpdate
}
func CopyPodContainers(fromPtr, toPtr *[]corev1.Container, basePath string, logger logr.Logger) (requireUpdate bool) {
to := *toPtr
from := *fromPtr
if len(to) != len(from) {
requireUpdate = true
logger.Info("Update required because field changed", "field", basePath+"Length", "from", len(to), "to", len(from))
*toPtr = from
} else {
for i := 0; i < len(from); i++ {
containerBasePath := basePath + "[" + strconv.Itoa(i) + "]."
if !DeepEqualWithNils(to[i].Name, from[i].Name) {
requireUpdate = true
logger.Info("Update required because field changed", "field", containerBasePath+"Name", "from", to[i].Name, "to", from[i].Name)
to[i].Name = from[i].Name
}
if !DeepEqualWithNils(to[i].Image, from[i].Image) {
requireUpdate = true
logger.Info("Update required because field changed", "field", containerBasePath+"Image", "from", to[i].Image, "to", from[i].Image)
to[i].Image = from[i].Image
}
if from[i].ImagePullPolicy != "" && !DeepEqualWithNils(to[i].ImagePullPolicy, from[i].ImagePullPolicy) {
// Only request an update if the requestedPullPolicy is not empty
// Otherwise kubernetes will specify a defaultPollPolicy and the operator will endlessly recurse, trying to unset the default policy.
requireUpdate = true
logger.Info("Update required because field changed", "field", containerBasePath+"ImagePullPolicy", "from", to[i].ImagePullPolicy, "to", from[i].ImagePullPolicy)
}
to[i].ImagePullPolicy = from[i].ImagePullPolicy
if !DeepEqualWithNils(to[i].Command, from[i].Command) {
requireUpdate = true
logger.Info("Update required because field changed", "field", containerBasePath+"Command", "from", to[i].Command, "to", from[i].Command)
to[i].Command = from[i].Command
}
if !DeepEqualWithNils(to[i].Args, from[i].Args) {
requireUpdate = true
logger.Info("Update required because field changed", "field", containerBasePath+"Args", "from", to[i].Args, "to", from[i].Args)
to[i].Args = from[i].Args
}
if !DeepEqualWithNils(to[i].Env, from[i].Env) {
requireUpdate = true
logger.Info("Update required because field changed", "field", containerBasePath+"Env", "from", to[i].Env, "to", from[i].Env)
to[i].Env = from[i].Env
}
if !DeepEqualWithNils(to[i].Resources, from[i].Resources) {
requireUpdate = true
logger.Info("Update required because field changed", "field", containerBasePath+"Resources", "from", to[i].Resources, "to", from[i].Resources)
to[i].Resources = from[i].Resources
}
if !DeepEqualWithNils(to[i].VolumeMounts, from[i].VolumeMounts) {
requireUpdate = true
logger.Info("Update required because field changed", "field", containerBasePath+"VolumeMounts", "from", to[i].VolumeMounts, "to", from[i].VolumeMounts)
to[i].VolumeMounts = from[i].VolumeMounts
}
if !DeepEqualWithNils(to[i].Ports, from[i].Ports) {
requireUpdate = true
logger.Info("Update required because field changed", "field", containerBasePath+"Ports", "from", to[i].Ports, "to", from[i].Ports)
to[i].Ports = from[i].Ports
}
if !DeepEqualWithNils(to[i].Lifecycle, from[i].Lifecycle) {
requireUpdate = true
logger.Info("Update required because field changed", "field", containerBasePath+"Lifecycle", "from", to[i].Lifecycle, "to", from[i].Lifecycle)
to[i].Lifecycle = from[i].Lifecycle
}
if !DeepEqualWithNils(to[i].LivenessProbe, from[i].LivenessProbe) {
requireUpdate = true
logger.Info("Update required because field changed", "field", containerBasePath+"LivenessProbe", "from", to[i].LivenessProbe, "to", from[i].LivenessProbe)
to[i].LivenessProbe = from[i].LivenessProbe
}
if !DeepEqualWithNils(to[i].ReadinessProbe, from[i].ReadinessProbe) {
requireUpdate = true
logger.Info("Update required because field changed", "field", containerBasePath+"ReadinessProbe", "from", to[i].ReadinessProbe, "to", from[i].ReadinessProbe)
to[i].ReadinessProbe = from[i].ReadinessProbe
}
if !DeepEqualWithNils(to[i].StartupProbe, from[i].StartupProbe) {
requireUpdate = true
logger.Info("Update required because field changed", "field", containerBasePath+"StartupProbe", "from", to[i].StartupProbe, "to", from[i].StartupProbe)
to[i].StartupProbe = from[i].StartupProbe
}
if from[i].TerminationMessagePath != "" && !DeepEqualWithNils(to[i].TerminationMessagePath, from[i].TerminationMessagePath) {
requireUpdate = true
logger.Info("Update required because field changed", "field", containerBasePath+"TerminationMessagePath", "from", to[i].TerminationMessagePath, "to", from[i].TerminationMessagePath)
to[i].TerminationMessagePath = from[i].TerminationMessagePath
}
if from[i].TerminationMessagePolicy != "" && !DeepEqualWithNils(to[i].TerminationMessagePolicy, from[i].TerminationMessagePolicy) {
requireUpdate = true
logger.Info("Update required because field changed", "field", containerBasePath+"TerminationMessagePolicy", "from", to[i].TerminationMessagePolicy, "to", from[i].TerminationMessagePolicy)
to[i].TerminationMessagePolicy = from[i].TerminationMessagePolicy
}
}
}
return requireUpdate
}
// OvertakeControllerRef makes sure that the controlled object has the owner as the controller ref.
// If the object has a different controller, then that ref will be downgraded to an "owner" and the new controller ref will be added
func OvertakeControllerRef(owner metav1.Object, controlled metav1.Object, scheme *runtime.Scheme) (needsUpdate bool, err error) {
if !metav1.IsControlledBy(controlled, owner) {
if otherController := metav1.GetControllerOfNoCopy(controlled); otherController != nil {
otherController.Controller = pointer.BoolPtr(false)
otherController.BlockOwnerDeletion = pointer.BoolPtr(false)
}
err = controllerutil.SetControllerReference(owner, controlled, scheme)
needsUpdate = true
}
return needsUpdate, err
}