netssh multi: mehrere Server in einem Fenster (tmux/zellij) #37

Merged
Sebi merged 3 commits from feat/multi into main 2026-11-14 12:37:29 +00:00
Owner

Baut auf #36 (Testumgebung) auf; nach dessen Merge Basis auf main umstellen.

Bedienung

netssh multi web01 web02 db01            # Hosts, Kurznamen, instanz/host, statische Hosts
netssh multi tag:k8s-worker              # NetBox-Tag + statische Hosts mit Tag
netssh multi cluster:pve-fsn1            # Geräte eines NetBox-Clusters; --kind vm|all
netssh multi @k8s                        # Gruppe aus der Config
netssh multi --sync @k8s                 # Eingabe an alle Panes
netssh sync                              # Broadcast im aktuellen Fenster/Tab umschalten
  • tmux: in tmux neues Fenster, sonst neue Session (attach); gekachelt, Pane-Rahmen mit Host + [SYNC].
  • zellij: generiertes Gitter-Layout; in zellij neuer Tab, sonst neue Session.
  • TUI: Space markiert, Ctrl+A alle, Enter öffnet die markierten zusammen.
  • Config/Configurator: groups: (verschachtelbar, Zykluserkennung), multi.multiplexer, multi.panes_per_window.
  • NetBox-Cluster-Filter (Name → IDs je Instanz), Cluster im Cache für Completion und Offline-Fallback.
  • Panes: einmaliger Background-Refresh statt pro Pane; HOME/XDG_* werden durchgereicht, NETSSH_* bewusst nicht (Tokens wären in ps sichtbar).

Tests

  • Unit: Multiplexer mit Fake-Runner (tmux innen/außen, Session-Kollision, Aufteilung, Sync; zellij-Layout, Tabs), Cluster-Filter (httptest), Selektoren (Gruppen, Zyklus, Cache-Fallback), TUI-Markierung, Config, Save-Roundtrip, multi --dry-run.
  • testenv 15-multi.sh mit echtem tmux und zellij: Cluster gegen echtes NetBox, Panes + Labels, ein Befehl per Broadcast landet auf allen drei Nodes, netssh sync, neue Session außerhalb tmux, zellij-Layout + neuer Tab. Gesamt: 160/160 grün.

🤖 Generated with Claude Code

Baut auf #36 (Testumgebung) auf; nach dessen Merge Basis auf `main` umstellen. ## Bedienung ```sh netssh multi web01 web02 db01 # Hosts, Kurznamen, instanz/host, statische Hosts netssh multi tag:k8s-worker # NetBox-Tag + statische Hosts mit Tag netssh multi cluster:pve-fsn1 # Geräte eines NetBox-Clusters; --kind vm|all netssh multi @k8s # Gruppe aus der Config netssh multi --sync @k8s # Eingabe an alle Panes netssh sync # Broadcast im aktuellen Fenster/Tab umschalten ``` - **tmux**: in tmux neues Fenster, sonst neue Session (attach); gekachelt, Pane-Rahmen mit Host + `[SYNC]`. - **zellij**: generiertes Gitter-Layout; in zellij neuer Tab, sonst neue Session. - **TUI**: `Space` markiert, `Ctrl+A` alle, `Enter` öffnet die markierten zusammen. - **Config/Configurator**: `groups:` (verschachtelbar, Zykluserkennung), `multi.multiplexer`, `multi.panes_per_window`. - NetBox-Cluster-Filter (Name → IDs je Instanz), Cluster im Cache für Completion und Offline-Fallback. - Panes: einmaliger Background-Refresh statt pro Pane; `HOME`/`XDG_*` werden durchgereicht, `NETSSH_*` bewusst nicht (Tokens wären in `ps` sichtbar). ## Tests - Unit: Multiplexer mit Fake-Runner (tmux innen/außen, Session-Kollision, Aufteilung, Sync; zellij-Layout, Tabs), Cluster-Filter (httptest), Selektoren (Gruppen, Zyklus, Cache-Fallback), TUI-Markierung, Config, Save-Roundtrip, `multi --dry-run`. - testenv `15-multi.sh` mit echtem tmux und zellij: Cluster gegen echtes NetBox, Panes + Labels, **ein Befehl per Broadcast landet auf allen drei Nodes**, `netssh sync`, neue Session außerhalb tmux, zellij-Layout + neuer Tab. Gesamt: **160/160** grün. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sebi changed target branch from test/docker-env to main 2026-11-14 12:35:07 +00:00
Sebi added 5 commits 2026-11-14 12:35:08 +00:00
Found by the new Docker test environment against a real NetBox 4.7:

- The interface_name strategy filtered IP addresses with interface_name
  and vminterface_name, which NetBox ignores, so it returned the first
  address of the host instead of the named interface's. Use the real
  filters interface and vminterface; a missing interface (HTTP 400)
  falls through to the next strategy.
- sftp and scp took instance-qualified hosts (prod/web01:/path) for
  local paths, because a "/" comes before the ":". Such arguments are
  remote when the prefix is a configured NetBox instance.
- Shell aliases of instance-qualified hosts ran the shortcut rules on
  "instance/host", so anchored rewrite rules never matched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
testenv/ starts two real NetBox 4.7 instances (v2 and v1 token), SSH
targets on public, mgmt, and prod networks, a jump host, an IPv6-only
host, a static host, and a client with ssh, sftp, scp, tmux, zellij,
bash, zsh, and fish. A seed script fills NetBox through the REST API.

141 end-to-end checks cover cache and refresh filters, connecting,
all resolver strategies, multiple instances, shortcuts and rewrites,
SSH options and rules, static hosts, sftp/scp incl. IPv6 and jump
hosts, tunnels, local notes and NetBox comments, completion and shell
hooks, the TUI (driven through tmux), the configurator, and uninstall.

Local only: testenv/up.sh, test.sh, shell.sh, down.sh. Not part of
CI/CD.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
netssh multi opens one pane per host in a tmux window or zellij tab.
Hosts come from names, tag:TAG (NetBox and static hosts), cluster:NAME
(NetBox virtualization clusters; devices by default, --kind vm|all),
and groups from the config (@name, nested, with cycle detection).
Every pane runs netssh HOST, so lookup, rules, and jump hosts apply.

- tmux: a new window inside tmux, else a new session that is attached;
  tiled layout, pane borders with the host and a [SYNC] marker.
- zellij: a generated grid layout; a new tab inside zellij, else a new
  session.
- --sync broadcasts typing to all panes; netssh sync toggles it in the
  current tmux window or zellij tab.
- TUI: Space marks hosts, Ctrl+A marks all, Enter opens them together.
- Configurator: multiplexer, panes per window, groups.

NetBox SearchAll gains a cluster filter (name to cluster IDs per
instance), and cache entries keep the host's cluster for completion
and an offline fallback. Panes skip the 24-hour background refresh
(checked once by multi) and get HOME/XDG paths but no NETSSH_* values,
which would expose tokens in the process list.

testenv/tests/15-multi.sh checks real tmux and zellij sessions,
including a broadcast command arriving on all three cluster nodes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tests/16-render.sh runs tmux, zellij, and the TUI in xterm on Xvfb,
takes screenshots, and reads them back with tesseract: remote prompts
in all panes, borders and titles with the hosts, [SYNC] appearing and
disappearing, panes side by side, broadcast output in every pane and
input in one pane only without it, windows split by panes_per_window,
the status bar, and TUI marks. Screenshots stay in testenv/.artifacts.

OCR reads three preprocessing variants (plain, stretched for dim gray,
brightest channel for colored text) and normalizes characters that
DejaVu Sans Mono makes ambiguous (1/l, C/().

The screenshots showed tmux cutting the session name in the status bar
to "[netssh-pv"; netssh multi now widens status-left-length for its
own session.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In windows opened by netssh multi, prefix S toggles broadcast for all
panes and prefix e excludes the current pane (a pane-level
synchronize-panes off, shown as [SOLO] in the border) or includes it
again. netssh sync --pane does the same from a shell.

S and e are unbound in a default tmux (E would be "spread evenly").
netssh writes the bindings to a small tmux config and sources it, binds
a key only if the user's tmux.conf does not use it (netssh's own earlier
binding is refreshed), and the bindings act only in windows marked
@netssh. multi.sync_key and multi.solo_key change the keys or turn them
off (none); also in the configurator. zellij syncs whole tabs only, so
excluding a pane is tmux-only.

testenv: the render test presses the keys through the xterm client
(send-keys -K) and checks [SOLO], that broadcast skips the excluded
pane, that S toggles, and that other windows are unaffected. The client
gets GNU grep: BusyBox grep -oF counted only one match per line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sebi merged commit 6493e7c41e into main 2026-11-14 12:37:29 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Sebi/ssh-netbox-wrapper#37