Skip to content

context port forward

Kadyapam edited this page May 28, 2026 · 1 revision

noetl context port-forward

Start, stop, or check a kubectl port-forward managed by noetl for the named context.

noetl context port-forward <name>             # foreground, exits on Ctrl-C
noetl context port-forward <name> --detach    # background daemon
noetl context port-forward <name> --stop      # kill the daemon
noetl context port-forward <name> --status    # PID + liveness

Available since noetl v2.15.0 (PR #14). The port-conflict probe and clearer error messages were added in v2.17.0 (PR #17).

Why this exists

The standard kubectl --context=… -n … port-forward svc/noetl LOCAL:REMOTE invocation works, but operators have to remember the four arguments, run it in a separate terminal, and remember to kill it later. The managed wrapper:

  • Reads kube_context, kube_namespace, kube_service, kube_remote_port, and the loopback port from server_url off the context — one place to configure, then --detach does the rest.
  • Writes the PID to ~/.noetl/port-forwards/<context>.pid so --stop and --status can find it.
  • Probes the local port before spawning so a stray kubectl port-forward from another shell fails fast with a diagnostic, instead of producing an orphan PID file.
  • Sends SIGTERM, waits a short grace, then SIGKILL on --stop.

Prerequisites

The context must have these fields set:

Field Set by Required?
server_url context add / context init / context update required — must be a loopback URL like http://127.0.0.1:18082
kube_context context add --kube-context=… or context update --kube-context=… required
kube_namespace same required
kube_service same optional, defaults to noetl
kube_remote_port same optional, defaults to 8082

The local port is parsed from the context's server_url — that's the port your other noetl commands already call. If the URL isn't loopback (localhost, 127.0.0.1, ::1), the CLI prints a diagnostic and exits.

Subcommands

Foreground (default)

noetl context port-forward gke-pf

Prints the equivalent kubectl invocation, blocks until you press Ctrl-C, and exits with kubectl's exit code. Useful for debugging — all stdout/stderr from kubectl is visible.

--detach

noetl context port-forward gke-pf --detach

Spawns kubectl as a background daemon, writes the PID, waits ~250 ms to catch fast failures, and returns. Output looks like:

Detached kubectl port-forward for context 'gke-pf' (pid 18808).
  Local:  http://127.0.0.1:18082
  Remote: noetl/noetl port 8082
  PID:    /Users/you/.noetl/port-forwards/gke-pf.pid
  Stop:   noetl context port-forward gke-pf --stop

If a detached forward is already running for the same context, the command refuses and points to --stop.

--stop

noetl context port-forward gke-pf --stop

Reads the PID file, sends SIGTERM, waits 500 ms, sends SIGKILL if the process is still alive, then removes the PID file. Idempotent — safe to run when no daemon is registered.

--status

noetl context port-forward gke-pf --status

Reports one of:

  • Running with PID.
  • Stale PID file (process dead). Tells you to run --stop to clean up.
  • No daemon registered.

Port-conflict probe

Before spawning kubectl, the CLI binds a TcpListener to 127.0.0.1:<local_port>. If that fails, the local port is held by something else and the CLI exits with a diagnostic:

Local port 18082 is already in use (bind probe failed: Address already in use).
  Identify the process:
    lsof -i :18082                 # macOS / Linux
    fuser 18082/tcp                # Linux

  If it's a stray ``kubectl port-forward`` from another shell:
    pkill -f 'port-forward svc/noetl'

  If it's another noetl-managed daemon: ``noetl context port-forward <other> --stop``.

There's a small race window between the probe and kubectl claiming the port (it's a different process), but the probe catches the common case where a stray kubectl from a previous shell is still holding the port — the case that used to produce orphan PID files with no hint of what went wrong.

File layout

~/.noetl/port-forwards/<context>.pid

The directory is created lazily on first --detach. One PID file per context name — the CLI does not attempt to manage multiple concurrent forwards for the same context.

Platform notes

  • The --stop grace-then-kill path uses POSIX signals via nix::sys::signal::kill. On non-Unix builds (Windows), --stop is a no-op past PID-file cleanup, and pid_is_running reports conservatively.
  • The CLI does not parse kubectl output for "Forwarding from" confirmation. If you need that, run foreground first.

Examples — full lifecycle

# One-time setup: write kube fields onto the context
noetl context update gke-prod \
  --kube-context=gke_acme_us-central1_prod \
  --kube-namespace=noetl

# Make sure server_url is a loopback URL (kubectl always binds 127.0.0.1)
noetl context update gke-prod --server-url=http://127.0.0.1:18082

# Start it in the background
noetl context port-forward gke-prod --detach

# Use the context for one command
noetl --context gke-prod catalog list Playbook

# Or switch to it for the duration of a shell
noetl context use gke-prod
noetl catalog list Playbook

# Confirm the tunnel is alive
noetl context port-forward gke-prod --status

# Tear it down
noetl context port-forward gke-prod --stop

See also

  • noetl context update — sets the kube_* fields this command consumes, and the loopback server_url.
  • Connecting to a cluster — the port-forward path in context with the other connection options.
  • Global flagsnoetl --context <name> to use a context for a single command without switching the current one.

Clone this wiki locally