Using Fabric for SSH

Fabric is a library and command-line tool for streamlining the use of SSH for application deployment or systems administration tasks.

It provides a basic suite of operations for executing local or remote shell commands (normally or via sudo) and uploading/downloading files, as well as auxiliary functionality such as prompting the running user for input, or aborting execution.

fab Command

Fabric provides a command line utility fab, which reads its configuration from a file named fabfile.py in directory from which it is run. A typical fabfile contains one or more functions to be executed on a group of remote hosts.

The following example provides functions to check free disk space and host type, as well as defining a group of hosts on which to run:

1
2
3
4
5
6
7
from fabric.api import run

def host_type():
    run('uname -s')
    
def diskspace():
    run('df')

Once a task is defined, it may be run on one or more servers, like so:

(sysadmin)$ fab -H newyork,seattle host_type
[newyork] run: uname -s
[newyork] out: Linux
[seattle] run: uname -s
[seattle] out: Linux

Done.
Disconnecting from newyork... done.
Disconnecting from seattle... done.

Rather than supplying hostnames on the command line, you can also define the group of hosts on which tasks will be run with env.hosts:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from fabric.api import run
from fabric.api import env

env.hosts = [
    'newyork',
    'seattle',
    'localhost',
    ]

def host_type():
    run('uname -s')
    
def diskspace():
    run('df')

Now run fab without a -H argument:

(sysadmin)$ fab host_type
[newyork] run: uname -s
[newyork] out: Linux
[seattle] run: uname -s
[seattle] out: Linux
[localhost] run: uname -s
[localhost] out: Linux

Done.
Disconnecting from newyork... done.
Disconnecting from seattle... done.
Disconnecting from localhost... done.

Task arguments

It’s often useful to pass runtime parameters into your tasks, just as you might during regular Python programming. Fabric has basic support for this using a shell-compatible notation: <task name>:<arg>,<kwarg>=<value>,.... It’s contrived, but let’s extend the above example to say hello to you personally: [1]

def hello(name="world"):
   print("Hello %s!" % name)

By default, calling fab hello will still behave as it did before; but now we can personalize it:

(sysadmin)$ fab hello:name=Jeff
Hello Jeff!

Done.

Those already used to programming in Python might have guessed that this invocation behaves exactly the same way:

(sysadmin)$ fab hello:Jeff
Hello Jeff!

Done.

For the time being, your argument values will always show up in Python as strings and may require a bit of string manipulation for complex types such as lists. Future versions may add a typecasting system to make this easier.

Library Usage

In addition to use via the fab tool, Fabric’s components may be imported into other Python code, providing a Pythonic interface to the SSH protocol suite at a higher level than that provided by e.g. the ssh library (which Fabric itself uses.) [2]

Lab – Average Uptime

Consider the case where we want to collect average uptime from a group of hosts. File labs/fabric/uptime.py will get you started:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
'''
Lab - Average Uptime

Write a script that uses the Fabric library to poll a group of hosts for their
uptimes, and displays their average uptime for the user.
'''


from fabric import tasks
from fabric.api import run
from fabric.api import env
from fabric.network import disconnect_all


env.hosts = [
    'newyork',
    'seattle',
    'localhost',
    ]

def uptime():
    res = run('cat /proc/uptime')
    #
    # Now, examine the result and extract the average uptime
    #
        

def main():
    uts_dict = tasks.execute(uptime)
    # 
    # Now, calculate average uptime...
    #
    disconnect_all() # Call this when you are done, or get an ugly exception!


if __name__ == '__main__':
    main()
    

Footnotes

[1]http://docs.fabfile.org/en/1.4.2/tutorial.html#task-arguments
[2]http://stackoverflow.com/a/8166050