Skip to content

feat(concourse): switch remaining Pulumi pipelines to preview-gated topology - #5600

Open
blarghmatey wants to merge 4 commits into
mainfrom
preview-gated-pipelines
Open

feat(concourse): switch remaining Pulumi pipelines to preview-gated topology#5600
blarghmatey wants to merge 4 commits into
mainfrom
preview-gated-pipelines

Conversation

@blarghmatey

Copy link
Copy Markdown
Member

What are the relevant tickets?

N/A

Description (What does it do?)

Switches every remaining Pulumi Concourse pipeline in src/ol_concourse/pipelines/ from the default deploy-chained topology to preview-gated, matching the pattern already adopted by edx_platform_v3, keycloak, and eks_clusters.

Under preview-gated, each gated stage runs pulumi preview and opens a GitHub issue with that stage's own diff; only closing the issue triggers pulumi up. Where a CI stage exists, it keeps auto-deploying via auto_deploy_stages=["CI"] so the fast feedback loop is preserved -- only QA/Production (or the single default/Production stage where that's all a project has) are gated.

Excluded, per explicit scope:

  • infrastructure/k8s_apps/pipeline.py -- left as deploy-chained
  • edx_platform_v3, keycloak, eks_clusters -- already on preview-gated

Files touched (16):

  • infrastructure/simple_pulumi/pipeline.py -- the ~26 apps in pipeline_params that hadn't been migrated yet (airbyte, celery-monitoring, clickhouse, data_warehouse, digital-credentials, fastly-redirector, grafana-alerting, jupyterhub-data, marimo-data, mongodb-atlas, ocw-site, open-discussions, open-metadata, open-metadata-substructure, opensearch, opik, qdrant-cloud, starrocks, tika, toolhive-apps, toolhive-data, toolhive-operator, toolhive-swe, vector-log-proxy, aws-sftp, b2b-partners-storage, mailgun)
  • Standalone project pipelines: open_edx/{xqwatcher,codejail_v3,edx_notes_v3,xqueue}, infrastructure/{omnigraph,concourse,vault,superset,aws,consul,kubewatch,ocw_site,witan,jupyterhub,dagster}

Also filed mitodl/ol-concourse#96, which adds a record_deployments flag to pulumi_jobs_chain so a preview-gated chain can drop the redundant post-deploy "... deployed." audit issue (it doesn't gate anything -- promotion is passed on the deploy job itself). Once that merges and is released, a follow-up here can set record_deployments=False on the newly preview-gated call sites.

Screenshots (if appropriate):

N/A

How can this be tested?

  • python3 -m pytest tests/ol_concourse -q -- 380 passed
  • pre-commit run on all 16 changed files -- clean (ruff, mypy, etc.)
  • Generated every changed pipeline locally to confirm no runtime errors:
    • Each standalone pipeline.py invoked directly (python3 <file> [release_name])
    • All 40 simple_pulumi app pipelines built via build_simple_pulumi_pipeline(name) in a loop
    • Spot-checked generated job/resource names for mongodb-atlas (multi-group) and aws-sftp (no CI stage) to confirm auto_deploy_stages=["CI"] and the no-CI gate-everything cases produce the expected job graph
  • A reviewer can regenerate any pipeline's definition.json with python3 src/ol_concourse/pipelines/<path>/pipeline.py [args] and diff the job list against the previous deploy-chained output to confirm QA/Production gained preview-* jobs while CI (where present) did not.

Additional Context

This does not deploy anything by itself -- pipelines still need fly set-pipeline (or the meta-pipeline self-update, for simple_pulumi) run against each Concourse target before the new topology takes effect there.

…opology

Every Pulumi chain outside k8s_apps (already tracked separately) and the
pipelines already migrated (edxapp, keycloak, eks_clusters) now gates QA/
Production behind a preview-of-itself issue instead of auto-applying on
merge. CI keeps auto-deploying via auto_deploy_stages=["CI"] where a CI
stage exists, matching the pattern those earlier adopters set.

Includes the ~26 simple_pulumi meta-pipeline apps that hadn't been migrated
yet (airbyte, tika, mongodb-atlas, opensearch, toolhive-*, etc.) alongside
the standalone project pipelines (xqwatcher, codejail_v3, edx_notes_v3,
xqueue, omnigraph, concourse, vault, superset, aws, consul, kubewatch,
ocw_site, witan, jupyterhub, dagster).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019mvaFgGzBYBL2aatAZ2mJG
Copilot AI balanced review requested due to automatic review settings August 25, 2026 18:56
Comment thread src/ol_concourse/pipelines/infrastructure/simple_pulumi/pipeline.py

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Migrates remaining Pulumi Concourse pipelines to preview-gated deployments while retaining automatic CI deployment.

Changes:

  • Gates QA, Production, and singleton stages on Pulumi previews.
  • Preserves automatic deployment for CI stages.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
open_edx/xqwatcher/pipeline.py Gates XQWatcher deployments.
open_edx/xqueue/pipeline.py Gates XQueue deployments.
open_edx/edx_notes_v3/pipeline.py Gates Notes deployments.
open_edx/codejail_v3/pipeline.py Gates CodeJail deployments.
infrastructure/witan/pipeline.py Gates Witan deployments.
infrastructure/vault/pipeline.py Gates Vault stacks.
infrastructure/superset/pipeline.py Gates Superset deployments.
infrastructure/simple_pulumi/pipeline.py Migrates remaining simple Pulumi applications.
infrastructure/omnigraph/pipeline.py Gates Omnigraph deployments.
infrastructure/ocw_site/pipeline.py Gates OCW Site deployments.
infrastructure/kubewatch/pipeline.py Gates Kubewatch components.
infrastructure/jupyterhub/pipeline.py Gates JupyterHub deployments.
infrastructure/dagster/pipeline.py Gates Dagster deployments.
infrastructure/consul/pipeline.py Gates Consul stacks.
infrastructure/concourse/pipeline.py Gates Concourse infrastructure.
infrastructure/aws/pipeline.py Gates shared and one-off AWS stacks.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/ol_concourse/pipelines/open_edx/codejail_v3/pipeline.py
Comment thread src/ol_concourse/pipelines/open_edx/xqueue/pipeline.py
Comment thread src/ol_concourse/pipelines/open_edx/edx_notes_v3/pipeline.py
Comment thread src/ol_concourse/pipelines/open_edx/xqwatcher/pipeline.py
Comment thread src/ol_concourse/pipelines/infrastructure/witan/pipeline.py
Comment thread src/ol_concourse/pipelines/infrastructure/kubewatch/pipeline.py
Comment thread src/ol_concourse/pipelines/infrastructure/kubewatch/pipeline.py
Comment thread src/ol_concourse/pipelines/infrastructure/dagster/pipeline.py
Comment thread src/ol_concourse/pipelines/infrastructure/consul/pipeline.py
Comment thread src/ol_concourse/pipelines/infrastructure/concourse/pipeline.py
blarghmatey added a commit to mitodl/ol-concourse that referenced this pull request Aug 25, 2026
…e's deploy

Chain-wide `dependencies` (a built Docker image, an AMI) previously carried
only whatever `passed` the caller set on them directly -- typically their own
build job. Nothing tied them to the PREVIOUS STAGE's deploy the way
`pulumi_code` already is via `passed_from`, so an image built after a stage's
own build step, but never actually deployed to the environment before it,
was still eligible to trigger and be approved there. Confirmed against
ol-infrastructure's generated pipelines (PR mitodl/ol-infrastructure#5600):
QA's preview job for the `concourse` AMI accepted any AMI that passed the
packer build, not specifically the one that deployed to CI.

Append the previous stage's deploy job to each chain-wide dependency's
`passed`, same guarantee `pulumi_code` gets, stacked on top of (not
replacing) whatever `passed` the caller already set. Copied, not mutated in
place, so this doesn't reintroduce the deploy-chained mutation trap this
topology exists to avoid. `custom_dependencies` is untouched -- those are
index-scoped and the caller already sets `passed` there explicitly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019mvaFgGzBYBL2aatAZ2mJG
…tion

preview-gated expands each gated stage into a preview/deploy pair, so
webhook_handler_fragment.jobs is no longer one job per environment (it's
now [deploy-ci, preview-qa, deploy-qa, preview-production,
deploy-production]). Indexing it positionally by env made kubewatch QA wait
on the webhook handler's QA *preview* rather than its deploy, and Production
wait on QA's deploy instead of its own -- kubewatch could reach later stages
before the webhook handler it depends on had actually deployed there.

Found via Copilot review on ol-infrastructure#5600; confirmed by inspecting
the generated pipeline (preview-ol-infrastructure-kubewatch-applications-qa
was gated on deploy-...-webhook-handler-applications-qa, not the QA preview,
after the fix).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019mvaFgGzBYBL2aatAZ2mJG
Comment thread src/ol_concourse/pipelines/infrastructure/kubewatch/pipeline.py Outdated
…inputs

The deploy-job lookup added in 7ca0962 hardcoded the expected job name as
a literal string duplicating pulumi_jobs_chain's project_name/stack_names
arguments. Extract both into module-level constants shared by both pipeline
builders instead, derive the slug the same way the library does
(stack_name.lower().replace(".", "-")), and raise a clear error naming what
was expected vs. what jobs actually exist rather than a bare StopIteration
if the library's naming ever changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019mvaFgGzBYBL2aatAZ2mJG
@blarghmatey

Copy link
Copy Markdown
Member Author

Addressed review feedback:

  • False positive (declined, resolved): sentry bot's auto_deploy_stages/stack_prefix concern — verified the library matches case-insensitively against the trailing dotted segment, confirmed in generated output.
  • kubewatch job-lookup bug (fixed, resolved) in 7ca0962: positional indexing into the expanded preview/deploy job list picked the wrong stage's job. Fixed by name lookup.
  • kubewatch job-lookup robustness (fixed, resolved) in ed95858, per follow-up review: the name-based lookup now derives from the same values passed to pulumi_jobs_chain() instead of a duplicated literal, and raises a clear error instead of a bare StopIteration if it ever mismatches.
  • Chain-wide dependency promotion (confirmed, root-caused, left open) across 13 threads (codejail_v3, xqueue, edx_notes_v3, xqwatcher, witan, vault, superset, simple_pulumi/celery-monitoring, omnigraph, ocw_site, kubewatch, dagster, consul, concourse): under preview-gated, a pipeline's built image/AMI only carried its own build-job passed constraint, not the previous stage's deploy -- so an artifact that never actually reached the prior environment could still be approved in the next one. Root-caused to ol-concourse's _preview_gated_chain, which doesn't chain dependencies the way it chains pulumi_code. Fixed upstream in feat(preview-gated): optional record issue + chain dependencies to prior stage ol-concourse#96. These threads stay open until that PR merges, is released, and this repo's ol-concourse pin is bumped in a follow-up commit here -- resolving now would be premature since the fix isn't in this diff yet.

blarghmatey added a commit to mitodl/ol-concourse that referenced this pull request Aug 25, 2026
…ior stage (#96)

* feat(preview-gated): make the post-deploy record issue optional

Under topology="preview-gated" the "... deployed." issue posted after every
apply is pure audit trail -- nothing reads it back, since promotion to the
next stage is `passed` on the deploy job itself and the gate issue already
authorised the deploy. Add record_deployments=True so callers whose gate
issue is doing the real work can turn the noise off.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019mvaFgGzBYBL2aatAZ2mJG

* fix(preview-gated): chain-constrain dependencies to the previous stage's deploy

Chain-wide `dependencies` (a built Docker image, an AMI) previously carried
only whatever `passed` the caller set on them directly -- typically their own
build job. Nothing tied them to the PREVIOUS STAGE's deploy the way
`pulumi_code` already is via `passed_from`, so an image built after a stage's
own build step, but never actually deployed to the environment before it,
was still eligible to trigger and be approved there. Confirmed against
ol-infrastructure's generated pipelines (PR mitodl/ol-infrastructure#5600):
QA's preview job for the `concourse` AMI accepted any AMI that passed the
packer build, not specifically the one that deployed to CI.

Append the previous stage's deploy job to each chain-wide dependency's
`passed`, same guarantee `pulumi_code` gets, stacked on top of (not
replacing) whatever `passed` the caller already set. Copied, not mutated in
place, so this doesn't reintroduce the deploy-chained mutation trap this
topology exists to avoid. `custom_dependencies` is untouched -- those are
index-scoped and the caller already sets `passed` there explicitly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019mvaFgGzBYBL2aatAZ2mJG

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
blarghmatey added a commit to mitodl/ol-concourse that referenced this pull request Aug 25, 2026
Covers #96: the preview-gated record_deployments flag and the
dependency-chaining fix, needed by mitodl/ol-infrastructure#5600.


Claude-Session: https://claude.ai/code/session_019mvaFgGzBYBL2aatAZ2mJG

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Picks up mitodl/ol-concourse#96/#97: the record_deployments flag, and the
fix for the dependency-chaining gap Copilot flagged on 13 threads in this
PR -- chain-wide dependencies (built images, AMIs) are now passed-constrained
to the previous stage's deploy, same as pulumi_code already was.

Verified against the regenerated pipelines: e.g. concourse's QA preview job
now requires packer-build to have passed deploy-...-ci, not just its own
build job.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019mvaFgGzBYBL2aatAZ2mJG
@blarghmatey

Copy link
Copy Markdown
Member Author

Follow-up now that mitodl/ol-concourse#96/#97 are merged and released (0.18.0): bumped the pin in 774e0a9 and resolved all 14 remaining threads — verified the fix directly in the regenerated pipelines (e.g. concourse's QA preview job now requires packer-build to have passed the CI deploy, not just its own build job). All review threads are now resolved.

Comment thread src/ol_concourse/pipelines/infrastructure/kubewatch/pipeline.py
@blarghmatey
blarghmatey requested review from Ardiea and feoh August 25, 2026 20:15
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.

3 participants