e4033209bb5e2e8d15394a2c2d9c25e9aac10c61
[wolnelektury.git] / fabfile.py
1 from __future__ import with_statement # needed for python 2.5
2 from fabric.api import *
3
4 import os
5
6 # Globals
7 env.project_name = 'wolnelektury'
8
9
10 # ===========
11 # = Servers =
12 # ===========
13 def staging():
14     """Use staging server"""
15     env.hosts = ['zuber@stigma.nowoczesnapolska.org.pl:2222']
16     env.path = '/var/lektury'
17     env.python = '/usr/bin/python'
18     env.virtualenv = '/usr/bin/virtualenv'
19     env.pip = '/usr/bin/pip'
20     
21 def production():
22     """Use production server"""
23     env.hosts = ['fundacja@wolnelektury.pl:22123']
24     env.path = '/opt/lektury'
25     env.python = '/opt/lektury/basevirtualenv/bin/python'
26     env.virtualenv = '/opt/lektury/basevirtualenv/bin/virtualenv'
27     env.pip = '/opt/lektury/basevirtualenv/bin/pip'
28
29 # =========
30 # = Tasks =
31 # =========
32 def test():
33     "Run the test suite and bail out if it fails"
34     require('hosts', 'path', provided_by=[staging, production])
35     result = run('cd %(path)s/%(project_name)s; %(python)s manage.py test' % env)
36
37 def deploy():
38     """
39     Deploy the latest version of the site to the servers, 
40     install any required third party modules, 
41     install the virtual host and then restart the webserver
42     """
43     require('hosts', 'path', provided_by=[staging, production])
44     
45     import time
46     env.release = time.strftime('%Y-%m-%dT%H%M')
47     
48     upload_tar_from_git()
49     upload_requirements_bundle()
50     install_requirements()
51     symlink_current_release()
52     migrate()
53     restart_webserver()
54
55 def deploy_version(version):
56     "Specify a specific version to be made live"
57     require('hosts', 'path', provided_by=[localhost,webserver])
58     env.version = version
59     with cd(env.path):
60         run('rm releases/previous; mv releases/current releases/previous;', pty=True)
61         run('ln -s %(version)s releases/current' % env, pty=True)
62     restart_webserver()
63
64 def rollback():
65     """
66     Limited rollback capability. Simple loads the previously current
67     version of the code. Rolling back again will swap between the two.
68     """
69     require('hosts', provided_by=[staging, production])
70     require('path')
71     with cd(env.path):
72         run('mv releases/current releases/_previous;', pty=True)
73         run('mv releases/previous releases/current;', pty=True)
74         run('mv releases/_previous releases/previous;', pty=True)
75     restart_webserver()
76     
77 # def setup():
78 #     """
79 #     Setup a fresh virtualenv as well as a few useful directories, then run
80 #     a full deployment
81 #     """
82 #     require('hosts', provided_by=[staging, production])
83 #     require('path')
84 #     sudo('aptitude install -y python-setuptools')
85 #     sudo('easy_install pip')
86 #     sudo('pip install virtualenv')
87 #     sudo('aptitude install -y apache2-threaded')
88 #     sudo('aptitude install -y libapache2-mod-wsgi') # beware, outdated on hardy!
89 #     # we want to get rid of the default apache config
90 #     sudo('cd /etc/apache2/sites-available/; a2dissite default;', pty=True)
91 #     sudo('mkdir -p %(path)s; chown %(user)s:%(user)s %(path)s;' % env, pty=True)
92 #     run('ln -s %(path)s www;' % env, pty=True) # symlink web dir in home
93 #     with cd(env.path):
94 #         run('virtualenv .;' % env, pty=True)
95 #         run('mkdir logs; chmod a+w logs; mkdir releases; mkdir shared; mkdir packages;' % env, pty=True)
96 #         if env.use_photologue: run('mkdir photologue');
97 #         run('cd releases; ln -s . current; ln -s . previous;', pty=True)
98 #     deploy()
99
100
101 # =====================================================================
102 # = Helpers. These are called by other functions rather than directly =
103 # =====================================================================
104 def upload_tar_from_git():
105     "Create an archive from the current Git master branch and upload it"
106     print '>>> upload tar from git'
107     require('release', provided_by=[deploy])
108     local('git archive --format=tar master | gzip > %(release)s.tar.gz' % env)
109     run('mkdir -p %(path)s/releases/%(release)s' % env, pty=True)
110     run('mkdir -p %(path)s/packages' % env, pty=True)
111     put('%(release)s.tar.gz' % env, '%(path)s/packages/' % env)
112     run('cd %(path)s/releases/%(release)s && tar zxf ../../packages/%(release)s.tar.gz' % env, pty=True)
113     local('rm %(release)s.tar.gz' % env)
114
115 def upload_requirements_bundle():
116     "Create a pybundle from requirements.txt file and upload it"
117     print '>>> upload requirements bundle'
118     require('release', provided_by=[deploy])
119     requirements_mtime = os.path.getmtime('requirements.txt')
120     pybundle_mtime = 0
121     try:
122         pybundle_mtime = os.path.getmtime('requirements.pybundle')
123     except os.error:
124         pass
125     if pybundle_mtime < requirements_mtime:
126         pip_options = file('pip-options.txt').read().strip()
127         local('pip bundle %s -r requirements.txt requirements.pybundle' % pip_options)
128     put('requirements.pybundle', '%(path)s/releases/%(release)s' % 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     with cd('%(path)s/releases/%(release)s' % env):
135         run('%(virtualenv)s --no-site-packages .' % env)
136         run('%(pip)s install -E . requirements.pybundle' % env)
137
138 def symlink_current_release():
139     "Symlink our current release"
140     print '>>> symlink current release'
141     require('release', provided_by=[deploy])
142     require('path', provided_by=[staging, production])
143     with cd(env.path):
144         with settings(
145             hide('warnings', 'running', 'stdout', 'stderr'),
146             warn_only=True
147         ):
148             run('rm releases/previous; mv releases/current releases/previous;')
149         
150         run('ln -s %(release)s releases/current' % env)
151
152 def migrate():
153     "Update the database"
154     print '>>> migrate'
155     require('project_name', provided_by=[staging, production])
156     with cd('%(path)s/releases/current/%(project_name)s' % env):
157         run('../bin/python manage.py syncdb --noinput' % env, pty=True)
158         run('../bin/python manage.py migrate' % env, pty=True)
159
160 def restart_webserver():
161     "Restart the web server"
162     print '>>> restart webserver'
163     run('touch %(path)s/releases/current/%(project_name)s/%(project_name)s.wsgi' % env)
164
165 # def install_site():
166 #     "Add the virtualhost file to apache"
167 #     require('release', provided_by=[deploy, setup])
168 #     #sudo('cd %(path)s/releases/%(release)s; cp %(project_name)s%(virtualhost_path)s%(project_name)s /etc/apache2/sites-available/' % env)
169 #     sudo('cd %(path)s/releases/%(release)s; cp vhost.conf /etc/apache2/sites-available/%(project_name)s' % env)
170 #     sudo('cd /etc/apache2/sites-available/; a2ensite %(project_name)s' % env, pty=True)