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)
|
||||
|
||||
- [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
|
||||
(`DiffSecretValues`, `AnyMismatch`).
|
||||
- [x] `internal/config`: YAML config loading (`context_pairs`,
|
||||
`team_label_key`), with safe defaults when no config file exists yet.
|
||||
- [x] `internal/config`: YAML config loading with template-based context
|
||||
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
|
||||
(contexts, namespaces, deployments, rollout restart/status, listing
|
||||
AWS secrets, reading all fields of a Kubernetes secret, ExternalSecret
|
||||
annotation).
|
||||
(namespaces, deployments, rollout restart/status, fetching AWS
|
||||
secrets by template-resolved ID, reading all fields of a Kubernetes
|
||||
secret, ExternalSecret annotation, AWS auth check).
|
||||
- [x] `cmd/kctl-tui` "full" mode: Bubble Tea navigation for
|
||||
context -> team -> namespace, with `Esc` correctly popping back one
|
||||
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:
|
||||
- Redeploy: pick a deployment from a list, confirm, then
|
||||
`rollout restart` + `rollout status`.
|
||||
- Secrets: pick an AWS region, then pick the actual secret from a
|
||||
**list of all AWS Secrets Manager secrets** in that region (no more
|
||||
manual secret-ID typing), enter the matching Kubernetes secret
|
||||
name, and automatically diff **every field** of both secrets in one
|
||||
table (key / AWS value / Kubernetes value / match status). If any
|
||||
field differs, offer a single force-sync request for the **whole
|
||||
secret** (one ExternalSecret annotation), not per individual field.
|
||||
- Secrets: AWS auth check with interactive SSO login fallback,
|
||||
then automatically resolve the AWS secret ID (from
|
||||
`secret_name_template`) and Kubernetes secret name (from
|
||||
`k8s_secret_name_template`), fetch both, diff **every field**
|
||||
in one table (key / AWS value / Kubernetes value / match status).
|
||||
If any field differs, offer a single force-sync request for the
|
||||
**whole secret** (one ExternalSecret annotation).
|
||||
- `Esc` closes the whole tmux session (`tmux kill-session`).
|
||||
|
||||
## 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
|
||||
`wt.exe split-pane` instead of `tmux` for the status panes.
|
||||
- [ ] Document/implement that `Tab`-based context switching and
|
||||
`Esc`-triggered session close are **not** available in the native
|
||||
Windows fallback, per SPEC.md 3.6 — the panes must be closed
|
||||
- [ ] Document/implement that `Esc`-triggered session close is **not**
|
||||
available in the native Windows fallback — the panes must be closed
|
||||
manually there.
|
||||
|
||||
## 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.
|
||||
- [ ] Homebrew tap / `scoop` manifest as additional install options
|
||||
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
|
||||
|
||||
|
||||
@@ -125,6 +125,7 @@ aws_region: "eu-central-1"
|
||||
aws_account_id: "123456789012"
|
||||
|
||||
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"
|
||||
|
||||
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
|
||||
the chosen namespace and environment. Placeholders: `{namespace}`,
|
||||
`{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
|
||||
region, account ID, environment, and context. Placeholders: `{region}`,
|
||||
`{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
|
||||
work, bundling the most common workflows currently done via long
|
||||
`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
|
||||
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
|
||||
Go tool's screen stack one level up: namespace selection -> team
|
||||
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
|
||||
|
||||
@@ -64,10 +61,10 @@ Navigation:
|
||||
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
|
||||
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).
|
||||
|
||||
### 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
|
||||
**three panes**, started with a single command:
|
||||
@@ -93,10 +90,12 @@ Example startup command (generic placeholders):
|
||||
|
||||
```
|
||||
tmux new-session -d -s kctl \
|
||||
"kctl-tui panel --ctx=$CTX_A --ns=$NS --team=$TEAM" \; \
|
||||
split-window -v "k9s --context $CTX_A -n $NS" \; \
|
||||
split-window -v "k9s --context $CTX_B -n $NS" \; \
|
||||
select-layout main-horizontal \; \
|
||||
"kctl-tui panel --context=$CTX_A --ns=$NS --team=$TEAM" \; \
|
||||
set-option -t kctl remain-on-exit on \; \
|
||||
split-window -v -t kctl:0.0 "k9s --context $CTX_A -n $NS" \; \
|
||||
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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
|
||||
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`.
|
||||
2. Show the contained keys for selection.
|
||||
3. Load the matching Kubernetes secret field:
|
||||
`kubectl -n <ns> get secret <secret-name> -o jsonpath='{.data.<field>}'`,
|
||||
base64-decode it.
|
||||
4. Compare the values (identical / different).
|
||||
5. On mismatch, optionally request a force-sync:
|
||||
4. Fetch all fields of the Kubernetes secret and base64-decode them:
|
||||
`kubectl -n <ns> get secret <secret-name> -o json`.
|
||||
5. Compare every field at once in a table (key / AWS value / Kubernetes
|
||||
value / match status).
|
||||
6. On mismatch, optionally request a force-sync for the whole secret:
|
||||
`kubectl -n <ns> annotate externalsecret <name> force-sync=<unix-timestamp> --overwrite`.
|
||||
|
||||
All names (secret ID, secret name, field name, ExternalSecret name) are
|
||||
asked for interactively at runtime, never hardcoded in the tool.
|
||||
The ExternalSecret object name for the force-sync annotation is the only
|
||||
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**
|
||||
status panes below it, not just an internal state.
|
||||
The actual kubectl context name/ARN for each environment is computed from
|
||||
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
|
||||
with generic placeholders:
|
||||
|
||||
```yaml
|
||||
context_pairs:
|
||||
- name: "environment-pair-1"
|
||||
contexts: ["<context-a1>", "<context-a2>"]
|
||||
- name: "environment-pair-2"
|
||||
contexts: ["<context-b1>", "<context-b2>"]
|
||||
contexts:
|
||||
- "internal"
|
||||
- "external"
|
||||
default_context: "internal"
|
||||
|
||||
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>"
|
||||
```
|
||||
|
||||
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.
|
||||
2. Restart both k9s panes via
|
||||
`tmux respawn-pane -k -t kctl:0.1 "k9s --context <newA> -n <ns>"` and
|
||||
`... kctl:0.2 ...` (namespace stays the same).
|
||||
3. If the current context is in no configured list: show a hint in the
|
||||
control pane instead of an error.
|
||||
4. No action outside this configuration — no error, only a hint.
|
||||
|
||||
**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.
|
||||
**Platform limitation on Windows without WSL:** `kill-session` is
|
||||
tmux-specific. Windows Terminal (`wt.exe`) offers no equivalent scripting
|
||||
to 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`); automatic session termination is unavailable there.
|
||||
This limitation is the main reason the primary target system is set to
|
||||
Linux/WSL.
|
||||
|
||||
## 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).
|
||||
- No RBAC/permission checks before executing sensitive actions — the tool
|
||||
assumes existing kubectl permissions.
|
||||
- Configuration file format (`config.yaml`) is a proposal, not finally
|
||||
agreed; concrete label keys, context names, and namespace names are
|
||||
- Configuration file format (`config.yaml`) is defined and implemented;
|
||||
concrete label keys, context names, and namespace names are
|
||||
project-specific and belong exclusively in the user's local, unversioned
|
||||
configuration, not in this document or the source code.
|
||||
- Native Windows (without WSL) remains a secondary platform with manual
|
||||
|
||||
Reference in New Issue
Block a user