mirror of
https://github.com/zalando/postgres-operator.git
synced 2026-09-30 08:51:59 +02:00
Fix deletion timestamp handling for clusters with finalizers (#3015)
When a Postgres cluster has a finalizer, deleting it sets a DeletionTimestamp but doesn't remove the object until the finalizer is cleared. The operator was not properly handling these DeletionTimestamp changes: 1. postgresqlUpdate() was filtering out events where only DeletionTimestamp changed (it only checked Spec and Annotations), causing the delete to never be processed. 2. EventUpdate case in processEvent() didn't check for DeletionTimestamp, so even if the event reached the processor, it would run Update() instead of Delete(). 3. removeFinalizer() used a cached object with stale resourceVersion, causing "object has been modified" errors. Fixes: - Add explicit DeletionTimestamp check in postgresqlUpdate() to queue the event - Add DeletionTimestamp check in EventUpdate to call Delete() when set - Fetch latest object from API before removing finalizer to avoid conflicts Co-authored-by: Felix Kunde <felix-kunde@gmx.de>
This commit is contained in:
@@ -277,7 +277,7 @@ func (c *Controller) initRoleBinding() {
|
||||
}`, c.PodServiceAccount.Name, c.PodServiceAccount.Name, c.PodServiceAccount.Name)
|
||||
c.opConfig.PodServiceAccountRoleBindingDefinition = compactValue(stringValue)
|
||||
}
|
||||
c.logger.Info("Parse role bindings")
|
||||
|
||||
// re-uses k8s internal parsing. See k8s client-go issue #193 for explanation
|
||||
decode := scheme.Codecs.UniversalDeserializer().Decode
|
||||
obj, groupVersionKind, err := decode([]byte(c.opConfig.PodServiceAccountRoleBindingDefinition), nil, nil)
|
||||
|
||||
@@ -259,13 +259,26 @@ func (c *Controller) processEvent(event ClusterEvent) {
|
||||
|
||||
lg.Infoln("cluster has been created")
|
||||
case EventUpdate:
|
||||
lg.Infoln("update of the cluster started")
|
||||
|
||||
if !clusterFound {
|
||||
lg.Warningln("cluster does not exist")
|
||||
return
|
||||
}
|
||||
c.curWorkerCluster.Store(event.WorkerID, cl)
|
||||
|
||||
// Check if this cluster has been marked for deletion
|
||||
if !event.NewSpec.ObjectMeta.DeletionTimestamp.IsZero() {
|
||||
lg.Infof("cluster has a DeletionTimestamp of %s, starting deletion now.", event.NewSpec.ObjectMeta.DeletionTimestamp.Format(time.RFC3339))
|
||||
if err = cl.Delete(); err != nil {
|
||||
cl.Error = fmt.Sprintf("error deleting cluster and its resources: %v", err)
|
||||
c.eventRecorder.Eventf(cl.GetReference(), v1.EventTypeWarning, "Delete", "%v", cl.Error)
|
||||
lg.Error(cl.Error)
|
||||
return
|
||||
}
|
||||
lg.Infoln("cluster has been deleted via update event")
|
||||
return
|
||||
}
|
||||
|
||||
lg.Infoln("update of the cluster started")
|
||||
err = cl.Update(event.OldSpec, event.NewSpec)
|
||||
if err != nil {
|
||||
cl.Error = fmt.Sprintf("could not update cluster: %v", err)
|
||||
@@ -380,7 +393,6 @@ func (c *Controller) processClusterEventsQueue(idx int, stopCh <-chan struct{},
|
||||
}
|
||||
|
||||
func (c *Controller) warnOnDeprecatedPostgreSQLSpecParameters(spec *acidv1.PostgresSpec) {
|
||||
|
||||
deprecate := func(deprecated, replacement string) {
|
||||
c.logger.Warningf("parameter %q is deprecated. Consider setting %q instead", deprecated, replacement)
|
||||
}
|
||||
@@ -426,7 +438,7 @@ func (c *Controller) queueClusterEvent(informerOldSpec, informerNewSpec *acidv1.
|
||||
clusterError string
|
||||
)
|
||||
|
||||
if informerOldSpec != nil { //update, delete
|
||||
if informerOldSpec != nil { // update, delete
|
||||
uid = informerOldSpec.GetUID()
|
||||
clusterName = util.NameFromMeta(informerOldSpec.ObjectMeta)
|
||||
|
||||
@@ -441,7 +453,7 @@ func (c *Controller) queueClusterEvent(informerOldSpec, informerNewSpec *acidv1.
|
||||
} else {
|
||||
clusterError = informerOldSpec.Error
|
||||
}
|
||||
} else { //add, sync
|
||||
} else { // add, sync
|
||||
uid = informerNewSpec.GetUID()
|
||||
clusterName = util.NameFromMeta(informerNewSpec.ObjectMeta)
|
||||
clusterError = informerNewSpec.Error
|
||||
@@ -552,7 +564,19 @@ func (c *Controller) postgresqlUpdate(prev, cur interface{}) {
|
||||
pgOld := c.postgresqlCheck(prev)
|
||||
pgNew := c.postgresqlCheck(cur)
|
||||
if pgOld != nil && pgNew != nil {
|
||||
// Avoid the inifinite recursion for status updates
|
||||
clusterName := util.NameFromMeta(pgNew.ObjectMeta)
|
||||
|
||||
// Check if DeletionTimestamp was set (resource marked for deletion)
|
||||
deletionTimestampChanged := pgOld.ObjectMeta.DeletionTimestamp.IsZero() && !pgNew.ObjectMeta.DeletionTimestamp.IsZero()
|
||||
if deletionTimestampChanged {
|
||||
c.logger.WithField("cluster-name", clusterName).Infof(
|
||||
"UPDATE event: DeletionTimestamp set to %s, queueing event",
|
||||
pgNew.ObjectMeta.DeletionTimestamp.Format(time.RFC3339))
|
||||
c.queueClusterEvent(pgOld, pgNew, EventUpdate)
|
||||
return
|
||||
}
|
||||
|
||||
// Avoid the infinite recursion for status updates
|
||||
if reflect.DeepEqual(pgOld.Spec, pgNew.Spec) {
|
||||
if reflect.DeepEqual(pgNew.Annotations, pgOld.Annotations) {
|
||||
return
|
||||
@@ -591,7 +615,6 @@ or config maps.
|
||||
The operator does not sync accounts/role bindings after creation.
|
||||
*/
|
||||
func (c *Controller) submitRBACCredentials(event ClusterEvent) error {
|
||||
|
||||
namespace := event.NewSpec.GetNamespace()
|
||||
|
||||
if err := c.createPodServiceAccount(namespace); err != nil {
|
||||
@@ -605,7 +628,6 @@ func (c *Controller) submitRBACCredentials(event ClusterEvent) error {
|
||||
}
|
||||
|
||||
func (c *Controller) createPodServiceAccount(namespace string) error {
|
||||
|
||||
podServiceAccountName := c.opConfig.PodServiceAccountName
|
||||
_, err := c.KubeClient.ServiceAccounts(namespace).Get(context.TODO(), podServiceAccountName, metav1.GetOptions{})
|
||||
if k8sutil.ResourceNotFound(err) {
|
||||
@@ -628,7 +650,6 @@ func (c *Controller) createPodServiceAccount(namespace string) error {
|
||||
}
|
||||
|
||||
func (c *Controller) createRoleBindings(namespace string) error {
|
||||
|
||||
podServiceAccountName := c.opConfig.PodServiceAccountName
|
||||
podServiceAccountRoleBindingName := c.PodServiceAccountRoleBinding.Name
|
||||
|
||||
|
||||
Reference in New Issue
Block a user