Skip to content

Commit 000db83

Browse files
committed
Allow users to configure CONFIG_DATABASE_URI setting in a Secret
This update allows users to configure the CONFIG_DATABASE_URI setting using a Secret rather than in plaintext in the PGAdmin manifest. - https://www.pgadmin.org/docs/pgadmin4/latest/external_database.html Issue: PGO-1130
1 parent 990631f commit 000db83

File tree

19 files changed

+324
-5
lines changed

19 files changed

+324
-5
lines changed

build/crd/pgadmins/todos.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,8 @@
1616
- op: copy
1717
from: /work
1818
path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/users/items/properties/passwordRef/properties/name/description
19+
- op: copy
20+
from: /work
21+
path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/config/properties/configDatabaseURI/properties/name/description
1922
- op: remove
2023
path: /work

config/crd/bases/postgres-operator.crunchydata.com_pgadmins.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,24 @@ spec:
860860
to any of these values will be loaded without validation. Be careful,
861861
as you may put pgAdmin into an unusable state.
862862
properties:
863+
configDatabaseURI:
864+
description: 'A Secret containing the value for the CONFIG_DATABASE_URI
865+
setting. More info: https://www.pgadmin.org/docs/pgadmin4/latest/external_database.html'
866+
properties:
867+
key:
868+
description: The key of the secret to select from. Must be
869+
a valid secret key.
870+
type: string
871+
name:
872+
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
873+
type: string
874+
optional:
875+
description: Specify whether the Secret or its key must be
876+
defined
877+
type: boolean
878+
required:
879+
- key
880+
type: object
863881
files:
864882
description: Files allows the user to mount projected volumes
865883
into the pgAdmin container so that files can be referenced by

internal/controller/standalone_pgadmin/pod.go

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const (
3131
configMountPath = "/etc/pgadmin/conf.d"
3232
configFilePath = "~postgres-operator/" + settingsConfigMapKey
3333
clusterFilePath = "~postgres-operator/" + settingsClusterMapKey
34+
configDatabaseURIPath = "~postgres-operator/config-database-uri"
3435
ldapFilePath = "~postgres-operator/ldap-bind-password"
3536
gunicornConfigFilePath = "~postgres-operator/" + gunicornConfigKey
3637

@@ -220,6 +221,21 @@ func podConfigFiles(configmap *corev1.ConfigMap, pgadmin v1beta1.PGAdmin) []core
220221
},
221222
}...)
222223

224+
if pgadmin.Spec.Config.ConfigDatabaseURI != nil {
225+
config = append(config, corev1.VolumeProjection{
226+
Secret: &corev1.SecretProjection{
227+
LocalObjectReference: pgadmin.Spec.Config.ConfigDatabaseURI.LocalObjectReference,
228+
Optional: pgadmin.Spec.Config.ConfigDatabaseURI.Optional,
229+
Items: []corev1.KeyToPath{
230+
{
231+
Key: pgadmin.Spec.Config.ConfigDatabaseURI.Key,
232+
Path: configDatabaseURIPath,
233+
},
234+
},
235+
},
236+
})
237+
}
238+
223239
// To enable LDAP authentication for pgAdmin, various LDAP settings must be configured.
224240
// While most of the required configuration can be set using the 'settings'
225241
// feature on the spec (.Spec.UserInterface.PGAdmin.Config.Settings), those
@@ -349,19 +365,23 @@ func startupCommand() []string {
349365
// - https://github.com/pgadmin-org/pgadmin4/blob/REL-7_7/docs/en_US/config_py.rst
350366
//
351367
// This command writes a script in `/etc/pgadmin/config_system.py` that reads from
352-
// the `pgadmin-settings.json` file and the `ldap-bind-password` file (if it exists)
353-
// and sets those variables globally. That way those values are available as pgAdmin
354-
// configurations when pgAdmin starts.
368+
// the `pgadmin-settings.json` file and the config-database-uri and/or
369+
// `ldap-bind-password` files (if either exists) and sets those variables globally.
370+
// That way those values are available as pgAdmin configurations when pgAdmin starts.
355371
//
356372
// Note: All pgAdmin settings are uppercase alphanumeric with underscores, so ignore
357373
// any keys/names that are not.
358374
//
359-
// Note: set pgAdmin's LDAP_BIND_PASSWORD setting from the Secret last
360-
// in order to overwrite configuration of LDAP_BIND_PASSWORD via ConfigMap JSON.
375+
// Note: set the pgAdmin LDAP_BIND_PASSWORD and CONFIG_DATABASE_URI settings from the
376+
// Secrets last in order to overwrite the respective configurations set via ConfigMap JSON.
377+
361378
const (
362379
// ldapFilePath is the path for mounting the LDAP Bind Password
363380
ldapPasswordAbsolutePath = configMountPath + "/" + ldapFilePath
364381

382+
// configDatabaseURIPath is the path for mounting the database URI connection string
383+
configDatabaseURIPathAbsolutePath = configMountPath + "/" + configDatabaseURIPath
384+
365385
configSystem = `
366386
import glob, json, re, os
367387
DEFAULT_BINARY_PATHS = {'pg': sorted([''] + glob.glob('/usr/pgsql-*/bin')).pop()}
@@ -372,6 +392,9 @@ with open('` + configMountPath + `/` + configFilePath + `') as _f:
372392
if os.path.isfile('` + ldapPasswordAbsolutePath + `'):
373393
with open('` + ldapPasswordAbsolutePath + `') as _f:
374394
LDAP_BIND_PASSWORD = _f.read()
395+
if os.path.isfile('` + configDatabaseURIPathAbsolutePath + `'):
396+
with open('` + configDatabaseURIPathAbsolutePath + `') as _f:
397+
CONFIG_DATABASE_URI = _f.read()
375398
`
376399
// gunicorn reads from the `/etc/pgadmin/gunicorn_config.py` file during startup
377400
// after all other config files.

internal/controller/standalone_pgadmin/pod_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ initContainers:
157157
if os.path.isfile('/etc/pgadmin/conf.d/~postgres-operator/ldap-bind-password'):
158158
with open('/etc/pgadmin/conf.d/~postgres-operator/ldap-bind-password') as _f:
159159
LDAP_BIND_PASSWORD = _f.read()
160+
if os.path.isfile('/etc/pgadmin/conf.d/~postgres-operator/config-database-uri'):
161+
with open('/etc/pgadmin/conf.d/~postgres-operator/config-database-uri') as _f:
162+
CONFIG_DATABASE_URI = _f.read()
160163
- |
161164
import json, re
162165
with open('/etc/pgadmin/conf.d/~postgres-operator/gunicorn-config.json') as _f:
@@ -336,6 +339,9 @@ initContainers:
336339
if os.path.isfile('/etc/pgadmin/conf.d/~postgres-operator/ldap-bind-password'):
337340
with open('/etc/pgadmin/conf.d/~postgres-operator/ldap-bind-password') as _f:
338341
LDAP_BIND_PASSWORD = _f.read()
342+
if os.path.isfile('/etc/pgadmin/conf.d/~postgres-operator/config-database-uri'):
343+
with open('/etc/pgadmin/conf.d/~postgres-operator/config-database-uri') as _f:
344+
CONFIG_DATABASE_URI = _f.read()
339345
- |
340346
import json, re
341347
with open('/etc/pgadmin/conf.d/~postgres-operator/gunicorn-config.json') as _f:

pkg/apis/postgres-operator.crunchydata.com/v1beta1/standalone_pgadmin_types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ type StandalonePGAdminConfiguration struct {
2626
// +optional
2727
Files []corev1.VolumeProjection `json:"files,omitempty"`
2828

29+
// A Secret containing the value for the CONFIG_DATABASE_URI setting.
30+
// More info: https://www.pgadmin.org/docs/pgadmin4/latest/external_database.html
31+
// +optional
32+
ConfigDatabaseURI *corev1.SecretKeySelector `json:"configDatabaseURI,omitempty"`
33+
2934
// Settings for the gunicorn server.
3035
// More info: https://docs.gunicorn.org/en/latest/settings.html
3136
// +optional

pkg/apis/postgres-operator.crunchydata.com/v1beta1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
apiVersion: kuttl.dev/v1beta1
2+
kind: TestStep
3+
apply:
4+
- files/00-cluster.yaml
5+
assert:
6+
- files/00-cluster-check.yaml
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
apiVersion: kuttl.dev/v1beta1
3+
kind: TestStep
4+
commands:
5+
# ensure the user schema is created for pgAdmin to use
6+
- script: |
7+
PRIMARY=$(
8+
kubectl get pod --namespace "${NAMESPACE}" \
9+
--output name --selector '
10+
postgres-operator.crunchydata.com/cluster=elephant,
11+
postgres-operator.crunchydata.com/role=master'
12+
)
13+
kubectl exec --namespace "${NAMESPACE}" "${PRIMARY}" \
14+
-- psql -qAt -d elephant --command 'CREATE SCHEMA elephant AUTHORIZATION elephant'
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
apiVersion: kuttl.dev/v1beta1
2+
kind: TestStep
3+
apply:
4+
- files/02-pgadmin.yaml
5+
assert:
6+
- files/02-pgadmin-check.yaml
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
apiVersion: kuttl.dev/v1beta1
2+
kind: TestAssert
3+
commands:
4+
- script: |
5+
PRIMARY=$(
6+
kubectl get pod --namespace "${NAMESPACE}" \
7+
--output name --selector '
8+
postgres-operator.crunchydata.com/cluster=elephant,
9+
postgres-operator.crunchydata.com/role=master'
10+
)
11+
12+
NUM_USERS=$(
13+
kubectl exec --namespace "${NAMESPACE}" "${PRIMARY}" -- \
14+
psql -qAt -d elephant --command 'select count(*) from elephant.user' \
15+
)
16+
17+
if [[ ${NUM_USERS} != 1 ]]; then
18+
echo >&2 'Expected 1 user'
19+
echo "got ${NUM_USERS}"
20+
exit 1
21+
fi

0 commit comments

Comments
 (0)