Skip to content

doc: Particularize Initializers and Provide Sample Code #3412

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 32 additions & 30 deletions docs/content/concepts/workspaces/workspace-initialization.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Initializers are used to customize workspaces and bootstrap required resources u

### Defining Initializers in WorkspaceTypes

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

```yaml
apiVersion: tenancy.kcp.io/v1alpha1
Expand All @@ -22,6 +22,15 @@ spec:
path: root
```

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`.

Since `WorkspaceType.spec.initializer` is a boolean field, each WorkspaceType comes with a single initializer by default. However each WorkspaceType inherits the initializers of its parent workspaces. As a result, it is possible to have multiple initializers on a WorkspaceType, but you will need to nest them.
Here is a example:

1. In `root` workspace, create a new WorkspaceType called `parent`. You will receive a `root:parent` initializer
2. In the newly created `parent` workspace, create a new WorkspaceType `child`. You will receive a `root:parent:child` initializer
3. Whenever a new workspace is created in the child workspace, it will receive both the `root:parent` as well as the `root:parent:child` initializer

### Enforcing Permissions for Initializers

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`.
Expand All @@ -37,6 +46,7 @@ rules:
resourceNames: ["example"]
verbs: ["initialize"]
```

You can then bind this role to a user or a group.

```yaml
Expand All @@ -54,46 +64,38 @@ roleRef:
apiGroup: rbac.authorization.k8s.io
```

## initializingworkspaces Virtual Workspace
## Writing Custom Initialization Controllers

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.
### Responsibilities Of Custom Intitialization Controllers

This Virtual Workspace can fetch `LogicalCluster` either by specific its name or using wildcard.
Custom Initialization Controllers are responsible for handling initialization logic for custom WorkspaceTypes. They interact with kcp by:

### Endpoint URL path
1. Watching for the creation of new LogicalClusters (the backing object behind Workspaces) with the corresponding initializer on them
2. Running any custom initialization logic
3. Removing the corresponding initializer from the `.status.initializers` list of the LogicalCluster after initialization logic has successfully finished

`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.
In order to simplify these processes, kcp provides the `initializingworkspaces` virtual workspace.

### The `initializingworkspaces` Virtual Workspace

```yaml
virtualWorkspaces:
- url: https://<front-proxy-ip>:6443/services/initializingworkspaces/<initializer>
```
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.

This is an example URL path for accessing logical cluster apis for a specific initializer in a `initializingworkspaces` virtual workspace.
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:

```yaml
/services/initializingworkspaces/<initializer>/clusters/*/apis/core.kcp.io/v1alpha1/logicalclusters
```

You can also use `LogicalCluster` name for the direct view, allowing to manage all resources within that logical cluster.
```sh
$ kubectl get workspacetype example -o yaml

```yaml
/services/initializingworkspaces/<initializer>/clusters/<logical-cluster-name>/apis/core.kcp.io/v1alpha1/logicalclusters
...
status:
virtualWorkspaces:
- url: https://127.0.0.1:6443/services/initializingworkspaces/root:example
```

### Example workflow

* Add your custom WorkspaceType to the platform with an initializer.
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 a user with sufficient permissions (see [Enforcing Permissions for Initializers](#enforcing-permissions-for-initializers))

* Create a workspace with the necessary warrants and scopes. The workspace will stay in the initializing state as the initializer is present.

* Use a controller to watch your initializing workspaces, you can interact with the workspace through the virtual workspace endpoint:

```yaml
/services/initializingworkspaces/foo/clusters/*/apis/core.kcp.io/v1alpha1/logicalclusters
```
### Code Sample

* Once you get the object, you need to initialize the workspace with its related resources, using the same endpoint
* It is important to use the kcp-dev controller runtime fork, as regular controller runtime is not able to deal with all logical clusters being name "cluster"
* LogicalClusters cannot updated using update api, but must be updated using patch api

* Once the initialization is complete, use the same endpoint to remove the initializer from the workspace.
// TODO paste in sample once it is finished