diff --git a/charts/postgres-operator/crds/postgresqls.yaml b/charts/postgres-operator/crds/postgresqls.yaml index 6f938cf8f..759e7d4bd 100644 --- a/charts/postgres-operator/crds/postgresqls.yaml +++ b/charts/postgres-operator/crds/postgresqls.yaml @@ -479,6 +479,8 @@ spec: type: string standby_port: type: string + standby_primary_slot_name: + type: string oneOf: - required: - s3_wal_path diff --git a/docs/administrator.md b/docs/administrator.md index 19cfe2109..e531d1f3e 100644 --- a/docs/administrator.md +++ b/docs/administrator.md @@ -1156,6 +1156,7 @@ the `STANDBY_` prefix for Spilo to find the backups and WAL files to stream. Alternatively, standby clusters can also stream from a remote primary cluster. You have to specify the host address. Port is optional and defaults to 5432. +Moreover, you can also specify a replication slot of the primary. Note, that only one of the options (`s3_wal_path`, `gs_wal_path`, `standby_host`) can be present under the `standby` top-level key. diff --git a/docs/reference/cluster_manifest.md b/docs/reference/cluster_manifest.md index 8cca890c8..0cec9b131 100644 --- a/docs/reference/cluster_manifest.md +++ b/docs/reference/cluster_manifest.md @@ -430,6 +430,9 @@ if the `standby` key is present. TCP port on which the primary is listening for connections. Patroni will use `"5432"` if not set. +* **standby_primary_slot_name** + replication slot on the primary. + ## Volume properties Those parameters are grouped under the `volume` top-level key and define the diff --git a/docs/user.md b/docs/user.md index fa82e3344..ee72b53bf 100644 --- a/docs/user.md +++ b/docs/user.md @@ -901,6 +901,15 @@ spec: standby: standby_host: "acid-minimal-cluster.default" standby_port: "5433" + standby_primary_slot_name: "slot" +``` + +If needed, one can also specify the slot on the primary to use for replication. + +```yaml +spec: + standby: + standby_primary_slot_name: "slot" ``` Note, that the pods and services use the same role labels like for normal clusters: diff --git a/manifests/postgresql.crd.yaml b/manifests/postgresql.crd.yaml index 6066abad1..e016a95ff 100644 --- a/manifests/postgresql.crd.yaml +++ b/manifests/postgresql.crd.yaml @@ -477,6 +477,8 @@ spec: type: string standby_port: type: string + standby_primary_slot_name: + type: string oneOf: - required: - s3_wal_path diff --git a/manifests/standby-manifest.yaml b/manifests/standby-manifest.yaml index 2db4d489b..c50a4dff4 100644 --- a/manifests/standby-manifest.yaml +++ b/manifests/standby-manifest.yaml @@ -14,3 +14,4 @@ spec: # s3_wal_path: "s3://mybucket/spilo/acid-minimal-cluster/abcd1234-2a4b-4b2a-8c9c-c1234defg567/wal/14/" standby_host: "acid-minimal-cluster.default" # standby_port: "5432" + # standby_primary_slot_name: "slot" diff --git a/pkg/apis/acid.zalan.do/v1/crds.go b/pkg/apis/acid.zalan.do/v1/crds.go index b82aa30b6..4e4962137 100644 --- a/pkg/apis/acid.zalan.do/v1/crds.go +++ b/pkg/apis/acid.zalan.do/v1/crds.go @@ -746,6 +746,9 @@ var PostgresCRDResourceValidation = apiextv1.CustomResourceValidation{ "standby_port": { Type: "string", }, + "standby_primary_slot_name": { + Type: "string", + }, }, OneOf: []apiextv1.JSONSchemaProps{ apiextv1.JSONSchemaProps{Required: []string{"s3_wal_path"}}, diff --git a/pkg/apis/acid.zalan.do/v1/postgresql_type.go b/pkg/apis/acid.zalan.do/v1/postgresql_type.go index 67007b522..c6612ae0a 100644 --- a/pkg/apis/acid.zalan.do/v1/postgresql_type.go +++ b/pkg/apis/acid.zalan.do/v1/postgresql_type.go @@ -180,10 +180,11 @@ type Patroni struct { // StandbyDescription contains remote primary config or s3/gs wal path type StandbyDescription struct { - S3WalPath string `json:"s3_wal_path,omitempty"` - GSWalPath string `json:"gs_wal_path,omitempty"` - StandbyHost string `json:"standby_host,omitempty"` - StandbyPort string `json:"standby_port,omitempty"` + S3WalPath string `json:"s3_wal_path,omitempty"` + GSWalPath string `json:"gs_wal_path,omitempty"` + StandbyHost string `json:"standby_host,omitempty"` + StandbyPort string `json:"standby_port,omitempty"` + StandbyPrimarySlotName string `json:"standby_primary_slot_name,omitempty"` } // TLSDescription specs TLS properties diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go index 2e317c1a2..74cb9ed02 100644 --- a/pkg/cluster/k8sres.go +++ b/pkg/cluster/k8sres.go @@ -2058,6 +2058,12 @@ func (c *Cluster) generateStandbyEnvironment(description *acidv1.StandbyDescript Value: description.StandbyPort, }) } + if description.StandbyPrimarySlotName != "" { + result = append(result, v1.EnvVar{ + Name: "STANDBY_PRIMARY_SLOT_NAME", + Value: description.StandbyPrimarySlotName, + }) + } } else { c.logger.Info("standby cluster streaming from WAL location") if description.S3WalPath != "" { diff --git a/pkg/cluster/k8sres_test.go b/pkg/cluster/k8sres_test.go index 226e5ced5..b1f47e409 100644 --- a/pkg/cluster/k8sres_test.go +++ b/pkg/cluster/k8sres_test.go @@ -1292,6 +1292,19 @@ func TestStandbyEnv(t *testing.T) { envPos: 1, envLen: 2, }, + { + subTest: "from remote primary with slot", + standbyOpts: &acidv1.StandbyDescription{ + StandbyHost: "remote-primary", + StandbyPrimarySlotName: "slot", + }, + env: v1.EnvVar{ + Name: "STANDBY_PRIMARY_SLOT_NAME", + Value: "slot", + }, + envPos: 1, + envLen: 2, + }, { subTest: "from remote primary - ignore WAL path", standbyOpts: &acidv1.StandbyDescription{