b132b9ddcd29541e94027f12ac5d2a600cd902ef
[redakcja.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 import time
7
8 # ==========
9 # = Config =
10 # ==========
11 # Globals
12 env.project_name = 'platforma'
13 env.use_south = True
14 env.giturl = "git://github.com/fnp/redakcja.git"
15
16
17 # Servers
18 def staging():
19     """Use staging server"""
20     env.hosts = ['stigma.nowoczesnapolska.org.pl:2222']
21     env.user = 'platforma'
22     env.path = '/var/services/platforma'
23     env.python = '/usr/bin/python'
24     env.virtualenv = '/usr/bin/virtualenv'
25     env.pip = '/usr/bin/pip'
26     env.gitbranch = "staging"
27     common()
28
29
30 def production():
31     """Use production server"""
32     env.hosts = ['szo.nowoczesnapolska.org.pl:2225']
33     env.user = 'librarian'
34     env.gitbranch = 'master'
35     env.sandbox = '/srv/library-in-a-box/sandbox/'
36     env.virtualenv = os.path.join(env.sandbox, 'bin', 'virtualenv')
37
38     env.pip = os.path.join(env.sandbox, 'python', 'bin', 'pip')
39     env.python = os.path.join(env.sandbox, 'python', 'bin', 'python')
40     common()
41
42
43 def common():
44     env.path = os.path.join(env.sandbox, env.project_name)
45     env.target = os.path.join(env.path, 'bin', 'python')
46
47
48 # =========
49 # = Tasks =
50 # =========
51 def test():
52     "Run the test suite and bail out if it fails"
53     require('hosts', 'path', provided_by=[staging, production])
54     result = run('cd %(path)s/%(project_name)s; %(python)s manage.py test' % env)
55
56
57 def setup():
58     """
59     Setup a fresh virtualenv as well as a few useful directories, then run
60     a full deployment. virtualenv and pip should be already installed.
61     """
62     require('hosts', 'sandbox', provided_by=[staging, production])
63
64     run("mkdir -p %(path)s; mkdir -p %(path)s/www/wsgi;" % env)
65
66     # make a git mirror
67     run("""\
68 cd %(path)s;
69 git clone %(giturl)s mirror;
70 cd %(path)s/mirror;
71 git pull""" % env, pty=True)
72
73     run('%(virtualenv)s %(path)s' % env, pty=True)
74     run('cd %(path)s; mkdir -p releases; mkdir -p shared; mkdir -p packages;' % env, pty=True)
75     run('cd %(path)s/releases; ln -s . current; ln -s . previous' % env, pty=True)
76     deploy()
77
78
79 def deploy():
80     """
81     Deploy the latest version of the site to the servers,
82     install any required third party modules,
83     install the virtual host and then restart the webserver
84     """
85     require('hosts', 'sandbox', 'gitbranch', provided_by=[staging, production])
86
87     env.release = time.strftime('%Y-%m-%dT%H%M')
88
89     prepare_package_from_git()
90
91     upload_wsgi_script()
92 #    upload_vhost_sample()
93     install_requirements()
94     hardlink_localsettings()
95     symlink_current_release()
96     migrate()
97     django_compress()
98     restart_webserver()
99
100
101 def deploy_version(version):
102     "Specify a specific version to be made live"
103     require('hosts', 'path', provided_by=[localhost, webserver])
104     env.version = version
105     with cd(env.path):
106         run('rm releases/previous; mv releases/current releases/previous;', pty=True)
107         run('ln -s %(version)s releases/current' % env, pty=True)
108
109     restart_webserver()
110
111
112 def rollback():
113     """
114     Limited rollback capability. Simple loads the previously current
115     version of the code. Rolling back again will swap between the two.
116     """
117     require('hosts', provided_by=[staging, production])
118     require('path')
119     with cd(env.path):
120         run('mv releases/current releases/_previous;', pty=True)
121         run('mv releases/previous releases/current;', pty=True)
122         run('mv releases/_previous releases/previous;', pty=True)
123     restart_webserver()
124
125
126 # =====================================================================
127 # = Helpers. These are called by other functions rather than directly =
128 # =====================================================================
129 def prepare_package_from_git():
130     "Create an archive from the current Git master branch and upload it"
131     print '>>> upload tar from git'
132
133     require('release', provided_by=[deploy])
134
135     run('mkdir -p %(path)s/releases/%(release)s' % env, pty=True)
136     run('mkdir -p %(path)s/packages' % env, pty=True)
137     run('cd %(path)s/mirror; git pull; git archive --format=tar %(gitbranch)s | gzip > %(path)s/packages/%(release)s.tar.gz' % env)
138     run('cd %(path)s/releases/%(release)s && tar zxf ../../packages/%(release)s.tar.gz' % env, pty=True)
139
140
141 #def upload_vhost_sample():
142 #    "Create and upload Apache virtual host configuration sample"
143 #    print ">>> upload vhost sample"
144 #    files.upload_template('%(project_name)s.vhost.template' % env, '%(path)s/%(project_name)s.vhost.sample' % env, context=env)
145
146
147 def upload_wsgi_script():
148     "Create and upload a wsgi script sample"
149     print ">>> upload wsgi script sample"
150     files.upload_template('%(project_name)s/config/%(project_name)s.wsgi.template' % env, '%(path)s/www/wsgi/%(project_name)s.wsgi' % env, context=env)
151     run('chmod ug+x %(path)s/www/wsgi/%(project_name)s.wsgi' % env)
152
153
154 def install_requirements():
155     "Install the required packages from the requirements file using pip"
156
157     print '>>> Instaling global requirements'
158     require('release', provided_by=[deploy])
159     run('cd %(path)s; %(path)s/bin/pip install -r %(path)s/releases/%(release)s/%(project_name)s/config/requirements.txt' % env, pty=True)
160
161     print '>>> Instaling site requirements'
162
163     with settings(warn_only=True):
164         run('cd %(path)s; %(path)s/bin/pip install -r %(sandbox)s/etc/%(project_name)s/requirements.txt' % env, pty=True)
165
166
167 def hardlink_localsettings():
168     "Hardlink localsettings.py from root directory to release directory (if this file exists)"
169     print ">>> Hardlink localsettings"
170     require('release', 'path', provided_by=[deploy])
171     require('sandbox', provided_by=[staging, production])
172
173     # hardlink localsettings
174     with settings(warn_only=True):
175         run('ln %(sandbox)s/etc/%(project_name)s/localsettings.py %(path)s/releases/%(release)s/%(project_name)s' % env)
176
177
178 def symlink_current_release():
179     "Symlink our current release"
180     print '>>> symlink current release'
181     require('release', provided_by=[deploy])
182     require('path', provided_by=[staging, production])
183     with cd(env.path):
184         run('rm releases/previous; mv releases/current releases/previous')
185         run('ln -s %(release)s releases/current' % env)
186
187
188 def migrate():
189     "Update the database"
190     print '>>> migrate'
191     require('project_name', provided_by=[staging, production])
192     with cd('%(path)s/releases/current/%(project_name)s' % env):
193         run('%(target)s manage.py syncdb --noinput' % env, pty=True)
194
195         if env.use_south:
196             run('%(target)s manage.py migrate' % env, pty=True)
197
198
199 def django_compress():
200     "Update static files"
201     print '>>> migrate'
202     require('project_name', provided_by=[staging, production])
203     with cd('%(path)s/releases/current/%(project_name)s' % env):
204         run('%(target)s manage.py synccompress --force' % env, pty=True)
205
206
207 def restart_webserver():
208     "Restart the web server"
209     print '>>> restart webserver'
210     run('touch %(path)s/www/wsgi/%(project_name)s.wsgi' % env)