feat(tenant): provision a self-contained ComputePlane for untrusted-code apps - #3150
Andrei Kvapil (kvaps) wants to merge 6 commits into
Conversation
…x apply Add spec.application.placement (ManagementPlane|ComputePlane, default ManagementPlane) to ApplicationDefinition. When a kind declares placement: ComputePlane, cozystack-api injects spec.kubeConfig (computeplane-admin-kubeconfig / super-admin.svc) and install.createNamespace on the generated HelmRelease, so Flux reconciles it onto the tenant's ComputePlane instead of the management cluster. Default is unchanged. Implements the core routing of design-proposals/compute-plane (cozystack/community#17). Signed-off-by: Andrei Kvapil <[email protected]>
…ster New single-string tenant value computePlane: "" (a profile name; empty disables). When set, templates/computeplane.yaml provisions a single-tenant ComputePlane cluster (the managed kubernetes app, release name 'computeplane' so Kamaji writes computeplane-admin-kubeconfig) using a platform-defined profile ConfigMap referenced by name. Not surfaced as a tenant-managed app. Signed-off-by: Andrei Kvapil <[email protected]>
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
placement: ComputePlane apps (cozyllm Jupyter/n8n/Langflow/etc.) render child HelmReleases, Certificate and Ingress objects into the target cluster. A vanilla Kubernetes app cluster lacks the controllers/CRDs for these, so remote apply fails with "no matches for kind". Enable the fluxcd, certManager and ingressNginx addons on the provisioned ComputePlane so it is a Cozystack-prepared environment for those resources. Addons are set as inline base values (Flux merges spec.values last) so a profile ConfigMap can extend but not disable them; the profile reference is now optional so the module is self-contained. Co-Authored-By: Claude <[email protected]> Signed-off-by: Andrei Kvapil <[email protected]>
The kubernetes-app fluxcd addon (cozy-fluxcd chart) defaults the
FluxInstance spec.distribution.artifact to "", which fails CRD validation
("spec.distribution.artifact must be of type string"). ComputePlane is the
first real consumer of the fluxcd addon (no tenant cluster enabled it
before), so the in-cluster Flux never installed and child HelmReleases
that placement: ComputePlane apps render could not reconcile. Provide the
canonical flux-operator-manifests artifact via addons.fluxcd.valuesOverride
so the ComputePlane's Flux installs. Verified on dev5: the fluxcd addon
HelmRelease moves from InstallFailed to InstallSucceeded with this set.
Co-Authored-By: Claude <[email protected]>
Signed-off-by: Andrei Kvapil <[email protected]>
…mote Flux apply" This reverts commit 4d259e6.
…osts The Proxied exposure Service (<cluster>-ingress-nginx, which selects the tenant cluster's ingress-nginx VM nodes via NodePort) was only created when addons.ingressNginx.hosts was non-empty, because it was gated together with the tenant-module Ingress that routes those hosts. A ComputePlane app exposes itself with its own per-app management Ingress that routes to this Service, so the Service must exist whenever exposeMethod is Proxied — without the tenant module having to enumerate every app host up front. Split the condition: the Service is created for any Proxied cluster; the hosts Ingress stays gated on hosts. Also set exposeMethod: Proxied explicitly on the tenant computePlane module so the ComputePlane's ingress-nginx is reachable from the tenant entry point with no management LoadBalancer. Co-Authored-By: Claude <[email protected]> Signed-off-by: Andrei Kvapil <[email protected]>
|
Closing this one. Two reasons:
Will reopen as a fresh PR implementing the #27 surface once that design lands. Thanks! |
The fluxcd addon pin was a holdover from the #3150-era model where app charts rendered nested HelmReleases into the target cluster and needed an in-cluster helm-controller. Consumers now keep their releases on the management cluster and remote-apply via spec.kubeConfig, so the management Flux resolves charts and applies manifests — nothing inside the ComputePlane reconciles HelmReleases. This also decouples the module from the FluxCD addon removal (#3379). certManager and ingressNginx stay pinned: Certificate and Ingress objects land inside the cluster and need their controllers there. Assisted-By: Claude <[email protected]> Signed-off-by: Andrei Kvapil <[email protected]>
The fluxcd addon pin was a holdover from the #3150-era model where app charts rendered nested HelmReleases into the target cluster and needed an in-cluster helm-controller. Consumers now keep their releases on the management cluster and remote-apply via spec.kubeConfig, so the management Flux resolves charts and applies manifests — nothing inside the ComputePlane reconciles HelmReleases. This also decouples the module from the FluxCD addon removal (#3379). certManager and ingressNginx stay pinned: Certificate and Ingress objects land inside the cluster and need their controllers there. Assisted-By: Claude <[email protected]> Signed-off-by: Andrei Kvapil <[email protected]>
The fluxcd addon pin was a holdover from the #3150-era model where app charts rendered nested HelmReleases into the target cluster and needed an in-cluster helm-controller. Consumers now keep their releases on the management cluster and remote-apply via spec.kubeConfig, so the management Flux resolves charts and applies manifests — nothing inside the ComputePlane reconciles HelmReleases. This also decouples the module from the FluxCD addon removal (#3379). certManager and ingressNginx stay pinned: Certificate and Ingress objects land inside the cluster and need their controllers there. Assisted-By: Claude <[email protected]> Signed-off-by: Andrei Kvapil <[email protected]>
…ted-code apps (#3280) ## What this PR does Implements the ComputePlane per the merged design proposal ([cozystack/community design-proposals/compute-plane](https://github.com/cozystack/community/tree/main/design-proposals/compute-plane); supersedes the earlier #3150 which was built on the pre-revision surface and came from a fork): a managed, isolated environment for running code-executing (untrusted-code) catalog applications. ComputePlane is delivered as an operator-owned **tenant module**: - **`packages/extra/computeplane`** — the module chart. Provisions a single-tenant, Cozystack-managed cluster by deploying the ordinary `apps/kubernetes` chart (Kamaji control plane + KubeVirt-VM workers) with operator-fixed values: the Cozystack-enablement addons (`fluxcd` + pinned distribution artifact, `certManager`, `ingressNginx` with `exposeMethod: Proxied`) are inline `spec.values`, so nothing injected via `valuesFrom` can disable them. The tenant can set cluster *shape* (`nodeGroups`, schema-validated) and receives no admin kubeconfig. - **Release naming**: neither HelmRelease sets `spec.releaseName` — the aggregated API rebuilds HelmRelease specs without that field, so both releases derive names from their object names. The cluster HelmRelease object is `computeplane-cluster`, and Kamaji writes the admin kubeconfig to the derived Secret **`computeplane-cluster-admin-kubeconfig`** — the contract future `placement: ComputePlane` routing consumes. Tenant-visible secrets are an allowlist (`include: []` withholds everything), so the credential is withheld by construction. - **`packages/system/computeplane-rd`** — registers the `ComputePlane` module-kind (`ApplicationDefinition`, `dashboard.module: true`). - **`packages/core/platform/sources/computeplane-application.yaml`** — self-contained package source: re-declares `apps/kubernetes` as its own source-only component; `dependsOn` cozystack-engine (ApplicationDefinition CRD) and kubernetes-application (registration ordering). Ships in the `iaas` bundle (variant `kubevirt`). - **Tenant toggle** — `computeplane: false` bool. The tenant chart fails loudly when the module is toggled on without the iaas package. Note: automatic `placement: ComputePlane` routing is a deferred follow-up and is not part of this PR; until it lands, external catalogs target the cluster via its kubeconfig Secret. - **`apps/kubernetes` fix** — the Proxied ingress `Service` renders only when the ingress-nginx addon is enabled **and** the tenant has etcd (mirroring the addon HelmRelease gates), independent of the `hosts` list. Follow-ups tracked separately: `placement` routing in cozystack-api, scoped per-service egress, visibility/mutation access control, e2e (#3369), release-name guards for the remaining extra charts (#3371). Tests: helm-unittest suites pin the module contract (object names, no explicit releaseName, tamper-proof inline addons, nodeGroups validation + ingress-role guard, unlisted-field pass-through), the tenant toggle, the package-source/bundle wiring, and the ingress Service gates. ### Screenshots Not a UI change. ### Release note ```release-note feat(computeplane): ComputePlane tenant module — a single-tenant, Cozystack-managed cluster for untrusted-code applications, delivered as an operator-owned extra module wrapping the kubernetes app. Enable with `computeplane: true` on the Tenant; the tenant receives no admin kubeconfig for it, and the cluster's admin kubeconfig Secret is `computeplane-cluster-admin-kubeconfig`. Catalog routing (`placement: ComputePlane`) ships separately. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a new **ComputePlane** tenant option (`computeplane`, default off) to provision an isolated single-tenant environment for untrusted-code applications, including cluster creation and configurable **node groups**. * **Bug Fixes** * Refined ingress-nginx proxied rendering rules to avoid emitting incomplete resources: Ingress/Services are now gated on addon enablement (and etcd-backed tenancy), with correct behavior when hosts aren’t provided. * **Documentation / Tests** * Updated tenant and ComputePlane documentation; added/extended rendering tests for the new ComputePlane module and ingress-nginx gating (including release-name and etcd-less cases). <!-- end of auto-generated comment: release notes by coderabbit.ai -->
What
Adds a tenant-level ComputePlane: a Cozystack-managed, single-tenant Kamaji + KubeVirt cluster that hosts untrusted-code applications (e.g. the cozyllm Jupyter/n8n/Langflow apps) on VM-isolated worker nodes, while their private data dependencies stay on the management cluster.
computePlanetenant module (packages/apps/tenant): provisions the managedkubernetesapp with thefluxcd,certManagerandingressNginxaddons enabled, so the cluster is a Cozystack-prepared environment that can reconcile the HelmReleases, Certificates and Ingresses an app renders onto it.kubeConfig.secretRef → computeplane-admin-kubeconfig. There is no app-levelplacementfield — routing belongs to the app chart, so a self-contained app keeps its private Postgres on management and sends only the untrusted workload to the ComputePlane (per docs(development): explain why packages live in apps vs extra website#594).exposeMethod: Proxied, and its Proxied Service is now created whenever Proxied is set (independent ofhosts) so an app's per-app Ingress can route to it.Why
Catalog apps that run arbitrary user code currently land as pods in the tenant namespace on the shared management cluster. The ComputePlane makes the isolated VM cluster the target for those workloads, without exposing it to the tenant as a manageable cluster (visibility is decoupled from the security boundary).
Validation
Validated end-to-end live on a dev cluster: remote-apply of a workload to the ComputePlane, addon convergence, and a real app (n8n) running on the ComputePlane while connected to its bundled Postgres on management over the cross-cluster DNS search domain.
Notes
distribution.artifactfailed CRD validation) — set to the canonical OCI artifact.