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:
Felix Kunde
2020-08-13 16:36:22 +02:00
committed by GitHub
parent 0d81f972a1
commit 3ddc56e5b9
18 changed files with 343 additions and 19 deletions
+32
View File
@@ -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
+2
View File
@@ -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")
+17
View File
@@ -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)
+87
View File
@@ -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)
}
}
}
}