Skip to main content

[Operational] poc-kcm-kcp

Installs the kcp side of the ADR-0001 cluster API into the workspace that owns the exports (by convention root:controllers:cluster):

  • five APIResourceSchemas across three API groups, shipped verbatim from schemas/;
  • the cluster-tenant and cluster-catalog APIExports;
  • per-export controller RBAC (apiexportendpointslices discovery and apiexports/content), scoped by resourceNames to these two exports.

Install​

helm upgrade --install cluster-kcp deploy/charts/poc-kcm-kcp \
--kube-context <context-pointing-at-root:controllers:cluster>

Then bind the exports (see examples/bindings.yaml at the repository root): tenant workspaces bind cluster-tenant; the catalog workspace binds cluster-catalog. kcp publishes a shard's URL in an endpoint slice only once at least one APIBinding for the export exists on that shard, so a fresh install shows empty slices until the first binding.

The catalog-workspace release​

Catalog reads go over the front proxy, which no permission claim covers, so the controllers need RBAC inside the catalog workspace. That is a second release of this same chart, against that workspace, with the export-workspace objects switched off so it does not plant a second copy of the exports where nothing binds them:

helm upgrade --install cluster-catalog-rbac deploy/charts/poc-kcm-kcp \
--kube-context <context-pointing-at-root:providers> \
--set apis.create=false \
--set rbac.create=false \
--set catalogWorkspace.create=true \
--values catalog-subjects.yaml

catalog-subjects.yaml carries catalogWorkspace.readers. Every subject that reads the catalog goes in it, cluster-scheduler included — the release renders one binding per list, so a release that omits it drops the scheduler's own grant.

Verify with /readyz, not with a reconcile. Each controller reads the catalog through a cache on the manager, so its readiness gate only flips once that cache has synced. A wrong or missing subject leaves the pod permanently not-ready with a Forbidden in its logs, while a correct one goes ready even against an empty catalog:

kubectl -n edge-connect-system port-forward deploy/cluster-scheduler 8081:8081 &
curl -fsS localhost:8081/readyz && echo " ready"

That distinguishes a wrong subject string from a working one immediately. Left to first reconcile it looks like an unseeded catalog instead, which is what a fresh install is told to expect.

Values​

KeyDefaultNotes
exports.tenant.namecluster-tenantMust match the controller's --endpointslice
exports.catalog.namecluster-catalog
exports.*.subjectsthe cluster-scheduler projected identitykind: User with the full management identity — a kind: ServiceAccount subject never matches inside a kcp workspace
apis.createtrueRender the export-workspace objects (schemas, both exports, identity Secrets, endpoint slices). Switch off for the catalog-workspace release
catalogWorkspace.createfalseRender the catalog-workspace RBAC instead of the export-workspace manifests; install as a second release against the catalog workspace
catalogWorkspace.readersthe scheduler's kind: User subjectSubjects granted get/list/watch on kubernetesclusterofferings and virtualmachinetypes. Whoever installs the catalog release owns every subject, not only their own: the release renders one binding from this list, so omitting cluster-scheduler drops the scheduler's grant
exports.tenant.claimsone secrets claimA provider controller writes the cluster's kubeconfig back as a Secret; a kcp claim cannot be scoped to a name, so verbs are enumerated and deletecollection is absent (ADR-0003)
exports.catalog.claims[]The catalog reconciler reads only the kinds that export serves, and the export carries Provider; it stays claim-free
exports.*.identity.enabledfalsePins the export's identityHash to sha256hex(key), stable across export recreation
endpointSlices.createfalseOn kcp 0.32 an APIExport already materialises a slice of the same name; creating one here collides with it
rbac.createtrue
schema*.namePrefixcontent hashesGenerated. Written by make schemas; never edit by hand

Schema pins are generated​

APIResourceSchema objects are immutable in kcp, so each schema's metadata.name is <namePrefix>.<resource>.<group> where namePrefix is a content hash of the CRD. make schemas regenerates the schemas, rewrites the schema*.namePrefix values here, and copies the documents into schemas/ — so the pins and the documents move together.

Note that schemaTenantCluster and schemaProviderCluster carry the same resource name (kubernetesclusters) in different groups. That is why the pinning in hack/generate-schemas.sh matches on group and resource: keying on resource alone would rewrite the wrong block. hack/charts_test.go fails the build if either the pins or the shipped documents fall behind config/kcp.