Files
kportal/.kportal.yaml
4d263319ab feat: add --context to forward only selected contexts (#85)
* feat: add --context to forward only selected contexts

kportal forwards every context in the config file. When the file describes
several clusters that host the same services, that means holding connections
open to clusters nobody is using, and - because all contexts are active at once
- every localPort has to be globally unique. The same service therefore lands on
a different local port per cluster, so switching clusters means reconfiguring
the app being developed.

--context limits a run to the contexts you name. It is repeatable and accepts
comma-separated values, and composes with -headless:

    kportal --context development-team-a
    kportal --context team-a,team-b -headless
    kportal --context team-a --context team-b

An unknown name is an error listing the contexts the file defines, so a typo
fails loudly instead of silently forwarding nothing.

Local-port and mDNS-hostname conflicts are now scoped to forwards that could run
at the same time: same context, or both contexts in the active selection. With
no selection every context is active, so existing behaviour is unchanged.
Contexts that are never selected together may reuse the same localPort, which is
what lets a service keep one fixed local port in every cluster.

Validation still covers the whole file, so a problem in a context outside the
selection is still reported and --check does not get weaker. Loading, validating
and filtering are shared by every path that re-reads the config (startup, file
watcher, SIGHUP in both headless and verbose modes), so no path can forget the
selection.

Also fixes a latent identity bug this makes reachable: Forward.ID() is only
"alias:localPort" when an alias is set, which was unique across contexts only
because duplicate local ports were globally rejected. With ports now shareable,
deleting or editing a forward from the TUI could have matched same-alias
forwards in other contexts and silently removed them. Delete and edit are now
scoped to the context the row came from.

* fix(config): keep the running config when no selected context remains

A reload dropped selected contexts that no longer exist in the file.
When all of them vanished, the reload returned an empty config and the
manager stopped every forward after a single rename.

LoadForRuntime now returns an error in that case. The watcher keeps the
previous config, as it does for any other invalid reload.

Refs #80

* fix(ui): apply new table columns after a successful SIGHUP reload

The context selection moved the SIGHUP reload into reloadFromSignal,
which had no way to update the verbose table columns. The function now
takes a callback that runs only after the manager reloads without error.
The verbose table passes SetColumns.

Refs #80

* style: gofmt run_test.go

---------

Co-authored-by: André Cruz <[email protected]>
2026-10-02 02:33:29 +01:00

116 lines
4.4 KiB
YAML

# Example kportal configuration
# Copy this file to your project and customize as needed
# Optional: Health check configuration
# These settings control how kportal monitors connection health and detects stale connections
healthCheck:
interval: "3s" # How often to check connection health (default: 3s)
timeout: "2s" # Timeout for health check operations (default: 2s)
method: "data-transfer" # Health check method: "tcp-dial" or "data-transfer" (default: data-transfer)
# - tcp-dial: Simple TCP connection test (fast, less reliable)
# - data-transfer: Attempts to read data (slower, more reliable)
maxConnectionAge: "25m" # Maximum connection age before proactive reconnect (default: 25m)
# Helps avoid Kubernetes API server timeouts (typically 30m)
maxIdleTime: "10m" # Maximum idle time before marking as stale (default: 10m)
# Connections with no data transfer are marked stale
# Optional: Reliability configuration
# These settings improve connection stability for long-running transfers
reliability:
tcpKeepalive: "30s" # TCP keepalive interval for OS-level connection monitoring (default: 30s)
dialTimeout: "30s" # Connection dial timeout (default: 30s)
retryOnStale: true # Automatically reconnect when stale connections detected (default: true)
watchdogPeriod: "30s" # Goroutine watchdog check interval to detect hung workers (default: 30s)
# Every context below is forwarded by default. Pass --context to run only some
# of them, for example:
#
# kportal --context staging
# kportal --context production,staging # repeatable, or comma-separated
#
# Local-port conflicts are only reported between forwards that could run at the
# same time, so contexts you never select together may reuse the same
# localPort - handy when the same service exists in several clusters and you
# want it on a fixed local port in each:
#
# contexts:
# - name: development-team-a
# namespaces:
# - name: rate-service
# forwards:
# - resource: pod/rpc-server
# protocol: tcp
# port: 50051
# localPort: 3004 # same port as team-b below
# - name: development-team-b
# namespaces:
# - name: rate-service
# forwards:
# - resource: pod/rpc-server
# protocol: tcp
# port: 50051
# localPort: 3004 # only valid when one of them is selected
# Optional: TUI table configuration
# Controls which columns are visible in the forwards table, in what order,
# and how wide each one renders. Omit this section (or leave it empty) to
# use the built-in default columns/order/widths.
# Valid column names: context, namespace, alias, type, resource, remote, local, status
# tui:
# columns:
# - name: alias
# width: 30 # optional; falls back to the built-in default width
# - name: resource
# - name: local
# - name: status
contexts:
# Production context
- name: production
namespaces:
- name: default
forwards:
# Forward to API service
- resource: service/api
protocol: tcp
port: 8080
localPort: 8080
alias: prod-api
httpLog: true # Enable HTTP traffic logging for this forward (press 'l' in the TUI)
# Forward to PostgreSQL database
- resource: service/postgres
protocol: tcp
port: 5432
localPort: 5432
alias: prod-db
- name: monitoring
forwards:
# Forward to Prometheus using label selector
- resource: pod
selector: app=prometheus
protocol: tcp
port: 9090
localPort: 9090
alias: prometheus
# Staging context
- name: staging
namespaces:
- name: default
forwards:
# Forward to staging app (prefix matching handles pod restarts)
- resource: pod/myapp
protocol: tcp
port: 8080
localPort: 8081
alias: staging-http
# Forward multiple ports from same pod
- resource: pod/myapp
protocol: tcp
port: 9090
localPort: 9091
alias: staging-metrics