Python code deployment with Fabric
written on Friday, May 6, 2011
So last night at the IndyPy meetup I gave a very impromptu talk on Fabric. It lasted maybe five minutes and afterward I really felt like I just did not do this great tool justice. In order to make up for that, I thought I'd dive in a little deeper to Fabric.
Why I am an idiot
First and foremost, I love Fabric because it lets me be lazy. For far too long while I was developing Yukmarks, I was manually typing things like:
local$ ssh my-ip-address.com
remote$ git pull && sudo /etc/init.d/apache2 restart && ./manage.py dump_data && pg_dump >> foo.txt
That's right:
You get the picture. It was ugly, and stupid, and time consuming, and I literally cannot believe that I spent all those calories typing those commands in over... and over... and over again.
Why I love Fabric
So then someone introduced me to Fabric. I now use Fabric to automate code deployment. (See my full fabfile here.)
(In no way do I claim to use Fabric to its full potential, nor do I claim to be an expert, nor do I claim that my fabfile is fabulous. If you've got tips or corrections, please leave them in the comments.)
To make Fabric work, you just import the API and you're off:
from fabric.api import *
from hosts import hosts, secret
# I keep my hosts and auth data in a local file called hosts.py
env.password = secret
env.hosts = hosts
def git_pull():
run("cd %s; . bin/activate; cd %s; git pull; ./manage.py schemamigration"
" --auto yuk; ./manage.py migrate yuk;cp %s* %s;sudo /etc/init.d/apache2"
" force-reload" % (domain_dir, appdir, css_dir, static_file_dir))
The above code is exactly what it looks like: a number of semicolon-separated shell commands. It's probably the most idiot-proof, time-saving thing I've ever used. Please see the below:
Stop typing so much. Fabric makes things ridiculously easy.
Edit 5/8/11: I actually reduced the complexity of my update_index() fabfile function quite a bit. I was doing a lot of really stupid chowning back and forth, which I've now fixed. Old:
def update_search():
run("cd %s; . bin/activate; cd %s; sudo chown matt:matt %s; sudo chown matt"
":matt %s*; ./manage.py update_index; sudo chown www-data:www-data %s; "
"sudo chown www-data:www-data %s*; sudo /etc/init.d/apache2 force-reloa"
"d" % (domain_dir, appdir, whoosh_dir,
whoosh_dir, whoosh_dir, whoosh_dir))
New:
def update_search():
run("sudo -u www-data /a/mattdeboard.net/bin/python %smanage.py update_inde"
"x; sudo /etc/init.d/apache2 force-reload" % appdir)
p.s. In addition to Fabric, you'll definitely want to incorporate cron & creative use of your Makefile to make your life easier. Consult the github repo for Yukmarks.