-
Notifications
You must be signed in to change notification settings - Fork 6
0002: Add mounts proposal #6
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
Open
mjudeikis
wants to merge
10
commits into
kcp-dev:main
Choose a base branch
from
mjudeikis:mjudeikis/mounts
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+281
−0
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
27094b7
WIP for proxy implementation
mjudeikis a1b9575
add example
mjudeikis ccd54a9
add tmc to the mix
mjudeikis 4fe0119
option 3
mjudeikis 821734b
add proxy/mount functionality
mjudeikis 1ef703d
nit about annotation vs spec
mjudeikis d791b0a
addressed the scope and terminology
mjudeikis 732fbec
add workspace status propagation
mjudeikis 9e7630d
clean the language
mjudeikis 5d22065
tabs vs spaces
mjudeikis File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,281 @@ | ||
# Workspace Mounts Enhancement Proposal | ||
|
||
## Summary | ||
|
||
To extend the spectrum of use cases for `kcp`, we need to support workspaces that | ||
are not backed by a `kcp` cluster itself but are backed by a mount that can be used | ||
to proxy requests directly to remote clusters or other workspaces. This enables | ||
use cases where external and internal integrations can be added into the same workspace structure. | ||
|
||
## Motivation | ||
|
||
This would enable use cases where `kcp` is used as a proxy to remote clusters, but | ||
some of the infrastructure is still managed by `kcp`. For example, `kcp` could be | ||
responsible for ArgoCD, Crossplane, or other infrastructure that is more CRD-based. | ||
|
||
At this point, communication between `kcp` and remote clusters is done via workspace abstractions. | ||
|
||
For example: | ||
``` | ||
$ kubectl ws tree | ||
root | ||
├── clusters (workspace) | ||
│ ├── cluster-mount (normal workspace, with mounted cluster ontop of it) | ||
│ ├── cluster-1 (workspace) | ||
├── infra (workspace) | ||
│ ├── argocd (workspace) | ||
│ ├── crossplane (workspace) | ||
... | ||
``` | ||
|
||
Where `cluster-mount` is a workspace backed by a mount that can be used to proxy | ||
requests to remote clusters. This provides a unified way of interacting with | ||
remote clusters while still having the ability to manage some of the infrastructure | ||
via `kcp`. | ||
|
||
### Goals | ||
|
||
1. Mounting remote clusters as workspaces. | ||
2. Softlink - mounting other workspaces as sub-workspaces, where changing the | ||
sub-workspace would change the parent workspace as well. | ||
3. Workspace status propagation - when mounting a workspace, there should be a | ||
way to propagate the status to the workspace itself, preventing false positives. | ||
|
||
### Non-Goals | ||
|
||
* Proxy/Mount functionality is not meant to replace `kcp` clusters. Additionally, | ||
the implementation of the mount functionality itself is out of the scope of this | ||
proposal. We should enable the mount functionality to be implemented by third | ||
parties using `kcp` as a platform. | ||
|
||
* Mount resources. This proposal is about enabling the mount functionality for | ||
all workspaces, not about mounting individual resources inside a workspace. | ||
|
||
* AuthN/AuthZ is out of scope of this proposal. We assume that the mount functionality | ||
implements just forwarding and redirections. Authentication and authorization are | ||
the implementer's responsibility, either by federating identities or using other | ||
means to authenticate and authorize requests. | ||
|
||
## Proposal | ||
|
||
Introduce an experimental `Mount` API to enable two use cases: | ||
|
||
1. Mounting remote clusters as workspaces. | ||
2. Softlink - mounting other workspaces as sub-workspaces, where changing the | ||
sub-workspace would change the parent workspace as well. | ||
|
||
Initially, we would put Mount into the annotation of the workspace, but in the | ||
future, we will promote it to the spec of the workspace. | ||
|
||
### Mount API | ||
|
||
This is a proposal for a mount API. This contains two parts: | ||
|
||
1. Experimental mount API used in the annotation of the workspace. | ||
2. Proposal for how this could look when promoted to the workspace structure. | ||
|
||
|
||
#### Experimental Mount API | ||
|
||
As an experimental API, we would place the mount into the annotation of the workspace. | ||
|
||
```go | ||
// Mount is a workspace mount that can be used to mount a workspace into another workspace or resource. | ||
// Mounting itself is done at the front proxy level. | ||
type Mount struct { | ||
// MountSpec is the spec of the mount. | ||
MountSpec MountSpec `json:"spec,omitempty"` | ||
// MountStatus is the status of the mount. | ||
MountStatus MountStatus `json:"status,omitempty"` | ||
} | ||
mjudeikis marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
type MountSpec struct { | ||
// Reference is an ObjectReference to the object that is mounted. | ||
Reference *corev1.ObjectReference `json:"ref,omitempty"` | ||
// Type is the type of the mount (URL, Redirect, Workspace). | ||
// +kubebuilder:default=Cluster | ||
Type MountType `json:"type,omitempty"` | ||
} | ||
|
||
// MountStatus is the status of a mount. It is used to indicate the status of a mount, | ||
// potentially managed outside of the core API. | ||
type MountStatus struct { | ||
// Phase of the mount (Initializing, Connecting, Ready, Unknown). | ||
// | ||
// +kubebuilder:default=Initializing | ||
Phase MountPhaseType `json:"phase,omitempty"` | ||
// Conditions is a list of conditions and their status. | ||
// Current processing state of the Mount. | ||
// +optional | ||
Conditions conditionsv1alpha1.Conditions `json:"conditions,omitempty"` | ||
|
||
// URL is the URL of the mount. Mount is considered mounted when the URL is set. | ||
// +optional | ||
URL string `json:"url,omitempty"` | ||
} | ||
``` | ||
|
||
#### Promoted Workspace API | ||
|
||
When the mount is promoted to the workspace spec, it could look like the example | ||
below. Mount would be just yet another condition on the workspace. The most important | ||
change is that the mount would be part of the workspace spec, and if the mount | ||
implementation becomes unhealthy, it would be reflected in the workspace conditions. | ||
This would drive the `Phase` change of the workspace. More on this in the next section. | ||
|
||
```go | ||
// WorkspaceSpec defines the desired state of Workspace | ||
type WorkspaceSpec struct { | ||
... | ||
// Mount is a workspace mount that can be used to mount a workspace into another workspace or resource. | ||
Mount *Mount `json:"mount,omitempty"` | ||
} | ||
|
||
// Mount is a workspace mount that can be used to mount a workspace into another workspace or resource. | ||
type Mount struct { | ||
// Reference is an ObjectReference to the object that is mounted. | ||
Reference *corev1.ObjectReference `json:"ref,omitempty"` | ||
// Type is the type of the mount (URL, Redirect, Workspace). | ||
// +kubebuilder:default=Cluster | ||
Type MountType `json:"type,omitempty"` | ||
} | ||
|
||
// WorkspaceStatus defines the observed state of Workspace | ||
type WorkspaceStatus struct { | ||
// Phase of the workspace (Scheduling, Initializing, Ready). | ||
// | ||
// +kubebuilder:default=Scheduling | ||
Phase corev1alpha1.LogicalClusterPhaseType `json:"phase,omitempty"` | ||
|
||
// Current processing state of the Workspace. | ||
// +optional | ||
Conditions conditionsv1alpha1.Conditions `json:"conditions,omitempty"` | ||
|
||
// Initializers must be cleared by a controller before the workspace is ready | ||
// and can be used. | ||
// | ||
// +optional | ||
Initializers []corev1alpha1.LogicalClusterInitializer `json:"initializers,omitempty"` | ||
|
||
// MountURL is the URL of the mount. Mount is considered mounted when the URL is set. | ||
// +optional | ||
MountURL string `json:"mountURL,omitempty"` | ||
} | ||
``` | ||
|
||
#### Type explanations | ||
|
||
Where `MountType` is an enum that would allow specifying the type of the mount: | ||
|
||
- `Proxy` - the mount is backed by a URL and should be used as a proxy to a remote cluster. | ||
- `Redirect` - the mount is backed by another workspace and should be used as a redirect to another workspace. | ||
- `LogicalCluster` - the mount is backed by another workspace and should be used as a proxy to another workspace/logical cluster. | ||
|
||
`Proxy` most simple proxy implementation is URL where we would just proxy all requests. | ||
A more advanced implementation could include `VirtualWorkspace` or an external | ||
service. But from a `kcp` perspective, it's a reverse proxy to a configured URL. | ||
|
||
`Redirect` and `LogicalCluster` have two main behaviors. These include softlinking | ||
of the (external or internal). | ||
|
||
1. Case 1: Local redirect: | ||
|
||
As a user, I want to redirect workspace `:users:john` to `:my-org:dev:john` so | ||
that I can have a redirect inside the same instance of `kcp`. In this case, the | ||
front proxy returns a `301 Redirect` request with a local (hostless) path to the | ||
new workspace. The CLI should be able to follow the redirect and update the local | ||
kubeconfig to point to the new workspace. | ||
|
||
1. Case 2: External redirect: | ||
|
||
As a user, I want to redirect workspace `:users:john` to `https://kcp.mycompany.com/workspaces/my-org/dev/john` | ||
so that I can have a redirect to another `kcp` instance. In this case, the front proxy | ||
returns a `301 Redirect` request with a full URL to the new workspace. The CLI | ||
should be able to follow the redirect and update the local kubeconfig. This | ||
would allow nesting different `kcp` instances. | ||
|
||
`Reference` is a reference to the object that is mounted. It can be a reference | ||
to an external object used to back the mount. | ||
|
||
Object reference would be read by the `kcp` core mount controller. It will retrieve | ||
the proxy URL from the referenced object's status and copy it into the mount status. | ||
This way, third-party components never need to interact with the `kcp` core or workspace | ||
directly in write mode. Moreover, the front-proxy interpreting the mount status URL | ||
does not have to read these mount implementation objects directly either. | ||
|
||
```yaml | ||
apiVersion: proxy.contrib.kcp.io/v1alpha1 | ||
kind: WorkspaceProxy | ||
metadata: | ||
name: cluster-proxy | ||
spec: | ||
type: passthrough | ||
``` | ||
|
||
### Workspace & Mount Status Propagation | ||
|
||
When mounting a workspace, there should be a way to propagate the status to the | ||
workspace itself, ensuring that the workspace is not falsely marked as ready when | ||
the mount is not ready. | ||
|
||
When a workspace mount is implemented by external objects: | ||
```go | ||
// Reference is an ObjectReference to the object that is mounted. | ||
Reference *corev1.ObjectReference `json:"ref,omitempty"` | ||
``` | ||
|
||
We need a way to propagate the status from the mount object to the workspace object. | ||
|
||
The suggestion is to create a `kcp` core controller which would propagate any | ||
conditions from the mount object to the workspace object which starts with the `Workspace*` prefix. | ||
|
||
If an object, implementing object raises conditions: | ||
|
||
```yaml | ||
conditions: | ||
- lastTransitionTime: "2024-04-28T10:43:29Z" | ||
status: "False" | ||
type: ConnectorReady | ||
- lastTransitionTime: "2024-04-28T10:43:29Z" | ||
status: "False" | ||
type: WorkspaceMountReady | ||
``` | ||
it would be propagated to the workspace object as bellow, making workspace | ||
unavailable: | ||
```yaml | ||
status: | ||
conditions: | ||
- lastTransitionTime: "2024-04-28T10:43:29Z" | ||
status: "True" | ||
type: MountReady | ||
- lastTransitionTime: "2024-04-28T10:40:25Z" | ||
status: "True" | ||
type: WorkspaceScheduled | ||
- lastTransitionTime: "2024-04-28T10:43:29Z" | ||
status: "False" | ||
type: MountReady | ||
phase: Unavailable | ||
``` | ||
|
||
Proposal is to make workspace conditions propagated as aggregate to workspace `phase`. | ||
|
||
Current flow: `Creating -> Initializing -> Ready` where once workspace is created and ready | ||
it is marked as ready and never updated. | ||
|
||
Proposed flow: `Creating -> Initializing -> Ready <-> Unavailable.` where if any of the conditions | ||
are not `Ready` the workspace is marked as `Unavailable`. | ||
|
||
This would be achieved my adding new controller into `kcp` core to reconcile workspace phase | ||
based on its own conditions. | ||
|
||
Existing mount controller would be responsible for propagating conditions from the mount object | ||
to the workspace object. | ||
|
||
#### Suggested action items | ||
|
||
1. Define the scope of the mount functionality. | ||
2. Determine the implementation approach for the mount functionality. | ||
|
||
#### Suggested timeline | ||
|
||
Efforts will proceed on a best-effort basis. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.