Ich hatte schon hin und wieder das Problem, dass ich einige SSH-Verbindungen auf andere Systeme offen hatte, und ausversehen auf dem falschen System einen Befehl ausgelöst habe. Meist geht so etwas glimpflich ab, aber ich habe auf diesem Weg auch schon einiges an Schaden angerichtet. Was kann man also tun, um dieses Problem zu reduzieren?
Mein Ziel habe ich in einem vorherigen Blog Post schon mal beschrieben: visuell erkennen, auf welchem System ich mich befinde.
Das Ziel: visuell erkennen, auf welchem System ich mich befinde
In Teil 1 des Blog Posts habe ich das Grundprinzip beschrieben: Die Verwendung von Shell Escape Codes zum Einblenden von Overlays bei iTerm2.
Die skizzierte Lösung hatte jedoch mehrere gravierende Probleme, wenn andere Tools wie Git oder Ansible über SSH funktionieren mussten. Dabei musste jeder Git-Server, wie auch jeder Server der mit Ansible deployt werden sollte, explizit vom dargestellten Script ausgenommen werden, da das Script (durch das Injecten von Escapesequenzen) Fehler bei Git oder Ansible produziert hatte.
ssh config: Match
Nun bin ich vor einigen Tagen auf einen Blog Post gestoßen, wo die SSH-Config-Direktive Match erläutert wurde: Diese Einstellung ermöglicht es, eine Art "Konfigurations-Overlay" über die normale SSH-Konfiguration zu legen. Um zu entscheiden, ob der "Overlay" aktiviert oder deaktiviert ist, kann man ein beliebiges Script hinterlegen.
Nun hatte ich die Idee, in der Prozesshierarchie - ausgehend vom SSH-Prozess selbst - weiter "hoch" zu schauen (die Eltern des SSH-Prozesses, etc); um herauszufinden, ob der SSH-Befehl gerade im Kontext einer interaktiven Shell (in meinem Fall ZSH) oder in einem anderen Kontext wie Ansible oder Git ausgeführt wurde. Dies macht die Zeile:
Damit das ganze funktioniert, muss noch diese Helfer-Anwendung installiert werden:
brew install sandstorm/tap/phook
Folgende Zeilen zeigen den aktuellen Host als Badge in iTerm2, und machen auch Ansible, Git, etc. nicht kaputt:
# If the SSH process is started from an interactive ZSH session, we display the badge of the target host.
#
# NOTE:
# - the PARENT of the exec'd process is the SSH process itself
# - the GRANDPARENT of the exec'd process is the calling process of the SSH process (e.g. ZSH, Ansible, Git)
Match exec "ps p $(ps p $$ -o ppid | grep -v PPID) -o ppid | grep -v PPID | xargs -r ps ww | grep zsh"
# Set the color to magenta, and the badge to the target host.
PermitLocalCommand yes
LocalCommand phook -e 'echo "\033]6;1;bg;red;brightness;255\a\033]6;1;bg;green;brightness;0\a\033]6;1;bg;blue;brightness;255\a";printf "\e]1337;SetBadgeFormat=%%s\a" $(echo "%n" | base64)' -a 'echo "\033]6;1;bg;*;default\a";printf "\e]1337;SetBadgeFormat=\a"'
Viel Spaß damit!
PS: Entwicklung des Grandparent-Finder-Scripts
# output current process ID
> echo $$
56913
# output PARENT process ID as a table
> ps p $$ -o ppid
PPID
56912
# remove table heading -> Parent Process ID
> ps p $$ -o ppid | grep -v PPID
56912
# GRANDparent Process ID (the above twice):
> ps p $(ps p $$ -o ppid | grep -v PPID) -o ppid | grep -v PPID
7359
# load infos about the given process ID
> echo 56912 | xargs -r ps ww
PID TT STAT TIME COMMAND
56912 s009 Ss 0:00.01 /usr/bin/login -fpl sebastian /Applications/iTerm.app/Contents/MacOS/ShellLauncher --launch_shell
# SIDENOTE: debugging what the resolved process is
> ps p $(ps p $$ -o ppid | grep -v PPID) -o ppid | grep -v PPID | xargs -r ps ww > /tmp/foo
# then look into /tmp/foo
#########################################################################################
# THE FINAL LINE which checks whether the grandparent process is ZSH (not ansible, not Git).
ps p $(ps p $$ -o ppid | grep -v PPID) -o ppid | grep -v PPID | xargs -r ps ww | grep zsh
#########################################################################################