This is a guide for installing and using Fabric on Ubuntu.
Fabric is a Python tool and a library for combining Python with SSH.
The tool can be used to execute Python functions from the command line. It’s also
possible to execute shell commands over SSH with Fabric and by combining the Python functions
with the SSH, it’s possible to automate system administration tasks. (fabfile.org)
You can use Fabric as a tool for centralized configuration management. You can run administrative tasks
on all of your machines simultaneously. Fabric is fast and easy to install and start using since there’s
no configuration needed, just install and start adding tasks to your fabfile.
Fabric doesn’t require anything else on the remote systems but a working SSH server. So if you
can control a device with SSH, you can also control it with Fabric. This is why Fabric is such
an easy and nice tool to add to your sysadmin tools. If you prefer Ruby over Python, take a look at a
similiar tool called Capistrano.
In these tutorials I will go through the installation and all the basics you need to start using
The recommended way to install Fabric is by using pip. If you don’t have pip, install it first.
sudo apt-get -y install python-pip
sudo pip install fabric
If you encounter any errors make sure you have at least Python 2.6 and pip 0.8.1 or above.
Making your first fabfile
Fabric uses a Python file called fabfile.py to execute tasks. The fabfile should be in the same
directory where you run the Fabric tool. Let’s create a basic Hello World first. Use whatever
text editor you wish for creating and modifying your fabfile. Just remember to name it fabfile.py.
This is taken from fabfile.org:
def hello(): print("Hello World!")
That’s all. It doesn’t even use the Fabric API yet. It’s just a simple python function that can be
executed with Fabric.
Now let’s run it:
You can list all your functions/tasks with:
This was still executed only on your local machine. But of course you’ll want to create tasks that are
run on remote devices. Let’s move on to remote tasks.
Running a command on remote hosts
You can just keep adding to your existing fabfile. We need to define some hosts that should run our tasks.
This will done in the fabfile by using environmental variable env.hosts. Now we also have to import
Fabric API. We’ll also add our username to the fabfile.
from fabric.api import * env.hosts=["10.10.10.10", "webserver.local"] env.user="hng" def hostname_check(): # hostname_check is just a task name, replace with anything run("hostname")
And we can run it with:
Now the hostname command was run on the remote machines defined in the env.hosts. The username hng
was used to connect to these machines and the output was printed back to you.
If you have different usernames on different hosts, you can use:
env.hosts=["firstname.lastname@example.org", "webserver.local"] env.user="hng"
Now simo username would be used on 10.10.10.10 and hng would be used on webserver.local.
Fabric will ask for your password when connecting to a remote host unless you define it on the fabfile.
Instead of defining it on the fabfile you should use public key authentication. Here’s how to do it in both
Password in the fabfile (not recommended)
Public key authentication
press enter so the key goes to the default location
press enter to leave passphrase empty
press enter to confirm the empty passphrase
Now you can SSH to these remote hosts without a password. And Fabric won’t ask for a password.
Using parameters to run a command
We don’t want to write a separate task for each command. Instead let’s create a task with parameters.
def command(cmd): run(cmd)
Now the cmd is replaced by whatever we decide when running the task.
This would run the hostname command on remote hosts. Another example:
fab command:"hostname -I"
Running a sudo command
Running sudo commands is almost as easy as running normal commands.
def sudo_command(cmd): sudo(cmd) # or sudo("apt-get update")
Run it with:
fab sudo_command:"apt-get install geany"
Now running this will cause remote host to ask for our sudo password. Fabric only asks for same password
once per run. But for full automation we need to get rid of it completely.
Public key authentication won’t help us here. Defining the password in the fabfile would prevent
this but there’s another way.
Removing sudo password prompt
We have to add a line to the remote hosts’ sudoers file or you can add a new file to sudoers.d with
%your_groupname ALL=(ALL) NOPASSWD: ALL
To modify sudoers file, you can use:
Just add the line to the end of the file.
For example user hng belongs to hng group so it would be
%hng ALL=(ALL) NOPASSWD: ALL
Just for enabling this for a certain user, just use it without the %:
hng ALL=(ALL) NOPASSWD: ALL
This has to be done on all of your remote hosts. Exercise: create a fab task to do it on all hosts.
Now we can run sudo commands on remote hosts without password prompting.
Let’s make a task that installs a package.
def install(package): sudo("apt-get -y install %s" % package)
Notice the %s. It’s a normal Python way of placing variables to a string of text. This way we can
easily use parameters in our tasks. Another example with more parameters and two commands:
def install(package1,package2): sudo("apt-get update") sudo("apt-get -y install %s %s" % (package1,package2))
You can run it with:
This would update sourcelist and install geany and e3 to our remote hosts.
If you need to run commands on the machine with Fabric. Just replace “run” with “local”:
def local_cmd(): local("echo fabtest >> test.log")
Since Fabric version 1.3.0 it’s been possible to run Fabric tasks simultaneously on all remote hosts.
To do this you can just add @parallel above your tasks or define it in the env.vars like this:
@parallel def pcmd(cmd): run(cmd)
Notice that you shouldn’t run parallel commands that require user input in the middle of execution as
it will mess up everything.
Now you’ve learned to run simple commands with Fabric on remote hosts, try using multiple commands on a single task to create more complex tasks. On my next post we’ll transfer files with Fabric and learn some basic error handling.
The complete tutorial fabfile here:
from fabric.api import * env.hosts=["email@example.com", "webserver.local"] env.user="hng" #env.password="password" #env.parallel=True def hostname_check(): run("hostname") def command(cmd): run(cmd) def sudo_command(cmd): sudo(cmd) def install(package): sudo("apt-get -y install %s" % package) def local_cmd(): local("echo fabtest >> test.log") @parallel def pcmd(cmd): run(cmd)
Feel free to leave a comment if you have any questions or improvement suggestions.