Use finalizers to avoid losing delete events and to ensure full resource cleanup (#941)

* Add Finalizer functions to Cluster; add/remove finalizer on Create/Delete events
* Check if clusters have a deletion timestamp and we missed that event. Run Delete() and remove finalizer when done.
* Fix nil handling when using Service from map; Remove Service, Endpoint entries from their maps - just like with Secrets
* Add handling of ResourceNotFound to all delete functions (Service, Endpoint, LogicalBackup CronJob, PDB and Secret) - this is not a real error when deleting things
* Emit events when there are issues deleting resources to the user is informed
* Depend the removal of the Finalizer on all resources being deleted successfully first. Otherwise the next sync run should let us try again
* Add config option to enable finalizers
* Removed dangling whitespace at EOL
* config.EnableFinalizers is a bool pointer

---------

Co-authored-by: Felix Kunde <felix-kunde@gmx.de>
This commit is contained in:
Christian Rohmann
2024-01-04 16:22:53 +01:00
committed by GitHub
co-authored by Felix Kunde
parent 9581ba969b
commit 743aade45f
8 changed files with 201 additions and 30 deletions
+36 -16
View File
@@ -247,9 +247,12 @@ func (c *Cluster) deleteStatefulSet() error {
}
err := c.KubeClient.StatefulSets(c.Statefulset.Namespace).Delete(context.TODO(), c.Statefulset.Name, c.deleteOptions)
if err != nil {
if k8sutil.ResourceNotFound(err) {
c.logger.Debugf("StatefulSet was already deleted")
} else if err != nil {
return err
}
c.logger.Infof("statefulset %q has been deleted", util.NameFromMeta(c.Statefulset.ObjectMeta))
c.Statefulset = nil
@@ -336,18 +339,21 @@ func (c *Cluster) updateService(role PostgresRole, oldService *v1.Service, newSe
func (c *Cluster) deleteService(role PostgresRole) error {
c.logger.Debugf("deleting service %s", role)
service, ok := c.Services[role]
if !ok {
if c.Services[role] == nil {
c.logger.Debugf("No service for %s role was found, nothing to delete", role)
return nil
}
if err := c.KubeClient.Services(service.Namespace).Delete(context.TODO(), service.Name, c.deleteOptions); err != nil {
return err
if err := c.KubeClient.Services(c.Services[role].Namespace).Delete(context.TODO(), c.Services[role].Name, c.deleteOptions); err != nil {
if k8sutil.ResourceNotFound(err) {
c.logger.Debugf("Service was already deleted")
} else if err != nil {
return err
}
}
c.logger.Infof("%s service %q has been deleted", role, util.NameFromMeta(service.ObjectMeta))
c.Services[role] = nil
c.logger.Infof("%s service %q has been deleted", role, util.NameFromMeta(c.Services[role].ObjectMeta))
delete(c.Services, role)
return nil
}
@@ -448,9 +454,12 @@ func (c *Cluster) deletePodDisruptionBudget() error {
err := c.KubeClient.
PodDisruptionBudgets(c.PodDisruptionBudget.Namespace).
Delete(context.TODO(), c.PodDisruptionBudget.Name, c.deleteOptions)
if err != nil {
return fmt.Errorf("could not delete pod disruption budget: %v", err)
if k8sutil.ResourceNotFound(err) {
c.logger.Debugf("PodDisruptionBudget was already deleted")
} else if err != nil {
return fmt.Errorf("could not delete PodDisruptionBudget: %v", err)
}
c.logger.Infof("pod disruption budget %q has been deleted", util.NameFromMeta(c.PodDisruptionBudget.ObjectMeta))
c.PodDisruptionBudget = nil
@@ -479,14 +488,16 @@ func (c *Cluster) deleteEndpoint(role PostgresRole) error {
return fmt.Errorf("there is no %s endpoint in the cluster", role)
}
if err := c.KubeClient.Endpoints(c.Endpoints[role].Namespace).Delete(
context.TODO(), c.Endpoints[role].Name, c.deleteOptions); err != nil {
return fmt.Errorf("could not delete endpoint: %v", err)
if err := c.KubeClient.Endpoints(c.Endpoints[role].Namespace).Delete(context.TODO(), c.Endpoints[role].Name, c.deleteOptions); err != nil {
if k8sutil.ResourceNotFound(err) {
c.logger.Debugf("Endpoint was already deleted")
} else if err != nil {
return fmt.Errorf("could not delete endpoint: %v", err)
}
}
c.logger.Infof("endpoint %q has been deleted", util.NameFromMeta(c.Endpoints[role].ObjectMeta))
c.Endpoints[role] = nil
delete(c.Endpoints, role)
return nil
}
@@ -514,7 +525,9 @@ func (c *Cluster) deleteSecret(uid types.UID, secret v1.Secret) error {
secretName := util.NameFromMeta(secret.ObjectMeta)
c.logger.Debugf("deleting secret %q", secretName)
err := c.KubeClient.Secrets(secret.Namespace).Delete(context.TODO(), secret.Name, c.deleteOptions)
if err != nil {
if k8sutil.ResourceNotFound(err) {
c.logger.Debugf("Secret was already deleted")
} else if err != nil {
return fmt.Errorf("could not delete secret %q: %v", secretName, err)
}
c.logger.Infof("secret %q has been deleted", secretName)
@@ -573,7 +586,14 @@ func (c *Cluster) deleteLogicalBackupJob() error {
c.logger.Info("removing the logical backup job")
return c.KubeClient.CronJobsGetter.CronJobs(c.Namespace).Delete(context.TODO(), c.getLogicalBackupJobName(), c.deleteOptions)
err := c.KubeClient.CronJobsGetter.CronJobs(c.Namespace).Delete(context.TODO(), c.getLogicalBackupJobName(), c.deleteOptions)
if k8sutil.ResourceNotFound(err) {
c.logger.Debugf("LogicalBackup CronJob was already deleted")
} else if err != nil {
return err
}
return nil
}
// GetServiceMaster returns cluster's kubernetes master Service