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