This commit is contained in:
Karolin Kostial 2026-05-08 09:57:59 +02:00 committed by GitHub
commit b93ccdd193
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 50 additions and 13 deletions

View File

@ -324,6 +324,12 @@ explanation of `ttl` and `loop_wait` parameters.
custom `pg_hba` should include the pam line to avoid breaking pam
authentication. Optional.
* **pg_ident**
list of custom `pg_ident` lines defining user name maps for external
authentication methods (e.g. cert, gss, peer). Each line is of the form
`mapname system-username pg-username`. Patroni manages `pg_ident.conf`
and reloads PostgreSQL when this list changes. Optional.
* **ttl**
Patroni `ttl` parameter value, optional. The default is set by the Spilo
Docker image. Optional.

View File

@ -137,6 +137,9 @@ spec:
# pg_hba:
# - hostssl all all 0.0.0.0/0 md5
# - host all all 0.0.0.0/0 md5
# pg_ident:
# - mymap /^(.*)@example\.com$ \1
# - mymap admin@example.com postgres
# slots:
# permanent_physical_1:
# type: physical

View File

@ -3484,6 +3484,10 @@ spec:
items:
type: string
type: array
pg_ident:
items:
type: string
type: array
retry_timeout:
format: int32
type: integer

View File

@ -3484,6 +3484,10 @@ spec:
items:
type: string
type: array
pg_ident:
items:
type: string
type: array
retry_timeout:
format: int32
type: integer

View File

@ -235,6 +235,7 @@ type Resources struct {
type Patroni struct {
InitDB map[string]string `json:"initdb,omitempty"`
PgHba []string `json:"pg_hba,omitempty"`
PgIdent []string `json:"pg_ident,omitempty"`
TTL uint32 `json:"ttl,omitempty"`
LoopWait uint32 `json:"loop_wait,omitempty"`
RetryTimeout uint32 `json:"retry_timeout,omitempty"`

View File

@ -257,6 +257,10 @@ var unmarshalCluster = []struct {
"hostssl all all 0.0.0.0/0 md5",
"host all all 0.0.0.0/0 md5"
],
"pg_ident": [
"mymap user1 dbuser1",
"mymap user2 dbuser2"
],
"ttl": 30,
"loop_wait": 10,
"retry_timeout": 10,
@ -307,6 +311,7 @@ var unmarshalCluster = []struct {
"data-checksums": "true",
},
PgHba: []string{"hostssl all all 0.0.0.0/0 md5", "host all all 0.0.0.0/0 md5"},
PgIdent: []string{"mymap user1 dbuser1", "mymap user2 dbuser2"},
TTL: 30,
LoopWait: 10,
RetryTimeout: 10,
@ -346,7 +351,7 @@ var unmarshalCluster = []struct {
},
Error: "",
},
marshal: []byte(`{"kind":"Postgresql","apiVersion":"acid.zalan.do/v1","metadata":{"name":"acid-testcluster1","creationTimestamp":null},"spec":{"postgresql":{"version":"18","parameters":{"log_statement":"all","max_connections":"10","shared_buffers":"32MB"}},"pod_priority_class_name":"spilo-pod-priority","volume":{"size":"5Gi","storageClass":"SSD", "subPath": "subdir"},"enableShmVolume":false,"patroni":{"initdb":{"data-checksums":"true","encoding":"UTF8","locale":"en_US.UTF-8"},"pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"],"ttl":30,"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"slots":{"permanent_logical_1":{"database":"foo","plugin":"pgoutput","type":"logical"}}},"resources":{"requests":{"cpu":"10m","memory":"50Mi"},"limits":{"cpu":"300m","memory":"3000Mi"}},"teamId":"acid","allowedSourceRanges":["127.0.0.1/32"],"numberOfInstances":2,"users":{"zalando":["superuser","createdb"]},"maintenanceWindows":["Mon:01:00-06:00","Sat:00:00-04:00","05:00-05:15"],"clone":{"cluster":"acid-batman"}},"status":{"PostgresClusterStatus":""}}`),
marshal: []byte(`{"kind":"Postgresql","apiVersion":"acid.zalan.do/v1","metadata":{"name":"acid-testcluster1","creationTimestamp":null},"spec":{"postgresql":{"version":"18","parameters":{"log_statement":"all","max_connections":"10","shared_buffers":"32MB"}},"pod_priority_class_name":"spilo-pod-priority","volume":{"size":"5Gi","storageClass":"SSD", "subPath": "subdir"},"enableShmVolume":false,"patroni":{"initdb":{"data-checksums":"true","encoding":"UTF8","locale":"en_US.UTF-8"},"pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"],"pg_ident":["mymap user1 dbuser1","mymap user2 dbuser2"],"ttl":30,"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"slots":{"permanent_logical_1":{"database":"foo","plugin":"pgoutput","type":"logical"}}},"resources":{"requests":{"cpu":"10m","memory":"50Mi"},"limits":{"cpu":"300m","memory":"3000Mi"}},"teamId":"acid","allowedSourceRanges":["127.0.0.1/32"],"numberOfInstances":2,"users":{"zalando":["superuser","createdb"]},"maintenanceWindows":["Mon:01:00-06:00","Sat:00:00-04:00","05:00-05:15"],"clone":{"cluster":"acid-batman"}},"status":{"PostgresClusterStatus":""}}`),
err: nil},
{
about: "example with clone",

View File

@ -587,6 +587,11 @@ func (in *Patroni) DeepCopyInto(out *Patroni) {
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.PgIdent != nil {
in, out := &in.PgIdent, &out.PgIdent
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Slots != nil {
in, out := &in.Slots, &out.Slots
*out = make(map[string]map[string]string, len(*in))

View File

@ -35,15 +35,16 @@ import (
)
const (
pgBinariesLocationTemplate = "/usr/lib/postgresql/%v/bin"
patroniPGBinariesParameterName = "bin_dir"
patroniPGHBAConfParameterName = "pg_hba"
localHost = "127.0.0.1/32"
scalyrSidecarName = "scalyr-sidecar"
logicalBackupContainerName = "logical-backup"
connectionPoolerContainer = "connection-pooler"
pgPort = 5432
operatorPort = 8080
pgBinariesLocationTemplate = "/usr/lib/postgresql/%v/bin"
patroniPGBinariesParameterName = "bin_dir"
patroniPGHBAConfParameterName = "pg_hba"
patroniPGIdentConfParameterName = "pg_ident"
localHost = "127.0.0.1/32"
scalyrSidecarName = "scalyr-sidecar"
logicalBackupContainerName = "logical-backup"
connectionPoolerContainer = "connection-pooler"
pgPort = 5432
operatorPort = 8080
)
type patroniDCS struct {
@ -469,12 +470,16 @@ PatroniInitDBParams:
config.Bootstrap.DCS.PGBootstrapConfiguration[constants.PatroniPGParametersParameterName] = bootstrap
}
}
// Patroni gives us a choice of writing pg_hba.conf to either the bootstrap section or to the local postgresql one.
// We choose the local one, because we need Patroni to change pg_hba.conf in PostgreSQL after the user changes the
// Patroni gives us a choice of writing pg_hba.conf and pg_ident.conf to either the bootstrap section or to the local postgresql one.
// We choose the local one, because we need Patroni to change them in PostgreSQL after the user changes the
// relevant section in the manifest.
if len(patroni.PgHba) > 0 {
config.PgLocalConfiguration[patroniPGHBAConfParameterName] = patroni.PgHba
}
if len(patroni.PgIdent) > 0 {
config.PgLocalConfiguration[patroniPGIdentConfParameterName] = patroni.PgIdent
}
res, err := json.Marshal(config)
return string(res), err

View File

@ -91,6 +91,7 @@ func TestGenerateSpiloJSONConfiguration(t *testing.T) {
"data-checksums": "true",
},
PgHba: []string{"hostssl all all 0.0.0.0/0 md5", "host all all 0.0.0.0/0 md5"},
PgIdent: []string{"mymap user1 dbuser1", "mymap user2 dbuser2"},
TTL: 30,
LoopWait: 10,
RetryTimeout: 10,
@ -102,7 +103,7 @@ func TestGenerateSpiloJSONConfiguration(t *testing.T) {
FailsafeMode: util.True(),
},
opConfig: &config.Config{},
result: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/18/bin","pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"]},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"},"data-checksums",{"encoding":"UTF8"},{"locale":"en_US.UTF-8"}],"dcs":{"ttl":30,"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"synchronous_mode":true,"synchronous_mode_strict":true,"synchronous_node_count":1,"slots":{"permanent_logical_1":{"database":"foo","plugin":"pgoutput","type":"logical"}},"failsafe_mode":true}}}`,
result: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/18/bin","pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"],"pg_ident":["mymap user1 dbuser1","mymap user2 dbuser2"]},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"},"data-checksums",{"encoding":"UTF8"},{"locale":"en_US.UTF-8"}],"dcs":{"ttl":30,"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"synchronous_mode":true,"synchronous_mode_strict":true,"synchronous_node_count":1,"slots":{"permanent_logical_1":{"database":"foo","plugin":"pgoutput","type":"logical"}},"failsafe_mode":true}}}`,
},
{
subtest: "Patroni failsafe_mode configured globally",

View File

@ -917,6 +917,9 @@ func (c *Cluster) checkAndSetGlobalPostgreSQLConfiguration(pod *v1.Pod, effectiv
if desiredPatroniConfig.PgHba != nil && !reflect.DeepEqual(desiredPatroniConfig.PgHba, effectivePatroniConfig.PgHba) {
configToSet["pg_hba"] = desiredPatroniConfig.PgHba
}
if desiredPatroniConfig.PgIdent != nil && !reflect.DeepEqual(desiredPatroniConfig.PgIdent, effectivePatroniConfig.PgIdent) {
configToSet["pg_ident"] = desiredPatroniConfig.PgIdent
}
if desiredPatroniConfig.RetryTimeout > 0 && desiredPatroniConfig.RetryTimeout != effectivePatroniConfig.RetryTimeout {
configToSet["retry_timeout"] = desiredPatroniConfig.RetryTimeout
}