Skip to content

Commit c4aab50

Browse files
Remove Patroni leftover objects on cluster deletion. (zalando#244)
* Remove all endpoints and configmaps from Patroni when Patroni is running with Kubernetes support on cluster deletion.
1 parent 6a29bbb commit c4aab50

File tree

3 files changed

+83
-4
lines changed

3 files changed

+83
-4
lines changed

pkg/cluster/cluster.go

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@ import (
3131
)
3232

3333
var (
34-
alphaNumericRegexp = regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9]*$")
35-
databaseNameRegexp = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$")
36-
userRegexp = regexp.MustCompile(`^[a-z0-9]([-_a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-_a-z0-9]*[a-z0-9])?)*$`)
34+
alphaNumericRegexp = regexp.MustCompile("^[a-zA-Z][a-zA-Z0-9]*$")
35+
databaseNameRegexp = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9_]*$")
36+
userRegexp = regexp.MustCompile(`^[a-z0-9]([-_a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-_a-z0-9]*[a-z0-9])?)*$`)
37+
patroniObjectSuffixes = []string{"config", "failover", "sync"}
3738
)
3839

3940
// Config contains operator-wide clients and configuration used from a cluster. TODO: remove struct duplication.
@@ -581,6 +582,10 @@ func (c *Cluster) Delete() error {
581582
}
582583
}
583584

585+
if err := c.deletePatroniClusterObjects(); err != nil {
586+
return fmt.Errorf("could not remove leftover patroni objects; %v", err)
587+
}
588+
584589
return nil
585590
}
586591

@@ -817,3 +822,73 @@ func (c *Cluster) shouldDeleteSecret(secret *v1.Secret) (delete bool, userName s
817822
secretUser := string(secret.Data["username"])
818823
return (secretUser != c.OpConfig.ReplicationUsername && secretUser != c.OpConfig.SuperUsername), secretUser
819824
}
825+
826+
type simpleActionWithResult func() error
827+
828+
type ClusterObjectGet func(name string) (spec.NamespacedName, error)
829+
830+
type ClusterObjectDelete func(name string) error
831+
832+
func (c *Cluster) deletePatroniClusterObjects() error {
833+
// TODO: figure out how to remove leftover patroni objects in other cases
834+
if !c.patroniUsesKubernetes() {
835+
c.logger.Infof("not cleaning up Etcd Patroni objects on cluster delete")
836+
}
837+
c.logger.Debugf("removing leftover Patroni objects (endpoints or configmaps)")
838+
for _, deleter := range []simpleActionWithResult{c.deletePatroniClusterEndpoints, c.deletePatroniClusterConfigMaps} {
839+
if err := deleter(); err != nil {
840+
return err
841+
}
842+
}
843+
return nil
844+
}
845+
846+
func (c *Cluster) deleteClusterObject(
847+
get ClusterObjectGet,
848+
del ClusterObjectDelete,
849+
objType string) error {
850+
for _, suffix := range patroniObjectSuffixes {
851+
name := fmt.Sprintf("%s-%s", c.Name, suffix)
852+
853+
if namespacedName, err := get(name); err == nil {
854+
c.logger.Debugf("deleting Patroni cluster object %q with name %q",
855+
objType, namespacedName)
856+
857+
if err = del(name); err != nil {
858+
return fmt.Errorf("could not Patroni delete cluster object %q with name %q: %v",
859+
objType, namespacedName, err)
860+
}
861+
862+
} else if !k8sutil.ResourceNotFound(err) {
863+
return fmt.Errorf("could not fetch Patroni Endpoint %q: %v",
864+
namespacedName, err)
865+
}
866+
}
867+
return nil
868+
}
869+
870+
func (c *Cluster) deletePatroniClusterEndpoints() error {
871+
get := func(name string) (spec.NamespacedName, error) {
872+
ep, err := c.KubeClient.Endpoints(c.Namespace).Get(name, metav1.GetOptions{})
873+
return util.NameFromMeta(ep.ObjectMeta), err
874+
}
875+
876+
delete := func(name string) error {
877+
return c.KubeClient.Endpoints(c.Namespace).Delete(name, c.deleteOptions)
878+
}
879+
880+
return c.deleteClusterObject(get, delete, "endpoint")
881+
}
882+
883+
func (c *Cluster) deletePatroniClusterConfigMaps() error {
884+
get := func(name string) (spec.NamespacedName, error) {
885+
cm, err := c.KubeClient.ConfigMaps(c.Namespace).Get(name, metav1.GetOptions{})
886+
return util.NameFromMeta(cm.ObjectMeta), err
887+
}
888+
889+
delete := func(name string) error {
890+
return c.KubeClient.ConfigMaps(c.Namespace).Delete(name, c.deleteOptions)
891+
}
892+
893+
return c.deleteClusterObject(get, delete, "configmap")
894+
}

pkg/cluster/k8sres.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ func (c *Cluster) generatePodTemplate(
363363
envVars = append(envVars, v1.EnvVar{Name: "WAL_BUCKET_SCOPE_SUFFIX", Value: getWALBucketScopeSuffix(string(uid))})
364364
}
365365

366-
if c.OpConfig.EtcdHost == "" {
366+
if c.patroniUsesKubernetes() {
367367
envVars = append(envVars, v1.EnvVar{Name: "DCS_ENABLE_KUBERNETES_API", Value: "true"})
368368
} else {
369369
envVars = append(envVars, v1.EnvVar{Name: "ETCD_HOST", Value: c.OpConfig.EtcdHost})

pkg/cluster/util.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,3 +414,7 @@ func (c *Cluster) GetSpec() (*spec.Postgresql, error) {
414414
defer c.specMu.RUnlock()
415415
return cloneSpec(&c.Postgresql)
416416
}
417+
418+
func (c *Cluster) patroniUsesKubernetes() bool {
419+
return c.OpConfig.EtcdHost == ""
420+
}

0 commit comments

Comments
 (0)