Skip to content
Merged
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
23 changes: 23 additions & 0 deletions .github/workflows/helm-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,29 @@ jobs:

fail() { echo "::error::$1"; exit 1; }

# Without a Namespace in the render, Argo's CreateNamespace=true creates
# one it never adopts: everything inside is deleted correctly and the
# namespace itself is left behind, one per PR, forever.
grep -q '^kind: Namespace' /tmp/preview.yaml \
|| fail "preview render has no Namespace — it would outlive the PR"
python3 - <<'NS'
import sys, yaml
ns = [d for d in yaml.safe_load_all(open("/tmp/preview.yaml"))
if d and d["kind"] == "Namespace"]
if len(ns) != 1:
print(f"::error::expected exactly one Namespace, found {len(ns)}"); sys.exit(1)
m = ns[0]["metadata"]
w = int((m.get("annotations") or {}).get("argocd.argoproj.io/sync-wave", 0))
if w >= -30:
print(f"::error::Namespace is at wave {w}, but everything lives inside it "
"— it must come before the ExternalSecret at -30"); sys.exit(1)
if not any(k.endswith("/preview") for k in (m.get("labels") or {})):
print("::error::Namespace carries no preview label — the Gateway admits "
"routes by namespace label, so the HTTPRoute would attach to nothing")
sys.exit(1)
print(f"namespace rendered at wave {w} with the gateway selector label")
NS

grep -q 'kind: HTTPRoute' /tmp/preview.yaml \
|| fail "preview render has no HTTPRoute — the preview would be unreachable"
grep -q 'pr-42.pr.studio.decocms.com' /tmp/preview.yaml \
Expand Down
7 changes: 7 additions & 0 deletions deploy/helm/studio-previews/templates/applicationset.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ spec:
tag: '{{ include "studio-previews.imageTag" . }}'
preview:
prNumber: '{{ `{{ .number }}` }}'
# The chart renders the namespace itself, so the label the
# Gateway selects on travels with the manifest instead of
# depending on managedNamespaceMetadata below. Both are set:
# the metadata still labels the namespace on the first sync,
# before the chart's own object is applied.
namespaceLabels:
{{ .Values.gateway.namespaceSelectorLabel }}: "true"
host: '{{ include "studio-previews.host" . }}'
gateway:
name: {{ .Values.gateway.name }}
Expand Down
8 changes: 7 additions & 1 deletion deploy/helm/studio/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ apiVersion: v2
name: chart-deco-studio
description: Helm chart for deco Studio — supports inline secrets, external secretName, and AWS Secrets Manager via ExternalSecret
type: application
# 0.14.3: the preview renders its own Namespace (preview.manageNamespace).
# CreateNamespace=true creates one without adopting it, so a cascading delete
# removed everything inside and left the namespace behind — one per pull request
# that ever had a preview. It also carries the Gateway's selector label now, so
# route attachment no longer depends on managedNamespaceMetadata.
#
# 0.14.2: optional hosted sandboxes for previews (preview.sandbox.enabled,
# default false). Renders one RoleBinding when on, nothing when off. Read the
# note in templates/preview-sandbox-rbac.yaml before enabling: the namespace it
Expand Down Expand Up @@ -32,7 +38,7 @@ type: application
# when disabled, so existing releases are unaffected.
# 0.12.4: chart-managed API/worker dispatch roles now use
# STUDIO_DISPATCH_ROLE; legacy overrides are rejected.
version: 0.14.2
version: 0.14.3
appVersion: "latest"

dependencies:
Expand Down
31 changes: 31 additions & 0 deletions deploy/helm/studio/templates/preview-namespace.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{{- if and .Values.preview.enabled .Values.preview.manageNamespace }}
{{- /*
The preview's own namespace, rendered by the chart rather than conjured by
Argo's CreateNamespace=true.

CreateNamespace=true creates a namespace but does not adopt it: the object gets
no tracking annotation and never joins the Application's resource tree, so a
cascading delete leaves it behind. Everything inside is removed correctly — pods,
Services, HTTPRoute, ConfigMaps, the Postgres and MinIO that hold the data — and
an empty namespace stays for every pull request that ever had a preview.

Rendering it here puts it under the same ownership as everything else, so it is
deleted with them. It also carries its own labels, which means the Gateway's
namespace selector no longer depends on managedNamespaceMetadata being set
correctly by whatever creates the Application — the failure that produces a
silent 404 with a green Argo.

Wave -40: before the ExternalSecret at -30, since everything else is inside it.
*/ -}}
apiVersion: v1
kind: Namespace
metadata:
name: {{ .Release.Namespace }}
labels:
{{- include "chart-deco-studio.labels" . | nindent 4 }}
{{- with .Values.preview.namespaceLabels }}
{{- toYaml . | nindent 4 }}
{{- end }}
annotations:
argocd.argoproj.io/sync-wave: "-40"
{{- end }}
2 changes: 2 additions & 0 deletions deploy/helm/studio/values-preview.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

preview:
enabled: true
# namespaceLabels is injected by the studio-previews ApplicationSet — it is
# the one that knows which label the Gateway selects on.
# prNumber / host injected per PR by the ApplicationSet.
gateway:
name: studio-preview
Expand Down
15 changes: 15 additions & 0 deletions deploy/helm/studio/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,21 @@ preview:
limits:
memory: "768Mi"

# Render the preview's namespace as part of the release.
#
# Argo's CreateNamespace=true creates a namespace without adopting it: no
# tracking annotation, never in the Application's resource tree, so a
# cascading delete leaves it behind. Everything inside is removed correctly,
# and an empty namespace accumulates for every PR that ever had a preview.
#
# Set false when something else owns the namespace.
manageNamespace: true
# Labels the namespace carries. The Gateway admits routes by namespace label,
# so this is what makes the HTTPRoute attach — putting it here means it no
# longer depends on the Application being created with the matching
# managedNamespaceMetadata, which is the omission that yields a silent 404.
namespaceLabels: {}

# Hosted agent sandboxes for a preview. OFF by default, and it should stay off
# unless someone is actively testing agent behaviour.
#
Expand Down
Loading