merge with master

This commit is contained in:
Felix Kunde 2020-05-04 14:48:43 +02:00
commit a73e89e8b5
20 changed files with 205 additions and 31 deletions

View File

@ -117,6 +117,10 @@ spec:
type: object type: object
additionalProperties: additionalProperties:
type: string type: string
downscaler_annotations:
type: array
items:
type: string
enable_init_containers: enable_init_containers:
type: boolean type: boolean
enable_pod_antiaffinity: enable_pod_antiaffinity:

View File

@ -67,6 +67,11 @@ configKubernetes:
# keya: valuea # keya: valuea
# keyb: valueb # keyb: valueb
# list of annotations propagated from cluster manifest to statefulset and deployment
# downscaler_annotations:
# - deployment-time
# - downscaler/*
# enables initContainers to run actions before Spilo is started # enables initContainers to run actions before Spilo is started
enable_init_containers: true enable_init_containers: true
# toggles pod anti affinity on the Postgres pods # toggles pod anti affinity on the Postgres pods
@ -262,11 +267,11 @@ configConnectionPooler:
# docker image # docker image
connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer" connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer"
# max db connections the pooler should hold # max db connections the pooler should hold
connection_pooler_max_db_connections: "60" connection_pooler_max_db_connections: 60
# default pooling mode # default pooling mode
connection_pooler_mode: "transaction" connection_pooler_mode: "transaction"
# number of pooler instances # number of pooler instances
connection_pooler_number_of_instances: "2" connection_pooler_number_of_instances: 2
# default resources # default resources
connection_pooler_default_cpu_request: 500m connection_pooler_default_cpu_request: 500m
connection_pooler_default_memory_request: 100Mi connection_pooler_default_memory_request: 100Mi

View File

@ -63,6 +63,9 @@ configKubernetes:
# annotations attached to each database pod # annotations attached to each database pod
# custom_pod_annotations: "keya:valuea,keyb:valueb" # custom_pod_annotations: "keya:valuea,keyb:valueb"
# list of annotations propagated from cluster manifest to statefulset and deployment
# downscaler_annotations: "deployment-time,downscaler/*"
# enables initContainers to run actions before Spilo is started # enables initContainers to run actions before Spilo is started
enable_init_containers: "true" enable_init_containers: "true"
# toggles pod anti affinity on the Postgres pods # toggles pod anti affinity on the Postgres pods

View File

@ -200,6 +200,12 @@ configuration they are grouped under the `kubernetes` key.
of a database created by the operator. If the annotation key is also provided of a database created by the operator. If the annotation key is also provided
by the database definition, the database definition value is used. by the database definition, the database definition value is used.
* **downscaler_annotations**
An array of annotations that should be passed from Postgres CRD on to the
statefulset and, if exists, to the connection pooler deployment as well.
Regular expressions like `downscaler/*` etc. are also accepted. Can be used
with [kube-downscaler](https://github.com/hjacobs/kube-downscaler).
* **watched_namespace** * **watched_namespace**
The operator watches for Postgres objects in the given namespace. If not The operator watches for Postgres objects in the given namespace. If not
specified, the value is taken from the operator namespace. A special `*` specified, the value is taken from the operator namespace. A special `*`

View File

@ -428,7 +428,7 @@ class EndToEndTestCase(unittest.TestCase):
k8s.api.core_v1.patch_node(current_master_node, patch_readiness_label) k8s.api.core_v1.patch_node(current_master_node, patch_readiness_label)
# wait a little before proceeding with the pod distribution test # wait a little before proceeding with the pod distribution test
time.sleep(k8s.RETRY_TIMEOUT_SEC) time.sleep(30)
# toggle pod anti affinity to move replica away from master node # toggle pod anti affinity to move replica away from master node
self.assert_distributed_pods(new_master_node, new_replica_nodes, cluster_label) self.assert_distributed_pods(new_master_node, new_replica_nodes, cluster_label)
@ -465,21 +465,24 @@ class EndToEndTestCase(unittest.TestCase):
pg_patch_custom_annotations = { pg_patch_custom_annotations = {
"spec": { "spec": {
"serviceAnnotations": { "serviceAnnotations": {
"annotation.key": "value" "annotation.key": "value",
"foo": "bar",
} }
} }
} }
k8s.api.custom_objects_api.patch_namespaced_custom_object( k8s.api.custom_objects_api.patch_namespaced_custom_object(
"acid.zalan.do", "v1", "default", "postgresqls", "acid-minimal-cluster", pg_patch_custom_annotations) "acid.zalan.do", "v1", "default", "postgresqls", "acid-minimal-cluster", pg_patch_custom_annotations)
# wait a little before proceeding
time.sleep(30)
annotations = { annotations = {
"annotation.key": "value", "annotation.key": "value",
"foo": "bar", "foo": "bar",
} }
self.assertTrue(k8s.check_service_annotations( self.assertTrue(k8s.check_service_annotations(
"cluster-name=acid-service-annotations,spilo-role=master", annotations)) "cluster-name=acid-minimal-cluster,spilo-role=master", annotations))
self.assertTrue(k8s.check_service_annotations( self.assertTrue(k8s.check_service_annotations(
"cluster-name=acid-service-annotations,spilo-role=replica", annotations)) "cluster-name=acid-minimal-cluster,spilo-role=replica", annotations))
# clean up # clean up
unpatch_custom_service_annotations = { unpatch_custom_service_annotations = {
@ -489,6 +492,40 @@ class EndToEndTestCase(unittest.TestCase):
} }
k8s.update_config(unpatch_custom_service_annotations) k8s.update_config(unpatch_custom_service_annotations)
@timeout_decorator.timeout(TEST_TIMEOUT_SEC)
def test_statefulset_annotation_propagation(self):
'''
Inject annotation to Postgresql CRD and check it's propagation to stateful set
'''
k8s = self.k8s
cluster_label = 'application=spilo,cluster-name=acid-minimal-cluster'
patch_sset_propagate_annotations = {
"data": {
"downscaler_annotations": "deployment-time,downscaler/*",
}
}
k8s.update_config(patch_sset_propagate_annotations)
pg_crd_annotations = {
"metadata": {
"annotations": {
"deployment-time": "2020-04-30 12:00:00",
"downscaler/downtime_replicas": "0",
},
}
}
k8s.api.custom_objects_api.patch_namespaced_custom_object(
"acid.zalan.do", "v1", "default", "postgresqls", "acid-minimal-cluster", pg_crd_annotations)
# wait a little before proceeding
time.sleep(60)
annotations = {
"deployment-time": "2020-04-30 12:00:00",
"downscaler/downtime_replicas": "0",
}
self.assertTrue(k8s.check_statefulset_annotations(cluster_label, annotations))
@timeout_decorator.timeout(TEST_TIMEOUT_SEC) @timeout_decorator.timeout(TEST_TIMEOUT_SEC)
def test_taint_based_eviction(self): def test_taint_based_eviction(self):
''' '''
@ -528,7 +565,7 @@ class EndToEndTestCase(unittest.TestCase):
k8s.update_config(patch_toleration_config) k8s.update_config(patch_toleration_config)
# wait a little before proceeding with the pod distribution test # wait a little before proceeding with the pod distribution test
time.sleep(k8s.RETRY_TIMEOUT_SEC) time.sleep(30)
# toggle pod anti affinity to move replica away from master node # toggle pod anti affinity to move replica away from master node
self.assert_distributed_pods(new_master_node, new_replica_nodes, cluster_label) self.assert_distributed_pods(new_master_node, new_replica_nodes, cluster_label)
@ -694,10 +731,18 @@ class K8s:
def check_service_annotations(self, svc_labels, annotations, namespace='default'): def check_service_annotations(self, svc_labels, annotations, namespace='default'):
svcs = self.api.core_v1.list_namespaced_service(namespace, label_selector=svc_labels, limit=1).items svcs = self.api.core_v1.list_namespaced_service(namespace, label_selector=svc_labels, limit=1).items
for svc in svcs: for svc in svcs:
if len(svc.metadata.annotations) != len(annotations): for key, value in annotations.items():
return False if key not in svc.metadata.annotations or svc.metadata.annotations[key] != value:
for key in svc.metadata.annotations: print("Expected key {} not found in annotations {}".format(key, svc.metadata.annotation))
if svc.metadata.annotations[key] != annotations[key]: return False
return True
def check_statefulset_annotations(self, sset_labels, annotations, namespace='default'):
ssets = self.api.apps_v1.list_namespaced_stateful_set(namespace, label_selector=sset_labels, limit=1).items
for sset in ssets:
for key, value in annotations.items():
if key not in sset.metadata.annotations or sset.metadata.annotations[key] != value:
print("Expected key {} not found in annotations {}".format(key, sset.metadata.annotation))
return False return False
return True return True

View File

@ -30,6 +30,7 @@ data:
# default_memory_limit: 500Mi # default_memory_limit: 500Mi
# default_memory_request: 100Mi # default_memory_request: 100Mi
docker_image: registry.opensource.zalan.do/acid/spilo-cdp-12:1.6-p115 docker_image: registry.opensource.zalan.do/acid/spilo-cdp-12:1.6-p115
# downscaler_annotations: "deployment-time,downscaler/*"
# enable_admin_role_for_users: "true" # enable_admin_role_for_users: "true"
# enable_crd_validation: "true" # enable_crd_validation: "true"
# enable_database_access: "true" # enable_database_access: "true"

View File

@ -93,6 +93,10 @@ spec:
type: object type: object
additionalProperties: additionalProperties:
type: string type: string
downscaler_annotations:
type: array
items:
type: string
enable_init_containers: enable_init_containers:
type: boolean type: boolean
enable_pod_antiaffinity: enable_pod_antiaffinity:

View File

@ -31,6 +31,9 @@ configuration:
# custom_pod_annotations: # custom_pod_annotations:
# keya: valuea # keya: valuea
# keyb: valueb # keyb: valueb
# downscaler_annotations:
# - deployment-time
# - downscaler/*
enable_init_containers: true enable_init_containers: true
enable_pod_antiaffinity: false enable_pod_antiaffinity: false
enable_pod_disruption_budget: true enable_pod_disruption_budget: true

View File

@ -21,48 +21,48 @@ const (
// PostgresCRDResourceColumns definition of AdditionalPrinterColumns for postgresql CRD // PostgresCRDResourceColumns definition of AdditionalPrinterColumns for postgresql CRD
var PostgresCRDResourceColumns = []apiextv1beta1.CustomResourceColumnDefinition{ var PostgresCRDResourceColumns = []apiextv1beta1.CustomResourceColumnDefinition{
apiextv1beta1.CustomResourceColumnDefinition{ {
Name: "Team", Name: "Team",
Type: "string", Type: "string",
Description: "Team responsible for Postgres cluster", Description: "Team responsible for Postgres cluster",
JSONPath: ".spec.teamId", JSONPath: ".spec.teamId",
}, },
apiextv1beta1.CustomResourceColumnDefinition{ {
Name: "Version", Name: "Version",
Type: "string", Type: "string",
Description: "PostgreSQL version", Description: "PostgreSQL version",
JSONPath: ".spec.postgresql.version", JSONPath: ".spec.postgresql.version",
}, },
apiextv1beta1.CustomResourceColumnDefinition{ {
Name: "Pods", Name: "Pods",
Type: "integer", Type: "integer",
Description: "Number of Pods per Postgres cluster", Description: "Number of Pods per Postgres cluster",
JSONPath: ".spec.numberOfInstances", JSONPath: ".spec.numberOfInstances",
}, },
apiextv1beta1.CustomResourceColumnDefinition{ {
Name: "Volume", Name: "Volume",
Type: "string", Type: "string",
Description: "Size of the bound volume", Description: "Size of the bound volume",
JSONPath: ".spec.volume.size", JSONPath: ".spec.volume.size",
}, },
apiextv1beta1.CustomResourceColumnDefinition{ {
Name: "CPU-Request", Name: "CPU-Request",
Type: "string", Type: "string",
Description: "Requested CPU for Postgres containers", Description: "Requested CPU for Postgres containers",
JSONPath: ".spec.resources.requests.cpu", JSONPath: ".spec.resources.requests.cpu",
}, },
apiextv1beta1.CustomResourceColumnDefinition{ {
Name: "Memory-Request", Name: "Memory-Request",
Type: "string", Type: "string",
Description: "Requested memory for Postgres containers", Description: "Requested memory for Postgres containers",
JSONPath: ".spec.resources.requests.memory", JSONPath: ".spec.resources.requests.memory",
}, },
apiextv1beta1.CustomResourceColumnDefinition{ {
Name: "Age", Name: "Age",
Type: "date", Type: "date",
JSONPath: ".metadata.creationTimestamp", JSONPath: ".metadata.creationTimestamp",
}, },
apiextv1beta1.CustomResourceColumnDefinition{ {
Name: "Status", Name: "Status",
Type: "string", Type: "string",
Description: "Current sync status of postgresql resource", Description: "Current sync status of postgresql resource",
@ -72,31 +72,31 @@ var PostgresCRDResourceColumns = []apiextv1beta1.CustomResourceColumnDefinition{
// OperatorConfigCRDResourceColumns definition of AdditionalPrinterColumns for OperatorConfiguration CRD // OperatorConfigCRDResourceColumns definition of AdditionalPrinterColumns for OperatorConfiguration CRD
var OperatorConfigCRDResourceColumns = []apiextv1beta1.CustomResourceColumnDefinition{ var OperatorConfigCRDResourceColumns = []apiextv1beta1.CustomResourceColumnDefinition{
apiextv1beta1.CustomResourceColumnDefinition{ {
Name: "Image", Name: "Image",
Type: "string", Type: "string",
Description: "Spilo image to be used for Pods", Description: "Spilo image to be used for Pods",
JSONPath: ".configuration.docker_image", JSONPath: ".configuration.docker_image",
}, },
apiextv1beta1.CustomResourceColumnDefinition{ {
Name: "Cluster-Label", Name: "Cluster-Label",
Type: "string", Type: "string",
Description: "Label for K8s resources created by operator", Description: "Label for K8s resources created by operator",
JSONPath: ".configuration.kubernetes.cluster_name_label", JSONPath: ".configuration.kubernetes.cluster_name_label",
}, },
apiextv1beta1.CustomResourceColumnDefinition{ {
Name: "Service-Account", Name: "Service-Account",
Type: "string", Type: "string",
Description: "Name of service account to be used", Description: "Name of service account to be used",
JSONPath: ".configuration.kubernetes.pod_service_account_name", JSONPath: ".configuration.kubernetes.pod_service_account_name",
}, },
apiextv1beta1.CustomResourceColumnDefinition{ {
Name: "Min-Instances", Name: "Min-Instances",
Type: "integer", Type: "integer",
Description: "Minimum number of instances per Postgres cluster", Description: "Minimum number of instances per Postgres cluster",
JSONPath: ".configuration.min_instances", JSONPath: ".configuration.min_instances",
}, },
apiextv1beta1.CustomResourceColumnDefinition{ {
Name: "Age", Name: "Age",
Type: "date", Type: "date",
JSONPath: ".metadata.creationTimestamp", JSONPath: ".metadata.creationTimestamp",
@ -888,6 +888,14 @@ var OperatorConfigCRDResourceValidation = apiextv1beta1.CustomResourceValidation
}, },
}, },
}, },
"downscaler_annotations": {
Type: "array",
Items: &apiextv1beta1.JSONSchemaPropsOrArray{
Schema: &apiextv1beta1.JSONSchemaProps{
Type: "string",
},
},
},
"enable_init_containers": { "enable_init_containers": {
Type: "boolean", Type: "boolean",
}, },

View File

@ -62,6 +62,7 @@ type KubernetesMetaConfiguration struct {
PodRoleLabel string `json:"pod_role_label,omitempty"` PodRoleLabel string `json:"pod_role_label,omitempty"`
ClusterLabels map[string]string `json:"cluster_labels,omitempty"` ClusterLabels map[string]string `json:"cluster_labels,omitempty"`
InheritedLabels []string `json:"inherited_labels,omitempty"` InheritedLabels []string `json:"inherited_labels,omitempty"`
DownscalerAnnotations []string `json:"downscaler_annotations,omitempty"`
ClusterNameLabel string `json:"cluster_name_label,omitempty"` ClusterNameLabel string `json:"cluster_name_label,omitempty"`
NodeReadinessLabel map[string]string `json:"node_readiness_label,omitempty"` NodeReadinessLabel map[string]string `json:"node_readiness_label,omitempty"`
CustomPodAnnotations map[string]string `json:"custom_pod_annotations,omitempty"` CustomPodAnnotations map[string]string `json:"custom_pod_annotations,omitempty"`

View File

@ -180,6 +180,11 @@ func (in *KubernetesMetaConfiguration) DeepCopyInto(out *KubernetesMetaConfigura
*out = make([]string, len(*in)) *out = make([]string, len(*in))
copy(*out, *in) copy(*out, *in)
} }
if in.DownscalerAnnotations != nil {
in, out := &in.DownscalerAnnotations, &out.DownscalerAnnotations
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.NodeReadinessLabel != nil { if in.NodeReadinessLabel != nil {
in, out := &in.NodeReadinessLabel, &out.NodeReadinessLabel in, out := &in.NodeReadinessLabel, &out.NodeReadinessLabel
*out = make(map[string]string, len(*in)) *out = make(map[string]string, len(*in))

View File

@ -711,8 +711,7 @@ func (c *Cluster) Update(oldSpec, newSpec *acidv1.Postgresql) error {
updateFailed = true updateFailed = true
return return
} }
if !reflect.DeepEqual(oldSs, newSs) || !reflect.DeepEqual(oldSpec.Annotations, newSpec.Annotations) {
if !reflect.DeepEqual(oldSs, newSs) {
c.logger.Debugf("syncing statefulsets") c.logger.Debugf("syncing statefulsets")
// TODO: avoid generating the StatefulSet object twice by passing it to syncStatefulSet // TODO: avoid generating the StatefulSet object twice by passing it to syncStatefulSet
if err := c.syncStatefulSet(); err != nil { if err := c.syncStatefulSet(); err != nil {

View File

@ -28,19 +28,48 @@ var eventRecorder = record.NewFakeRecorder(1)
var cl = New( var cl = New(
Config{ Config{
OpConfig: config.Config{ OpConfig: config.Config{
ProtectedRoles: []string{"admin"}, PodManagementPolicy: "ordered_ready",
ProtectedRoles: []string{"admin"},
Auth: config.Auth{ Auth: config.Auth{
SuperUsername: superUserName, SuperUsername: superUserName,
ReplicationUsername: replicationUserName, ReplicationUsername: replicationUserName,
}, },
Resources: config.Resources{
DownscalerAnnotations: []string{"downscaler/*"},
},
}, },
}, },
k8sutil.NewMockKubernetesClient(), k8sutil.NewMockKubernetesClient(),
acidv1.Postgresql{ObjectMeta: metav1.ObjectMeta{Name: "acid-test", Namespace: "test"}}, acidv1.Postgresql{ObjectMeta: metav1.ObjectMeta{Name: "acid-test", Namespace: "test", Annotations: map[string]string{"downscaler/downtime_replicas": "0"}}},
logger, logger,
eventRecorder, eventRecorder,
) )
func TestStatefulSetAnnotations(t *testing.T) {
testName := "CheckStatefulsetAnnotations"
spec := acidv1.PostgresSpec{
TeamID: "myapp", NumberOfInstances: 1,
Resources: acidv1.Resources{
ResourceRequests: acidv1.ResourceDescription{CPU: "1", Memory: "10"},
ResourceLimits: acidv1.ResourceDescription{CPU: "1", Memory: "10"},
},
Volume: acidv1.Volume{
Size: "1G",
},
}
ss, err := cl.generateStatefulSet(&spec)
if err != nil {
t.Errorf("in %s no statefulset created %v", testName, err)
}
if ss != nil {
annotation := ss.ObjectMeta.GetAnnotations()
if _, ok := annotation["downscaler/downtime_replicas"]; !ok {
t.Errorf("in %s respective annotation not found on sts", testName)
}
}
}
func TestInitRobotUsers(t *testing.T) { func TestInitRobotUsers(t *testing.T) {
testName := "TestInitRobotUsers" testName := "TestInitRobotUsers"
tests := []struct { tests := []struct {

View File

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"path" "path"
"sort" "sort"
"strconv"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
@ -1182,12 +1183,15 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef
return nil, fmt.Errorf("could not set the pod management policy to the unknown value: %v", c.OpConfig.PodManagementPolicy) return nil, fmt.Errorf("could not set the pod management policy to the unknown value: %v", c.OpConfig.PodManagementPolicy)
} }
annotations = make(map[string]string)
annotations[rollingUpdateStatefulsetAnnotationKey] = strconv.FormatBool(false)
statefulSet := &appsv1.StatefulSet{ statefulSet := &appsv1.StatefulSet{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: c.statefulSetName(), Name: c.statefulSetName(),
Namespace: c.Namespace, Namespace: c.Namespace,
Labels: c.labelsSet(true), Labels: c.labelsSet(true),
Annotations: map[string]string{rollingUpdateStatefulsetAnnotationKey: "false"}, Annotations: c.AnnotationsToPropagate(annotations),
}, },
Spec: appsv1.StatefulSetSpec{ Spec: appsv1.StatefulSetSpec{
Replicas: &numberOfInstances, Replicas: &numberOfInstances,

View File

@ -853,3 +853,24 @@ func (c *Cluster) updateConnectionPoolerDeployment(oldDeploymentSpec, newDeploym
return deployment, nil return deployment, nil
} }
//updateConnectionPoolerAnnotations updates the annotations of connection pooler deployment
func (c *Cluster) updateConnectionPoolerAnnotations(annotations map[string]string) (*appsv1.Deployment, error) {
c.logger.Debugf("updating connection pooler annotations")
patchData, err := metaAnnotationsPatch(annotations)
if err != nil {
return nil, fmt.Errorf("could not form patch for the deployment metadata: %v", err)
}
result, err := c.KubeClient.Deployments(c.ConnectionPooler.Deployment.Namespace).Patch(
context.TODO(),
c.ConnectionPooler.Deployment.Name,
types.MergePatchType,
[]byte(patchData),
metav1.PatchOptions{},
"")
if err != nil {
return nil, fmt.Errorf("could not patch connection pooler annotations %q: %v", patchData, err)
}
return result, nil
}

View File

@ -3,6 +3,7 @@ package cluster
import ( import (
"context" "context"
"fmt" "fmt"
"regexp"
"strings" "strings"
acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1" acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
@ -358,6 +359,8 @@ func (c *Cluster) syncStatefulSet() error {
} }
} }
} }
annotations := c.AnnotationsToPropagate(c.Statefulset.Annotations)
c.updateStatefulSetAnnotations(annotations)
if !podsRollingUpdateRequired && !c.OpConfig.EnableLazySpiloUpgrade { if !podsRollingUpdateRequired && !c.OpConfig.EnableLazySpiloUpgrade {
// even if desired and actual statefulsets match // even if desired and actual statefulsets match
@ -397,6 +400,30 @@ func (c *Cluster) syncStatefulSet() error {
return nil return nil
} }
// AnnotationsToPropagate get the annotations to update if required
// based on the annotations in postgres CRD
func (c *Cluster) AnnotationsToPropagate(annotations map[string]string) map[string]string {
toPropagateAnnotations := c.OpConfig.DownscalerAnnotations
pgCRDAnnotations := c.Postgresql.ObjectMeta.GetAnnotations()
if toPropagateAnnotations != nil && pgCRDAnnotations != nil {
for _, anno := range toPropagateAnnotations {
for k, v := range pgCRDAnnotations {
matched, err := regexp.MatchString(anno, k)
if err != nil {
c.logger.Errorf("annotations matching issue: %v", err)
return nil
}
if matched {
annotations[k] = v
}
}
}
}
return annotations
}
// checkAndSetGlobalPostgreSQLConfiguration checks whether cluster-wide API parameters // checkAndSetGlobalPostgreSQLConfiguration checks whether cluster-wide API parameters
// (like max_connections) has changed and if necessary sets it via the Patroni API // (like max_connections) has changed and if necessary sets it via the Patroni API
func (c *Cluster) checkAndSetGlobalPostgreSQLConfiguration() error { func (c *Cluster) checkAndSetGlobalPostgreSQLConfiguration() error {
@ -939,6 +966,11 @@ func (c *Cluster) syncConnectionPoolerWorker(oldSpec, newSpec *acidv1.Postgresql
} }
} }
newAnnotations := c.AnnotationsToPropagate(c.ConnectionPooler.Deployment.Annotations)
if newAnnotations != nil {
c.updateConnectionPoolerAnnotations(newAnnotations)
}
service, err := c.KubeClient. service, err := c.KubeClient.
Services(c.Namespace). Services(c.Namespace).
Get(context.TODO(), c.connectionPoolerName(), metav1.GetOptions{}) Get(context.TODO(), c.connectionPoolerName(), metav1.GetOptions{})

View File

@ -73,6 +73,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
result.PodRoleLabel = util.Coalesce(fromCRD.Kubernetes.PodRoleLabel, "spilo-role") result.PodRoleLabel = util.Coalesce(fromCRD.Kubernetes.PodRoleLabel, "spilo-role")
result.ClusterLabels = fromCRD.Kubernetes.ClusterLabels result.ClusterLabels = fromCRD.Kubernetes.ClusterLabels
result.InheritedLabels = fromCRD.Kubernetes.InheritedLabels result.InheritedLabels = fromCRD.Kubernetes.InheritedLabels
result.DownscalerAnnotations = fromCRD.Kubernetes.DownscalerAnnotations
result.ClusterNameLabel = util.Coalesce(fromCRD.Kubernetes.ClusterNameLabel, "cluster-name") result.ClusterNameLabel = util.Coalesce(fromCRD.Kubernetes.ClusterNameLabel, "cluster-name")
result.NodeReadinessLabel = fromCRD.Kubernetes.NodeReadinessLabel result.NodeReadinessLabel = fromCRD.Kubernetes.NodeReadinessLabel
result.PodPriorityClassName = fromCRD.Kubernetes.PodPriorityClassName result.PodPriorityClassName = fromCRD.Kubernetes.PodPriorityClassName

View File

@ -487,7 +487,9 @@ func (c *Controller) postgresqlUpdate(prev, cur interface{}) {
if pgOld != nil && pgNew != nil { if pgOld != nil && pgNew != nil {
// Avoid the inifinite recursion for status updates // Avoid the inifinite recursion for status updates
if reflect.DeepEqual(pgOld.Spec, pgNew.Spec) { if reflect.DeepEqual(pgOld.Spec, pgNew.Spec) {
return if reflect.DeepEqual(pgNew.Annotations, pgOld.Annotations) {
return
}
} }
c.queueClusterEvent(pgOld, pgNew, EventUpdate) c.queueClusterEvent(pgOld, pgNew, EventUpdate)
} }

View File

@ -34,6 +34,7 @@ type Resources struct {
SpiloPrivileged bool `name:"spilo_privileged" default:"false"` SpiloPrivileged bool `name:"spilo_privileged" default:"false"`
ClusterLabels map[string]string `name:"cluster_labels" default:"application:spilo"` ClusterLabels map[string]string `name:"cluster_labels" default:"application:spilo"`
InheritedLabels []string `name:"inherited_labels" default:""` InheritedLabels []string `name:"inherited_labels" default:""`
DownscalerAnnotations []string `name:"downscaler_annotations"`
ClusterNameLabel string `name:"cluster_name_label" default:"cluster-name"` ClusterNameLabel string `name:"cluster_name_label" default:"cluster-name"`
PodRoleLabel string `name:"pod_role_label" default:"spilo-role"` PodRoleLabel string `name:"pod_role_label" default:"spilo-role"`
PodToleration map[string]string `name:"toleration" default:""` PodToleration map[string]string `name:"toleration" default:""`