Skip to content

feat(tenant): provision a self-contained ComputePlane for untrusted-code apps - #3150

Closed
Andrei Kvapil (kvaps) wants to merge 6 commits into
cozystack:mainfrom
kvaps:feat/compute-plane
Closed

Andrei Kvapil (kvaps) wants to merge 6 commits into
cozystack:mainfrom
kvaps:feat/compute-plane

Conversation

@kvaps

@kvaps Andrei Kvapil (kvaps) commented Jun 30, 2026 •

Copy link
Copy Markdown
Member

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.

  • New computePlane tenant module (packages/apps/tenant): provisions the managed kubernetes app with the fluxcd, certManager and ingressNginx addons enabled, so the cluster is a Cozystack-prepared environment that can reconcile the HelmReleases, Certificates and Ingresses an app renders onto it.
  • An app routes a workload onto the ComputePlane by giving its workload HelmRelease kubeConfig.secretRef → computeplane-admin-kubeconfig. There is no app-level placement field — 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).
  • Exposure without a management LoadBalancer: the ComputePlane ingress-nginx runs with exposeMethod: Proxied, and its Proxied Service is now created whenever Proxied is set (independent of hosts) 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

  • The fluxcd addon needed a fix (empty distribution.artifact failed CRD validation) — set to the canonical OCI artifact.
  • A companion cozyllm PR reworks the apps to the self-contained model.

…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]>
@coderabbitai

coderabbitai Bot commented Jun 30, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b8496cc8-5750-447a-a705-5ee8b057d8de

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added area/api Issues or PRs related to the cozystack-api aggregated API server kind/feature Categorizes issue or PR as related to a new feature size/L This PR changes 100-499 lines, ignoring generated files labels Jun 30, 2026
Andrei Kvapil (kvaps) and others added 4 commits June 30, 2026 16:59
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]>
…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]>
@kvaps Andrei Kvapil (kvaps) changed the title feat(api): ComputePlane placement for untrusted-code workloads feat(tenant): provision a self-contained ComputePlane for untrusted-code apps Jul 1, 2026
@github-actions github-actions Bot added the area/uncategorized PR auto-labeler could not map title scope to a known area/*; please review label Jul 1, 2026
@myasnikovdaniil

Copy link
Copy Markdown
Contributor

Closing this one. Two reasons:

  1. Superseded design. This is built on the original single-string computePlane: module + fixed routing, which we've since moved to Alternatives (rejected) in favor of the kind: Kubernetes preset surface (isolationProfile × componentProfile, placement → named cluster, cozystack-api access control) agreed in Follow-up to #17 (ComputePlane): deliver it as composable presets on kind: Kubernetes, not a new kind community#26 and folded into design-proposal(compute-plane): deliver as kind: Kubernetes presets, not a new kind (per #26 / #17 review) community#27. The mechanism here (remote Flux apply onto a Kamaji+KubeVirt cluster) is unchanged and still correct — only the user-facing surface changed.
  2. Fork branch. It's from a fork, so it needs recreating against the new surface anyway.

Will reopen as a fresh PR implementing the #27 surface once that design lands. Thanks!

Andrei Kvapil (kvaps) added a commit that referenced this pull request Jul 20, 2026
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]>
Andrei Kvapil (kvaps) added a commit that referenced this pull request Jul 23, 2026
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]>
Andrei Kvapil (kvaps) added a commit that referenced this pull request Jul 28, 2026
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]>
Andrei Kvapil (kvaps) added a commit that referenced this pull request Jul 29, 2026
…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 -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/api Issues or PRs related to the cozystack-api aggregated API server area/uncategorized PR auto-labeler could not map title scope to a known area/*; please review kind/feature Categorizes issue or PR as related to a new feature size/L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants