Skip to content

feat(omnigraph): give the 0.13 server what it needs to take over the lock - #6351

Merged
blarghmatey merged 3 commits into
mainfrom
omnigraph-013-stack
Oct 13, 2026
Merged

blarghmatey merged 3 commits into
mainfrom
omnigraph-013-stack

Conversation

@blarghmatey

@blarghmatey blarghmatey commented Oct 13, 2026 •

Copy link
Copy Markdown
Member

What are the relevant tickets?

witan task tk-ol-infrastructure-omnigraph-stack-for-0-12-clust-2dee94, part of the omnigraph 0.13 / storage format 14 upgrade (D3 and D4 of the spec in mitodl/agent-kit#461). This is the first part of that task. The entrypoint it serves is mitodl/agent-kit#479.

Description (What does it do?)

From omnigraph 0.12 a server keeps its storage root's exclusive lock after it exits, and the next start is refused until that lock is force-unlocked. The 0.13 image's entrypoint does that on boot, after taking a Kubernetes Lease and checking that no other server pod is alive. Without the Lease, the RBAC and its env it exits before serving.

Everything here is keyed on omnigraph:internal_schema_version >= 14. Each environment reaches that in its cutover change, and validate_internal_schema_version ties the value to the served fmt<N> prefix, so it cannot be set early.

  • New lock_handoff.py: the omnigraph-unlock Lease, pre-created with no holder because RBAC cannot restrict create by name, and a Role giving the omnigraph-server ServiceAccount get/update on that Lease and list on pods. The Deployment gets OMNIGRAPH_UNLOCK_LEASE, OMNIGRAPH_POD_SELECTOR, POD_NAME, OMNIGRAPH_APPLY_ACTOR and OMNIGRAPH_GRAPH_REMOVAL_ALLOWLIST, and depends on the Lease and the binding.
  • New omnigraph:graph_removal_allowlist. 0.13 deletes a graph's storage and history when cluster.yaml stops declaring it, and the entrypoint refuses that apply unless the graph is listed. An entry for a graph that is still declared fails the preview, so a stale entry cannot let a later accidental removal through.
  • The cluster-apply Job is not created at format 14. A no-op direct apply still leaves a lock (measured on 0.13.0), which would refuse the server's first boot after a cutover, and beside a serving server the apply is refused. The entrypoint applies on every boot.
  • The optimize and cleanup CronJobs are suspended at format 14, because the lock refuses them too.
  • The /readyz comment is rewritten from a measurement on 0.13.0 with one of four graphs missing: 200, status: degraded, blocked_graph_count: 1.

Not in this PR, and needed before any environment cuts over:

  • The read-only cluster plan Job in the apply Job's place. Until it exists, a bad schema or policy change is first seen by the restarting pod, after Recreate has stopped the old one.
  • The stop-window maintenance CronJob. Until it exists a format-14 environment gets no compaction or version cleanup.
  • Moving the staleness rules to that CronJob. WitanDailyMaintenanceStale* (36h) and ScheduledJobStaleSlow* (15d) match omnigraph-optimize and omnigraph-cleanup by name and do not filter on kube_cronjob_spec_suspend, so they fire for the suspended jobs after a cutover. Until the replacement exists that is accurate, because nothing is compacting. The change that adds it should repoint the rules, or they fire for good.
  • Re-sizing the 135s startup budget. The entrypoint can wait up to 50s for a terminating pod before it applies, and I have no 0.13 boot timings against real graphs yet.
  • WitanGraphQuarantined*: on 0.13 the startup line's graph_count counts declared graphs, so the rule can no longer fire. The new signal is the graph blocked during startup graph_id=<id> WARN line.

How can this be tested?

  • pulumi preview --stack CI with the deployed image digest: 52 unchanged. I could not preview the format-14 branch, since no stack can declare 14 while it serves fmt9.
  • data_tier.py imports pulumi_aws, so nothing in the suite calls create_data_tier, and the four gated lines there (no apply Job, suspended sweeps, the env, the depends_on) are covered by reading only. lock_handoff.py is tested under Pulumi mocks against the names and verbs the entrypoint uses (one GET and one PUT on the Lease, one pod list).
  • pytest tests/ol_infrastructure/applications/omnigraph/: 227 passed.

https://claude.ai/code/session_01SfdKkJ4YSVXssjVYmBPTWh

…lock

From omnigraph 0.12 a server keeps its storage root's exclusive lock after
it exits, and the 0.13 image's entrypoint releases it on the next boot. It
needs a Lease to exclude other unlockers and the pod list to show the old
pod has exited, and exits before serving without them.

Keyed on internal_schema_version >= 14, which each environment reaches in
its cutover change, so nothing changes on format 9:

- Pre-create the omnigraph-unlock Lease and grant the server get/update on
  it and list on pods. Pass the entrypoint its Lease, selector, pod name,
  apply actor and graph-removal allow-list.
- Add omnigraph:graph_removal_allowlist. 0.13 deletes a graph that
  cluster.yaml stops declaring, and the entrypoint refuses unless it is
  listed. An entry for a graph that is still declared fails the preview.
- Stop creating the cluster-apply Job. Beside a serving 0.13 server it is
  refused, and at cutover its lock would refuse the server's first boot.
- Suspend the optimize and cleanup sweeps, which the lock also refuses.

Still to come for format 14: the read-only plan gate in the Job's place and
the stop-window maintenance CronJob.

Claude-Session: https://claude.ai/code/session_01SfdKkJ4YSVXssjVYmBPTWh
Also says in the runbook that the optimize and cleanup sweeps stay
suspended on format 14, and drops an ignore_changes that did nothing.

Claude-Session: https://claude.ai/code/session_01SfdKkJ4YSVXssjVYmBPTWh
Copilot AI balanced review requested due to automatic review settings October 13, 2026 01:51

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.

🟡 Changes recommended

Falsey malformed allowlist values currently bypass preview-time validation.

2 open findings
What changed in this PR

Adds format-14 infrastructure required for Omnigraph 0.13 lock handoff and safe graph removal.

Changes:

  • Adds the unlock Lease, scoped RBAC, and entrypoint environment.
  • Disables incompatible apply and maintenance jobs for persisted-lock formats.
  • Documents and tests the new cutover behavior.
File Description
lock_handoff.py Provisions lock-handoff resources and validation.
data_tier.py Integrates format-gated lock handoff and job suspension.
__main__.py Reads and passes the graph-removal allowlist.
test_lock_handoff.py Tests RBAC, environment, and validation.
omnigraph-storage-format-upgrade-runbook.md Updates format-14 procedures.

🧠 Review effort: Balanced


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

Comment thread src/ol_infrastructure/applications/omnigraph/__main__.py Outdated
Comment thread src/ol_infrastructure/applications/omnigraph/data_tier.py
Both callers passed the value through `or []`, so a malformed falsey value
(`{}`, `0`, `false`) became an empty allow-list before
`validate_graph_removal_allowlist` could refuse it. In a change that also
removes a graph, the first sign would be the new pod refusing to apply, after
`Recreate` had stopped the old one.

This defaults only a missing key, so any configured value reaches the type
check and fails the preview.

Claude-Session: https://claude.ai/code/session_013DBLiMHBByMfSpbTRLUNXG
Comment thread src/ol_infrastructure/applications/omnigraph/data_tier.py
@blarghmatey
blarghmatey merged commit b40ca80 into main Oct 13, 2026
12 checks passed
@blarghmatey
blarghmatey deleted the omnigraph-013-stack branch October 13, 2026 14:25
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.

2 participants