Now all you have to do is...
• ﬁx bugs and implement new • keep track of local_settings
• reload wsgi ﬁles
• git archive
• Change symbolic links (yay,
• move ﬁles from development deployed!)
to staging and production
servers • empty and pre-warm cache
• install updates to django, • oops! forgot to migrate data!
reusable apps, pypi
• run backups
(for the rest of your life)
Wouldn’t it be nice if all you had to
do was this?
$ fab staging deploy
$ fab production deploy (yay, backup’d
Basic building blocks (the core API)
• run — run a command on a remote host.
• sudo — run a sudoed command on a remote host.
• local — run a command on the local host.
• get/put — copy a ﬁle from/to a remote host.
• prompt — ask the user for information
• For everything else there’s Python.
• Get output and return code:
output = run(“command”)
• Chain commands:
run(“workon project && git pull origin master”)
• start pseudo-daemons:
run(“screen -d -m not-a-daemon”)
• Any return code except 0 is treated as an error and an exception is
thrown (unless warn_only is set)
• Put a ﬁle (upload):
put(“local-file”, “remote-file”, mode=0755)
• Get a ﬁle (download):
• If a problem occurs while uploading or downloading ﬁles, fabric
throws an exception.
relase_name = prompt(“What do you want to “
“name the new release?: ”,
proxy_port_number = prompt(“Proxy port: “,
username = prompt(“Username: “,
Keeping state (sort of)
run(“git clone git://git/something.git”)
run(“mkvirtualenv --no-site-packages something“)
• For those running from trunk:
with prefix(“workon something”):
run(“pip install Django>=1.1”)
Observe that the name is not set in stone yet.
• Contrib is a collection of useful tools. Search and replace in remote
ﬁles amongst other things.
• However, it is not as evolved as the Fabric core API and contains, in
Jeff Forcier’s own words, “approaches that work for Jeff on two
different Linux distros and that’s about it.”
Append text to ﬁles
• Appends text unless it already exist in ﬁle as a discrete line:
from fabric.contrib.files import append
append(“DATABASE_NAME = 'hello.db'”,
Search and replace
• Use fabric’s sed function to modify content of ﬁles:
from fabric.contrib.files import sed
“^DEBUG = True$”,
“DEBUG = False”)
from fabric.api import run
run('workon myproject && pip install django')
$ fab -H localhost,djangodev install_django
This will install Django within the myproject virtualenv on both the local
machine and on the host djangodev
While Fabric is easy,
deployment is hard!
Rebuilding from scratch?
• Deﬁne scratch Depends to some degree on
what you want to achieve
Do you start from a given and if it’s limited to
virtual machine image? deployment purposes.
...or just your application and Perhaps you just want to be
its dependencies? able to easily test against a
new release of Ubuntu,
...or just your application? perhaps a new release of
What about the database?
• Do you migrate the current • Apply migrations to a copy?
When you’ve deployed, the
You could backup and copy becomes the new
restore if something goes production DB.
Make sure you have a way
But you can’t reliably keep of ﬁnding out the name of
the site up while migrating. your current production DB
(in order to deploy the next
might need to be handled.
• Cancel and revert deployment if the test suite fails!
• This is actually pretty simple:
run(“workon project && python manage.py test”)
Django returns the number of failed tests or 0 if all tests pass, and
run throws an exception if the return code is anything but 0.
All you have to worry about is reverting to the state before
What about the live site?
• Show an update banner on • Set database layer to read-
the site? only?
• Set Django application to Have you designed your
application to handle SQL
Have you separated code
that reads from the DB from • Shut down Apache? What if
code that writes? you have multiple
• You’ll probably need to work
on a separate DB while
updating and migrating,
Trying to combine it all
1. Get source code
2. Create virtualenv
3. Use buildout to install dependencies
4. Copy local conﬁguration for testing and production from local
repository (as to avoid checking in passwords)
5. Show upgrade banner on site
6. Close database for writing
7. Fetch the name of the current production database
8. Clone database
9. Modify Django settings to point at cloned database
10.Migrate using South
11.Run tests with testing conﬁguration
12.Re-index site using your chosen search backend
13.Switch symlink from pointing to previous production site to new (site
should reload automatically since wsgi ﬁle is updated)
14.Open DB for writing