8ae349f019e4c0b04dfab7e63275afce53df4392
[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 = env.target = os.path.join(env.sandbox, 'python', 'bin', 'python')
40
41     common()
42
43
44 def common():
45     env.path = os.path.join(env.sandbox, env.project_name)
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     copy_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 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     print '>>> install requirements'
157     require('release', provided_by=[deploy])
158     run('cd %(path)s; %(path)s/bin/pip install -r %(path)s/releases/%(release)s/%(project_name)s/config/requirements.txt' % env, pty=True)
159
160
161 def copy_localsettings():
162     "Copy localsettings.py from root directory to release directory (if this file exists)"
163     print ">>> copy localsettings"
164     require('release', 'path', provided_by=[deploy])
165     require('sandbox', provided_by=[staging, production])
166
167     with settings(warn_only=True):
168         run('cp %(sandbox)s/etc/%(project_name)s/localsettings.py %(path)s/releases/%(release)s/%(project_name)s' % env)
169
170
171 def symlink_current_release():
172     "Symlink our current release"
173     print '>>> symlink current release'
174     require('release', provided_by=[deploy])
175     require('path', provided_by=[staging, production])
176     with cd(env.path):
177         run('rm releases/previous; mv releases/current releases/previous')
178         run('ln -s %(release)s releases/current' % env)
179
180
181 def migrate():
182     "Update the database"
183     print '>>> migrate'
184     require('project_name', provided_by=[staging, production])
185     with cd('%(path)s/releases/current/%(project_name)s' % env):
186         run('%(target) manage.py syncdb --noinput' % env, pty=True)
187
188         if env.use_south:
189             run('%(target) manage.py migrate' % env, pty=True)
190
191
192 def django_compress():
193     "Update static files"
194     print '>>> migrate'
195     require('project_name', provided_by=[staging, production])
196     with cd('%(path)s/releases/current/%(project_name)s' % env):
197         run('%(target) manage.py synccompress --force' % env, pty=True)
198
199
200 def restart_webserver():
201     "Restart the web server"
202     print '>>> restart webserver'
203     run('touch %(path)s/www/wsgi/%(project_name)s.wsgi' % env)