ruralmind

test driving TextPress

Archive for October 2008

Fabric: Avoiding deployment tedium

written by avanderlip, on Oct 20, 2008 2:28:00 AM.

I gave a lightning talk at the 2008 Plone Conference on Fabric. To clear up one point immediately, though I presented on Fabric, I did not write it. Fabric is a Python based remote deployment tool. It is similar to Capistrano for ROR but is more generic; it makes no assumptions about the target of the deployment. It is used to automate tasks on remote machines, like updating SVN, restarting Zope clients, etc. Certainly the same can be accomplished using shell scripts, but Fabric provides a common library for creating deployment scripts. It automates the tedium of deploying changes, I have fewer excuses to put off updates.

My colleague Rocky Burt provided me with the following instructions for setting up Fabric:

Note: The following requires Python 2.5 and was written assuming a UNIX-style workstation

Instructions

  1. Install virtualenv for Python 2.5 (if you haven't already)
    1. download http://pypi.python.org/packages/source/v/virtualenv/virtualenv-1.1.tar.gz
    2. extract virtualenv-1.1.tar.gz into your favourite directory
  1. Create new virtualenv to contain fabric
    1. cd $HOME # do this in the home dir
    2. python2.5 /some/path/to/virtualenv-1.1/virtualenv.py fabric
  1. Install fabric
    1. cd $HOME/fabric
    2. ./bin/easy_install Fabric
  1. Create directory to house the fabric deployments
    1. cd $HOME/fabric
    2. mkdir fabs

example command

One of the common tasks for development is to download the production Data.fs from a remote server to your local development environment.

def download_datafs():
    """Download the remote Data.fs file to the /tmp dir"""

    fname = '$(fab_timestamp)-www.jazkarta.com-Data.fs'
    fpath = '/tmp/' + fname
    fabcommon.run('cp '+basedir+'/var/filestorage/Data.fs ' + fpath)
    fabcommon.run('bzip2 ' + fpath)

    localfile = '/tmp/'+fname+'.bz2'
    download(fpath+'.bz2', localfile)

    newfile = localfile+'.$(fab_host)'
    targetdir = '/tmp/$(fab_timestamp)-$(fab_host)'
    targetfile = targetdir+'/Data.fs.bz2'
    local_per_host('mkdir -p '+targetdir)
    local_per_host('mv '+newfile+' '+targetfile)
    local_per_host('echo "Downloaded Data.fs to "' + targetfile)
  1. To run this command
    1. cd $HOME/fabric
    2. source ./bin/activate
    3. cd fabs/yoursite.org
    4. fab download_datafs
You can chain commands together so that a single update command runs a series of commands from your fab file
def update(_rebuild=_rebuild, _update_svn=_update_svn):
    """Run everything to update the site (does restart)
    """

    _rebuild(_update_svn)

    fabcommon.site_status(domainname,
                          'updated to latest code and rebuilt, '
                          'please note that you may have to wait a few '
                          'minutes for zope to finish restarting')


def _rebuild(stopcallback=None, _restart=_restart):

    def f(stopcallback=stopcallback):
        if stopcallback is not None:
            stopcallback()
        fabcommon.run('./bin/buildout -v', basedir)

    _restart(f)


def update_svn(_update_svn=_update_svn):
    """Update svn for buildout (no restart)"""

    _update_svn()
    fabcommon.site_status(domainname,
                          'updated to latest code but the services were '
                          'NOT restarted')


						

ideas

  • Creating fab files using paster's interactive prompt
  • A library of Fabric utilities for Zope development. For example the download_datafs function should probably use repozo to be safe, or scripts that run benchmarks when the server code is updated
  • A mechanism to allow for rolling back a Fabric command should the Zeo clients fail to restart
Check out Fabric