Skip to content

Commit 5929e95

Browse files
authored
add PostgreSQL preview schema setup and teardown actions (#7)
* add action to setup PostgreSQL preview schema for PRs * add action to teardown PostgreSQL preview schema for PRs * update readme with PostgreSQL preview schema actions * parameterize setup of PostgreSQL preview schema actions * parameterize teardown of PostgreSQL preview schema actions * update readme * adjust envsubst formatting for better readability * parameterize PostgreSQL schema teardown with improved env handling
1 parent 93be9cc commit 5929e95

5 files changed

Lines changed: 342 additions & 0 deletions

File tree

readme.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,59 @@ The following inputs can be used as `step.with` keys:
9090
| `timeout` | `5m` | The timeout for the Helm command |
9191
| `working-directory` | `.` | The working directory where the action commands will operate |
9292

93+
### Setup PostgreSQL Preview Schema
94+
95+
Sets up a PostgreSQL preview schema by cloning a base schema.
96+
97+
#### Example
98+
99+
```yaml
100+
- uses: aboutbits/github-actions-kubernetes/setup-postgres-preview-schema@v3
101+
with:
102+
deployment-name: my-app
103+
namespace: my-namespace
104+
preview-number: ${{ github.event.number }}
105+
```
106+
107+
#### Inputs
108+
109+
The following inputs can be used as `step.with` keys:
110+
111+
| Name | Required/Default | Description |
112+
|-------------------|------------------|--------------------------------------------|
113+
| `deployment-name` | required | Name of the deployment |
114+
| `namespace` | required | Kubernetes namespace |
115+
| `preview-number` | required | Preview number (PR number) |
116+
| `secret-name` | `app-secrets` | Name of the secret containing PostgreSQL password |
117+
| `postgres-image` | `postgres:18` | PostgreSQL image to use |
118+
| `base-schema` | `main` | Base schema to copy from |
119+
120+
### Teardown PostgreSQL Preview Schema
121+
122+
Drops the PostgreSQL preview schema.
123+
124+
#### Example
125+
126+
```yaml
127+
- uses: aboutbits/github-actions-kubernetes/teardown-postgres-preview-schema@v3
128+
with:
129+
deployment-name: my-app
130+
namespace: my-namespace
131+
preview-number: ${{ github.event.number }}
132+
```
133+
134+
#### Inputs
135+
136+
The following inputs can be used as `step.with` keys:
137+
138+
| Name | Required/Default | Description |
139+
|-------------------|------------------|--------------------------------------------|
140+
| `deployment-name` | required | Name of the deployment |
141+
| `namespace` | required | Kubernetes namespace |
142+
| `preview-number` | required | Preview number (PR number) |
143+
| `secret-name` | `app-secrets` | Name of the secret containing PostgreSQL password |
144+
| `postgres-image` | `postgres:18` | PostgreSQL image to use |
145+
93146
## Build & Publish
94147

95148
To build and publish the action, visit the GitHub Actions page of the repository and trigger the workflow "Release Package" manually.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
name: 'Setup PostgreSQL Preview Schema'
2+
description: 'Sets up a PostgreSQL preview schema by cloning a base schema'
3+
inputs:
4+
deployment-name:
5+
description: 'Name of the deployment (used for ConfigMap name)'
6+
required: true
7+
namespace:
8+
description: 'Kubernetes namespace'
9+
required: true
10+
preview-number:
11+
description: 'Preview number (PR number)'
12+
required: true
13+
secret-name:
14+
description: 'Name of the secret containing DB password'
15+
required: false
16+
default: 'app-secrets'
17+
postgres-image:
18+
description: 'PostgreSQL image to use'
19+
required: false
20+
default: 'postgres:18'
21+
base-schema:
22+
description: 'Base schema to copy from'
23+
required: false
24+
default: 'main'
25+
26+
runs:
27+
using: "composite"
28+
steps:
29+
- name: Prepare setup-schema job
30+
env:
31+
JOB_NAME: "prepare-schema-preview-${{ inputs.preview-number }}"
32+
CONFIGMAP_NAME: "${{ inputs.deployment-name }}-environments"
33+
SECRET_NAME: "${{ inputs.secret-name }}"
34+
PREVIEW_SCHEMA_NAME: "preview_${{ inputs.preview-number }}"
35+
POSTGRES_IMAGE: "${{ inputs.postgres-image }}"
36+
BASE_SCHEMA: "${{ inputs.base-schema }}"
37+
run: |
38+
envsubst '
39+
$JOB_NAME
40+
$CONFIGMAP_NAME
41+
$SECRET_NAME
42+
$PREVIEW_SCHEMA_NAME
43+
$POSTGRES_IMAGE
44+
$BASE_SCHEMA
45+
' < ${{ github.action_path }}/job-template.yml > job-setup-schema.yml
46+
47+
echo "Prepared job manifest: job-setup-schema.yml"
48+
shell: bash
49+
50+
- name: Create setup-schema job
51+
run: |
52+
kubectl apply --namespace ${{ inputs.namespace }} -f job-setup-schema.yml
53+
shell: bash
54+
55+
- name: Wait for setup-schema job to complete
56+
env:
57+
JOB_NAME: "prepare-schema-preview-${{ inputs.preview-number }}"
58+
NAMESPACE: "${{ inputs.namespace }}"
59+
run: |
60+
echo "Waiting for job $JOB_NAME in namespace $NAMESPACE..."
61+
62+
if kubectl wait --namespace $NAMESPACE --for=condition=complete --timeout=60s job/$JOB_NAME; then
63+
echo "Job finished with status: Complete"
64+
kubectl logs job/$JOB_NAME --namespace $NAMESPACE
65+
elif kubectl wait --namespace $NAMESPACE --for=condition=failed --timeout=1s job/$JOB_NAME; then
66+
echo "Job finished with status: Failed"
67+
kubectl logs job/$JOB_NAME --namespace $NAMESPACE
68+
exit 1
69+
else
70+
echo "Timeout waiting for job to complete."
71+
kubectl logs job/$JOB_NAME --namespace $NAMESPACE || true
72+
exit 1
73+
fi
74+
shell: bash
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
apiVersion: batch/v1
2+
kind: Job
3+
metadata:
4+
name: ${JOB_NAME}
5+
labels:
6+
app.kubernetes.io/managed-by: github-actions
7+
app.kubernetes.io/component: database-schema-setup
8+
spec:
9+
ttlSecondsAfterFinished: 60
10+
template:
11+
spec:
12+
restartPolicy: Never
13+
containers:
14+
- name: prepare-preview-schema
15+
image: ${POSTGRES_IMAGE}
16+
command: [ "bash", "-c" ]
17+
args:
18+
- |
19+
set -e
20+
21+
echo "### START $(date --iso-8601=seconds) ###"
22+
23+
if psql -t -A -c "SELECT 1 FROM information_schema.schemata WHERE schema_name = '${PREVIEW_SCHEMA_NAME}'" | grep -q 1; then
24+
echo "Schema ${PREVIEW_SCHEMA_NAME} already exists. Skipping setup."
25+
echo "Script finished successfully!"
26+
echo "### END $(date --iso-8601=seconds) ###"
27+
exit 0
28+
fi
29+
30+
echo "Dumping base schema ${BASE_SCHEMA}..."
31+
pg_dump --schema=${BASE_SCHEMA} \
32+
--no-comments \
33+
--no-owner \
34+
--no-acl \
35+
--quote-all-identifiers \
36+
--format=plain \
37+
--file=preview-dump.sql
38+
39+
echo "Modifying dump file..."
40+
sed -i preview-dump.sql \
41+
-e "s/\"${BASE_SCHEMA}\"/\"${PREVIEW_SCHEMA_NAME}\"/g" \
42+
-e 's/SET /--SET /g' \
43+
-e 's/SELECT pg_catalog/--SELECT pg_catalog/g' \
44+
-e 's/--SELECT pg_catalog.setval/SELECT pg_catalog.setval/g'
45+
46+
echo "Creating schema ${PREVIEW_SCHEMA_NAME} with modified dump file..."
47+
psql --echo-queries \
48+
--echo-errors \
49+
--single-transaction \
50+
--set=ON_ERROR_STOP=1 \
51+
--set=SESSION_REPLICATION_ROLE=replica \
52+
--file=preview-dump.sql
53+
54+
echo "Script finished successfully!"
55+
echo "### END $(date --iso-8601=seconds) ###"
56+
env:
57+
- name: PGHOST
58+
valueFrom:
59+
configMapKeyRef:
60+
name: ${CONFIGMAP_NAME}
61+
key: DB_HOST
62+
- name: PGPORT
63+
valueFrom:
64+
configMapKeyRef:
65+
name: ${CONFIGMAP_NAME}
66+
key: DB_PORT
67+
- name: PGDATABASE
68+
valueFrom:
69+
configMapKeyRef:
70+
name: ${CONFIGMAP_NAME}
71+
key: DB_NAME
72+
- name: PGSCHEMA
73+
valueFrom:
74+
configMapKeyRef:
75+
name: ${CONFIGMAP_NAME}
76+
key: DB_SCHEMA
77+
- name: PGUSER
78+
valueFrom:
79+
configMapKeyRef:
80+
name: ${CONFIGMAP_NAME}
81+
key: DB_USERNAME
82+
- name: PGPASSWORD
83+
valueFrom:
84+
secretKeyRef:
85+
name: ${SECRET_NAME}
86+
key: DB_PASSWORD
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
name: 'Teardown PostgreSQL Preview Schema'
2+
description: 'Drops the PostgreSQL preview schema'
3+
inputs:
4+
deployment-name:
5+
description: 'Name of the deployment (used for ConfigMap name)'
6+
required: true
7+
namespace:
8+
description: 'Kubernetes namespace'
9+
required: true
10+
preview-number:
11+
description: 'Preview number (PR number)'
12+
required: true
13+
secret-name:
14+
description: 'Name of the secret containing DB password'
15+
required: false
16+
default: 'app-secrets'
17+
postgres-image:
18+
description: 'PostgreSQL image to use'
19+
required: false
20+
default: 'postgres:18'
21+
22+
runs:
23+
using: "composite"
24+
steps:
25+
- name: Prepare teardown-schema job
26+
env:
27+
JOB_NAME: "drop-schema-preview-${{ inputs.preview-number }}"
28+
CONFIGMAP_NAME: "${{ inputs.deployment-name }}-environments"
29+
SECRET_NAME: "${{ inputs.secret-name }}"
30+
PREVIEW_SCHEMA_NAME: "preview_${{ inputs.preview-number }}"
31+
POSTGRES_IMAGE: "${{ inputs.postgres-image }}"
32+
run: |
33+
envsubst '
34+
$JOB_NAME
35+
$CONFIGMAP_NAME
36+
$SECRET_NAME
37+
$PREVIEW_SCHEMA_NAME
38+
$POSTGRES_IMAGE
39+
' < ${{ github.action_path }}/job-template.yml > job-teardown-schema.yml
40+
41+
echo "Prepared job manifest: job-teardown-schema.yml"
42+
shell: bash
43+
44+
- name: Create teardown-schema job
45+
run: |
46+
kubectl apply --namespace ${{ inputs.namespace }} -f job-teardown-schema.yml
47+
shell: bash
48+
49+
- name: Wait for teardown-schema job to complete
50+
env:
51+
JOB_NAME: "drop-schema-preview-${{ inputs.preview-number }}"
52+
NAMESPACE: "${{ inputs.namespace }}"
53+
run: |
54+
echo "Waiting for job $JOB_NAME in namespace $NAMESPACE..."
55+
56+
if kubectl wait --namespace $NAMESPACE --for=condition=complete --timeout=60s job/$JOB_NAME; then
57+
echo "Job finished with status: Complete"
58+
kubectl logs job/$JOB_NAME --namespace $NAMESPACE
59+
elif kubectl wait --namespace $NAMESPACE --for=condition=failed --timeout=1s job/$JOB_NAME; then
60+
echo "Job finished with status: Failed"
61+
kubectl logs job/$JOB_NAME --namespace $NAMESPACE
62+
exit 1
63+
else
64+
echo "Timeout waiting for job to complete."
65+
kubectl logs job/$JOB_NAME --namespace $NAMESPACE || true
66+
exit 1
67+
fi
68+
shell: bash
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
apiVersion: batch/v1
2+
kind: Job
3+
metadata:
4+
name: ${JOB_NAME}
5+
labels:
6+
app.kubernetes.io/managed-by: github-actions
7+
app.kubernetes.io/component: database-schema-teardown
8+
spec:
9+
ttlSecondsAfterFinished: 60
10+
template:
11+
spec:
12+
restartPolicy: Never
13+
containers:
14+
- name: drop-preview-schema
15+
image: ${POSTGRES_IMAGE}
16+
command: [ "bash", "-c" ]
17+
args:
18+
- |
19+
set -e
20+
21+
echo "### START $(date --iso-8601=seconds) ###"
22+
echo "Drop schema ${PREVIEW_SCHEMA_NAME}..."
23+
psql --echo-queries \
24+
--echo-errors \
25+
--single-transaction \
26+
--set=ON_ERROR_STOP=1 \
27+
--command="drop schema if exists ${PREVIEW_SCHEMA_NAME} cascade;"
28+
29+
echo "Script finished successfully!"
30+
echo "### END $(date --iso-8601=seconds) ###"
31+
env:
32+
- name: PGHOST
33+
valueFrom:
34+
configMapKeyRef:
35+
name: ${CONFIGMAP_NAME}
36+
key: DB_HOST
37+
- name: PGPORT
38+
valueFrom:
39+
configMapKeyRef:
40+
name: ${CONFIGMAP_NAME}
41+
key: DB_PORT
42+
- name: PGDATABASE
43+
valueFrom:
44+
configMapKeyRef:
45+
name: ${CONFIGMAP_NAME}
46+
key: DB_NAME
47+
- name: PGSCHEMA
48+
valueFrom:
49+
configMapKeyRef:
50+
name: ${CONFIGMAP_NAME}
51+
key: DB_SCHEMA
52+
- name: PGUSER
53+
valueFrom:
54+
configMapKeyRef:
55+
name: ${CONFIGMAP_NAME}
56+
key: DB_USERNAME
57+
- name: PGPASSWORD
58+
valueFrom:
59+
secretKeyRef:
60+
name: ${SECRET_NAME}
61+
key: DB_PASSWORD

0 commit comments

Comments
 (0)