Skip to content

Commit f49b4f1

Browse files
authored
Ensure podAnnotations are removed from pods if reset in the config (#2826)
1 parent b0cfeb3 commit f49b4f1

9 files changed

+311
-58
lines changed

pkg/cluster/cluster.go

+40-24
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,17 @@ type Cluster struct {
105105
}
106106

107107
type compareStatefulsetResult struct {
108-
match bool
109-
replace bool
110-
rollingUpdate bool
111-
reasons []string
108+
match bool
109+
replace bool
110+
rollingUpdate bool
111+
reasons []string
112+
deletedPodAnnotations []string
113+
}
114+
115+
type compareLogicalBackupJobResult struct {
116+
match bool
117+
reasons []string
118+
deletedPodAnnotations []string
112119
}
113120

114121
// New creates a new cluster. This function should be called from a controller.
@@ -431,6 +438,7 @@ func (c *Cluster) Create() (err error) {
431438
}
432439

433440
func (c *Cluster) compareStatefulSetWith(statefulSet *appsv1.StatefulSet) *compareStatefulsetResult {
441+
deletedPodAnnotations := []string{}
434442
reasons := make([]string, 0)
435443
var match, needsRollUpdate, needsReplace bool
436444

@@ -445,7 +453,7 @@ func (c *Cluster) compareStatefulSetWith(statefulSet *appsv1.StatefulSet) *compa
445453
needsReplace = true
446454
reasons = append(reasons, "new statefulset's ownerReferences do not match")
447455
}
448-
if changed, reason := c.compareAnnotations(c.Statefulset.Annotations, statefulSet.Annotations); changed {
456+
if changed, reason := c.compareAnnotations(c.Statefulset.Annotations, statefulSet.Annotations, nil); changed {
449457
match = false
450458
needsReplace = true
451459
reasons = append(reasons, "new statefulset's annotations do not match: "+reason)
@@ -519,7 +527,7 @@ func (c *Cluster) compareStatefulSetWith(statefulSet *appsv1.StatefulSet) *compa
519527
}
520528
}
521529

522-
if changed, reason := c.compareAnnotations(c.Statefulset.Spec.Template.Annotations, statefulSet.Spec.Template.Annotations); changed {
530+
if changed, reason := c.compareAnnotations(c.Statefulset.Spec.Template.Annotations, statefulSet.Spec.Template.Annotations, &deletedPodAnnotations); changed {
523531
match = false
524532
needsReplace = true
525533
reasons = append(reasons, "new statefulset's pod template metadata annotations does not match "+reason)
@@ -541,7 +549,7 @@ func (c *Cluster) compareStatefulSetWith(statefulSet *appsv1.StatefulSet) *compa
541549
reasons = append(reasons, fmt.Sprintf("new statefulset's name for volume %d does not match the current one", i))
542550
continue
543551
}
544-
if changed, reason := c.compareAnnotations(c.Statefulset.Spec.VolumeClaimTemplates[i].Annotations, statefulSet.Spec.VolumeClaimTemplates[i].Annotations); changed {
552+
if changed, reason := c.compareAnnotations(c.Statefulset.Spec.VolumeClaimTemplates[i].Annotations, statefulSet.Spec.VolumeClaimTemplates[i].Annotations, nil); changed {
545553
needsReplace = true
546554
reasons = append(reasons, fmt.Sprintf("new statefulset's annotations for volume %q do not match the current ones: %s", name, reason))
547555
}
@@ -579,7 +587,7 @@ func (c *Cluster) compareStatefulSetWith(statefulSet *appsv1.StatefulSet) *compa
579587
match = false
580588
}
581589

582-
return &compareStatefulsetResult{match: match, reasons: reasons, rollingUpdate: needsRollUpdate, replace: needsReplace}
590+
return &compareStatefulsetResult{match: match, reasons: reasons, rollingUpdate: needsRollUpdate, replace: needsReplace, deletedPodAnnotations: deletedPodAnnotations}
583591
}
584592

585593
type containerCondition func(a, b v1.Container) bool
@@ -781,7 +789,7 @@ func volumeMountExists(mount v1.VolumeMount, mounts []v1.VolumeMount) bool {
781789
return false
782790
}
783791

784-
func (c *Cluster) compareAnnotations(old, new map[string]string) (bool, string) {
792+
func (c *Cluster) compareAnnotations(old, new map[string]string, removedList *[]string) (bool, string) {
785793
reason := ""
786794
ignoredAnnotations := make(map[string]bool)
787795
for _, ignore := range c.OpConfig.IgnoredAnnotations {
@@ -794,6 +802,9 @@ func (c *Cluster) compareAnnotations(old, new map[string]string) (bool, string)
794802
}
795803
if _, ok := new[key]; !ok {
796804
reason += fmt.Sprintf(" Removed %q.", key)
805+
if removedList != nil {
806+
*removedList = append(*removedList, key)
807+
}
797808
}
798809
}
799810

@@ -836,41 +847,46 @@ func (c *Cluster) compareServices(old, new *v1.Service) (bool, string) {
836847
return true, ""
837848
}
838849

839-
func (c *Cluster) compareLogicalBackupJob(cur, new *batchv1.CronJob) (match bool, reason string) {
850+
func (c *Cluster) compareLogicalBackupJob(cur, new *batchv1.CronJob) *compareLogicalBackupJobResult {
851+
deletedPodAnnotations := []string{}
852+
reasons := make([]string, 0)
853+
match := true
840854

841855
if cur.Spec.Schedule != new.Spec.Schedule {
842-
return false, fmt.Sprintf("new job's schedule %q does not match the current one %q",
843-
new.Spec.Schedule, cur.Spec.Schedule)
856+
match = false
857+
reasons = append(reasons, fmt.Sprintf("new job's schedule %q does not match the current one %q", new.Spec.Schedule, cur.Spec.Schedule))
844858
}
845859

846860
newImage := new.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Image
847861
curImage := cur.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Image
848862
if newImage != curImage {
849-
return false, fmt.Sprintf("new job's image %q does not match the current one %q",
850-
newImage, curImage)
863+
match = false
864+
reasons = append(reasons, fmt.Sprintf("new job's image %q does not match the current one %q", newImage, curImage))
851865
}
852866

853867
newPodAnnotation := new.Spec.JobTemplate.Spec.Template.Annotations
854868
curPodAnnotation := cur.Spec.JobTemplate.Spec.Template.Annotations
855-
if changed, reason := c.compareAnnotations(curPodAnnotation, newPodAnnotation); changed {
856-
return false, fmt.Sprintf("new job's pod template metadata annotations does not match " + reason)
869+
if changed, reason := c.compareAnnotations(curPodAnnotation, newPodAnnotation, &deletedPodAnnotations); changed {
870+
match = false
871+
reasons = append(reasons, fmt.Sprint("new job's pod template metadata annotations do not match "+reason))
857872
}
858873

859874
newPgVersion := getPgVersion(new)
860875
curPgVersion := getPgVersion(cur)
861876
if newPgVersion != curPgVersion {
862-
return false, fmt.Sprintf("new job's env PG_VERSION %q does not match the current one %q",
863-
newPgVersion, curPgVersion)
877+
match = false
878+
reasons = append(reasons, fmt.Sprintf("new job's env PG_VERSION %q does not match the current one %q", newPgVersion, curPgVersion))
864879
}
865880

866881
needsReplace := false
867-
reasons := make([]string, 0)
868-
needsReplace, reasons = c.compareContainers("cronjob container", cur.Spec.JobTemplate.Spec.Template.Spec.Containers, new.Spec.JobTemplate.Spec.Template.Spec.Containers, needsReplace, reasons)
882+
contReasons := make([]string, 0)
883+
needsReplace, contReasons = c.compareContainers("cronjob container", cur.Spec.JobTemplate.Spec.Template.Spec.Containers, new.Spec.JobTemplate.Spec.Template.Spec.Containers, needsReplace, contReasons)
869884
if needsReplace {
870-
return false, fmt.Sprintf("logical backup container specs do not match: %v", strings.Join(reasons, `', '`))
885+
match = false
886+
reasons = append(reasons, fmt.Sprintf("logical backup container specs do not match: %v", strings.Join(contReasons, `', '`)))
871887
}
872888

873-
return true, ""
889+
return &compareLogicalBackupJobResult{match: match, reasons: reasons, deletedPodAnnotations: deletedPodAnnotations}
874890
}
875891

876892
func (c *Cluster) comparePodDisruptionBudget(cur, new *policyv1.PodDisruptionBudget) (bool, string) {
@@ -881,7 +897,7 @@ func (c *Cluster) comparePodDisruptionBudget(cur, new *policyv1.PodDisruptionBud
881897
if !reflect.DeepEqual(new.ObjectMeta.OwnerReferences, cur.ObjectMeta.OwnerReferences) {
882898
return false, "new PDB's owner references do not match the current ones"
883899
}
884-
if changed, reason := c.compareAnnotations(cur.Annotations, new.Annotations); changed {
900+
if changed, reason := c.compareAnnotations(cur.Annotations, new.Annotations, nil); changed {
885901
return false, "new PDB's annotations do not match the current ones:" + reason
886902
}
887903
return true, ""
@@ -1021,7 +1037,7 @@ func (c *Cluster) Update(oldSpec, newSpec *acidv1.Postgresql) error {
10211037
// only when streams were not specified in oldSpec but in newSpec
10221038
needStreamUser := len(oldSpec.Spec.Streams) == 0 && len(newSpec.Spec.Streams) > 0
10231039

1024-
annotationsChanged, _ := c.compareAnnotations(oldSpec.Annotations, newSpec.Annotations)
1040+
annotationsChanged, _ := c.compareAnnotations(oldSpec.Annotations, newSpec.Annotations, nil)
10251041

10261042
initUsers := !sameUsers || !sameRotatedUsers || needPoolerUser || needStreamUser
10271043
if initUsers {

pkg/cluster/cluster_test.go

+14-6
Original file line numberDiff line numberDiff line change
@@ -1680,12 +1680,20 @@ func TestCompareLogicalBackupJob(t *testing.T) {
16801680
}
16811681
}
16821682

1683-
match, reason := cluster.compareLogicalBackupJob(currentCronJob, desiredCronJob)
1684-
if match != tt.match {
1685-
t.Errorf("%s - unexpected match result %t when comparing cronjobs %#v and %#v", t.Name(), match, currentCronJob, desiredCronJob)
1686-
} else {
1687-
if !strings.HasPrefix(reason, tt.reason) {
1688-
t.Errorf("%s - expected reason prefix %s, found %s", t.Name(), tt.reason, reason)
1683+
cmp := cluster.compareLogicalBackupJob(currentCronJob, desiredCronJob)
1684+
if cmp.match != tt.match {
1685+
t.Errorf("%s - unexpected match result %t when comparing cronjobs %#v and %#v", t.Name(), cmp.match, currentCronJob, desiredCronJob)
1686+
} else if !cmp.match {
1687+
found := false
1688+
for _, reason := range cmp.reasons {
1689+
if strings.HasPrefix(reason, tt.reason) {
1690+
found = true
1691+
break
1692+
}
1693+
found = false
1694+
}
1695+
if !found {
1696+
t.Errorf("%s - expected reason prefix %s, not found in %#v", t.Name(), tt.reason, cmp.reasons)
16891697
}
16901698
}
16911699
})

pkg/cluster/connection_pooler.go

+33-7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package cluster
22

33
import (
44
"context"
5+
"encoding/json"
56
"fmt"
67
"reflect"
78
"strings"
@@ -977,6 +978,7 @@ func (c *Cluster) syncConnectionPoolerWorker(oldSpec, newSpec *acidv1.Postgresql
977978
err error
978979
)
979980

981+
updatedPodAnnotations := map[string]*string{}
980982
syncReason := make([]string, 0)
981983
deployment, err = c.KubeClient.
982984
Deployments(c.Namespace).
@@ -1038,9 +1040,27 @@ func (c *Cluster) syncConnectionPoolerWorker(oldSpec, newSpec *acidv1.Postgresql
10381040
}
10391041

10401042
newPodAnnotations := c.annotationsSet(c.generatePodAnnotations(&c.Spec))
1041-
if changed, reason := c.compareAnnotations(deployment.Spec.Template.Annotations, newPodAnnotations); changed {
1043+
deletedPodAnnotations := []string{}
1044+
if changed, reason := c.compareAnnotations(deployment.Spec.Template.Annotations, newPodAnnotations, &deletedPodAnnotations); changed {
10421045
specSync = true
10431046
syncReason = append(syncReason, []string{"new connection pooler's pod template annotations do not match the current ones: " + reason}...)
1047+
1048+
for _, anno := range deletedPodAnnotations {
1049+
updatedPodAnnotations[anno] = nil
1050+
}
1051+
templateMetadataReq := map[string]map[string]map[string]map[string]map[string]*string{
1052+
"spec": {"template": {"metadata": {"annotations": updatedPodAnnotations}}}}
1053+
patch, err := json.Marshal(templateMetadataReq)
1054+
if err != nil {
1055+
return nil, fmt.Errorf("could not marshal ObjectMeta for %s connection pooler's pod template: %v", role, err)
1056+
}
1057+
deployment, err = c.KubeClient.Deployments(c.Namespace).Patch(context.TODO(),
1058+
deployment.Name, types.StrategicMergePatchType, patch, metav1.PatchOptions{}, "")
1059+
if err != nil {
1060+
c.logger.Errorf("failed to patch %s connection pooler's pod template: %v", role, err)
1061+
return nil, err
1062+
}
1063+
10441064
deployment.Spec.Template.Annotations = newPodAnnotations
10451065
}
10461066

@@ -1064,7 +1084,7 @@ func (c *Cluster) syncConnectionPoolerWorker(oldSpec, newSpec *acidv1.Postgresql
10641084
}
10651085

10661086
newAnnotations := c.AnnotationsToPropagate(c.annotationsSet(nil)) // including the downscaling annotations
1067-
if changed, _ := c.compareAnnotations(deployment.Annotations, newAnnotations); changed {
1087+
if changed, _ := c.compareAnnotations(deployment.Annotations, newAnnotations, nil); changed {
10681088
deployment, err = patchConnectionPoolerAnnotations(c.KubeClient, deployment, newAnnotations)
10691089
if err != nil {
10701090
return nil, err
@@ -1098,14 +1118,20 @@ func (c *Cluster) syncConnectionPoolerWorker(oldSpec, newSpec *acidv1.Postgresql
10981118
if err != nil {
10991119
return nil, fmt.Errorf("could not delete pooler pod: %v", err)
11001120
}
1101-
} else if changed, _ := c.compareAnnotations(pod.Annotations, deployment.Spec.Template.Annotations); changed {
1102-
patchData, err := metaAnnotationsPatch(deployment.Spec.Template.Annotations)
1121+
} else if changed, _ := c.compareAnnotations(pod.Annotations, deployment.Spec.Template.Annotations, nil); changed {
1122+
metadataReq := map[string]map[string]map[string]*string{"metadata": {}}
1123+
1124+
for anno, val := range deployment.Spec.Template.Annotations {
1125+
updatedPodAnnotations[anno] = &val
1126+
}
1127+
metadataReq["metadata"]["annotations"] = updatedPodAnnotations
1128+
patch, err := json.Marshal(metadataReq)
11031129
if err != nil {
1104-
return nil, fmt.Errorf("could not form patch for pooler's pod annotations: %v", err)
1130+
return nil, fmt.Errorf("could not marshal ObjectMeta for %s connection pooler's pods: %v", role, err)
11051131
}
1106-
_, err = c.KubeClient.Pods(pod.Namespace).Patch(context.TODO(), pod.Name, types.MergePatchType, []byte(patchData), metav1.PatchOptions{})
1132+
_, err = c.KubeClient.Pods(pod.Namespace).Patch(context.TODO(), pod.Name, types.StrategicMergePatchType, patch, metav1.PatchOptions{})
11071133
if err != nil {
1108-
return nil, fmt.Errorf("could not patch annotations for pooler's pod %q: %v", pod.Name, err)
1134+
return nil, fmt.Errorf("could not patch annotations for %s connection pooler's pod %q: %v", role, pod.Name, err)
11091135
}
11101136
}
11111137
}

pkg/cluster/resources.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ func (c *Cluster) updateService(role PostgresRole, oldService *v1.Service, newSe
329329
}
330330
}
331331

332-
if changed, _ := c.compareAnnotations(oldService.Annotations, newService.Annotations); changed {
332+
if changed, _ := c.compareAnnotations(oldService.Annotations, newService.Annotations, nil); changed {
333333
patchData, err := metaAnnotationsPatch(newService.Annotations)
334334
if err != nil {
335335
return nil, fmt.Errorf("could not form patch for service %q annotations: %v", oldService.Name, err)

pkg/cluster/streams.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ func (c *Cluster) compareStreams(curEventStreams, newEventStreams *zalandov1.Fab
545545
for newKey, newValue := range newEventStreams.Annotations {
546546
desiredAnnotations[newKey] = newValue
547547
}
548-
if changed, reason := c.compareAnnotations(curEventStreams.ObjectMeta.Annotations, desiredAnnotations); changed {
548+
if changed, reason := c.compareAnnotations(curEventStreams.ObjectMeta.Annotations, desiredAnnotations, nil); changed {
549549
match = false
550550
reasons = append(reasons, fmt.Sprintf("new streams annotations do not match: %s", reason))
551551
}

0 commit comments

Comments
 (0)