|
| 1 | +# Workspace Termination |
| 2 | + |
| 3 | +Workspace termination in kcp involves setting up optional cleanup logic when a Workspace is marked for deletion. This process is managed through `terminators`, which are enabled via `WorkspaceType` objects. In kcp, Terminators are the counterpart to [initializers](workspace-initialization.md). This document covers how to configure terminators, the necessary RBAC permissions, URL schemes, and the reasons for using terminators. |
| 4 | + |
| 5 | +## Terminators |
| 6 | + |
| 7 | +Terminators are used to customize the cleanup of workspaces and required resources. Terminators are defined in `WorkspaceType` objects and will be propagated to Workspaces and LogicalClusters. By doing this, users can create controllers processing `LogicalClusters` and running custom cleanup logic. Afterwards the controller has to remove its corresponding terminator. Once all terminators are removed, a logical cluster will be deleted. After a logical-cluster is deleted, its workspace is also ready for deletion. |
| 8 | + |
| 9 | +Terminators are meant to be used specifically to customize deletion logic of LogicalClusters. For resources inside your workspace, you can use traditional Kubernetes finalizers. |
| 10 | + |
| 11 | +### Defining Terminators in WorkspaceTypes |
| 12 | + |
| 13 | +A `WorkspaceType` can specify having a terminator using the `terminator` field. Here is an example of a `WorkspaceType` with a terminator. |
| 14 | + |
| 15 | +```yaml |
| 16 | +apiVersion: tenancy.kcp.io/v1alpha1 |
| 17 | +kind: WorkspaceType |
| 18 | +metadata: |
| 19 | + name: example |
| 20 | +spec: |
| 21 | + terminator: true |
| 22 | + defaultChildWorkspaceType: |
| 23 | + name: universal |
| 24 | + path: root |
| 25 | +``` |
| 26 | +
|
| 27 | +Each terminator 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` in the `root` workspace, your terminator would be called `root:example`. |
| 28 | + |
| 29 | +Since `WorkspaceType.spec.terminators` is a boolean field, each `WorkspaceType` comes with a single terminator by default. However each `WorkspaceType` inherits the terminators of its parent WorkspaceType. As a result, it is possible to have multiple terminators on a `WorkspaceType` using [WorkspaceType Extension](../../concepts/workspaces/workspace-types.md#workspace-type-extensions-and-constraints) |
| 30 | + |
| 31 | +In the following example, `child` inherits the terminators of `parent`. As a result, child workspaces will have the `root:child` and `root:parent` terminators set. |
| 32 | + |
| 33 | +```yaml |
| 34 | +apiVersion: tenancy.kcp.io/v1alpha1 |
| 35 | +kind: WorkspaceType |
| 36 | +metadata: |
| 37 | + name: child |
| 38 | +spec: |
| 39 | + terminator: true |
| 40 | + extend: |
| 41 | + with: |
| 42 | + - name: parent |
| 43 | + path: root |
| 44 | +``` |
| 45 | + |
| 46 | +### Enforcing Permissions for Terminators |
| 47 | + |
| 48 | +The non-root user must have the `terminate` verb on the `WorkspaceType` that the terminator is for. This ensures that only authorized users can perform termination actions using the virtual workspace endpoint. Here is an example of the `ClusterRole`. |
| 49 | + |
| 50 | +```yaml |
| 51 | +apiVersion: rbac.authorization.k8s.io/v1 |
| 52 | +kind: ClusterRole |
| 53 | +metadata: |
| 54 | + name: terminate-example-workspacetype |
| 55 | +rules: |
| 56 | + - apiGroups: ["tenancy.kcp.io"] |
| 57 | + resources: ["workspacetypes"] |
| 58 | + resourceNames: ["example"] |
| 59 | + verbs: ["terminate"] |
| 60 | +``` |
| 61 | + |
| 62 | +You can then bind this role to a user or a group. |
| 63 | + |
| 64 | +```yaml |
| 65 | +apiVersion: rbac.authorization.k8s.io/v1 |
| 66 | +kind: ClusterRoleBinding |
| 67 | +metadata: |
| 68 | + name: terminate-example-workspacetype-binding |
| 69 | +subjects: |
| 70 | + - kind: User |
| 71 | + name: user1 |
| 72 | + apiGroup: rbac.authorization.k8s.io |
| 73 | +roleRef: |
| 74 | + kind: ClusterRole |
| 75 | + name: terminate-example-workspacetype |
| 76 | + apiGroup: rbac.authorization.k8s.io |
| 77 | +``` |
| 78 | + |
| 79 | +## Writing Custom Termination Controllers |
| 80 | + |
| 81 | +Custom Termination Controllers are responsible for handling termination logic for custom WorkspaceTypes. They interact with kcp by: |
| 82 | + |
| 83 | +1. Watching for `LogicalClusters` (the backing object behind Workspaces) which are marked for deletion and have the corresponding terminator set |
| 84 | +2. Running any custom cleanup logic |
| 85 | +3. Removing the corresponding terminator from the `.status.terminators` list of the `LogicalCluster` after cleanup logic has successfully finished |
| 86 | + |
| 87 | +In order to simplify these processes, kcp provides the `terminating` virtual workspace. |
| 88 | + |
| 89 | +### The `terminating` Virtual Workspace |
| 90 | + |
| 91 | +As a service provider, you can use the `terminatingworkspaces` virtual workspace to manage workspace resources in the terminating phase. This virtual workspace allows you to fetch `LogicalCluster` objects which have a DeletionTimeStamp and request termination by a specific controller. |
| 92 | + |
| 93 | +You can retrieve the url for the TerminatingVirtualWorkspace 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: |
| 94 | + |
| 95 | +```sh |
| 96 | +$ kubectl get workspacetype example -o yaml |
| 97 | +... |
| 98 | +status: |
| 99 | + virtualWorkspaces: |
| 100 | + - url: https://<shard-url>/services/terminatingworkspaces/root:example |
| 101 | +``` |
| 102 | + |
| 103 | +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 Terminators](#enforcing-permissions-for-terminators)) |
| 104 | + |
| 105 | +### Practical Tips |
| 106 | + |
| 107 | +When writing a custom terminator controller, the following needs to be taken into account: |
| 108 | + |
| 109 | +* We strongly recommend to use [multicluster-runtime](github.com/kcp-dev/multicluster-runtime) to build your controller in order to properly handle which `LogicalCluster` originates from which workspace |
| 110 | +* You need to update `LogicalClusters` using patches; They cannot be updated using the update api |
0 commit comments