From d0e215dee31a246a9421d7f0e60b7e7c6e6ebe5f Mon Sep 17 00:00:00 2001 From: Pavel Zaytsev Date: Tue, 23 Dec 2025 16:18:09 -0800 Subject: [PATCH] Add ignore_slots support to Patroni DCS configuration - Add ignore_slots field to Patroni struct in CRD - Add ignore_slots to patroniDCS struct for Spilo configuration - Generate ignore_slots in SPILO_CONFIGURATION when specified - Update CRD manifest to accept ignore_slots field - Add unit test for ignore_slots configuration This enables PostgreSQL 17 native slot synchronization support by allowing users to configure Patroni to ignore specific replication slot types (e.g., logical slots) during failover operations. Users can now configure ignore_slots in their PostgreSQL manifest: patroni: ignore_slots: - type: logical This instructs Patroni to ignore logical replication slots during failover, which is essential for PostgreSQL 17's native logical slot synchronization feature where slots are automatically synced to standbys. --- manifests/postgresql.crd.yaml | 6 ++++++ pkg/apis/acid.zalan.do/v1/postgresql_type.go | 1 + pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go | 13 +++++++++++++ pkg/cluster/k8sres.go | 5 +++++ pkg/cluster/k8sres_test.go | 11 +++++++++++ 5 files changed, 36 insertions(+) diff --git a/manifests/postgresql.crd.yaml b/manifests/postgresql.crd.yaml index 7a1b21a4d..711e54335 100644 --- a/manifests/postgresql.crd.yaml +++ b/manifests/postgresql.crd.yaml @@ -327,6 +327,12 @@ spec: properties: failsafe_mode: type: boolean + ignore_slots: + type: array + items: + type: object + additionalProperties: + type: string initdb: type: object additionalProperties: diff --git a/pkg/apis/acid.zalan.do/v1/postgresql_type.go b/pkg/apis/acid.zalan.do/v1/postgresql_type.go index ef6dfe7ff..6734f188f 100644 --- a/pkg/apis/acid.zalan.do/v1/postgresql_type.go +++ b/pkg/apis/acid.zalan.do/v1/postgresql_type.go @@ -182,6 +182,7 @@ type Patroni struct { SynchronousModeStrict bool `json:"synchronous_mode_strict,omitempty"` SynchronousNodeCount uint32 `json:"synchronous_node_count,omitempty" defaults:"1"` FailsafeMode *bool `json:"failsafe_mode,omitempty"` + IgnoreSlots []map[string]string `json:"ignore_slots,omitempty"` } // StandbyDescription contains remote primary config or s3/gs wal path diff --git a/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go b/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go index 5d0a5b341..63771420b 100644 --- a/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go +++ b/pkg/apis/acid.zalan.do/v1/zz_generated.deepcopy.go @@ -597,6 +597,19 @@ func (in *Patroni) DeepCopyInto(out *Patroni) { *out = new(bool) **out = **in } + if in.IgnoreSlots != nil { + in, out := &in.IgnoreSlots, &out.IgnoreSlots + *out = make([]map[string]string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + } + } return } diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go index 9bc39a9db..67e42cb76 100644 --- a/pkg/cluster/k8sres.go +++ b/pkg/cluster/k8sres.go @@ -57,6 +57,7 @@ type patroniDCS struct { PGBootstrapConfiguration map[string]interface{} `json:"postgresql,omitempty"` Slots map[string]map[string]string `json:"slots,omitempty"` FailsafeMode *bool `json:"failsafe_mode,omitempty"` + IgnoreSlots []map[string]string `json:"ignore_slots,omitempty"` } type pgBootstrap struct { @@ -441,6 +442,10 @@ PatroniInitDBParams: config.Bootstrap.DCS.FailsafeMode = opConfig.EnablePatroniFailsafeMode } + + if patroni.IgnoreSlots != nil { + config.Bootstrap.DCS.IgnoreSlots = patroni.IgnoreSlots + } config.PgLocalConfiguration = make(map[string]interface{}) // the newer and preferred way to specify the PG version is to use the `PGVERSION` env variable diff --git a/pkg/cluster/k8sres_test.go b/pkg/cluster/k8sres_test.go index 6bd87366d..d5f0149af 100644 --- a/pkg/cluster/k8sres_test.go +++ b/pkg/cluster/k8sres_test.go @@ -135,6 +135,17 @@ func TestGenerateSpiloJSONConfiguration(t *testing.T) { }, result: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/17/bin"},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"}],"dcs":{"failsafe_mode":true}}}`, }, + { + subtest: "Patroni ignore_slots configured for PostgreSQL 17 slot sync", + pgParam: &acidv1.PostgresqlParam{PgVersion: "17"}, + patroni: &acidv1.Patroni{ + IgnoreSlots: []map[string]string{ + {"type": "logical"}, + }, + }, + opConfig: &config.Config{}, + result: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/17/bin"},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"}],"dcs":{"ignore_slots":[{"type":"logical"}]}}}`, + }, } for _, tt := range tests { cluster.OpConfig = *tt.opConfig