Merge lp:~ricardokirkner/locolander/django-supervisor into lp:locolander

Proposed by Ricardo Kirkner
Status: Needs review
Proposed branch: lp:~ricardokirkner/locolander/django-supervisor
Merge into: lp:locolander
Prerequisite: lp:~ricardokirkner/locolander/lean-output
Diff against target: 534 lines (+137/-127)
12 files modified
.locolander.yml (+7/-3)
config/supervisord.conf (+0/-37)
docker/Dockerfile (+5/-4)
docker/scripts/locolander (+5/-6)
fabfile.py (+8/-22)
locolander/locolander/settings.py (+3/-2)
locolander/locolanderweb/models.py (+9/-0)
locolander/locolanderweb/tasks.py (+11/-18)
locolander/locolanderweb/tests/test_models.py (+15/-1)
locolander/locolanderweb/tests/test_tasks.py (+28/-31)
locolander/supervisord.conf (+38/-0)
requirements.txt (+8/-3)
To merge this branch: bzr merge lp:~ricardokirkner/locolander/django-supervisor
Reviewer Review Type Date Requested Status
LocoLanderos Pending
Review via email: mp+177407@code.launchpad.net

Commit message

simplified fabfile for supervisor tasks

To post a comment you must log in.
34. By Ricardo Kirkner

better output from script

35. By Ricardo Kirkner

added config for docker process

36. By Ricardo Kirkner

merged trunk

Unmerged revisions

36. By Ricardo Kirkner

merged trunk

35. By Ricardo Kirkner

added config for docker process

34. By Ricardo Kirkner

better output from script

33. By Ricardo Kirkner

replace subprocess with envoy

use envoy instead of subprocess, because the latter fails to run properly
when celeryd is started under supervisor.

32. By Ricardo Kirkner

customized model repr strings

31. By Ricardo Kirkner

use absolute path for database file

30. By Ricardo Kirkner

better output handling

29. By Ricardo Kirkner

disable autoreload

28. By Ricardo Kirkner

added envoy and django-supervisor as dependencies

27. By Ricardo Kirkner

merged branch lp:~ricardokirkner/locolander/lean-output

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.locolander.yml'
2--- .locolander.yml 2013-07-23 23:55:56 +0000
3+++ .locolander.yml 2013-08-17 00:46:15 +0000
4@@ -5,9 +5,6 @@
5 libxml2-dev:
6 libxslt1-dev:
7 pip:
8- Django: 1.5.1
9- PyYAML: 3.10.0
10- South: 0.8.1
11 amqp: 1.0.12
12 anyjson: 0.3.3
13 argparse: 1.2.1
14@@ -16,8 +13,11 @@
15 celery: 3.0.21
16 cssselect: 0.8
17 distribute: 0.6.34
18+ Django: 1.5.1
19 django-allauth: 0.12.0
20 django-celery: 3.0.17
21+ django-supervisor: 0.3.1
22+ envoy: 0.0.2
23 flower: 0.5.2
24 github3.py: 0.7.0
25 gunicorn: 17.5
26@@ -33,6 +33,7 @@
27 mock: 1.0.1
28 oauth: 1.0.1
29 oauthlib: 0.5.0
30+ pathtools: 0.1.2
31 pep8: 1.4.6
32 psycopg2: 2.5.1
33 pyflakes: 0.7.3
34@@ -40,15 +41,18 @@
35 python-dateutil: 2.1
36 python-openid: 2.2.5
37 pytz: 2013b
38+ PyYAML: 3.10.0
39 redis: 2.7.6
40 requests: 1.2.3
41 requests-oauthlib: 0.3.2
42 simplejson: 3.3.0
43 six: 1.3.0
44+ South: 0.8.1
45 supervisor: 3.0b2
46 testresources: 0.2.7
47 tornado: 3.1
48 wadllib: 1.3.2
49+ watchdog: 0.6.0
50 wsgi-intercept: 0.5.1
51 wsgiref: 0.1.2
52 zope.interface: 4.0.5
53
54=== removed file 'config/supervisord.conf'
55--- config/supervisord.conf 2013-07-13 17:01:27 +0000
56+++ config/supervisord.conf 1970-01-01 00:00:00 +0000
57@@ -1,37 +0,0 @@
58-; Sample supervisor config file.
59-
60-[supervisord]
61-nodaemon = true
62-loglevel = info
63-logfile = supervisord.log
64-
65-
66-; service configuration sections
67-
68-[program:gunicorn]
69-command = gunicorn_django locolander/locolander/settings.py
70-autostart = true
71-autorestart = true
72-stdout_logfile = supervisord.log
73-redirect_stderr = true
74-
75-[program:redis]
76-command = redis-server
77-autostart = true
78-autorestart = true
79-stdout_logfile = supervisord.log
80-redirect_stderr = true
81-
82-[program:celeryd]
83-command = python locolander/manage.py celeryd
84-autostart = true
85-autorestart = true
86-stdout_logfile = supervisord.log
87-redirect_stderr = true
88-
89-[program:flower]
90-command = python locolander/manage.py celery flower
91-autostart = true
92-autorestart = true
93-stdout_logfile = supervisord.log
94-redirect_stderr = true
95
96=== modified file 'docker/Dockerfile'
97--- docker/Dockerfile 2013-06-21 21:48:36 +0000
98+++ docker/Dockerfile 2013-08-17 00:46:15 +0000
99@@ -24,10 +24,6 @@
100 # add locolander user
101 run adduser locolander
102
103-# install main locolander script
104-add ./scripts/run_tests.sh /usr/local/bin/run_tests.sh
105-run chown locolander.locolander /usr/local/bin/run_tests.sh
106-
107 # configure ssh
108 run mkdir /home/locolander/.ssh
109 add ./files/ssh/id_rsa /home/locolander/.ssh/id_rsa
110@@ -40,3 +36,8 @@
111
112 # ensure proper ownership
113 run chown -R locolander.locolander /home/locolander/
114+
115+# install main locolander script
116+add ./scripts/locolander /usr/local/bin/locolander
117+run chown locolander.locolander /usr/local/bin/locolander
118+
119
120=== modified file 'docker/scripts/locolander'
121--- docker/scripts/locolander 2013-07-27 00:04:40 +0000
122+++ docker/scripts/locolander 2013-08-17 00:46:15 +0000
123@@ -56,8 +56,8 @@
124 OUTPUT=$(python ns2df.py $PROJECT .locolander.yml Dockerfile 2>&1)
125 OUTPUT=$(docker build -t $PROJECT . 2>&1)
126 if [ -z $? -o "`echo $OUTPUT | grep 'Error'`" != "" ]; then
127- echo "FAILURE - Build failed:"
128 echo $OUTPUT
129+ echo "FAILURE - Build failed"
130 exit 1
131 fi
132
133@@ -67,9 +67,8 @@
134
135 # 4. run test script using image
136 echo "Running tests ..."
137-docker run $PROJECT
138-
139-if [ -z $? -o "`echo $OUTPUT | grep 'Error'`" != "" ]; then
140+docker run $PROJECT 2>&1
141+if [ -z $? ]; then
142 echo "FAILURE - Tests failed"
143 exit 1
144 fi
145@@ -87,7 +86,7 @@
146 echo "Pushing merge ..."
147 OUTPUT=$(bzr push $TARGET 2>&1)
148
149-echo "SUCCESS"
150-
151 # cleanup
152 rm -rf $TMPFOLDER
153+
154+echo "SUCCESS"
155
156=== modified file 'fabfile.py'
157--- fabfile.py 2013-07-17 13:33:49 +0000
158+++ fabfile.py 2013-08-17 00:46:15 +0000
159@@ -23,30 +23,16 @@
160
161
162 @virtualenv
163+def run():
164+ manage('supervisor')
165+
166+
167+@virtualenv
168 def test():
169 local('./run_tests.sh')
170
171
172 @virtualenv
173-def start_redis():
174- local('redis-server')
175-
176-
177-@virtualenv
178-def start_gunicorn():
179- local('gunicorn_django locolander/locolander/settings.py')
180-
181-
182-@virtualenv
183-def start_celery():
184- manage('celeryd')
185-
186-
187-@virtualenv
188-def start_flower():
189- manage('celery flower')
190-
191-
192-@virtualenv
193-def start_supervisor():
194- local('supervisord -c config/supervisord.conf -n')
195+def docker_build():
196+ local('python ns2df.py locolander .locolander.yml Dockerfile')
197+ local('docker build -t locolander .')
198
199=== modified file 'locolander/locolander/settings.py'
200--- locolander/locolander/settings.py 2013-07-21 03:05:23 +0000
201+++ locolander/locolander/settings.py 2013-08-17 00:46:15 +0000
202@@ -16,7 +16,7 @@
203 DATABASES = {
204 'default': {
205 'ENGINE': 'django.db.backends.sqlite3',
206- 'NAME': 'locolander.db',
207+ 'NAME': os.path.abspath(os.path.join(os.curdir, 'locolander.db')),
208 # The following settings are not used with sqlite3:
209 'USER': '',
210 'PASSWORD': '',
211@@ -126,9 +126,10 @@
212 'django.contrib.messages',
213 'django.contrib.staticfiles',
214 'django.contrib.admin',
215- 'djcelery',
216 'locolanderweb',
217 'south',
218+ 'djcelery',
219+ 'djsupervisor',
220 'allauth',
221 'allauth.account',
222 'allauth.socialaccount',
223
224=== modified file 'locolander/locolanderweb/models.py'
225--- locolander/locolanderweb/models.py 2013-07-13 18:44:18 +0000
226+++ locolander/locolanderweb/models.py 2013-08-17 00:46:15 +0000
227@@ -33,6 +33,9 @@
228 name = models.TextField()
229 url = models.CharField(max_length=256, validators=[service_url_validator])
230
231+ def __repr__(self):
232+ return u"<Project: %s>" % self.name
233+
234 @property
235 def service(self):
236 return get_service_from_url(self.url)
237@@ -56,6 +59,9 @@
238 date_created = models.DateTimeField()
239 date_completed = models.DateTimeField(null=True, blank=True)
240
241+ def __repr__(self):
242+ return u"<MergeRequest: %s -> %s>" % (self.source, self.target)
243+
244 def complete(self, error=False):
245 self.date_completed = datetime.utcnow()
246 self.status = STATUS_MERGED if not error else STATUS_ERROR
247@@ -71,3 +77,6 @@
248
249 class Meta:
250 get_latest_by = 'timestamp'
251+
252+ def __repr__(self):
253+ return u"<RunLog: %r at %s>" % (self.merge_request, self.timestamp)
254
255=== modified file 'locolander/locolanderweb/tasks.py'
256--- locolander/locolanderweb/tasks.py 2013-08-03 17:06:41 +0000
257+++ locolander/locolanderweb/tasks.py 2013-08-17 00:46:15 +0000
258@@ -1,7 +1,7 @@
259 import os
260-import subprocess
261 from datetime import datetime
262
263+import envoy
264 from celery import task
265
266 from locolanderweb.models import MergeRequest, RunLog
267@@ -21,23 +21,16 @@
268 author = request.author
269 message = request.commit_message
270
271- cmd = [
272- os.path.realpath(os.path.join(
273- os.path.abspath('.'), 'docker/scripts/locolander')),
274- project.name,
275- source,
276- target,
277- message,
278- author,
279- ]
280- try:
281- output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
282- return_code = 0
283- error = False
284- except subprocess.CalledProcessError as err:
285- output = err.output
286- return_code = err.returncode
287- error = True
288+ cmd = '{script} {project} {source} {target} "{message}" "{author}"'.format(
289+ script=os.path.join(os.path.abspath(os.curdir),
290+ 'docker', 'scripts', 'locolander'),
291+ project=project.name, source=source, target=target, message=message,
292+ author=author)
293+
294+ r = envoy.run(cmd)
295+ output = r.std_out
296+ return_code = r.status_code
297+ error = return_code != 0
298
299 RunLog.objects.create(merge_request=request, raw=output,
300 return_code=return_code)
301
302=== modified file 'locolander/locolanderweb/tests/test_models.py'
303--- locolander/locolanderweb/tests/test_models.py 2013-07-20 21:10:37 +0000
304+++ locolander/locolanderweb/tests/test_models.py 2013-08-17 00:46:15 +0000
305@@ -96,6 +96,10 @@
306 result = self.obj.approved_requests()
307 self.assertEqual(len(result), 1)
308
309+ def test_repr(self):
310+ expected = u'<Project: foo>'
311+ self.assertEqual(repr(self.obj), expected)
312+
313
314 class MergeRequestTestCase(BaseTestCase):
315
316@@ -156,14 +160,20 @@
317 self.assertEqual(self.obj.status, STATUS_ERROR)
318 self.assertEqual(self.obj.date_completed, completed)
319
320+ def test_repr(self):
321+ expected = u'<MergeRequest: source -> target>'
322+ self.assertEqual(repr(self.obj), expected)
323+
324
325 class RunLogTestCase(BaseTestCase):
326
327 def setUp(self):
328 super(RunLogTestCase, self).setUp()
329 self.merge_request = self.factory.make_merge_request()
330+ self.timestamp = datetime.utcnow()
331 self.obj = RunLog.objects.create(
332- merge_request=self.merge_request, return_code=0)
333+ merge_request=self.merge_request, return_code=0,
334+ timestamp=self.timestamp)
335
336 def test_merge_request(self):
337 self.assertEqual(self.obj.merge_request, self.merge_request)
338@@ -187,3 +197,7 @@
339 merge_request=self.merge_request, return_code=0,
340 timestamp=self.obj.timestamp + timedelta(seconds=1))
341 self.assertEqual(RunLog.objects.latest(), other)
342+
343+ def test_repr(self):
344+ expected = u"<RunLog: %r at %s>" % (self.merge_request, self.timestamp)
345+ self.assertEqual(repr(self.obj), expected)
346
347=== modified file 'locolander/locolanderweb/tests/test_tasks.py'
348--- locolander/locolanderweb/tests/test_tasks.py 2013-07-20 21:07:18 +0000
349+++ locolander/locolanderweb/tests/test_tasks.py 2013-08-17 00:46:15 +0000
350@@ -1,7 +1,7 @@
351-import subprocess
352+import os
353 from datetime import datetime
354
355-from mock import ANY, patch
356+from mock import patch
357
358 from locolanderweb.models import (
359 STATUS_ERROR,
360@@ -55,29 +55,28 @@
361
362 def setUp(self):
363 super(RunRequestTestCase, self).setUp()
364- patcher = patch('locolanderweb.tasks.subprocess.check_output')
365- self.mock_check_output = patcher.start()
366+ patcher = patch('locolanderweb.tasks.envoy.run')
367+ self.mock_run = patcher.start()
368 self.addCleanup(patcher.stop)
369
370 def test_run_request(self):
371- self.mock_check_output.return_value = 'SUCCESS'
372+ self.mock_run.return_value.std_out = 'SUCCESS'
373+ self.mock_run.return_value.status_code = 0
374
375 merge_request = self.factory.make_merge_request()
376
377 run_request(merge_request)
378
379- cmd = [
380- ANY,
381- merge_request.project.name,
382- merge_request.source,
383- merge_request.target,
384- merge_request.commit_message,
385- merge_request.author,
386- ]
387- self.mock_check_output.assert_called_once_with(
388- cmd, stderr=subprocess.STDOUT)
389- real_cmd = self.mock_check_output.call_args[0][0][0]
390- self.assertTrue(real_cmd.endswith('docker/scripts/locolander'))
391+ cmd = ('{script} {project} {source} {target} '
392+ '"{message}" "{author}"').format(
393+ script=os.path.abspath('./docker/scripts/locolander'),
394+ project=merge_request.project.name,
395+ source=merge_request.source,
396+ target=merge_request.target,
397+ message=merge_request.commit_message,
398+ author=merge_request.author
399+ )
400+ self.mock_run.assert_called_once_with(cmd)
401
402 self.assertEqual(RunLog.objects.all().count(), 1)
403 run_log = RunLog.objects.get(merge_request=merge_request)
404@@ -91,23 +90,21 @@
405 def test_run_request_with_error(self):
406 merge_request = self.factory.make_merge_request()
407
408- cmd = [
409- ANY,
410- merge_request.project.name,
411- merge_request.source,
412- merge_request.target,
413- merge_request.commit_message,
414- merge_request.author,
415- ]
416- error = subprocess.CalledProcessError(1, cmd, output='FAILURE')
417- self.mock_check_output.side_effect = error
418+ cmd = ('{script} {project} {source} {target} '
419+ '"{message}" "{author}"').format(
420+ script=os.path.abspath('./docker/scripts/locolander'),
421+ project=merge_request.project.name,
422+ source=merge_request.source,
423+ target=merge_request.target,
424+ message=merge_request.commit_message,
425+ author=merge_request.author
426+ )
427+ self.mock_run.return_value.std_out = 'FAILURE'
428+ self.mock_run.return_value.status_code = 1
429
430 run_request(merge_request)
431
432- self.mock_check_output.assert_called_once_with(
433- cmd, stderr=subprocess.STDOUT)
434- real_cmd = self.mock_check_output.call_args[0][0][0]
435- self.assertTrue(real_cmd.endswith('docker/scripts/locolander'))
436+ self.mock_run.assert_called_once_with(cmd)
437
438 self.assertEqual(RunLog.objects.all().count(), 1)
439 run_log = RunLog.objects.get(merge_request=merge_request)
440
441=== added file 'locolander/supervisord.conf'
442--- locolander/supervisord.conf 1970-01-01 00:00:00 +0000
443+++ locolander/supervisord.conf 2013-08-17 00:46:15 +0000
444@@ -0,0 +1,38 @@
445+[program:gunicorn]
446+command = gunicorn -b 0.0.0.0:8000 locolander.wsgi:application
447+directory = {{ PROJECT_DIR }}
448+autostart = true
449+autorestart = true
450+stdout_logfile = supervisord.log
451+redirect_stderr = true
452+
453+[program:redis]
454+command = redis-server
455+autostart = true
456+autorestart = true
457+stdout_logfile = supervisord.log
458+redirect_stderr = true
459+
460+[program:docker]
461+command = /usr/bin/docker
462+autostart = false
463+autorestart = true
464+stdout_logfile = supervisord.log
465+redirect_stderr = true
466+
467+[program:celeryd]
468+command = {{ PYTHON }} {{ PROJECT_DIR }}/manage.py celeryd
469+autostart = true
470+autorestart = true
471+stdout_logfile = supervisord.log
472+redirect_stderr = true
473+
474+[program:flower]
475+command = {{ PYTHON }} {{ PROJECT_DIR }}/manage.py celery flower
476+autostart = true
477+autorestart = true
478+stdout_logfile = supervisord.log
479+redirect_stderr = true
480+
481+[program:autoreload]
482+exclude = true
483
484=== modified file 'requirements.txt'
485--- requirements.txt 2013-07-20 23:52:03 +0000
486+++ requirements.txt 2013-08-17 00:46:15 +0000
487@@ -1,16 +1,17 @@
488-Django==1.5.1
489-PyYAML==3.10
490-South==0.8.1
491 amqp==1.0.12
492 anyjson==0.3.3
493+argh==0.23.2
494 argparse==1.2.1
495 billiard==2.7.3.31
496 bzr==2.6b2
497 celery==3.0.21
498 cssselect==0.8
499 distribute==0.6.34
500+Django==1.5.1
501 django-allauth==0.12.0
502 django-celery==3.0.17
503+django-supervisor==0.3.1
504+envoy==0.0.2
505 flower==0.5.2
506 github3.py==0.7.0
507 gunicorn==17.5
508@@ -26,6 +27,7 @@
509 mock==1.0.1
510 oauth==1.0.1
511 oauthlib==0.5.0
512+pathtools==0.1.2
513 pep8==1.4.6
514 psycopg2==2.5.1
515 pyflakes==0.7.3
516@@ -33,15 +35,18 @@
517 python-dateutil==2.1
518 python-openid==2.2.5
519 pytz==2013b
520+PyYAML==3.10
521 redis==2.7.6
522 requests==1.2.3
523 requests-oauthlib==0.3.2
524 simplejson==3.3.0
525 six==1.3.0
526+South==0.8.1
527 supervisor==3.0b2
528 testresources==0.2.7
529 tornado==3.1
530 wadllib==1.3.2
531+watchdog==0.6.0
532 wsgi-intercept==0.5.1
533 wsgiref==0.1.2
534 zope.interface==4.0.5

Subscribers

People subscribed via source and target branches

to all changes: