Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ jobs:
helm repo add bitnami "https://charts.bitnami.com/bitnami"
helm dependency build .

- run:
name: Verify migration modes
command: |
if [[ $HELM_VERSION =~ ^v3\. ]]; then
bash ./tests/test-migration-modes.sh
fi

- run:
name: Generate test configuration
command: |
Expand Down
3 changes: 2 additions & 1 deletion .helmignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@
# Ignore development oriented files
.circleci/
scripts/
tests/test-migration-modes.sh
*.gotmpl
.restyled.yaml
.pre-commit-config.yaml

release/
release/
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 3.1.0

- Add an ordinary, wave-ordered database migration Job for Argo CD releases.
- Preserve the existing install and upgrade hooks for Helm releases.
- Allow Helm test Pods to be disabled for Argo CD rendering.

## 3.0.16

- Use `Recreate` for the scheduler Deployment.
Expand Down
2 changes: 1 addition & 1 deletion Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
apiVersion: v1
name: redash
version: 3.0.16
version: 3.1.0
appVersion: 11.0.0-next
description: Redash is an open source tool built for teams to query, visualize and collaborate.
keywords:
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ $ helm delete my-release

The command removes all the Kubernetes components associated with the chart and deletes the release.

## Database migrations

The default `helm-hooks` mode preserves existing Helm behavior. For an Argo
CD-managed release, use `argocd-job` to run one ordinary migration Job before
the Deployments. Retry a failed migration by syncing the application again.

## Requirements

| Repository | Name | Version |
Expand Down
6 changes: 6 additions & 0 deletions README.md.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ $ helm delete my-release

The command removes all the Kubernetes components associated with the chart and deletes the release.

## Database migrations

The default `helm-hooks` mode preserves existing Helm behavior. For an Argo
CD-managed release, use `argocd-job` to run one ordinary migration Job before
the Deployments. Retry a failed migration by syncing the application again.

{{ template "chart.requirementsSection" . }}

## Configuration
Expand Down
9 changes: 9 additions & 0 deletions templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ Create chart name and version as used by the chart label.
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/* Validate and return the database migration mode. */}}
{{- define "redash.migrationMode" -}}
{{- $mode := default "helm-hooks" .Values.migration.mode -}}
{{- if not (has $mode (list "helm-hooks" "argocd-job")) -}}
{{- fail "migration.mode must be one of helm-hooks or argocd-job" -}}
{{- end -}}
{{- $mode -}}
{{- end -}}

{{/*
Create a default fully qualified app name.
We truncate at 43 chars because some Kubernetes name fields are limited to 64 (by the DNS naming spec),
Expand Down
5 changes: 5 additions & 0 deletions templates/dua-server-deployment.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{{- if .Values.duaServer.enabled }}
{{- $migrationMode := include "redash.migrationMode" . }}
# Dedicated DUA server for long-lived /api/dua/* requests.
# Keep shared application settings aligned with server-deployment.yaml.
apiVersion: apps/v1
Expand All @@ -8,6 +9,10 @@ metadata:
labels:
{{- include "redash.labels" . | nindent 4 }}
app.kubernetes.io/component: dua-server
{{- if eq $migrationMode "argocd-job" }}
annotations:
argocd.argoproj.io/sync-wave: "2"
{{- end }}
spec:
replicas: {{ .Values.duaServer.replicaCount }}
strategy:
Expand Down
2 changes: 2 additions & 0 deletions templates/hook-install-job.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{{- if eq (include "redash.migrationMode" .) "helm-hooks" }}
apiVersion: batch/v1
kind: Job
metadata:
Expand Down Expand Up @@ -69,3 +70,4 @@ spec:
tolerations:
{{ toYaml . | indent 8 }}
{{- end }}
{{- end }}
2 changes: 2 additions & 0 deletions templates/hook-upgrade-job.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{{- if eq (include "redash.migrationMode" .) "helm-hooks" }}
apiVersion: batch/v1
kind: Job
metadata:
Expand Down Expand Up @@ -69,3 +70,4 @@ spec:
tolerations:
{{ toYaml . | indent 8 }}
{{- end }}
{{- end }}
76 changes: 76 additions & 0 deletions templates/migration-job.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{{- if eq (include "redash.migrationMode" .) "argocd-job" }}
apiVersion: batch/v1
kind: Job
metadata:
name: {{ printf "%s-db-migration" (include "redash.fullname" .) }}
labels:
{{- include "redash.labels" . | nindent 4 }}
app.kubernetes.io/component: database-migration
annotations:
argocd.argoproj.io/sync-wave: "1"
argocd.argoproj.io/sync-options: Force=true,Replace=true
spec:
backoffLimit: 0
template:
metadata:
labels:
{{- include "redash.selectorLabels" . | nindent 8 }}
app.kubernetes.io/component: database-migration
{{- with .Values.commonLabels }}
{{- tpl (toYaml .) $ | nindent 8 }}
{{- end }}
annotations:
sidecar.istio.io/inject: "false"
spec:
automountServiceAccountToken: false
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "redash.serviceAccountName" . }}
restartPolicy: Never
securityContext:
{{- toYaml .Values.hookUpgradeJob.podSecurityContext | nindent 8 }}
containers:
- name: database-migration
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
securityContext:
{{- toYaml .Values.hookUpgradeJob.securityContext | nindent 12 }}
command:
- /bin/bash
- -c
args:
- '. /config/dynamicenv.sh && exec /app/manage.py db upgrade'
volumeMounts:
- name: config
mountPath: /config
env:
{{- include "redash.env" . | nindent 12 }}
{{- range $key, $value := .Values.server.env }}
- name: {{ $key | quote }}
value: {{ $value | quote }}
{{- end }}
envFrom:
{{- include "redash.envFrom" . | nindent 12 }}
{{- with .Values.hookUpgradeJob.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
volumes:
- name: config
configMap:
name: {{ include "redash.fullname" . }}
{{- with .Values.hookUpgradeJob.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.hookUpgradeJob.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.hookUpgradeJob.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- end }}
5 changes: 5 additions & 0 deletions templates/scheduler-deployment.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
{{- if not .Values.skipSchedulerDeployment }}
{{- $migrationMode := include "redash.migrationMode" . }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "redash.scheduler.fullname" . }}
labels:
{{- include "redash.labels" . | nindent 4 }}
app.kubernetes.io/component: scheduler
{{- if eq $migrationMode "argocd-job" }}
annotations:
argocd.argoproj.io/sync-wave: "2"
{{- end }}
spec:
replicas: {{ .Values.scheduler.replicaCount }}
strategy:
Expand Down
5 changes: 5 additions & 0 deletions templates/server-deployment.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
{{- $migrationMode := include "redash.migrationMode" . }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "redash.fullname" . }}
labels:
{{- include "redash.labels" . | nindent 4 }}
app.kubernetes.io/component: server
{{- if eq $migrationMode "argocd-job" }}
annotations:
argocd.argoproj.io/sync-wave: "2"
{{- end }}
spec:
replicas: {{ .Values.server.replicaCount }}
strategy:
Expand Down
2 changes: 2 additions & 0 deletions templates/tests/test-connection.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{{- if .Values.tests.enabled }}
apiVersion: v1
kind: Pod
metadata:
Expand All @@ -14,3 +15,4 @@ spec:
command: ['sh']
args: ['-c', 'curl --silent --show-error -L --max-redirs 3 --retry 3 --retry-connrefused --retry-delay 10 --max-time 30 "http://{{ include "redash.fullname" . }}:{{ .Values.service.port }}" | fgrep "Welcome to Redash"']
restartPolicy: Never
{{- end }}
5 changes: 5 additions & 0 deletions templates/worker-deployment.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
{{ range $key, $worker := .Values.workers }}
{{- $migrationMode := include "redash.migrationMode" $ }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "redash.worker.fullname" (dict "root" $ "worker" $worker) }}
labels:
{{- include "redash.labels" $ | nindent 4 }}
app.kubernetes.io/component: {{ $worker.name }}
{{- if eq $migrationMode "argocd-job" }}
annotations:
argocd.argoproj.io/sync-wave: "2"
{{- end }}
spec:
replicas: {{ $worker.replicaCount }}
selector:
Expand Down
72 changes: 72 additions & 0 deletions tests/test-migration-modes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/env bash
set -euo pipefail

repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
tmp_dir="$(mktemp -d "${TMPDIR:-/tmp}/redash-chart-migrations.XXXXXX")"
trap 'rm -rf -- "$tmp_dir"' EXIT

base_args=(
--namespace default
--set postgresql.enabled=false
--set redis.enabled=false
--set-string externalPostgreSQL=postgresql://redash:password@postgresql:5432/redash
--set-string externalRedis=redis://redis:6379/0
--set redash.secretKey=test
--set redash.cookieSecret=test
)

default_render="$tmp_dir/default.yaml"
helm template redash "$repo_root" "${base_args[@]}" >"$default_render"
[[ "$(grep -c '^kind: Job$' "$default_render")" -eq 2 ]]
[[ "$(grep -c 'helm.sh/hook: post-' "$default_render")" -eq 2 ]]

legacy_render="$tmp_dir/legacy.yaml"
helm template redash "$repo_root/release/redash-3.0.16.tgz" \
"${base_args[@]}" >"$legacy_render"
sed -E 's/helm.sh\/chart: redash-[^[:space:]]+/helm.sh\/chart: redash-VERSION/' \
"$default_render" >"$tmp_dir/default-normalized.yaml"
sed -E 's/helm.sh\/chart: redash-[^[:space:]]+/helm.sh\/chart: redash-VERSION/' \
"$legacy_render" >"$tmp_dir/legacy-normalized.yaml"
diff -u "$tmp_dir/legacy-normalized.yaml" "$tmp_dir/default-normalized.yaml"

argo_render="$tmp_dir/argocd.yaml"
helm template redash "$repo_root" "${base_args[@]}" \
--set migration.mode=argocd-job \
--set tests.enabled=false >"$argo_render"

[[ "$(grep -c '^kind: Job$' "$argo_render")" -eq 1 ]]
grep -Fq 'name: redash-db-migration' "$argo_render"
grep -Fq 'argocd.argoproj.io/sync-wave: "1"' "$argo_render"
grep -Fq 'argocd.argoproj.io/sync-options: Force=true,Replace=true' "$argo_render"
grep -Fq '. /config/dynamicenv.sh && exec /app/manage.py db upgrade' "$argo_render"
grep -Fq 'sidecar.istio.io/inject: "false"' "$argo_render"
grep -Fq 'backoffLimit: 0' "$argo_render"

deployment_count="$(grep -c '^kind: Deployment$' "$argo_render")"
[[ "$deployment_count" -gt 0 ]]
[[ "$deployment_count" -eq "$(grep -c 'argocd.argoproj.io/sync-wave: \"2\"' "$argo_render")" ]]

if grep -Eq 'helm.sh/hook|argocd.argoproj.io/hook|^kind: Pod$|release-database|database-head|sha256:' "$argo_render"; then
echo "Argo CD migration mode rendered unsupported migration machinery" >&2
exit 1
fi

if helm template redash "$repo_root" "${base_args[@]}" \
--set migration.mode=disabled >"$tmp_dir/invalid.out" 2>"$tmp_dir/invalid.err"; then
echo "invalid migration mode unexpectedly rendered" >&2
exit 1
fi
grep -Fq 'migration.mode must be one of' "$tmp_dir/invalid.err"

builtin_postgresql_render="$tmp_dir/builtin-postgresql.yaml"
helm template redash "$repo_root" \
--namespace default \
--set redash.secretKey=test \
--set redash.cookieSecret=test \
--set-string postgresql.postgresqlPassword=test \
--set migration.mode=argocd-job \
--set tests.enabled=false >"$builtin_postgresql_render"
grep -Fq 'name: REDASH_DATABASE_HOSTNAME' "$builtin_postgresql_render"
grep -Fq '/app/manage.py db upgrade' "$builtin_postgresql_render"

echo "migration mode render tests passed"
8 changes: 8 additions & 0 deletions values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""

# migration.mode -- Database migration integration. Use helm-hooks for Helm releases or argocd-job for Argo CD.
migration:
mode: helm-hooks

# tests.enabled -- Render the Helm test Pod.
tests:
enabled: true

# commonLabels -- Labels applied to all chart resources and pod templates. Values are rendered as templates.
commonLabels: {}

Expand Down