Solve the long-standing USB adapter enumeration shift problem: 9 Prolific
USB-to-DB9 adapters on pfv-tsys4 have no unique serial numbers and get
assigned /dev/ttyUSB0-8 based on enumeration order, which changes on every
reboot and breaks the old /root/conmap + manual screen workflow.
Solution: udev rules pin each adapter by its ID_PATH (physical USB port
topology), which is stable across reboots regardless of enumeration order.
Each adapter gets a named symlink in /dev/consoles/<name>. ser2net opens
these stable symlinks and exposes them on TCP ports (2001-2007) bound to
the Tailscale interface only. conman connects to those TCP ports for
session logging and multi-user console sharing.
Architecture (layered, no port sharing):
USB adapter → udev symlink → ser2net (TCP) → conman (logging + mux)
Port assignments (all on Tailscale IP 100.70.77.93):
2001 = pfv-core-sw01 2002 = pfv-tor3-mgmt 2003 = pfv-tor3-stor
2004 = pfv-rrinfra-rtr 2005 = pfv-r2-tor-top 2006 = subodev-torsw
2007 = pfv-r2-sw
Scripts (console/):
- mapping.txt: source of truth (TCP port | name | ID_PATH | baud | comment)
- generate-config.sh: generates udev rules, ser2net.yaml, conman.conf
entries from mapping.txt. Idempotent (markers in conman.conf for clean
regeneration). Uses | delimiter (ID_PATH values contain colons).
- setup.sh: full deploy — generate configs, create symlinks (udev trigger
+ manual fallback for already-discovered devices), create conmand
systemd unit (Debian doesn't ship one), restart services
- discover.sh: read-only USB adapter and service state discovery
- validate-conman.sh: verify conman→ser2net→device data path and log capture
Issues fixed during development:
- /dev/console is a kernel char device (major 5, minor 1) — cannot create
a directory there. Changed symlink namespace to /dev/consoles/.
- conman 0.3.x has no 'include' directive — CONSOLE entries written
directly into /etc/conman.conf between idempotent markers.
- Debian conman package has no systemd unit — created
/etc/systemd/system/conmand.service with After=ser2net ordering.
- conman.conf had no LOGDIR — logs weren't being written to
/var/log/conman/. Fixed by adding server logdir directive.
Validation: 7 symlinks resolving, 7 TCP ports on Tailscale, conmand with
7 consoles registered, 7 log files actively capturing console output,
both services enabled for reboot survival.
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
103 lines
3.9 KiB
Bash
103 lines
3.9 KiB
Bash
#!/usr/bin/bash
|
|
#
|
|
# console/discover.sh — READ-ONLY discovery of console setup on pfv-tsys4
|
|
#
|
|
# Usage: PROX_HOST=pfv-tsys4 bash tests/remote.sh prox-file console/discover.sh
|
|
#
|
|
# This script is strictly read-only. No writes to the system.
|
|
#
|
|
set -uo pipefail
|
|
|
|
echo "============================================"
|
|
echo " Console Setup Discovery"
|
|
echo " Host: $(hostname)"
|
|
echo " Date: $(date)"
|
|
echo " READ-ONLY"
|
|
echo "============================================"
|
|
|
|
echo ""
|
|
echo "=== 1. USB devices ==="
|
|
lsusb 2>/dev/null || echo "(lsusb not available)"
|
|
|
|
echo ""
|
|
echo "=== 2. All ttyUSB* devices (with major/minor) ==="
|
|
ls -la /dev/ttyUSB* 2>/dev/null || echo "(no /dev/ttyUSB* devices)"
|
|
|
|
echo ""
|
|
echo "=== 3. USB-serial driver bindings ==="
|
|
echo "-- pl2303 --"
|
|
ls -la /sys/bus/usb-serial/drivers/pl2303/ 2>/dev/null | grep -v '^total\|^d\|module\|new_id\|uevent' || echo "(none)"
|
|
echo "-- cp210x --"
|
|
ls -la /sys/bus/usb-serial/drivers/cp210x/ 2>/dev/null | grep -v '^total\|^d\|module\|new_id\|uevent' || echo "(none)"
|
|
echo "-- ftdi_sio --"
|
|
ls -la /sys/bus/usb-serial/drivers/ftdi_sio/ 2>/dev/null | grep -v '^total\|^d\|module\|new_id\|uevent' || echo "(none)"
|
|
echo "-- ch341 --"
|
|
ls -la /sys/bus/usb-serial/drivers/ch341/ 2>/dev/null | grep -v '^total\|^d\|module\|new_id\|uevent' || echo "(none)"
|
|
|
|
echo ""
|
|
echo "=== 4. USB serial adapter details (vendor/model/serial per port) ==="
|
|
for tty in /dev/ttyUSB*; do
|
|
[ -e "$tty" ] || continue
|
|
echo "--- $tty ---"
|
|
udevadm info -q all -n "$tty" 2>/dev/null | grep -E 'ID_VENDOR_ID|ID_MODEL_ID|ID_SERIAL|ID_USB_DRIVER|ID_PATH=' | sed 's/^/ /'
|
|
done
|
|
|
|
echo ""
|
|
echo "=== 5. Existing /root/conmap ==="
|
|
if [ -f /root/conmap ]; then
|
|
cat /root/conmap
|
|
else
|
|
echo "(no /root/conmap)"
|
|
fi
|
|
ls -la /root/conmap* 2>/dev/null
|
|
|
|
echo ""
|
|
echo "=== 6. Screen sessions (running) ==="
|
|
screen -ls 2>&1 || echo "(screen not running or not installed)"
|
|
|
|
echo ""
|
|
echo "=== 7. Existing screen wrappers/scripts in /root ==="
|
|
ls -la /root/ 2>/dev/null | grep -iE 'screen|con|console|tty|usb' || echo "(no obvious console scripts in /root)"
|
|
|
|
echo ""
|
|
echo "=== 8. ser2net ==="
|
|
which ser2net 2>/dev/null || echo "(ser2net not installed)"
|
|
dpkg -l ser2net 2>/dev/null | tail -2 || echo "(ser2net not in dpkg)"
|
|
cat /etc/ser2net/ser2net.yaml 2>/dev/null || cat /etc/ser2net.conf 2>/dev/null || cat /etc/ser2net/ser2net.conf 2>/dev/null || echo "(no ser2net config)"
|
|
systemctl is-active ser2net 2>/dev/null || echo "(ser2net service not found)"
|
|
|
|
echo ""
|
|
echo "=== 9. conman ==="
|
|
which conman 2>/dev/null || echo "(conman not installed)"
|
|
which conmand 2>/dev/null || echo "(conmand not installed)"
|
|
dpkg -l conman 2>/dev/null | tail -2 || echo "(conman not in dpkg)"
|
|
echo "--- /etc/conman.conf (console lines only) ---"
|
|
grep -nE 'CONSOLE|SERVER|LOG|SERIAL|DEV|BAUD|^[^#].*name=' /etc/conman.conf 2>/dev/null | head -60 || echo "(no conman.conf or no console entries)"
|
|
echo "--- conmand service ---"
|
|
systemctl is-active conmand 2>/dev/null || echo "(conmand not running)"
|
|
systemctl is-enabled conmand 2>/dev/null || echo "(conmand not enabled)"
|
|
|
|
echo ""
|
|
echo "=== 10. Existing console logs ==="
|
|
ls -la /var/log/conman/ 2>/dev/null | head -20 || echo "(no /var/log/conman)"
|
|
ls -la /var/consoles/ 2>/dev/null | head -20 || echo "(no /var/consoles)"
|
|
|
|
echo ""
|
|
echo "=== 11. udev rules for ttyUSB ==="
|
|
grep -r ttyUSB /etc/udev/rules.d/ 2>/dev/null || echo "(no udev rules for ttyUSB)"
|
|
grep -r 'console' /etc/udev/rules.d/ 2>/dev/null | head -10 || true
|
|
|
|
echo ""
|
|
echo "=== 12. expect availability ==="
|
|
command -v expect && expect -v 2>&1 || echo "expect: NOT installed"
|
|
command -v socat && socat -V 2>&1 | head -1 || echo "socat: NOT installed"
|
|
|
|
echo ""
|
|
echo "=== 13. Ports in use (2001-2099, 7000-7999, 7820-7899) ==="
|
|
ss -tlnp 2>/dev/null | grep -E ':200[0-9]|:700[0-9]|:782[0-9]|:789[0-9]' || echo "(no relevant ports listening)"
|
|
|
|
echo ""
|
|
echo "============================================"
|
|
echo " Discovery complete (read-only)."
|
|
echo "============================================"
|