Skip to content

Commit

Permalink
fix(prefect-server): better support for internal and external databas…
Browse files Browse the repository at this point in the history
…e configs (#365)

* Create PostgreSQL Secret even if postgresql.enabled=false

Ensures that the PostgreSQL Secret is created, even if
`postgresql.enabled=false`. This ensures that we support a use case
where folks want to use an external instance of PostgreSQL, but still
want the Secret to automatically be generated with the proper connection
string.

With a recent change, we would skip creation of this secret if
PostgreSQL was disabled which forced users to create a Secret
themselves. This change now allows them to continue providing the `auth`
values and letting the chart build the Secret with the correct
connection string.

Closes #358

* Remove custom config from postgresql subchart

The `postgresql` key in `values.yaml` is for overriding the PostgreSQL
chart's default values. It's not a good place to define custom keys
because these are conflated with the actual configuration from the
subchart. This changes removes those custom configs.

It also removes any configured values that already matched the default
from the PostgreSQL subchart, and were therefore not doing anything.

* Support providing external connection string

When the PostgreSQL subchart is disabled, we need a way to provide the
connection string information for the external instance. This adds the
required values and template helpers to calculate the connection string
in this scenario.

* Support setting name and creation of Secret

- Supports setting the name to use for the Secret
- Supports controlling whether or not to create the Secret
- Supports someone providing their own existing Secret

* Add helm unit tests for database configuration

Uses https://github.com/helm-unittest/helm-unittest
to unit test the database configuration. This is a replacement
for coming up with test cases locally, running `helm template`, and
manually validating the output.

* Add script and CI workflow for helm-unittest

- Adds script to run helm-unittest locally
- Adds CI workflow to run helm-unittest in GitHub Actions

* Update README for new external db configuration

Updates the README to reflect the new configuration for external
databases.

* Add helm/chart-testing to mise

Installs the helm/chart-testing binary at its latest version.
Needed for the tests defined under `charts/<chart>/tests/test-*.yaml`.

* Mention how to run the `helm-unittest` helper
  • Loading branch information
mitchnielsen authored Aug 13, 2024
1 parent 25129d3 commit bfe341a
Show file tree
Hide file tree
Showing 12 changed files with 322 additions and 169 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/helm-unittest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# https://github.com/marketplace/actions/helm-unit-tests

name: Run Helm unit tests

on: pull_request

# Do not grant jobs any permissions by default
permissions: {}

jobs:
unittest:
runs-on: ubuntu-latest
permissions:
# required to read from the repo
contents: read
steps:
- uses: actions/checkout@v3
- uses: d3adb5/helm-unittest-action@v2
with:
helm-version: v3.15.3
1 change: 1 addition & 0 deletions .mise.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
helm-docs = '1.13.1'
pre-commit = '3.7.1'
helm = '3.15'
helm-ct = '3.11.0'
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,19 @@ Please make sure that your changes have been linted & the chart documentation ha
Make sure that any new functionality is well tested! You can do this by installing the chart locally, see [above](https://github.com/PrefectHQ/prefect-helm#installing-development-versions) for how to do this.
You can also create and run test suites via [helm-unittest](https://github.com/helm-unittest/helm-unittest).
Related test files are stored under `./charts/<chart>/tests/*_test.yaml`.
Refer to the `helm-unittest` repository for more information.
The following helper script will run the tests via the `helm-unittest` Docker image in case you don't have the binary installed locally:

```shell
./scripts/helm_unittest.sh
```

When `helm-unittest` is available via the [`mise` registry](https://mise.jdx.dev/registry.html), we'll add it to `.mise.toml`
for easy local installation.
### Opening a PR
A helpful PR explains WHAT changed and WHY the change is important. Please take time to make your PR descriptions as helpful as possible. If you are opening a PR from a forked repository - please follow [these](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) docs to allow `prefect-helm` maintainers to push commits to your local branch.
2 changes: 2 additions & 0 deletions charts/prefect-server/.helmignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@
.idea/
*.tmproj
.vscode/
# helm-unittest
tests
52 changes: 35 additions & 17 deletions charts/prefect-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,14 @@ Note: If you choose to make modifications to either the `server.prefectApiUrl` o

### Handling Connection Secrets

If you are installing the chart as-is (and therefore installing PostgreSQL) - you'll need to update one of two fields:
1. `postgresql.auth.password`: a password you want to set for the prefect user
#### Using the bundled PostgreSQL chart

By default, Bitnami's PostgreSQL Helm Chart will be deployed. This is **not intended for production use**, and is only
included to provide a functional proof of concept installation.

In this scenario, you'll need to provide _either one_ of the following fields:

1. `postgresql.auth.password`: a password you want to set for the prefect user (default: `prefect-rocks`)

2. `postgresql.auth.existingSecret`: name of an existing secret in your cluster with the following field:

Expand All @@ -38,24 +44,33 @@ If you are installing the chart as-is (and therefore installing PostgreSQL) - yo
- hostname = `<release-name>-postgresql.<release-namespace>:<postgresql.containerPorts.postgresql>`
- database = `postgresql.auth.database`

Two secrets are created when not providing an existing secret name:
1. `prefect-server-postgresql-connection`: used by the prefect-server deployment to connect to the postgresql database.

2. `<release-name>-postgresql-0`: defines the `postgresql.auth.username`'s password on the postgresql server to allow successful authentication from the prefect server.

#### Using an external instance of PostgreSQL

If you want to disable the bundled PostgreSQL chart and use an external instance, provide the following configuration:

```yaml
prefect-server:
postgresql:
# Disable the objects from the bundled PostgreSQL chart
enabled: false
auth:
# Provide the name of an existing secret following the instructions above.
existingSecret: <existing secret name>
```
Two secrets are created when not providing an existing secret name:
1. `prefect-server-postgresql-connection`: used by the prefect-server deployment to connect to the postgresql database.

2. `<release-name>-postgresql-0`: defines the `postgresql.auth.username`'s password on the postgresql server to allow successful authentication from the prefect server.

No secrets are created when providing an existing secret.
secret:
# Option 1: provide the name of an existing secret following the instructions above.
create: false
name: <existing secret name>

# Option 2: provide the connection string details directly
create: true
username: myuser
password: mypass
host: myhost.com
port: 1234
database: mydb
```
### Connecting with SSL configured
Expand Down Expand Up @@ -134,16 +149,19 @@ No secrets are created when providing an existing secret.
| namespaceOverride | string | `""` | fully override common.names.namespace |
| postgresql.auth.database | string | `"server"` | name for a custom database |
| postgresql.auth.enablePostgresUser | bool | `false` | determines whether an admin user is created within postgres |
| postgresql.auth.existingSecret | string | `""` | Name of existing secret to use for PostgreSQL credentials. |
| postgresql.auth.password | string | `"prefect-rocks"` | password for the custom user. Ignored if `auth.existingSecret` with key `password` is provided |
| postgresql.auth.username | string | `"prefect"` | name for a custom user |
| postgresql.containerPorts | object | `{"postgresql":5432}` | PostgreSQL container port |
| postgresql.enabled | bool | `true` | enable use of bitnami/postgresql subchart |
| postgresql.externalHostname | string | `""` | |
| postgresql.image.tag | string | `"14.3.0"` | Version tag, corresponds to tags at https://hub.docker.com/r/bitnami/postgresql/ |
| postgresql.primary.initdb.user | string | `"postgres"` | specify the PostgreSQL username to execute the initdb scripts |
| postgresql.primary.persistence.enabled | bool | `false` | enable PostgreSQL Primary data persistence using PVC |
| postgresql.primary.persistence.size | string | `"8Gi"` | PVC Storage Request for PostgreSQL volume |
| secret.create | bool | `true` | whether to create a Secret containing the PostgreSQL connection string |
| secret.database | string | `""` | database for the PostgreSQL connection string |
| secret.host | string | `""` | host for the PostgreSQL connection string |
| secret.name | string | `""` | name for the Secret containing the PostgreSQL connection string To provide an existing Secret, provide a name and set `create=false` |
| secret.password | string | `""` | password for the PostgreSQL connection string |
| secret.port | string | `""` | port for the PostgreSQL connection string |
| secret.username | string | `""` | username for the PostgreSQL connection string |
| server.affinity | object | `{}` | affinity for server pods assignment |
| server.autoscaling.enabled | bool | `false` | enable autoscaling for server |
| server.autoscaling.maxReplicas | int | `100` | maximum number of server replicas |
Expand Down
41 changes: 28 additions & 13 deletions charts/prefect-server/README.md.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,14 @@ Note: If you choose to make modifications to either the `server.prefectApiUrl` o

### Handling Connection Secrets

If you are installing the chart as-is (and therefore installing PostgreSQL) - you'll need to update one of two fields:
1. `postgresql.auth.password`: a password you want to set for the prefect user
#### Using the bundled PostgreSQL chart

By default, Bitnami's PostgreSQL Helm Chart will be deployed. This is **not intended for production use**, and is only
included to provide a functional proof of concept installation.

In this scenario, you'll need to provide _either one_ of the following fields:

1. `postgresql.auth.password`: a password you want to set for the prefect user (default: `prefect-rocks`)

2. `postgresql.auth.existingSecret`: name of an existing secret in your cluster with the following field:

Expand All @@ -37,24 +43,33 @@ If you are installing the chart as-is (and therefore installing PostgreSQL) - yo
- hostname = `<release-name>-postgresql.<release-namespace>:<postgresql.containerPorts.postgresql>`
- database = `postgresql.auth.database`

Two secrets are created when not providing an existing secret name:
1. `prefect-server-postgresql-connection`: used by the prefect-server deployment to connect to the postgresql database.

2. `<release-name>-postgresql-0`: defines the `postgresql.auth.username`'s password on the postgresql server to allow successful authentication from the prefect server.

#### Using an external instance of PostgreSQL

If you want to disable the bundled PostgreSQL chart and use an external instance, provide the following configuration:

```yaml
prefect-server:
postgresql:
# Disable the objects from the bundled PostgreSQL chart
enabled: false
auth:
# Provide the name of an existing secret following the instructions above.
existingSecret: <existing secret name>
```

Two secrets are created when not providing an existing secret name:
1. `prefect-server-postgresql-connection`: used by the prefect-server deployment to connect to the postgresql database.

2. `<release-name>-postgresql-0`: defines the `postgresql.auth.username`'s password on the postgresql server to allow successful authentication from the prefect server.

No secrets are created when providing an existing secret.
secret:
# Option 1: provide the name of an existing secret following the instructions above.
create: false
name: <existing secret name>

# Option 2: provide the connection string details directly
create: true
username: myuser
password: mypass
host: myhost.com
port: 1234
database: mydb
```

### Connecting with SSL configured

Expand Down
82 changes: 73 additions & 9 deletions charts/prefect-server/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,80 @@ Create the name of the service account to use
{{- end -}}
{{- end -}}

// ----- Connection string templates ------

{{/*
server.postgres-hostname:
Generate the hostname of the postgresql service
If a subchart is used, evaluate using its fullname function
as {subchart.fullname}-{namespace}
and append the namespace at the end.
Otherwise, the configured external hostname will be returned
*/}}
{{- define "server.postgres-hostname" -}}
{{- if .Values.postgresql.enabled -}}
{{- $subchart_overrides := .Values.postgresql -}}
{{- $name := include "postgresql.v1.primary.fullname" (dict "Values" $subchart_overrides "Chart" (dict "Name" "postgresql") "Release" .Release) -}}
{{- printf "%s.%s" $name .Release.Namespace -}}
{{- $subchart_overrides := .Values.postgresql -}}
{{- $name := include "postgresql.v1.primary.fullname" (dict "Values" $subchart_overrides "Chart" (dict "Name" "postgresql") "Release" .Release) -}}
{{- printf "%s.%s" $name .Release.Namespace -}}
{{- else -}}
{{- .Values.secret.host | required ".Values.secret.host is required." -}}
{{- end -}}
{{- end -}}

{{/*
server.postgres-port:
Generate the port of the postgresql service
If a subchart is used, evaluate using its port function
Otherwise, the configured port will be returned
*/}}
{{- define "server.postgres-port" -}}
{{- if .Values.postgresql.enabled -}}
{{- $subchart_overrides := .Values.postgresql -}}
{{- include "postgresql.v1.service.port" (dict "Values" $subchart_overrides) -}}
{{- else -}}
{{- .Values.secret.port | required ".Values.secret.port is required." -}}
{{- end -}}
{{- end -}}

{{/*
server.postgres-username:
Generate the username for postgresql
If a subchart is used, evaluate using its username function
Otherwise, the configured username will be returned
*/}}
{{- define "server.postgres-username" -}}
{{- if .Values.postgresql.enabled -}}
{{- $subchart_overrides := .Values.postgresql -}}
{{- include "postgresql.v1.username" (dict "Values" $subchart_overrides) -}}
{{- else -}}
{{- .Values.postgresql.externalHostname -}}
{{- .Values.secret.username | required ".Values.secret.username is required." -}}
{{- end -}}
{{- end -}}

{{/*
server.postgres-password:
Generate the password for postgresql
If a subchart is used, evaluate using its password value
Otherwise, the configured password will be returned
*/}}
{{- define "server.postgres-password" -}}
{{- if .Values.postgresql.enabled -}}
{{- .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required." -}}
{{- else -}}
{{- .Values.secret.password | required ".Values.secret.password is required." -}}
{{- end -}}
{{- end -}}

{{/*
server.postgres-database:
Generate the database for postgresql
If a subchart is used, evaluate using its database value
Otherwise, the configured database will be returned
*/}}
{{- define "server.postgres-database" -}}
{{- if .Values.postgresql.enabled -}}
{{- .Values.postgresql.auth.database | required ".Values.postgresql.auth.database is required." -}}
{{- else -}}
{{- .Values.secret.database | required ".Values.secret.database is required." -}}
{{- end -}}
{{- end -}}

Expand All @@ -31,11 +91,11 @@ Create the name of the service account to use
Generates the connection string for the postgresql service
*/}}
{{- define "server.postgres-connstr" -}}
{{- $user := .Values.postgresql.auth.username -}}
{{- $pass := .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required." -}}
{{- $user := include "server.postgres-username" . -}}
{{- $pass := include "server.postgres-password" . -}}
{{- $host := include "server.postgres-hostname" . -}}
{{- $port := .Values.postgresql.containerPorts.postgresql | toString -}}
{{- $db := .Values.postgresql.auth.database -}}
{{- $port := include "server.postgres-port" . -}}
{{- $db := include "server.postgres-database" . -}}
{{- printf "postgresql+asyncpg://%s:%s@%s:%s/%s" $user $pass $host $port $db -}}
{{- end -}}

Expand All @@ -48,12 +108,16 @@ Create the name of the service account to use
{{- define "server.postgres-string-secret-name" -}}
{{- if .Values.postgresql.auth.existingSecret -}}
{{- .Values.postgresql.auth.existingSecret -}}
{{- else if .Values.secret.name -}}
{{- .Values.secret.name -}}
{{- else -}}
{{- $name := include "common.names.fullname" . -}}
{{- printf "%s-%s" $name "postgresql-connection" -}}
{{- end -}}
{{- end -}}

// ----- End connection string templates -----

{{- define "server.uiUrl" -}}
{{- if .Values.server.uiConfig.prefectUiUrl -}}
{{- .Values.server.uiConfig.prefectUiUrl -}}
Expand Down
2 changes: 1 addition & 1 deletion charts/prefect-server/templates/secret.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{- if and .Values.postgresql.enabled (not .Values.postgresql.auth.existingSecret) }}
{{- if .Values.secret.create }}
apiVersion: v1
kind: Secret
metadata:
Expand Down
Loading

0 comments on commit bfe341a

Please sign in to comment.