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