Skip to content

Commit bc97666

Browse files
authored
feat: Allow specifying non-public schema for database (#271)
* feat: Allow specifying non-public schema for database * Make all * Add wrapper * Add unit tests
1 parent 0604e84 commit bc97666

File tree

5 files changed

+53
-0
lines changed

5 files changed

+53
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ View [our docs](https://coder.com/docs/setup/installation) for detailed installa
124124
| postgres.noPasswordEnv | bool | If enabled, passwordSecret will be specified as a volumeMount and the env `DB_PASSWORD_PATH` will be set instead to point to that location. The default behaviour is to set the environment variable `DB_PASSWORD` to the value of the postgres password secret. | `false` |
125125
| postgres.passwordSecret | string | Name of an existing secret in the current namespace with the password of the PostgreSQL instance. The password must be contained in the secret field `password`. This should be set to an empty string if the database does not require a password to connect. | `""` |
126126
| postgres.port | string | Port of the external PostgreSQL instance. | `""` |
127+
| postgres.searchPath | string | Optional. Schema for coder tables in the external PostgresSQL instance. This changes the 'search_path' client configuration option (https://www.postgresql.org/docs/current/runtime-config-client.html). By default, the 'public' schema will be used. | `""` |
127128
| postgres.ssl | object | Options for configuring the SSL cert, key, and root cert when connecting to Postgres. | `{"certSecret":{"key":"","name":""},"keySecret":{"key":"","name":""},"rootCertSecret":{"key":"","name":""}}` |
128129
| postgres.ssl.certSecret | object | Secret containing a PEM encoded cert file. | `{"key":"","name":""}` |
129130
| postgres.ssl.certSecret.key | string | Key pointing to a certificate in the secret. | `""` |

templates/_common.tpl

+4
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ storageClassName: {{ .Values.postgres.default.storageClassName | quote }}
4545
value: {{ .Values.postgres.sslMode | quote }}
4646
- name: DB_NAME
4747
value: {{ .Values.postgres.database | quote }}
48+
{{- if ne .Values.postgres.searchPath "" }}
49+
- name: DB_SEARCH_PATH
50+
value: {{ .Values.postgres.searchPath | quote }}
51+
{{- end }}
4852
{{- if ne .Values.postgres.ssl.certSecret.name "" }}
4953
- name: DB_CERT
5054
value: "/etc/ssl/certs/pg/cert/{{ .Values.postgres.ssl.certSecret.key }}"

tests/postgres_test.go

+42
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ func Test_PostgresNoPasswordEnv(t *testing.T) {
2323
cv.Postgres.Host = pointer.String("1.1.1.1")
2424
cv.Postgres.Port = pointer.String("5432")
2525
cv.Postgres.User = pointer.String("postgres")
26+
// Empty string is the same as no value
27+
cv.Postgres.SearchPath = pointer.String("")
2628

2729
cv.Postgres.Database = pointer.String("postgres")
2830
cv.Postgres.PasswordSecret = pointer.String("pg-pass")
@@ -40,7 +42,47 @@ func Test_PostgresNoPasswordEnv(t *testing.T) {
4042
assert.NotNil(t, env.ValueFrom.SecretKeyRef) &&
4143
assert.Equal(t, "pg-pass", env.ValueFrom.SecretKeyRef.Name)
4244
})
45+
46+
AssertNoEnvVar(t, c.Env, "DB_PASSWORD_PATH")
47+
AssertNoEnvVar(t, c.Env, "DB_SEARCH_PATH")
48+
AssertNoVolumeMount(t, c.VolumeMounts, "pg-pass")
49+
})
50+
}
51+
})
52+
53+
// Setting some extra pg vars
54+
t.Run("OffSomeVars", func(t *testing.T) {
55+
t.Parallel()
56+
57+
objs := LoadChart(t).MustRender(t, func(cv *CoderValues) {
58+
cv.Postgres.Default.Enable = pointer.Bool(false)
59+
60+
cv.Postgres.Host = pointer.String("1.1.1.1")
61+
cv.Postgres.Port = pointer.String("5432")
62+
cv.Postgres.User = pointer.String("postgres")
63+
cv.Postgres.SearchPath = pointer.String("custom_search")
64+
65+
cv.Postgres.Database = pointer.String("postgres")
66+
cv.Postgres.PasswordSecret = pointer.String("pg-pass")
67+
})
68+
coderd := MustFindDeployment(t, objs, "coderd")
69+
70+
for _, cnt := range []string{"migrations", "coderd"} {
71+
// Combine both init and regular containers.
72+
cnts := append(coderd.Spec.Template.Spec.InitContainers, coderd.Spec.Template.Spec.Containers...)
73+
74+
AssertContainer(t, cnts, cnt, func(t testing.TB, c corev1.Container) {
75+
AssertEnvVar(t, c.Env, "DB_PASSWORD", func(t testing.TB, env corev1.EnvVar) {
76+
_ = assert.Empty(t, env.Value) &&
77+
assert.NotNil(t, env.ValueFrom) &&
78+
assert.NotNil(t, env.ValueFrom.SecretKeyRef) &&
79+
assert.Equal(t, "pg-pass", env.ValueFrom.SecretKeyRef.Name)
80+
})
81+
4382
AssertNoEnvVar(t, c.Env, "DB_PASSWORD_PATH")
83+
AssertEnvVar(t, c.Env, "DB_SEARCH_PATH", func(t testing.TB, env corev1.EnvVar) {
84+
assert.Equal(t, "custom_search", env.Value)
85+
})
4486
AssertNoVolumeMount(t, c.VolumeMounts, "pg-pass")
4587
})
4688
}

tests/values.go

+1
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ type PostgresValues struct {
271271
User *string `json:"user" yaml:"user"`
272272
SSLMode *string `json:"sslMode" yaml:"sslMode"`
273273
Database *string `json:"database" yaml:"database"`
274+
SearchPath *string `json:"searchPath" yaml:"searchPath"`
274275
PasswordSecret *string `json:"passwordSecret" yaml:"passwordSecret"`
275276
Default *PostgresDefaultValues `json:"default" yaml:"default"`
276277
SSL *PostgresSSLValues `json:"ssl" yaml:"ssl"`

values.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,11 @@ postgres:
360360
# postgres.database -- Name of the database that Coder will use.
361361
# You must create this database first.
362362
database: ""
363+
# postgres.searchPath -- Optional. Schema for coder tables in the external
364+
# PostgresSQL instance. This changes the 'search_path' client configuration
365+
# option (https://www.postgresql.org/docs/current/runtime-config-client.html).
366+
# By default, the 'public' schema will be used.
367+
searchPath: ""
363368
# postgres.passwordSecret -- Name of an existing secret in the
364369
# current namespace with the password of the PostgreSQL instance.
365370
# The password must be contained in the secret field `password`.

0 commit comments

Comments
 (0)