Control Center UI, sb-mock test backend, and optional upstream Ramen - #512
Open
schmidt-scaled wants to merge 12 commits into
Open
schmidt-scaled wants to merge 12 commits into
schmidt-scaled wants to merge 12 commits into
Conversation
Adds the simplyblock Control Center (the web console built with Claude Design) as a monorepo component and wires it into the simplyblock-operator Helm chart as an optional, off-by-default deployment. - control-center/: image build (nginx + in-pod reverse proxy in front of the Kubernetes API, operator API and Prometheus), entrypoint, prepare script that strips fixtures and vendors React/Babel/fonts, and plain k8s manifests for non-Helm installs. The console sources (index.html and the .jsx files) land at control-center/ root in a follow-up. - helm chart: control-center.yaml (SA/Deployment/Service/Ingress), control-center-rbac.yaml, an optional NetworkPolicy, and self-contained sbcc.* helpers whose upstream defaults resolve to this chart's static service names (simplyblock-operator:8080, simplyblock-prometheus:9090). Everything is gated on controlCenter.enabled=false in values.yaml. - CI: control_center_build.yaml (branch images to DockerHub/ECR) and control_center_release.yaml (release images to quay.io), both skipping gracefully while the console sources are not committed; the release is chained into repo_release.yaml without blocking the chart publish. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A single Go binary (control-center/mock) that impersonates all three upstreams the console proxies, so the real, unmodified UI runs against generated data: the Kubernetes API (simplyblock CRDs, Ramen CRDs, core objects), the operator HTTP API, and Prometheus. - Kubernetes API engine over a generic in-memory store: discovery, list/get/create/update/delete, merge/JSON/apply patches, /status subresources, pod logs, label and field selectors, and streaming watches with resourceVersion/generation/uid bookkeeping. Writes persist and fire watch events but perform no underlying change. - Seeded test data sets (small-healthy, medium-degraded, large-scale, dr-failover, chaos; --dataset auto picks randomly) rendered as a coherent object graph: devices reference their nodes, slots their PVCs, DRPCs their DRPolicy, and the Helm release Secret is a structurally real helm.sh/release.v1 payload. Same seed = same world. - A simulator plays every reconciler: Ops objects walk Pending -> Running -> Succeeded/Failed (with subphases and a fail rate), spec.abort is honored, DRPC failovers and volume migrations progress, replication slots cut over, and transitions emit Events. - Prometheus mock serves deterministic per-node series derived from the same topology; the operator API is fixture-driven and records unmatched requests (/mockctl/info) so the still-settling /v1 surface can be modeled incrementally. - Admin API for e2e suites: /mockctl/reset (dataset/seed swap), /mockctl/advance (deterministic ticks with --sim-interval=0). - --serve-ui serves the console statics directly for nginx-less local dev; in-cluster, controlCenter.mock.enabled=true deploys the mock next to the console and rewires its proxy env — the console image runs unmodified. - CI: go vet/test plus a control-center-mock image on branch pushes, and a quay.io release image (not gated on the UI sources, which are still to be committed). Stdlib-only, tested (store semantics, REST+watch roundtrips, selector matrix, simulator state machines, per-dataset coherence and determinism). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deploys RamenDR — the DR orchestrator the Control Center's DR views drive — split across the two cluster roles the way Ramen itself is, both off by default: - ramen.hub.enabled (management cluster): the hub operator reconciling DRPolicy, DRPlacementControl and DRCluster, driving placement through OCM. - ramen.drCluster.enabled (managed clusters): the dr-cluster operator reconciling VolumeReplicationGroups and executing the protection where the volumes live; enable it alongside the local simplyblock operator. Manifests are vendored verbatim from RamenDR/ramen v0.1.0-rc1 (config/hub, config/dr-cluster, config/crd/bases) under ramen/, and parameterized only for namespace, image, resources and the RamenConfig (ramen.hub.config / ramen.drCluster.config deep-merge over upstream defaults; ramen.s3StoreProfiles shared). Object names are kept upstream (ramen-hub-operator, ramen-dr-cluster-operator, namespace ramen-system) because Ramen refers to its own names at runtime. CRDs render as templates rather than from crds/, so they stay optional: only the enabled halves install their CRDs, ramen.installCRDs=false skips them on clusters where RHACM/ODF already ships Ramen, and every vendored CRD carries helm.sh/resource-policy: keep so an uninstall never removes a CRD or the DR state it holds. RBAC ClusterRoles are config/*/rbac/role.yaml verbatim. Verified with helm lint and template across all modes (default = zero Ramen objects; hub = 3 hub CRDs; dr-cluster = 6 execution CRDs; both = 9 with keep policy; installCRDs=false = none) and that helm package bundles ramen/. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New optional, off-by-default features since 26.2.x: the Control Center web console (controlCenter.enabled), its sb-mock test backend (controlCenter.mock.enabled), and upstream Ramen for disaster recovery (ramen.hub.enabled / ramen.drCluster.enabled). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- control-center/mock/main.go: "statics" -> "assets" in a comment. - repo_codespell.yaml: ignore "notin" (the Kubernetes label-selector set operator used in control-center/mock, alongside the existing NotIn) and skip helm-charts/.../ramen, whose vendored-verbatim RamenDR CRDs spell "various" as "vaious" — not ours to correct, same rationale as the existing zz_generated skip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Populates control-center/ with the actual console from the design package (index.html + the .jsx sources it loads, the mock-*.jsx fixture backend, the CRD/RBAC design docs and screenshots). Until now only the deploy scaffold was present, so the image build no-opped; with the sources committed, control_center_build / control_center_release produce a real image. - Console sources: index.html, config.js (dev preview; replaced at runtime), and all *.jsx. prepare.mjs strips the MOCK block and the mock-*.jsx fixture backend from the shipped image (verified: 24 assets, no mock-* shipped, no external subresource leaks). - deploy/Dockerfile: fixed the prepare.mjs invocation to --out=/out. The script's arg reader only understands --flag=value, so the previous space form (--out /out) mis-parsed the path and would have failed the image build the moment sources existed. - .dockerignore: keep mock/ (the Go test backend), screenshots/, uploads and docs out of the image build context. - Docs: the package README.md becomes control-center/README.md (the product doc, so re-exports don't clobber a hand-written file); the prior monorepo integration guide moves to INTEGRATION.md, linked from the top of README. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- deploy/build/prepare.mjs was silently untracked: the repo-root .gitignore ignores build/, so `git add` skipped it and the image build failed with "Cannot find module '/src/deploy/build/prepare.mjs'". Add a scoped control-center/deploy/.gitignore that re-includes build/prepare.mjs, and commit the file. - codespell: skip the design-exported console sources (*.jsx, index.html, config.js, the CRD/RBAC design docs). They are re-exported from Claude Design, so their typos (asend, acount, ...) are corrected upstream, not here — same rationale as the vendored Ramen CRDs. Hand-maintained files (mock/, README, INTEGRATION.md) stay spell-checked. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Syncs control-center/ to the new design export. The console no longer transpiles JSX in the browser (30-40s cold start); the .jsx are compiled to dist/app.js and dist/mock.js and index.html loads those. - New: build.md, deploy/build/bundle.mjs (Babel compile step), dist/app.js, dist/mock.js. Refreshed all .jsx, index.html, prepare.mjs, the deploy scaffold (incl. CSP: unsafe-eval dropped now that Babel is gone) and design docs. Removed the screenshots/ set (dropped upstream). - deploy/Dockerfile stage 2 now runs bundle.mjs (rebuilding dist/ in-image so it never ships a stale bundle) then prepare.mjs. Re-applied the --out=/out fix the export reverted (prepare.mjs only parses --flag=value). - deploy/.gitignore now re-includes build/bundle.mjs too: the repo-root build/ ignore would otherwise silently drop it, as it did prepare.mjs. - codespell: skip control-center/dist (generated bundles carry the same words as the already-skipped *.jsx). Validated: prepare.mjs strips the fixture (dist/mock.js) and ships index.html + dist/app.js with no mock refs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…hree) The prepare stage installed @babel/core, @babel/cli and @babel/preset-react all at BABEL_VERSION=7.29.0, but only @babel/core published 7.29.0 — @babel/cli and @babel/preset-react version on their own release trains and have no 7.29.0, so npm failed with ETARGET and the image never built. 7.29.7 exists for all three (same "separate release trains" caveat the Dockerfile already notes for the fontsource packages). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The multi-arch build ran the vendor and prepare stages under QEMU emulation
for linux/arm64 and crashed in npm/Babel ("qemu: uncaught target signal 4
(Illegal instruction)", exit 132). Both stages only produce arch-independent
output — vendored JS/fonts/svg and the Babel-compiled dist/ — so pin them to
--platform=$BUILDPLATFORM to run natively on the build host. Only the nginx
runtime stage stays per-target-arch, receiving the static assets by COPY.
amd64 already succeeded ("bundled 11 mock + 24 app sources into dist/").
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adjusts the UI test backend to the CRD-redesign + multi-cluster RBAC design so the console can be exercised against the intended model, even though almost none of it exists on main. PARADIGM.md documents, principle by principle, what is faithful and where a mock necessarily stands in. Reproduced faithfully: - Namespace layout + hierarchy labels: simplyblock-system, sb-mc-<managed> (transport), sb-sc-<cluster> (RBAC target), sb-dr-system, app namespaces — structure in labels (scope-kind, managed-cluster, storage-cluster), not names. - Hub->agent projection: the StorageCluster exists user-facing in sb-sc-* and as a same-kind projection in sb-mc-* labelled managed-by:hub, whose status is agent-authored (lastSyncTime, agentConnected, Applied/AgentConnected conditions). The simulator plays the agent and heals drift. - observedGeneration on every simplyblock kind, with the applied/pending distinction: a bumped hub spec reads Applied=Pending until the agent (a sim tick) catches observedGeneration up (design-crd-model §7.9). - Hub-only conditions the managed cluster can't self-report (AgentConnected, InSync/DriftDetected) on ManagedCluster. - Actor-stamp annotations on hub-authored objects (§3.2). - RBAC vocabulary: eight aggregated sb:* ClusterRoles + rules-carrying children, RoleBindings/ClusterRoleBinding grants labelled managed-by:control-center, AccessGrant CR, and the cluster-scoped NodePoolAllocation envelope, StorageClusterClass and ManagedCluster. - Authorization queries: SelfSubjectRulesReview / SubjectAccessReview and a scope-projection (/operator/v1/access/scopes, /access/self), driven by a configurable --viewer identity (global | none | <sb:role>@<ns>). Documented deviations (see PARADIGM.md): no real identity/impersonation (reviews are display-only, CRUD is not enforced); no server-side-apply field managers; managed-by:hub is labelled but not admission-enforced; the NodePoolAllocation CEL envelope, the agent CSR registration handshake, and the RFC 8693 delegated-token exchange are out of the k8s/UI surface a mock sees. New: tenancy.go, rbac.go, PARADIGM.md, paradigm_test.go. go vet + full test suite pass; live-verified the layout, projection, drift heal, and authz. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adjusts the hub mock's RBAC to the product-facing model: namespaces are tenants, and within a tenant there is one full-admin (CRUD) role plus one read-only role per main object. - Tenancy is now tenant-centric: sb-<tenant> namespaces (scope-kind=tenant) hold one or more whole clusters plus the tenant's DR-policies and DR-applications. Global admins create/manage them; extra tenants (large-scale, chaos) are generated empty with only a tenant-admin grant — ready to provision into. Replaces the per-cluster sb-sc-*/sb-sp-*/sb-dr-system layout. - Role model (tenancy.go sbRoles): sb:infra-admin (global — manage tenants and bindings), sb:tenant-admin (full CRUD, the provisioning role), and one read-only role per main object: sb:cluster-reader, sb:dr-policy-reader, sb:dr-application-reader — each covering that object and its sub-objects. Adding a main object is one entry. - Grants: a tenant-admin RoleBinding per tenant + the three reader bindings on the primary tenant, an infra-admin ClusterRoleBinding, and a tenant-scoped AccessGrant CR. - DR-application is now a generated main object (protectedapplications + applicationfailovers) in the tenant namespace. - authz (SSRR/SAR/scopes) unchanged in shape; --viewer accepts the new role names, and a scoped reader correctly denies cross-object and write access. - PARADIGM.md updated (tenant layout, role table) with a deviation note: this simplifies the uploaded 8-role design per the product owner; the console .jsx/RBAC-DESIGN.md still describe the old model and must align on re-export. go vet + full suite pass (new TestRoleModel); live-verified roles, per-tenant grants, empty tenant, DR-application, and scoped-reader isolation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds three optional, off-by-default capabilities to the operator Helm chart, and bumps the chart to 26.3.0.
1. Control Center web console (
controlCenter.enabled)The simplyblock web UI, deployed alongside the operator. Static document served by nginx with an in-pod reverse proxy in front of the three upstreams it uses (Kubernetes API, operator API, Prometheus). New monorepo component at
control-center/; self-contained chart templates (control-center*.yaml,_control_center_helpers.tpl) withsbcc.*helpers. Serviceaccount/passthrough auth, optional Ingress and NetworkPolicy.2. sb-mock — UI test backend (
controlCenter.mock.enabled)A stdlib-only Go server (
control-center/mock/) that impersonates all three upstreams so the real, unmodified console runs against generated data: Kubernetes API (simplyblock + Ramen CRDs + core objects, incl. the proposed kinds with no CRD yet), operator API (fixture-driven), Prometheus (deterministic series). Writes persist and fire watch events but do nothing real; a simulator advances Ops/DRPC/migration phases. Seeded datasets (small-healthy,medium-degraded,large-scale,dr-failover,chaos,auto). Full test suite (go test).3. Optional upstream Ramen (
ramen.hub.enabled/ramen.drCluster.enabled)RamenDR split across the two cluster roles: the hub operator on the management cluster (DRPolicy/DRPlacementControl/DRCluster via OCM) and the dr-cluster operator on managed clusters (VolumeReplicationGroups). Vendored verbatim from RamenDR/ramen v0.1.0-rc1 under
ramen/; CRDs render as templates (ramen.installCRDs=falseto skip where RHACM/ODF already ships them) and carryhelm.sh/resource-policy: keep.Validation
helm lint+helm templateacross all modes (default = zero optional objects; each feature renders correctly in isolation and combined);go vet/go testfor sb-mock;helm packageconfirmed to bundleramen/.🤖 Generated with Claude Code