Skip to content

orchestratord: add a status API and management UI - #38117

Draft
jubrad wants to merge 1 commit into
MaterializeInc:mainfrom
jubrad:orchestrator-mgmt-console
Draft

orchestratord: add a status API and management UI#38117
jubrad wants to merge 1 commit into
MaterializeInc:mainfrom
jubrad:orchestrator-mgmt-console

Conversation

@jubrad

@jubrad jubrad commented Aug 7, 2026

Copy link
Copy Markdown
Member

Motivation

The only ways to see what orchestratord is doing today are kubectl spelunking, operator logs, and Prometheus metrics. Answering "what environments exist, what version are they running, is an upgrade in flight, is it stuck waiting for promotion" means knowing the CRD status conventions and the per-generation resource naming scheme. Managing system parameters means hand-editing a JSON blob inside a ConfigMap.

This adds a status API and a small management UI to the operator itself.

What this looks like

The environment list, answering "what is running, is it healthy, is an upgrade in flight" at a glance:

Configuration is one card, with a pencil on each editable row:

What is actually running, kept as its own section below the configuration:

Editing in place. The rollout strategy is a select, since it is a closed set and one of its values causes downtime:

A rollout in flight, showing the controller's own stages:

Approach

A fourth HTTP server in the orchestratord process, alongside the existing webhook, metrics, and profiling servers, behind --api-listen-address (default [::]:8002). It serves JSON under /api and one self-contained HTML page at /.

No new deployable: the operator already holds a kube client with exactly the RBAC involved, so a separate deployment would only add an image, a ServiceAccount, duplicated RBAC, and version skew for no benefit at this scale. The page has no build step and makes no external requests, so it works in an airgapped cluster. It is deliberately not under the leadership lease, since it serves status and its writes go through the Kubernetes API, so every replica behind the Service can answer.

The write surface is a small fixed set of intentional operations rather than a generic write path, because there is no authentication yet: request or promote a rollout, PUT /config for the editable slice of the spec, and PUT /system-params.

Two behaviors worth review

Both were verified against a live cluster rather than assumed.

System parameters apply without a rollout. The operator mounts the ConfigMap and passes --config-sync-file-path with a one second --config-sync-loop-interval; environmentd re-reads the file each tick and applies changes through ALTER SYSTEM. The write also stamps an annotation onto the environmentd pods so the kubelet re-projects the volume immediately, which took propagation from about fifteen seconds to under two. This annotates the live pods, not the pod template: the template is part of the StatefulSet that is hashed into the Materialize status, so touching it would roll the environment on every save.

Only some configuration needs a rollout. The image, the RBAC flag, and environmentd's own resources are part of that StatefulSet. The rollout strategy, the rollout timeout, replica counts, and balancerd and console resources flow to the Balancer and Console resources their own controllers reconcile, so they take effect without a new generation. The API reports which case a write was, and the UI says so per field.

The proposed image is checked against the same upgrade window the controller enforces, by running the check against a candidate copy of the resource rather than reimplementing the rule, so an illegal jump is rejected up front instead of surfacing later as FailedDeploy.

Design

The UI follows the console's theme in console/src/theme: its semantic color roles, type scale, and StatusPill and Table component shapes, in light and dark, defaulting to the system setting as the console does. Full write-up in doc/developer/design/20260724_orchestratord_api_ui.md.

Helm

New operator.api.enabled toggle, the port on the deployment and service, and events read access for the events feed.

Tips for reviewer

Worth a close look at the pod-annotation refresh in refresh_mounted_configmap, and at ROLLOUT_BOUND_FIELDS in put_config, since that list is what decides whether a config change is reported as needing a rollout.

No tests are added. The handlers are thin views over the kube API and the UI is static; integration coverage would belong in the cloudtest suite. Happy to add that here if reviewers would rather not merge without it.

Checklist

  • This PR has adequate test coverage / QA involvement has been duly considered. (trigger-ci for additional test/nightly runs)
  • This PR has an associated up-to-date design doc, is a design doc (template), or is sufficiently small to not require a design.
  • If this PR evolves an existing $T ⇔ Proto$T mapping (possibly in a backwards-incompatible way), then it is tagged with a T-proto label.
  • If this PR will require changes to cloud orchestration or tests, there is a companion cloud PR to account for those changes that is tagged with the release-blocker label (example).
  • If this PR includes major user-facing behavior changes, I have pinged the relevant PM to schedule a changelog entry.

The only ways to see what the operator is doing today are kubectl
spelunking, operator logs, and Prometheus metrics. Answering "what
environments exist, what version are they running, is an upgrade in
flight, is it stuck waiting for promotion" requires knowing the CRD
status conventions and the per-generation resource naming scheme.

This adds a fourth HTTP server to the orchestratord process, alongside
the existing webhook, metrics, and profiling servers, behind a new
--api-listen-address (default [::]:8002). It serves a JSON API under
/api and a single self-contained HTML page at /. The operator already
holds a kube client with exactly the RBAC involved, so a separate
deployment would only add an image, a ServiceAccount, duplicated RBAC,
and version skew for no benefit at this scale. The page has no build
step and no external requests, so it works in an airgapped cluster.

The read side lists environments with their running and desired image,
rollout state, and generation, and drills into the owned workloads,
pods, services, and recent events. The write side is a small fixed set
of intentional operations rather than a generic write path, since there
is no authentication yet: request or promote a rollout, edit the
editable slice of the spec, and edit system parameters.

Two behaviors are worth calling out, both verified against a cluster
rather than assumed. System parameters apply to a running environment
without a rollout: the operator mounts the ConfigMap and runs
environmentd's config sync loop against it, so a write is picked up and
applied through ALTER SYSTEM. The write also annotates the environmentd
pods to make the kubelet re-project the volume immediately, which took
propagation from about fifteen seconds to under two. It annotates the
live pods rather than the pod template, because the template is part of
the StatefulSet that is hashed into the Materialize status, and
touching it would roll the environment on every save.

Second, only some configuration needs a rollout. The image, the RBAC
flag, and environmentd's own resources are part of that StatefulSet.
The rollout strategy, the rollout timeout, replica counts, and
balancerd and console resources flow to the Balancer and Console
resources that their own controllers reconcile, so they take effect
without a new generation. The API reports which of the two a given
write was, and the UI says so per field.

The proposed image is checked against the same upgrade window the
controller enforces, by running the check against a candidate copy of
the resource rather than reimplementing the rule, so an illegal jump is
rejected up front instead of surfacing later as FailedDeploy.

The UI follows the console's theme in console/src/theme: its semantic
color roles, type scale, and StatusPill and Table component shapes, in
light and dark, defaulting to the system setting as the console does.

The helm chart gains an operator.api.enabled toggle, the port on the
deployment and service, and events read access for the events feed.

No tests are added. The handlers are thin views over the kube API and
the UI is static; integration coverage would belong in the cloudtest
suite.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@jubrad
jubrad force-pushed the orchestrator-mgmt-console branch from b5d9a52 to 8730b45 Compare August 8, 2026 03:01
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