From 5cb92dee4eb30dadaefa649739fed2973bfb3eb0 Mon Sep 17 00:00:00 2001 From: arch-err Date: Sat, 13 Jun 2026 03:42:09 +0200 Subject: [PATCH 1/3] fix: sync n8n app before namespace resources --- kubernetes/infra.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kubernetes/infra.yaml b/kubernetes/infra.yaml index e503c07..7e82d25 100644 --- a/kubernetes/infra.yaml +++ b/kubernetes/infra.yaml @@ -265,7 +265,11 @@ components: repo: https://bjw-s-labs.github.io/helm-charts name: app-template version: 4.6.2 - syncWave: "3" # after cnpg + infra base; db Cluster rendered by platform chart + # Must sync before parent-rendered n8n namespace resources (CNPG Cluster + # wave 0, OIDC Role/RoleBinding wave 9, HTTPRoute wave 10). The child app's + # CreateNamespace=true creates `n8n`; otherwise Argo can softlock trying to + # apply namespace-scoped resources before the namespace exists. + syncWave: "-1" db: enabled: true version: "16" From 8a7bdb2d93a218e977e6e480afe816dd3e9736d7 Mon Sep 17 00:00:00 2001 From: arch-err Date: Sat, 13 Jun 2026 14:06:47 +0200 Subject: [PATCH 2/3] fix: order platform prerequisites before app sync --- kubernetes/infra.yaml | 8 ++- .../platform/templates/applications.yaml | 12 ++++- .../platform/templates/db-postgres.yaml | 5 +- kubernetes/platform/templates/extras.yaml | 7 +++ kubernetes/platform/templates/namespaces.yaml | 50 +++++++++++++++++++ .../platform/templates/oidc-bootstrap.yaml | 12 +++-- 6 files changed, 82 insertions(+), 12 deletions(-) create mode 100644 kubernetes/platform/templates/namespaces.yaml diff --git a/kubernetes/infra.yaml b/kubernetes/infra.yaml index 7e82d25..0422b58 100644 --- a/kubernetes/infra.yaml +++ b/kubernetes/infra.yaml @@ -265,11 +265,9 @@ components: repo: https://bjw-s-labs.github.io/helm-charts name: app-template version: 4.6.2 - # Must sync before parent-rendered n8n namespace resources (CNPG Cluster - # wave 0, OIDC Role/RoleBinding wave 9, HTTPRoute wave 10). The child app's - # CreateNamespace=true creates `n8n`; otherwise Argo can softlock trying to - # apply namespace-scoped resources before the namespace exists. - syncWave: "-1" + # DB and OIDC prerequisites are parent-rendered before app consumers: + # namespaces wave -5, CNPG Cluster/OIDC Job wave 2, child app wave 3. + syncWave: "3" db: enabled: true version: "16" diff --git a/kubernetes/platform/templates/applications.yaml b/kubernetes/platform/templates/applications.yaml index ac18f53..a052229 100644 --- a/kubernetes/platform/templates/applications.yaml +++ b/kubernetes/platform/templates/applications.yaml @@ -9,7 +9,17 @@ metadata: finalizers: - resources-finalizer.argocd.argoproj.io annotations: - argocd.argoproj.io/sync-wave: {{ .syncWave | default "0" | quote }} + {{- /* + Components that consume parent-rendered prerequisites (CNPG db Secrets or + OIDC client Secrets) must not sync before those prerequisites. Explicit + syncWave wins; otherwise default those consumers to wave 3, after namespace + bootstrap (wave -5), OIDC RBAC (wave 1), DB/OIDC jobs (wave 2). + */}} + {{- $defaultWave := "0" }} + {{- if or (and .db .db.enabled) (and .oidc .oidc.enabled) }} + {{- $defaultWave = "3" }} + {{- end }} + argocd.argoproj.io/sync-wave: {{ .syncWave | default $defaultWave | quote }} spec: project: default sources: diff --git a/kubernetes/platform/templates/db-postgres.yaml b/kubernetes/platform/templates/db-postgres.yaml index bc43fe5..a56debd 100644 --- a/kubernetes/platform/templates/db-postgres.yaml +++ b/kubernetes/platform/templates/db-postgres.yaml @@ -88,7 +88,10 @@ metadata: name: {{ $clusterName }} namespace: {{ $appNs }} annotations: - argocd.argoproj.io/sync-wave: "0" + # Wave 2: after cnpg operator app/CRDs (wave 0) and kadalu storage (wave 1), + # before db-consuming child apps (default/explicit wave 3). + argocd.argoproj.io/sync-wave: "2" + argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true labels: app.kubernetes.io/managed-by: platform-chart app.kubernetes.io/component: db-postgres diff --git a/kubernetes/platform/templates/extras.yaml b/kubernetes/platform/templates/extras.yaml index 461d82e..b107a59 100644 --- a/kubernetes/platform/templates/extras.yaml +++ b/kubernetes/platform/templates/extras.yaml @@ -32,6 +32,8 @@ apiVersion: v1 kind: Namespace metadata: name: gateway-system + annotations: + argocd.argoproj.io/sync-wave: "-5" --- # L2 Announcement Policy apiVersion: cilium.io/v2alpha1 @@ -277,6 +279,8 @@ apiVersion: v1 kind: Namespace metadata: name: external + annotations: + argocd.argoproj.io/sync-wave: "-5" --- # Service pointing to Docker host apiVersion: v1 @@ -1363,6 +1367,8 @@ apiVersion: v1 kind: Namespace metadata: name: kadalu + annotations: + argocd.argoproj.io/sync-wave: "-5" labels: pod-security.kubernetes.io/enforce: privileged pod-security.kubernetes.io/audit: privileged @@ -1887,3 +1893,4 @@ data: {{- end }} {{- end }} + diff --git a/kubernetes/platform/templates/namespaces.yaml b/kubernetes/platform/templates/namespaces.yaml new file mode 100644 index 0000000..5b97000 --- /dev/null +++ b/kubernetes/platform/templates/namespaces.yaml @@ -0,0 +1,50 @@ +{{- /* +══════════════════════════════════════════════════════════════════════════════ +NAMESPACES — parent-owned namespace bootstrap +══════════════════════════════════════════════════════════════════════════════ + +The platform chart renders parent-owned resources into some component namespaces +(CNPG Cluster CRs, OIDC RBAC, HTTPRoutes). Those resources cannot rely on the +child ArgoCD Application's CreateNamespace=true when the child app syncs later +than its prerequisites. Create missing component namespaces early, but do not +re-render namespaces already owned by extras.yaml (many carry PSS annotations). +*/}} +{{- $seen := dict -}} +{{- $extrasOwned := dict + "audiobookshelf-v2" true + "booklore" true + "calibre-web" true + "external" true + "gateway-system" true + "hermes" true + "home-assistant" true + "immich" true + "jellyfin" true + "kadalu" true + "mattermost" true + "metube" true + "monitoring" true + "mqtt" true + "navidrome" true + "paperless-ngx" true + "qbittorrent" true + "samba" true + "sops-secrets-operator" true + "stirling-pdf" true + "zigbee2mqtt" true +-}} +{{- range $component := .Values.components }} +{{- $ns := ($component.namespace | default $component.name) }} +{{- if and (ne $ns "kube-system") (not (hasKey $extrasOwned $ns)) (not (hasKey $seen $ns)) }} +{{- $_ := set $seen $ns true }} +--- +apiVersion: v1 +kind: Namespace +metadata: + name: {{ $ns }} + annotations: + argocd.argoproj.io/sync-wave: "-5" + labels: + app.kubernetes.io/managed-by: platform-chart +{{- end }} +{{- end }} diff --git a/kubernetes/platform/templates/oidc-bootstrap.yaml b/kubernetes/platform/templates/oidc-bootstrap.yaml index 3c6dbe7..c639251 100644 --- a/kubernetes/platform/templates/oidc-bootstrap.yaml +++ b/kubernetes/platform/templates/oidc-bootstrap.yaml @@ -91,7 +91,7 @@ metadata: name: oidc-bootstrap-{{ $clientId }} namespace: pocket-id annotations: - argocd.argoproj.io/sync-wave: "9" + argocd.argoproj.io/sync-wave: "1" labels: app.kubernetes.io/managed-by: platform-chart app.kubernetes.io/component: oidc-bootstrap @@ -105,7 +105,7 @@ metadata: name: oidc-bootstrap-{{ $clientId }} namespace: {{ $appNs }} annotations: - argocd.argoproj.io/sync-wave: "9" + argocd.argoproj.io/sync-wave: "1" labels: app.kubernetes.io/managed-by: platform-chart app.kubernetes.io/component: oidc-bootstrap @@ -127,7 +127,7 @@ metadata: name: oidc-bootstrap-{{ $clientId }} namespace: {{ $appNs }} annotations: - argocd.argoproj.io/sync-wave: "9" + argocd.argoproj.io/sync-wave: "1" labels: app.kubernetes.io/managed-by: platform-chart app.kubernetes.io/component: oidc-bootstrap @@ -148,7 +148,7 @@ metadata: name: oidc-bootstrap-{{ $clientId }} namespace: pocket-id annotations: - argocd.argoproj.io/sync-wave: "9" + argocd.argoproj.io/sync-wave: "1" labels: app.kubernetes.io/managed-by: platform-chart app.kubernetes.io/component: oidc-bootstrap @@ -348,7 +348,9 @@ metadata: name: oidc-bootstrap-{{ $clientId }}-{{ $specHash }} namespace: pocket-id annotations: - argocd.argoproj.io/sync-wave: "11" + # Wave 2: after pocket-id app/namespace and OIDC RBAC (wave 1), before + # OIDC-consuming child apps (default/explicit wave 3). + argocd.argoproj.io/sync-wave: "2" # Replace=true was here historically but caused argocd re-syncs to faceplant on # completed Jobs (spec.selector is server-set + immutable post-create). Job names # already include $specHash so any spec change produces a NEW Job — replacement From 26f3df9f440cf958fcb5292f676ab5375cdb2e04 Mon Sep 17 00:00:00 2001 From: arch-err Date: Sat, 13 Jun 2026 15:47:57 +0200 Subject: [PATCH 3/3] Revert "fix: order platform prerequisites before app sync" This reverts commit 8a7bdb2d93a218e977e6e480afe816dd3e9736d7. --- kubernetes/infra.yaml | 8 +-- .../platform/templates/applications.yaml | 12 +---- .../platform/templates/db-postgres.yaml | 5 +- kubernetes/platform/templates/extras.yaml | 7 --- kubernetes/platform/templates/namespaces.yaml | 50 ------------------- .../platform/templates/oidc-bootstrap.yaml | 12 ++--- 6 files changed, 12 insertions(+), 82 deletions(-) delete mode 100644 kubernetes/platform/templates/namespaces.yaml diff --git a/kubernetes/infra.yaml b/kubernetes/infra.yaml index 0422b58..7e82d25 100644 --- a/kubernetes/infra.yaml +++ b/kubernetes/infra.yaml @@ -265,9 +265,11 @@ components: repo: https://bjw-s-labs.github.io/helm-charts name: app-template version: 4.6.2 - # DB and OIDC prerequisites are parent-rendered before app consumers: - # namespaces wave -5, CNPG Cluster/OIDC Job wave 2, child app wave 3. - syncWave: "3" + # Must sync before parent-rendered n8n namespace resources (CNPG Cluster + # wave 0, OIDC Role/RoleBinding wave 9, HTTPRoute wave 10). The child app's + # CreateNamespace=true creates `n8n`; otherwise Argo can softlock trying to + # apply namespace-scoped resources before the namespace exists. + syncWave: "-1" db: enabled: true version: "16" diff --git a/kubernetes/platform/templates/applications.yaml b/kubernetes/platform/templates/applications.yaml index a052229..ac18f53 100644 --- a/kubernetes/platform/templates/applications.yaml +++ b/kubernetes/platform/templates/applications.yaml @@ -9,17 +9,7 @@ metadata: finalizers: - resources-finalizer.argocd.argoproj.io annotations: - {{- /* - Components that consume parent-rendered prerequisites (CNPG db Secrets or - OIDC client Secrets) must not sync before those prerequisites. Explicit - syncWave wins; otherwise default those consumers to wave 3, after namespace - bootstrap (wave -5), OIDC RBAC (wave 1), DB/OIDC jobs (wave 2). - */}} - {{- $defaultWave := "0" }} - {{- if or (and .db .db.enabled) (and .oidc .oidc.enabled) }} - {{- $defaultWave = "3" }} - {{- end }} - argocd.argoproj.io/sync-wave: {{ .syncWave | default $defaultWave | quote }} + argocd.argoproj.io/sync-wave: {{ .syncWave | default "0" | quote }} spec: project: default sources: diff --git a/kubernetes/platform/templates/db-postgres.yaml b/kubernetes/platform/templates/db-postgres.yaml index a56debd..bc43fe5 100644 --- a/kubernetes/platform/templates/db-postgres.yaml +++ b/kubernetes/platform/templates/db-postgres.yaml @@ -88,10 +88,7 @@ metadata: name: {{ $clusterName }} namespace: {{ $appNs }} annotations: - # Wave 2: after cnpg operator app/CRDs (wave 0) and kadalu storage (wave 1), - # before db-consuming child apps (default/explicit wave 3). - argocd.argoproj.io/sync-wave: "2" - argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true + argocd.argoproj.io/sync-wave: "0" labels: app.kubernetes.io/managed-by: platform-chart app.kubernetes.io/component: db-postgres diff --git a/kubernetes/platform/templates/extras.yaml b/kubernetes/platform/templates/extras.yaml index b107a59..461d82e 100644 --- a/kubernetes/platform/templates/extras.yaml +++ b/kubernetes/platform/templates/extras.yaml @@ -32,8 +32,6 @@ apiVersion: v1 kind: Namespace metadata: name: gateway-system - annotations: - argocd.argoproj.io/sync-wave: "-5" --- # L2 Announcement Policy apiVersion: cilium.io/v2alpha1 @@ -279,8 +277,6 @@ apiVersion: v1 kind: Namespace metadata: name: external - annotations: - argocd.argoproj.io/sync-wave: "-5" --- # Service pointing to Docker host apiVersion: v1 @@ -1367,8 +1363,6 @@ apiVersion: v1 kind: Namespace metadata: name: kadalu - annotations: - argocd.argoproj.io/sync-wave: "-5" labels: pod-security.kubernetes.io/enforce: privileged pod-security.kubernetes.io/audit: privileged @@ -1893,4 +1887,3 @@ data: {{- end }} {{- end }} - diff --git a/kubernetes/platform/templates/namespaces.yaml b/kubernetes/platform/templates/namespaces.yaml deleted file mode 100644 index 5b97000..0000000 --- a/kubernetes/platform/templates/namespaces.yaml +++ /dev/null @@ -1,50 +0,0 @@ -{{- /* -══════════════════════════════════════════════════════════════════════════════ -NAMESPACES — parent-owned namespace bootstrap -══════════════════════════════════════════════════════════════════════════════ - -The platform chart renders parent-owned resources into some component namespaces -(CNPG Cluster CRs, OIDC RBAC, HTTPRoutes). Those resources cannot rely on the -child ArgoCD Application's CreateNamespace=true when the child app syncs later -than its prerequisites. Create missing component namespaces early, but do not -re-render namespaces already owned by extras.yaml (many carry PSS annotations). -*/}} -{{- $seen := dict -}} -{{- $extrasOwned := dict - "audiobookshelf-v2" true - "booklore" true - "calibre-web" true - "external" true - "gateway-system" true - "hermes" true - "home-assistant" true - "immich" true - "jellyfin" true - "kadalu" true - "mattermost" true - "metube" true - "monitoring" true - "mqtt" true - "navidrome" true - "paperless-ngx" true - "qbittorrent" true - "samba" true - "sops-secrets-operator" true - "stirling-pdf" true - "zigbee2mqtt" true --}} -{{- range $component := .Values.components }} -{{- $ns := ($component.namespace | default $component.name) }} -{{- if and (ne $ns "kube-system") (not (hasKey $extrasOwned $ns)) (not (hasKey $seen $ns)) }} -{{- $_ := set $seen $ns true }} ---- -apiVersion: v1 -kind: Namespace -metadata: - name: {{ $ns }} - annotations: - argocd.argoproj.io/sync-wave: "-5" - labels: - app.kubernetes.io/managed-by: platform-chart -{{- end }} -{{- end }} diff --git a/kubernetes/platform/templates/oidc-bootstrap.yaml b/kubernetes/platform/templates/oidc-bootstrap.yaml index c639251..3c6dbe7 100644 --- a/kubernetes/platform/templates/oidc-bootstrap.yaml +++ b/kubernetes/platform/templates/oidc-bootstrap.yaml @@ -91,7 +91,7 @@ metadata: name: oidc-bootstrap-{{ $clientId }} namespace: pocket-id annotations: - argocd.argoproj.io/sync-wave: "1" + argocd.argoproj.io/sync-wave: "9" labels: app.kubernetes.io/managed-by: platform-chart app.kubernetes.io/component: oidc-bootstrap @@ -105,7 +105,7 @@ metadata: name: oidc-bootstrap-{{ $clientId }} namespace: {{ $appNs }} annotations: - argocd.argoproj.io/sync-wave: "1" + argocd.argoproj.io/sync-wave: "9" labels: app.kubernetes.io/managed-by: platform-chart app.kubernetes.io/component: oidc-bootstrap @@ -127,7 +127,7 @@ metadata: name: oidc-bootstrap-{{ $clientId }} namespace: {{ $appNs }} annotations: - argocd.argoproj.io/sync-wave: "1" + argocd.argoproj.io/sync-wave: "9" labels: app.kubernetes.io/managed-by: platform-chart app.kubernetes.io/component: oidc-bootstrap @@ -148,7 +148,7 @@ metadata: name: oidc-bootstrap-{{ $clientId }} namespace: pocket-id annotations: - argocd.argoproj.io/sync-wave: "1" + argocd.argoproj.io/sync-wave: "9" labels: app.kubernetes.io/managed-by: platform-chart app.kubernetes.io/component: oidc-bootstrap @@ -348,9 +348,7 @@ metadata: name: oidc-bootstrap-{{ $clientId }}-{{ $specHash }} namespace: pocket-id annotations: - # Wave 2: after pocket-id app/namespace and OIDC RBAC (wave 1), before - # OIDC-consuming child apps (default/explicit wave 3). - argocd.argoproj.io/sync-wave: "2" + argocd.argoproj.io/sync-wave: "11" # Replace=true was here historically but caused argocd re-syncs to faceplant on # completed Jobs (spec.selector is server-set + immutable post-create). Job names # already include $specHash so any spec change produces a NEW Job — replacement