From abf73bb5bf01e75c4d26783d79428e7f6ee22b17 Mon Sep 17 00:00:00 2001 From: unkin-agent Date: Sun, 30 Aug 2026 15:30:43 +1000 Subject: [PATCH] arrproxy: v0.6.0 self-migrating, drop external migrate Job (#444) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Why arrproxy v0.6.0 applies its own schema at startup under a Postgres advisory lock and holds `/readyz` until the schema is current, so every replica is safe to roll without an external gate. The wave-1 psql `arrproxy-migrate` Job and its SQL ConfigMap now only re-run idempotent statements the app already owns — dead weight, a second source of truth for the schema, and a standing drift trap whenever the app's embedded migrations move ahead of the manifests. ## How - Bump `arrproxy-api` and `arrproxy-ui` to `v0.6.0`. - Delete `migrate-job.yaml` and `migrations-configmap.yaml` and drop both from the arrproxy kustomization. - Keep the wave-0/wave-2 split: wave 2 still orders the api behind the wave-0 CNPG Cluster and VSO-synced Secrets, which is independent of the migrate Job; the stale "serve only after the wave-1 migrate Job" comment is corrected. - Rendered diff vs `main` is exactly the two image bumps plus the `arrproxy-migrate` Job and `arrproxy-migrations` ConfigMap disappearing; `kustomize build --enable-helm apps/overlays/au-syd1/arrstack` and pre-commit both clean. Reviewed-on: https://git.unkin.net/unkin/argocd-apps/pulls/444 Co-authored-by: unkin-agent Co-committed-by: unkin-agent --- .../arrstack/arrproxy/api-deployment.yaml | 6 +- .../base/arrstack/arrproxy/kustomization.yaml | 2 - apps/base/arrstack/arrproxy/migrate-job.yaml | 96 ------------------- .../arrproxy/migrations-configmap.yaml | 42 -------- .../base/arrstack/arrproxy/ui-deployment.yaml | 2 +- 5 files changed, 5 insertions(+), 143 deletions(-) delete mode 100644 apps/base/arrstack/arrproxy/migrate-job.yaml delete mode 100644 apps/base/arrstack/arrproxy/migrations-configmap.yaml diff --git a/apps/base/arrstack/arrproxy/api-deployment.yaml b/apps/base/arrstack/arrproxy/api-deployment.yaml index 3ccfba3..2d42b86 100644 --- a/apps/base/arrstack/arrproxy/api-deployment.yaml +++ b/apps/base/arrstack/arrproxy/api-deployment.yaml @@ -5,7 +5,9 @@ metadata: name: arrproxy-api namespace: arrstack annotations: - # Wave 2: serve only after the wave-1 migrate Job completes. + # Wave 2: start only after the wave-0 CNPG Cluster and VSO-synced Secrets + # exist. The api self-migrates at startup under a Postgres advisory lock and + # holds /readyz until the schema is current, so no migration ordering is needed. argocd.argoproj.io/sync-wave: "2" secret.reloader.stakater.com/reload: "arrproxy-pepper,arrproxy-admin-token,arrproxy-db-app,sonarr-adult-apikey,radarr-adult-apikey,sonarr-kids-apikey,radarr-kids-apikey" configmap.reloader.stakater.com/reload: "arrproxy-tiers" @@ -34,7 +36,7 @@ spec: type: RuntimeDefault containers: - name: api - image: artifactapi.k8s.syd1.au.unkin.net/docker-internal/arrproxy-api:v0.5.0 + image: artifactapi.k8s.syd1.au.unkin.net/docker-internal/arrproxy-api:v0.6.0 imagePullPolicy: IfNotPresent ports: - containerPort: 8080 diff --git a/apps/base/arrstack/arrproxy/kustomization.yaml b/apps/base/arrstack/arrproxy/kustomization.yaml index 778f2d2..c3b32d0 100644 --- a/apps/base/arrstack/arrproxy/kustomization.yaml +++ b/apps/base/arrstack/arrproxy/kustomization.yaml @@ -5,8 +5,6 @@ kind: Kustomization resources: - cnpg_cluster.yaml - cnpg_backup.yaml - - migrations-configmap.yaml - - migrate-job.yaml - vaultstaticsecret.yaml - tiers-configmap.yaml - oauth2-proxy-configmap.yaml diff --git a/apps/base/arrstack/arrproxy/migrate-job.yaml b/apps/base/arrstack/arrproxy/migrate-job.yaml deleted file mode 100644 index 69dbcb8..0000000 --- a/apps/base/arrstack/arrproxy/migrate-job.yaml +++ /dev/null @@ -1,96 +0,0 @@ ---- -# Applies the arrproxy schema once per sync, before the api rolls, so the serve -# replicas never race migrations (arrproxy-api does not self-migrate). Runs as the -# CNPG-minted app user so the tokens table is owned by that role. -# -# Sync-phase hook at wave 1 (NOT PreSync): the CNPG Cluster + generated -# arrproxy-db-app Secret apply at wave 0 and ArgoCD waits for the Cluster to be -# Healthy before starting wave 1, so Postgres exists before migrate connects. -apiVersion: batch/v1 -kind: Job -metadata: - name: arrproxy-migrate - namespace: arrstack - annotations: - argocd.argoproj.io/hook: Sync - argocd.argoproj.io/hook-delete-policy: BeforeHookCreation - argocd.argoproj.io/sync-wave: "1" -spec: - backoffLimit: 6 - ttlSecondsAfterFinished: 600 - template: - metadata: - labels: - app: arrproxy-migrate - spec: - serviceAccountName: default - automountServiceAccountToken: false - restartPolicy: Never - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - fsGroup: 65532 - seccompProfile: - type: RuntimeDefault - containers: - - name: migrate - image: docker.io/library/postgres:18-alpine - imagePullPolicy: IfNotPresent - env: - - name: HOME - value: /tmp - - name: PGUSER - valueFrom: - secretKeyRef: - name: arrproxy-db-app - key: username - - name: PGPASSWORD - valueFrom: - secretKeyRef: - name: arrproxy-db-app - key: password - - name: PGHOST - value: arrproxy-db-rw.arrstack.svc.cluster.local - - name: PGPORT - value: "5432" - - name: PGDATABASE - value: arrproxy - - name: PGSSLMODE - value: require - command: - - psql - - -v - - ON_ERROR_STOP=1 - - -f - - /migrations/0001_init.sql - - -f - - /migrations/0002_tier_tokens.sql - - -f - - /migrations/0003_token_methods.sql - volumeMounts: - - name: migrations - mountPath: /migrations - readOnly: true - - name: tmp - mountPath: /tmp - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - resources: - requests: - cpu: 100m - memory: 128Mi - limits: - cpu: 500m - memory: 256Mi - volumes: - - name: migrations - configMap: - name: arrproxy-migrations - - name: tmp - emptyDir: - sizeLimit: 64Mi diff --git a/apps/base/arrstack/arrproxy/migrations-configmap.yaml b/apps/base/arrstack/arrproxy/migrations-configmap.yaml deleted file mode 100644 index bb26dfc..0000000 --- a/apps/base/arrstack/arrproxy/migrations-configmap.yaml +++ /dev/null @@ -1,42 +0,0 @@ ---- -# arrproxy schema, mirrored from the arrproxy repo migrations/ (v0.5.0). -# arrproxy-api does NOT self-migrate, so the wave-1 migrate Job applies these in -# order once per sync as the app user. Every statement is idempotent, so a resync -# over an already-migrated database is a no-op. Keep in sync with the repo on -# schema bumps. -apiVersion: v1 -kind: ConfigMap -metadata: - name: arrproxy-migrations - namespace: arrstack - annotations: - argocd.argoproj.io/sync-wave: "0" -data: - 0001_init.sql: | - -- arrproxy token store. Only token hashes are persisted; plaintext is shown - -- once at mint time and never recoverable. - CREATE TABLE IF NOT EXISTS tokens ( - id TEXT PRIMARY KEY, - subject TEXT NOT NULL, - label TEXT NOT NULL DEFAULT '', - token_hash TEXT NOT NULL UNIQUE, - apps TEXT[] NOT NULL DEFAULT '{}', - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - expires_at TIMESTAMPTZ, - disabled BOOLEAN NOT NULL DEFAULT false, - last_used_at TIMESTAMPTZ - ); - - CREATE INDEX IF NOT EXISTS tokens_subject_idx ON tokens (subject); - CREATE INDEX IF NOT EXISTS tokens_token_hash_idx ON tokens (token_hash); - 0002_tier_tokens.sql: | - -- Tier-scoped virtual API keys. Existing rows (tier '') remain legacy per-app - -- tokens validated on the unprefixed routes; tier keys carry a tier name and, - -- for read-only tiers (kids), read_only=true so writes are rejected. - ALTER TABLE tokens ADD COLUMN IF NOT EXISTS tier TEXT NOT NULL DEFAULT ''; - ALTER TABLE tokens ADD COLUMN IF NOT EXISTS read_only BOOLEAN NOT NULL DEFAULT false; - 0003_token_methods.sql: | - -- Per-token HTTP method scoping. An empty list (the default every existing row - -- gets) means unrestricted, so tokens minted before this column behave exactly - -- as before; a non-empty list limits the token to those methods. - ALTER TABLE tokens ADD COLUMN IF NOT EXISTS methods TEXT[] NOT NULL DEFAULT '{}'; diff --git a/apps/base/arrstack/arrproxy/ui-deployment.yaml b/apps/base/arrstack/arrproxy/ui-deployment.yaml index 5a2ff91..aac4fe0 100644 --- a/apps/base/arrstack/arrproxy/ui-deployment.yaml +++ b/apps/base/arrstack/arrproxy/ui-deployment.yaml @@ -31,7 +31,7 @@ spec: type: RuntimeDefault containers: - name: ui - image: artifactapi.k8s.syd1.au.unkin.net/docker-internal/arrproxy-ui:v0.5.0 + image: artifactapi.k8s.syd1.au.unkin.net/docker-internal/arrproxy-ui:v0.6.0 imagePullPolicy: IfNotPresent ports: - containerPort: 8080