Skip to content

fix(preview): the namespace outlived the PR - #6213

Merged
nicacioliveira merged 1 commit into
mainfrom
fix/preview-namespace-teardown
Aug 19, 2026
Merged

fix(preview): the namespace outlived the PR#6213
nicacioliveira merged 1 commit into
mainfrom
fix/preview-namespace-teardown

Conversation

@nicacioliveira

@nicacioliveira nicacioliveira commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Found tearing down #6205 by removing its label.

The cascade worked for everything inside the namespace — pods, Services, HTTPRoute, ExternalSecret, ConfigMaps, and the Postgres and MinIO holding the data. attachedRoutes went back to 0 and the URL returned 404.

The namespace itself stayed:

$ kubectl get ns studio-pr-6205
studio-pr-6205   Active   5h6m

ownerReferences: (none)
argocd tracking: (none)

Why

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 cannot reach it. This is documented Argo behaviour, not a bug in the sync.

The effect is one empty namespace per pull request that ever had a preview, accumulating with nothing to clean them up. Cheap individually, unbounded over time — and three files already promised the opposite:

  • deploy/preview/README.md: "its own namespace… all three are destroyed"
  • apps/studio-preview/README.md in the CD repo: "the Application, its namespace, its database and its bucket all go away"
  • the description of test: smoke-check the per-PR preview pipeline #6205 itself

Fix

The chart renders the Namespace at wave -40 — ahead of the ExternalSecret at -30, since everything else lives inside it. It is then owned like every other resource and deleted with them.

Second failure this removes

The namespace now carries the Gateway's selector label from the manifest. Route attachment previously depended on whoever creates the Application setting managedNamespaceMetadata correctly — which the troubleshooting guide names as the most likely cause of a silent 404 with a green Argo:

Almost always the namespace label. The Gateway's allowedRoutes.namespaces.from: Selector matches on namespace labels, and Argo's CreateNamespace=true does not label namespaces unless syncPolicy.managedNamespaceMetadata sets them.

The ApplicationSet still sets managedNamespaceMetadata as well, so the namespace is labelled on the very first sync, before the chart's own object is applied.

Assertion

helm-test.yml now checks that the preview render contains exactly one Namespace, at a wave earlier than -30, carrying a preview label. Verified against the pre-fix chart: it fails there and passes here.

Verification

  • Default render outside preview: 0 lines of difference against main.
  • helm lint clean.
  • preview.manageNamespace defaults to true but is gated on preview.enabled, so nothing outside previews renders a Namespace.

Cleanup

studio-pr-6205 is still around from the run that found this. Safe to delete by hand; the README now documents that, and any future one goes with its PR.

Chart 0.14.20.14.3.


Summary by cubic

Make preview namespaces part of the chart so they are created and deleted with the preview. Previously CreateNamespace=true created an unmanaged namespace that outlived the PR; now the chart renders and owns it. The namespace also carries the Gateway selector label, removing reliance on managedNamespaceMetadata and preventing silent 404s.

  • Adds a Namespace manifest rendered at sync wave -40 with preview labels; gated by preview.enabled and preview.manageNamespace (default true).
  • ApplicationSet injects preview.namespaceLabels from the Gateway selector and still sets managedNamespaceMetadata for the first sync.
  • CI asserts exactly one Namespace in the preview render, at wave < -30, with a preview label.
  • No changes outside previews; chart version 0.14.3.
  • Action: delete any existing orphan preview namespaces manually (older ones were not owned).

Written for commit aba4aa7. Summary will update on new commits.

Review in cubic

Argo's CreateNamespace=true creates a namespace without adopting it: no tracking
annotation, never part of the Application's resource tree. So a cascading delete
removed everything inside — pods, Services, HTTPRoute, ConfigMaps, and the
Postgres and MinIO holding the data — and left an empty namespace behind. One
per pull request that ever had a preview, accumulating quietly.

Observed removing the label from #6205: every resource gone, attachedRoutes back
to 0, the URL 404, and studio-pr-6205 still Active with no ownerReferences and no
argocd tracking-id.

The chart now renders the Namespace at wave -40, so it is owned like everything
else and deleted with them. Three README files promised this behaviour already;
it is now true.

It also carries the Gateway's selector label, which removes a second failure:
route attachment no longer depends on whoever creates the Application setting
managedNamespaceMetadata correctly — the omission the troubleshooting guide
calls the most likely cause of a silent 404.

Chart 0.14.2 -> 0.14.3.
@nicacioliveira
nicacioliveira merged commit dc312d2 into main Aug 19, 2026
31 of 32 checks passed
@nicacioliveira
nicacioliveira deleted the fix/preview-namespace-teardown branch August 19, 2026 02:05
nicacioliveira added a commit that referenced this pull request Aug 19, 2026
* fix(previews): bump to 0.1.1 so namespaceLabels actually ships

#6213 added namespaceLabels to the ApplicationSet template but only bumped the
studio chart. release-sandbox-charts.yaml skips the push when the version is
already published — correctly, since OCI tags should be immutable — so 0.1.0 in
the registry is still the version without it.

Without this the preview's Namespace renders with no gateway selector label and
the HTTPRoute attaches to nothing: a 404 with a green Argo, which is the exact
failure #6213 set out to make impossible.

* fix(ci): the preview render must pass the namespace labels the AppSet passes

The Namespace assertion added alongside the chart change reported exactly the
condition it was written for — a namespace with no gateway selector label — but
against the test render rather than a real one, because the step never supplied
preview.namespaceLabels.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant