mirror of
https://github.com/skoelle/kctl-tui.git
synced 2026-09-17 20:10:24 +00:00
update docs
This commit is contained in:
@@ -17,15 +17,17 @@ is still open. For the full requirements, see [SPEC.md](SPEC.md).
|
|||||||
## Phase 1 — Core logic + navigation (done, initial version)
|
## Phase 1 — Core logic + navigation (done, initial version)
|
||||||
|
|
||||||
- [x] `internal/kctl`: pure, unit-tested logic —
|
- [x] `internal/kctl`: pure, unit-tested logic —
|
||||||
context-pair matching (`FindNextContext`), namespace/label filtering
|
template resolution (`ResolveTemplate`), namespace/label filtering
|
||||||
(`DistinctLabelValues`, `NamespacesForLabelValue`), and secret diffing
|
(`DistinctLabelValues`, `NamespacesForLabelValue`), and secret diffing
|
||||||
(`DiffSecretValues`, `AnyMismatch`).
|
(`DiffSecretValues`, `AnyMismatch`).
|
||||||
- [x] `internal/config`: YAML config loading (`context_pairs`,
|
- [x] `internal/config`: YAML config loading with template-based context
|
||||||
`team_label_key`), with safe defaults when no config file exists yet.
|
and secret name resolution (`ContextTemplate`, `SecretNameTemplate`,
|
||||||
|
`K8sSecretNameTemplate`), with safe defaults when no config file
|
||||||
|
exists yet.
|
||||||
- [x] `internal/kubeexec`: thin wrappers around `kubectl`/`aws` CLI calls
|
- [x] `internal/kubeexec`: thin wrappers around `kubectl`/`aws` CLI calls
|
||||||
(contexts, namespaces, deployments, rollout restart/status, listing
|
(namespaces, deployments, rollout restart/status, fetching AWS
|
||||||
AWS secrets, reading all fields of a Kubernetes secret, ExternalSecret
|
secrets by template-resolved ID, reading all fields of a Kubernetes
|
||||||
annotation).
|
secret, ExternalSecret annotation, AWS auth check).
|
||||||
- [x] `cmd/kctl-tui` "full" mode: Bubble Tea navigation for
|
- [x] `cmd/kctl-tui` "full" mode: Bubble Tea navigation for
|
||||||
context -> team -> namespace, with `Esc` correctly popping back one
|
context -> team -> namespace, with `Esc` correctly popping back one
|
||||||
level at a time, defaults pre-selected from the currently active
|
level at a time, defaults pre-selected from the currently active
|
||||||
@@ -38,13 +40,13 @@ is still open. For the full requirements, see [SPEC.md](SPEC.md).
|
|||||||
- [x] `cmd/kctl-tui` "panel" mode:
|
- [x] `cmd/kctl-tui` "panel" mode:
|
||||||
- Redeploy: pick a deployment from a list, confirm, then
|
- Redeploy: pick a deployment from a list, confirm, then
|
||||||
`rollout restart` + `rollout status`.
|
`rollout restart` + `rollout status`.
|
||||||
- Secrets: pick an AWS region, then pick the actual secret from a
|
- Secrets: AWS auth check with interactive SSO login fallback,
|
||||||
**list of all AWS Secrets Manager secrets** in that region (no more
|
then automatically resolve the AWS secret ID (from
|
||||||
manual secret-ID typing), enter the matching Kubernetes secret
|
`secret_name_template`) and Kubernetes secret name (from
|
||||||
name, and automatically diff **every field** of both secrets in one
|
`k8s_secret_name_template`), fetch both, diff **every field**
|
||||||
table (key / AWS value / Kubernetes value / match status). If any
|
in one table (key / AWS value / Kubernetes value / match status).
|
||||||
field differs, offer a single force-sync request for the **whole
|
If any field differs, offer a single force-sync request for the
|
||||||
secret** (one ExternalSecret annotation), not per individual field.
|
**whole secret** (one ExternalSecret annotation).
|
||||||
- `Esc` closes the whole tmux session (`tmux kill-session`).
|
- `Esc` closes the whole tmux session (`tmux kill-session`).
|
||||||
|
|
||||||
## Phase 2 — Hardening (open)
|
## Phase 2 — Hardening (open)
|
||||||
@@ -68,9 +70,8 @@ is still open. For the full requirements, see [SPEC.md](SPEC.md).
|
|||||||
|
|
||||||
- [ ] Detect OS at runtime; on native Windows (no WSL), fall back to
|
- [ ] Detect OS at runtime; on native Windows (no WSL), fall back to
|
||||||
`wt.exe split-pane` instead of `tmux` for the status panes.
|
`wt.exe split-pane` instead of `tmux` for the status panes.
|
||||||
- [ ] Document/implement that `Tab`-based context switching and
|
- [ ] Document/implement that `Esc`-triggered session close is **not**
|
||||||
`Esc`-triggered session close are **not** available in the native
|
available in the native Windows fallback — the panes must be closed
|
||||||
Windows fallback, per SPEC.md 3.6 — the panes must be closed
|
|
||||||
manually there.
|
manually there.
|
||||||
|
|
||||||
## Phase 4 — Nice-to-haves (open, not committed)
|
## Phase 4 — Nice-to-haves (open, not committed)
|
||||||
@@ -82,9 +83,6 @@ is still open. For the full requirements, see [SPEC.md](SPEC.md).
|
|||||||
kubeconfig.
|
kubeconfig.
|
||||||
- [ ] Homebrew tap / `scoop` manifest as additional install options
|
- [ ] Homebrew tap / `scoop` manifest as additional install options
|
||||||
alongside `install.sh`.
|
alongside `install.sh`.
|
||||||
- [ ] Optional heuristic to suggest a matching Kubernetes secret name for
|
|
||||||
a chosen AWS secret (e.g. by common naming convention), instead of
|
|
||||||
always asking for it manually.
|
|
||||||
|
|
||||||
## Notes for contributors
|
## Notes for contributors
|
||||||
|
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ aws_region: "eu-central-1"
|
|||||||
aws_account_id: "123456789012"
|
aws_account_id: "123456789012"
|
||||||
|
|
||||||
secret_name_template: "tf-{namespace}-{env}-secrets"
|
secret_name_template: "tf-{namespace}-{env}-secrets"
|
||||||
|
k8s_secret_name_template: "{namespace}-common-secrets"
|
||||||
context_template: "arn:aws:eks:{region}:{account_id}:cluster/tf-{env}-{context}-1"
|
context_template: "arn:aws:eks:{region}:{account_id}:cluster/tf-{env}-{context}-1"
|
||||||
|
|
||||||
team_label_key: "example.org/team"
|
team_label_key: "example.org/team"
|
||||||
@@ -144,6 +145,10 @@ aws_sso_login_command: "aws sso login"
|
|||||||
- `secret_name_template`: builds the AWS Secrets Manager secret ID from
|
- `secret_name_template`: builds the AWS Secrets Manager secret ID from
|
||||||
the chosen namespace and environment. Placeholders: `{namespace}`,
|
the chosen namespace and environment. Placeholders: `{namespace}`,
|
||||||
`{env}`.
|
`{env}`.
|
||||||
|
- `k8s_secret_name_template`: builds the Kubernetes secret name from the
|
||||||
|
chosen namespace. Kept separate from `secret_name_template` because the
|
||||||
|
two sides commonly follow different naming conventions. Placeholders:
|
||||||
|
`{namespace}`.
|
||||||
- `context_template`: builds the actual kubectl context name/ARN from
|
- `context_template`: builds the actual kubectl context name/ARN from
|
||||||
region, account ID, environment, and context. Placeholders: `{region}`,
|
region, account ID, environment, and context. Placeholders: `{region}`,
|
||||||
`{account_id}`, `{env}`, `{context}`. Adjust the literal parts (`tf-`,
|
`{account_id}`, `{env}`, `{context}`. Adjust the literal parts (`tf-`,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
A single terminal tool as the central entry point for everyday Kubernetes
|
A single terminal tool as the central entry point for everyday Kubernetes
|
||||||
work, bundling the most common workflows currently done via long
|
work, bundling the most common workflows currently done via long
|
||||||
`kubectl`/`k9s`/`aws-cli` commands, operable through a text UI (arrow keys,
|
`kubectl`/`k9s`/`aws-cli` commands, operable through a text UI (arrow keys,
|
||||||
Esc, Tab) instead of long typed commands.
|
Esc) instead of long typed commands.
|
||||||
|
|
||||||
Target platform: **Linux / WSL** (primary usage scenario, since split
|
Target platform: **Linux / WSL** (primary usage scenario, since split
|
||||||
panes require a real terminal multiplexer). Native Windows (without WSL)
|
panes require a real terminal multiplexer). Native Windows (without WSL)
|
||||||
@@ -49,9 +49,6 @@ Navigation:
|
|||||||
(`tmux kill-session`, closing both k9s panes as well) and then moves the
|
(`tmux kill-session`, closing both k9s panes as well) and then moves the
|
||||||
Go tool's screen stack one level up: namespace selection -> team
|
Go tool's screen stack one level up: namespace selection -> team
|
||||||
selection -> context selection.
|
selection -> context selection.
|
||||||
- **Tab** in the control pane switches the context pair according to the
|
|
||||||
context-pair pattern (see 3.6) for both status panes simultaneously; the
|
|
||||||
namespace stays the same.
|
|
||||||
|
|
||||||
### 3.2 Namespace grouping via labels
|
### 3.2 Namespace grouping via labels
|
||||||
|
|
||||||
@@ -64,10 +61,10 @@ Navigation:
|
|||||||
kubectl get ns -o jsonpath='{range .items[*]}{.metadata.labels["<team-label-key>"]}{"\n"}{end}' | sort -u
|
kubectl get ns -o jsonpath='{range .items[*]}{.metadata.labels["<team-label-key>"]}{"\n"}{end}' | sort -u
|
||||||
```
|
```
|
||||||
- The actual label key is project-specific and set via the configuration
|
- The actual label key is project-specific and set via the configuration
|
||||||
file (see 3.6), not hardcoded.
|
file (see `team_label_key` in config), not hardcoded.
|
||||||
- Namespace labeling is a prerequisite (one-time setup outside the tool).
|
- Namespace labeling is a prerequisite (one-time setup outside the tool).
|
||||||
|
|
||||||
### 3.3 Layout: 3-panel view (core design change vs. earlier drafts)
|
### 3.3 Layout: 3-panel view
|
||||||
|
|
||||||
Once start navigation is complete, the tool opens a tmux session with
|
Once start navigation is complete, the tool opens a tmux session with
|
||||||
**three panes**, started with a single command:
|
**three panes**, started with a single command:
|
||||||
@@ -93,10 +90,12 @@ Example startup command (generic placeholders):
|
|||||||
|
|
||||||
```
|
```
|
||||||
tmux new-session -d -s kctl \
|
tmux new-session -d -s kctl \
|
||||||
"kctl-tui panel --ctx=$CTX_A --ns=$NS --team=$TEAM" \; \
|
"kctl-tui panel --context=$CTX_A --ns=$NS --team=$TEAM" \; \
|
||||||
split-window -v "k9s --context $CTX_A -n $NS" \; \
|
set-option -t kctl remain-on-exit on \; \
|
||||||
split-window -v "k9s --context $CTX_B -n $NS" \; \
|
split-window -v -t kctl:0.0 "k9s --context $CTX_A -n $NS" \; \
|
||||||
select-layout main-horizontal \; \
|
split-window -v -t kctl:0.1 "k9s --context $CTX_B -n $NS" \; \
|
||||||
|
select-layout -t kctl even-vertical \; \
|
||||||
|
select-pane -t kctl:0.0 \; \
|
||||||
attach -t kctl
|
attach -t kctl
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -115,54 +114,66 @@ Switching between panes: `Ctrl-b` + arrow key, or `Ctrl-b` `o`.
|
|||||||
|
|
||||||
### 3.5 AWS Secrets Manager <-> Kubernetes Secret diff — in the control pane
|
### 3.5 AWS Secrets Manager <-> Kubernetes Secret diff — in the control pane
|
||||||
|
|
||||||
1. Load the secret from AWS Secrets Manager:
|
1. Before entering the secrets workflow, verify the AWS session is valid
|
||||||
|
(`aws sts get-caller-identity`). If expired, offer to run the
|
||||||
|
configured SSO login command interactively.
|
||||||
|
2. Resolve the AWS Secrets Manager secret ID from `secret_name_template`
|
||||||
|
(using namespace + env) and the Kubernetes secret name from
|
||||||
|
`k8s_secret_name_template` (using namespace). No manual input required
|
||||||
|
for either name.
|
||||||
|
3. Fetch the AWS secret:
|
||||||
`aws secretsmanager get-secret-value --secret-id <secret-id> --region <region> --query SecretString --output text`.
|
`aws secretsmanager get-secret-value --secret-id <secret-id> --region <region> --query SecretString --output text`.
|
||||||
2. Show the contained keys for selection.
|
4. Fetch all fields of the Kubernetes secret and base64-decode them:
|
||||||
3. Load the matching Kubernetes secret field:
|
`kubectl -n <ns> get secret <secret-name> -o json`.
|
||||||
`kubectl -n <ns> get secret <secret-name> -o jsonpath='{.data.<field>}'`,
|
5. Compare every field at once in a table (key / AWS value / Kubernetes
|
||||||
base64-decode it.
|
value / match status).
|
||||||
4. Compare the values (identical / different).
|
6. On mismatch, optionally request a force-sync for the whole secret:
|
||||||
5. On mismatch, optionally request a force-sync:
|
|
||||||
`kubectl -n <ns> annotate externalsecret <name> force-sync=<unix-timestamp> --overwrite`.
|
`kubectl -n <ns> annotate externalsecret <name> force-sync=<unix-timestamp> --overwrite`.
|
||||||
|
|
||||||
All names (secret ID, secret name, field name, ExternalSecret name) are
|
The ExternalSecret object name for the force-sync annotation is the only
|
||||||
asked for interactively at runtime, never hardcoded in the tool.
|
value asked for interactively at runtime.
|
||||||
|
|
||||||
### 3.6 Context-pair pattern (configurable) — drives both status panes at once
|
### 3.6 Context resolution via templates
|
||||||
|
|
||||||
Requirement: the Tab switch in the control pane must switch **both**
|
The actual kubectl context name/ARN for each environment is computed from
|
||||||
status panes below it, not just an internal state.
|
a configurable template at startup. The two k9s status panes and all
|
||||||
|
kubectl calls in the control pane use the resolved context.
|
||||||
|
|
||||||
Configuration format (e.g. `~/.kctl-tui/config.yaml`), purely illustrative
|
Configuration format (e.g. `~/.kctl-tui/config.yaml`), purely illustrative
|
||||||
with generic placeholders:
|
with generic placeholders:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
context_pairs:
|
contexts:
|
||||||
- name: "environment-pair-1"
|
- "internal"
|
||||||
contexts: ["<context-a1>", "<context-a2>"]
|
- "external"
|
||||||
- name: "environment-pair-2"
|
default_context: "internal"
|
||||||
contexts: ["<context-b1>", "<context-b2>"]
|
|
||||||
|
envs:
|
||||||
|
- "beta"
|
||||||
|
- "prod"
|
||||||
|
|
||||||
|
aws_region: "eu-central-1"
|
||||||
|
aws_account_id: "123456789012"
|
||||||
|
|
||||||
|
context_template: "arn:aws:eks:{region}:{account_id}:cluster/tf-{env}-{context}-1"
|
||||||
|
secret_name_template: "tf-{namespace}-{env}-secrets"
|
||||||
|
k8s_secret_name_template: "{namespace}-common-secrets"
|
||||||
|
|
||||||
team_label_key: "<organization>/<label-name>"
|
team_label_key: "<organization>/<label-name>"
|
||||||
```
|
```
|
||||||
|
|
||||||
Behavior on Tab in the control pane:
|
The `context_template` replaces `{region}`, `{account_id}`, `{env}`, and
|
||||||
|
`{context}` placeholders with the configured values and the currently
|
||||||
|
selected environment/context. The resolved value must match an existing
|
||||||
|
context in your kubeconfig (e.g. added via `aws eks update-kubeconfig`).
|
||||||
|
|
||||||
1. Determine the current context pair from the configuration.
|
**Platform limitation on Windows without WSL:** `kill-session` is
|
||||||
2. Restart both k9s panes via
|
tmux-specific. Windows Terminal (`wt.exe`) offers no equivalent scripting
|
||||||
`tmux respawn-pane -k -t kctl:0.1 "k9s --context <newA> -n <ns>"` and
|
to end the session from inside a pane. On plain Windows (without WSL),
|
||||||
`... kctl:0.2 ...` (namespace stays the same).
|
only a simplified flow is possible: k9s panes are closed manually (`q`,
|
||||||
3. If the current context is in no configured list: show a hint in the
|
then `Ctrl+Shift+W`); automatic session termination is unavailable there.
|
||||||
control pane instead of an error.
|
This limitation is the main reason the primary target system is set to
|
||||||
4. No action outside this configuration — no error, only a hint.
|
Linux/WSL.
|
||||||
|
|
||||||
**Platform limitation on Windows without WSL:** `respawn-pane`/
|
|
||||||
`kill-session` are tmux-specific. Windows Terminal (`wt.exe`) offers no
|
|
||||||
equivalent scripting to replace panes or end the session from inside a
|
|
||||||
pane. On plain Windows (without WSL), only a simplified flow is possible:
|
|
||||||
k9s panes are closed manually (`q`, then `Ctrl+Shift+W`); Tab switching and
|
|
||||||
automatic session termination are unavailable there. This limitation is
|
|
||||||
the main reason the primary target system is set to Linux/WSL.
|
|
||||||
|
|
||||||
## 4. Non-functional requirements
|
## 4. Non-functional requirements
|
||||||
|
|
||||||
@@ -240,8 +251,8 @@ Rejected options (see discussion history):
|
|||||||
- Split view v1 fixed at 2 status panes + 1 control pane (3 panes total).
|
- Split view v1 fixed at 2 status panes + 1 control pane (3 panes total).
|
||||||
- No RBAC/permission checks before executing sensitive actions — the tool
|
- No RBAC/permission checks before executing sensitive actions — the tool
|
||||||
assumes existing kubectl permissions.
|
assumes existing kubectl permissions.
|
||||||
- Configuration file format (`config.yaml`) is a proposal, not finally
|
- Configuration file format (`config.yaml`) is defined and implemented;
|
||||||
agreed; concrete label keys, context names, and namespace names are
|
concrete label keys, context names, and namespace names are
|
||||||
project-specific and belong exclusively in the user's local, unversioned
|
project-specific and belong exclusively in the user's local, unversioned
|
||||||
configuration, not in this document or the source code.
|
configuration, not in this document or the source code.
|
||||||
- Native Windows (without WSL) remains a secondary platform with manual
|
- Native Windows (without WSL) remains a secondary platform with manual
|
||||||
|
|||||||
Reference in New Issue
Block a user