- Go 88.1%
- Smarty 4.2%
- Makefile 3.5%
- Shell 2.7%
- Nix 1.5%
EnsureAPIBindings now reads the referenced APIExport's spec.permissionClaims at reconcile time and accepts each verbatim (verbs and identityHash copied, selector from defaultSelector else matchAll). Previously bindings were created with empty permissionClaims, so kcp warned that exported claims were not specified, not accepted, and had mismatched verbs. Claims stay in sync via the existing drift-reconcile path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .forgejo/workflows | ||
| api/v1alpha1 | ||
| cmd/workspace-controller | ||
| config | ||
| deploy/charts | ||
| hack | ||
| internal | ||
| .envrc | ||
| .gitignore | ||
| .golangci.yml | ||
| .goreleaser.yaml | ||
| AGENTS.md | ||
| CLAUDE.md | ||
| Dockerfile.workspace.goreleaser | ||
| flake.nix | ||
| go.mod | ||
| go.sum | ||
| Makefile | ||
| README.md | ||
| renovate.json | ||
workspace-controller
kcp controller that owns the Workspace resource (per ADR-0020). A
Workspace authored inside an org workspace
(root:orgs:{org}) is reconciled into a kcp nested workspace at
root:orgs:{org}:{name}, with:
- the three controller-managed
ClusterRoles (workspace-owner/workspace-editor/workspace-viewer) seeded inside it, ClusterRoleBindings for every entry inspec.owners(the unifiedOwnerBinding{Kind, Name}shape from ADR-0021),- an
APIBindingper configured customer-facingAPIExport.
The controller is multi-cluster: a single binary watches Workspace CRs across
every org workspace via an APIExport's virtual-workspace endpoint, using
kcp-dev/multicluster-provider + multicluster-runtime.
Layout
.
├── api/v1alpha1/ # CRD source of truth (kubebuilder annotations)
│ ├── groupversion_info.go
│ ├── ownerbinding_types.go # canonical OwnerBinding{Kind, Name}
│ ├── workspace_types.go # Workspace, WorkspaceSpec, WorkspaceStatus
│ └── zz_generated.deepcopy.go # generated by `make generate`
├── cmd/
│ └── workspace-controller/ # main binary
├── internal/
│ ├── controller/
│ │ ├── util/ # shared helpers (conditions)
│ │ ├── workspace/ # the Workspace reconciler
│ │ └── testutil/ # test fixtures + fake mcmanager
│ └── kcpws/ # kcp-facing client (workspace + RBAC + APIBindings)
├── config/
│ ├── crd/ # generated by `make manifests`
│ └── kcp/ # generated by `make schemas`
├── deploy/charts/
│ ├── workspace-controller/ # deployment chart for the binary
│ └── workspace-controller-kcp/ # APIExport + APIResourceSchema + RBAC
├── Dockerfile.workspace.goreleaser
├── .goreleaser.yaml
├── Makefile
└── go.mod
Generating CRDs and APIResourceSchemas
make all # generate + manifests + schemas
make generate # zz_generated.deepcopy.go
make manifests # CRD YAML in config/crd/
make schemas # APIResourceSchema YAML in config/kcp/
make build # build the controller binary to bin/
make vet
make test
make helm-lint
Running the controller
KCP_KUBECONFIG=/path/to/kcp.kubeconfig \
go run ./cmd/workspace-controller \
--endpointslice=workspaces \
--apibinding=workspaces:root:controllers:workspace-controller \
--owner-cluster-role-name=workspace-owner
--apibinding may be repeated. Each value is name:exportPath (or
name:exportPath:exportName when the binding name differs from the export
name) and produces one APIBinding inside every provisioned workspace. The
APIBindingsReady condition flips True once all of them report Bound /
Ready. Pass none to skip the binding step entirely; the condition then
trivially reports True.