devantler-tech / devantler-tech/ksail

feat: see & operate on unmanaged kubeconfig clusters across the CLI, desktop app & web UI

Open
#5,654 1 comment 0 reactions 0 assignees View on GitHub
enhancement roadmap
Dominant language
Go
Stars
165
Forks
12
Avg merge
5h 41m
Merged PRs (30d)
337

Description

> 🤖 Generated by the Daily AI Assistant

## Problem

ksail only "sees" clusters that it discovers through its **infrastructure providers** (Docker / Hetzner / Omni / AWS-EKS / nested-Kubernetes) plus in-flight lifecycle jobs — `Service.List()` in `pkg/cli/clusterapi/local_service.go`, which backs both the CLI (`ksail cluster list`) and the web UI / desktop app. A cluster that already exists in the user's kubeconfig but was **not** provisioned by ksail (a managed EKS/GKE/AKS cluster, a kubeadm cluster, a colleague's cluster, etc.) is **invisible** everywhere — even though most of ksail's read/operate surface already works against any context via client-go.

## Goal

ksail should be able to **see and operate on any kubeconfig cluster**, across **both the CLI and the desktop app / web UI**, within the limitations of what it can do for a cluster it does **not** manage. Unmanaged (kubeconfig-only) clusters are shown **clearly and visibly marked as unmanaged / unsupported** — never hidden, never presented as a normal managed cluster, and never silently failing when a ksail-only action is attempted.

## What already works generically (any kubeconfig context, via client-go)

Resource browsing, pod logs & exec, `kubectl`-style access, server-side manifest apply, kubeconfig export, apiserver proxy/watch, and secrets cipher are all client-go / local-key backed and need no per-cluster ksail metadata — so they should "just work" against an imported cluster once ksail can select it.

## Proposed direction

1. **One cluster model, marked.** Extend cluster enumeration (`Service.List()` / `enumerate`) to also read the user's kubeconfig (`clientcmd`) and synthesize a `v1alpha1.Cluster` for each context **not** already discovered via a provider — keyed by context name and flagged **unmanaged / kubeconfig-only**. Distribution/provider are best-effort hints (context-name / server-URL heuristics) and left empty when unknown. This one model feeds **both** the CLI and the UI, so behaviour is identical across surfaces. The existing injectable `kubeconfigPath` seam makes it unit-testable with a fixture kubeconfig.
2. **CLI surfaces them, marked.** See the CLI parity section below.
3. **UI surfaces them, marked.** An "Add / import from kubeconfig" affordance in `ClusterFormDialog.tsx`; render unmanaged clusters in `ClustersTable.tsx` / `ClusterSwitcher.tsx` with a clear **unmanaged** badge and a graceful `—` for unknown distribution/provider.
4. **Gate ksail-only actions with the existing capability flags** (no silent failures) — reusing the flags the local backend already emits (`clusterUpdate`, component-install, start/stop, …); no new flags expected.

## CLI parity — `ksail cluster` and `ksail workload`

The same "see + operate within limits, clearly marked unmanaged" model applies to the CLI. `ksail cluster list` and `ksail cluster switch` are the headline cases; the rest of the `cluster` and `workload` groups follow the same rule:

- **See / select (work on any kubeconfig context) — surface with an explicit `unmanaged` / `unsupported` marker:**
- `ksail cluster list` — include kubeconfig contexts not managed by ksail, with an explicit `unmanaged` status column (never hidden, never shown as a normal managed cluster).
- `ksail cluster switch` — allow switching the active context to an unmanaged cluster (it is just a kubeconfig context switch), noting it is unmanaged.
- `ksail cluster info` / `ksail cluster connect` — show/emit what client-go can (endpoint, kubeconfig access), with unknown ksail-only fields shown as `—`.
- **Operate within limits (client-go-backed — work on the selected context):** `ksail workload {kubectl, watch, network, edit, images, push, render, validate, scan, debug}` and `ksail cluster diagnose` should work against the selected unmanaged context. GitOps-driven commands (`ksail workload reconcile`, `ksail workload install`) depend on ksail/GitOps config and should clearly report "requires a ksail-managed / GitOps-configured cluster" when that config is absent — not a stack trace.
- **Manage / lifecycle (ksail-only → refuse clearly on unmanaged):** `ksail cluster {create, delete, update, start, stop, backup, restore, repair, ttl}` must fail fast with a documented message (e.g. `cluster '' is not managed by ksail; lifecycle operations are unavailable for imported kubeconfig clusters`) — a clean, documented exit, never a stack trace or a silent no-op.

Consistency: the CLI `unmanaged` marker and the UI "unmanaged" badge are the **same** concept driven by the one marked cluster model, so a cluster behaves identically whether the user is on the CLI or in the UI.

## Limitations to make clearly & visibly unavailable on unmanaged (kubeconfig-only) clusters

These require ksail-managed provisioning / `spec.cluster.*` metadata, so they are shown as explicitly disabled/refused with a reason (UI: disabled control + tooltip; CLI: documented error):

- **Lifecycle operations** (create / delete / start / stop) — ksail has no provider or distribution to drive them.
- **Component installation** (CNI, CSI, metrics-server, GitOps/Flux, policy engine) — all driven from `spec.cluster.*`.
- **Reconfigure / re-provision & provider credentials** — no provider spec to act on.
- **GitOps operations** (reconcile / install) — need ksail/GitOps config, not just a kubeconfig.
- **Distribution / provider** shown as best-effort or `—` (no ksail spec to read).
- **Live status reconciliation** (phase / endpoint / nodesReady) — limited to what client-go can directly observe, without the operator's reconciler.

## Acceptance criteria

- `ksail cluster list` and the UI cluster list both show kubeconfig contexts not managed by ksail, clearly marked `unmanaged` / imported (CLI status column + UI badge).
- `ksail cluster switch` can select an unmanaged cluster; the client-go-backed read/operate commands (and their UI equivalents — resource browsing, logs/exec, manifest apply, proxy/watch) work against it.
- Every ksail-only action (lifecycle, component install, GitOps, reprovision) is **visibly disabled/refused with an explanation** on unmanaged clusters — never a silent failure, a bare 501, or an unhandled stack trace.
- No regression for ksail-managed clusters (they keep full capability across CLI + UI).
- Docs (CLI reference for `cluster`/`workload`, plus web UI / desktop) document unmanaged-cluster tracking and its visible-limitations model.

## Suggested decomposition (independently-shippable children)

1. **Backend enumeration + marked model** (natural first slice): kubeconfig-context enumeration in `Service.List()` → synthetic `v1alpha1.Cluster` with an **unmanaged** marker + a distribution-detection heuristic + tests via the `kubeconfigPath` fixture seam. Audit `spec.cluster.distribution` / `provider` optionality in `pkg/apis/cluster/v1alpha1/types.go` (`omitempty` / schema). This model is shared by all downstream children.
2. **CLI: see / select** — `ksail cluster list` shows the `unmanaged` marker; `ksail cluster switch` / `info` / `connect` operate on unmanaged contexts; `ksail cluster diagnose` + the client-go `workload` commands work against the selected context.
3. **CLI: refuse lifecycle clearly** — `ksail cluster {create,delete,update,start,stop,backup,restore,repair,ttl}` and GitOps `workload {reconcile,install}` return the documented "not managed by ksail" error for unmanaged clusters.
4. **Capability gating & API contract** — imported clusters report the right capability flags so ksail-only actions are disabled + labelled; confirm the `pkg/webui/api` contract stays cluster-agnostic.
5. **Web UI** — import affordance in `ClusterFormDialog.tsx` + unmanaged badge + graceful degraded rendering in `ClustersTable.tsx` / `ClusterSwitcher.tsx` (the SSE cluster-list stream already carries generic cluster objects, so `useClusterStream.ts` / `api.ts` likely need no change).
6. **Docs** — document the unmanaged-cluster tracking capability and the visible-limitations model across CLI + UI.

## Size

**Large (epic)** — decomposes into the small children above; the backend-enumeration + marked-model child (1) is the natural first increment and unblocks both the CLI (2/3) and UI (5) work.

## Change surface (grounded on `main`)

- **Backend / model:** `pkg/cli/clusterapi/local_service.go` (`List` / `enumerate` / `newCluster`), `pkg/apis/cluster/v1alpha1/types.go` (`ClusterSpec` optionality), `pkg/webui/api` (contract).
- **CLI:** `pkg/cli/cmd/cluster/{list,switch,info,connect,diagnose}.go` (surface + select), `pkg/cli/cmd/cluster/{create,delete,update,startstop,backup,restore,repair,ttl}.go` (refuse cleanly), `pkg/cli/cmd/workload/{reconcile,install}.go` (GitOps guard).
- **UI:** `web/ui/src/components/{ClustersTable,ClusterSwitcher,ClusterFormDialog}.tsx`, `web/ui/src/api.ts` (likely no change).

---

Part of the KSail-as-a-Kubernetes-UI direction (see roadmap #4988).

Contributor guide

Open the contributing guide

Research direction

Start with pkg/cli/clusterapi/local_service.go, especially List, enumerate, and newCluster, then inspect the kubeconfigPath fixture seam and pkg/apis/cluster/v1alpha1/types.go for optional distribution/provider fields. The first increment is complete when kubeconfig-only contexts are enumerated as marked synthetic clusters with tests, without changing managed-cluster behavior; later work covers the listed CLI and UI files.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, kubernetes, typescript
Domain
backend, cli, devops, frontend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.