Merge branch 'master' of git@github.com:fnp/wolnelektury
[wolnelektury.git] / fabfile.py
1 from __future__ import with_statement # needed for python 2.5
2 from fabric.api import *
3 from fabric.contrib import files
4
5 import os
6
7
8 # ==========
9 # = Config =
10 # ==========
11 # Globals
12 env.project_name = 'wolnelektury'
13 env.use_south = True
14
15 # Servers
16 def staging():
17     """Use staging server"""
18     env.hosts = ['stigma.nowoczesnapolska.org.pl:2222']
19     env.user = 'platforma'
20     env.path = '/var/services/wolnelektury'
21     env.python = '/usr/bin/python'
22     env.virtualenv = '/usr/bin/virtualenv'
23     env.pip = '/usr/bin/pip'
24
25 def production():
26     """Use production server"""
27     env.hosts = ['wolnelektury.pl:22123']
28     env.user = 'fundacja'
29     env.path = '/opt/lektury/wolnelektury'
30     env.python = '/opt/lektury/basevirtualenv/bin/python'
31     env.virtualenv = '/opt/lektury/basevirtualenv/bin/virtualenv'
32     env.pip = '/opt/lektury/basevirtualenv/bin/pip'
33
34
35 # =========
36 # = Tasks =
37 # =========
38 def test():
39     "Run the test suite and bail out if it fails"
40     require('hosts', 'path', provided_by=[staging, production])
41     result = run('cd %(path)s/%(project_name)s; %(python)s manage.py test' % env)
42
43 def setup():
44     """
45     Setup a fresh virtualenv as well as a few useful directories, then run
46     a full deployment. virtualenv and pip should be already installed.
47     """
48     require('hosts', 'path', provided_by=[staging, production])
49
50     run('mkdir -p %(path)s; cd %(path)s; %(virtualenv)s --no-site-packages .;' % env, pty=True)
51     run('cd %(path)s; mkdir releases; mkdir shared; mkdir packages;' % env, pty=True)
52     run('cd %(path)s/releases; ln -s . current; ln -s . previous' % env, pty=True)
53     deploy()
54
55 def deploy():
56     """
57     Deploy the latest version of the site to the servers,
58     install any required third party modules,
59     install the virtual host and then restart the webserver
60     """
61     require('hosts', 'path', provided_by=[staging, production])
62
63     import time
64     env.release = time.strftime('%Y-%m-%dT%H%M')
65
66     upload_tar_from_git()
67     upload_wsgi_script()
68     upload_vhost_sample()
69     install_requirements()
70     copy_localsettings()
71     symlink_current_release()
72     migrate()
73     restart_webserver()
74
75 def deploy_version(version):
76     "Specify a specific version to be made live"
77     require('hosts', 'path', provided_by=[localhost,webserver])
78     env.version = version
79     with cd(env.path):
80         run('rm releases/previous; mv releases/current releases/previous;', pty=True)
81         run('ln -s %(version)s releases/current' % env, pty=True)
82     restart_webserver()
83
84 def rollback():
85     """
86     Limited rollback capability. Simple loads the previously current
87     version of the code. Rolling back again will swap between the two.
88     """
89     require('hosts', provided_by=[staging, production])
90     require('path')
91     with cd(env.path):
92         run('mv releases/current releases/_previous;', pty=True)
93         run('mv releases/previous releases/current;', pty=True)
94         run('mv releases/_previous releases/previous;', pty=True)
95     restart_webserver()
96
97
98 # =====================================================================
99 # = Helpers. These are called by other functions rather than directly =
100 # =====================================================================
101 def upload_tar_from_git():
102     "Create an archive from the current Git branch and upload it"
103     print '>>> upload tar from git'
104     require('release', provided_by=[deploy])
105     local('git-archive-all.sh --format tar %(release)s.tar' % env)
106     local('gzip %(release)s.tar' % env)
107     run('mkdir -p %(path)s/releases/%(release)s' % env, pty=True)
108     run('mkdir -p %(path)s/packages' % env, pty=True)
109     put('%(release)s.tar.gz' % env, '%(path)s/packages/' % env)
110     run('cd %(path)s/releases/%(release)s && tar zxf ../../packages/%(release)s.tar.gz' % env, pty=True)
111     local('rm %(release)s.tar.gz' % env)
112
113 def upload_vhost_sample():
114     "Create and upload Apache virtual host configuration sample"
115     print ">>> upload vhost sample"
116     files.upload_template('%(project_name)s.vhost.template' % env, '%(path)s/%(project_name)s.vhost.sample' % env, context=env)
117
118 def upload_wsgi_script():
119     "Create and upload a wsgi script sample"
120     print ">>> upload wsgi script sample"
121     files.upload_template('%(project_name)s.wsgi.template' % env, '%(path)s/%(project_name)s.wsgi' % env, context=env)
122     run('chmod ug+x %(path)s/%(project_name)s.wsgi' % env)
123
124 def install_requirements():
125     "Install the required packages from the requirements file using pip"
126     print '>>> install requirements'
127     require('release', provided_by=[deploy])
128     run('cd %(path)s; %(pip)s install -E . -r %(path)s/releases/%(release)s/requirements.txt' % env, pty=True)
129
130 def copy_localsettings():
131     "Copy localsettings.py from root directory to release directory (if this file exists)"
132     print ">>> copy localsettings"
133     require('release', provided_by=[deploy])
134     require('path', provided_by=[staging, production])
135
136     with settings(warn_only=True):
137         run('cp %(path)s/localsettings.py %(path)s/releases/%(release)s/%(project_name)s' % env)
138
139 def symlink_current_release():
140     "Symlink our current release"
141     print '>>> symlink current release'
142     require('release', provided_by=[deploy])
143     require('path', provided_by=[staging, production])
144     with cd(env.path):
145         run('rm releases/previous; mv releases/current releases/previous')
146         run('ln -s %(release)s releases/current' % env)
147
148 def migrate():
149     "Update the database"
150     print '>>> migrate'
151     require('project_name', provided_by=[staging, production])
152     with cd('%(path)s/releases/current/%(project_name)s' % env):
153         run('../../../bin/python manage.py syncdb --noinput' % env, pty=True)
154         if env.use_south:
155             run('../../../bin/python manage.py migrate' % env, pty=True)
156
157 def restart_webserver():
158     "Restart the web server"
159     print '>>> restart webserver'
160     run('touch %(path)s/releases/current/%(project_name)s/%(project_name)s.wsgi' % env)