feat(concourse): switch remaining Pulumi pipelines to preview-gated topology - #5600
feat(concourse): switch remaining Pulumi pipelines to preview-gated topology#5600blarghmatey wants to merge 4 commits into
Conversation
…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
There was a problem hiding this comment.
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.
…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
…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
|
Addressed review feedback:
|
…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>
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
|
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. |
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 defaultdeploy-chainedtopology topreview-gated, matching the pattern already adopted byedx_platform_v3,keycloak, andeks_clusters.Under
preview-gated, each gated stage runspulumi previewand opens a GitHub issue with that stage's own diff; only closing the issue triggerspulumi up. Where a CI stage exists, it keeps auto-deploying viaauto_deploy_stages=["CI"]so the fast feedback loop is preserved -- only QA/Production (or the singledefault/Productionstage where that's all a project has) are gated.Excluded, per explicit scope:
infrastructure/k8s_apps/pipeline.py-- left asdeploy-chainededx_platform_v3,keycloak,eks_clusters-- already onpreview-gatedFiles touched (16):
infrastructure/simple_pulumi/pipeline.py-- the ~26 apps inpipeline_paramsthat 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)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_deploymentsflag topulumi_jobs_chainso a preview-gated chain can drop the redundant post-deploy "... deployed." audit issue (it doesn't gate anything -- promotion ispassedon the deploy job itself). Once that merges and is released, a follow-up here can setrecord_deployments=Falseon the newly preview-gated call sites.Screenshots (if appropriate):
N/A
How can this be tested?
python3 -m pytest tests/ol_concourse -q-- 380 passedpre-commit runon all 16 changed files -- clean (ruff, mypy, etc.)pipeline.pyinvoked directly (python3 <file> [release_name])simple_pulumiapp pipelines built viabuild_simple_pulumi_pipeline(name)in a loopmongodb-atlas(multi-group) andaws-sftp(no CI stage) to confirmauto_deploy_stages=["CI"]and the no-CI gate-everything cases produce the expected job graphdefinition.jsonwithpython3 src/ol_concourse/pipelines/<path>/pipeline.py [args]and diff the job list against the previousdeploy-chainedoutput to confirm QA/Production gainedpreview-*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, forsimple_pulumi) run against each Concourse target before the new topology takes effect there.