Friday, December 21, 2012

Python: Encapsulating Exceptions with Context Managers

Try/except can often interrupt the flow of logic making code harder to read. Take for example the following piece of code:

import sys

class Car(object):
   def create(self, color, stereo):
      try:
         vin = self._factory.make_car(color)
      except FactoryColorError, err:
         stacktrace = sys.exc_info()[2]
         raise ValidationError(err.message), None, stacktrace

      try:
         self._customizer.update_car(vin, stereo)
      except CustomizerError, err:
         self._factory.remove_car(vin)
         stacktrace = sys.exc_info()[2]
         raise ValidationError(err.message), None, stacktrace

      return vin

   def update(self, vin, color, stereo):
      try:
         self._factory.update_car_color(vin, color)
      except FactoryColorError, err:
         stacktrace = sys.exc_info()[2]
         raise ValidationError(err.message), None, stacktrace
 
      try:
         self._customizer.update_car(vin, stereo)
      except CustomizerError, err:
         stacktrace = sys.exc_info()[2]
         raise ValidationError(err.message), None, stacktrace

      return

A somewhat typical piece of code where the create and update are composed of multiple calls on the backend.  So the logic is as follows:

  • exception logic that changes third party exceptions into ValidationError
  • rollback exception logic in create that removes the car if the stereo option is invalid
The code is cluttered and the exception handling obscures the flow of both create and update.  The more exception logic we have the less readable the code is.  We also have some duplication of code. Enter context managers.

from contextlib import contextmanager
import sys

class Car(object):
   @contextmanager
   def _factory_error_handler(self):
      try:
         yield
      except FactoryColorError, err:
         stacktrace = sys.exc_info()[2]
         raise ValidationError(err.message, None, stacktrace

   @contextmanager
   def _create_customizer_error_handler(self, vin):
      try:
         yield
      except CustomizerError, err:
         self._factory.remove_car(vin)
         stacktrace = sys.exc_info()[2]
         raise ValidationError(err.message), None, stacktrace

   @contextmanager
   def _update_customizer_error_handler(self, vin):
      try:
         yield
      except CustomizerError, err:
         stacktrace = sys.exc_info()[2]
         raise ValidationError(err.message), None, stacktrace

   def create(self, color, stereo):
      with self._factory_error_handler():
         vin = self._factory.make_car(color)

      with self._create_customizer_error_handler(vin):
         self._customizer.update_car(vin, stereo)

      return vin

   def update(self, vin, color, stereo):
      with self._factory_error_handler():
         self._factory.update_car_color(vin, color)
 
      with self._update_customizer_error_handler(vin):
         self._customizer.update_car(vin, stereo)

      return


Refactoring the exception code to encapsulate the logic in it's own namespace in order to make the code more readable.  The core logic is no longer obscured by the exception handling, in fact the handlers make both the core and the exception logic easy to read and understand. We are also able to de-dupe some of the exception logic through reuse of the _factory_error_handler.  However, we can do better.

from contextlib import contextmanager
import sys

@contextmanager
def cleanup_error_handler(cleanup):
   try:
      yield
   except Exception:
      cleanup()
      raise

def make_error_handler(catch, throw):
   @contextmanager
   def handler():
      try:
         yield
      except catch, e:
         stacktrace = sys.exc_info()[2]
         raise throw(e.message), None, stacktrace
   return handler

factory_error_handler = make_error_handler(FactoryError, ValidationError)
customizer_error_handler = make_error_handler(CustomizerError, ValidationError)

class Car(object):
   def create(self, color, stereo):
      with factory_error_handler():
         vin = self._factory.make_car(color)

      cleanup = partial(self._factory.remove_car, vin)
      with cleanup_error_handler(cleanup), \
           customizer_error_handler():
         self._customizer.update_car(vin, stereo)

      return vin

   def update(self, vin, color, stereo):
      with factory_error_handler():
         self._factory.update_car_color(vin, color)
 
      with customizer_error_handler():
         self._customizer.update_car(vin, stereo)

      return


We retained the readability of using the handlers, but extracted them completely from the class.  The exception logic is now both encapsulated and decoupled from the specific class allowing reuse throughout the rest of the codebase.

§

Thursday, December 20, 2012

Python Metaprogramming: Dynamically Adding Methods to Classes

Dynamic addition of methods and attributes to classes and instances.

Dynamic Class Method Addition

Occasionally you may need dynamically add a function as a method to a class.  This is easily accomplished by assigning the function as an attribute of the class.


def fn(self):
  return id(self), self, type(self)

# Traditional Class Definition
class A_Class(object):
  def method_a(self):
    return id(self), self, type(self)

instance = A_Class()

# Modify the class and add fn as a method
setattr(A_Class, 'method_b', fn)

# Call the traditionally defined method
instance.method_a()
# Call the dynamically added method
instance.method_b()



Dynamic Instance Method Addition

When you add the method to a class all instances can access it.  If you only want a particular instance to have a method do this:

from types import MethodType

instance2 = A_Class()
setattr(instance, fn.__name__, MethodType(fn, instance, type(instance)))

# Calls the fn method attached to the instance
instance.fn()

# Throws an exception
instance2.fn()

§

Friday, November 30, 2012

Configing Emacs: TRAMP with Putty

I've already written how to configure TRAMP in Emacs, but it only works on Mac and Linux. Unfortunately there are some who continue to use Windows as a desktop platform.   While they may be second class netizens, they do not need to settle for second class remote editing.

Emacs is available for Windows.  For secure remote editing you need ssh.  Enter Putty, an excellent implementation of the SSH protocol for Windows.  Putty comes with plink.exe which is the command line executable.   Once you've installed Emacs and Putty on Windows you'll want to update the Path environment variable.

Right-click Computer → Properties → Advanced System Settings → Environment Variables



Once the Putty path has been appended, update your emacs config.  Set your default tramp method to be plink and the tramp auto save directory to your username's temp directory.

(require 'tramp)
(set-default 'tramp-auto-save-directory "C:\Users\<username>\AppData\Local\Temp")
(set-default 'tramp-default-method "plink")

This all you need to start remote editing with emacs using ssh. You can setup password-less logins to make it even easier.  And if you have to go through an intermediary ssh server you can use transparent multihop with Putty.

§

Thursday, November 29, 2012

Python Metaprogramming: Dynamic Class and Metaclass Creation

Python has great metaprogramming capabilities.


Python classes are typically created using the class definition.  Classes are used in much the same other classes in other OOP languages are used.  They are used to define an instantiable object with associated methods and attributes.  Classes are also one of the primary namespacing mechanisms in Python. The terms class and type are often used interchangeably in Python. Occasionaly you may need to dynamically create a class.

There are use cases for dynamically creating a class or type.  Often it's a static definition doesn't meet your needs such as a type factory that needs to work on incoming types.  You may need to create a type dynamically for testing purposes, or because it's required by a framework or library you need to use.


NewClass = type('NewClass', (object, ), {})



Metaclasses are a another kind of class.  They are created in the same way as other classes except they derive from `type`.  You can programmaticlly create a a metaclass as follows:

def new(cls, name, bases, dct):
    print "metaclass new", name
    return type.__new__(cls, name, bases, dct)

def init(cls, name, bases, dct):
    print "metclass init", name
    super(type(cls), cls).__init__(name, bases, dct)

DynamicMetaClass = type('DynamicMetaClass',(type, ),dict(__init__=init, __new__=new))
X = DynamicMetaClass('X',(), dict(foo=lambda self:'foo'))
# returns metaclass new X
#         metclass init X

§

Friday, November 16, 2012

Python Class Decorator: Logging

Python class decorators provide powerful metaprogramming capabilities.  Instead of a function, a class decorator takes a class and returns a class.  The decorator can manipulate the incoming class, or simply create a new class and return it.

The following piece of code is an example of leveraging a decorator to do Aspect Oriented Programming.  The classic example in AOP is the addition of logging to methods and functions.  Rather than writing a function decorator, and adding the decorator to each function, you can choose to create a class decorator and logging by class.



import logging
log = logging.getLogger(name)


from functools import wraps
from types import MethodType

def class_logging(klass):
    """
    Class decorator that adds logging to all "public" class methods.
    """
    method_p = lambda m: not m.startswith('_') and \
                         isinstance(getattr(klass, m), MethodType)
    public_methods = filter(method_p, dir(klass))

    for method_name in public_methods:
        class_method = getattr(klass, method_name)

        def helper(mname, method):
            @wraps(method)
            def wrapper(*a, **kw):
                msg = '{0}({1}, {2})'.format(mname, a, kw)
                log.debug(msg)
                try:
                    response = method(*a, **kw)
                except Exception, e:
                    error_message = 'no additional information'
                    if hasattr(e, 'message'):
                        error_message = e.message
                    msg = '{0} raised {1}, {2}'.format(mname, type(e), error_message)
                    log.debug(msg)
                    raise
                else:
                    msg = '{0} returned {1}'.format(mname, response)
                    log.debug(msg)

                return response
            return wrapper
        
        fn = MethodType(helper(method_name, class_method), None, klass)
        setattr(klass, method_name, fn)
    return klass



§

Wednesday, November 14, 2012

Caveat Scriptor: Python Closures


You can read more/ about the generic gotchas associated with closures here.  The following are specific to closures as they are implemented in Python.

Closure variables are read only
In Python closures variables are readonly. This means the only way you can keep and modify state is by using an element in a mutable multi-element object like a dict or list. You cannot allocate a whole new list, dict, int, etc. So this won't work.

def mk_closure():
   storage=0
   def adder():
      storage+=1
      return storage
   return adder

It will work if a list is used instead.

def mk_closure():
   storage=[0]
   def adder():
      storage[0]+=1
      return storage[0]
   return adder

Looping structures (for, while) do not have there own lexical environments
Closures capture values from lexical environments. These are only created by executing a function which means this won't work:

functions=[]
storage=[0] * 5
for i in (1, 2, 3, 4, 5):
   def adder():
      storage[i-1] += i
      return storage[i-1]
   functions.append(adder)

A lexical environment is needs to be created in every iteration that can be closed over.

functions=[]
storage=[0]*5
for i in (1, 2, 3, 4, 5):
   def helper(x):
      def adder():
         storage[x-1] += x
         return storage[0]
      return adder
   functions.append(helper(i))

There is a shortcut in Python that eliminates the need to define the helper function.  This happens to work because the default value is set at definition time of the function which acts similarly to the function execution of helper.

functions=[]
storage=[0] * 5
for i in (1, 2, 3, 4, 5):
   def adder(x=i):
      storage[x-1] += x
      return storage[x-1]
   functions.append(adder)

§

Thursday, November 1, 2012

Ubuntu: Oracle Java Browser Plugin

Web8 has create ppa for Oracle Java which installs not only java, but the web browser plugin.  You can find the details here.  Here are the cliff notes version:
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java7-installer

Once you've install Java you need to disable the IceTea plugin in your browser.


Now you should be able to run java applets using Oracle's Java.

§

Tuesday, July 10, 2012

Configuring Remote X11: MacOS Lion

Configuring OSX to be able to display remote X11 (X.Org) applications on the local (MacOS Lion) display.

  • Reconfigure X11 on OSX to listen to TCP port 6000 if it doesn't already.
    • Move on to the next section if

      % defaults read org.x.X11 | grep nolisten
      "nolisten_tcp" = 0;
      
      
      Otherwise...
    • Enable the X11 server to listen on it's tcp port.

      % defaults write org.x.X11 nolisten_tcp 0
      
      
  • Make sure xauth is installed on the remote server.

    % which xauth
    
    
  • Start an ssh session with X11 forwarding enabled.

    % ssh -X remote-host
    
    
  • Open xcalc on the remote server and verify it comes up on your local display.
§

Monday, July 2, 2012

Configuring PuTTY: Transparent Multi-hop SSH

Many environments require that you login into a gateway server before being able to login into the remote server you actually want to get to.  In these cases you can configure PuTTY to proxy through the gateway server so that it looks as though you're going directly to the remote server.

The following examples assumes OpenSSH on the remote server and gateway and Windows7 on the Desktop.

  • Login into the gateway server and add your to to the authorized keys file 
    • ssh-add -L >> ~/.ssh/authorized_keys
  • Configure PuTTY Proxy Tab
    • Proxy type: Local
    • Proxy hostname: (gateway server here)
    • Exclude Hosts/IPs: (gateway server here)
    • Username: (gateway username here)
    • Local Proxy Command:  plink.exe %user@%proxyhost -nc %host:%port \n



  • Login into the remote server and add your key to the authorized keys file
    • ssh-add -L >> ~/.ssh/authorized_keys


§

Configuring PuTTY: Pageant

Setting up PuTTY's Pageant.
  • Follow Configuring PuTTY: Generating SSH Keys
  • Create a shortcut for Pageant
  • Move the shortcut into Startup
  • Append the Putty Private Key to the shortcut's Target property
  • Logout, Login and Verify Pageant starts up and prompts for the passphrase


§

Configuring PuTTY: Generating SSH Keys

There are two options to generating keys for PuTTY's puttygen.
  1. Import OpenSSH keys
  2. Generate PuTTY SSH keys
  • Follow Configuring PuTTY: Installing PuTTY Software
  • Start PuTTY's puttygen program
  • Set SSH-2 RSA keys to generate.
  • Select: "Conversions → Import" OR "Generate"
  • Save public key (..\Desktop\putty_key.pub)
  • Save private key (..\Desktop\putty_key.ppk)

Configuring PuTTY: Installing PuTTY Software

This article assumes you are installing on Windows7 (64bit).
  • Download PuTTY installer and execute
  • Append PuTTY's install path (C:\Program Files (x86)\PuTTY) to Windows7 Path Environment Variables

§

Saturday, June 9, 2012

Enterprise Applications: Checklist For Lowering the Cost of Operations

    Lower the TCO of management and administration by choosing applications that meet the criteria on the checklist.
    • API
      • all UI operations should reflected in API (including administrative controls)
      • the API should use the same credentials as the UI
      • all the business logic should live in the server
    • Extensibility
      • execute arbitrary actions based on events
    • Authentication
      • should integrate with LDAP/AD
      • should use user and group ACLS for object management and access
    • Revision Control
      • configs should be in files or have built in revision control capability
      • modifications/extensions should be in files or have built in revision control capability
    • High Availability
      • should support clustering
      • ideally clustering should support geographic distribution
      • should be able to recover from situation like multiple active nodes
    • Disaster Recovery
      • ideally an extension of HA with geographic distribution
    • %0 downtime (or as close as possible) for upgrades
    • %0 downtime (or as close as possible) for maintenance
    • Should be monitorable via standard network protocols (SNMP, HTTP, etc) BTW: email does NOT count
    • Should easily scale horizontally
    • Operation Cost
      • should have %0 manual administrative management for standard usage (no cleaning queues, removing files, marking messages)

      §

      Friday, April 27, 2012

      Configuring Emacs: TRAMP

      TRAMP is an Emacs library that allows you to remotely edit over a number of different protocols including ssh, sftp and scp.   With the later TRAMP libraries you have to list a set of names which define the servers you will be accessing.  The good news is you can use globs.

      (require 'tramp)
      (set-default 'tramp-default-proxies-alist (quote ((".*" "\\`root\\'" "/ssh:%h:"))))
      

      You can edit remotely over an ssh connection by executing find-file and passing it:

      /ssh:servername.com:path/to/remote/file
      

      This can be used in conjunction with Transparent Multihop Connections in your ssh config to provide easy transparent access to machines behind ssh gateways.

      §

      Wednesday, April 25, 2012

      An Abrupt Introduction: Scaling


      How to scale:
      • Identify your bottlenecks.
      • Identify the best solution for the problem.
      • Check to see if you can implement the the solution.
      • Identify alternate solution(s) and check ability to implement.

      Typical Scaling Options:
      • Vertical Scaling (bigger, faster server hardware)
      • Load balancing (active/active, active/passive)
      • Split tiers/components out onto more/other hardware
      • Offload work through caching/cdn

      Database Scaling Options:
      • Vertical Scaling (bigger, faster server hardware)
      • Replication (active or passive)
      • Clustering (if DBMS supports it)
      • Sharding
      §

      Friday, April 20, 2012

      Disambiguation: Dependency Injection vs. Avoidance of Globals

      Dependency injection is about decoupling code. When you avoid the use of globals by passing arguments you are decoupling code. You are removing the dependency the code has on the globals.

      You can generalize this decoupling to more than just the avoidance of globals. Take the following code:

      def foo(arg):
         return ClassBar(arg).attr
      
      foo(1)
      

      The function foo is dependent on or tightly coupled to ClassBar. The reason this is not good is you will be forced to update foo when:
      • the arguments to ClassBar constructor changes
      • you want to change the creation of a ClassBar object to something else
      • another piece of code wants to access attr from a different object
      If the code was rewritten:

      def foo(instanceBar):
         return instanceBar.attr
      
      foo(ClassBar(1))
      

      You've pushed the coupling up to the caller. This removed the dependency from the definition of foo. This frees you from having to update foo in the cases outlined above. The more of your code that is decoupled, the fewer code changes you'll need to make.

      §

      Configuring Emacs: making TRAMP use ssh-agent

      TRAMP provides Emacs with remote editing over ssh and sftp sessions.  We should be able to leverage ssh-agent to eliminate the need for passwords when using TRAMP.  Sometimes it doesn't automatically use the ssh-agent.  It may be because of a custom configuration, old version, or a platform that isn't full supported.  This is one technique that has worked for me.
      • In your emacs config set SSH_AUTH_SOCK.
      cat >> ~/.emacs <<EOF
      (setenv "SSH_AUTH_SOCK" (concat (getenv "HOME") "/.ssh-auth-sock"))
      EOF
      
      • Start the ssh-agent
      • Add and authenticate your key to the ssh-agent
      • Create a soft link to the ssh auth sock file
      cat >> ~/.profile <<EOF
      test -r ~/.agent && . ~/.agent
      
      ssh-add -l > /dev/null 2>&1
      test ${?} = 2 && ssh-agent -s > ~/.agent
      
      ln -sf $SSH_AUTH_SOCK ~/.ssh-auth-sock
      
      ssh-add -l > /dev/null 2>&1
      test $? = 1 && ssh-add
      EOF
      


      Now you should be able to test TRAMP.  Access a file on a server with authorized_keys set up and verify you don't get prompted for a password.

      §

      Wednesday, April 18, 2012

      Using Mercurial: Backing out changeset(s)

      Backing out changeset is the process of applying the inverse patch of that changeset.  By extension, you can backout a range of changesets by applying the inverse of patch of all the changesets.  This should be the default methodology of "reverting" a change or set of changes as it will maintain the consistency and completeness of the repository.

      • hg pull
      • hg up # Now your working directory and local repo are up to date
      • hg up -r revLast # Update to the latest revision you want to backout
      • hg revert -a -r revFirst-1 # Creates an inverse patch of revFirst to revLast
      • hg ci -m "Backed out revFirst - revLast" # Commit inverse patch
      • hg merge # Merge inverse patch to tip in my working directory
      • hg ci -m "Merged change back into the tip" # Commit inverse patch to tip in local repo
      • hg push # Push to master

      Reference http://ehsanakhgari.org/blog/2010-0Whether iWhether i9-09/backing-out-multiple-consecutive-changesets-mercurial

      §

      Mac Apps I Use

      Thursday, April 5, 2012

      Fix: SSHKeychain hanging in Lion

      Update: I have since discontinued use of SSHKeychainin favor of openssh-agent.

      Since upgrading my Mac to Lion I've been having problems with SSHKeychain.  After a sleep the SSHKeychain would be hung (aka. spinning beachball).  I would have to kill it and restart or I would get prompts for my passphrase when I used ssh.


      Turns out it is due to the security setting "On Keychain Events".  Since setting "On Keychain events" to  "No action", I havn't had SSHKeychain hang. 

      §

      Saturday, March 10, 2012

      Caveat Scriptor: Closures

      Closures are a flexible and powerful concept.  However, you have to keep in mind certain caveats when writing them.

      Understand how the closure will grow
      • You can easily create a memory leak with a closure because the only interface to the allocated memory is through the closure (typically). You should make sure your closure will not grow unbounded.
      Watch out for capturing references
      • This is more of standard gotcha, but it's even more important when dealing with closures. A closure will capture lexical variables including ones that contain references. This means whatever those references point to will continue stick around as long as the closure is around, unless they are explicitly weak refs.
      Don't close over variables you don't need to close over
      • It's wasteful, bad code and makes it more likely you'll introduce a memory leak.
      Make the functions that will become closures as simple as possible
      • The bigger, more complex the function that will become a closure, the more likely you are to have a bug which may lead to a memory leak.
      Don't create closures when they aren't needed
      • See: common sense
      §

      Wednesday, March 7, 2012

      An Abrupt Introduction: Closures

      A closure is created by a first class function creafing and returning a function which captures the lexical bindings of the free variables in its defining environment. Once it has captured the lexical bindings the function becomes a closure because it "closes over" those variables.

      Note this means closures only exist at run time.  However, it has become common to refer to the function that will become a closure as a closure.

      In practical terms a closure is a function that has data attached to it.  The data retains it's state across calls.  Here is a trivial example of a closure in python:

      def return_a_closure():
          total = [0]
          def adder(num=1):
              total[0] = total[0] + num
              return total[0]
          return adder
      
      closure = return_a_closure()
      closure() # returns 1
      closure() # returns 2
      closure() # returns 3
      

      When creating a closure you are not limited to binding only one function or only one piece of data.  You can even share data between multiple closures.

      def return_a_closure():
          total = [0]
          def adder(num=1):
              total[0] = total[0] + num
              return total[0]
      
          def deducter(num=1):
              total[0] = total[0] - num
              return total[0]
      
          return adder, deducter
      
      add, deduct = return_a_closure()
      add()    # returns 1
      add()    # returns 2
      deduct() # returns 1
      add()    # returns 2
      deduct() # returns 1
      

      §

      Friday, March 2, 2012

      Configuring SSH: Creating a Command Key

      OpenSSH provides the capability of binding a particular key to a command.  This is often the best way to execute a remote command without the risk of sending a password over the network.

      1. Change directory to your .ssh directory. (ie. cd ~/.ssh)
      2. Create the key pair. (ie. ssh-keygen -N "" -f hello_world)
      3. Add the key to the authorized_keys file along with the command. (ie. echo -n 'command="echo Hello World"' | cat - hello_world.pub >> authorized_keys)
      4. Try it out! (ie. SSH_AUTH_SOCK=/dev/null ssh -o BatchMode=true -qi hello_world localhost)
      §

      Friday, February 24, 2012

      Configuring Procmail: Adding Growl Notifications


      I use a Mac and like to have Growl notify me when procmail process a new message.
      • Open your procmail config for editing. (ie. vim ~/.procmailrc)
      • Added the following procmail rule at the end:
      :0c
      | /usr/bin/formail -X Subject  | /usr/local/bin/growlnotify -n mutt -a Mail.app >/dev/null 2>&1

       §

      Configuring GNU Screen: adding the caption




      The above gnu screen session has the caption enabled.  This provides the bottom line which contains a clock, the date and all the shells in your screen session.  To add the same caption to your screen session:

      Open your screen configuration file for editing. (ie. vim ~/.screenrc)
      Add the appropriate caption line.

      # Caption
      caption always "%?%F%{= kw}[%{= g}%c%{+b g}%D%{= kw}] %{= c}%Y%{+b c}%M%{= c}%d%{= w} -*-%?%F%? %L=%-Lw%45>%{+r} %n%f* %t %{-}%+Lw%-0<"

      §

      Saturday, February 18, 2012

      Configuring SSH: Always Forwarding Your Agent

      Configure you ssh agent to always forward and while your at it reuse existing connections to the same server.
      1. Open up your ssh config for editing. (ie. vim ~/.ssh/config)
      2. Add the following entries:
      ForwardAgent yes
      ControlPath /tmp/m-%l-%r@%h:%p
      ControlMaster yes
      ControlPersist yes

      §

      Thursday, February 16, 2012

      Configuring GNU Screen or tmux: Retain ssh-agent access when a session is reattached

      For those that use terminal multiplexers like screen or tmux a common problem is to "lose" your ssh-agent after ending an ssh session.

      The Problem

      1. ssh to a remote server and start the terminal multiplexer for the first time.

      The terminal multiplexer starts and all your shells capture the value of SSH_AUTH_SOCK at that time.  You can access your agent because the value of the environment variable in each shell is current.

      2. Detach from the terminal multiplexer and exit from your ssh session.

      The multiplexer still running on the remote server (along with all your shells).

      3. ssh to the remote server and reattach.

      So now you've reattached, but the environment variable SSH_AUTH_SOCK in each of your running shells is out of date. As a result you can't access your ssh-agent from your shells unless you update SSH_AUTH_SOCK.


      The Solution
      1. Open up the shell config file you store your aliases in. ie. vim ~/.bashrc
      2. Add an alias for screen or tmux that will transparently update the auth-sock location to the same location every time.
      alias screen='ln -sf $SSH_AUTH_SOCK $HOME/.ssh-auth-sock; env SSH_AUTH_SOCK=$HOME/.ssh-auth-sock screen'
      alias tmux='ln -sf $SSH_AUTH_SOCK $HOME/.ssh-auth-sock; env SSH_AUTH_SOCK=$HOME/.ssh-auth-sock tmux'

      §

      Configuring Emacs: Remote Editing

      TRAMP provides Emacs the ability to remotely edit file over a number of protocols including ssh.

      To get a directory listing of the home directory on the remote server:

      C-x C-d
      /ssh:<server>:

      You can add the following snippet to also support sudo'ing on the remote box.

      (require 'tramp)
      (set-default 'tramp-default-proxies-alist (quote ((".*" "\\`root\\'" "/ssh:%h:"))))
      Now you can remotely edit the /etc/motd file as root without needing to login as root.  Instead you will login as your user and then sudo to root.

      C-x C-f
      /sudo:<server>:/etc/motd

      §

      Wednesday, February 15, 2012

      Configuring SSH: Suppressing the Banner

      Tired of receiving cronmail because the ssh banner is sent to STDERR?  Tired of not being able to see real errors because the banner pollutes your log?

      For interactive sessions:
      • ssh -q
      This sets ssh's LogLevel to Quiet.  This means *only* Fatal logging events are logged.  This suppresses Error logging events that you may be interested in.

      • ssh -o LogLevel=error
      This sets ssh's LogLevel to Error.  This may not work in older ssh clients.  This allows you to see Error logging events that may be important.  You can also set this in your client config.

      Or modify your config:
      1. Open your ssh config for editing. ie. vim ~/.ssh/config
      2. Add a host entry for the servers you want to access through the ssh proxy.
      LogLevel error

      §

      Configuring SSH: Transparent Multihop Connections

      OpenSSH, the client that comes with most Unix/Linux systems, provides the capability for proxying through one ssh server to another. This is a completely client side configuration.

      1. Setup your Secure Passwordless Login for ssh.
      2. Open your ssh config for editing. ie. vim ~/.ssh/config
      3. Add a host entry for the servers you want to access through the ssh proxy.
      ForwardAgent yes
      Host gateway0?
              HostName %h.domain
      Host *.domain !gateway0?
              ProxyCommand ssh gateway01.domain exec nc %h %p

      Now you should be able to login to internal servers transparently from your workstation. This will hold true for interactive ssh, sftp, and scp.

      §

      Configuring SSH: Secure Passwordless Login

      • Create a passphrase protected ssh key.
      > ssh-keygen -b 2048 -t rsa
      • Add an ssh-agent to your session startup. (ie. SSHKeychain on Mac OS)
      • Whenever you start a session add your ssh key to your agent. (ie. ssh-add)
      • Make sure your agent follows you.
      ForwardAgent yes
      • ssh to a server and put your public key in the authorized_keys file. (ie. ssh-add -L > ~/.ssh/authorized_keys)
      • Fix the permissions, just in case. (ie. chmod 600 ~/.ssh/authorized_keys)
      • Logout, and try and log back in without a password.

      §