Technical Musings: 2012

Monday, February 6, 2012

SSH LocalCommand / OSX Terminal Colors

UPDATE: If you're like me, you work in many different computing environments: home, test, QA, and production.  And it's REALLY important not to get them mixed up.  I've always used a color scheme in my ssh/console windows to help me differentiate each.   I've manually set the color of each console before I log in, and try not to reuse a console for different environments.  It's kind of a pain, and if I'm brain dead enough to not notice what host I'm logged into, chances are high that I'm not going to set the colors correctly either.  So I created an OSX (I'm on 10.7) AppleScript to automatically change the Terminal colors for each of my windows/tabs to match the environment that console is logged into.

To trigger the AppleScript, I added it to an until-now-unknown to me ssh client setting: LocalCommand.  It will run a command locally each time you make an ssh connection.

To setup the trigger, you must add the following lines into ~/.ssh/config:
(Note: it's important to add the & at the end of LocalCommand to put the command in background so it can wait for Terminal to connect)
 Host *
   PermitLocalCommand yes
   LocalCommand /Users/MYNAME/applescript/term_tab_style.scpt &

UPDATE: And this in /etc/ssh_config:
  PermitLocalCommand yes  

The AppleScript goes through all open Terminal windows/tabs and checks the title.  This is normally set to the user@hostname, and I have a naming convention 'purpose'-'env'-'location'-'number'.  Applescript has very limited parsing capabilites; I found the functions I used here to split the hostname up and get the environment name.  You can then set the Terminal window/tab to whatever Profile you desire.

The code for term_tab_style.scpt.  Copy this code into wherever you specified the LocalCommand in ~/.ssh/config and don't forget to run 'chmod u+x ~/term_tab_style.scpt'.

 on run argv

   delay 1
   tell application "Terminal"
     repeat with w from 1 to count windows
       repeat with t from 1 to count tabs of window w
         set title to custom title of tab t of window w  
           set myArray to my theSplit(title, "@")
           set userName to my getArrayValue(myArray, 1)
           set restName to my getArrayValue(myArray, 2)
           set myArray to my theSplit(restName, "-")
           set envName to my getArrayValue(myArray, 2)
           if envName is "pro" then
             #display dialog ("" & envName)
                set current settings of tab t of window w to (first settings set whose name is "Basic Blue")
           else if envName is "qa" then
                set current settings of tab t of window w to (first settings set whose name is "Basic")
           end if
         end try
       end repeat
     end repeat
   end tell
 end run
 on theSplit(theString, theDelimiter) 
   -- save delimiters to restore old settings
   set oldDelimiters to AppleScript's text item delimiters
   -- set delimiters to delimiter to be used
   set AppleScript's text item delimiters to theDelimiter
   -- create the array
   set theArray to every text item of theString  
   -- restore the old setting  
   set AppleScript's text item delimiters to oldDelimiters  
   -- return the result  
   return theArray 
 end theSplit
 on getArrayValue(array, location)  
   -- very important -- The list index starts at 1 not 0  
   return item location in array  
 end getArrayValue

Thursday, January 12, 2012

Python JSON one-liner

I've seen the python one-liner to parse and pretty-print json:

cat test.json | python -mjson.tool

But I still have to grep/awk to get the value.  Here's a python one-liner to get a json value:

curl -s -u user:password "http://test.json.output" | python -c "import json,sys;input=json.load(sys.stdin);print (input.get('messages'))"

A reasonably short, pure python way to do this is with the requests library, but that's not built into python, and I find one-liners are only useful if they work across a lot of systems as-is:

import json,requests
r = requests.get("http://test.json.output/api/", auth=('user','pass'))
o = json.loads(r.content)
print (o.get('messages'))