Skip to content

Commit 7bd0106

Browse files
authored
Merge pull request #3412 from SimonTheLeg/fix-initializer-documentation
Particularize Initializers and Provide Sample Code
2 parents eadfe46 + c85829d commit 7bd0106

File tree

2 files changed

+44
-30
lines changed

2 files changed

+44
-30
lines changed

docs/content/concepts/workspaces/workspace-initialization.md

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Initializers are used to customize workspaces and bootstrap required resources u
88

99
### Defining Initializers in WorkspaceTypes
1010

11-
A `WorkspaceType` can specify an initializer using the `initializer` field. Here is an example of a `WorkspaceType` with an initializer.
11+
A `WorkspaceType` can specify having an initializer using the `initializer` field. Here is an example of a `WorkspaceType` with an initializer.
1212

1313
```yaml
1414
apiVersion: tenancy.kcp.io/v1alpha1
@@ -22,6 +22,25 @@ spec:
2222
path: root
2323
```
2424
25+
Each initializer has a unique name, which gets automatically generated using `<workspace-path-of-WorkspaceType>:<WorkspaceType-name>`. So for example, if you were to apply the aforementioned WorkspaceType on the root workspace, your initializer would be called `root:example`.
26+
27+
Since `WorkspaceType.spec.initializers` is a boolean field, each WorkspaceType comes with a single initializer by default. However each WorkspaceType inherits the initializers of its parent WorkspaceType. As a result, it is possible to have multiple initializers on a WorkspaceType using [WorkspaceType Extension](../../concepts/workspaces/workspace-types.md#workspace-type-extensions-and-constraints)
28+
29+
In the following example, `child` inherits the initializers of `parent`. As a result, child workspaces will have the `root:child` and `root:parent` initializers set.
30+
31+
```yaml
32+
apiVersion: tenancy.kcp.io/v1alpha1
33+
kind: WorkspaceType
34+
metadata:
35+
name: child
36+
spec:
37+
initializer: true
38+
extend:
39+
with:
40+
- name: parent
41+
path: root
42+
```
43+
2544
### Enforcing Permissions for Initializers
2645

2746
The non-root user must have the `verb=initialize` on the `WorkspaceType` that the initializer is for. This ensures that only authorized users can perform initialization actions using virtual workspace endpoint. Here is an example of the `ClusterRole`.
@@ -37,6 +56,7 @@ rules:
3756
resourceNames: ["example"]
3857
verbs: ["initialize"]
3958
```
59+
4060
You can then bind this role to a user or a group.
4161

4262
```yaml
@@ -54,46 +74,40 @@ roleRef:
5474
apiGroup: rbac.authorization.k8s.io
5575
```
5676

57-
## initializingworkspaces Virtual Workspace
58-
59-
As a service provider, you can use the `initializingworkspaces` virtual workspace to manage workspace resources in the initializing phase. This virtual workspace allows you to fetch `LogicalCluster` objects that are in the initializing phase and request initialization by a specific controller.
77+
## Writing Custom Initialization Controllers
6078

61-
This Virtual Workspace can fetch `LogicalCluster` either by specific its name or using wildcard.
79+
### Responsibilities Of Custom Initialization Controllers
6280

63-
### Endpoint URL path
81+
Custom Initialization Controllers are responsible for handling initialization logic for custom WorkspaceTypes. They interact with kcp by:
6482

65-
`initializingworkspaces` Virtual Workspace provide a virtual api-server to access workspaces that are initializing with the specific initializer. These URLs are published in the status of WorkspaceType object.
83+
1. Watching for the creation of new LogicalClusters (the backing object behind Workspaces) with the corresponding initializer on them
84+
2. Running any custom initialization logic
85+
3. Removing the corresponding initializer from the `.status.initializers` list of the LogicalCluster after initialization logic has successfully finished
6686

87+
In order to simplify these processes, kcp provides the `initializingworkspaces` virtual workspace.
6788

68-
```yaml
69-
virtualWorkspaces:
70-
- url: https://<front-proxy-ip>:6443/services/initializingworkspaces/<initializer>
71-
```
89+
### The `initializingworkspaces` Virtual Workspace
7290

73-
This is an example URL path for accessing logical cluster apis for a specific initializer in a `initializingworkspaces` virtual workspace.
91+
As a service provider, you can use the `initializingworkspaces` virtual workspace to manage workspace resources in the initializing phase. This virtual workspace allows you to fetch `LogicalCluster` objects that are in the initializing phase and request initialization by a specific controller.
7492

75-
```yaml
76-
/services/initializingworkspaces/<initializer>/clusters/*/apis/core.kcp.io/v1alpha1/logicalclusters
77-
```
93+
You can retrieve the url of a Virtual Workspace directly from the `.status.virtualWorkspaces` field of the corresponding WorkspaceType. Returning to our previous example using a custom WorkspaceType called "example", you will receive the following output:
7894

79-
You can also use `LogicalCluster` name for the direct view, allowing to manage all resources within that logical cluster.
95+
```sh
96+
$ kubectl get workspacetype example -o yaml
8097
81-
```yaml
82-
/services/initializingworkspaces/<initializer>/clusters/<logical-cluster-name>/apis/core.kcp.io/v1alpha1/logicalclusters
98+
...
99+
status:
100+
virtualWorkspaces:
101+
- url: https://<shard-url>/services/initializingworkspaces/root:example
83102
```
84103

85-
### Example workflow
86-
87-
* Add your custom WorkspaceType to the platform with an initializer.
104+
You can use this url to construct a kubeconfig for your controller. To do so, use the url directly as the `cluster.server` in your kubeconfig and provide the subject with sufficient permissions (see [Enforcing Permissions for Initializers](#enforcing-permissions-for-initializers))
88105

89-
* Create a workspace with the necessary warrants and scopes. The workspace will stay in the initializing state as the initializer is present.
106+
### Code Sample
90107

91-
* Use a controller to watch your initializing workspaces, you can interact with the workspace through the virtual workspace endpoint:
92-
93-
```yaml
94-
/services/initializingworkspaces/foo/clusters/*/apis/core.kcp.io/v1alpha1/logicalclusters
95-
```
108+
When writing a custom initializer, the following needs to be taken into account:
96109

97-
* Once you get the object, you need to initialize the workspace with its related resources, using the same endpoint
110+
* We strongly recommend to use the kcp [initializingworkspace multicluster-provider](https://github.com/kcp-dev/multicluster-provider) to build your custom initializer
111+
* You need to update LogicalClusters using patches; They cannot be updated using the update api
98112

99-
* Once the initialization is complete, use the same endpoint to remove the initializer from the workspace.
113+
Keeping this in mind, you can use the [multicluster-provider initializingworkspaces example](https://github.com/kcp-dev/multicluster-provider/tree/main/examples/initializingworkspaces) as a starting point for your initialization controller

pkg/reconciler/committer/committer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ type Patcher[R runtime.Object] interface {
5151
}
5252

5353
// CommitFunc is an alias to clean up type declarations.
54-
type CommitFunc[Sp any, St any] func(context.Context, *Resource[Sp, St], *Resource[Sp, St]) error
54+
type CommitFunc[Sp any, St any] func(_ context.Context, old *Resource[Sp, St], new *Resource[Sp, St]) error
5555

5656
// NewCommitter returns a function that can patch instances of R based on meta,
5757
// spec or status changes using a cluster-aware patcher.

0 commit comments

Comments
 (0)