Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- """
- This fabric file makes setting up and deploying a django application much
- easier, but it does make a few assumptions. Namely that you're using Git,
- Apache and mod_wsgi and your using Debian or Ubuntu. Also you should have
- Django installed on your local machine and SSH installed on both the local
- machine and any servers you want to deploy to.
- _note that I've used the name project_name throughout this example. Replace
- this with whatever your project is called._
- First step is to create your project locally:
- mkdir project_name
- cd project_name
- django-admin.py startproject project_name
- Now add a requirements file so pip knows to install Django. You'll probably
- add other required modules in here later. Creat a file called requirements.txt
- and save it at the top level with the following contents:
- Django
- Then save this fabfile.py file in the top level directory which should give you:
- project_name
- fabfile.py
- requirements.txt
- project_name
- __init__.py
- manage.py
- settings.py
- urls.py
- You'll need a WSGI file called project_name.wsgi, where project_name
- is the name you gave to your django project. It will probably look
- like the following, depending on your specific paths and the location
- of your settings module
- import os
- import sys
- # put the Django project on sys.path
- sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../")))
- os.environ["DJANGO_SETTINGS_MODULE"] = "project_name.settings"
- from django.core.handlers.wsgi import WSGIHandler
- application = WSGIHandler()
- Last but not least you'll want a virtualhost file for apache which looks
- something like the following. Save this as project_name in the inner directory.
- You'll want to change /path/to/project_name/ to the location on the remote
- server you intent to deploy to.
- <VirtualHost *:80>
- WSGIDaemonProcess project_name-production user=project_name group=project_name threads=10 python-path=/path/to/project_name/lib/python2.6/site-packages
- WSGIProcessGroup project_name-production
- WSGIScriptAlias / /path/to/project_name/releases/current/project_name/project_name.wsgi
- <Directory /path/to/project_name/releases/current/project_name>
- Order deny,allow
- Allow from all
- </Directory>
- ErrorLog /var/log/apache2/error.log
- LogLevel warn
- CustomLog /var/log/apache2/access.log combined
- </VirtualHost>
- Now create a file called .gitignore, containing the following. This
- prevents the compiled python code being included in the repository and
- the archive we use for deployment.
- *.pyc
- You should now be ready to initialise a git repository in the top
- level project_name directory.
- git init
- git add .gitignore project_name
- git commit -m "Initial commit"
- All of that should leave you with
- project_name
- .git
- .gitignore
- requirements.txt
- fabfile.py
- project_name
- __init__.py
- project_name
- project_name.wsgi
- manage.py
- settings.py
- urls.py
- In reality you might prefer to keep your wsgi files and virtual host files
- elsewhere. The fabfile has a variable (config.virtualhost_path) for this case.
- You'll also want to set the hosts that you intend to deploy to (config.hosts)
- as well as the user (config.user).
- The first task we're interested in is called setup. It installs all the
- required software on the remote machine, then deploys your code and restarts
- the webserver.
- fab local setup
- After you've made a few changes and commit them to the master Git branch you
- can run to deply the changes.
- fab local deploy
- If something is wrong then you can rollback to the previous version.
- fab local rollback
- Note that this only allows you to rollback to the release immediately before
- the latest one. If you want to pick a arbitrary release then you can use the
- following, where 20090727170527 is a timestamp for an existing release.
- fab local deploy_version:20090727170527
- If you want to ensure your tests run before you make a deployment then you can
- do the following.
- fab local test deploy
- """
- # globals
- config.project_name = 'project_name'
- # environments
- def local():
- "Use the local virtual server"
- config.hosts = ['127.0.0.1']
- config.path = '/path/to/project_name'
- config.user = 'garethr'
- config.virtualhost_path = "/"
- # tasks
- def test():
- "Run the test suite and bail out if it fails"
- local("cd $(project_name); python manage.py test", fail="abort")
- def setup():
- """
- Setup a fresh virtualenv as well as a few useful directories, then run
- a full deployment
- """
- require('hosts', provided_by=[local])
- require('path')
- sudo('aptitude install -y python-setuptools')
- sudo('easy_install pip')
- sudo('pip install virtualenv')
- sudo('aptitude install -y apache2')
- sudo('aptitude install -y libapache2-mod-wsgi')
- # we want rid of the defult apache config
- sudo('cd /etc/apache2/sites-available/; a2dissite default;')
- run('mkdir -p $(path); cd $(path); virtualenv .;')
- run('cd $(path); mkdir releases; mkdir shared; mkdir packages;', fail='ignore')
- deploy()
- def deploy():
- """
- Deploy the latest version of the site to the servers, install any
- required third party modules, install the virtual host and
- then restart the webserver
- """
- require('hosts', provided_by=[local])
- require('path')
- import time
- config.release = time.strftime('%Y%m%d%H%M%S')
- upload_tar_from_git()
- install_requirements()
- install_site()
- symlink_current_release()
- migrate()
- restart_webserver()
- def deploy_version(version):
- "Specify a specific version to be made live"
- require('hosts', provided_by=[local])
- require('path')
- config.version = version
- run('cd $(path); rm releases/previous; mv releases/current releases/previous;')
- run('cd $(path); ln -s $(version) releases/current')
- restart_webserver()
- def rollback():
- """
- Limited rollback capability. Simple loads the previously current
- version of the code. Rolling back again will swap between the two.
- """
- require('hosts', provided_by=[local])
- require('path')
- run('cd $(path); mv releases/current releases/_previous;')
- run('cd $(path); mv releases/previous releases/current;')
- run('cd $(path); mv releases/_previous releases/previous;')
- restart_webserver()
- # Helpers. These are called by other functions rather than directly
- def upload_tar_from_git():
- require('release', provided_by=[deploy, setup])
- "Create an archive from the current Git master branch and upload it"
- local('git archive --format=tar master | gzip > $(release).tar.gz')
- run('mkdir $(path)/releases/$(release)')
- put('$(release).tar.gz', '$(path)/packages/')
- run('cd $(path)/releases/$(release) && tar zxf ../../packages/$(release).tar.gz')
- local('rm $(release).tar.gz')
- def install_site():
- "Add the virtualhost file to apache"
- require('release', provided_by=[deploy, setup])
- sudo('cd $(path)/releases/$(release); cp $(project_name)$(virtualhost_path)$(project_name) /etc/apache2/sites-available/')
- sudo('cd /etc/apache2/sites-available/; a2ensite $(project_name)')
- def install_requirements():
- "Install the required packages from the requirements file using pip"
- require('release', provided_by=[deploy, setup])
- run('cd $(path); pip install -E . -r ./releases/$(release)/requirements.txt')
- def symlink_current_release():
- "Symlink our current release"
- require('release', provided_by=[deploy, setup])
- run('cd $(path); rm releases/previous; mv releases/current releases/previous;', fail='ignore')
- run('cd $(path); ln -s $(release) releases/current')
- def migrate():
- "Update the database"
- require('project_name')
- run('cd $(path)/releases/current/$(project_name); ../../../bin/python manage.py syncdb --noinput')
- def restart_webserver():
- "Restart the web server"
- sudo('/etc/init.d/apache2 restart')
Add Comment
Please, Sign In to add comment