SSH and terminal background

Every once in a while there is some horror story happening about a dev-ops person executing commands on the wrong servers. These days I have control of a lot of servers which need attention and I often freak out when I'm inside mysql / mongo cli and perform operations, wondering if I'm on the machine that I think I am.

Recently I managed to spend some time on figuring out how can I improve my situation and here is what I came up with.

iTerm with changing background

What is actually happening here is ssh executes a command on the local machine after successfully connecting to the server, which command changes the background of the terminal ( in my case iTerm ) and after the connection is closed ( the trickiest part ), another command is run which reverts the background to the default one.

Let's go step by step into the details :

  1. Change background ( iTerm )
  2. Change background ( Terminal )
  3. Configuring SSH's LocalCommand feature
  4. Final words and other methods

Change background ( iTerm )

This was quite trivial.

Credits goes to this gist by @mihigh.

Create two additional copies of your default profile and name them e.g. Staging , Production then change the background color of each of them to what matches your default profile theme. The way to change the profile of the current iTerm window for me was using an escape code.

It looks like this :

$ echo -e "\033]50;SetProfile=Production\a"

To change it back your default profile you need to do the same, but just change the name :

$ echo -e "\033]50;SetProfile=NameOfYourDefaultProfile\a"

Change background ( Terminal )

For the macOS Terminal App this is done via AppleScript.

on run tbg
    tell application "Terminal"
        tell selected tab of front window
            if (item 1 of tbg = "default") then
                set background color to {9766, 12850, 14392}
            else if (item 1 of tbg = "staging") then
                set background color to {10280, 10280, 6425}
            else if (item 1 of tbg = "production") then
                set background color to {10794, 6682, 5911}
            end if
        end tell
    end tell
end run

Just copy the file above and paste it into Script Editor, then save it as ~/tbg.scpt. Executing this script with argument default, production or staging will change the Terminal's background color.

$ osascript ~/tbg.scpt production

Since we won't use different profiles, but only background color change, you need to specify the background colors for your environments.

About that color format

The format is {R, G, B}, but the colors are interpreted in 16bit values.

Credits goes to Stack Overflow's user @bingles.

To convert from 8bit to 16bit ( LOL ) I used this bash script.

#!/bin/bash

r=${1:-255}
g=${2:-255}
b=${3:-255}

r=$(($r * 256 + $r))
g=$(($g * 256 + $g))
b=$(($b * 256 + $b))

echo ${r} ${g} ${b}

So in order to get 16bit of pure green ( 0, 255, 0 ) you execute :

$ ./8to16rgb.sh 0 255 0
0 65535 0

You can use those colors for changing Terminal's background

Configuring SSH's LocalCommand feature

SSH support's LocalCommand feature, which executes a command when you connect to your server successfully. The problem comes when you need to also execute another command when you have disconnected.

After reading a bit I managed to achieve the effect via event handler that waits for the parent process to finish and executes a command when that happens.

Credits goes to Server Fault's user @wfaulk.

Based on the idea and the code of @wfaulk I managed to create a small C program phook, which basically executes a command when it starts and executes another one when the parent process has been terminated.

I also included a listener for catching SIGINT system call in order to make it work when SSH is terminated with CTRL+C.

You can follow the instructions to install :

  1. Download the latest release of phook.
  2. Extract and run make install.

This should create /usr/local/bin/phook executable that you will need for SSH's LocalCommand.

With this program, configuring SSH is trivial. This is how my ~/.ssh/config looks like :

#
# Hooks for certain hosts
#

Host do-styberry-staging do-mongo-01 do-mongo-02 do-mongo-arbiter
    PermitLocalCommand yes
    LocalCommand phook -e 'echo "\033]50;SetProfile=OceanicStaging\a"' -a 'echo "\033]50;SetProfile=Oceanic\a"'

Host do-styberry-production do-q-mongo-01 do-q-mongo-02 do-q-mongo-arbiter
    PermitLocalCommand yes
    LocalCommand phook -e 'echo "\033]50;SetProfile=OceanicProduction\a"' -a 'echo "\033]50;SetProfile=Oceanic\a"'

That's pretty much all of it.

Final words and other methods

Reading logs looks much better now.

iTerm with journalctl

There are of course other methods to achieve similar effect.

I don't want to go into details, but here are some issues that I had attempting to do the same with :

  1. Wrap ssh around a bash script. Adding/removing hosts will be difficult. Also it broke my autocomplete.
  2. iTerm's automatic profile switching. Never managed to make it work properly. It actually needs you to install additional shell integrations and configuring hosts will be hard as well.