Merge branch 'master' of github.com:FinalsClub/karmaworld
[oweals/karmaworld.git] / fabfile.py
1 """Management utilities."""
2
3 import os
4 from contextlib import contextmanager as _contextmanager
5
6 from fabric.api import cd, env, lcd, prefix, run, task, local, settings
7
8
9 ########## GLOBALS
10 env.proj_repo = 'git@github.com:FinalsClub/karmaworld.git'
11 env.virtualenv = 'venv-kw'
12 env.activate = 'workon %s' % env.virtualenv
13
14 # Using this env var to be able to specify the function
15 # used to run the commands. By default it's `run`, which
16 # runs commands remotely, but in the `here` task we set
17 # env.run to `local` to run commands locally.
18 env.run = run
19 env.cd = cd
20 ########## END GLOBALS
21
22
23 ########## HELPERS
24 @_contextmanager
25 def _virtualenv():
26     """
27     Changes to the proj_dir and activates the virtualenv
28     """
29     with env.cd(env.proj_dir):
30         with prefix(env.activate):
31             yield
32
33 ########## END HELPERS
34
35 ########## ENVIRONMENTS
36 @task
37 def here():
38     """
39     Connection information for the local machine
40     """
41     # This is required, because local doesn't read the user's
42     # .bashrc file, because it doesn't use an interactive shell
43     def _custom_local(command):
44         prefixed_command = '/bin/bash -l -i -c "%s"' % command
45         return local(prefixed_command)
46
47     # This is required for the same reason as above
48     env.activate = '/bin/bash -l -i -c "workon %s"' % env.virtualenv
49     env.proj_dir = os.getcwd()
50     env.proj_root = os.path.dirname(env.proj_dir)
51     env.run = _custom_local
52     env.cd = lcd
53     env.reqs = 'reqs/dev.txt'
54     env.confs = 'confs/dev/'
55     env.branch = 'master'
56
57
58 @task
59 def beta():
60     """
61     Beta connection information
62     """
63     env.user = 'djkarma'
64     env.hosts = ['beta.karmanotes.org']
65     env.proj_root = '/var/www/karmaworld'
66     env.proj_dir = os.path.join(env.proj_root, 'karmaworld')
67     env.reqs = 'reqs/prod.txt'
68     env.confs = 'confs/beta/'
69     env.branch = 'beta'
70
71
72 @task
73 def prod():
74     """
75     Production connection information
76     """
77     env.user = 'djkarma'
78     env.hosts = ['karmanotes.org']
79     env.proj_root = '/var/www/karmaworld'
80     env.proj_dir = os.path.join(env.proj_root, 'karmaworld')
81     env.reqs = 'reqs/prod.txt'
82     env.confs = 'confs/prod/'
83     env.branch = 'master'
84 ########## END ENVIRONMENTS
85
86
87 ########## DATABASE MANAGEMENT
88 @task
89 def syncdb():
90     """Runs syncdb (along with any pending South migrations)"""
91     env.run('python manage.py syncdb --noinput --migrate')
92 ########## END DATABASE MANAGEMENT
93
94
95 ########## FILE MANAGEMENT
96 @task
97 def manage_static():
98     """
99     Collects, compresses and uploads static files.
100     """
101     collect_static()
102     compress_static()
103     upload_static()
104
105
106 @task
107 def collect_static():
108     """Collect all static files, and copy them to S3 for production usage."""
109     env.run('python manage.py collectstatic --noinput')
110
111
112 @task
113 def compress_static():
114     """
115     Compresses the static files.
116     """
117     pass
118
119
120 @task
121 def upload_static():
122     """
123     Uploads the static files to the specified host.
124     """
125     pass
126 ########## END FILE MANAGEMENT
127
128
129 ########## COMMANDS
130 @task
131 def make_virtualenv():
132     """
133     Creates a virtualenv on the remote host
134     """
135     env.run('mkvirtualenv --no-site-packages %s' % env.virtualenv)
136
137
138 @task
139 def update_reqs():
140     """
141     Makes sure all packages listed in requirements are installed
142     """
143     with _virtualenv():
144         env.run('pip install -r %s' % env.reqs)
145
146
147 @task
148 def clone():
149     """
150     Clones the project from the central repository
151     """
152     env.run('git clone %s %s' % (env.proj_repo, env.proj_dir))
153
154
155 @task
156 def update_code():
157     """
158     Pulls changes from the central repo and checks out the right branch
159     """
160     with env.cd(env.proj_dir):
161         env.run('git pull && git checkout %s' % env.branch)
162
163
164 @task
165 def start_supervisord():
166     """
167     Starts supervisord
168     """
169     with _virtualenv():
170         config_file = os.path.join(env.confs, 'supervisord.conf')
171         env.run('supervisord -c %s' % config_file)
172
173
174 @task
175 def stop_supervisord():
176     """
177     Restarts supervisord
178     """
179     with _virtualenv():
180         config_file = os.path.join(env.confs, 'supervisord.conf')
181         env.run('supervisorctl -c %s shutdown' % config_file)
182
183
184 @task
185 def restart_supervisord():
186     """
187     Restarts supervisord
188     """
189     stop_supervisord()
190     start_supervisord()
191
192
193 def supervisorctl(action, process):
194     """
195     Takes as arguments the name of the process as is
196     defined in supervisord.conf and the action that should
197     be performed on it: start|stop|restart.
198     """
199     supervisor_conf = os.path.join(env.confs, 'supervisord.conf')
200     env.run('supervisorctl -c %s %s %s' % (supervisor_conf, action, process))
201
202
203 @task
204 def start_celeryd():
205     """
206     Starts the celeryd process
207     """
208     supervisorctl('start', 'celeryd')
209
210
211 @task
212 def stop_celeryd():
213     """
214     Stops the celeryd process
215     """
216     supervisorctl('stop', 'celeryd')
217
218
219 @task
220 def restart_celery():
221     """
222     Restarts the celeryd process
223     """
224     supervisorctl('restart', 'celeryd')
225
226
227 @task
228 def start_gunicorn():
229     """
230     Starts the gunicorn process
231     """
232     supervisorctl('start', 'gunicorn')
233
234
235 @task
236 def stop_gunicorn():
237     """
238     Stops the gunicorn process
239     """
240     supervisorctl('stop', 'gunicorn')
241
242
243 @task
244 def restart_gunicorn():
245     """
246     Restarts the gunicorn process
247     """
248     supervisorctl('restart', 'gunicorn')
249
250
251 @task
252 def first_deploy():
253     """
254     Sets up and deploys the project for the first time.
255     """
256     # If we're on the local machine, there's no point in cloning
257     # the project, because it's already been cloned. Otherwise
258     # the user couldn't run this file
259     if env.run == run:
260         # We're doing this to filter out the hosts that have
261         # already been setup and deployed to
262         with settings(warn_only=True):
263             if env.run('test -d %s' % env.project).failed:
264                 return
265         clone()
266
267     make_virtualenv()
268     update_reqs()
269     syncdb()
270
271     # We don't collect the static files and start supervisor on
272     # development machines
273     if env.run == run:
274         manage_static()
275         start_supervisord()
276
277
278 @task
279 def deploy():
280     """
281     Deploys the latest changes
282     """
283     update_code()
284     update_reqs()
285     syncdb()
286     manage_static()
287     restart_supervisord()
288 ########## END COMMANDS