3d1be713b13eaf6b0c84f13a54f358e0ad326d6b
[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     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 upload_celery_conf():
125     "Create and upload a Celery conf for supervisord"
126     print ">>> upload celery supervisord conf"
127     files.upload_template('%(project_name)s-celery.conf.template' % env, '%(path)s/%(project_name)s-celery.conf' % env, context=env)
128     run('chmod ug+x %(path)s/%(project_name)s-celery.conf' % env)
129
130 def install_requirements():
131     "Install the required packages from the requirements file using pip"
132     print '>>> install requirements'
133     require('release', provided_by=[deploy])
134     run('cd %(path)s; %(pip)s install -E . -r %(path)s/releases/%(release)s/requirements.txt' % env, pty=True)
135
136 def copy_localsettings():
137     "Copy localsettings.py from root directory to release directory (if this file exists)"
138     print ">>> copy localsettings"
139     require('release', provided_by=[deploy])
140     require('path', provided_by=[staging, production])
141
142     with settings(warn_only=True):
143         run('cp %(path)s/localsettings.py %(path)s/releases/%(release)s/%(project_name)s' % env)
144
145 def symlink_current_release():
146     "Symlink our current release"
147     print '>>> symlink current release'
148     require('release', provided_by=[deploy])
149     require('path', provided_by=[staging, production])
150     with cd(env.path):
151         run('rm releases/previous; mv releases/current releases/previous')
152         run('ln -s %(release)s releases/current' % env)
153
154 def migrate():
155     "Update the database"
156     print '>>> migrate'
157     require('project_name', provided_by=[staging, production])
158     with cd('%(path)s/releases/current/%(project_name)s' % env):
159         run('../../../bin/python manage.py syncdb --noinput' % env, pty=True)
160         if env.use_south:
161             run('../../../bin/python manage.py migrate' % env, pty=True)
162
163 def restart_webserver():
164     "Restart the web server"
165     print '>>> restart webserver'
166     run('touch %(path)s/%(project_name)s.wsgi' % env)
167     print '>>> restart Celery'
168     sudo('supervisorctl restart celery.%(project_name)s:' % env, shell=False)