SaltyCrane Blog — Notes on JavaScript and web development

Notes on Python Fabric 0.9b1

Fabric is a Python package used for deploying websites or generally running commands on a remote server. I first used Fabric about a year ago and thought it was great. Since then, Fabric has procured a new maintainer, a new domain, and a few new revisions.

Here are my notes on installing the latest stable version (0.9b1) on Ubuntu Jaunty and running a simple example.

Install Fabric 0.9b1

  • Install Easy Install & pip
    sudo apt-get install python-setuptools python-dev build-essential
    sudo easy_install -U pip
  • Install Fabric

    Note: According to the Fabric website, the latest version of the prerequisite Python library, Paramiko has a bug, so it is recommended to install the previous version, 1.7.4, instead. This can be accomplished by creating a requirements file for pip:

    http://www.lag.net/paramiko/download/paramiko-1.7.4.tar.gz
    http://git.fabfile.org/cgit.cgi/fabric/snapshot/fabric-0.9b1.tar.gz

    To install, use the pip install command with the -r option and the path to your requirements file. For convenience, you can install Fabric using my requirements file:

    sudo pip install -r http://www.saltycrane.com/site_media/code/fabric-requirements.txt

Using Fabric

  • Create a file called fabfile.py in ~/myproject:
    from __future__ import with_statement # needed for python 2.5
    from fabric.api import env, run
    
    def ec2():
        env.hosts = ['ec2-65-234-55-183.compute-1.amazonaws.com']
        env.user = 'saltycrane'
        env.key_filename = '/path/to/my/id_ssh_keyfile'
    
    def ps_apache():
        run('ps -e -O rss,pcpu | grep apache')
    
  • Run it
    cd ~/myproject
    fab ec2 ps_apache

    Results:

    [ec2-65-234-55-183.compute-1.amazonaws.com] run: ps -e -O rss,pcpu | grep apache
    [ec2-65-234-55-183.compute-1.amazonaws.com] err: stdin: is not a tty
    [ec2-65-234-55-183.compute-1.amazonaws.com] out:  3571 10996  0.0 S ?        00:00:00 /usr/sbin/apache2 -k start
    [ec2-65-234-55-183.compute-1.amazonaws.com] out:  5047 28352  0.0 S ?        00:00:00 /usr/sbin/apache2 -k start
    [ec2-65-234-55-183.compute-1.amazonaws.com] out:  5048 27756  0.0 S ?        00:00:00 /usr/sbin/apache2 -k start
    [ec2-65-234-55-183.compute-1.amazonaws.com] out:  5049 23752  0.0 S ?        00:00:00 /usr/sbin/apache2 -k start
    [ec2-65-234-55-183.compute-1.amazonaws.com] out:  5050 27344  0.0 S ?        00:00:00 /usr/sbin/apache2 -k start
    [ec2-65-234-55-183.compute-1.amazonaws.com] out:  5055 27344  0.0 S ?        00:00:00 /usr/sbin/apache2 -k start
    [ec2-65-234-55-183.compute-1.amazonaws.com] out:  5166 28404  0.0 S ?        00:00:00 /usr/sbin/apache2 -k start
    [ec2-65-234-55-183.compute-1.amazonaws.com] out:  5167 27900  0.0 S ?        00:00:00 /usr/sbin/apache2 -k start
    [ec2-65-234-55-183.compute-1.amazonaws.com] out:  9365  1208  0.0 S ?        00:00:00 /bin/bash -l -c ps -e -O rss,pcpu | grep apache
    
    Done.
    Disconnecting from ec2-65-234-55-183.compute-1.amazonaws.com... done.

List of available env options

I extracted this list from state.py (0.9b1). Or view the tip version

env.reject_unknown_hosts = True         # reject unknown hosts
env.disable_known_hosts = True          # do not load user known_hosts file
env.user = 'username'                   # username to use when connecting to remote hosts
env.password = 'mypassword'             # password for use with authentication and/or sudo
env.hosts = ['host1.com', 'host2.com']  # comma-separated list of hosts to operate on
env.roles = ['web']                     # comma-separated list of roles to operate on
env.key_filename = 'id_rsa'             # path to SSH private key file. May be repeated.
env.fabfile = '../myfabfile.py'         # name of fabfile to load, e.g. 'fabfile.py' or '../other.py'
env.warn_only = True                    # warn, instead of abort, when commands fail
env.shell = '/bin/sh'                   # specify a new shell, defaults to '/bin/bash -l -c'
env.rcfile = 'myfabconfig'              # specify location of config file to use
env.hide = ['everything']               # comma-separated list of output levels to hide
env.show = ['debug']                    # comma-separated list of output levels to show
env.version = '1.0'
env.sudo_prompt = 'sudo password:'
env.use_shell = False
env.roledefs = {'web': ['www1', 'www2', 'www3'],
                'dns': ['ns1', 'ns2'],
                }
env.cwd = 'mydir'

How to check the status code of a command

To check the return code of your command, set the env.warn_only option to True and check the return_code attribute of object returned from run(). For example:

def ec2():
    env.hosts = ['ec2-65-234-55-183.compute-1.amazonaws.com']
    env.user = 'saltycrane'
    env.key_filename = '/path/to/my/id_ssh_keyfile'
    env.warn_only = True

def getstatus():
    output = run('ls non_existent_file')
    print 'output:', output
    print 'failed:', output.failed
    print 'return_code:', output.return_code
fab ec2 getstatus
[ec2-65-234-55-183.compute-1.amazonaws.com] run: ls non_existent_file
[ec2-65-234-55-183.compute-1.amazonaws.com] err: ls: cannot access non_existent_file: No such file or directory

Warning: run() encountered an error (return code 2) while executing 'ls non_existent_file'

output:
failed: True
return_code: 2

Done.
Disconnecting from ec2-65-234-55-183.compute-1.amazonaws.com... done.

Links

Other notes

  • Error message: paramiko.SSHException: Channel closed.

    Try using Paramiko version 1.7.4 instead of 1.7.5. See http://www.mail-archive.com/[email protected]/msg00844.html.

  • How to check the version of Paramiko:
    $ python
    Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) 
    [GCC 4.3.3] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import paramiko
    >>> paramiko.__version__
    '1.7.5 (Ernest)'
  • Error message: Fatal error: No existing session

    This occurred when I used the wrong username.

Comments


#1 Jonathan Chu commented on :

Very good notes Eliot - quick and easy way to get started with Fabric.

I attended a talk a few weeks back given by the new maintainer, Jeff Forcier. It was interesting to learn that he uses Fabric at work more for sysadmin stuff than for regular deployment.


#2 Eliot commented on :

Hey Jonathan, thanks a lot. I hope your new job is going well.


#3 Meenal commented on :

Thanks Eliot for your wonderful notes.

I developed my blog on Django based on your notes. If you do not mind I have added you to my blogroll.

I see from comments that you have a new job. Congrats!.


#4 Eliot commented on :

Hi Meenal, thanks for adding me to your blogroll! I'm glad my notes were useful to you. Good luck with your Django projects. I like your blog design.


#5 Mark commented on :

Nice post, Eliot. Thanks. If you're interested in getting rid of the "[ec2-65-234-55-183.compute-1.amazonaws.com] err: stdin: is not a tty" error message (which is harmless, but annoying), I wrote up a little note on how to do it. It's due to the 'mesg n' command in a .profile on the remote machine.


#6 Eliot commented on :

Hey Mark thanks for the tip! I will give that a try!