Fabric: a System Administrator's Best Friend
Do you routinely make changes to more than a dozen machines at a time? Read this article to find out about a tool to make that task much easier.
I'll be honest. Even though this library is fully five years old, I hadn't heard of Fabric until about six months ago. Now I can't imagine not having it in my digital tool belt. Fabric is a Python library/tool that is designed to use SSH to execute system administration and deployment tasks on one or more remote machines. No more running the same task, machine by machine, to make one change across the board. It is a simple fire-and-forget tool that will make your life so much simpler. Not only can you run simple tasks via SSH on multiple machines, but since you're using Python code to execute items, you can combine it with any arbitrary Python code to make robust, complex, elegant applications for deployment or administration tasks.
Fabric requires Python 2.5 or later, the setuptools packaging/installation library, the ssh Python library, and SSH and its dependencies. For the most part, you won't have to worry about any of this, because Fabric can be installed easily through various package managers. The easiest, and most prolific way to install Fabric is using pip (or easy_install). On most systems, you can use your systems package manager (apt-get, install, and so on) to install it (the package either will be fabric or python-fabric). If you're feeling froggy, you can check out the git repository and hack away at the source code.
Once installed, you will have access to the
fab script from the command
The Fabric library is composed of nine separate operations that can be used in conjunction to achieve your desired effect. Simply insert these functions into your fabfile and off you go:
getallows you to pull files from the remote machine to your local machine. This is like using
scpto copy a file or files from many machines. This is super effective for systematically collecting log files or backups in a central location. The remote path is the path of the file on the remote machine that you are grabbing, and the local path is the path to which you want to save the file on the local machine. If the local path is omitted, Fabric assumes you are saving the file to the working directory.
local(command, capture=False)— the local function allows you to take action on the local host in a similar fashion to the Python subprocess module (in fact, local is a simplistic wrapper that sits on top of the subprocess module). Simply supply the command to run and, if needed, whether you want to capture the output. If you specify
capture=True, the output will be returned as a string from local, otherwise it will be output to STDOUT.
open_shell(command=None)— this function is mostly for debugging purposes. It opens an interactive shell on the remote end, allowing you to run any number of commands. This is particularly helpful if you are running a series of particularly complex commands and it doesn't seem to be working on some of your machines.
prompt(text, key=None, default='', validate=None)— in the case when you need to supply a value, but don't want to specify it on the command line for whatever reason,
promptis the ideal way to do this. I have a fabfile I use to add/remove/check the status of software on all of the servers I maintain, and I use this in the script for when I forget to specify what software I'm working on. This prompt will appear for each host you specify, so make sure you account for that!
put(local_path, remote_path, use_sudo=False, mirror_local_mode=False, mode=None)— this is the opposite command of
get, although you are given more options when putting to a remote system than getting. The local path can be a relative or absolute file path, or it can be an actual file object. If either
remote_pathis left blank, the working directory will be used. If
use_sudo=Trueis specified, Fabric will put the file in a temporary location on the remote machine, then use
sudoto move it from the temporary location to the specified location. This is particularly handy when moving system files like /etc/resolv.conf or the like that can't be moved by a standard user and you have root login turned off in SSH. If you want the file mode preserved through the copy, use
mirror_local_mode=True; otherwise, you can set the mode using
rebootdoes exactly what it says: reboots the remote machine. By default,
rebootwill wait 120 seconds before attempting to reconnect to the machine to continue executing any following commands.
requireforces the specified keys to be present in the shared environment dict in order to continue execution. If these keys are not present, Fabric will abort. Optionally, you can specify
used_forto indicate what the key is used for in this particular context.
run(command, shell=True, pty=True, combine_stderr=True, quiet=False, warn_only=False, stdout=None, stderr=None)— This and sudo are the two most used functions in Fabric, because they actually execute commands on the remote host (which is the whole point of Fabric). With
run, you execute the specified command as the given user.
runreturns the output from the command as a string that can be checked for a failed, succeeded and return_code attribute.
shellcontrols whether a shell interpreter is created for the command. If turned off, characters will not be escaped automatically in the command. Passing
pty=Falsecauses a psuedo-terminal not to be created while executing this command; this can have some benefit if the command you are running has issues interacting with the psuedo-terminal, but otherwise, it will be created by default. If you want stderr from the command to be parsable separately from stdout, use
combine_stderr=Falseto indicate that.
quiet=Truewill cause the command to run silently, sending no output to the screen while executing. When an error occurs in Fabric, typically the script will abort and indicate as such. You can indicate that Fabric need not abort if a particular command errors using the
warn_onlyargument. Finally, you can redirect where the remote stderr and stdout redirect to on the local side. For instance, if you want the stderr to pipe to stdout on the local end, you could indicate that with
sudo(command, shell=True, pty=True, combine_stderr=True, user=None, quiet=False, warn_only=False, stdout=None, stderr=None, group=None)—
sudoworks precisely like
run, except that it will elevate privileges prior to executing the command. It basically works the same is if you'd run the command using
run, but prepended
sudoto the front of command.
sudoalso takes user and group arguments, allowing you to specify which user or group to run the command as. As long as the original user has the permissions to escalate for that particular user/group and command, you are good to go.
Free DevOps eBooks, Videos, and more!
Regardless of where you are in your DevOps process, Linux Journal can help!
We offer here the DEFINITIVE DevOps for Dummies, a mobile Application Development Primer, and advice & help from the expert sources like:
- Linux Journal
- High-Availability Storage with HA-LVM
- DNSMasq, the Pint-Sized Super Dæmon!
- March 2015 Issue of Linux Journal: System Administration
- Localhost DNS Cache
- Real-Time Rogue Wireless Access Point Detection with the Raspberry Pi
- Days Between Dates: the Counting
- PostgreSQL, the NoSQL Database
- The Usability of GNOME
- Linux for Astronomers
- You're the Boss with UBOS