be more robust
[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']
28     env.user = 'lektury'
29     env.path = '/srv/wolnelektury.pl'
30     env.python = '/usr/bin/python'
31     env.virtualenv = '/usr/bin/virtualenv'
32     env.pip = '/usr/bin/pip'
33
34 # =========
35 # = Tasks =
36 # =========
37 def test():
38     "Run the test suite and bail out if it fails"
39     require('hosts', 'path', provided_by=[staging, production])
40     result = run('cd %(path)s/%(project_name)s; %(python)s manage.py test' % env)
41
42 def setup():
43     """
44     Setup a fresh virtualenv as well as a few useful directories, then run
45     a full deployment. virtualenv and pip should be already installed.
46     """
47     require('hosts', 'path', provided_by=[staging, production])
48
49     run('mkdir -p %(path)s; cd %(path)s; %(virtualenv)s .;' % env, pty=True)
50     run('cd %(path)s; mkdir releases; mkdir shared; mkdir packages;' % env, pty=True)
51     run('cd %(path)s/releases; ln -s . current; ln -s . previous' % env, pty=True)
52     deploy()
53
54 def deploy():
55     """
56     Deploy the latest version of the site to the servers,
57     install any required third party modules,
58     install the virtual host and then restart the webserver
59     """
60     require('hosts', 'path', provided_by=[staging, production])
61
62     import time
63     env.release = time.strftime('%Y-%m-%dT%H%M')
64
65     upload_tar_from_git()
66     upload_wsgi_script()
67     upload_vhost_sample()
68     upload_celery_conf()
69     install_requirements()
70     copy_localsettings()
71     symlink_current_release()
72     migrate()
73     collectstatic()
74     restart_webserver()
75
76 def deploy_version(version):
77     "Specify a specific version to be made live"
78     require('hosts', 'path', provided_by=[localhost,webserver])
79     env.version = version
80     with cd(env.path):
81         run('rm releases/previous; mv releases/current releases/previous;', pty=True)
82         run('ln -s %(version)s releases/current' % env, pty=True)
83     restart_webserver()
84
85 def rollback():
86     """
87     Limited rollback capability. Simple loads the previously current
88     version of the code. Rolling back again will swap between the two.
89     """
90     require('hosts', provided_by=[staging, production])
91     require('path')
92     with cd(env.path):
93         run('mv releases/current releases/_previous;', pty=True)
94         run('mv releases/previous releases/current;', pty=True)
95         run('mv releases/_previous releases/previous;', pty=True)
96     restart_webserver()
97
98
99 # =====================================================================
100 # = Helpers. These are called by other functions rather than directly =
101 # =====================================================================
102 def upload_tar_from_git():
103     "Create an archive from the current Git branch and upload it"
104     print '>>> upload tar from git'
105     require('release', provided_by=[deploy])
106     local('git-archive-all.sh --format tar %(release)s.tar' % env)
107     local('gzip %(release)s.tar' % env)
108     run('mkdir -p %(path)s/releases/%(release)s' % env, pty=True)
109     run('mkdir -p %(path)s/packages' % env, pty=True)
110     put('%(release)s.tar.gz' % env, '%(path)s/packages/' % env)
111     run('cd %(path)s/releases/%(release)s && tar zxf ../../packages/%(release)s.tar.gz' % env, pty=True)
112     local('rm %(release)s.tar.gz' % env)
113
114 def upload_vhost_sample():
115     "Create and upload Apache virtual host configuration sample"
116     print ">>> upload vhost sample"
117     files.upload_template('%(project_name)s.vhost.template' % env, '%(path)s/%(project_name)s.vhost.sample' % env, context=env)
118
119 def upload_wsgi_script():
120     "Create and upload a wsgi script sample"
121     print ">>> upload wsgi script sample"
122     files.upload_template('%(project_name)s.wsgi.template' % env, '%(path)s/%(project_name)s.wsgi' % env, context=env)
123     run('chmod ug+x %(path)s/%(project_name)s.wsgi' % env)
124
125 def upload_celery_conf():
126     "Create and upload a Celery conf for supervisord"
127     print ">>> upload celery supervisord conf"
128     files.upload_template('%(project_name)s-celery.conf.template' % env, '%(path)s/%(project_name)s-celery.conf' % env, context=env)
129     run('chmod ug+x %(path)s/%(project_name)s-celery.conf' % env)
130
131 def install_requirements():
132     "Install the required packages from the requirements file using pip"
133     print '>>> install requirements'
134     require('release', provided_by=[deploy])
135     run('cd %(path)s; %(pip)s install -E ve -r %(path)s/releases/%(release)s/requirements.txt' % env, pty=True)
136
137 def copy_localsettings():
138     "Copy localsettings.py from root directory to release directory (if this file exists)"
139     print ">>> copy localsettings"
140     require('release', provided_by=[deploy])
141     require('path', provided_by=[staging, production])
142
143     with settings(warn_only=True):
144         run('cp %(path)s/localsettings.py %(path)s/releases/%(release)s/%(project_name)s' % env)
145
146 def symlink_current_release():
147     "Symlink our current release"
148     print '>>> symlink current release'
149     require('release', provided_by=[deploy])
150     require('path', provided_by=[staging, production])
151     with cd(env.path):
152         run('rm releases/previous; mv releases/current releases/previous')
153         run('ln -s %(release)s releases/current' % env)
154
155 def migrate():
156     "Update the database"
157     print '>>> migrate'
158     require('project_name', provided_by=[staging, production])
159     with cd('%(path)s/releases/current/%(project_name)s' % env):
160         run('../../../ve/bin/python manage.py syncdb --noinput' % env, pty=True)
161         if env.use_south:
162             run('../../../ve/bin/python manage.py migrate' % env, pty=True)
163
164 def collectstatic():
165     """Collect static files"""
166     print '>>> collectstatic'
167     require('project_name', provided_by=[staging, production])
168     with cd('%(path)s/releases/current/%(project_name)s' % env):
169         run('../../../ve/bin/python manage.py collectstatic --noinput' % env, pty=True)
170
171 def restart_webserver():
172     "Restart the web server"
173     print '>>> restart webserver'
174     run('touch %(path)s/%(project_name)s.wsgi' % env)
175     print '>>> restart Celery'
176     sudo('supervisorctl restart celery.%(project_name)s:' % env, shell=False)