mirror of
https://github.com/zalando/postgres-operator.git
synced 2026-09-30 19:02:57 +02:00
allow delete only if annotations meet configured criteria (#1069)
* define annotations for delete protection * change log level and reduce log lines for e2e tests * reduce wait_for_pod_start even further
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
|
||||
@@ -454,6 +455,37 @@ func (c *Controller) GetReference(postgresql *acidv1.Postgresql) *v1.ObjectRefer
|
||||
return ref
|
||||
}
|
||||
|
||||
func (c *Controller) meetsClusterDeleteAnnotations(postgresql *acidv1.Postgresql) error {
|
||||
|
||||
deleteAnnotationDateKey := c.opConfig.DeleteAnnotationDateKey
|
||||
currentTime := time.Now()
|
||||
currentDate := currentTime.Format("2006-01-02") // go's reference date
|
||||
|
||||
if deleteAnnotationDateKey != "" {
|
||||
if deleteDate, ok := postgresql.Annotations[deleteAnnotationDateKey]; ok {
|
||||
if deleteDate != currentDate {
|
||||
return fmt.Errorf("annotation %s not matching the current date: got %s, expected %s", deleteAnnotationDateKey, deleteDate, currentDate)
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("annotation %s not set in manifest to allow cluster deletion", deleteAnnotationDateKey)
|
||||
}
|
||||
}
|
||||
|
||||
deleteAnnotationNameKey := c.opConfig.DeleteAnnotationNameKey
|
||||
|
||||
if deleteAnnotationNameKey != "" {
|
||||
if clusterName, ok := postgresql.Annotations[deleteAnnotationNameKey]; ok {
|
||||
if clusterName != postgresql.Name {
|
||||
return fmt.Errorf("annotation %s not matching the cluster name: got %s, expected %s", deleteAnnotationNameKey, clusterName, postgresql.Name)
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("annotation %s not set in manifest to allow cluster deletion", deleteAnnotationNameKey)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// hasOwnership returns true if the controller is the "owner" of the postgresql.
|
||||
// Whether it's owner is determined by the value of 'acid.zalan.do/controller'
|
||||
// annotation. If the value matches the controllerID then it owns it, or if the
|
||||
|
||||
@@ -92,6 +92,8 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
|
||||
result.InheritedLabels = fromCRD.Kubernetes.InheritedLabels
|
||||
result.DownscalerAnnotations = fromCRD.Kubernetes.DownscalerAnnotations
|
||||
result.ClusterNameLabel = util.Coalesce(fromCRD.Kubernetes.ClusterNameLabel, "cluster-name")
|
||||
result.DeleteAnnotationDateKey = fromCRD.Kubernetes.DeleteAnnotationDateKey
|
||||
result.DeleteAnnotationNameKey = fromCRD.Kubernetes.DeleteAnnotationNameKey
|
||||
result.NodeReadinessLabel = fromCRD.Kubernetes.NodeReadinessLabel
|
||||
result.PodPriorityClassName = fromCRD.Kubernetes.PodPriorityClassName
|
||||
result.PodManagementPolicy = util.Coalesce(fromCRD.Kubernetes.PodManagementPolicy, "ordered_ready")
|
||||
|
||||
@@ -2,6 +2,7 @@ package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
@@ -420,6 +421,22 @@ func (c *Controller) queueClusterEvent(informerOldSpec, informerNewSpec *acidv1.
|
||||
clusterError = informerNewSpec.Error
|
||||
}
|
||||
|
||||
// only allow deletion if delete annotations are set and conditions are met
|
||||
if eventType == EventDelete {
|
||||
if err := c.meetsClusterDeleteAnnotations(informerOldSpec); err != nil {
|
||||
c.logger.WithField("cluster-name", clusterName).Warnf(
|
||||
"ignoring %q event for cluster %q - manifest does not fulfill delete requirements: %s", eventType, clusterName, err)
|
||||
c.logger.WithField("cluster-name", clusterName).Warnf(
|
||||
"please, recreate Postgresql resource %q and set annotations to delete properly", clusterName)
|
||||
if currentManifest, marshalErr := json.Marshal(informerOldSpec); marshalErr != nil {
|
||||
c.logger.WithField("cluster-name", clusterName).Warnf("could not marshal current manifest:\n%+v", informerOldSpec)
|
||||
} else {
|
||||
c.logger.WithField("cluster-name", clusterName).Warnf("%s\n", string(currentManifest))
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if clusterError != "" && eventType != EventDelete {
|
||||
c.logger.WithField("cluster-name", clusterName).Debugf("skipping %q event for the invalid cluster: %s", eventType, clusterError)
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
|
||||
"github.com/zalando/postgres-operator/pkg/spec"
|
||||
@@ -90,3 +92,88 @@ func TestMergeDeprecatedPostgreSQLSpecParameters(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMeetsClusterDeleteAnnotations(t *testing.T) {
|
||||
// set delete annotations in configuration
|
||||
postgresqlTestController.opConfig.DeleteAnnotationDateKey = "delete-date"
|
||||
postgresqlTestController.opConfig.DeleteAnnotationNameKey = "delete-clustername"
|
||||
|
||||
currentTime := time.Now()
|
||||
today := currentTime.Format("2006-01-02") // go's reference date
|
||||
clusterName := "acid-test-cluster"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
pg *acidv1.Postgresql
|
||||
error string
|
||||
}{
|
||||
{
|
||||
"Postgres cluster with matching delete annotations",
|
||||
&acidv1.Postgresql{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: clusterName,
|
||||
Annotations: map[string]string{
|
||||
"delete-date": today,
|
||||
"delete-clustername": clusterName,
|
||||
},
|
||||
},
|
||||
},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"Postgres cluster with violated delete date annotation",
|
||||
&acidv1.Postgresql{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: clusterName,
|
||||
Annotations: map[string]string{
|
||||
"delete-date": "2020-02-02",
|
||||
"delete-clustername": clusterName,
|
||||
},
|
||||
},
|
||||
},
|
||||
fmt.Sprintf("annotation delete-date not matching the current date: got 2020-02-02, expected %s", today),
|
||||
},
|
||||
{
|
||||
"Postgres cluster with violated delete cluster name annotation",
|
||||
&acidv1.Postgresql{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: clusterName,
|
||||
Annotations: map[string]string{
|
||||
"delete-date": today,
|
||||
"delete-clustername": "acid-minimal-cluster",
|
||||
},
|
||||
},
|
||||
},
|
||||
fmt.Sprintf("annotation delete-clustername not matching the cluster name: got acid-minimal-cluster, expected %s", clusterName),
|
||||
},
|
||||
{
|
||||
"Postgres cluster with missing delete annotations",
|
||||
&acidv1.Postgresql{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: clusterName,
|
||||
Annotations: map[string]string{},
|
||||
},
|
||||
},
|
||||
"annotation delete-date not set in manifest to allow cluster deletion",
|
||||
},
|
||||
{
|
||||
"Postgres cluster with missing delete cluster name annotation",
|
||||
&acidv1.Postgresql{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: clusterName,
|
||||
Annotations: map[string]string{
|
||||
"delete-date": today,
|
||||
},
|
||||
},
|
||||
},
|
||||
"annotation delete-clustername not set in manifest to allow cluster deletion",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
if err := postgresqlTestController.meetsClusterDeleteAnnotations(tt.pg); err != nil {
|
||||
if !reflect.DeepEqual(err.Error(), tt.error) {
|
||||
t.Errorf("Expected error %q, got: %v", tt.error, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user