Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
5046565
prepare postgreslet for operator v2.0.1 upgrade
Aug 3, 2026
c61a216
fix ToUnstructuredZalandoPostgresql calls
Aug 3, 2026
83e5773
use tsc opts struct
Aug 3, 2026
87adeb0
comment out unless v2 op api available
Aug 3, 2026
fa4a4e2
feat: bump zalando/postgres-operator using pseudo-version
l0wl3vel Aug 3, 2026
f999cbd
fix: update controller-runtime and controller-gen to fix build
l0wl3vel Aug 3, 2026
31df020
fix: bumpt golang-ci lint action
l0wl3vel Aug 3, 2026
c013f09
fix linter call
Aug 4, 2026
151277b
fix linter call in the here as well
Aug 4, 2026
ce0aed4
add TopologySpreadConstraint to zalando CR if enabled
Aug 4, 2026
31d4286
satisfy linter
Aug 4, 2026
38db8ff
upd docker build to use 1.26 as well
Aug 4, 2026
3d9baee
make sure the TopologySpreadConstraints mutator is disabled on v2
Aug 4, 2026
1ffe2a0
fix name label (use Postgres UID)
Aug 6, 2026
a675272
mv PodTopologySpreadConstraintsOpts to api/v1
Aug 6, 2026
0648250
revert renaming vars
Aug 7, 2026
bddef79
revert PodTopologySpreadConstraintsOpts, use separate vars again
Aug 7, 2026
d984f4d
Revert "fix linter call in the here as well"
Aug 7, 2026
a8f1c40
Revert "fix linter call"
Aug 7, 2026
ff49dbd
Revert "fix: bumpt golang-ci lint action"
Aug 7, 2026
4a1f41f
bail out if enablePodTopologySpreadConstraint set with operator <v2
Aug 7, 2026
174070f
linter update required due to golang 1.26 dependency
Aug 7, 2026
1a3a419
lint only new commits, update latest as well
Aug 7, 2026
71f8ddb
fix yaml indents
Aug 7, 2026
95505b3
remove redundant func args
Aug 7, 2026
994fed9
properly update config
Aug 10, 2026
c307ebb
fix misleading error message
Aug 10, 2026
52697a9
deprecate kubernetes_use_configmaps=false, use op builtin default
Aug 13, 2026
b646b7e
fix: add missing patching for postgres-operator-deployment
l0wl3vel Aug 13, 2026
64f87be
revert enable-kubernetes-use-configmaps deprecation note
Aug 17, 2026
f87dd78
Merge branch 'main' into upgrade-operator-v2
TLINDEN Aug 17, 2026
450869c
satisfy linter: remove exhaustruct
Aug 17, 2026
5190bbd
record.Eventf does not support error-wrapping directive %w, use %v
Aug 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ linters:
- errname
- errorlint
- exhaustive
- exhaustruct
- exptostd
- forbidigo
- forcetypeassert
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ARG baseImage="golang:1.24"
ARG baseImage="golang:1.26"
# Build the manager binary
FROM ${baseImage} as builder

Expand All @@ -18,7 +18,7 @@ RUN make

# Start obj-cache
# https://medium.com/windmill-engineering/tips-tricks-for-making-your-golang-container-builds-10x-faster-4cc618a43827
FROM golang:1.24 as obj-cache
FROM golang:1.26 as obj-cache
COPY --from=builder /root/.cache /root/.cache

# Use distroless as minimal base image to package the manager binary
Expand Down
9 changes: 7 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ BUILDDATE := $(shell date -Iseconds)
VERSION := $(or ${DOCKER_TAG},latest)
LOCALBIN ?= $(shell pwd)/bin
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
CONTROLLER_TOOLS_VERSION ?= v0.14.0
CONTROLLER_TOOLS_VERSION ?= v0.21.0

# Postgres operator variables for YAML download
POSTGRES_OPERATOR_VERSION ?= v1.15.1
POSTGRES_OPERATOR_VERSION ?= v2.0.1
POSTGRES_OPERATOR_URL ?= https://raw.githubusercontent.com/zalando/postgres-operator/$(POSTGRES_OPERATOR_VERSION)/manifests
POSTGRES_CRD_URL ?= https://raw.githubusercontent.com/zalando/postgres-operator/$(POSTGRES_OPERATOR_VERSION)/charts/postgres-operator/crds/postgresqls.yaml

Expand Down Expand Up @@ -141,6 +141,11 @@ svc-postgres-operator-yaml:
-f $(POSTGRES_OPERATOR_URL)/postgres-operator.yaml \
-f $(POSTGRES_OPERATOR_URL)/api-service.yaml \
--dry-run=client -o yaml > external/svc-postgres-operator.yaml

@# deep-merge every external/patches/*.yaml into the list item matching its kind and name
@for p in external/patches/*.yaml; do echo "patching with $$p"; PATCH=$$p yq -i \
'load(strenv(PATCH)) as $$p | (.items[] | select(.kind == $$p.kind and .metadata.name == $$p.metadata.name)) *=d $$p' \
external/svc-postgres-operator.yaml; done

# crd-postgresql-yaml:
# kubectl apply -f $(POSTGRES_CRD_URL) --dry-run=client -o yaml > external/crd-postgresql.yaml
Expand Down
65 changes: 51 additions & 14 deletions api/v1/postgres_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/utils/ptr"
"sigs.k8s.io/controller-runtime/pkg/client"
)

Expand Down Expand Up @@ -680,16 +679,20 @@ func (p *Postgres) ToPeripheralResourceLookupKey() types.NamespacedName {
}
}

func (p *Postgres) ToUnstructuredZalandoPostgresql(z *zalando.Postgresql, c *corev1.ConfigMap, sc string, pgParamBlockList map[string]bool, rbs *BackupConfig, srcDB *Postgres, patroniTTL, patroniLoopWait, patroniRetryTimeout uint32, dboIsSuperuser bool, enableTlsCert bool, image string, cpuRequestsPercentage int) (*unstructured.Unstructured, error) {
func (p *Postgres) ToUnstructuredZalandoPostgresql(z *zalando.Postgresql, c *corev1.ConfigMap, sc string, pgParamBlockList map[string]bool, rbs *BackupConfig, srcDB *Postgres, patroniTTL, patroniLoopWait, patroniRetryTimeout uint32, dboIsSuperuser bool, enableTLSCert bool, image string, cpuRequestsPercentage int, tscEnable bool, tscKey string, tscMaxSkew, tscMinDomains int32) (*unstructured.Unstructured, error) {
if z == nil {
z = &zalando.Postgresql{}
}
z.TypeMeta = ZalandoPostgresqlTypeMeta
z.Namespace = p.ToPeripheralResourceNamespace()
z.Name = p.ToPeripheralResourceName()
z.Labels = p.ToZalandoPostgresqlMatchingLabels()
// Add the newly introduced label only here, not in p.ToZalandoPostgresqlMatchingLabels() (so that the selectors using p.ToZalandoPostgresqlMatchingLabels() will still work until all postgres resources have that new label)
// TODO once all the custom resources have that new label, move this part to p.ToZalandoPostgresqlMatchingLabels()
// Add the newly introduced label only here, not in
// p.ToZalandoPostgresqlMatchingLabels() (so that the selectors
// using p.ToZalandoPostgresqlMatchingLabels() will still work
// until all postgres resources have that new label) TODO once all
// the custom resources have that new label, move this part to
// p.ToZalandoPostgresqlMatchingLabels()
z.Labels[PartitionIDLabelName] = p.Spec.PartitionID
// Add the additional version label to the custom resource
z.Labels[PostgresVersionLabelName] = p.Spec.Version
Expand Down Expand Up @@ -721,12 +724,14 @@ func (p *Postgres) ToUnstructuredZalandoPostgresql(z *zalando.Postgresql, c *cor
if err != nil {
return nil, fmt.Errorf("failed to convert to unstructured zalando postgresql: %w", err)
}
z.Spec.ResourceRequests.CPU = ptr.To(cpuReq)
z.Spec.ResourceRequests.Memory = ptr.To(p.Spec.Size.Memory)
z.Spec.ResourceLimits.CPU = ptr.To(p.Spec.Size.CPU)
z.Spec.ResourceLimits.Memory = ptr.To(p.Spec.Size.Memory)

z.Spec.ResourceRequests.CPU = new(cpuReq)
z.Spec.ResourceRequests.Memory = new(p.Spec.Size.Memory)
z.Spec.ResourceLimits.CPU = new(p.Spec.Size.CPU)
z.Spec.ResourceLimits.Memory = new(p.Spec.Size.Memory)
z.Spec.TeamID = p.generateTeamID()
z.Spec.Size = p.Spec.Size.StorageSize

if p.Spec.StorageClass != nil {
z.Spec.StorageClass = *p.Spec.StorageClass
} else {
Expand All @@ -741,12 +746,12 @@ func (p *Postgres) ToUnstructuredZalandoPostgresql(z *zalando.Postgresql, c *cor

// required with image ermajn/postgres-operator:v1.6.0-20-g1cc71663-dirty
// see https://github.com/fi-ts/postgreslet/issues/293
z.Spec.EnableConnectionPooler = ptr.To(false)
z.Spec.EnableConnectionPooler = new(false)

prefix := alphaNumericRegExp.ReplaceAllString(string(p.Spec.Tenant), "")
prefix = strings.ToLower(prefix)
databaseName := prefix + "db01"
prepDbName := prefix + "prepdb01"
prepDBName := prefix + "prepdb01"
ownerName := prefix + "dbo"

// Create database owner
Expand All @@ -766,7 +771,7 @@ func (p *Postgres) ToUnstructuredZalandoPostgresql(z *zalando.Postgresql, c *cor

// Create prepared database
z.Spec.PreparedDatabases = make(map[string]zalando.PreparedDatabase)
z.Spec.PreparedDatabases[prepDbName] = zalando.PreparedDatabase{
z.Spec.PreparedDatabases[prepDBName] = zalando.PreparedDatabase{
DefaultUsers: true,
Extensions: map[string]string{
"pg_partman": "public",
Expand All @@ -789,7 +794,10 @@ func (p *Postgres) ToUnstructuredZalandoPostgresql(z *zalando.Postgresql, c *cor
}

if p.Spec.PostgresRestore != nil && rbs != nil && srcDB != nil {
// make sure there is always a value set. The operator will fall back to CLONE_WITH_BASEBACKUP, which assumes the source db's credentials are existing within the same namespace, which is not the case with the postgreslet.
// make sure there is always a value set. The operator will
// fall back to CLONE_WITH_BASEBACKUP, which assumes the
// source db's credentials are existing within the same
// namespace, which is not the case with the postgreslet.
if p.Spec.PostgresRestore.Timestamp == "" {
// e.g. 2021-12-07T15:28:00+01:00
p.Spec.PostgresRestore.Timestamp = time.Now().Format(zalando_timestamp_format)
Expand All @@ -801,7 +809,7 @@ func (p *Postgres) ToUnstructuredZalandoPostgresql(z *zalando.Postgresql, c *cor
S3Endpoint: rbs.S3Endpoint,
S3AccessKeyId: rbs.S3AccessKey,
S3SecretAccessKey: rbs.S3SecretKey,
S3ForcePathStyle: ptr.To(true),
S3ForcePathStyle: new(true),
}
} else {
// if we don't set the clone block, remove it completely
Expand All @@ -821,14 +829,43 @@ func (p *Postgres) ToUnstructuredZalandoPostgresql(z *zalando.Postgresql, c *cor
}
}

if enableTlsCert {
if enableTLSCert {
z.Spec.TLS = &zalando.TLSDescription{
SecretName: p.ToTLSSecretName(),
}
} else {
z.Spec.TLS = nil
}

if tscEnable {
tsc := corev1.TopologySpreadConstraint{
MaxSkew: tscMaxSkew,
WhenUnsatisfiable: corev1.ScheduleAnyway,
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"application": "spilo",
"cluster-name": z.Name,
NameLabelName: p.Name,
PartitionIDLabelName: p.Spec.PartitionID,
ProjectIDLabelName: p.Spec.ProjectID,
TenantLabelName: p.Spec.Tenant,
UIDLabelName: string(p.UID),
"team": p.generateTeamID(),
Comment thread
l0wl3vel marked this conversation as resolved.
},
},
TopologyKey: tscKey,
}

// if defined, set the minDomains (and corresponding whenUnsatisfied) field as well
if tscMinDomains > 0 {
tsc.MinDomains = &tscMinDomains
tsc.WhenUnsatisfiable = corev1.DoNotSchedule
Comment thread
l0wl3vel marked this conversation as resolved.
}

// override topology spread constraints
z.Spec.TopologySpreadConstraints = []corev1.TopologySpreadConstraint{tsc}
}

jsonZ, err := runtime.DefaultUnstructuredConverter.ToUnstructured(z)
if err != nil {
return nil, fmt.Errorf("failed to convert to unstructured zalando postgresql: %w", err)
Expand Down
3 changes: 2 additions & 1 deletion api/v1/postgres_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,8 @@ func TestPostgresRestoreTimestamp_ToUnstructuredZalandoPostgresql(t *testing.T)
p := &Postgres{
Spec: tt.spec,
}
got, _ := p.ToUnstructuredZalandoPostgresql(nil, tt.c, tt.sc, tt.pgParamBlockList, tt.rbs, tt.srcDB, 130, 10, 60, false, false, "dockerImage", 66)
got, _ := p.ToUnstructuredZalandoPostgresql(nil, tt.c, tt.sc, tt.pgParamBlockList, tt.rbs, tt.srcDB,
130, 10, 60, false, false, "dockerImage", 66, false, "", 0, 0)

jsonZ, err := runtime.DefaultUnstructuredConverter.ToUnstructured(got)
if err != nil {
Expand Down
9 changes: 6 additions & 3 deletions controllers/postgres_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ type PostgresReconciler struct {
WalGExporterCPULimit string
WalGExporterMemoryLimit string
SpiloCpuRequestsPercentage int
EnableTopologySpreadConstraints bool
TscMinDomains, TscMaxSkew int32
TscKey string
}

type PatroniStandbyCluster struct {
Expand Down Expand Up @@ -480,7 +483,7 @@ func (r *PostgresReconciler) createOrUpdateZalandoPostgresql(ctx context.Context
return fmt.Errorf("failed to fetch zalando postgresql: %w", err)
}

u, err := instance.ToUnstructuredZalandoPostgresql(nil, sidecarsCM, r.StorageClass, r.PgParamBlockList, restoreBackupConfig, restoreSourceInstance, patroniTTL, patroniLoopWait, patroniRetryTimeout, r.EnableSuperUserForDBO, r.EnableCustomTLSCert, r.PostgresImage, r.SpiloCpuRequestsPercentage)
u, err := instance.ToUnstructuredZalandoPostgresql(nil, sidecarsCM, r.StorageClass, r.PgParamBlockList, restoreBackupConfig, restoreSourceInstance, patroniTTL, patroniLoopWait, patroniRetryTimeout, r.EnableSuperUserForDBO, r.EnableCustomTLSCert, r.PostgresImage, r.SpiloCpuRequestsPercentage, r.EnableTopologySpreadConstraints, r.TscKey, r.TscMaxSkew, r.TscMinDomains)
if err != nil {
return fmt.Errorf("failed to convert to unstructured zalando postgresql: %w", err)
}
Expand All @@ -496,7 +499,7 @@ func (r *PostgresReconciler) createOrUpdateZalandoPostgresql(ctx context.Context
// Update zalando postgresql
mergeFrom := client.MergeFrom(rawZ.DeepCopy())

u, err := instance.ToUnstructuredZalandoPostgresql(rawZ, sidecarsCM, r.StorageClass, r.PgParamBlockList, restoreBackupConfig, restoreSourceInstance, patroniTTL, patroniLoopWait, patroniRetryTimeout, r.EnableSuperUserForDBO, r.EnableCustomTLSCert, r.PostgresImage, r.SpiloCpuRequestsPercentage)
u, err := instance.ToUnstructuredZalandoPostgresql(rawZ, sidecarsCM, r.StorageClass, r.PgParamBlockList, restoreBackupConfig, restoreSourceInstance, patroniTTL, patroniLoopWait, patroniRetryTimeout, r.EnableSuperUserForDBO, r.EnableCustomTLSCert, r.PostgresImage, r.SpiloCpuRequestsPercentage, r.EnableTopologySpreadConstraints, r.TscKey, r.TscMaxSkew, r.TscMinDomains)
if err != nil {
return fmt.Errorf("failed to convert to unstructured zalando postgresql: %w", err)
}
Expand Down Expand Up @@ -750,7 +753,7 @@ func (r *PostgresReconciler) getStandbyEnvs(ctx context.Context, p *pg.Postgres)
}
primaryS3url, err := url.Parse(primaryBackupConfig.S3Endpoint)
if err != nil {
r.recorder.Eventf(primary, "Warning", "Error", "error while parsing the s3 endpoint url in the backup secret: %w", err)
r.recorder.Eventf(primary, "Warning", "Error", "error while parsing the s3 endpoint url in the backup secret: %v", err)

return standbyEnvs
}
Expand Down
13 changes: 13 additions & 0 deletions external/patches/postgres-operator-deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
kind: Deployment
metadata:
name: postgres-operator
spec:
template:
spec:
containers:
- securityContext:
seccompProfile:
type: RuntimeDefault
capabilities:
drop:
- ALL
Loading
Loading